From 57b3597c88c8c10889bedd9a6ce915b2ac26eb85 Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Mon, 2 Aug 2021 22:27:25 -0400 Subject: [PATCH] operator install: honor operatorframework.io/suggested-namespace by default Signed-off-by: Joe Lanford --- go.sum | 3 -- internal/cmd/operator_install.go | 7 ++++ internal/pkg/action/operator_install.go | 48 ++++++++++++++++++++----- pkg/action/config.go | 2 ++ 4 files changed, 48 insertions(+), 12 deletions(-) diff --git a/go.sum b/go.sum index 6726039..f185bd6 100644 --- a/go.sum +++ b/go.sum @@ -581,7 +581,6 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.11.0 h1:+CqWgvj0OZycCaqclBD1pxKHAU+tOkHmQIWvDHq2aug= github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg= @@ -898,7 +897,6 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -1147,7 +1145,6 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/internal/cmd/operator_install.go b/internal/cmd/operator_install.go index 4ecf241..9411f1c 100644 --- a/internal/cmd/operator_install.go +++ b/internal/cmd/operator_install.go @@ -1,6 +1,7 @@ package cmd import ( + "errors" "fmt" "time" @@ -25,6 +26,11 @@ func newOperatorInstallCmd(cfg *action.Configuration) *cobra.Command { i.Package = args[0] csv, err := i.Run(cmd.Context()) if err != nil { + if errors.Is(err, internalaction.ErrNoOperatorGroup) { + log.Fatalf("operator group not found in namespace %q, use --create-operator-group to create one automatically", cfg.Namespace) + } else if altNsErr := (&internalaction.ErrIncorrectNamespace{}); errors.As(err, altNsErr) { + log.Fatalf("invalid installation namespace: use --namespace=%q to install into operator's suggested namespace or --permit-alternate-namespace to force installation in %q", altNsErr.Suggested, altNsErr.Requested) + } log.Fatalf("failed to install operator: %v", err) } log.Printf("operator %q installed; installed csv is %q", i.Package, csv.Name) @@ -42,6 +48,7 @@ func bindOperatorInstallFlags(fs *pflag.FlagSet, i *internalaction.OperatorInsta fs.StringSliceVarP(&i.WatchNamespaces, "watch", "w", []string{}, "namespaces to watch") fs.DurationVar(&i.CleanupTimeout, "cleanup-timeout", time.Minute, "the amount of time to wait before cancelling cleanup") fs.BoolVarP(&i.CreateOperatorGroup, "create-operator-group", "C", false, "create operator group if necessary") + fs.BoolVar(&i.PermitAlternateNamespace, "permit-alternate-namespace", false, "permit an alternate namespace to be used when the operator defines operatorframework.io/suggested-namespace") fs.VarP(&i.InstallMode, "install-mode", "i", "install mode") err := fs.MarkHidden("install-mode") diff --git a/internal/pkg/action/operator_install.go b/internal/pkg/action/operator_install.go index 76fe118..2a76666 100644 --- a/internal/pkg/action/operator_install.go +++ b/internal/pkg/action/operator_install.go @@ -2,6 +2,7 @@ package action import ( "context" + "errors" "fmt" "regexp" "strings" @@ -10,6 +11,7 @@ import ( v1 "github.com/operator-framework/api/pkg/operators/v1" "github.com/operator-framework/api/pkg/operators/v1alpha1" operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" @@ -23,14 +25,15 @@ import ( type OperatorInstall struct { config *action.Configuration - Package string - Channel string - Version string - Approval subscription.ApprovalValue - WatchNamespaces []string - InstallMode operator.InstallMode - CleanupTimeout time.Duration - CreateOperatorGroup bool + Package string + Channel string + Version string + Approval subscription.ApprovalValue + WatchNamespaces []string + InstallMode operator.InstallMode + CleanupTimeout time.Duration + CreateOperatorGroup bool + PermitAlternateNamespace bool Logf func(string, ...interface{}) } @@ -42,6 +45,17 @@ func NewOperatorInstall(cfg *action.Configuration) *OperatorInstall { } } +var ErrNoOperatorGroup = errors.New("operator group not found") + +type ErrIncorrectNamespace struct { + Requested string + Suggested string +} + +func (e ErrIncorrectNamespace) Error() string { + return fmt.Sprintf("requested install namespace is %q, but operator's suggested namespace is %q", e.Requested, e.Suggested) +} + func (i *OperatorInstall) Run(ctx context.Context) (*v1alpha1.ClusterServiceVersion, error) { if len(i.WatchNamespaces) > 0 && !i.InstallMode.IsEmpty() { return nil, fmt.Errorf("WatchNamespaces and InstallMode options are mutually exclusive") @@ -60,6 +74,10 @@ func (i *OperatorInstall) Run(ctx context.Context) (*v1alpha1.ClusterServiceVers return nil, fmt.Errorf("get package channel: %v", err) } + if err := i.ensureNamespace(ctx, pc); err != nil { + return nil, err + } + if _, err := i.ensureOperatorGroup(ctx, pm, pc); err != nil { return nil, err } @@ -117,6 +135,18 @@ func (i *OperatorInstall) getPackageManifest(ctx context.Context) (*operator.Pac return &operator.PackageManifest{PackageManifest: *pm}, nil } +func (i *OperatorInstall) ensureNamespace(ctx context.Context, pc *operator.PackageChannel) error { + suggestedNamespace := pc.CurrentCSVDesc.Annotations["operatorframework.io/suggested-namespace"] + if !i.PermitAlternateNamespace && suggestedNamespace != "" && i.config.Namespace != suggestedNamespace { + return ErrIncorrectNamespace{Suggested: suggestedNamespace, Requested: i.config.Namespace} + } + ns := corev1.Namespace{} + if err := i.config.Client.Get(ctx, types.NamespacedName{Name: i.config.Namespace}, &ns); err != nil { + return err + } + return nil +} + func (i *OperatorInstall) ensureOperatorGroup(ctx context.Context, pm *operator.PackageManifest, pc *operator.PackageChannel) (*v1.OperatorGroup, error) { og, err := i.getOperatorGroup(ctx) if err != nil { @@ -156,7 +186,7 @@ func (i *OperatorInstall) ensureOperatorGroup(ctx context.Context, pm *operator. } i.Logf("operatorgroup %q created", og.Name) } else { - return nil, fmt.Errorf("namespace %q has no existing operator group; use --create-operator-group to create one automatically", i.config.Namespace) + return nil, ErrNoOperatorGroup } } else if err := i.validateOperatorGroup(*og, supported); err != nil { return nil, err diff --git a/pkg/action/config.go b/pkg/action/config.go index 5681a68..b4c6d9b 100644 --- a/pkg/action/config.go +++ b/pkg/action/config.go @@ -7,6 +7,7 @@ import ( "github.com/operator-framework/api/pkg/operators/v1alpha1" operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1" "github.com/spf13/pflag" + corev1 "k8s.io/api/core/v1" apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/tools/clientcmd" @@ -16,6 +17,7 @@ import ( func NewScheme() (*runtime.Scheme, error) { sch := runtime.NewScheme() for _, f := range []func(*runtime.Scheme) error{ + corev1.AddToScheme, v1alpha1.AddToScheme, operatorsv1.AddToScheme, v1.AddToScheme,