From 5de69b17e194c037c86934b55eed09d1873351a6 Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Wed, 12 Aug 2020 21:03:23 -0400 Subject: [PATCH 1/9] fix ansible-operator link to CR sample --- .../ansible/reference/retroactively-owned-resources.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/content/en/docs/building-operators/ansible/reference/retroactively-owned-resources.md b/website/content/en/docs/building-operators/ansible/reference/retroactively-owned-resources.md index 14f708e1a8..136c5e61e4 100644 --- a/website/content/en/docs/building-operators/ansible/reference/retroactively-owned-resources.md +++ b/website/content/en/docs/building-operators/ansible/reference/retroactively-owned-resources.md @@ -66,7 +66,7 @@ resource is a cluster level resource. **NOTE**: The {group} can be found by splitting the `apiVersion` metadata of the CR, into `group` and `version`. As an example, -[this apiVersion field](https://github.com/operator-framework/operator-sdk-samples/blob/master/ansible/memcached-operator/deploy/crds/cache.example.com_v1alpha1_memcached_cr.yaml#L1) +[this apiVersion field](https://github.com/operator-framework/operator-sdk-samples/blob/938fd148ba106ca9811925e4956d6bb70c36b29d/ansible/memcached-operator/config/samples/cache_v1alpha1_memcached.yaml#L1) gives us the group `cache.example.com`. **Example Annotation:** From 897d43d961df409ee0965b64eb28e28928d16c99 Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Mon, 3 Aug 2020 22:35:56 -0400 Subject: [PATCH 2/9] internal/operator-sdk/run|cleanup: initial boilerplate for bundle run and cleanup commands --- hack/lib/test_lib.sh | 2 +- .../cmd/operator-sdk/cleanup/bundle/cmd.go | 63 ++++++++++ internal/cmd/operator-sdk/run/bundle/cmd.go | 82 +++++++++++++ internal/cmd/operator-sdk/run/cmd.go | 7 +- internal/cmd/operator-sdk/run/cmd_test.go | 2 +- .../run/packagemanifests/packagemanifests.go | 2 +- internal/operator/bundle/install.go | 116 ++++++++++++++++++ internal/operator/bundle/uninstall.go | 66 ++++++++++ internal/operator/internal/catalog.go | 25 ++++ internal/operator/internal/index_image.go | 62 ++++++++++ internal/operator/internal/install_mode.go | 92 ++++++++++++++ .../operator/internal/operator_installer.go | 64 ++++++++++ .../operator/internal/operator_uninstaller.go | 54 ++++++++ .../content/en/docs/cli/operator-sdk_run.md | 3 - .../cli/operator-sdk_run_packagemanifests.md | 2 +- 15 files changed, 631 insertions(+), 11 deletions(-) create mode 100644 internal/cmd/operator-sdk/cleanup/bundle/cmd.go create mode 100644 internal/cmd/operator-sdk/run/bundle/cmd.go create mode 100644 internal/operator/bundle/install.go create mode 100644 internal/operator/bundle/uninstall.go create mode 100644 internal/operator/internal/catalog.go create mode 100644 internal/operator/internal/index_image.go create mode 100644 internal/operator/internal/install_mode.go create mode 100644 internal/operator/internal/operator_installer.go create mode 100644 internal/operator/internal/operator_uninstaller.go diff --git a/hack/lib/test_lib.sh b/hack/lib/test_lib.sh index 3c29cac3bd..7255f856bc 100644 --- a/hack/lib/test_lib.sh +++ b/hack/lib/test_lib.sh @@ -3,7 +3,7 @@ source hack/lib/common.sh function listPkgDirs() { - go list -f '{{.Dir}}' ./cmd/... ./pkg/... ./test/... ./internal/... | grep -v generated + go list -f '{{.Dir}}' ./cmd/... ./test/... ./internal/... | grep -v generated } function listFiles() { diff --git a/internal/cmd/operator-sdk/cleanup/bundle/cmd.go b/internal/cmd/operator-sdk/cleanup/bundle/cmd.go new file mode 100644 index 0000000000..7e78be2bb9 --- /dev/null +++ b/internal/cmd/operator-sdk/cleanup/bundle/cmd.go @@ -0,0 +1,63 @@ +// Copyright 2020 The Operator-SDK 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 bundle + +import ( + "context" + "fmt" + "time" + + "github.com/spf13/cobra" + + "github.com/operator-framework/operator-sdk/internal/operator" + "github.com/operator-framework/operator-sdk/internal/operator/bundle" +) + +func NewCmd() *cobra.Command { + var timeout time.Duration + + // TODO(joelanford): the initialization of cfg up to + // the "run" subcommand when migrating packagemanifests + // to this design. + cfg := &operator.Configuration{} + + u := bundle.NewUninstall(cfg) + cmd := &cobra.Command{ + Use: "bundle ", + Short: "Cleanup an Operator in the bundle format with OLM", + Hidden: true, + Args: cobra.ExactArgs(1), + PersistentPreRunE: func(_ *cobra.Command, _ []string) error { + return cfg.Load() + }, + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(cmd.Context(), timeout) + defer cancel() + + u.BundleImage = args[0] + + if err := u.Run(ctx); err != nil { + fmt.Printf("cleanup error: %v\n", err) + } + fmt.Printf("operator uninstalled\n") + }, + } + cmd.Flags().SortFlags = false + cfg.BindFlags(cmd.PersistentFlags()) + u.BindFlags(cmd.Flags()) + + cmd.Flags().DurationVar(&timeout, "timeout", 60*time.Second, "cleanup timeout") + return cmd +} diff --git a/internal/cmd/operator-sdk/run/bundle/cmd.go b/internal/cmd/operator-sdk/run/bundle/cmd.go new file mode 100644 index 0000000000..38383e572d --- /dev/null +++ b/internal/cmd/operator-sdk/run/bundle/cmd.go @@ -0,0 +1,82 @@ +// Copyright 2020 The Operator-SDK 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 bundle + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/spf13/cobra" + + "github.com/operator-framework/operator-sdk/internal/operator" + "github.com/operator-framework/operator-sdk/internal/operator/bundle" +) + +func NewCmd() *cobra.Command { + var timeout time.Duration + var cleanupTimeout time.Duration + + // TODO(joelanford): the initialization of cfg up to + // the "run" subcommand when migrating packagemanifests + // to this design. + cfg := &operator.Configuration{} + + i := bundle.NewInstall(cfg) + u := bundle.NewUninstall(cfg) + cmd := &cobra.Command{ + Use: "bundle ", + Short: "Deploy an Operator in the bundle format with OLM", + Hidden: true, + Args: cobra.ExactArgs(1), + PersistentPreRunE: func(_ *cobra.Command, _ []string) error { + return cfg.Load() + }, + Run: func(cmd *cobra.Command, args []string) { + runCtx, runCancel := context.WithTimeout(cmd.Context(), timeout) + defer runCancel() + + i.BundleImage = args[0] + u.BundleImage = args[0] + u.DeleteAll = true + + csv, err := i.Run(runCtx) + if err != nil { + func() { + cancelCtx, cancelCancel := context.WithTimeout(cmd.Context(), cleanupTimeout) + defer cancelCancel() + + cleanupErr := u.Run(cancelCtx) + if cleanupErr != nil { + defer func() { + fmt.Printf("cleanup error: %v\n", cleanupErr) + }() + } + fmt.Printf("failed to run bundle: %v\n", err) + }() + os.Exit(1) + } + fmt.Printf("csv %q installed\n", csv.Name) + }, + } + cmd.Flags().SortFlags = false + cfg.BindFlags(cmd.PersistentFlags()) + i.BindFlags(cmd.Flags()) + + cmd.Flags().DurationVar(&timeout, "timeout", 60*time.Second, "install timeout") + cmd.Flags().DurationVar(&cleanupTimeout, "cleanup-timeout", 10*time.Second, "cleanup timeout") + return cmd +} diff --git a/internal/cmd/operator-sdk/run/cmd.go b/internal/cmd/operator-sdk/run/cmd.go index 63633c3145..8fddddd573 100644 --- a/internal/cmd/operator-sdk/run/cmd.go +++ b/internal/cmd/operator-sdk/run/cmd.go @@ -24,13 +24,12 @@ func NewCmd() *cobra.Command { cmd := &cobra.Command{ Use: "run", Short: "Run an Operator in a variety of environments", - Long: `This command has subcommands that will deploy your Operator with OLM. -Currently only the package manifests format is supported via the 'packagemanifests' subcommand. -Run 'operator-sdk run --help' for more information. -`, + Long: "This command has subcommands that will deploy your Operator with OLM.", } cmd.AddCommand( + // TODO(joelanford): enable bundle command when implementation is complete + //bundle.NewCmd(), packagemanifests.NewCmd(), ) diff --git a/internal/cmd/operator-sdk/run/cmd_test.go b/internal/cmd/operator-sdk/run/cmd_test.go index 49f6917345..a7604258f0 100644 --- a/internal/cmd/operator-sdk/run/cmd_test.go +++ b/internal/cmd/operator-sdk/run/cmd_test.go @@ -30,7 +30,7 @@ var _ = Describe("Running a run command", func() { subcommands := cmd.Commands() Expect(len(subcommands)).To(Equal(1)) - Expect(subcommands[0].Use).To(Equal("packagemanifests")) + Expect(subcommands[0].Use).To(Equal("packagemanifests ")) }) }) }) diff --git a/internal/cmd/operator-sdk/run/packagemanifests/packagemanifests.go b/internal/cmd/operator-sdk/run/packagemanifests/packagemanifests.go index e7d4532318..da97440b4e 100644 --- a/internal/cmd/operator-sdk/run/packagemanifests/packagemanifests.go +++ b/internal/cmd/operator-sdk/run/packagemanifests/packagemanifests.go @@ -31,7 +31,7 @@ func NewCmd() *cobra.Command { c := &packagemanifestsCmd{} cmd := &cobra.Command{ - Use: "packagemanifests", + Use: "packagemanifests ", Short: "Deploy an Operator in the package manifests format with OLM", Long: `'run packagemanifests' deploys an Operator's package manifests with OLM. The command's argument must be set to a valid package manifests root directory, ex. '/packagemanifests'.`, diff --git a/internal/operator/bundle/install.go b/internal/operator/bundle/install.go new file mode 100644 index 0000000000..c4d83d386c --- /dev/null +++ b/internal/operator/bundle/install.go @@ -0,0 +1,116 @@ +// Copyright 2020 The Operator-SDK 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 bundle + +import ( + "context" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/operator-framework/operator-registry/pkg/registry" + log "github.com/sirupsen/logrus" + "github.com/spf13/pflag" + + "github.com/operator-framework/operator-sdk/internal/operator" + "github.com/operator-framework/operator-sdk/internal/operator/internal" + registryutil "github.com/operator-framework/operator-sdk/internal/registry" +) + +type Install struct { + BundleImage string + + *internal.IndexImageCatalogCreator + *internal.OperatorInstaller +} + +func NewInstall(cfg *operator.Configuration) Install { + i := Install{ + OperatorInstaller: internal.NewOperatorInstaller(cfg), + } + i.IndexImageCatalogCreator = internal.NewIndexImageCatalogCreator(cfg) + i.CatalogCreator = i.IndexImageCatalogCreator + return i +} + +const defaultIndexImage = "quay.io/operator-framework/upstream-opm-builder:latest" + +func (i *Install) BindFlags(fs *pflag.FlagSet) { + fs.StringVar(&i.IndexImage, "index-image", defaultIndexImage, "index image in which to inject bundle") + fs.Var(&i.InstallMode, "install-mode", "install mode") + fs.StringVar(&i.InjectBundleMode, "mode", "", "mode to use for adding bundle to index") + _ = fs.MarkHidden("mode") +} + +func (i Install) Run(ctx context.Context) (*v1alpha1.ClusterServiceVersion, error) { + if err := i.setup(ctx); err != nil { + return nil, err + } + return i.InstallOperator(ctx) +} + +func (i *Install) setup(ctx context.Context) error { + labels, csv, err := loadBundle(ctx, i.BundleImage) + if err != nil { + return fmt.Errorf("load bundle: %v", err) + } + + i.OperatorInstaller.PackageName = labels["operators.operatorframework.io.bundle.package.v1"] + i.OperatorInstaller.CatalogSourceName = fmt.Sprintf("%s-catalog", i.OperatorInstaller.PackageName) + i.OperatorInstaller.StartingCSV = csv.Name + i.OperatorInstaller.Channel = strings.Split(labels["operators.operatorframework.io.bundle.channels.v1"], ",")[0] + + i.IndexImageCatalogCreator.InjectBundles = []string{i.BundleImage} + i.IndexImageCatalogCreator.InjectBundleMode = "replaces" + if i.IndexImageCatalogCreator.IndexImage == defaultIndexImage { + i.IndexImageCatalogCreator.InjectBundleMode = "semver" + } + + return nil +} + +func loadBundle(ctx context.Context, bundleImage string) (labels registryutil.Labels, csv *registry.ClusterServiceVersion, err error) { + bundlePath, err := registryutil.ExtractBundleImage(ctx, discardLogger(), bundleImage, false) + if err != nil { + return nil, nil, fmt.Errorf("pull bundle image: %v", err) + } + defer func() { + _ = os.RemoveAll(bundlePath) + }() + + labels, _, err = registryutil.FindBundleMetadata(bundlePath) + if err != nil { + return nil, nil, fmt.Errorf("load bundle metadata: %v", err) + } + + relManifestsDir := labels["operators.operatorframework.io.bundle.manifests.v1"] + manifestsDir := filepath.Join(bundlePath, relManifestsDir) + csv, err = registry.ReadCSVFromBundleDirectory(manifestsDir) + if err != nil { + return nil, nil, fmt.Errorf("read bundle csv: %v", err) + } + + return labels, csv, nil +} + +// discardLogger returns a logger that throws away input. +func discardLogger() *log.Entry { + logger := log.New() + logger.SetOutput(ioutil.Discard) + return log.NewEntry(logger) +} diff --git a/internal/operator/bundle/uninstall.go b/internal/operator/bundle/uninstall.go new file mode 100644 index 0000000000..82709675a9 --- /dev/null +++ b/internal/operator/bundle/uninstall.go @@ -0,0 +1,66 @@ +// Copyright 2020 The Operator-SDK 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 bundle + +import ( + "context" + "fmt" + + "github.com/spf13/pflag" + + "github.com/operator-framework/operator-sdk/internal/operator" + "github.com/operator-framework/operator-sdk/internal/operator/internal" +) + +type Uninstall struct { + BundleImage string + + *internal.OperatorUninstaller +} + +func NewUninstall(cfg *operator.Configuration) Uninstall { + u := Uninstall{ + OperatorUninstaller: internal.NewOperatorUninstaller(cfg), + } + return u +} + +func (u *Uninstall) BindFlags(fs *pflag.FlagSet) { + // TODO: compare with packagemanifests cleanup flags. How does it work now? + fs.BoolVarP(&u.DeleteAll, "delete-all", "X", false, "Enable all deletion flags") + fs.BoolVar(&u.DeleteCRDs, "delete-crds", false, "Delete CRDs (and CRs) before cleaning up operator") + fs.BoolVar(&u.DeleteOperatorGroup, "delete-operator-group", false, "Delete Operator Group if no other subscriptions exist in this namespace") +} + +func (u Uninstall) Run(ctx context.Context) error { + if err := u.setup(ctx); err != nil { + return err + } + return u.UninstallOperator(ctx) +} + +func (u *Uninstall) setup(ctx context.Context) error { + labels, _, err := loadBundle(ctx, u.BundleImage) + if err != nil { + return fmt.Errorf("load bundle: %v", err) + } + + u.PackageName = labels["operators.operatorframework.io.bundle.package.v1"] + if u.DeleteAll { + u.DeleteOperatorGroup = true + u.DeleteCRDs = true + } + return nil +} diff --git a/internal/operator/internal/catalog.go b/internal/operator/internal/catalog.go new file mode 100644 index 0000000000..c5428973b7 --- /dev/null +++ b/internal/operator/internal/catalog.go @@ -0,0 +1,25 @@ +// Copyright 2020 The Operator-SDK 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 internal + +import ( + "context" + + "github.com/operator-framework/api/pkg/operators/v1alpha1" +) + +type CatalogCreator interface { + CreateCatalog(ctx context.Context, name string) (*v1alpha1.CatalogSource, error) +} diff --git a/internal/operator/internal/index_image.go b/internal/operator/internal/index_image.go new file mode 100644 index 0000000000..93bd0c1999 --- /dev/null +++ b/internal/operator/internal/index_image.go @@ -0,0 +1,62 @@ +// Copyright 2020 The Operator-SDK 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 internal + +import ( + "context" + "fmt" + "strings" + + "github.com/operator-framework/api/pkg/operators/v1alpha1" + + "github.com/operator-framework/operator-sdk/internal/operator" +) + +type IndexImageCatalogCreator struct { + IndexImage string + InjectBundles []string + InjectBundleMode string + + cfg *operator.Configuration +} + +func NewIndexImageCatalogCreator(cfg *operator.Configuration) *IndexImageCatalogCreator { + return &IndexImageCatalogCreator{ + cfg: cfg, + } +} + +func (c IndexImageCatalogCreator) CreateCatalog(ctx context.Context, name string) (*v1alpha1.CatalogSource, error) { + fmt.Printf("IndexImageCatalogCreator.IndexImage: %q\n", c.IndexImage) + fmt.Printf("IndexImageCatalogCreator.InjectBundles: %q\n", strings.Join(c.InjectBundles, ",")) + fmt.Printf("IndexImageCatalogCreator.InjectBundleMode: %q\n", c.InjectBundleMode) + + // Create barebones catalog source + + // Create registry pod, assigning its owner as the catalog source + + // Wait for registry pod to be ready + + // Update catalog source with `spec.Address = pod.status.podIP` + + // Update catalog source with annotations for index image, + // injected bundle, and registry add mode + + // Wait for catalog source status to indicate a successful + // connection with the registry pod + + // Return the catalog source + return nil, nil +} diff --git a/internal/operator/internal/install_mode.go b/internal/operator/internal/install_mode.go new file mode 100644 index 0000000000..dd5dda6e4c --- /dev/null +++ b/internal/operator/internal/install_mode.go @@ -0,0 +1,92 @@ +// Copyright 2020 The Operator-SDK 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 internal + +import ( + "flag" + "fmt" + "sort" + "strings" + + "github.com/operator-framework/api/pkg/operators/v1alpha1" + "k8s.io/apimachinery/pkg/util/validation" +) + +type InstallMode struct { + InstallModeType v1alpha1.InstallModeType + TargetNamespaces []string +} + +var _ flag.Value = &InstallMode{} + +func (i *InstallMode) Set(str string) error { + split := strings.SplitN(str, "=", 2) + i.InstallModeType = v1alpha1.InstallModeType(split[0]) + if len(split) == 2 { + namespaces := strings.Split(split[1], ",") + for _, ns := range namespaces { + i.TargetNamespaces = append(i.TargetNamespaces, strings.TrimSpace(ns)) + } + sort.Strings(i.TargetNamespaces) + } + return i.Validate() +} + +func (i InstallMode) IsEmpty() bool { + return i.InstallModeType == "" +} + +func (i InstallMode) String() string { + switch i.InstallModeType { + case v1alpha1.InstallModeTypeSingleNamespace, v1alpha1.InstallModeTypeMultiNamespace: + return fmt.Sprintf("%s=%s", i.InstallModeType, strings.Join(i.TargetNamespaces, ",")) + default: + return string(i.InstallModeType) + } +} + +func (InstallMode) Type() string { + return "InstallModeValue" +} + +func (i InstallMode) Validate() error { + switch i.InstallModeType { + case v1alpha1.InstallModeTypeAllNamespaces, v1alpha1.InstallModeTypeOwnNamespace: + if len(i.TargetNamespaces) != 0 { + return fmt.Errorf("install mode %q must have zero target namespaces", i.InstallModeType) + } + case v1alpha1.InstallModeTypeSingleNamespace: + if len(i.TargetNamespaces) != 1 { + return fmt.Errorf("install mode %q must have exactly one target namespace", i.InstallModeType) + } + case v1alpha1.InstallModeTypeMultiNamespace: + if len(i.TargetNamespaces) == 0 { + return fmt.Errorf("install mode %q must have at least one target namespace", i.InstallModeType) + } + case "": + if len(i.TargetNamespaces) != 0 { + return fmt.Errorf("target namespaces defined without type") + } + default: + return fmt.Errorf("unknown install mode type") + } + for _, ns := range i.TargetNamespaces { + errs := validation.IsDNS1123Label(ns) + if len(errs) > 0 { + return fmt.Errorf("invalid target namespace %q: %v", ns, strings.Join(errs, ", ")) + } + } + return nil +} diff --git a/internal/operator/internal/operator_installer.go b/internal/operator/internal/operator_installer.go new file mode 100644 index 0000000000..7126615933 --- /dev/null +++ b/internal/operator/internal/operator_installer.go @@ -0,0 +1,64 @@ +// Copyright 2020 The Operator-SDK 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 internal + +import ( + "context" + "fmt" + + "github.com/operator-framework/api/pkg/operators/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/operator-framework/operator-sdk/internal/operator" +) + +type OperatorInstaller struct { + CatalogSourceName string + PackageName string + StartingCSV string + Channel string + InstallMode InstallMode + CatalogCreator CatalogCreator + + cfg *operator.Configuration +} + +func NewOperatorInstaller(cfg *operator.Configuration) *OperatorInstaller { + return &OperatorInstaller{cfg: cfg} +} + +func (o OperatorInstaller) InstallOperator(ctx context.Context) (*v1alpha1.ClusterServiceVersion, error) { + cs, err := o.CatalogCreator.CreateCatalog(ctx, o.CatalogSourceName) + if err != nil { + return nil, fmt.Errorf("create catalog: %v", err) + } + _ = cs + + fmt.Printf("OperatorInstaller.CatalogSourceName: %q\n", o.CatalogSourceName) + fmt.Printf("OperatorInstaller.PackageName: %q\n", o.PackageName) + fmt.Printf("OperatorInstaller.StartingCSV: %q\n", o.StartingCSV) + fmt.Printf("OperatorInstaller.Channel: %q\n", o.Channel) + fmt.Printf("OperatorInstaller.InstallMode: %q\n", o.InstallMode) + todo := &v1alpha1.ClusterServiceVersion{ + ObjectMeta: metav1.ObjectMeta{Name: o.StartingCSV}, + } + + // Ensure Operator Group + // Create Subscription + // Approve Install Plan (if necessary) + // Wait for successfully installed CSV + + return todo, nil +} diff --git a/internal/operator/internal/operator_uninstaller.go b/internal/operator/internal/operator_uninstaller.go new file mode 100644 index 0000000000..c4cf694d7c --- /dev/null +++ b/internal/operator/internal/operator_uninstaller.go @@ -0,0 +1,54 @@ +// Copyright 2020 The Operator-SDK 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 internal + +import ( + "context" + "fmt" + + "github.com/operator-framework/operator-sdk/internal/operator" +) + +type OperatorUninstaller struct { + PackageName string + DeleteCRDs bool + DeleteOperatorGroup bool + DeleteAll bool + + cfg *operator.Configuration +} + +func NewOperatorUninstaller(cfg *operator.Configuration) *OperatorUninstaller { + return &OperatorUninstaller{ + cfg: cfg, + } +} + +func (u OperatorUninstaller) UninstallOperator(ctx context.Context) error { + fmt.Printf("OperatorUninstaller.PackageName: %q\n", u.PackageName) + fmt.Printf("OperatorUninstaller.DeleteCRDs: %v\n", u.DeleteCRDs) + fmt.Printf("OperatorUninstaller.DeleteOperatorGroup: %v\n", u.DeleteOperatorGroup) + fmt.Printf("OperatorUninstaller.DeleteAll: %v\n", u.DeleteAll) + + // Delete Subscription + + // Delete CRDs (if delete-crds option set) + + // Delete CSV + + // Delete OperatorGroup (if delete-operator-group option set + // and no more subscriptions remaining in NS) + return nil +} diff --git a/website/content/en/docs/cli/operator-sdk_run.md b/website/content/en/docs/cli/operator-sdk_run.md index 3c50cfec00..0a91662ba7 100644 --- a/website/content/en/docs/cli/operator-sdk_run.md +++ b/website/content/en/docs/cli/operator-sdk_run.md @@ -8,9 +8,6 @@ Run an Operator in a variety of environments ### Synopsis This command has subcommands that will deploy your Operator with OLM. -Currently only the package manifests format is supported via the 'packagemanifests' subcommand. -Run 'operator-sdk run --help' for more information. - ### Options diff --git a/website/content/en/docs/cli/operator-sdk_run_packagemanifests.md b/website/content/en/docs/cli/operator-sdk_run_packagemanifests.md index d171f0b519..fcad1d6432 100644 --- a/website/content/en/docs/cli/operator-sdk_run_packagemanifests.md +++ b/website/content/en/docs/cli/operator-sdk_run_packagemanifests.md @@ -11,7 +11,7 @@ Deploy an Operator in the package manifests format with OLM must be set to a valid package manifests root directory, ex. '<project-root>/packagemanifests'. ``` -operator-sdk run packagemanifests [flags] +operator-sdk run packagemanifests [flags] ``` ### Options From 6e4dd900e5dff20fcf2275428f0061b344d6a9a1 Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Tue, 4 Aug 2020 10:49:09 -0400 Subject: [PATCH 3/9] registryutil: use DiscardLogger if logger is nil; run bundle: get DB path --- internal/cmd/operator-sdk/scorecard/cmd.go | 10 +------- internal/operator/bundle/install.go | 11 +-------- internal/operator/internal/index_image.go | 20 ++++++++++++++++ internal/registry/image.go | 7 ++++++ internal/registry/logger.go | 28 ++++++++++++++++++++++ internal/registry/validate.go | 3 +++ 6 files changed, 60 insertions(+), 19 deletions(-) create mode 100644 internal/registry/logger.go diff --git a/internal/cmd/operator-sdk/scorecard/cmd.go b/internal/cmd/operator-sdk/scorecard/cmd.go index 9f2623217f..89270bdb7b 100644 --- a/internal/cmd/operator-sdk/scorecard/cmd.go +++ b/internal/cmd/operator-sdk/scorecard/cmd.go @@ -19,7 +19,6 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" "os" "path/filepath" "time" @@ -204,17 +203,10 @@ func (c *scorecardCmd) validate(args []string) error { return nil } -// discardLogger returns a logger that throws away input. -func discardLogger() *log.Logger { - logger := log.New() - logger.SetOutput(ioutil.Discard) - return logger -} - // extractBundleImage returns bundleImage's path on disk post-extraction. func extractBundleImage(bundleImage string) (string, error) { // Discard bundle extraction logs unless user sets verbose mode. - logger := log.NewEntry(discardLogger()) + logger := registryutil.DiscardLogger() if viper.GetBool(flags.VerboseOpt) { logger = log.WithFields(log.Fields{"bundle": bundleImage}) } diff --git a/internal/operator/bundle/install.go b/internal/operator/bundle/install.go index c4d83d386c..49e1ac07f7 100644 --- a/internal/operator/bundle/install.go +++ b/internal/operator/bundle/install.go @@ -17,14 +17,12 @@ package bundle import ( "context" "fmt" - "io/ioutil" "os" "path/filepath" "strings" "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/operator-framework/operator-registry/pkg/registry" - log "github.com/sirupsen/logrus" "github.com/spf13/pflag" "github.com/operator-framework/operator-sdk/internal/operator" @@ -85,7 +83,7 @@ func (i *Install) setup(ctx context.Context) error { } func loadBundle(ctx context.Context, bundleImage string) (labels registryutil.Labels, csv *registry.ClusterServiceVersion, err error) { - bundlePath, err := registryutil.ExtractBundleImage(ctx, discardLogger(), bundleImage, false) + bundlePath, err := registryutil.ExtractBundleImage(ctx, nil, bundleImage, false) if err != nil { return nil, nil, fmt.Errorf("pull bundle image: %v", err) } @@ -107,10 +105,3 @@ func loadBundle(ctx context.Context, bundleImage string) (labels registryutil.La return labels, csv, nil } - -// discardLogger returns a logger that throws away input. -func discardLogger() *log.Entry { - logger := log.New() - logger.SetOutput(ioutil.Discard) - return log.NewEntry(logger) -} diff --git a/internal/operator/internal/index_image.go b/internal/operator/internal/index_image.go index 93bd0c1999..070bd00ffd 100644 --- a/internal/operator/internal/index_image.go +++ b/internal/operator/internal/index_image.go @@ -22,6 +22,7 @@ import ( "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/operator-framework/operator-sdk/internal/operator" + registryutil "github.com/operator-framework/operator-sdk/internal/registry" ) type IndexImageCatalogCreator struct { @@ -39,7 +40,13 @@ func NewIndexImageCatalogCreator(cfg *operator.Configuration) *IndexImageCatalog } func (c IndexImageCatalogCreator) CreateCatalog(ctx context.Context, name string) (*v1alpha1.CatalogSource, error) { + dbPath, err := c.getDBPath(ctx) + if err != nil { + return nil, fmt.Errorf("get database path: %v", err) + } + fmt.Printf("IndexImageCatalogCreator.IndexImage: %q\n", c.IndexImage) + fmt.Printf("IndexImageCatalogCreator.IndexImageDBPath: %v\n", dbPath) fmt.Printf("IndexImageCatalogCreator.InjectBundles: %q\n", strings.Join(c.InjectBundles, ",")) fmt.Printf("IndexImageCatalogCreator.InjectBundleMode: %q\n", c.InjectBundleMode) @@ -60,3 +67,16 @@ func (c IndexImageCatalogCreator) CreateCatalog(ctx context.Context, name string // Return the catalog source return nil, nil } + +const defaultDBPath = "/database/index.db" + +func (c IndexImageCatalogCreator) getDBPath(ctx context.Context) (string, error) { + labels, err := registryutil.GetImageLabels(ctx, nil, c.IndexImage, false) + if err != nil { + return "", fmt.Errorf("get index image labels: %v", err) + } + if dbPath, ok := labels["operators.operatorframework.io.index.database.v1"]; ok { + return dbPath, nil + } + return defaultDBPath, nil +} diff --git a/internal/registry/image.go b/internal/registry/image.go index 07cdf75ec4..fe5d822737 100644 --- a/internal/registry/image.go +++ b/internal/registry/image.go @@ -29,6 +29,9 @@ import ( // ExtractBundleImage returns a bundle directory containing files extracted // from image. If local is true, the image will not be pulled. func ExtractBundleImage(ctx context.Context, logger *log.Entry, image string, local bool) (string, error) { + if logger == nil { + logger = DiscardLogger() + } // Use a temp directory for bundle files. This will likely be removed by // the caller. wd, err := os.Getwd() @@ -75,6 +78,10 @@ func ExtractBundleImage(ctx context.Context, logger *log.Entry, image string, lo // GetImageLabels returns the set of labels on image. func GetImageLabels(ctx context.Context, logger *log.Entry, image string, local bool) (map[string]string, error) { + if logger == nil { + logger = DiscardLogger() + } + // Create a containerd registry for socket-less image layer reading. reg, err := containerdregistry.NewRegistry(containerdregistry.WithLog(logger)) if err != nil { diff --git a/internal/registry/logger.go b/internal/registry/logger.go new file mode 100644 index 0000000000..32b6efc865 --- /dev/null +++ b/internal/registry/logger.go @@ -0,0 +1,28 @@ +// Copyright 2019 The Operator-SDK 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 registry + +import ( + "io/ioutil" + + log "github.com/sirupsen/logrus" +) + +// DiscardLogger returns a logger that throws away input. +func DiscardLogger() *log.Entry { + logger := log.New() + logger.SetOutput(ioutil.Discard) + return log.NewEntry(logger) +} diff --git a/internal/registry/validate.go b/internal/registry/validate.go index f3882152df..02683afad0 100644 --- a/internal/registry/validate.go +++ b/internal/registry/validate.go @@ -36,6 +36,9 @@ import ( // if they can be applied to a cluster using `kubectl` provided users have all // necessary permissions and configurations. func ValidateBundleContent(logger *log.Entry, bundle *apimanifests.Bundle, mediaType string) []apierrors.ManifestResult { + if logger == nil { + logger = DiscardLogger() + } // Use errs to collect bundle-level validation errors. errs := apierrors.ManifestResult{ From 9b5d83453eab6e252c709397e119ed416b32af14 Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Wed, 12 Aug 2020 09:25:31 -0400 Subject: [PATCH 4/9] move log function to uninstall struct --- .../cmd/operator-sdk/cleanup/bundle/cmd.go | 63 ------------------- internal/cmd/operator-sdk/cleanup/cmd.go | 2 +- internal/operator/config.go | 4 -- internal/operator/uninstall.go | 4 +- test/integration/operator_olm_test.go | 2 +- 5 files changed, 5 insertions(+), 70 deletions(-) delete mode 100644 internal/cmd/operator-sdk/cleanup/bundle/cmd.go diff --git a/internal/cmd/operator-sdk/cleanup/bundle/cmd.go b/internal/cmd/operator-sdk/cleanup/bundle/cmd.go deleted file mode 100644 index 7e78be2bb9..0000000000 --- a/internal/cmd/operator-sdk/cleanup/bundle/cmd.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2020 The Operator-SDK 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 bundle - -import ( - "context" - "fmt" - "time" - - "github.com/spf13/cobra" - - "github.com/operator-framework/operator-sdk/internal/operator" - "github.com/operator-framework/operator-sdk/internal/operator/bundle" -) - -func NewCmd() *cobra.Command { - var timeout time.Duration - - // TODO(joelanford): the initialization of cfg up to - // the "run" subcommand when migrating packagemanifests - // to this design. - cfg := &operator.Configuration{} - - u := bundle.NewUninstall(cfg) - cmd := &cobra.Command{ - Use: "bundle ", - Short: "Cleanup an Operator in the bundle format with OLM", - Hidden: true, - Args: cobra.ExactArgs(1), - PersistentPreRunE: func(_ *cobra.Command, _ []string) error { - return cfg.Load() - }, - Run: func(cmd *cobra.Command, args []string) { - ctx, cancel := context.WithTimeout(cmd.Context(), timeout) - defer cancel() - - u.BundleImage = args[0] - - if err := u.Run(ctx); err != nil { - fmt.Printf("cleanup error: %v\n", err) - } - fmt.Printf("operator uninstalled\n") - }, - } - cmd.Flags().SortFlags = false - cfg.BindFlags(cmd.PersistentFlags()) - u.BindFlags(cmd.Flags()) - - cmd.Flags().DurationVar(&timeout, "timeout", 60*time.Second, "cleanup timeout") - return cmd -} diff --git a/internal/cmd/operator-sdk/cleanup/cmd.go b/internal/cmd/operator-sdk/cleanup/cmd.go index 5c28f6dc43..84eeb18c1e 100644 --- a/internal/cmd/operator-sdk/cleanup/cmd.go +++ b/internal/cmd/operator-sdk/cleanup/cmd.go @@ -27,7 +27,6 @@ import ( func NewCmd() *cobra.Command { var timeout time.Duration cfg := &operator.Configuration{} - cfg.Log = log.Infof cmd := &cobra.Command{ Use: "cleanup ", Short: "Clean up an Operator deployed with the 'run' subcommand", @@ -41,6 +40,7 @@ func NewCmd() *cobra.Command { u.Package = args[0] u.DeleteAll = true u.DeleteOperatorGroupNames = []string{operator.SDKOperatorGroupName} + u.Logf = log.Infof ctx, cancel := context.WithTimeout(cmd.Context(), timeout) defer cancel() diff --git a/internal/operator/config.go b/internal/operator/config.go index c743dd1a7e..a60402fd3b 100644 --- a/internal/operator/config.go +++ b/internal/operator/config.go @@ -34,7 +34,6 @@ type Configuration struct { RESTConfig *rest.Config Client client.Client Scheme *runtime.Scheme - Log func(string, ...interface{}) overrides *clientcmd.ConfigOverrides } @@ -61,9 +60,6 @@ func (c *Configuration) Load() error { if c.overrides == nil { c.overrides = &clientcmd.ConfigOverrides{} } - if c.Log == nil { - c.Log = func(_ string, _ ...interface{}) {} - } loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() loadingRules.ExplicitPath = c.KubeconfigPath mergedConfig, err := loadingRules.Load() diff --git a/internal/operator/uninstall.go b/internal/operator/uninstall.go index 74374ead96..e161588785 100644 --- a/internal/operator/uninstall.go +++ b/internal/operator/uninstall.go @@ -41,6 +41,8 @@ type Uninstall struct { DeleteCRDs bool DeleteOperatorGroups bool DeleteOperatorGroupNames []string + + Logf func(string, ...interface{}) } func NewUninstall(cfg *Configuration) *Uninstall { @@ -156,7 +158,7 @@ func (u *Uninstall) deleteObjects(ctx context.Context, waitForDelete bool, objs if err := u.config.Client.Delete(ctx, obj); err != nil && !apierrors.IsNotFound(err) { return fmt.Errorf("delete %s %q: %v", lowerKind, obj.GetName(), err) } else if err == nil { - u.config.Log("%s %q deleted", lowerKind, obj.GetName()) + u.Logf("%s %q deleted", lowerKind, obj.GetName()) } if waitForDelete { key, err := client.ObjectKeyFromObject(obj) diff --git a/test/integration/operator_olm_test.go b/test/integration/operator_olm_test.go index 896f7ac07b..4d9bdeb4c6 100644 --- a/test/integration/operator_olm_test.go +++ b/test/integration/operator_olm_test.go @@ -273,12 +273,12 @@ func PackageManifestsMultiplePackages(t *testing.T) { func doUninstall(t *testing.T, kubeconfigPath string, timeout time.Duration) error { cfg := &operator2.Configuration{KubeconfigPath: kubeconfigPath} - cfg.Log = logrus.Infof assert.NoError(t, cfg.Load()) uninstall := operator2.NewUninstall(cfg) uninstall.DeleteAll = true uninstall.DeleteOperatorGroupNames = []string{operator2.SDKOperatorGroupName} uninstall.Package = defaultOperatorName + uninstall.Logf = logrus.Infof ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() From f0542bc81906a6b5365e2c164256baf22416246f Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Wed, 12 Aug 2020 12:54:37 -0400 Subject: [PATCH 5/9] PR review suggestions --- internal/cmd/operator-sdk/run/cmd.go | 4 +- internal/operator/bundle/install.go | 5 +- internal/operator/bundle/uninstall.go | 66 --------------------------- internal/registry/logger.go | 2 +- 4 files changed, 8 insertions(+), 69 deletions(-) delete mode 100644 internal/operator/bundle/uninstall.go diff --git a/internal/cmd/operator-sdk/run/cmd.go b/internal/cmd/operator-sdk/run/cmd.go index 8fddddd573..66c9636ecd 100644 --- a/internal/cmd/operator-sdk/run/cmd.go +++ b/internal/cmd/operator-sdk/run/cmd.go @@ -24,7 +24,9 @@ func NewCmd() *cobra.Command { cmd := &cobra.Command{ Use: "run", Short: "Run an Operator in a variety of environments", - Long: "This command has subcommands that will deploy your Operator with OLM.", + // TODO(joelanford): remove the second sentence when `run bundle` implementation is complete + Long: `This command has subcommands that will deploy your Operator with OLM. +Currently only the package manifests format is supported via the 'packagemanifests' subcommand.`, } cmd.AddCommand( diff --git a/internal/operator/bundle/install.go b/internal/operator/bundle/install.go index 49e1ac07f7..c8b47a2bff 100644 --- a/internal/operator/bundle/install.go +++ b/internal/operator/bundle/install.go @@ -96,7 +96,10 @@ func loadBundle(ctx context.Context, bundleImage string) (labels registryutil.La return nil, nil, fmt.Errorf("load bundle metadata: %v", err) } - relManifestsDir := labels["operators.operatorframework.io.bundle.manifests.v1"] + relManifestsDir, ok := labels.GetManifestsDir() + if !ok { + relManifestsDir = "manifests" + } manifestsDir := filepath.Join(bundlePath, relManifestsDir) csv, err = registry.ReadCSVFromBundleDirectory(manifestsDir) if err != nil { diff --git a/internal/operator/bundle/uninstall.go b/internal/operator/bundle/uninstall.go deleted file mode 100644 index 82709675a9..0000000000 --- a/internal/operator/bundle/uninstall.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2020 The Operator-SDK 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 bundle - -import ( - "context" - "fmt" - - "github.com/spf13/pflag" - - "github.com/operator-framework/operator-sdk/internal/operator" - "github.com/operator-framework/operator-sdk/internal/operator/internal" -) - -type Uninstall struct { - BundleImage string - - *internal.OperatorUninstaller -} - -func NewUninstall(cfg *operator.Configuration) Uninstall { - u := Uninstall{ - OperatorUninstaller: internal.NewOperatorUninstaller(cfg), - } - return u -} - -func (u *Uninstall) BindFlags(fs *pflag.FlagSet) { - // TODO: compare with packagemanifests cleanup flags. How does it work now? - fs.BoolVarP(&u.DeleteAll, "delete-all", "X", false, "Enable all deletion flags") - fs.BoolVar(&u.DeleteCRDs, "delete-crds", false, "Delete CRDs (and CRs) before cleaning up operator") - fs.BoolVar(&u.DeleteOperatorGroup, "delete-operator-group", false, "Delete Operator Group if no other subscriptions exist in this namespace") -} - -func (u Uninstall) Run(ctx context.Context) error { - if err := u.setup(ctx); err != nil { - return err - } - return u.UninstallOperator(ctx) -} - -func (u *Uninstall) setup(ctx context.Context) error { - labels, _, err := loadBundle(ctx, u.BundleImage) - if err != nil { - return fmt.Errorf("load bundle: %v", err) - } - - u.PackageName = labels["operators.operatorframework.io.bundle.package.v1"] - if u.DeleteAll { - u.DeleteOperatorGroup = true - u.DeleteCRDs = true - } - return nil -} diff --git a/internal/registry/logger.go b/internal/registry/logger.go index 32b6efc865..1f4c4d9a47 100644 --- a/internal/registry/logger.go +++ b/internal/registry/logger.go @@ -1,4 +1,4 @@ -// Copyright 2019 The Operator-SDK Authors +// Copyright 2020 The Operator-SDK Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From c3b0e375a38ca34b0cdec3180cc7355628f43ba9 Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Wed, 12 Aug 2020 14:04:02 -0400 Subject: [PATCH 6/9] remove the boilerplate cleanup logic (needs to be re-worked with new cleanup subcommand backend) --- internal/cmd/operator-sdk/run/bundle/cmd.go | 42 ++++++--------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/internal/cmd/operator-sdk/run/bundle/cmd.go b/internal/cmd/operator-sdk/run/bundle/cmd.go index 38383e572d..47212ae59a 100644 --- a/internal/cmd/operator-sdk/run/bundle/cmd.go +++ b/internal/cmd/operator-sdk/run/bundle/cmd.go @@ -16,10 +16,9 @@ package bundle import ( "context" - "fmt" - "os" "time" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/operator-framework/operator-sdk/internal/operator" @@ -28,55 +27,38 @@ import ( func NewCmd() *cobra.Command { var timeout time.Duration - var cleanupTimeout time.Duration - // TODO(joelanford): the initialization of cfg up to + // TODO(joelanford): move the initialization of cfg up to // the "run" subcommand when migrating packagemanifests // to this design. cfg := &operator.Configuration{} i := bundle.NewInstall(cfg) - u := bundle.NewUninstall(cfg) cmd := &cobra.Command{ - Use: "bundle ", - Short: "Deploy an Operator in the bundle format with OLM", - Hidden: true, - Args: cobra.ExactArgs(1), + Use: "bundle ", + Short: "Deploy an Operator in the bundle format with OLM", + Args: cobra.ExactArgs(1), PersistentPreRunE: func(_ *cobra.Command, _ []string) error { return cfg.Load() }, Run: func(cmd *cobra.Command, args []string) { - runCtx, runCancel := context.WithTimeout(cmd.Context(), timeout) - defer runCancel() + ctx, cancel := context.WithTimeout(cmd.Context(), timeout) + defer cancel() i.BundleImage = args[0] - u.BundleImage = args[0] - u.DeleteAll = true - csv, err := i.Run(runCtx) + // TODO(joelanford): Add cleanup logic if this fails? + csv, err := i.Run(ctx) if err != nil { - func() { - cancelCtx, cancelCancel := context.WithTimeout(cmd.Context(), cleanupTimeout) - defer cancelCancel() - - cleanupErr := u.Run(cancelCtx) - if cleanupErr != nil { - defer func() { - fmt.Printf("cleanup error: %v\n", cleanupErr) - }() - } - fmt.Printf("failed to run bundle: %v\n", err) - }() - os.Exit(1) + logrus.Fatalf("failed to run bundle: %v\n", err) } - fmt.Printf("csv %q installed\n", csv.Name) + logrus.Infof("csv %q installed\n", csv.Name) }, } cmd.Flags().SortFlags = false cfg.BindFlags(cmd.PersistentFlags()) i.BindFlags(cmd.Flags()) - cmd.Flags().DurationVar(&timeout, "timeout", 60*time.Second, "install timeout") - cmd.Flags().DurationVar(&cleanupTimeout, "cleanup-timeout", 10*time.Second, "cleanup timeout") + cmd.Flags().DurationVar(&timeout, "timeout", 2*time.Minute, "install timeout") return cmd } From ae254fd96404e1ede194dcf684c70f221468e17c Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Wed, 12 Aug 2020 16:26:34 -0400 Subject: [PATCH 7/9] fix sanity test, error on missing manifests label --- internal/cmd/operator-sdk/run/bundle/cmd.go | 4 ++-- internal/operator/bundle/install.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/cmd/operator-sdk/run/bundle/cmd.go b/internal/cmd/operator-sdk/run/bundle/cmd.go index 47212ae59a..153893c420 100644 --- a/internal/cmd/operator-sdk/run/bundle/cmd.go +++ b/internal/cmd/operator-sdk/run/bundle/cmd.go @@ -50,9 +50,9 @@ func NewCmd() *cobra.Command { // TODO(joelanford): Add cleanup logic if this fails? csv, err := i.Run(ctx) if err != nil { - logrus.Fatalf("failed to run bundle: %v\n", err) + logrus.Fatalf("Failed to run bundle: %v\n", err) } - logrus.Infof("csv %q installed\n", csv.Name) + logrus.Infof("CSV %q installed\n", csv.Name) }, } cmd.Flags().SortFlags = false diff --git a/internal/operator/bundle/install.go b/internal/operator/bundle/install.go index c8b47a2bff..769ed7f808 100644 --- a/internal/operator/bundle/install.go +++ b/internal/operator/bundle/install.go @@ -98,7 +98,7 @@ func loadBundle(ctx context.Context, bundleImage string) (labels registryutil.La relManifestsDir, ok := labels.GetManifestsDir() if !ok { - relManifestsDir = "manifests" + return nil, nil, fmt.Errorf("manifests directory not defined in bundle metadata") } manifestsDir := filepath.Join(bundlePath, relManifestsDir) csv, err = registry.ReadCSVFromBundleDirectory(manifestsDir) From e251520062f3877a41128c9fdb7c970c11f2c246 Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Wed, 12 Aug 2020 17:18:21 -0400 Subject: [PATCH 8/9] re-generate CLI docs --- website/content/en/docs/cli/operator-sdk_run.md | 1 + 1 file changed, 1 insertion(+) diff --git a/website/content/en/docs/cli/operator-sdk_run.md b/website/content/en/docs/cli/operator-sdk_run.md index 0a91662ba7..414fccc760 100644 --- a/website/content/en/docs/cli/operator-sdk_run.md +++ b/website/content/en/docs/cli/operator-sdk_run.md @@ -8,6 +8,7 @@ Run an Operator in a variety of environments ### Synopsis This command has subcommands that will deploy your Operator with OLM. +Currently only the package manifests format is supported via the 'packagemanifests' subcommand. ### Options From b560e681157e59dcb991ce423e1880b5a5d13b38 Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Wed, 12 Aug 2020 20:47:40 -0400 Subject: [PATCH 9/9] delete unnecessary operator_uninstaller.go --- .../operator/internal/operator_uninstaller.go | 54 ------------------- 1 file changed, 54 deletions(-) delete mode 100644 internal/operator/internal/operator_uninstaller.go diff --git a/internal/operator/internal/operator_uninstaller.go b/internal/operator/internal/operator_uninstaller.go deleted file mode 100644 index c4cf694d7c..0000000000 --- a/internal/operator/internal/operator_uninstaller.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2020 The Operator-SDK 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 internal - -import ( - "context" - "fmt" - - "github.com/operator-framework/operator-sdk/internal/operator" -) - -type OperatorUninstaller struct { - PackageName string - DeleteCRDs bool - DeleteOperatorGroup bool - DeleteAll bool - - cfg *operator.Configuration -} - -func NewOperatorUninstaller(cfg *operator.Configuration) *OperatorUninstaller { - return &OperatorUninstaller{ - cfg: cfg, - } -} - -func (u OperatorUninstaller) UninstallOperator(ctx context.Context) error { - fmt.Printf("OperatorUninstaller.PackageName: %q\n", u.PackageName) - fmt.Printf("OperatorUninstaller.DeleteCRDs: %v\n", u.DeleteCRDs) - fmt.Printf("OperatorUninstaller.DeleteOperatorGroup: %v\n", u.DeleteOperatorGroup) - fmt.Printf("OperatorUninstaller.DeleteAll: %v\n", u.DeleteAll) - - // Delete Subscription - - // Delete CRDs (if delete-crds option set) - - // Delete CSV - - // Delete OperatorGroup (if delete-operator-group option set - // and no more subscriptions remaining in NS) - return nil -}