From 413faa8774d7ed4003acf0417b7b21f17d966783 Mon Sep 17 00:00:00 2001 From: Tadayoshi Sato Date: Wed, 14 Dec 2022 17:25:31 +0900 Subject: [PATCH 1/2] fix(cmd): refactor install cmd to remove maintidx lint --- pkg/cmd/install.go | 609 ++++++++++++++++++++------------------ pkg/install/cluster.go | 55 ++-- pkg/install/operator.go | 8 +- pkg/util/olm/available.go | 2 +- 4 files changed, 369 insertions(+), 305 deletions(-) diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go index fccea5ba87..002e53d45d 100644 --- a/pkg/cmd/install.go +++ b/pkg/cmd/install.go @@ -215,16 +215,53 @@ type installCmdOptions struct { olmOptions olm.Options } -// nolint: gocyclo,maintidx // TODO: refactor the code -func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error { - var collection *kubernetes.Collection +func (o *installCmdOptions) install(cmd *cobra.Command, _ []string) error { + var output *kubernetes.Collection if o.OutputFormat != "" { - collection = kubernetes.NewCollection() + output = kubernetes.NewCollection() } // Let's use a client provider during cluster installation, to eliminate the problem of CRD object caching clientProvider := client.Provider{Get: o.NewCmdClient} + o.setupEnvVars() + + installViaOLM := false + if o.Olm { + installed, err := o.tryInstallViaOLM(cmd, clientProvider, output) + if err != nil { + return err + } + installViaOLM = installed + } + + if !o.SkipClusterSetup && !installViaOLM { + if err := install.SetupClusterWideResourcesOrCollect(o.Context, clientProvider, + output, o.ClusterType, o.Force); err != nil { + if k8serrors.IsForbidden(err) { + fmt.Fprintln(cmd.OutOrStdout(), + "Current user is not authorized to create cluster-wide objects like custom resource definitions or cluster roles:", + err) + msg := `please login as cluster-admin and execute "kamel install --cluster-setup" to install cluster-wide resources (one-time operation)` + return errors.New(msg) + } + return err + } + } + + if o.ClusterSetupOnly { + if output != nil { + return o.printOutput(cmd, output) + } + fmt.Fprintln(cmd.OutOrStdout(), "Camel K cluster setup completed successfully") + return nil + } + + return o.installOperator(cmd, output, installViaOLM) +} + +// setupEnvVars sets up additional env vars from the command options. +func (o *installCmdOptions) setupEnvVars() { // --operator-id={id} is a syntax sugar for '--operator-env-vars KAMEL_OPERATOR_ID={id}' o.EnvVars = append(o.EnvVars, fmt.Sprintf("KAMEL_OPERATOR_ID=%s", strings.TrimSpace(o.OperatorID))) @@ -237,347 +274,342 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error { if len(o.LogLevel) > 0 { o.EnvVars = append(o.EnvVars, fmt.Sprintf("LOG_LEVEL=%s", strings.TrimSpace(o.LogLevel))) } +} - installViaOLM := false - if o.Olm { - var err error - var olmClient client.Client - if olmClient, err = clientProvider.Get(); err != nil { - return err - } - var olmAvailable bool - if olmAvailable, err = olm.IsAPIAvailable(o.Context, olmClient, o.Namespace); err != nil { - return errors.Wrap(err, "error while checking OLM availability. Run with '--olm=false' to skip this check") - } - if olmAvailable { - if installViaOLM, err = olm.HasPermissionToInstall(o.Context, olmClient, o.Namespace, o.Global, o.olmOptions); err != nil { - return errors.Wrap(err, "error while checking permissions to install operator via OLM. Run with '--olm=false' to skip this check") - } - if !installViaOLM { - fmt.Fprintln(cobraCmd.OutOrStdout(), "OLM is available but current user has not enough permissions to create the operator. "+ - "You can either ask your administrator to provide permissions (preferred) or run the install command with the `--olm=false` flag.") - os.Exit(1) - } - } else { - fmt.Fprintln(cobraCmd.OutOrStdout(), "OLM is not available in the cluster. Fallback to regular installation.") - } +func (o *installCmdOptions) tryInstallViaOLM( + cmd *cobra.Command, clientProvider client.Provider, output *kubernetes.Collection, +) (bool, error) { + olmClient, err := clientProvider.Get() + if err != nil { + return false, err + } + if olmAvailable, err := olm.IsAPIAvailable(o.Context, olmClient, o.Namespace); err != nil { + return false, errors.Wrap(err, + "error while checking OLM availability. Run with '--olm=false' to skip this check") + } else if !olmAvailable { + fmt.Fprintln(cmd.OutOrStdout(), "OLM is not available in the cluster. Fallback to regular installation.") + return false, nil + } - if installViaOLM { - fmt.Fprintln(cobraCmd.OutOrStdout(), "OLM is available in the cluster") - var installed bool - if installed, err = olm.Install(o.Context, olmClient, o.Namespace, o.Global, o.olmOptions, collection, - o.Tolerations, o.NodeSelectors, o.ResourcesRequirements, o.EnvVars); err != nil { - return err - } - if !installed { - fmt.Fprintln(cobraCmd.OutOrStdout(), "OLM resources are already available: skipping installation") - } + if hasPermission, err := olm.HasPermissionToInstall(o.Context, olmClient, + o.Namespace, o.Global, o.olmOptions); err != nil { + return false, errors.Wrap(err, + "error while checking permissions to install operator via OLM. Run with '--olm=false' to skip this check") + } else if !hasPermission { + return false, errors.New( + "OLM is available but current user has not enough permissions to create the operator. " + + "You can either ask your administrator to provide permissions (preferred) " + + "or run the install command with the '--olm=false' flag.") + } - if err = install.WaitForAllCrdInstallation(o.Context, clientProvider, 90*time.Second); err != nil { - return err - } - } + // Install or collect via OLM + fmt.Fprintln(cmd.OutOrStdout(), "OLM is available in the cluster") + if installed, err := olm.Install(o.Context, olmClient, o.Namespace, o.Global, o.olmOptions, output, + o.Tolerations, o.NodeSelectors, o.ResourcesRequirements, o.EnvVars); err != nil { + return false, err + } else if !installed { + fmt.Fprintln(cmd.OutOrStdout(), "OLM resources are already available; skipping installation") } - if !o.SkipClusterSetup && !installViaOLM { - err := install.SetupClusterWideResourcesOrCollect(o.Context, clientProvider, collection, o.ClusterType, o.Force) - if err != nil && k8serrors.IsForbidden(err) { - fmt.Fprintln(cobraCmd.OutOrStdout(), "Current user is not authorized to create cluster-wide objects like custom resource definitions or cluster roles: ", err) + if err := install.WaitForAllCrdInstallation(o.Context, clientProvider, 90*time.Second); err != nil { + return false, err + } - meg := `please login as cluster-admin and execute "kamel install --cluster-setup" to install cluster-wide resources (one-time operation)` - return errors.New(meg) - } else if err != nil { - return err - } + return true, nil +} + +func (o *installCmdOptions) installOperator(cmd *cobra.Command, output *kubernetes.Collection, olm bool) error { + operatorID, err := getOperatorID(o.EnvVars) + if err != nil { + return err } - if o.ClusterSetupOnly { - if collection == nil { - fmt.Fprintln(cobraCmd.OutOrStdout(), "Camel K cluster setup completed successfully") - } + c, err := o.GetCmdClient() + if err != nil { + return err + } + + namespace := o.Namespace + + var platformName string + if operatorID != "" { + platformName = operatorID } else { - operatorID, err := getOperatorID(o.EnvVars) - if err != nil { - return err + platformName = platformutil.DefaultPlatformName + } + + // Set up operator + if !olm { + if !o.SkipOperatorSetup { + if err := o.setupOperator(cmd, c, namespace, platformName, output); err != nil { + return err + } + } else { + fmt.Fprintln(cmd.OutOrStdout(), "Camel K operator installation skipped") } + } - c, err := o.GetCmdClient() + // Set up registry secret + registrySecretName := "" + if !o.SkipRegistrySetup { + registrySecretName, err = o.setupRegistrySecret(c, namespace, output) if err != nil { return err } + } else { + fmt.Fprintln(cmd.OutOrStdout(), "Camel K operator registry setup skipped") + } - namespace := o.Namespace - - var platformName string - if operatorID != "" { - platformName = operatorID - } else { - platformName = platformutil.DefaultPlatformName - } + // Set up IntegrationPlatform + platform, err := o.setupIntegrationPlatform(cmd, c, namespace, platformName, registrySecretName, output) + if err != nil { + return err + } - if !o.SkipOperatorSetup && !installViaOLM { - if ok, err := isInstallAllowed(o.Context, c, platformName, o.Force, cobraCmd.OutOrStdout()); err != nil { - if k8serrors.IsForbidden(err) { - o.PrintfVerboseOutf(cobraCmd, "Unable to verify existence of operator id [%s] due to lack of user privileges\n", platformName) - } else { - return err - } - } else if !ok { - return fmt.Errorf("installation not allowed because operator with id '%s' already exists, use the --force option to skip this check", platformName) - } + if output != nil { + return o.printOutput(cmd, output) + } - cfg := install.OperatorConfiguration{ - CustomImage: o.OperatorImage, - CustomImagePullPolicy: o.OperatorImagePullPolicy, - Namespace: namespace, - Global: o.Global, - ClusterType: o.ClusterType, - Health: install.OperatorHealthConfiguration{ - Port: o.HealthPort, - }, - Monitoring: install.OperatorMonitoringConfiguration{ - Enabled: o.Monitoring, - Port: o.MonitoringPort, - }, - Tolerations: o.Tolerations, - NodeSelectors: o.NodeSelectors, - ResourcesRequirements: o.ResourcesRequirements, - EnvVars: o.EnvVars, - } - err = install.OperatorOrCollect(o.Context, cobraCmd, c, cfg, collection, o.Force) - if err != nil { - return err - } - } else if o.SkipOperatorSetup { - fmt.Fprintln(cobraCmd.OutOrStdout(), "Camel K operator installation skipped") + if o.Wait { + if err := o.waitForPlatformReady(cmd, platform); err != nil { + return err } + } - generatedSecretName := "" + strategy := "" + if olm { + strategy = "via OLM subscription" + } + if o.Global { + fmt.Fprintln(cmd.OutOrStdout(), "Camel K installed in namespace", namespace, strategy, "(global mode)") + } else { + fmt.Fprintln(cmd.OutOrStdout(), "Camel K installed in namespace", namespace, strategy) + } - if !o.SkipRegistrySetup { - if o.registryAuth.IsSet() { - regData := o.registryAuth - regData.Registry = o.registry.Address - generatedSecretName, err = install.RegistrySecretOrCollect(o.Context, c, namespace, regData, collection, o.Force) - if err != nil { - return err - } - } else if o.RegistryAuthFile != "" { - generatedSecretName, err = install.RegistrySecretFromFileOrCollect(o.Context, c, namespace, o.RegistryAuthFile, collection, o.Force) - if err != nil { - return err - } - } - } else if o.SkipRegistrySetup { - fmt.Fprintln(cobraCmd.OutOrStdout(), "Camel K operator registry setup skipped") + return nil +} + +func getOperatorID(vars []string) (string, error) { + envs, _, _, err := env.ParseEnv(vars, nil) + if err != nil { + return "", err + } + for _, e := range envs { + if e.Name == "KAMEL_OPERATOR_ID" { + return e.Value, nil } + } - platform, err := install.NewPlatform(o.Context, c, o.ClusterType, o.SkipRegistrySetup, o.registry, platformName) - if err != nil { + return "", nil +} + +func (o *installCmdOptions) setupOperator( + cmd *cobra.Command, c client.Client, namespace string, platformName string, output *kubernetes.Collection, +) error { + if ok, err := isInstallAllowed(o.Context, c, platformName, o.Force, cmd.OutOrStdout()); err != nil { + if k8serrors.IsForbidden(err) { + o.PrintfVerboseOutf(cmd, + "Unable to verify existence of operator id %q due to lack of user privileges\n", + platformName) + } else { return err } + } else if !ok { + return fmt.Errorf( + "installation not allowed because operator with id %q already exists; use the --force option to skip this check", + platformName) + } - if generatedSecretName != "" { - platform.Spec.Build.Registry.Secret = generatedSecretName - } + cfg := install.OperatorConfiguration{ + CustomImage: o.OperatorImage, + CustomImagePullPolicy: o.OperatorImagePullPolicy, + Namespace: namespace, + Global: o.Global, + ClusterType: o.ClusterType, + Health: install.OperatorHealthConfiguration{ + Port: o.HealthPort, + }, + Monitoring: install.OperatorMonitoringConfiguration{ + Enabled: o.Monitoring, + Port: o.MonitoringPort, + }, + Tolerations: o.Tolerations, + NodeSelectors: o.NodeSelectors, + ResourcesRequirements: o.ResourcesRequirements, + EnvVars: o.EnvVars, + } - if len(o.MavenProperties) > 0 { - platform.Spec.Build.Maven.Properties = make(map[string]string) - for _, property := range o.MavenProperties { - kv := strings.Split(property, "=") - if len(kv) == 2 { - platform.Spec.Build.Maven.Properties[kv[0]] = kv[1] - } - } - } + return install.OperatorOrCollect(o.Context, cmd, c, cfg, output, o.Force) +} - if size := len(o.MavenExtensions); size > 0 { - platform.Spec.Build.Maven.Extension = make([]v1.MavenArtifact, 0, size) - for _, extension := range o.MavenExtensions { - gav := strings.Split(extension, ":") - if len(gav) != 2 && len(gav) != 3 { - meg := fmt.Sprintf("Maven build extension GAV must match ::, found: %s", extension) - return errors.New(meg) - } - ext := v1.MavenArtifact{ - GroupID: gav[0], - ArtifactID: gav[1], - } - if len(gav) == 3 { - ext.Version = gav[2] - } - platform.Spec.Build.Maven.Extension = append(platform.Spec.Build.Maven.Extension, ext) - } - } +func isInstallAllowed(ctx context.Context, c client.Client, operatorID string, force bool, out io.Writer) (bool, error) { + // find existing platform with given name in any namespace + pl, err := platformutil.LookupForPlatformName(ctx, c, operatorID) - if o.MavenLocalRepository != "" { - platform.Spec.Build.Maven.LocalRepository = o.MavenLocalRepository - } + if pl != nil && force { + fmt.Fprintf(out, "Overwriting existing operator with id %q\n", operatorID) + return true, nil + } - if len(o.MavenCLIOptions) > 0 { - platform.Spec.Build.Maven.CLIOptions = o.MavenCLIOptions - } + // only allow installation when platform with given name is not found + return pl == nil, err +} - if o.RuntimeVersion != "" { - platform.Spec.Build.RuntimeVersion = o.RuntimeVersion - } - if o.BaseImage != "" { - platform.Spec.Build.BaseImage = o.BaseImage - } - if o.BuildStrategy != "" { - platform.Spec.Build.BuildStrategy = v1.BuildStrategy(o.BuildStrategy) - } - if o.BuildPublishStrategy != "" { - platform.Spec.Build.PublishStrategy = v1.IntegrationPlatformBuildPublishStrategy(o.BuildPublishStrategy) - } - if o.BuildTimeout != "" { - d, err := time.ParseDuration(o.BuildTimeout) - if err != nil { - return err - } +func (o *installCmdOptions) setupRegistrySecret(c client.Client, namespace string, output *kubernetes.Collection) (string, error) { + if o.registryAuth.IsSet() { + regData := o.registryAuth + regData.Registry = o.registry.Address + return install.RegistrySecretOrCollect(o.Context, c, namespace, regData, output, o.Force) + } else if o.RegistryAuthFile != "" { + return install.RegistrySecretFromFileOrCollect(o.Context, c, namespace, o.RegistryAuthFile, output, o.Force) + } + + return "", nil +} + +func (o *installCmdOptions) setupIntegrationPlatform( + cmd *cobra.Command, c client.Client, namespace string, platformName string, registrySecretName string, + output *kubernetes.Collection, +) (*v1.IntegrationPlatform, error) { + platform, err := install.NewPlatform(o.Context, c, o.ClusterType, o.SkipRegistrySetup, o.registry, platformName) + if err != nil { + return nil, err + } + + if registrySecretName != "" { + platform.Spec.Build.Registry.Secret = registrySecretName + } - platform.Spec.Build.Timeout = &metav1.Duration{ - Duration: d, + if len(o.MavenProperties) > 0 { + platform.Spec.Build.Maven.Properties = make(map[string]string) + for _, property := range o.MavenProperties { + kv := strings.Split(property, "=") + if len(kv) == 2 { + platform.Spec.Build.Maven.Properties[kv[0]] = kv[1] } } - if o.TraitProfile != "" { - platform.Spec.Profile = v1.TraitProfileByName(o.TraitProfile) - } - - if len(o.MavenRepositories) > 0 { - settings, err := maven.NewSettings(maven.Repositories(o.MavenRepositories...), maven.DefaultRepositories) + } - if err != nil { - return err + if size := len(o.MavenExtensions); size > 0 { + platform.Spec.Build.Maven.Extension = make([]v1.MavenArtifact, 0, size) + for _, extension := range o.MavenExtensions { + gav := strings.Split(extension, ":") + if len(gav) != 2 && len(gav) != 3 { + msg := fmt.Sprintf("Maven build extension GAV must match ::, found: %s", extension) + return nil, errors.New(msg) } - err = createDefaultMavenSettingsConfigMap(o.Context, c, namespace, platform.Name, settings) - if err != nil { - return err + ext := v1.MavenArtifact{ + GroupID: gav[0], + ArtifactID: gav[1], } - platform.Spec.Build.Maven.Settings.ConfigMapKeyRef = &corev1.ConfigMapKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: platform.Name + "-maven-settings", - }, - Key: "settings.xml", + if len(gav) == 3 { + ext.Version = gav[2] } + platform.Spec.Build.Maven.Extension = append(platform.Spec.Build.Maven.Extension, ext) } + } - if o.MavenSettings != "" { - mavenSettings, err := decodeMavenSettings(o.MavenSettings) - if err != nil { - return err - } - platform.Spec.Build.Maven.Settings = mavenSettings - } + if o.MavenLocalRepository != "" { + platform.Spec.Build.Maven.LocalRepository = o.MavenLocalRepository + } - if o.MavenCASecret != "" { - secret, err := decodeSecretKeySelector(o.MavenCASecret) - if err != nil { - return err - } - platform.Spec.Build.Maven.CASecrets = append(platform.Spec.Build.Maven.CASecrets, *secret) - } + if len(o.MavenCLIOptions) > 0 { + platform.Spec.Build.Maven.CLIOptions = o.MavenCLIOptions + } - if o.ClusterType != "" { - for _, c := range v1.AllIntegrationPlatformClusters { - if strings.EqualFold(string(c), o.ClusterType) { - platform.Spec.Cluster = c - } - } + if o.RuntimeVersion != "" { + platform.Spec.Build.RuntimeVersion = o.RuntimeVersion + } + if o.BaseImage != "" { + platform.Spec.Build.BaseImage = o.BaseImage + } + if o.BuildStrategy != "" { + platform.Spec.Build.BuildStrategy = v1.BuildStrategy(o.BuildStrategy) + } + if o.BuildPublishStrategy != "" { + platform.Spec.Build.PublishStrategy = v1.IntegrationPlatformBuildPublishStrategy(o.BuildPublishStrategy) + } + if o.BuildTimeout != "" { + d, err := time.ParseDuration(o.BuildTimeout) + if err != nil { + return nil, err } - if platform.Spec.Build.PublishStrategy == v1.IntegrationPlatformBuildPublishStrategyKaniko && cobraCmd.Flags().Lookup("kaniko-build-cache").Changed { - fmt.Fprintln(cobraCmd.OutOrStdout(), "Warn: the flag --kaniko-build-cache is deprecated, use --build-publish-strategy-option KanikoBuildCacheEnabled=true instead") - platform.Spec.Build.AddOption(builder.KanikoBuildCacheEnabled, strconv.FormatBool(o.KanikoBuildCache)) + + platform.Spec.Build.Timeout = &metav1.Duration{ + Duration: d, } - if len(o.BuildPublishStrategyOptions) > 0 { - if err = o.addBuildPublishStrategyOptions(&platform.Spec.Build); err != nil { - return err - } + } + if o.TraitProfile != "" { + platform.Spec.Profile = v1.TraitProfileByName(o.TraitProfile) + } + + if len(o.MavenRepositories) > 0 { + settings, err := maven.NewSettings(maven.Repositories(o.MavenRepositories...), maven.DefaultRepositories) + if err != nil { + return nil, err } - // Always create a platform in the namespace where the operator is located - err = install.ObjectOrCollect(o.Context, c, namespace, collection, o.Force, platform) + err = createDefaultMavenSettingsConfigMap(o.Context, c, namespace, platform.Name, settings) if err != nil { - return err + return nil, err } - - if err := install.IntegrationPlatformViewerRole(o.Context, c, namespace); err != nil && !k8serrors.IsAlreadyExists(err) { - return errors.Wrap(err, "Error while installing global IntegrationPlatform viewer role") + platform.Spec.Build.Maven.Settings.ConfigMapKeyRef = &corev1.ConfigMapKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: platform.Name + "-maven-settings", + }, + Key: "settings.xml", } + } - if o.ExampleSetup { - err = install.ExampleOrCollect(o.Context, c, namespace, collection, o.Force) - if err != nil { - return err - } + if o.MavenSettings != "" { + mavenSettings, err := decodeMavenSettings(o.MavenSettings) + if err != nil { + return nil, err } + platform.Spec.Build.Maven.Settings = mavenSettings + } - if collection == nil { - if o.Wait { - err = o.waitForPlatformReady(cobraCmd, platform) - if err != nil { - return err - } - } + if o.MavenCASecret != "" { + secret, err := decodeSecretKeySelector(o.MavenCASecret) + if err != nil { + return nil, err + } + platform.Spec.Build.Maven.CASecrets = append(platform.Spec.Build.Maven.CASecrets, *secret) + } - strategy := "" - if installViaOLM { - strategy = "via OLM subscription" - } - if o.Global { - fmt.Fprintln(cobraCmd.OutOrStdout(), "Camel K installed in namespace", namespace, strategy, "(global mode)") - } else { - fmt.Fprintln(cobraCmd.OutOrStdout(), "Camel K installed in namespace", namespace, strategy) + if o.ClusterType != "" { + for _, c := range v1.AllIntegrationPlatformClusters { + if strings.EqualFold(string(c), o.ClusterType) { + platform.Spec.Cluster = c } } } - - if collection != nil { - return o.printOutput(cobraCmd, collection) + if platform.Spec.Build.PublishStrategy == v1.IntegrationPlatformBuildPublishStrategyKaniko && cmd.Flags().Lookup("kaniko-build-cache").Changed { + fmt.Fprintln(cmd.OutOrStdout(), "Warn: the flag --kaniko-build-cache is deprecated, use --build-publish-strategy-option KanikoBuildCacheEnabled=true instead") + platform.Spec.Build.AddOption(builder.KanikoBuildCacheEnabled, strconv.FormatBool(o.KanikoBuildCache)) } - - return nil -} - -func isInstallAllowed(ctx context.Context, c client.Client, operatorID string, force bool, out io.Writer) (bool, error) { - // find existing platform with given name in any namespace - pl, err := platformutil.LookupForPlatformName(ctx, c, operatorID) - - if pl != nil && force { - fmt.Fprintf(out, "Overwriting existing operator with id '%s'\n", operatorID) - return true, nil + if len(o.BuildPublishStrategyOptions) > 0 { + if err = o.addBuildPublishStrategyOptions(&platform.Spec.Build); err != nil { + return nil, err + } } - - // only allow installation when platform with given name is not found - return pl == nil, err -} - -func getOperatorID(vars []string) (string, error) { - envs, _, _, err := env.ParseEnv(vars, nil) + // Always create a platform in the namespace where the operator is located + err = install.ObjectOrCollect(o.Context, c, namespace, output, o.Force, platform) if err != nil { - return "", err - } - for _, e := range envs { - if e.Name == "KAMEL_OPERATOR_ID" { - return e.Value, nil - } + return nil, err } - return "", nil -} + if err := install.IntegrationPlatformViewerRole(o.Context, c, namespace); err != nil && !k8serrors.IsAlreadyExists(err) { + return nil, errors.Wrap(err, "Error while installing global IntegrationPlatform viewer role") + } -func (o *installCmdOptions) postRun(cmd *cobra.Command, _ []string) error { - if o.Save { - cfg, err := LoadConfiguration() + if o.ExampleSetup { + err = install.ExampleOrCollect(o.Context, c, namespace, output, o.Force) if err != nil { - return err + return nil, err } - - cfg.Update(cmd, pathToRoot(cmd), o, true) - - return cfg.Save() } - return nil + return platform, nil } func (o *installCmdOptions) printOutput(cmd *cobra.Command, collection *kubernetes.Collection) error { @@ -623,6 +655,21 @@ func (o *installCmdOptions) waitForPlatformReady(cmd *cobra.Command, platform *v return watch.HandlePlatformStateChanges(o.Context, c, platform, handler) } +func (o *installCmdOptions) postRun(cmd *cobra.Command, _ []string) error { + if o.Save { + cfg, err := LoadConfiguration() + if err != nil { + return err + } + + cfg.Update(cmd, pathToRoot(cmd), o, true) + + return cfg.Save() + } + + return nil +} + func (o *installCmdOptions) decode(cmd *cobra.Command, _ []string) error { path := pathToRoot(cmd) if err := decodeKey(o, path); err != nil { diff --git a/pkg/install/cluster.go b/pkg/install/cluster.go index 5eb0c26b90..fd704759a6 100644 --- a/pkg/install/cluster.go +++ b/pkg/install/cluster.go @@ -40,7 +40,10 @@ import ( ) // nolint: maintidx // TODO: refactor the code -func SetupClusterWideResourcesOrCollect(ctx context.Context, clientProvider client.Provider, collection *kubernetes.Collection, clusterType string, force bool) error { +func SetupClusterWideResourcesOrCollect( + ctx context.Context, clientProvider client.Provider, + collection *kubernetes.Collection, clusterType string, force bool, +) error { // Get a client to install the CRD c, err := clientProvider.Get() if err != nil { @@ -48,23 +51,22 @@ func SetupClusterWideResourcesOrCollect(ctx context.Context, clientProvider clie } isAPIExtensionsV1 := true - _, err = c.Discovery().ServerResourcesForGroupVersion("apiextensions.k8s.io/v1") - if err != nil && k8serrors.IsNotFound(err) { - isAPIExtensionsV1 = false - } else if err != nil { - return err + if _, err := c.Discovery().ServerResourcesForGroupVersion("apiextensions.k8s.io/v1"); err != nil { + if k8serrors.IsNotFound(err) { + isAPIExtensionsV1 = false + } else { + return err + } } // Convert the CRD to apiextensions.k8s.io/v1beta1 in case v1 is not available. // This is mainly required to support OpenShift 3, and older versions of Kubernetes. // It can be removed as soon as these versions are not supported anymore. - err = apiextensionsv1.AddToScheme(c.GetScheme()) - if err != nil { + if err := apiextensionsv1.AddToScheme(c.GetScheme()); err != nil { return err } if !isAPIExtensionsV1 { - err = apiextensionsv1beta1.AddToScheme(c.GetScheme()) - if err != nil { + if err := apiextensionsv1beta1.AddToScheme(c.GetScheme()); err != nil { return err } } @@ -114,37 +116,44 @@ func SetupClusterWideResourcesOrCollect(ctx context.Context, clientProvider clie } // Install CRD for Integration Platform (if needed) - if err := installCRD(ctx, c, "IntegrationPlatform", "v1", "camel.apache.org_integrationplatforms.yaml", downgradeToCRDv1beta1, collection, force); err != nil { + if err := installCRD(ctx, c, "IntegrationPlatform", "v1", "camel.apache.org_integrationplatforms.yaml", + downgradeToCRDv1beta1, collection, force); err != nil { return err } // Install CRD for Integration Kit (if needed) - if err := installCRD(ctx, c, "IntegrationKit", "v1", "camel.apache.org_integrationkits.yaml", downgradeToCRDv1beta1, collection, force); err != nil { + if err := installCRD(ctx, c, "IntegrationKit", "v1", "camel.apache.org_integrationkits.yaml", + downgradeToCRDv1beta1, collection, force); err != nil { return err } // Install CRD for Integration (if needed) - if err := installCRD(ctx, c, "Integration", "v1", "camel.apache.org_integrations.yaml", downgradeToCRDv1beta1, collection, force); err != nil { + if err := installCRD(ctx, c, "Integration", "v1", "camel.apache.org_integrations.yaml", + downgradeToCRDv1beta1, collection, force); err != nil { return err } // Install CRD for Camel Catalog (if needed) - if err := installCRD(ctx, c, "CamelCatalog", "v1", "camel.apache.org_camelcatalogs.yaml", downgradeToCRDv1beta1, collection, force); err != nil { + if err := installCRD(ctx, c, "CamelCatalog", "v1", "camel.apache.org_camelcatalogs.yaml", + downgradeToCRDv1beta1, collection, force); err != nil { return err } // Install CRD for Build (if needed) - if err := installCRD(ctx, c, "Build", "v1", "camel.apache.org_builds.yaml", downgradeToCRDv1beta1, collection, force); err != nil { + if err := installCRD(ctx, c, "Build", "v1", "camel.apache.org_builds.yaml", + downgradeToCRDv1beta1, collection, force); err != nil { return err } // Install CRD for Kamelet (if needed) - if err := installCRD(ctx, c, "Kamelet", "v1alpha1", "camel.apache.org_kamelets.yaml", downgradeToCRDv1beta1, collection, force); err != nil { + if err := installCRD(ctx, c, "Kamelet", "v1alpha1", "camel.apache.org_kamelets.yaml", + downgradeToCRDv1beta1, collection, force); err != nil { return err } // Install CRD for KameletBinding (if needed) - if err := installCRD(ctx, c, "KameletBinding", "v1alpha1", "camel.apache.org_kameletbindings.yaml", downgradeToCRDv1beta1, collection, force); err != nil { + if err := installCRD(ctx, c, "KameletBinding", "v1alpha1", "camel.apache.org_kameletbindings.yaml", + downgradeToCRDv1beta1, collection, force); err != nil { return err } @@ -173,7 +182,8 @@ func SetupClusterWideResourcesOrCollect(ctx context.Context, clientProvider clie return err } if !ok { - if err := installResource(ctx, c, collection, "/rbac/operator-cluster-role-custom-resource-definitions.yaml"); err != nil { + if err := installResource(ctx, c, collection, + "/rbac/operator-cluster-role-custom-resource-definitions.yaml"); err != nil { return err } } @@ -237,7 +247,9 @@ func WaitForAllCrdInstallation(ctx context.Context, clientProvider client.Provid } // Check after 2 seconds if not expired if time.Now().After(deadline) { - return errors.New("cannot check CRD installation after " + strconv.FormatInt(timeout.Nanoseconds()/1000000000, 10) + " seconds") + return fmt.Errorf( + "cannot check CRD installation after %s seconds", + strconv.FormatInt(timeout.Nanoseconds()/1000000000, 10)) } time.Sleep(2 * time.Second) } @@ -292,7 +304,10 @@ func isCrdInstalled(c client.Client, kind string, version string) (bool, error) return false, nil } -func installCRD(ctx context.Context, c client.Client, kind string, version string, resourceName string, converter ResourceCustomizer, collection *kubernetes.Collection, force bool) error { +func installCRD( + ctx context.Context, c client.Client, kind string, version string, resourceName string, + converter ResourceCustomizer, collection *kubernetes.Collection, force bool, +) error { content, err := resources.ResourceAsString("/crd/bases/" + resourceName) if err != nil { return err diff --git a/pkg/install/operator.go b/pkg/install/operator.go index 00d01f1d0b..f48ac3ba56 100644 --- a/pkg/install/operator.go +++ b/pkg/install/operator.go @@ -509,9 +509,11 @@ func installLeaseBindings(ctx context.Context, c client.Client, namespace string ) } -// NewPlatform -- -// nolint: lll -func NewPlatform(ctx context.Context, c client.Client, clusterType string, skipRegistrySetup bool, registry v1.RegistrySpec, operatorID string) (*v1.IntegrationPlatform, error) { +// NewPlatform creates a new IntegrationPlatform instance. +func NewPlatform( + ctx context.Context, c client.Client, + clusterType string, skipRegistrySetup bool, registry v1.RegistrySpec, operatorID string, +) (*v1.IntegrationPlatform, error) { isOpenShift, err := isOpenShift(c, clusterType) if err != nil { return nil, err diff --git a/pkg/util/olm/available.go b/pkg/util/olm/available.go index 9f54455062..69125edb14 100644 --- a/pkg/util/olm/available.go +++ b/pkg/util/olm/available.go @@ -31,7 +31,7 @@ import ( kubernetesutils "github.com/apache/camel-k/pkg/util/kubernetes" ) -// IsAPIAvailable returns true if we are connected to a cluster with OLM installed +// IsAPIAvailable returns true if we are connected to a cluster with OLM installed. // // This method should not be called from the operator, as it might require permissions that are not available. func IsAPIAvailable(ctx context.Context, c kubernetes.Interface, namespace string) (bool, error) { From 3c6ff89d8653162e49d8e59e02ac0bb73da10c69 Mon Sep 17 00:00:00 2001 From: Tadayoshi Sato Date: Wed, 14 Dec 2022 18:11:20 +0900 Subject: [PATCH 2/2] fix(install): refactor install cmd support funcs to remove another maintidx lint --- pkg/install/cluster.go | 246 +++++++++++++++++++++++------------------ 1 file changed, 136 insertions(+), 110 deletions(-) diff --git a/pkg/install/cluster.go b/pkg/install/cluster.go index fd704759a6..0af2e0e309 100644 --- a/pkg/install/cluster.go +++ b/pkg/install/cluster.go @@ -39,7 +39,6 @@ import ( "github.com/apache/camel-k/pkg/util/kubernetes" ) -// nolint: maintidx // TODO: refactor the code func SetupClusterWideResourcesOrCollect( ctx context.Context, clientProvider client.Provider, collection *kubernetes.Collection, clusterType string, force bool, @@ -50,110 +49,8 @@ func SetupClusterWideResourcesOrCollect( return err } - isAPIExtensionsV1 := true - if _, err := c.Discovery().ServerResourcesForGroupVersion("apiextensions.k8s.io/v1"); err != nil { - if k8serrors.IsNotFound(err) { - isAPIExtensionsV1 = false - } else { - return err - } - } - - // Convert the CRD to apiextensions.k8s.io/v1beta1 in case v1 is not available. - // This is mainly required to support OpenShift 3, and older versions of Kubernetes. - // It can be removed as soon as these versions are not supported anymore. - if err := apiextensionsv1.AddToScheme(c.GetScheme()); err != nil { - return err - } - if !isAPIExtensionsV1 { - if err := apiextensionsv1beta1.AddToScheme(c.GetScheme()); err != nil { - return err - } - } - downgradeToCRDv1beta1 := func(object ctrl.Object) ctrl.Object { - // Remove default values in v1beta1 Integration and KameletBinding CRDs, - removeDefaultFromCrd := func(crd *apiextensionsv1beta1.CustomResourceDefinition, property string) { - defaultValue := apiextensionsv1beta1.JSONSchemaProps{ - Default: nil, - } - if crd.Name == "integrations.camel.apache.org" { - crd.Spec.Validation.OpenAPIV3Schema. - Properties["spec"].Properties["template"].Properties["spec"].Properties[property].Items.Schema. - Properties["ports"].Items.Schema.Properties["protocol"] = defaultValue - } - if crd.Name == "kameletbindings.camel.apache.org" { - crd.Spec.Validation.OpenAPIV3Schema.Properties["spec"].Properties["integration"].Properties["template"]. - Properties["spec"].Properties[property].Items.Schema.Properties["ports"].Items.Schema. - Properties["protocol"] = defaultValue - } - } - - if !isAPIExtensionsV1 { - v1Crd, ok := object.(*apiextensionsv1.CustomResourceDefinition) - if !ok { - return nil - } - v1beta1Crd := &apiextensionsv1beta1.CustomResourceDefinition{} - crd := &apiextensions.CustomResourceDefinition{} - - err := apiextensionsv1.Convert_v1_CustomResourceDefinition_To_apiextensions_CustomResourceDefinition(v1Crd, crd, nil) - if err != nil { - return nil - } - - err = apiextensionsv1beta1.Convert_apiextensions_CustomResourceDefinition_To_v1beta1_CustomResourceDefinition(crd, v1beta1Crd, nil) - if err != nil { - return nil - } - - removeDefaultFromCrd(v1beta1Crd, "ephemeralContainers") - removeDefaultFromCrd(v1beta1Crd, "containers") - removeDefaultFromCrd(v1beta1Crd, "initContainers") - - return v1beta1Crd - } - return object - } - - // Install CRD for Integration Platform (if needed) - if err := installCRD(ctx, c, "IntegrationPlatform", "v1", "camel.apache.org_integrationplatforms.yaml", - downgradeToCRDv1beta1, collection, force); err != nil { - return err - } - - // Install CRD for Integration Kit (if needed) - if err := installCRD(ctx, c, "IntegrationKit", "v1", "camel.apache.org_integrationkits.yaml", - downgradeToCRDv1beta1, collection, force); err != nil { - return err - } - - // Install CRD for Integration (if needed) - if err := installCRD(ctx, c, "Integration", "v1", "camel.apache.org_integrations.yaml", - downgradeToCRDv1beta1, collection, force); err != nil { - return err - } - - // Install CRD for Camel Catalog (if needed) - if err := installCRD(ctx, c, "CamelCatalog", "v1", "camel.apache.org_camelcatalogs.yaml", - downgradeToCRDv1beta1, collection, force); err != nil { - return err - } - - // Install CRD for Build (if needed) - if err := installCRD(ctx, c, "Build", "v1", "camel.apache.org_builds.yaml", - downgradeToCRDv1beta1, collection, force); err != nil { - return err - } - - // Install CRD for Kamelet (if needed) - if err := installCRD(ctx, c, "Kamelet", "v1alpha1", "camel.apache.org_kamelets.yaml", - downgradeToCRDv1beta1, collection, force); err != nil { - return err - } - - // Install CRD for KameletBinding (if needed) - if err := installCRD(ctx, c, "KameletBinding", "v1alpha1", "camel.apache.org_kameletbindings.yaml", - downgradeToCRDv1beta1, collection, force); err != nil { + // Install CRDs + if err := installCRDs(ctx, c, collection, force); err != nil { return err } @@ -165,7 +62,14 @@ func SetupClusterWideResourcesOrCollect( } } - // Installing ClusterRoles + // Install ClusterRoles + return installClusterRoles(ctx, c, collection, clusterType) +} + +func installClusterRoles( + ctx context.Context, c client.Client, collection *kubernetes.Collection, clusterType string, +) error { + // ClusterRole: camel-k-edit ok, err := isClusterRoleInstalled(ctx, c, "camel-k-edit") if err != nil { return err @@ -177,6 +81,7 @@ func SetupClusterWideResourcesOrCollect( } } + // ClusterRole: camel-k-operator-custom-resource-definitions ok, err = isClusterRoleInstalled(ctx, c, "camel-k-operator-custom-resource-definitions") if err != nil { return err @@ -188,12 +93,15 @@ func SetupClusterWideResourcesOrCollect( } } + // ClusterRole: camel-k-operator-local-registry ok, err = isClusterRoleInstalled(ctx, c, "camel-k-operator-local-registry") if err == nil && !ok { - // nolint: errcheck - installResource(ctx, c, collection, "/rbac/operator-cluster-role-local-registry.yaml") + // ignore errors + _ = installResource(ctx, c, collection, "/rbac/operator-cluster-role-local-registry.yaml") } + // === For OpenShift === + // ClusterRole: camel-k-operator-console-openshift isOpenShift, err := isOpenShift(c, clusterType) if err != nil { return err @@ -211,6 +119,8 @@ func SetupClusterWideResourcesOrCollect( } } + // === For Knative === + // ClusterRole: camel-k-operator-bind-addressable-resolver isKnative, err := knative.IsInstalled(c) if err != nil { return err @@ -231,6 +141,122 @@ func SetupClusterWideResourcesOrCollect( return nil } +func installCRDs(ctx context.Context, c client.Client, collection *kubernetes.Collection, force bool) error { + isAPIExtensionsV1 := true + if _, err := c.Discovery().ServerResourcesForGroupVersion("apiextensions.k8s.io/v1"); err != nil { + if k8serrors.IsNotFound(err) { + isAPIExtensionsV1 = false + } else { + return err + } + } + + // Convert the CRD to apiextensions.k8s.io/v1beta1 in case v1 is not available. + // This is mainly required to support OpenShift 3, and older versions of Kubernetes. + // It can be removed as soon as these versions are not supported anymore. + if err := apiextensionsv1.AddToScheme(c.GetScheme()); err != nil { + return err + } + if !isAPIExtensionsV1 { + if err := apiextensionsv1beta1.AddToScheme(c.GetScheme()); err != nil { + return err + } + } + v1beta1Customizer := downgradeToCRDv1beta1(isAPIExtensionsV1) + + // Install CRD for Integration Platform (if needed) + if err := installCRD(ctx, c, "IntegrationPlatform", "v1", "camel.apache.org_integrationplatforms.yaml", + v1beta1Customizer, collection, force); err != nil { + return err + } + + // Install CRD for Integration Kit (if needed) + if err := installCRD(ctx, c, "IntegrationKit", "v1", "camel.apache.org_integrationkits.yaml", + v1beta1Customizer, collection, force); err != nil { + return err + } + + // Install CRD for Integration (if needed) + if err := installCRD(ctx, c, "Integration", "v1", "camel.apache.org_integrations.yaml", + v1beta1Customizer, collection, force); err != nil { + return err + } + + // Install CRD for Camel Catalog (if needed) + if err := installCRD(ctx, c, "CamelCatalog", "v1", "camel.apache.org_camelcatalogs.yaml", + v1beta1Customizer, collection, force); err != nil { + return err + } + + // Install CRD for Build (if needed) + if err := installCRD(ctx, c, "Build", "v1", "camel.apache.org_builds.yaml", + v1beta1Customizer, collection, force); err != nil { + return err + } + + // Install CRD for Kamelet (if needed) + if err := installCRD(ctx, c, "Kamelet", "v1alpha1", "camel.apache.org_kamelets.yaml", + v1beta1Customizer, collection, force); err != nil { + return err + } + + // Install CRD for KameletBinding (if needed) + if err := installCRD(ctx, c, "KameletBinding", "v1alpha1", "camel.apache.org_kameletbindings.yaml", + v1beta1Customizer, collection, force); err != nil { + return err + } + + return nil +} + +func downgradeToCRDv1beta1(isAPIExtensionsV1 bool) ResourceCustomizer { + return func(object ctrl.Object) ctrl.Object { + // Remove default values in v1beta1 Integration and KameletBinding CRDs, + removeDefaultFromCrd := func(crd *apiextensionsv1beta1.CustomResourceDefinition, property string) { + defaultValue := apiextensionsv1beta1.JSONSchemaProps{ + Default: nil, + } + if crd.Name == "integrations.camel.apache.org" { + crd.Spec.Validation.OpenAPIV3Schema. + Properties["spec"].Properties["template"].Properties["spec"].Properties[property].Items.Schema. + Properties["ports"].Items.Schema.Properties["protocol"] = defaultValue + } + if crd.Name == "kameletbindings.camel.apache.org" { + crd.Spec.Validation.OpenAPIV3Schema.Properties["spec"].Properties["integration"].Properties["template"]. + Properties["spec"].Properties[property].Items.Schema.Properties["ports"].Items.Schema. + Properties["protocol"] = defaultValue + } + } + + if !isAPIExtensionsV1 { + v1Crd, ok := object.(*apiextensionsv1.CustomResourceDefinition) + if !ok { + return nil + } + v1beta1Crd := &apiextensionsv1beta1.CustomResourceDefinition{} + crd := &apiextensions.CustomResourceDefinition{} + + err := apiextensionsv1.Convert_v1_CustomResourceDefinition_To_apiextensions_CustomResourceDefinition(v1Crd, crd, nil) + if err != nil { + return nil + } + + err = apiextensionsv1beta1.Convert_apiextensions_CustomResourceDefinition_To_v1beta1_CustomResourceDefinition(crd, v1beta1Crd, nil) + if err != nil { + return nil + } + + removeDefaultFromCrd(v1beta1Crd, "ephemeralContainers") + removeDefaultFromCrd(v1beta1Crd, "containers") + removeDefaultFromCrd(v1beta1Crd, "initContainers") + + return v1beta1Crd + } + + return object + } +} + func WaitForAllCrdInstallation(ctx context.Context, clientProvider client.Provider, timeout time.Duration) error { deadline := time.Now().Add(timeout) for { @@ -306,7 +332,7 @@ func isCrdInstalled(c client.Client, kind string, version string) (bool, error) func installCRD( ctx context.Context, c client.Client, kind string, version string, resourceName string, - converter ResourceCustomizer, collection *kubernetes.Collection, force bool, + customizer ResourceCustomizer, collection *kubernetes.Collection, force bool, ) error { content, err := resources.ResourceAsString("/crd/bases/" + resourceName) if err != nil { @@ -318,7 +344,7 @@ func installCRD( return err } - crd = converter(crd) + crd = customizer(crd) if crd == nil { // The conversion has failed return errors.New("cannot convert " + resourceName + " CRD to apiextensions.k8s.io/v1beta1")