Adds --force flag to service create command (service replace) (#79)

* Adds --force flag to service create command / service replace

 Fixes #13

* Keeps the resourceVersion of service with --force flag

* Updates the tests

* Removes unnecessary comments
This commit is contained in:
Navid Shaikh 2019-05-16 03:19:32 +05:30 committed by Knative Prow Robot
parent 08a12e112f
commit cab512c969
3 changed files with 95 additions and 5 deletions

View File

@ -29,6 +29,7 @@ type ConfigurationEditFlags struct {
Image string
Env []string
RequestsFlags, LimitsFlags ResourceFlags
ForceCreate bool
}
type ResourceFlags struct {
@ -49,6 +50,7 @@ func (p *ConfigurationEditFlags) AddUpdateFlags(command *cobra.Command) {
func (p *ConfigurationEditFlags) AddCreateFlags(command *cobra.Command) {
p.AddUpdateFlags(command)
command.Flags().BoolVar(&p.ForceCreate, "force", false, "Create service forcefully, replaces existing service if any.")
command.MarkFlagRequired("image")
}

View File

@ -22,6 +22,7 @@ import (
servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func NewServiceCreateCommand(p *KnParams) *cobra.Command {
@ -35,7 +36,19 @@ func NewServiceCreateCommand(p *KnParams) *cobra.Command {
kn service create mysvc --image dev.local/ns/image:latest
# Create a service with multiple environment variables
kn service create mysvc --env KEY1=VALUE1 --env KEY2=VALUE2 --image dev.local/ns/image:latest`,
kn service create mysvc --env KEY1=VALUE1 --env KEY2=VALUE2 --image dev.local/ns/image:latest
# Create or replace a service 's1' with image dev.local/ns/image:v2 using --force flag
# if service 's1' doesn't exist, it's just a normal create operation
kn service create --force s1 --image dev.local/ns/image:v2
# Create or replace environment variables of service 's1' using --force flag
kn service create --force s1 --env KEY1=NEW_VALUE1 --env NEW_KEY2=NEW_VALUE2 --image dev.local/ns/image:v1
# Create or replace default resources of a service 's1' using --force flag
# (earlier configured resource requests and limits will be replaced with default)
# (earlier configured environment variables will be cleared too if any)
kn service create --force s1 --image dev.local/ns/image:v1`,
RunE: func(cmd *cobra.Command, args []string) (err error) {
if len(args) != 1 {
@ -70,11 +83,26 @@ func NewServiceCreateCommand(p *KnParams) *cobra.Command {
if err != nil {
return err
}
var serviceExists bool = false
if editFlags.ForceCreate {
existingService, err := client.Services(namespace).Get(args[0], v1.GetOptions{})
if err == nil {
serviceExists = true
service.ResourceVersion = existingService.ResourceVersion
_, err = client.Services(namespace).Update(&service)
if err != nil {
return err
}
fmt.Fprintf(cmd.OutOrStdout(), "Service '%s' successfully replaced in namespace '%s'.\n", args[0], namespace)
}
}
if !serviceExists {
_, err = client.Services(namespace).Create(&service)
if err != nil {
return err
}
fmt.Fprintf(cmd.OutOrStdout(), "Service '%s' successfully created in namespace '%s'.\n", args[0], namespace)
}
return nil
},
}

View File

@ -290,3 +290,63 @@ func parseQuantity(t *testing.T, quantityString string) resource.Quantity {
}
return quantity
}
func TestServiceCreateImageForce(t *testing.T) {
_, _, _, err := fakeServiceCreate([]string{
"service", "create", "foo", "--image", "gcr.io/foo/bar:v1"})
if err != nil {
t.Fatal(err)
}
action, created, output, err := fakeServiceCreate([]string{
"service", "create", "foo", "--force", "--image", "gcr.io/foo/bar:v2"})
if err != nil {
t.Fatal(err)
} else if !action.Matches("create", "services") {
t.Fatalf("Bad action %v", action)
}
conf, err := servinglib.GetConfiguration(created)
if err != nil {
t.Fatal(err)
} else if conf.RevisionTemplate.Spec.Container.Image != "gcr.io/foo/bar:v2" {
t.Fatalf("wrong image set: %v", conf.RevisionTemplate.Spec.Container.Image)
} else if !strings.Contains(output, "foo") || !strings.Contains(output, "default") {
t.Fatalf("wrong output: %s", output)
}
}
func TestServiceCreateEnvForce(t *testing.T) {
_, _, _, err := fakeServiceCreate([]string{
"service", "create", "foo", "--image", "gcr.io/foo/bar:v1", "-e", "A=DOGS", "--env", "B=WOLVES"})
if err != nil {
t.Fatal(err)
}
action, created, output, err := fakeServiceCreate([]string{
"service", "create", "foo", "--force", "--image", "gcr.io/foo/bar:v2", "-e", "A=CATS", "--env", "B=LIONS"})
if err != nil {
t.Fatal(err)
} else if !action.Matches("create", "services") {
t.Fatalf("Bad action %v", action)
}
expectedEnvVars := map[string]string{
"A": "CATS",
"B": "LIONS"}
conf, err := servinglib.GetConfiguration(created)
actualEnvVars, err := servinglib.EnvToMap(conf.RevisionTemplate.Spec.Container.Env)
if err != nil {
t.Fatal(err)
}
if err != nil {
t.Fatal(err)
} else if conf.RevisionTemplate.Spec.Container.Image != "gcr.io/foo/bar:v2" {
t.Fatalf("wrong image set: %v", conf.RevisionTemplate.Spec.Container.Image)
} else if !reflect.DeepEqual(
actualEnvVars,
expectedEnvVars) {
t.Fatalf("wrong env vars:%v", conf.RevisionTemplate.Spec.Container.Env)
} else if !strings.Contains(output, "foo") || !strings.Contains(output, "default") {
t.Fatalf("wrong output: %s", output)
}
}