diff --git a/go.mod b/go.mod index 5fcf24b8f3..d221227c49 100644 --- a/go.mod +++ b/go.mod @@ -50,6 +50,7 @@ require ( k8s.io/apiextensions-apiserver v0.20.2 k8s.io/apimachinery v0.20.2 k8s.io/client-go v0.20.2 + k8s.io/cli-runtime v0.20.2 k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027 k8s.io/klog/v2 v2.8.0 k8s.io/utils v0.0.0-20210111153108-fddb29f9d009 diff --git a/go.sum b/go.sum index f2f4172b0a..e5a95dae51 100644 --- a/go.sum +++ b/go.sum @@ -670,6 +670,8 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac h1:+2b6iGRJe3hvV/yVXrd41yVEjxuFHxasJqDhkIjS4gk= @@ -1631,6 +1633,8 @@ k8s.io/apiserver v0.19.2/go.mod h1:FreAq0bJ2vtZFj9Ago/X0oNGC51GfubKK/ViOKfVAOA= k8s.io/apiserver v0.19.7/go.mod h1:DmWVQggNePspa+vSsVytVbS3iBSDTXdJVt0akfHacKk= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.2/go.mod h1:2nKd93WyMhZx4Hp3RfgH2K5PhwyTrprrkWYnI7id7jA= +k8s.io/cli-runtime v0.20.2 h1:W0/FHdbApnl9oB7xdG643c/Zaf7TZT+43I+zKxwqvhU= +k8s.io/cli-runtime v0.20.2/go.mod h1:FjH6uIZZZP3XmwrXWeeYCbgxcrD6YXxoAykBaWH0VdM= k8s.io/client-go v0.17.4/go.mod h1:ouF6o5pz3is8qU0/qYL2RnoxOPqgfuidYLowytyLJmc= k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= k8s.io/client-go v0.18.6/go.mod h1:/fwtGLjYMS1MaM5oi+eXhKwG+1UHidUEXRh6cNsdO0Q= @@ -1734,6 +1738,7 @@ sigs.k8s.io/controller-runtime v0.6.4/go.mod h1:WlZNXcM0++oyaQt4B7C2lEE5JYRs8vJU sigs.k8s.io/controller-runtime v0.8.3 h1:GMHvzjTmaWHQB8HadW+dIvBoJuLvZObYJ5YoZruPRao= sigs.k8s.io/controller-runtime v0.8.3/go.mod h1:U/l+DUopBc1ecfRZ5aviA9JDmGFQKvLf5YkZNx2e0sU= sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI= +sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= diff --git a/pkg/cmd/bind.go b/pkg/cmd/bind.go index 277189984b..352551da17 100644 --- a/pkg/cmd/bind.go +++ b/pkg/cmd/bind.go @@ -31,6 +31,8 @@ import ( "github.com/spf13/cobra" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/cli-runtime/pkg/printers" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -47,8 +49,8 @@ func newCmdBind(rootCmdOptions *RootCmdOptions) (*cobra.Command, *bindCmdOptions if err := options.validate(cmd, args); err != nil { return err } - if err := options.run(args); err != nil { - fmt.Println(err.Error()) + if err := options.run(cmd, args); err != nil { + fmt.Fprintln(cmd.OutOrStdout(), string(err.Error())) } return nil @@ -124,7 +126,7 @@ func (o *bindCmdOptions) validate(cmd *cobra.Command, args []string) error { return nil } -func (o *bindCmdOptions) run(args []string) error { +func (o *bindCmdOptions) run(cmd *cobra.Command, args []string) error { source, err := o.decode(args[0], sourceKey) if err != nil { return err @@ -160,34 +162,15 @@ func (o *bindCmdOptions) run(args []string) error { } } - switch o.OutputFormat { - case "": - // continue.. - case "yaml": - data, err := kubernetes.ToYAML(&binding) - if err != nil { - return err - } - fmt.Print(string(data)) - return nil - - case "json": - data, err := kubernetes.ToJSON(&binding) - if err != nil { - return err - } - fmt.Print(string(data)) - return nil - - default: - return fmt.Errorf("invalid output format option '%s', should be one of: yaml|json", o.OutputFormat) - } - client, err := o.GetCmdClient() if err != nil { return err } + if o.OutputFormat != "" { + return showOutput(cmd, &binding, o.OutputFormat, client.GetScheme()) + } + existed := false err = client.Create(o.Context, &binding) if err != nil && k8serrors.IsAlreadyExists(err) { @@ -206,6 +189,14 @@ func (o *bindCmdOptions) run(args []string) error { return nil } +func showOutput(cmd *cobra.Command, binding *v1alpha1.KameletBinding, outputFormat string, scheme *runtime.Scheme) error { + printer := printers.NewTypeSetter(scheme) + printer.Delegate = &kubernetes.CLIPrinter{ + Format: outputFormat, + } + return printer.PrintObj(binding, cmd.OutOrStdout()) +} + func (o *bindCmdOptions) decode(res string, key string) (v1alpha1.Endpoint, error) { refConverter := reference.NewConverter(reference.KameletPrefix) endpoint := v1alpha1.Endpoint{} diff --git a/pkg/cmd/bind_test.go b/pkg/cmd/bind_test.go new file mode 100644 index 0000000000..8467d31f4f --- /dev/null +++ b/pkg/cmd/bind_test.go @@ -0,0 +1,84 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You 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 cmd + +import ( + "testing" + + "github.com/apache/camel-k/pkg/util/test" + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" +) + +const cmdBind = "bind" + +func initializeBindCmdOptions(t *testing.T) (*bindCmdOptions, *cobra.Command, RootCmdOptions) { + options, rootCmd := kamelTestPreAddCommandInit() + bindCmdOptions := addTestBindCmd(*options, rootCmd) + kamelTestPostAddCommandInit(t, rootCmd) + + return bindCmdOptions, rootCmd, *options +} + +func addTestBindCmd(options RootCmdOptions, rootCmd *cobra.Command) *bindCmdOptions { + //add a testing version of bind Command + bindCmd, bindOptions := newCmdBind(&options) + bindCmd.PersistentPreRunE = func(c *cobra.Command, args []string) error { + return nil + } + bindCmd.Args = test.ArbitraryArgs + rootCmd.AddCommand(bindCmd) + return bindOptions +} + +func TestBindOutputJSON(t *testing.T) { + buildCmdOptions, bindCmd, _ := initializeBindCmdOptions(t) + output, err := test.ExecuteCommand(bindCmd, cmdBind, "my:src", "my:dst", "-o", "json") + assert.Equal(t, "json", buildCmdOptions.OutputFormat) + + assert.Nil(t, err) + assert.Equal(t, `{"kind":"KameletBinding","apiVersion":"camel.apache.org/v1alpha1","metadata":{"name":"my-to-my","creationTimestamp":null},"spec":{"source":{"uri":"my:src"},"sink":{"uri":"my:dst"}},"status":{}}`, output) +} + +func TestBindOutputYAML(t *testing.T) { + buildCmdOptions, bindCmd, _ := initializeBindCmdOptions(t) + output, err := test.ExecuteCommand(bindCmd, cmdBind, "my:src", "my:dst", "-o", "yaml") + assert.Equal(t, "yaml", buildCmdOptions.OutputFormat) + + assert.Nil(t, err) + assert.Equal(t, `apiVersion: camel.apache.org/v1alpha1 +kind: KameletBinding +metadata: + creationTimestamp: null + name: my-to-my +spec: + sink: + uri: my:dst + source: + uri: my:src +status: {} +`, output) +} + +func TestBindOutputUnknownFormat(t *testing.T) { + buildCmdOptions, bindCmd, _ := initializeBindCmdOptions(t) + output, _ := test.ExecuteCommand(bindCmd, cmdBind, "my:src", "my:dst", "-o", "fail") + assert.Equal(t, "fail", buildCmdOptions.OutputFormat) + + assert.Equal(t, "invalid output format option 'fail', should be one of: yaml|json\n", output) +} diff --git a/pkg/util/kubernetes/printer.go b/pkg/util/kubernetes/printer.go new file mode 100644 index 0000000000..7b8e764fa5 --- /dev/null +++ b/pkg/util/kubernetes/printer.go @@ -0,0 +1,50 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You 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 kubernetes + +import ( + "fmt" + "io" + + "k8s.io/apimachinery/pkg/runtime" +) + +// CLIPrinter is delegated to print the runtime object +type CLIPrinter struct { + // It accepts either yaml or json format + Format string +} + +// PrintObj prints the obj in json|yaml format according to the type of the obj. +func (p *CLIPrinter) PrintObj(obj runtime.Object, output io.Writer) error { + var data []byte + var err error + switch p.Format { + case "yaml": + data, err = ToYAML(obj) + case "json": + data, err = ToJSON(obj) + default: + err = fmt.Errorf("invalid output format option '%s', should be one of: yaml|json", p.Format) + } + if err != nil { + return err + } + fmt.Fprintf(output, string(data)) + return nil +} diff --git a/pkg/util/kubernetes/util.go b/pkg/util/kubernetes/util.go index 232cf85cb4..317839fd22 100644 --- a/pkg/util/kubernetes/util.go +++ b/pkg/util/kubernetes/util.go @@ -24,10 +24,12 @@ import ( "github.com/apache/camel-k/pkg/util" ) +// ToJSON marshal to json format func ToJSON(value runtime.Object) ([]byte, error) { return json.Marshal(value) } +// ToYAML marshal to yaml format func ToYAML(value runtime.Object) ([]byte, error) { data, err := ToJSON(value) if err != nil {