Skip to content

Commit f64fc36

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

File tree

12 files changed

+218
-38
lines changed

12 files changed

+218
-38
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ require (
1111
github.com/onsi/gomega v1.36.2
1212
github.com/opencontainers/image-spec v1.1.0
1313
github.com/operator-framework/api v0.29.0
14+
github.com/operator-framework/catalogd v1.1.0
1415
github.com/operator-framework/operator-controller v1.1.0
1516
github.com/operator-framework/operator-lifecycle-manager v0.23.1
1617
github.com/operator-framework/operator-registry v1.50.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE
242242
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
243243
github.com/operator-framework/api v0.29.0 h1:TxAR8RCO+I4FjRrY4PSMgnlmbxNWeD8pzHXp7xwHNmw=
244244
github.com/operator-framework/api v0.29.0/go.mod h1:0whQE4mpMDd2zyHkQe+bFa3DLoRs6oGWCbu8dY/3pyc=
245+
github.com/operator-framework/catalogd v1.1.0 h1:mu2DYL5mpREEAAP+uPG+CMSsfsJkgrIasgLRG8nvwJg=
246+
github.com/operator-framework/catalogd v1.1.0/go.mod h1:8Je9CqMPwhNgRoqGX5OPsLYHsEoTDvPnELLLKRw1RHE=
245247
github.com/operator-framework/operator-controller v1.1.0 h1:h0b1SSuv9ZiIgI8dTuutSPVL4uIeyvTW3gOB2szkBMQ=
246248
github.com/operator-framework/operator-controller v1.1.0/go.mod h1:dJIt5/gfm1n3y9IeX4kpSlpu4CFq8WFVHU2n9ZDVUkA=
247249
github.com/operator-framework/operator-lifecycle-manager v0.23.1 h1:Xw2ml1T4W2ieoFaVwanW/eFlZ11yAOJZUpUI8RLSql8=
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
@@ -14,9 +14,17 @@ func newOlmV1Cmd(cfg *action.Configuration) *cobra.Command {
1414
Long: "Manage operators via OLMv1 in a cluster from the command line.",
1515
}
1616

17+
deleteCmd := &cobra.Command{
18+
Use: "delete",
19+
Short: "Delete an OLMv1 resource",
20+
Long: "Delete an OLMv1 resource",
21+
}
22+
deleteCmd.AddCommand(olmv1.NewCatalogDeleteCmd(cfg))
23+
1724
cmd.AddCommand(
1825
olmv1.NewOperatorInstallCmd(cfg),
1926
olmv1.NewOperatorUninstallCmd(cfg),
27+
deleteCmd,
2028
)
2129

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

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
}

0 commit comments

Comments
 (0)