diff --git a/internal/cmd/internal/olmv1/operator_install.go b/internal/cmd/internal/olmv1/extension_install.go similarity index 64% rename from internal/cmd/internal/olmv1/operator_install.go rename to internal/cmd/internal/olmv1/extension_install.go index 8795d927..0b6032cb 100644 --- a/internal/cmd/internal/olmv1/operator_install.go +++ b/internal/cmd/internal/olmv1/extension_install.go @@ -8,21 +8,21 @@ import ( "github.com/operator-framework/kubectl-operator/pkg/action" ) -func NewOperatorInstallCmd(cfg *action.Configuration) *cobra.Command { - i := v1action.NewOperatorInstall(cfg) +func NewExtensionInstallCmd(cfg *action.Configuration) *cobra.Command { + i := v1action.NewExtensionInstall(cfg) i.Logf = log.Printf cmd := &cobra.Command{ - Use: "install ", - Short: "Install an operator", + Use: "install ", + Short: "Install an extension", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { i.Package = args[0] _, err := i.Run(cmd.Context()) if err != nil { - log.Fatalf("failed to install operator: %v", err) + log.Fatalf("failed to install extension: %v", err) } - log.Printf("operator %q created", i.Package) + log.Printf("extension %q created", i.Package) }, } diff --git a/internal/cmd/internal/olmv1/extension_installed_get.go b/internal/cmd/internal/olmv1/extension_installed_get.go new file mode 100644 index 00000000..b85a93b9 --- /dev/null +++ b/internal/cmd/internal/olmv1/extension_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" +) + +// NewExtensionInstalledGetCmd handles get commands in the form of: +// extension(s) [extension_name] - this will either list all the installed extensions +// if no extension_name has been provided or display the details of the specific +// one otherwise +func NewExtensionInstalledGetCmd(cfg *action.Configuration) *cobra.Command { + i := v1action.NewExtensionInstalledGet(cfg) + i.Logf = log.Printf + + cmd := &cobra.Command{ + Use: "extension [extension_name]", + Aliases: []string{"extensions [extension_name]"}, + Args: cobra.RangeArgs(0, 1), + Short: "Display one or many installed extensions", + Run: func(cmd *cobra.Command, args []string) { + if len(args) == 1 { + i.ExtensionName = args[0] + } + installedExtensions, err := i.Run(cmd.Context()) + if err != nil { + log.Fatalf("failed getting installed extension(s): %v", err) + } + + printFormattedExtensions(installedExtensions...) + }, + } + + return cmd +} diff --git a/internal/cmd/internal/olmv1/operator_uninstall.go b/internal/cmd/internal/olmv1/extension_uninstall.go similarity index 59% rename from internal/cmd/internal/olmv1/operator_uninstall.go rename to internal/cmd/internal/olmv1/extension_uninstall.go index 25deff7b..3bc54194 100644 --- a/internal/cmd/internal/olmv1/operator_uninstall.go +++ b/internal/cmd/internal/olmv1/extension_uninstall.go @@ -8,26 +8,26 @@ import ( "github.com/operator-framework/kubectl-operator/pkg/action" ) -func NewOperatorUninstallCmd(cfg *action.Configuration) *cobra.Command { - u := v1action.NewOperatorUninstall(cfg) +func NewExtensionUninstallCmd(cfg *action.Configuration) *cobra.Command { + u := v1action.NewExtensionUninstall(cfg) u.Logf = log.Printf cmd := &cobra.Command{ - Use: "uninstall ", - Short: "Uninstall an operator", - Long: `Uninstall deletes the named Operator object. + Use: "uninstall ", + Short: "Uninstall an extension", + Long: `Uninstall deletes the named extension object. Warning: this command permanently deletes objects from the cluster. If the -uninstalled Operator bundle contains CRDs, the CRDs will be deleted, which +uninstalled extension bundle contains CRDs, the CRDs will be deleted, which cascades to the deletion of all operands. `, Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { u.Package = args[0] if err := u.Run(cmd.Context()); err != nil { - log.Fatalf("uninstall operator: %v", err) + log.Fatalf("uninstall extension: %v", err) } - log.Printf("deleted operator %q", u.Package) + log.Printf("deleted extension %q", u.Package) }, } return cmd diff --git a/internal/cmd/internal/olmv1/operator_update.go b/internal/cmd/internal/olmv1/extension_update.go similarity index 61% rename from internal/cmd/internal/olmv1/operator_update.go rename to internal/cmd/internal/olmv1/extension_update.go index c0a76c28..9fe1f544 100644 --- a/internal/cmd/internal/olmv1/operator_update.go +++ b/internal/cmd/internal/olmv1/extension_update.go @@ -9,34 +9,34 @@ import ( "github.com/operator-framework/kubectl-operator/pkg/action" ) -// NewOperatorUpdateCmd allows updating a selected operator -func NewOperatorUpdateCmd(cfg *action.Configuration) *cobra.Command { - i := v1action.NewOperatorUpdate(cfg) +// NewExtensionUpdateCmd allows updating a selected operator +func NewExtensionUpdateCmd(cfg *action.Configuration) *cobra.Command { + i := v1action.NewExtensionUpdate(cfg) i.Logf = log.Printf cmd := &cobra.Command{ - Use: "operator ", - Short: "Update an operator", + Use: "extension ", + Short: "Update an extension", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { i.Package = args[0] _, err := i.Run(cmd.Context()) if err != nil { - log.Fatalf("failed to update operator: %v", err) + log.Fatalf("failed to update extension: %v", err) } - log.Printf("operator %q updated", i.Package) + log.Printf("extension %q updated", i.Package) }, } - bindOperatorUpdateFlags(cmd.Flags(), i) + bindExtensionUpdateFlags(cmd.Flags(), i) return cmd } -func bindOperatorUpdateFlags(fs *pflag.FlagSet, i *v1action.OperatorUpdate) { - fs.StringVar(&i.Version, "version", "", "desired operator version (single or range) in semVer format. AND operation with channels") +func bindExtensionUpdateFlags(fs *pflag.FlagSet, i *v1action.ExtensionUpdate) { + fs.StringVar(&i.Version, "version", "", "desired extension version (single or range) in semVer format. AND operation with channels") fs.StringVar(&i.Selector, "selector", "", "filters the set of catalogs used in the bundle selection process. Empty means that all catalogs will be used in the bundle selection process") - fs.StringArrayVar(&i.Channels, "channels", []string{}, "desired channels for operator versions. AND operation with version. Empty list means all available channels will be taken into consideration") + fs.StringArrayVar(&i.Channels, "channels", []string{}, "desired channels for extension versions. AND operation with version. Empty list means all available channels will be taken into consideration") fs.StringVar(&i.UpgradeConstraintPolicy, "upgrade-constraint-policy", "", "controls whether the upgrade path(s) defined in the catalog are enforced. One of CatalogProvided|SelfCertified), Default: CatalogProvided") - fs.StringToStringVar(&i.Labels, "labels", map[string]string{}, "labels that will be set on the operator") + fs.StringToStringVar(&i.Labels, "labels", map[string]string{}, "labels that will be set on the extension") fs.BoolVar(&i.IgnoreUnset, "ignore-unset", true, "when enabled, any unset flag value will not be changed. Disabling means that for each unset value a default will be used instead") } diff --git a/internal/cmd/internal/olmv1/operator_installed_get.go b/internal/cmd/internal/olmv1/operator_installed_get.go deleted file mode 100644 index f5d0747c..00000000 --- a/internal/cmd/internal/olmv1/operator_installed_get.go +++ /dev/null @@ -1,38 +0,0 @@ -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 index 4da607c2..8d62181b 100644 --- a/internal/cmd/internal/olmv1/printing.go +++ b/internal/cmd/internal/olmv1/printing.go @@ -15,11 +15,11 @@ import ( olmv1 "github.com/operator-framework/operator-controller/api/v1" ) -func printFormattedOperators(extensions ...olmv1.ClusterExtension) { +func printFormattedExtensions(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) + sortExtensions(extensions) for _, ext := range extensions { var bundleName, bundleVersion string if ext.Status.Install != nil { @@ -63,9 +63,9 @@ func printFormattedCatalogs(catalogs ...olmv1.ClusterCatalog) { _ = tw.Flush() } -// sortOperators sorts operators in place and uses the following sorting order: +// sortExtensions sorts extensions in place and uses the following sorting order: // name (asc), version (desc) -func sortOperators(extensions []olmv1.ClusterExtension) { +func sortExtensions(extensions []olmv1.ClusterExtension) { slices.SortFunc(extensions, func(a, b olmv1.ClusterExtension) int { if a.Status.Install == nil || b.Status.Install == nil { return cmp.Compare(a.Name, b.Name) diff --git a/internal/cmd/internal/olmv1/printing_test.go b/internal/cmd/internal/olmv1/printing_test.go index 47c14bf6..0ac818e9 100644 --- a/internal/cmd/internal/olmv1/printing_test.go +++ b/internal/cmd/internal/olmv1/printing_test.go @@ -26,22 +26,22 @@ var _ = Describe("SortCatalogs", func() { }) }) -var _ = Describe("SortOperators", func() { - It("sorts operators in correct order", func() { - operators := []olmv1.ClusterExtension{ +var _ = Describe("SortExtensions", func() { + It("sorts extensions in correct order", func() { + extensions := []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) + sortExtensions(extensions) - 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")) + Expect(extensions[0].Status.Install.Bundle.Version).To(Equal("1.0.1")) + Expect(extensions[1].Status.Install.Bundle.Version).To(Equal("1.0.1-rc4")) + Expect(extensions[2].Status.Install.Bundle.Version).To(Equal("1.0.1-rc2")) + Expect(extensions[3].Status.Install.Bundle.Version).To(Equal("1.0.0")) + Expect(extensions[4].Status.Install.Bundle.Version).To(Equal("2.0.0")) }) }) diff --git a/internal/cmd/olmv1.go b/internal/cmd/olmv1.go index a1a0defb..8791d3e4 100644 --- a/internal/cmd/olmv1.go +++ b/internal/cmd/olmv1.go @@ -10,8 +10,8 @@ import ( func newOlmV1Cmd(cfg *action.Configuration) *cobra.Command { cmd := &cobra.Command{ Use: "olmv1", - Short: "Manage operators via OLMv1 in a cluster from the command line", - Long: "Manage operators via OLMv1 in a cluster from the command line.", + Short: "Manage extensions via OLMv1 in a cluster from the command line", + Long: "Manage extensions via OLMv1 in a cluster from the command line.", } getCmd := &cobra.Command{ @@ -20,7 +20,7 @@ func newOlmV1Cmd(cfg *action.Configuration) *cobra.Command { Long: "Display one or many resource(s)", } getCmd.AddCommand( - olmv1.NewOperatorInstalledGetCmd(cfg), + olmv1.NewExtensionInstalledGetCmd(cfg), olmv1.NewCatalogInstalledGetCmd(cfg), ) @@ -44,12 +44,12 @@ func newOlmV1Cmd(cfg *action.Configuration) *cobra.Command { Long: "Update a resource", } updateCmd.AddCommand( - olmv1.NewOperatorUpdateCmd(cfg), + olmv1.NewExtensionUpdateCmd(cfg), ) cmd.AddCommand( - olmv1.NewOperatorInstallCmd(cfg), - olmv1.NewOperatorUninstallCmd(cfg), + olmv1.NewExtensionInstallCmd(cfg), + olmv1.NewExtensionUninstallCmd(cfg), getCmd, createCmd, deleteCmd, diff --git a/internal/pkg/v1/action/action_suite_test.go b/internal/pkg/v1/action/action_suite_test.go index 6b25714e..d7e5e570 100644 --- a/internal/pkg/v1/action/action_suite_test.go +++ b/internal/pkg/v1/action/action_suite_test.go @@ -157,7 +157,7 @@ func buildExtension(packageName string, opts ...extensionOpt) *olmv1.ClusterExte return ext } -func updateOperatorConditionStatus(name string, cl client.Client, typ string, status metav1.ConditionStatus) error { +func updateExtensionConditionStatus(name string, cl client.Client, typ string, status metav1.ConditionStatus) error { var ext olmv1.ClusterExtension key := types.NamespacedName{Name: name} diff --git a/internal/pkg/v1/action/catalog_installed_get_test.go b/internal/pkg/v1/action/catalog_installed_get_test.go index ee528068..b8c7ee0a 100644 --- a/internal/pkg/v1/action/catalog_installed_get_test.go +++ b/internal/pkg/v1/action/catalog_installed_get_test.go @@ -52,10 +52,10 @@ var _ = Describe("CatalogInstalledGet", func() { It("returns empty list in case no catalogs were found", func() { cfg := setupEnv() - getter := internalaction.NewOperatorInstalledGet(&cfg) - operators, err := getter.Run(context.TODO()) + getter := internalaction.NewCatalogInstalledGet(&cfg) + catalogs, err := getter.Run(context.TODO()) Expect(err).To(BeNil()) - Expect(operators).To(BeEmpty()) + Expect(catalogs).To(BeEmpty()) }) It("gets an installed catalog", func() { @@ -63,20 +63,20 @@ var _ = Describe("CatalogInstalledGet", func() { getter := internalaction.NewCatalogInstalledGet(&cfg) getter.CatalogName = "cat2" - operators, err := getter.Run(context.TODO()) + catalogs, 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")) + Expect(catalogs).NotTo(BeEmpty()) + Expect(catalogs).To(HaveLen(1)) + Expect(catalogs[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()) + getter := internalaction.NewCatalogInstalledGet(&cfg) + getter.CatalogName = "cat2" + catalogs, err := getter.Run(context.TODO()) Expect(err).NotTo(BeNil()) - Expect(operators).To(BeEmpty()) + Expect(catalogs).To(BeEmpty()) }) }) diff --git a/internal/pkg/v1/action/errors.go b/internal/pkg/v1/action/errors.go index 194562d7..6cb1d9be 100644 --- a/internal/pkg/v1/action/errors.go +++ b/internal/pkg/v1/action/errors.go @@ -5,5 +5,5 @@ import "errors" var ( ErrNoResourcesFound = errors.New("no resources found") ErrNameAndSelector = errors.New("name cannot be provided when a selector is specified") - ErrNoChange = errors.New("no changes detected - operator already in desired state") + ErrNoChange = errors.New("no changes detected - extension already in desired state") ) diff --git a/internal/pkg/v1/action/operator_install.go b/internal/pkg/v1/action/extension_install.go similarity index 84% rename from internal/pkg/v1/action/operator_install.go rename to internal/pkg/v1/action/extension_install.go index 7fb7d031..00fce350 100644 --- a/internal/pkg/v1/action/operator_install.go +++ b/internal/pkg/v1/action/extension_install.go @@ -14,7 +14,7 @@ import ( "github.com/operator-framework/kubectl-operator/pkg/action" ) -type OperatorInstall struct { +type ExtensionInstall struct { config *action.Configuration Package string @@ -22,17 +22,17 @@ type OperatorInstall struct { Logf func(string, ...interface{}) } -func NewOperatorInstall(cfg *action.Configuration) *OperatorInstall { - return &OperatorInstall{ +func NewExtensionInstall(cfg *action.Configuration) *ExtensionInstall { + return &ExtensionInstall{ config: cfg, Logf: func(string, ...interface{}) {}, } } -func (i *OperatorInstall) Run(ctx context.Context) (*olmv1.ClusterExtension, error) { +func (i *ExtensionInstall) Run(ctx context.Context) (*olmv1.ClusterExtension, error) { // TODO(developer): Lookup package information when the OLMv1 equivalent of the // packagemanifests API is available. That way, we can check to see if the - // package is actually available to the cluster before creating the Operator + // package is actually available to the cluster before creating the Extension // object. opKey := types.NamespacedName{Name: i.Package} @@ -51,9 +51,9 @@ func (i *OperatorInstall) Run(ctx context.Context) (*olmv1.ClusterExtension, err return nil, err } - // TODO(developer): Improve the logic in this poll wait once the Operator reconciler + // TODO(developer): Improve the logic in this poll wait once the Extension reconciler // and conditions types and reasons are improved. For now, this will stop waiting as - // soon as a Ready condition is found, but we should probably wait until the Operator + // soon as a Ready condition is found, but we should probably wait until the Extension // stops progressing. // All Types will exist, so Ready may have a false Status. So, wait until // Type=Ready,Status=True happens @@ -68,7 +68,7 @@ func (i *OperatorInstall) Run(ctx context.Context) (*olmv1.ClusterExtension, err } return false, nil }); err != nil { - return nil, fmt.Errorf("waiting for operator to become ready: %v", err) + return nil, fmt.Errorf("waiting for extension to become ready: %v", err) } return op, nil diff --git a/internal/pkg/v1/action/operator_installed_get.go b/internal/pkg/v1/action/extension_installed_get.go similarity index 63% rename from internal/pkg/v1/action/operator_installed_get.go rename to internal/pkg/v1/action/extension_installed_get.go index ec2e56b0..994fc5f9 100644 --- a/internal/pkg/v1/action/operator_installed_get.go +++ b/internal/pkg/v1/action/extension_installed_get.go @@ -11,25 +11,25 @@ import ( "github.com/operator-framework/kubectl-operator/pkg/action" ) -type OperatorInstalledGet struct { - config *action.Configuration - OperatorName string +type ExtensionInstalledGet struct { + config *action.Configuration + ExtensionName string Logf func(string, ...interface{}) } -func NewOperatorInstalledGet(cfg *action.Configuration) *OperatorInstalledGet { - return &OperatorInstalledGet{ +func NewExtensionInstalledGet(cfg *action.Configuration) *ExtensionInstalledGet { + return &ExtensionInstalledGet{ config: cfg, Logf: func(string, ...interface{}) {}, } } -func (i *OperatorInstalledGet) Run(ctx context.Context) ([]olmv1.ClusterExtension, error) { +func (i *ExtensionInstalledGet) Run(ctx context.Context) ([]olmv1.ClusterExtension, error) { // get - if i.OperatorName != "" { + if i.ExtensionName != "" { var result olmv1.ClusterExtension - opKey := types.NamespacedName{Name: i.OperatorName} + opKey := types.NamespacedName{Name: i.ExtensionName} err := i.config.Client.Get(ctx, opKey, &result) if err != nil { return nil, err diff --git a/internal/pkg/v1/action/extension_installed_get_test.go b/internal/pkg/v1/action/extension_installed_get_test.go new file mode 100644 index 00000000..804b525d --- /dev/null +++ b/internal/pkg/v1/action/extension_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("ExtensionInstalledGet", func() { + setupEnv := func(extensions ...client.Object) action.Configuration { + var cfg action.Configuration + + sch, err := action.NewScheme() + Expect(err).To(BeNil()) + + cl := fake.NewClientBuilder(). + WithObjects(extensions...). + WithScheme(sch). + Build() + cfg.Scheme = sch + cfg.Client = cl + + return cfg + } + + It("lists all installed extensions", func() { + cfg := setupEnv(setupTestExtensions(3)...) + + getter := internalaction.NewExtensionInstalledGet(&cfg) + extensions, err := getter.Run(context.TODO()) + Expect(err).To(BeNil()) + Expect(extensions).NotTo(BeEmpty()) + Expect(extensions).To(HaveLen(3)) + + for _, testExtensionName := range []string{"ext1", "ext2", "ext3"} { + Expect(slices.ContainsFunc(extensions, func(op olmv1.ClusterExtension) bool { + return op.Name == testExtensionName + })).To(BeTrue()) + } + }) + + It("returns empty list in case no extensions were found", func() { + cfg := setupEnv() + + getter := internalaction.NewExtensionInstalledGet(&cfg) + extensions, err := getter.Run(context.TODO()) + Expect(err).To(BeNil()) + Expect(extensions).To(BeEmpty()) + }) + + It("gets an installed extension", func() { + cfg := setupEnv(setupTestExtensions(3)...) + + getter := internalaction.NewExtensionInstalledGet(&cfg) + getter.ExtensionName = "ext2" + extensions, err := getter.Run(context.TODO()) + Expect(err).To(BeNil()) + Expect(extensions).NotTo(BeEmpty()) + Expect(extensions).To(HaveLen(1)) + Expect(extensions[0].Name).To(Equal("ext2")) + }) + + It("returns an empty list and an error when an installed extension was not found", func() { + cfg := setupEnv() + + getter := internalaction.NewExtensionInstalledGet(&cfg) + getter.ExtensionName = "ext2" + extensions, err := getter.Run(context.TODO()) + Expect(err).NotTo(BeNil()) + Expect(extensions).To(BeEmpty()) + }) +}) + +func setupTestExtensions(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/internal/pkg/v1/action/operator_uninstall.go b/internal/pkg/v1/action/extension_uninstall.go similarity index 75% rename from internal/pkg/v1/action/operator_uninstall.go rename to internal/pkg/v1/action/extension_uninstall.go index a6d504c4..59d58563 100644 --- a/internal/pkg/v1/action/operator_uninstall.go +++ b/internal/pkg/v1/action/extension_uninstall.go @@ -13,7 +13,7 @@ import ( "github.com/operator-framework/kubectl-operator/pkg/action" ) -type OperatorUninstall struct { +type ExtensionUninstall struct { config *action.Configuration Package string @@ -21,18 +21,18 @@ type OperatorUninstall struct { Logf func(string, ...interface{}) } -func NewOperatorUninstall(cfg *action.Configuration) *OperatorUninstall { - return &OperatorUninstall{ +func NewExtensionUninstall(cfg *action.Configuration) *ExtensionUninstall { + return &ExtensionUninstall{ config: cfg, Logf: func(string, ...interface{}) {}, } } -func (u *OperatorUninstall) Run(ctx context.Context) error { +func (u *ExtensionUninstall) Run(ctx context.Context) error { opKey := types.NamespacedName{Name: u.Package} op := &olmv1.ClusterExtension{} op.SetName(opKey.Name) - op.SetGroupVersionKind(olmv1.GroupVersion.WithKind("Operator")) + op.SetGroupVersionKind(olmv1.GroupVersion.WithKind("Extension")) lowerKind := strings.ToLower(op.GetObjectKind().GroupVersionKind().Kind) if err := u.config.Client.Delete(ctx, op); err != nil && !apierrors.IsNotFound(err) { diff --git a/internal/pkg/v1/action/operator_update.go b/internal/pkg/v1/action/extension_update.go similarity index 82% rename from internal/pkg/v1/action/operator_update.go rename to internal/pkg/v1/action/extension_update.go index 830ae5d5..4ef40324 100644 --- a/internal/pkg/v1/action/operator_update.go +++ b/internal/pkg/v1/action/extension_update.go @@ -16,7 +16,7 @@ import ( "github.com/operator-framework/kubectl-operator/pkg/action" ) -type OperatorUpdate struct { +type ExtensionUpdate struct { cfg *action.Configuration Package string @@ -36,14 +36,14 @@ type OperatorUpdate struct { Logf func(string, ...interface{}) } -func NewOperatorUpdate(cfg *action.Configuration) *OperatorUpdate { - return &OperatorUpdate{ +func NewExtensionUpdate(cfg *action.Configuration) *ExtensionUpdate { + return &ExtensionUpdate{ cfg: cfg, Logf: func(string, ...interface{}) {}, } } -func (ou *OperatorUpdate) Run(ctx context.Context) (*olmv1.ClusterExtension, error) { +func (ou *ExtensionUpdate) Run(ctx context.Context) (*olmv1.ClusterExtension, error) { var ext olmv1.ClusterExtension var err error @@ -80,14 +80,14 @@ func (ou *OperatorUpdate) Run(ctx context.Context) (*olmv1.ClusterExtension, err return nil, err } - if err := waitUntilOperatorStatusCondition(ctx, ou.cfg.Client, &ext, olmv1.TypeInstalled, metav1.ConditionTrue); err != nil { - return nil, fmt.Errorf("timed out waiting for operator: %w", err) + if err := waitUntilExtensionStatusCondition(ctx, ou.cfg.Client, &ext, olmv1.TypeInstalled, metav1.ConditionTrue); err != nil { + return nil, fmt.Errorf("timed out waiting for extension: %w", err) } return &ext, nil } -func (ou *OperatorUpdate) setDefaults(ext olmv1.ClusterExtension) { +func (ou *ExtensionUpdate) setDefaults(ext olmv1.ClusterExtension) { if !ou.IgnoreUnset { if ou.UpgradeConstraintPolicy == "" { ou.UpgradeConstraintPolicy = string(olmv1.UpgradeConstraintPolicyCatalogProvided) @@ -116,7 +116,7 @@ func (ou *OperatorUpdate) setDefaults(ext olmv1.ClusterExtension) { } } -func (ou *OperatorUpdate) needsUpdate(ext olmv1.ClusterExtension, constraintPolicy olmv1.UpgradeConstraintPolicy) bool { +func (ou *ExtensionUpdate) needsUpdate(ext olmv1.ClusterExtension, constraintPolicy olmv1.UpgradeConstraintPolicy) bool { catalogSrc := ext.Spec.Source.Catalog // object string form is used for comparison to: @@ -137,7 +137,7 @@ func (ou *OperatorUpdate) needsUpdate(ext olmv1.ClusterExtension, constraintPoli return true } -func (ou *OperatorUpdate) prepareUpdatedExtension(ext *olmv1.ClusterExtension, constraintPolicy olmv1.UpgradeConstraintPolicy) { +func (ou *ExtensionUpdate) prepareUpdatedExtension(ext *olmv1.ClusterExtension, constraintPolicy olmv1.UpgradeConstraintPolicy) { ext.SetLabels(ou.Labels) ext.Spec.Source.Catalog.Version = ou.Version ext.Spec.Source.Catalog.Selector = ou.parsedSelector diff --git a/internal/pkg/v1/action/operator_update_test.go b/internal/pkg/v1/action/extension_update_test.go similarity index 84% rename from internal/pkg/v1/action/operator_update_test.go rename to internal/pkg/v1/action/extension_update_test.go index 79743635..4e33de5e 100644 --- a/internal/pkg/v1/action/operator_update_test.go +++ b/internal/pkg/v1/action/extension_update_test.go @@ -18,7 +18,7 @@ import ( "github.com/operator-framework/kubectl-operator/pkg/action" ) -var _ = Describe("OperatorUpdate", func() { +var _ = Describe("ExtensionUpdate", func() { setupEnv := func(extensions ...client.Object) action.Configuration { var cfg action.Configuration @@ -35,10 +35,10 @@ var _ = Describe("OperatorUpdate", func() { return cfg } - It("fails finding existing operator", func() { + It("fails finding existing extension", func() { cfg := setupEnv() - updater := internalaction.NewOperatorUpdate(&cfg) + updater := internalaction.NewExtensionUpdate(&cfg) updater.Package = "does-not-exist" ext, err := updater.Run(context.TODO()) @@ -47,10 +47,10 @@ var _ = Describe("OperatorUpdate", func() { Expect(ext).To(BeNil()) }) - It("fails to handle operator with non-catalog source type", func() { + It("fails to handle extension with non-catalog source type", func() { cfg := setupEnv(buildExtension("test", withSourceType("unknown"))) - updater := internalaction.NewOperatorUpdate(&cfg) + updater := internalaction.NewExtensionUpdate(&cfg) updater.Package = "test" ext, err := updater.Run(context.TODO()) @@ -59,14 +59,14 @@ var _ = Describe("OperatorUpdate", func() { Expect(ext).To(BeNil()) }) - It("fails because desired operator state matches current", func() { + It("fails because desired extension state matches current", func() { cfg := setupEnv(buildExtension( "test", withSourceType(olmv1.SourceTypeCatalog), withConstraintPolicy(string(olmv1.UpgradeConstraintPolicyCatalogProvided))), ) - updater := internalaction.NewOperatorUpdate(&cfg) + updater := internalaction.NewExtensionUpdate(&cfg) updater.Package = "test" ext, err := updater.Run(context.TODO()) @@ -75,7 +75,7 @@ var _ = Describe("OperatorUpdate", func() { Expect(ext).To(BeNil()) }) - It("fails because desired operator state matches current with IgnoreUnset enabled", func() { + It("fails because desired extension state matches current with IgnoreUnset enabled", func() { cfg := setupEnv(buildExtension( "test", withSourceType(olmv1.SourceTypeCatalog), @@ -85,7 +85,7 @@ var _ = Describe("OperatorUpdate", func() { withVersion("10.0.4"), )) - updater := internalaction.NewOperatorUpdate(&cfg) + updater := internalaction.NewExtensionUpdate(&cfg) updater.Package = "test" updater.IgnoreUnset = true ext, err := updater.Run(context.TODO()) @@ -95,14 +95,14 @@ var _ = Describe("OperatorUpdate", func() { Expect(ext).To(BeNil()) }) - It("fails validating operator version", func() { + It("fails validating extension version", func() { cfg := setupEnv(buildExtension( "test", withSourceType(olmv1.SourceTypeCatalog), withConstraintPolicy(string(olmv1.UpgradeConstraintPolicyCatalogProvided))), ) - updater := internalaction.NewOperatorUpdate(&cfg) + updater := internalaction.NewExtensionUpdate(&cfg) updater.Package = "test" updater.Version = "10-4" ext, err := updater.Run(context.TODO()) @@ -112,7 +112,7 @@ var _ = Describe("OperatorUpdate", func() { Expect(ext).To(BeNil()) }) - It("fails updating operator", func() { + It("fails updating extension", func() { testExt := buildExtension( "test", withSourceType(olmv1.SourceTypeCatalog), @@ -123,7 +123,7 @@ var _ = Describe("OperatorUpdate", func() { ctx, cancel := context.WithCancel(context.TODO()) cancel() - updater := internalaction.NewOperatorUpdate(&cfg) + updater := internalaction.NewExtensionUpdate(&cfg) updater.Package = "test" updater.Version = "10.0.4" updater.Channels = []string{"a", "b"} @@ -136,7 +136,7 @@ var _ = Describe("OperatorUpdate", func() { Expect(ext).To(BeNil()) }) - It("successfully updates operator", func() { + It("successfully updates extension", func() { testExt := buildExtension( "test", withSourceType(olmv1.SourceTypeCatalog), @@ -145,13 +145,13 @@ var _ = Describe("OperatorUpdate", func() { cfg := setupEnv(testExt, buildExtension("test2"), buildExtension("test3")) go func() { - Eventually(updateOperatorConditionStatus). + Eventually(updateExtensionConditionStatus). WithArguments("test", cfg.Client, olmv1.TypeInstalled, metav1.ConditionTrue). WithTimeout(5 * time.Second).WithPolling(200 * time.Millisecond). Should(Succeed()) }() - updater := internalaction.NewOperatorUpdate(&cfg) + updater := internalaction.NewExtensionUpdate(&cfg) updater.Package = "test" updater.Version = "10.0.4" updater.Channels = []string{"a", "b"} diff --git a/internal/pkg/v1/action/helpers.go b/internal/pkg/v1/action/helpers.go index 69edd750..3a76ab18 100644 --- a/internal/pkg/v1/action/helpers.go +++ b/internal/pkg/v1/action/helpers.go @@ -47,20 +47,20 @@ func waitUntilCatalogStatusCondition( }) } -func waitUntilOperatorStatusCondition( +func waitUntilExtensionStatusCondition( ctx context.Context, cl getter, - operator *olmv1.ClusterExtension, + extension *olmv1.ClusterExtension, conditionType string, conditionStatus metav1.ConditionStatus, ) error { - opKey := objectKeyForObject(operator) + opKey := objectKeyForObject(extension) return wait.PollUntilContextCancel(ctx, pollInterval, true, func(conditionCtx context.Context) (bool, error) { - if err := cl.Get(conditionCtx, opKey, operator); err != nil { + if err := cl.Get(conditionCtx, opKey, extension); err != nil { return false, err } - if slices.ContainsFunc(operator.Status.Conditions, func(cond metav1.Condition) bool { + if slices.ContainsFunc(extension.Status.Conditions, func(cond metav1.Condition) bool { return cond.Type == conditionType && cond.Status == conditionStatus }) { return true, nil diff --git a/internal/pkg/v1/action/operator_installed_get_test.go b/internal/pkg/v1/action/operator_installed_get_test.go deleted file mode 100644 index f4a536c6..00000000 --- a/internal/pkg/v1/action/operator_installed_get_test.go +++ /dev/null @@ -1,107 +0,0 @@ -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, - }, - }, - }, - } -}