diff --git a/go.mod b/go.mod index 36452175..d6e33dd0 100644 --- a/go.mod +++ b/go.mod @@ -5,12 +5,14 @@ go 1.23.0 toolchain go1.23.4 require ( + github.com/blang/semver/v4 v4.0.0 github.com/containerd/containerd v1.7.25 github.com/containerd/platforms v0.2.1 github.com/onsi/ginkgo v1.16.5 github.com/onsi/gomega v1.36.2 github.com/opencontainers/image-spec v1.1.0 github.com/operator-framework/api v0.29.0 + github.com/operator-framework/catalogd v1.1.0 github.com/operator-framework/operator-controller v1.1.0 github.com/operator-framework/operator-lifecycle-manager v0.23.1 github.com/operator-framework/operator-registry v1.50.0 @@ -32,7 +34,6 @@ require ( github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Microsoft/hcsshim v0.12.9 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect - github.com/blang/semver/v4 v4.0.0 // indirect github.com/containerd/cgroups/v3 v3.0.3 // indirect github.com/containerd/containerd/api v1.8.0 // indirect github.com/containerd/continuity v0.4.4 // indirect diff --git a/go.sum b/go.sum index 2cd77898..ce0511d2 100644 --- a/go.sum +++ b/go.sum @@ -242,6 +242,8 @@ github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/operator-framework/api v0.29.0 h1:TxAR8RCO+I4FjRrY4PSMgnlmbxNWeD8pzHXp7xwHNmw= github.com/operator-framework/api v0.29.0/go.mod h1:0whQE4mpMDd2zyHkQe+bFa3DLoRs6oGWCbu8dY/3pyc= +github.com/operator-framework/catalogd v1.1.0 h1:mu2DYL5mpREEAAP+uPG+CMSsfsJkgrIasgLRG8nvwJg= +github.com/operator-framework/catalogd v1.1.0/go.mod h1:8Je9CqMPwhNgRoqGX5OPsLYHsEoTDvPnELLLKRw1RHE= github.com/operator-framework/operator-controller v1.1.0 h1:h0b1SSuv9ZiIgI8dTuutSPVL4uIeyvTW3gOB2szkBMQ= github.com/operator-framework/operator-controller v1.1.0/go.mod h1:dJIt5/gfm1n3y9IeX4kpSlpu4CFq8WFVHU2n9ZDVUkA= github.com/operator-framework/operator-lifecycle-manager v0.23.1 h1:Xw2ml1T4W2ieoFaVwanW/eFlZ11yAOJZUpUI8RLSql8= diff --git a/internal/cmd/internal/olmv1/action_suite_test.go b/internal/cmd/internal/olmv1/action_suite_test.go new file mode 100644 index 00000000..77867e3c --- /dev/null +++ b/internal/cmd/internal/olmv1/action_suite_test.go @@ -0,0 +1,13 @@ +package olmv1 + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestCommand(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Internal action Suite") +} diff --git a/internal/cmd/internal/olmv1/catalog_installed_get.go b/internal/cmd/internal/olmv1/catalog_installed_get.go new file mode 100644 index 00000000..87eb5dd1 --- /dev/null +++ b/internal/cmd/internal/olmv1/catalog_installed_get.go @@ -0,0 +1,38 @@ +package olmv1 + +import ( + "github.com/spf13/cobra" + + "github.com/operator-framework/kubectl-operator/internal/cmd/internal/log" + v1action "github.com/operator-framework/kubectl-operator/internal/pkg/v1/action" + "github.com/operator-framework/kubectl-operator/pkg/action" +) + +// NewCatalogInstalledGetCmd handles get commands in the form of: +// catalog(s) [catalog_name] - this will either list all the installed operators +// if no catalog_name has been provided or display the details of the specific +// one otherwise +func NewCatalogInstalledGetCmd(cfg *action.Configuration) *cobra.Command { + i := v1action.NewCatalogInstalledGet(cfg) + i.Logf = log.Printf + + cmd := &cobra.Command{ + Use: "catalog [catalog_name]", + Aliases: []string{"catalogs"}, + Args: cobra.RangeArgs(0, 1), + Short: "Display one or many installed catalogs", + Run: func(cmd *cobra.Command, args []string) { + if len(args) == 1 { + i.CatalogName = args[0] + } + installedCatalogs, err := i.Run(cmd.Context()) + if err != nil { + log.Fatalf("failed getting installed catalog(s): %v", err) + } + + printFormattedCatalogs(installedCatalogs...) + }, + } + + return cmd +} diff --git a/internal/cmd/internal/olmv1/operator_installed_get.go b/internal/cmd/internal/olmv1/operator_installed_get.go new file mode 100644 index 00000000..f5d0747c --- /dev/null +++ b/internal/cmd/internal/olmv1/operator_installed_get.go @@ -0,0 +1,38 @@ +package olmv1 + +import ( + "github.com/spf13/cobra" + + "github.com/operator-framework/kubectl-operator/internal/cmd/internal/log" + v1action "github.com/operator-framework/kubectl-operator/internal/pkg/v1/action" + "github.com/operator-framework/kubectl-operator/pkg/action" +) + +// NewOperatorInstalledGetCmd handles get commands in the form of: +// operator(s) [operator_name] - this will either list all the installed operators +// if no operator_name has been provided or display the details of the specific +// one otherwise +func NewOperatorInstalledGetCmd(cfg *action.Configuration) *cobra.Command { + i := v1action.NewOperatorInstalledGet(cfg) + i.Logf = log.Printf + + cmd := &cobra.Command{ + Use: "operator [operator_name]", + Aliases: []string{"operators"}, + Args: cobra.RangeArgs(0, 1), + Short: "Display one or many installed operators", + Run: func(cmd *cobra.Command, args []string) { + if len(args) == 1 { + i.OperatorName = args[0] + } + installedExtensions, err := i.Run(cmd.Context()) + if err != nil { + log.Fatalf("failed getting installed operator(s): %v", err) + } + + printFormattedOperators(installedExtensions...) + }, + } + + return cmd +} diff --git a/internal/cmd/internal/olmv1/printing.go b/internal/cmd/internal/olmv1/printing.go new file mode 100644 index 00000000..c4b60ce2 --- /dev/null +++ b/internal/cmd/internal/olmv1/printing.go @@ -0,0 +1,90 @@ +package olmv1 + +import ( + "cmp" + "fmt" + "os" + "slices" + "text/tabwriter" + "time" + + "github.com/blang/semver/v4" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/duration" + + catalogdv1 "github.com/operator-framework/catalogd/api/v1" + olmv1 "github.com/operator-framework/operator-controller/api/v1" +) + +func printFormattedOperators(extensions ...olmv1.ClusterExtension) { + tw := tabwriter.NewWriter(os.Stdout, 3, 4, 2, ' ', 0) + _, _ = fmt.Fprint(tw, "NAME\tINSTALLED BUNDLE\tVERSION\tSOURCE TYPE\tINSTALLED\tPROGRESSING\tAGE\n") + + sortOperators(extensions) + for _, ext := range extensions { + age := time.Since(ext.CreationTimestamp.Time) + _, _ = fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", + ext.Name, + ext.Status.Install.Bundle.Name, + ext.Status.Install.Bundle.Version, + ext.Spec.Source.SourceType, + status(ext.Status.Conditions, olmv1.TypeInstalled), + status(ext.Status.Conditions, olmv1.TypeProgressing), + duration.HumanDuration(age), + ) + } + _ = tw.Flush() +} + +func printFormattedCatalogs(catalogs ...catalogdv1.ClusterCatalog) { + tw := tabwriter.NewWriter(os.Stdout, 3, 4, 2, ' ', 0) + _, _ = fmt.Fprint(tw, "NAME\tAVAILABILITY\tPRIORITY\tLASTUNPACKED\tSERVING\tAGE\n") + + sortCatalogs(catalogs) + for _, cat := range catalogs { + age := time.Since(cat.CreationTimestamp.Time) + lastUnpacked := time.Since(cat.Status.LastUnpacked.Time) + _, _ = fmt.Fprintf(tw, "%s\t%s\t%d\t%s\t%s\t%s\n", + cat.Name, + string(cat.Spec.AvailabilityMode), + cat.Spec.Priority, + duration.HumanDuration(lastUnpacked), + status(cat.Status.Conditions, catalogdv1.TypeServing), + duration.HumanDuration(age), + ) + } + _ = tw.Flush() +} + +// sortOperators sorts operators in place and uses the following sorting order: +// name (asc), version (desc) +func sortOperators(extensions []olmv1.ClusterExtension) { + slices.SortFunc(extensions, func(a, b olmv1.ClusterExtension) int { + return cmp.Or( + cmp.Compare(a.Name, b.Name), + -semver.MustParse(a.Status.Install.Bundle.Version).Compare(semver.MustParse(b.Status.Install.Bundle.Version)), + ) + }) +} + +// sortCatalogs sorts catalogs in place and uses the following sorting order: +// availability (asc), priority (desc), name (asc) +func sortCatalogs(catalogs []catalogdv1.ClusterCatalog) { + slices.SortFunc(catalogs, func(a, b catalogdv1.ClusterCatalog) int { + return cmp.Or( + cmp.Compare(a.Spec.AvailabilityMode, b.Spec.AvailabilityMode), + -cmp.Compare(a.Spec.Priority, b.Spec.Priority), + cmp.Compare(a.Name, b.Name), + ) + }) +} + +func status(conditions []metav1.Condition, typ string) string { + for _, condition := range conditions { + if condition.Type == typ { + return string(condition.Status) + } + } + + return "Unknown" +} diff --git a/internal/cmd/internal/olmv1/printing_test.go b/internal/cmd/internal/olmv1/printing_test.go new file mode 100644 index 00000000..7596562a --- /dev/null +++ b/internal/cmd/internal/olmv1/printing_test.go @@ -0,0 +1,68 @@ +package olmv1 + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + olmv1catalogd "github.com/operator-framework/catalogd/api/v1" + olmv1 "github.com/operator-framework/operator-controller/api/v1" +) + +var _ = Describe("SortCatalogs", func() { + It("sorts catalogs in correct order", func() { + catalogs := []olmv1catalogd.ClusterCatalog{ + newClusterCatalog("cat-unavailable-0", olmv1catalogd.AvailabilityModeUnavailable, 0), + newClusterCatalog("cat-unavailable-1", olmv1catalogd.AvailabilityModeUnavailable, 1), + newClusterCatalog("cat-available-0", olmv1catalogd.AvailabilityModeAvailable, 0), + newClusterCatalog("cat-available-1", olmv1catalogd.AvailabilityModeAvailable, 1), + } + sortCatalogs(catalogs) + + Expect(catalogs[0].Name).To(Equal("cat-available-1")) + Expect(catalogs[1].Name).To(Equal("cat-available-0")) + Expect(catalogs[2].Name).To(Equal("cat-unavailable-1")) + Expect(catalogs[3].Name).To(Equal("cat-unavailable-0")) + }) +}) + +var _ = Describe("SortOperators", func() { + It("sorts operators in correct order", func() { + operators := []olmv1.ClusterExtension{ + newClusterExtension("op-1", "1.0.0"), + newClusterExtension("op-1", "1.0.1"), + newClusterExtension("op-1", "1.0.1-rc4"), + newClusterExtension("op-1", "1.0.1-rc2"), + newClusterExtension("op-2", "2.0.0"), + } + sortOperators(operators) + + Expect(operators[0].Status.Install.Bundle.Version).To(Equal("1.0.1")) + Expect(operators[1].Status.Install.Bundle.Version).To(Equal("1.0.1-rc4")) + Expect(operators[2].Status.Install.Bundle.Version).To(Equal("1.0.1-rc2")) + Expect(operators[3].Status.Install.Bundle.Version).To(Equal("1.0.0")) + Expect(operators[4].Status.Install.Bundle.Version).To(Equal("2.0.0")) + }) +}) + +func newClusterCatalog(name string, availabilityMode olmv1catalogd.AvailabilityMode, priority int32) olmv1catalogd.ClusterCatalog { + return olmv1catalogd.ClusterCatalog{ + ObjectMeta: metav1.ObjectMeta{Name: name}, + Spec: olmv1catalogd.ClusterCatalogSpec{AvailabilityMode: availabilityMode, Priority: priority}, + } +} + +func newClusterExtension(name, version string) olmv1.ClusterExtension { + return olmv1.ClusterExtension{ + ObjectMeta: metav1.ObjectMeta{Name: name}, + Status: olmv1.ClusterExtensionStatus{ + Install: &olmv1.ClusterExtensionInstallStatus{ + Bundle: olmv1.BundleMetadata{ + Name: name, + Version: version, + }, + }, + }, + } +} diff --git a/internal/cmd/olmv1.go b/internal/cmd/olmv1.go index 9ca930b4..e986d73a 100644 --- a/internal/cmd/olmv1.go +++ b/internal/cmd/olmv1.go @@ -14,9 +14,20 @@ func newOlmV1Cmd(cfg *action.Configuration) *cobra.Command { Long: "Manage operators via OLMv1 in a cluster from the command line.", } + getCmd := &cobra.Command{ + Use: "get", + Short: "Display one or many OLMv1-specific resource(s)", + Long: "Display one or many OLMv1-specific resource(s)", + } + getCmd.AddCommand( + olmv1.NewOperatorInstalledGetCmd(cfg), + olmv1.NewCatalogInstalledGetCmd(cfg), + ) + cmd.AddCommand( olmv1.NewOperatorInstallCmd(cfg), olmv1.NewOperatorUninstallCmd(cfg), + getCmd, ) return cmd diff --git a/internal/pkg/v1/action/action_suite_test.go b/internal/pkg/v1/action/action_suite_test.go new file mode 100644 index 00000000..40957f3d --- /dev/null +++ b/internal/pkg/v1/action/action_suite_test.go @@ -0,0 +1,13 @@ +package action_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestCommand(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Internal action Suite") +} diff --git a/internal/pkg/v1/action/catalog_installed_get.go b/internal/pkg/v1/action/catalog_installed_get.go new file mode 100644 index 00000000..d602c535 --- /dev/null +++ b/internal/pkg/v1/action/catalog_installed_get.go @@ -0,0 +1,47 @@ +package action + +import ( + "context" + + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + olmv1catalogd "github.com/operator-framework/catalogd/api/v1" + + "github.com/operator-framework/kubectl-operator/pkg/action" +) + +type CatalogInstalledGet struct { + config *action.Configuration + CatalogName string + + Logf func(string, ...interface{}) +} + +func NewCatalogInstalledGet(cfg *action.Configuration) *CatalogInstalledGet { + return &CatalogInstalledGet{ + config: cfg, + Logf: func(string, ...interface{}) {}, + } +} + +func (i *CatalogInstalledGet) Run(ctx context.Context) ([]olmv1catalogd.ClusterCatalog, error) { + // get + if i.CatalogName != "" { + var result olmv1catalogd.ClusterCatalog + + opKey := types.NamespacedName{Name: i.CatalogName} + err := i.config.Client.Get(ctx, opKey, &result) + if err != nil { + return nil, err + } + + return []olmv1catalogd.ClusterCatalog{result}, nil + } + + // list + var result olmv1catalogd.ClusterCatalogList + err := i.config.Client.List(ctx, &result, &client.ListOptions{}) + + return result.Items, err +} diff --git a/internal/pkg/v1/action/catalog_installed_get_test.go b/internal/pkg/v1/action/catalog_installed_get_test.go new file mode 100644 index 00000000..b9a77f1d --- /dev/null +++ b/internal/pkg/v1/action/catalog_installed_get_test.go @@ -0,0 +1,99 @@ +package action_test + +import ( + "context" + "fmt" + "slices" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + olmv1catalogd "github.com/operator-framework/catalogd/api/v1" + + internalaction "github.com/operator-framework/kubectl-operator/internal/pkg/v1/action" + "github.com/operator-framework/kubectl-operator/pkg/action" +) + +var _ = Describe("CatalogInstalledGet", func() { + setupEnv := func(catalogs ...client.Object) action.Configuration { + var cfg action.Configuration + + sch, err := action.NewScheme() + Expect(err).To(BeNil()) + + cl := fake.NewClientBuilder(). + WithObjects(catalogs...). + WithScheme(sch). + Build() + cfg.Scheme = sch + cfg.Client = cl + + return cfg + } + + It("lists all installed catalogs", func() { + cfg := setupEnv(setupTestCatalogs(3)...) + + getter := internalaction.NewCatalogInstalledGet(&cfg) + catalogs, err := getter.Run(context.TODO()) + Expect(err).To(BeNil()) + Expect(catalogs).NotTo(BeEmpty()) + Expect(catalogs).To(HaveLen(3)) + + for _, testCatalogName := range []string{"cat1", "cat2", "cat3"} { + Expect(slices.ContainsFunc(catalogs, func(cat olmv1catalogd.ClusterCatalog) bool { + return cat.Name == testCatalogName + })).To(BeTrue()) + } + }) + + It("returns empty list in case no catalogs were found", func() { + cfg := setupEnv() + + getter := internalaction.NewOperatorInstalledGet(&cfg) + operators, err := getter.Run(context.TODO()) + Expect(err).To(BeNil()) + Expect(operators).To(BeEmpty()) + }) + + It("gets an installed catalog", func() { + cfg := setupEnv(setupTestCatalogs(3)...) + + getter := internalaction.NewCatalogInstalledGet(&cfg) + getter.CatalogName = "cat2" + operators, err := getter.Run(context.TODO()) + Expect(err).To(BeNil()) + Expect(operators).NotTo(BeEmpty()) + Expect(operators).To(HaveLen(1)) + Expect(operators[0].Name).To(Equal("cat2")) + }) + + It("returns an empty list when an installed catalog was not found", func() { + cfg := setupEnv() + + getter := internalaction.NewOperatorInstalledGet(&cfg) + getter.OperatorName = "cat2" + operators, err := getter.Run(context.TODO()) + Expect(err).NotTo(BeNil()) + Expect(operators).To(BeEmpty()) + }) +}) + +func setupTestCatalogs(n int) []client.Object { + var result []client.Object + for i := 1; i <= n; i++ { + result = append(result, newClusterCatalog(fmt.Sprintf("cat%d", i))) + } + + return result +} + +func newClusterCatalog(name string) *olmv1catalogd.ClusterCatalog { + return &olmv1catalogd.ClusterCatalog{ + ObjectMeta: metav1.ObjectMeta{Name: name}, + } +} diff --git a/internal/pkg/v1/action/operator_installed_get.go b/internal/pkg/v1/action/operator_installed_get.go new file mode 100644 index 00000000..ec2e56b0 --- /dev/null +++ b/internal/pkg/v1/action/operator_installed_get.go @@ -0,0 +1,46 @@ +package action + +import ( + "context" + + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + olmv1 "github.com/operator-framework/operator-controller/api/v1" + + "github.com/operator-framework/kubectl-operator/pkg/action" +) + +type OperatorInstalledGet struct { + config *action.Configuration + OperatorName string + + Logf func(string, ...interface{}) +} + +func NewOperatorInstalledGet(cfg *action.Configuration) *OperatorInstalledGet { + return &OperatorInstalledGet{ + config: cfg, + Logf: func(string, ...interface{}) {}, + } +} + +func (i *OperatorInstalledGet) Run(ctx context.Context) ([]olmv1.ClusterExtension, error) { + // get + if i.OperatorName != "" { + var result olmv1.ClusterExtension + opKey := types.NamespacedName{Name: i.OperatorName} + err := i.config.Client.Get(ctx, opKey, &result) + if err != nil { + return nil, err + } + + return []olmv1.ClusterExtension{result}, nil + } + + // list + var result olmv1.ClusterExtensionList + err := i.config.Client.List(ctx, &result, &client.ListOptions{}) + + return result.Items, err +} diff --git a/internal/pkg/v1/action/operator_installed_get_test.go b/internal/pkg/v1/action/operator_installed_get_test.go new file mode 100644 index 00000000..f4a536c6 --- /dev/null +++ b/internal/pkg/v1/action/operator_installed_get_test.go @@ -0,0 +1,107 @@ +package action_test + +import ( + "context" + "fmt" + "slices" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + olmv1 "github.com/operator-framework/operator-controller/api/v1" + + internalaction "github.com/operator-framework/kubectl-operator/internal/pkg/v1/action" + "github.com/operator-framework/kubectl-operator/pkg/action" +) + +var _ = Describe("OperatorInstalledGet", func() { + setupEnv := func(operators ...client.Object) action.Configuration { + var cfg action.Configuration + + sch, err := action.NewScheme() + Expect(err).To(BeNil()) + + cl := fake.NewClientBuilder(). + WithObjects(operators...). + WithScheme(sch). + Build() + cfg.Scheme = sch + cfg.Client = cl + + return cfg + } + + It("lists all installed operators", func() { + cfg := setupEnv(setupTestOperators(3)...) + + getter := internalaction.NewOperatorInstalledGet(&cfg) + operators, err := getter.Run(context.TODO()) + Expect(err).To(BeNil()) + Expect(operators).NotTo(BeEmpty()) + Expect(operators).To(HaveLen(3)) + + for _, testOperatorName := range []string{"ext1", "ext2", "ext3"} { + Expect(slices.ContainsFunc(operators, func(op olmv1.ClusterExtension) bool { + return op.Name == testOperatorName + })).To(BeTrue()) + } + }) + + It("returns empty list in case no operators were found", func() { + cfg := setupEnv() + + getter := internalaction.NewOperatorInstalledGet(&cfg) + operators, err := getter.Run(context.TODO()) + Expect(err).To(BeNil()) + Expect(operators).To(BeEmpty()) + }) + + It("gets an installed operator", func() { + cfg := setupEnv(setupTestOperators(3)...) + + getter := internalaction.NewOperatorInstalledGet(&cfg) + getter.OperatorName = "ext2" + operators, err := getter.Run(context.TODO()) + Expect(err).To(BeNil()) + Expect(operators).NotTo(BeEmpty()) + Expect(operators).To(HaveLen(1)) + Expect(operators[0].Name).To(Equal("ext2")) + }) + + It("returns an empty list and an error when an installed operator was not found", func() { + cfg := setupEnv() + + getter := internalaction.NewOperatorInstalledGet(&cfg) + getter.OperatorName = "ext2" + operators, err := getter.Run(context.TODO()) + Expect(err).NotTo(BeNil()) + Expect(operators).To(BeEmpty()) + }) +}) + +func setupTestOperators(n int) []client.Object { + var result []client.Object + for i := 1; i <= n; i++ { + result = append(result, newClusterExtension(fmt.Sprintf("ext%d", i), fmt.Sprintf("%d.0", n))) + } + + return result +} + +func newClusterExtension(name, version string) *olmv1.ClusterExtension { + return &olmv1.ClusterExtension{ + ObjectMeta: metav1.ObjectMeta{Name: name}, + Status: olmv1.ClusterExtensionStatus{ + Install: &olmv1.ClusterExtensionInstallStatus{ + Bundle: olmv1.BundleMetadata{ + Name: name, + Version: version, + }, + }, + }, + } +} diff --git a/pkg/action/config.go b/pkg/action/config.go index f265aef8..e550a94d 100644 --- a/pkg/action/config.go +++ b/pkg/action/config.go @@ -11,6 +11,7 @@ import ( v1 "github.com/operator-framework/api/pkg/operators/v1" "github.com/operator-framework/api/pkg/operators/v1alpha1" + catalogdv1 "github.com/operator-framework/catalogd/api/v1" olmv1 "github.com/operator-framework/operator-controller/api/v1" operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1" ) @@ -23,6 +24,7 @@ func NewScheme() (*runtime.Scheme, error) { v1.AddToScheme, apiextensionsv1.AddToScheme, olmv1.AddToScheme, + catalogdv1.AddToScheme, } { if err := f(sch); err != nil { return nil, err