Skip to content

Commit 85a9c09

Browse files
committed
Add command to delete an existing olmv1 catalog
Signed-off-by: Artur Zych <[email protected]>
1 parent c788f7c commit 85a9c09

File tree

10 files changed

+205
-56
lines changed

10 files changed

+205
-56
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package olmv1
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
6+
"github.com/operator-framework/kubectl-operator/internal/cmd/internal/log"
7+
v1action "github.com/operator-framework/kubectl-operator/internal/pkg/v1/action"
8+
"github.com/operator-framework/kubectl-operator/pkg/action"
9+
)
10+
11+
// NewCatalogDeleteCmd allows deleting a specified, existing catalog
12+
func NewCatalogDeleteCmd(cfg *action.Configuration) *cobra.Command {
13+
i := v1action.NewCatalogDelete(cfg)
14+
i.Logf = log.Printf
15+
16+
cmd := &cobra.Command{
17+
Use: "catalog <catalog_name>",
18+
Aliases: []string{"catalogs <catalog_name>"},
19+
Args: cobra.ExactArgs(1),
20+
Short: "Delete an existing catalog",
21+
Run: func(cmd *cobra.Command, args []string) {
22+
i.CatalogName = args[0]
23+
24+
if err := i.Run(cmd.Context()); err != nil {
25+
log.Fatalf("failed to delete catalog %q: %v", i.CatalogName, err)
26+
}
27+
log.Printf("catalog %q deleted", i.CatalogName)
28+
},
29+
}
30+
31+
return cmd
32+
}

internal/cmd/olmv1.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,18 @@ func newOlmV1Cmd(cfg *action.Configuration) *cobra.Command {
2424
olmv1.NewCatalogInstalledGetCmd(cfg),
2525
)
2626

27+
deleteCmd := &cobra.Command{
28+
Use: "delete",
29+
Short: "Delete an OLMv1 resource",
30+
Long: "Delete an OLMv1 resource",
31+
}
32+
deleteCmd.AddCommand(olmv1.NewCatalogDeleteCmd(cfg))
33+
2734
cmd.AddCommand(
2835
olmv1.NewOperatorInstallCmd(cfg),
2936
olmv1.NewOperatorUninstallCmd(cfg),
3037
getCmd,
38+
deleteCmd,
3139
)
3240

3341
return cmd
Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,34 @@
11
package action_test
22

33
import (
4+
"fmt"
45
"testing"
56

67
. "github.com/onsi/ginkgo"
78
. "github.com/onsi/gomega"
9+
10+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
"sigs.k8s.io/controller-runtime/pkg/client"
12+
13+
olmv1catalogd "github.com/operator-framework/catalogd/api/v1"
814
)
915

