From c22d627642caca77a5812d35230a3526ee6e70c2 Mon Sep 17 00:00:00 2001 From: Pasquale Congiusti Date: Wed, 13 Apr 2022 11:10:31 +0200 Subject: [PATCH] feat(cli): disconnected run and bind If we detect the -o option, then the CLI goes in offline mode, allowing to be used without a K8S cluster. Closes #3021 --- pkg/cmd/bind.go | 40 ++++++++++++++++++++++++++-------------- pkg/cmd/bind_test.go | 3 --- pkg/cmd/run.go | 42 +++++++++++++++++++++++++++--------------- pkg/cmd/run_test.go | 15 ++++++--------- 4 files changed, 59 insertions(+), 41 deletions(-) diff --git a/pkg/cmd/bind.go b/pkg/cmd/bind.go index 51bbe92bc8..3ab20c67b3 100644 --- a/pkg/cmd/bind.go +++ b/pkg/cmd/bind.go @@ -43,20 +43,13 @@ func newCmdBind(rootCmdOptions *RootCmdOptions) (*cobra.Command, *bindCmdOptions RootCmdOptions: rootCmdOptions, } cmd := cobra.Command{ - Use: "bind [source] [sink] ...", - Short: "Bind Kubernetes resources, such as Kamelets, in an integration flow.", - Long: "Bind Kubernetes resources, such as Kamelets, in an integration flow. Endpoints are expected in the format \"[[apigroup/]version:]kind:[namespace/]name\" or plain Camel URIs.", - PreRunE: decode(&options), - RunE: func(cmd *cobra.Command, args []string) error { - if err := options.validate(cmd, args); err != nil { - return err - } - if err := options.run(cmd, args); err != nil { - fmt.Fprintln(cmd.OutOrStdout(), err.Error()) - } - - return nil - }, + Use: "bind [source] [sink] ...", + Short: "Bind Kubernetes resources, such as Kamelets, in an integration flow.", + Long: "Bind Kubernetes resources, such as Kamelets, in an integration flow. Endpoints are expected in the format \"[[apigroup/]version:]kind:[namespace/]name\" or plain Camel URIs.", + PersistentPreRunE: decode(&options), + PreRunE: options.preRunE, + RunE: options.runE, + Annotations: make(map[string]string), } cmd.Flags().StringArrayP("connect", "c", nil, "A ServiceBinding or Provisioned Service that the integration should bind to, specified as [[apigroup/]version:]kind:[namespace/]name") @@ -90,6 +83,25 @@ type bindCmdOptions struct { Traits []string `mapstructure:"traits" yaml:",omitempty"` } +func (o *bindCmdOptions) preRunE(cmd *cobra.Command, args []string) error { + if o.OutputFormat != "" { + // let the command to work in offline mode + cmd.Annotations[offlineCommandLabel] = "true" + } + return o.RootCmdOptions.preRun(cmd, args) +} + +func (o *bindCmdOptions) runE(cmd *cobra.Command, args []string) error { + if err := o.validate(cmd, args); err != nil { + return err + } + if err := o.run(cmd, args); err != nil { + fmt.Fprintln(cmd.OutOrStdout(), err.Error()) + } + + return nil +} + func (o *bindCmdOptions) validate(cmd *cobra.Command, args []string) error { if len(args) > 2 { return errors.New("too many arguments: expected source and sink") diff --git a/pkg/cmd/bind_test.go b/pkg/cmd/bind_test.go index d1c396a8b2..72600ab6b9 100644 --- a/pkg/cmd/bind_test.go +++ b/pkg/cmd/bind_test.go @@ -41,9 +41,6 @@ func initializeBindCmdOptions(t *testing.T) (*bindCmdOptions, *cobra.Command, Ro 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 diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go index 247d9e1a50..384b73bbd3 100644 --- a/pkg/cmd/run.go +++ b/pkg/cmd/run.go @@ -81,13 +81,15 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) (*cobra.Command, *runCmdOptions) } cmd := cobra.Command{ - Use: "run [file to run]", - Short: "Run a integration on Kubernetes", - Long: `Deploys and execute a integration pod on Kubernetes.`, - Args: options.validateArgs, - PreRunE: options.decode, - RunE: options.run, - PostRunE: options.postRun, + Use: "run [file to run]", + Short: "Run a integration on Kubernetes", + Long: `Deploys and execute a integration pod on Kubernetes.`, + Args: options.validateArgs, + PersistentPreRunE: options.decode, + PreRunE: options.preRunE, + RunE: options.run, + PostRunE: options.postRun, + Annotations: make(map[string]string), } cmd.Flags().String("name", "", "The integration name") @@ -154,6 +156,14 @@ type runCmdOptions struct { Sources []string `mapstructure:"sources" yaml:",omitempty"` } +func (o *runCmdOptions) preRunE(cmd *cobra.Command, args []string) error { + if o.OutputFormat != "" { + // let the command to work in offline mode + cmd.Annotations[offlineCommandLabel] = "true" + } + return o.RootCmdOptions.preRun(cmd, args) +} + func (o *runCmdOptions) decode(cmd *cobra.Command, args []string) error { // ************************************************************************* // @@ -492,14 +502,16 @@ func (o *runCmdOptions) createOrUpdateIntegration(cmd *cobra.Command, c client.C } existing := &v1.Integration{} - err := c.Get(o.Context, ctrl.ObjectKeyFromObject(integration), existing) - switch { - case err == nil: - integration = existing.DeepCopy() - case k8serrors.IsNotFound(err): - existing = nil - default: - return nil, err + if !isOfflineCommand(cmd) { + err := c.Get(o.Context, ctrl.ObjectKeyFromObject(integration), existing) + switch { + case err == nil: + integration = existing.DeepCopy() + case k8serrors.IsNotFound(err): + existing = nil + default: + return nil, err + } } var integrationKit *corev1.ObjectReference diff --git a/pkg/cmd/run_test.go b/pkg/cmd/run_test.go index b865fb7ce4..be71a84255 100644 --- a/pkg/cmd/run_test.go +++ b/pkg/cmd/run_test.go @@ -76,9 +76,6 @@ func addTestRunCmd(options RootCmdOptions, rootCmd *cobra.Command) *runCmdOption func addTestRunCmdWithOutput(options RootCmdOptions, rootCmd *cobra.Command) *runCmdOptions { // add a testing version of run Command with output runCmd, runOptions := newCmdRun(&options) - runCmd.PersistentPreRunE = func(c *cobra.Command, args []string) error { - return nil - } runCmd.Args = test.ArbitraryArgs rootCmd.AddCommand(runCmd) return runOptions @@ -604,9 +601,9 @@ func TestOutputYaml(t *testing.T) { assert.Nil(t, ioutil.WriteFile(tmpFile.Name(), []byte(TestSrcContent), 0o400)) fileName := filepath.Base(tmpFile.Name()) - buildCmdOptions, runCmd, _ := initializeRunCmdOptionsWithOutput(t) + runCmdOptions, runCmd, _ := initializeRunCmdOptionsWithOutput(t) output, err := test.ExecuteCommand(runCmd, cmdRun, tmpFile.Name(), "-o", "yaml") - assert.Equal(t, "yaml", buildCmdOptions.OutputFormat) + assert.Equal(t, "yaml", runCmdOptions.OutputFormat) assert.Nil(t, err) assert.Equal(t, fmt.Sprintf(`apiVersion: camel.apache.org/v1 @@ -635,9 +632,9 @@ func TestTrait(t *testing.T) { assert.Nil(t, ioutil.WriteFile(tmpFile.Name(), []byte(TestSrcContent), 0o400)) fileName := filepath.Base(tmpFile.Name()) - buildCmdOptions, runCmd, _ := initializeRunCmdOptionsWithOutput(t) + runCmdOptions, runCmd, _ := initializeRunCmdOptionsWithOutput(t) output, err := test.ExecuteCommand(runCmd, cmdRun, tmpFile.Name(), "-o", "yaml", "-t", "mount.configs=configmap:my-cm", "--connect", "my-service-binding") - assert.Equal(t, "yaml", buildCmdOptions.OutputFormat) + assert.Equal(t, "yaml", runCmdOptions.OutputFormat) assert.Nil(t, err) assert.Equal(t, fmt.Sprintf(`apiVersion: camel.apache.org/v1 @@ -674,9 +671,9 @@ func TestMissingTrait(t *testing.T) { assert.Nil(t, tmpFile.Close()) assert.Nil(t, ioutil.WriteFile(tmpFile.Name(), []byte(TestSrcContent), 0o400)) - buildCmdOptions, runCmd, _ := initializeRunCmdOptionsWithOutput(t) + runCmdOptions, runCmd, _ := initializeRunCmdOptionsWithOutput(t) output, err := test.ExecuteCommand(runCmd, cmdRun, tmpFile.Name(), "-o", "yaml", "-t", "bogus.fail=i-must-fail") - assert.Equal(t, "yaml", buildCmdOptions.OutputFormat) + assert.Equal(t, "yaml", runCmdOptions.OutputFormat) assert.Equal(t, "Error: bogus.fail=i-must-fail is not a valid trait property\n", output) assert.NotNil(t, err) }