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/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/cmd/operator-sdk/run/bundle/cmd.go b/internal/cmd/operator-sdk/run/bundle/cmd.go new file mode 100644 index 0000000000..153893c420 --- /dev/null +++ b/internal/cmd/operator-sdk/run/bundle/cmd.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 bundle + +import ( + "context" + "time" + + "github.com/sirupsen/logrus" + "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): move the initialization of cfg up to + // the "run" subcommand when migrating packagemanifests + // to this design. + cfg := &operator.Configuration{} + + i := bundle.NewInstall(cfg) + cmd := &cobra.Command{ + 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) { + ctx, cancel := context.WithTimeout(cmd.Context(), timeout) + defer cancel() + + i.BundleImage = args[0] + + // 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.Infof("CSV %q installed\n", csv.Name) + }, + } + cmd.Flags().SortFlags = false + cfg.BindFlags(cmd.PersistentFlags()) + i.BindFlags(cmd.Flags()) + + cmd.Flags().DurationVar(&timeout, "timeout", 2*time.Minute, "install timeout") + return cmd +} diff --git a/internal/cmd/operator-sdk/run/cmd.go b/internal/cmd/operator-sdk/run/cmd.go index 63633c3145..66c9636ecd 100644 --- a/internal/cmd/operator-sdk/run/cmd.go +++ b/internal/cmd/operator-sdk/run/cmd.go @@ -24,13 +24,14 @@ func NewCmd() *cobra.Command { cmd := &cobra.Command{ Use: "run", Short: "Run an Operator in a variety of environments", + // 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. -Run 'operator-sdk run --help' for more information. -`, +Currently only the package manifests format is supported via the 'packagemanifests' subcommand.`, } 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/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 new file mode 100644 index 0000000000..769ed7f808 --- /dev/null +++ b/internal/operator/bundle/install.go @@ -0,0 +1,110 @@ +// 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" + "path/filepath" + "strings" + + "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/operator-framework/operator-registry/pkg/registry" + "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, nil, 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, ok := labels.GetManifestsDir() + if !ok { + return nil, nil, fmt.Errorf("manifests directory not defined in bundle metadata") + } + 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 +} 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/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..070bd00ffd --- /dev/null +++ b/internal/operator/internal/index_image.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 internal + +import ( + "context" + "fmt" + "strings" + + "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 { + 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) { + 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) + + // 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 +} + +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/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/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/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..1f4c4d9a47 --- /dev/null +++ b/internal/registry/logger.go @@ -0,0 +1,28 @@ +// 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 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{ 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() 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:** diff --git a/website/content/en/docs/cli/operator-sdk_run.md b/website/content/en/docs/cli/operator-sdk_run.md index 3c50cfec00..414fccc760 100644 --- a/website/content/en/docs/cli/operator-sdk_run.md +++ b/website/content/en/docs/cli/operator-sdk_run.md @@ -9,8 +9,6 @@ Run an Operator in a variety of environments 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