1016
func TestCommand(t *testing.T) {
1117
RegisterFailHandler(Fail)
12-
RunSpecs(t, "Internal action Suite")
18+
RunSpecs(t, "Internal v1 action Suite")
19+
}
20+
21+
func setupTestCatalogs(n int) []client.Object {
22+
var result []client.Object
23+
for i := 1; i <= n; i++ {
24+
result = append(result, newClusterCatalog(fmt.Sprintf("cat%d", i)))
25+
}
26+
27+
return result
28+
}
29+
30+
func newClusterCatalog(name string) *olmv1catalogd.ClusterCatalog {
31+
return &olmv1catalogd.ClusterCatalog{
32+
ObjectMeta: metav1.ObjectMeta{Name: name},
33+
}
1334
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package action
2+
3+
import (
4+
"context"
5+
6+
olmv1catalogd "github.com/operator-framework/catalogd/api/v1"
7+
8+
"github.com/operator-framework/kubectl-operator/pkg/action"
9+
)
10+
11+
type CatalogDelete struct {
12+
config *action.Configuration
13+
CatalogName string
14+
15+
Logf func(string, ...interface{})
16+
}
17+
18+
func NewCatalogDelete(cfg *action.Configuration) *CatalogDelete {
19+
return &CatalogDelete{
20+
config: cfg,
21+
Logf: func(string, ...interface{}) {},
22+
}
23+
}
24+
25+
func (i *CatalogDelete) Run(ctx context.Context) error {
26+
op := &olmv1catalogd.ClusterCatalog{}
27+
op.SetName(i.CatalogName)
28+
29+
if err := i.config.Client.Delete(ctx, op); err != nil {
30+
return err
31+
}
32+
33+
return waitForDeletion(ctx, i.config.Client, op)
34+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package action_test
2+
3+
import (
4+
"context"
5+
"slices"
6+
7+
. "github.com/onsi/ginkgo"
8+
. "github.com/onsi/gomega"
9+
10+
"sigs.k8s.io/controller-runtime/pkg/client"
11+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
12+
13+
olmv1catalogd "github.com/operator-framework/catalogd/api/v1"
14+
15+
internalaction "github.com/operator-framework/kubectl-operator/internal/pkg/v1/action"
16+
"github.com/operator-framework/kubectl-operator/pkg/action"
17+
)
18+
19+
var _ = Describe("CatalogInstalledGet", func() {
20+
setupEnv := func(catalogs ...client.Object) action.Configuration {
21+
var cfg action.Configuration
22+
23+
sch, err := action.NewScheme()
24+
Expect(err).To(BeNil())
25+
26+
cl := fake.NewClientBuilder().
27+
WithObjects(catalogs...).
28+
WithScheme(sch).
29+
Build()
30+
cfg.Scheme = sch
31+
cfg.Client = cl
32+
33+
return cfg
34+
}
35+
36+
It("fails deleting a non-existing catalog", func() {
37+
cfg := setupEnv(setupTestCatalogs(2)...)
38+
39+
deleter := internalaction.NewCatalogDelete(&cfg)
40+
deleter.CatalogName = "does-not-exist"
41+
err := deleter.Run(context.TODO())
42+
Expect(err).NotTo(BeNil())
43+
44+
validateExistingCatalogs(cfg.Client, []string{"cat1", "cat2"})
45+
})
46+
47+
It("successfully deletes an existing catalog", func() {
48+
cfg := setupEnv(setupTestCatalogs(3)...)
49+
50+
deleter := internalaction.NewCatalogDelete(&cfg)
51+
deleter.CatalogName = "cat2"
52+
err := deleter.Run(context.TODO())
53+
Expect(err).To(BeNil())
54+
55+
validateExistingCatalogs(cfg.Client, []string{"cat1", "cat3"})
56+
})
57+
})
58+
59+
func validateExistingCatalogs(c client.Client, wantedNames []string) {
60+
var catalogsList olmv1catalogd.ClusterCatalogList
61+
err := c.List(context.TODO(), &catalogsList)
62+
Expect(err).To(BeNil())
63+
64+
catalogs := catalogsList.Items
65+
Expect(catalogs).To(HaveLen(len(wantedNames)))
66+
for _, wantedName := range wantedNames {
67+
Expect(slices.ContainsFunc(catalogs, func(cat olmv1catalogd.ClusterCatalog) bool {
68+
return cat.Name == wantedName
69+
})).To(BeTrue())
70+
}
71+
}

internal/pkg/v1/action/catalog_installed_get_test.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@ package action_test
22

33
import (
44
"context"
5-
"fmt"
65
"slices"
76

87
. "github.com/onsi/ginkgo"
98
. "github.com/onsi/gomega"
109

11-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1210
"sigs.k8s.io/controller-runtime/pkg/client"
1311
"sigs.k8s.io/controller-runtime/pkg/client/fake"
1412

@@ -82,18 +80,3 @@ var _ = Describe("CatalogInstalledGet", func() {
8280
Expect(operators).To(BeEmpty())
8381
})
8482
})
85-
86-
func setupTestCatalogs(n int) []client.Object {
87-
var result []client.Object
88-
for i := 1; i <= n; i++ {
89-
result = append(result, newClusterCatalog(fmt.Sprintf("cat%d", i)))
90-
}
91-
92-
return result
93-
}
94-
95-
func newClusterCatalog(name string) *olmv1catalogd.ClusterCatalog {
96-
return &olmv1catalogd.ClusterCatalog{
97-
ObjectMeta: metav1.ObjectMeta{Name: name},
98-
}
99-
}

internal/pkg/v1/action/helpers.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package action
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
apierrors "k8s.io/apimachinery/pkg/api/errors"
9+
"k8s.io/apimachinery/pkg/types"
10+
"k8s.io/apimachinery/pkg/util/wait"
11+
"sigs.k8s.io/controller-runtime/pkg/client"
12+
)
13+
14+
const pollInterval = 250 * time.Millisecond
15+
16+
func objectKeyForObject(obj client.Object) types.NamespacedName {
17+
return types.NamespacedName{
18+
Namespace: obj.GetNamespace(),
19+
Name: obj.GetName(),
20+
}
21+
}
22+
23+
func waitForDeletion(ctx context.Context, cl client.Client, obj client.Object) error {
24+
key := objectKeyForObject(obj)
25+
if err := wait.PollUntilContextCancel(ctx, pollInterval, true, func(conditionCtx context.Context) (bool, error) {
26+
if err := cl.Get(conditionCtx, key, obj); apierrors.IsNotFound(err) {
27+
return true, nil
28+
} else if err != nil {
29+
return false, err
30+
}
31+
return false, nil
32+
}); err != nil {
33+
return fmt.Errorf("waiting for deletion: %w", err)
34+
}
35+
36+
return nil
37+
}

