diff --git a/pkg/kn/commands/service.go b/pkg/kn/commands/service.go index 1f0802c93..77441e92a 100644 --- a/pkg/kn/commands/service.go +++ b/pkg/kn/commands/service.go @@ -27,5 +27,6 @@ func NewServiceCommand(p *KnParams) *cobra.Command { serviceCmd.AddCommand(NewServiceDescribeCommand(p)) serviceCmd.AddCommand(NewServiceCreateCommand(p)) serviceCmd.AddCommand(NewServiceDeleteCommand(p)) + serviceCmd.AddCommand(NewServiceUpdateCommand(p)) return serviceCmd } diff --git a/pkg/kn/commands/service_update.go b/pkg/kn/commands/service_update.go new file mode 100644 index 000000000..e302ac617 --- /dev/null +++ b/pkg/kn/commands/service_update.go @@ -0,0 +1,71 @@ +// Copyright © 2019 The Knative Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package commands + +import ( + "errors" + + serving_lib "github.com/knative/client/pkg/serving" + "github.com/spf13/cobra" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func NewServiceUpdateCommand(p *KnParams) *cobra.Command { + var editFlags ConfigurationEditFlags + + serviceUpdateCommand := &cobra.Command{ + Use: "update NAME", + Short: "Update a service.", + RunE: func(cmd *cobra.Command, args []string) (err error) { + if len(args) != 1 { + return errors.New("requires the service name.") + } + + namespace, err := GetNamespace(cmd) + if err != nil { + return err + } + + client, err := p.ServingFactory() + if err != nil { + return err + } + + service, err := client.Services(namespace).Get(args[0], v1.GetOptions{}) + if err != nil { + return err + } + + config, err := serving_lib.GetConfiguration(service) + if err != nil { + return err + } + err = editFlags.Apply(config) + if err != nil { + return err + } + + _, err = client.Services(namespace).Update(service) + if err != nil { + return err + } + + return nil + }, + } + AddNamespaceFlags(serviceUpdateCommand.Flags(), false) + editFlags.AddFlags(serviceUpdateCommand) + return serviceUpdateCommand +} diff --git a/pkg/kn/commands/service_update_test.go b/pkg/kn/commands/service_update_test.go new file mode 100644 index 000000000..71c3dd9dd --- /dev/null +++ b/pkg/kn/commands/service_update_test.go @@ -0,0 +1,109 @@ +// Copyright © 2019 The Knative Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package commands + +import ( + "bytes" + "errors" + "fmt" + "testing" + + servinglib "github.com/knative/client/pkg/serving" + + "github.com/knative/serving/pkg/apis/serving/v1alpha1" + serving "github.com/knative/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1" + "github.com/knative/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + client_testing "k8s.io/client-go/testing" +) + +func fakeServiceUpdate(original *v1alpha1.Service, args []string) ( + action client_testing.Action, + updated *v1alpha1.Service, + output string, + err error) { + + buf := new(bytes.Buffer) + fakeServing := &fake.FakeServingV1alpha1{&client_testing.Fake{}} + cmd := NewKnCommand(KnParams{ + Output: buf, + ServingFactory: func() (serving.ServingV1alpha1Interface, error) { return fakeServing, nil }, + }) + fakeServing.AddReactor("update", "*", + func(a client_testing.Action) (bool, runtime.Object, error) { + updateAction, ok := a.(client_testing.UpdateAction) + action = updateAction + if !ok { + return true, nil, fmt.Errorf("wrong kind of action %v", action) + } + updated, ok = updateAction.GetObject().(*v1alpha1.Service) + if !ok { + return true, nil, errors.New("was passed the wrong object") + } + return true, updated, nil + }) + fakeServing.AddReactor("get", "*", + func(a client_testing.Action) (bool, runtime.Object, error) { + return true, original, nil + }) + cmd.SetArgs(args) + err = cmd.Execute() + if err != nil { + return + } + output = buf.String() + return +} + +func TestServiceUpdateImage(t *testing.T) { + + orig := &v1alpha1.Service{ + TypeMeta: metav1.TypeMeta{ + Kind: "Service", + APIVersion: "knative.dev/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + }, + Spec: v1alpha1.ServiceSpec{ + RunLatest: &v1alpha1.RunLatestType{}, + }, + } + + config, err := servinglib.GetConfiguration(orig) + + if err != nil { + t.Fatal(err) + } + + servinglib.UpdateImage(config, "gcr.io/foo/bar:baz") + + action, updated, _, err := fakeServiceUpdate(orig, []string{ + "service", "update", "foo", "--image", "gcr.io/foo/quux:xyzzy"}) + + if err != nil { + t.Fatal(err) + } else if !action.Matches("update", "services") { + t.Fatalf("Bad action %v", action) + } + conf, err := servinglib.GetConfiguration(updated) + if err != nil { + t.Fatal(err) + } else if conf.RevisionTemplate.Spec.Container.Image != "gcr.io/foo/quux:xyzzy" { + t.Fatalf("wrong image set: %v", conf.RevisionTemplate.Spec.Container.Image) + } +}