internal/pkg/v1/action/operator.go

Lines changed: 0 additions & 9 deletions
This file was deleted.

internal/pkg/v1/action/operator_install.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (i *OperatorInstall) Run(ctx context.Context) (*olmv1.ClusterExtension, err
5858
// All Types will exist, so Ready may have a false Status. So, wait until
5959
// Type=Ready,Status=True happens
6060

61-
if err := wait.PollUntilContextCancel(ctx, pollTimeout, true, func(conditionCtx context.Context) (bool, error) {
61+
if err := wait.PollUntilContextCancel(ctx, pollInterval, true, func(conditionCtx context.Context) (bool, error) {
6262
if err := i.config.Client.Get(conditionCtx, opKey, op); err != nil {
6363
return false, err
6464
}

internal/pkg/v1/action/operator_uninstall.go

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import (
77

88
apierrors "k8s.io/apimachinery/pkg/api/errors"
99
"k8s.io/apimachinery/pkg/types"
10-
"k8s.io/apimachinery/pkg/util/wait"
11-
"sigs.k8s.io/controller-runtime/pkg/client"
1210

1311
olmv1 "github.com/operator-framework/operator-controller/api/v1"
1412

@@ -42,29 +40,3 @@ func (u *OperatorUninstall) Run(ctx context.Context) error {
4240
}
4341
return waitForDeletion(ctx, u.config.Client, op)
4442
}
45-
46-
func objectKeyForObject(obj client.Object) types.NamespacedName {
47-
return types.NamespacedName{
48-
Namespace: obj.GetNamespace(),
49-
Name: obj.GetName(),
50-
}
51-
}
52-
53-
func waitForDeletion(ctx context.Context, cl client.Client, objs ...client.Object) error {
54-
for _, obj := range objs {
55-
obj := obj
56-
lowerKind := strings.ToLower(obj.GetObjectKind().GroupVersionKind().Kind)
57-
key := objectKeyForObject(obj)
58-
if err := wait.PollUntilContextCancel(ctx, pollTimeout, true, func(conditionCtx context.Context) (bool, error) {
59-
if err := cl.Get(conditionCtx, key, obj); apierrors.IsNotFound(err) {
60-
return true, nil
61-
} else if err != nil {
62-
return false, err
63-
}
64-
return false, nil
65-
}); err != nil {
66-
return fmt.Errorf("wait for %s %q deleted: %v", lowerKind, key.Name, err)
67-
}
68-
}
69-
return nil
70-
}

0 commit comments

Comments
 (0)