Skip to content

Commit 930d034

Browse files
Add command for updating olmv1 catalog
Signed-off-by: Rashmi Gottipati <chowdary.grashmi@gmail.com>
1 parent ec84fc0 commit 930d034

File tree

5 files changed

+249
-0
lines changed

5 files changed

+249
-0
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package olmv1
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
"github.com/spf13/pflag"
6+
7+
"github.com/operator-framework/kubectl-operator/internal/cmd/internal/log"
8+
v1action "github.com/operator-framework/kubectl-operator/internal/pkg/v1/action"
9+
"github.com/operator-framework/kubectl-operator/pkg/action"
10+
)
11+
12+
// NewCatalogUpdateCmd allows updating a selected clustercatalog
13+
func NewCatalogUpdateCmd(cfg *action.Configuration) *cobra.Command {
14+
i := v1action.NewCatalogUpdate(cfg)
15+
i.Logf = log.Printf
16+
17+
cmd := &cobra.Command{
18+
Use: "catalog <catalog>",
19+
Short: "Update a catalog",
20+
Args: cobra.ExactArgs(1),
21+
Run: func(cmd *cobra.Command, args []string) {
22+
i.CatalogName = args[0]
23+
_, err := i.Run(cmd.Context())
24+
if err != nil {
25+
log.Fatalf("failed to update catalog: %v", err)
26+
}
27+
log.Printf("catalog %q updated", i.CatalogName)
28+
},
29+
}
30+
bindCatalogUpdateFlags(cmd.Flags(), i)
31+
32+
return cmd
33+
}
34+
35+
func bindCatalogUpdateFlags(fs *pflag.FlagSet, i *v1action.CatalogUpdate) {
36+
fs.Int32Var(&i.Priority, "priority", 1, "priority determines the likelihood of a catalog being selected in conflict scenarios")
37+
fs.IntVar(&i.PollIntervalMinutes, "source-poll-interval-minutes", 5, "catalog source polling interval [in minutes]")
38+
fs.StringToStringVar(&i.Labels, "labels", map[string]string{}, "labels that will be added to the catalog")
39+
fs.StringVar(&i.AvailabilityMode, "availability-mode", "", "available means that the catalog should be active and serving data")
40+
}

internal/cmd/olmv1.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ func newOlmV1Cmd(cfg *action.Configuration) *cobra.Command {
4848
}
4949
updateCmd.AddCommand(
5050
olmv1.NewExtensionUpdateCmd(cfg),
51+
olmv1.NewCatalogUpdateCmd(cfg),
5152
)
5253

5354
installCmd := &cobra.Command{

internal/pkg/v1/action/action_suite_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ func newClusterCatalog(name string) *olmv1.ClusterCatalog {
110110

111111
type extensionOpt func(*olmv1.ClusterExtension)
112112

113+
type catalogOpt func(*olmv1.ClusterCatalog)
114+
113115
func withVersion(version string) extensionOpt {
114116
return func(ext *olmv1.ClusterExtension) {
115117
ext.Spec.Source.Catalog.Version = version
@@ -141,6 +143,28 @@ func withLabels(labels map[string]string) extensionOpt {
141143
}
142144
}
143145

146+
func withCatalogSourceType(sourceType olmv1.SourceType) catalogOpt {
147+
return func(catalog *olmv1.ClusterCatalog) {
148+
catalog.Spec.Source.Type = sourceType
149+
}
150+
}
151+
152+
func withCatalogSourcePriority(priority int32) catalogOpt {
153+
return func(catalog *olmv1.ClusterCatalog) {
154+
catalog.Spec.Priority = priority
155+
}
156+
}
157+
158+
func withCatalogPollInterval(pollInterval int, ref string) catalogOpt {
159+
return func(catalog *olmv1.ClusterCatalog) {
160+
if catalog.Spec.Source.Image == nil {
161+
catalog.Spec.Source.Image = &olmv1.ImageSource{}
162+
}
163+
catalog.Spec.Source.Image.Ref = ref
164+
catalog.Spec.Source.Image.PollIntervalMinutes = &pollInterval
165+
}
166+
}
167+
144168
func buildExtension(packageName string, opts ...extensionOpt) *olmv1.ClusterExtension {
145169
ext := &olmv1.ClusterExtension{
146170
Spec: olmv1.ClusterExtensionSpec{
@@ -173,3 +197,19 @@ func updateExtensionConditionStatus(name string, cl client.Client, typ string, s
173197

174198
return cl.Update(context.TODO(), &ext)
175199
}
200+
201+
func buildCatalog(catalogName string, opts ...catalogOpt) *olmv1.ClusterCatalog {
202+
catalog := &olmv1.ClusterCatalog{
203+
Spec: olmv1.ClusterCatalogSpec{
204+
Source: olmv1.CatalogSource{
205+
Type: olmv1.SourceTypeImage,
206+
},
207+
},
208+
}
209+
catalog.SetName(catalogName)
210+
for _, opt := range opts {
211+
opt(catalog)
212+
}
213+
214+
return catalog
215+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package action
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"k8s.io/apimachinery/pkg/types"
8+
9+
olmv1 "github.com/operator-framework/operator-controller/api/v1"
10+
11+
"github.com/operator-framework/kubectl-operator/pkg/action"
12+
)
13+
14+
type CatalogUpdate struct {
15+
config *action.Configuration
16+
CatalogName string
17+
18+
Priority int32
19+
PollIntervalMinutes int
20+
Labels map[string]string
21+
AvailabilityMode string
22+
23+
Logf func(string, ...interface{})
24+
}
25+
26+
func NewCatalogUpdate(config *action.Configuration) *CatalogUpdate {
27+
return &CatalogUpdate{
28+
config: config,
29+
Logf: func(string, ...interface{}) {},
30+
}
31+
}
32+
33+
func (cu *CatalogUpdate) Run(ctx context.Context) (*olmv1.ClusterCatalog, error) {
34+
var catalog olmv1.ClusterCatalog
35+
var err error
36+
37+
cuKey := types.NamespacedName{
38+
Name: cu.CatalogName,
39+
Namespace: cu.config.Namespace,
40+
}
41+
if err = cu.config.Client.Get(ctx, cuKey, &catalog); err != nil {
42+
return nil, err
43+
}
44+
45+
if catalog.Spec.Source.Type != olmv1.SourceTypeImage {
46+
return nil, fmt.Errorf("unrecognized source type: %q", catalog.Spec.Source.Type)
47+
}
48+
49+
cu.setDefaults(catalog)
50+
51+
cu.setUpdatedCatalog(&catalog)
52+
if err := cu.config.Client.Update(ctx, &catalog); err != nil {
53+
return nil, err
54+
}
55+
56+
return &catalog, nil
57+
}
58+
59+
func (cu *CatalogUpdate) setUpdatedCatalog(catalog *olmv1.ClusterCatalog) {
60+
catalog.SetLabels(cu.Labels)
61+
catalog.Spec.Priority = cu.Priority
62+
if catalog.Spec.Source.Image != nil && catalog.Spec.Source.Image.PollIntervalMinutes != nil {
63+
catalog.Spec.Source.Image.PollIntervalMinutes = &cu.PollIntervalMinutes
64+
}
65+
catalog.Spec.AvailabilityMode = olmv1.AvailabilityMode(cu.AvailabilityMode)
66+
}
67+
68+
func (cu *CatalogUpdate) setDefaults(catalog olmv1.ClusterCatalog) {
69+
catalogSrc := catalog.Spec.Source
70+
if catalogSrc.Image != nil && catalogSrc.Image.PollIntervalMinutes != nil {
71+
if cu.PollIntervalMinutes == 0 {
72+
cu.PollIntervalMinutes = *catalogSrc.Image.PollIntervalMinutes
73+
}
74+
}
75+
if cu.AvailabilityMode == "" {
76+
cu.AvailabilityMode = string(catalog.Spec.AvailabilityMode)
77+
}
78+
if cu.Priority == 1 {
79+
cu.Priority = catalog.Spec.Priority
80+
}
81+
if len(cu.Labels) == 0 {
82+
cu.Labels = catalog.Labels
83+
}
84+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package action_test
2+
3+
import (
4+
"context"
5+
"maps"
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+
olmv1 "github.com/operator-framework/operator-controller/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("CatalogUpdate", 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 finding existing catalog", func() {
37+
cfg := setupEnv()
38+
39+
updater := internalaction.NewCatalogUpdate(&cfg)
40+
updater.CatalogName = "does-not-exist"
41+
cat, err := updater.Run(context.TODO())
42+
43+
Expect(err).NotTo(BeNil())
44+
Expect(err.Error()).To(ContainSubstring("not found"))
45+
Expect(cat).To(BeNil())
46+
})
47+
48+
It("fails to handle catalog with unknown source type", func() {
49+
cfg := setupEnv(buildCatalog("test", withCatalogSourceType("invalid-type")))
50+
51+
updater := internalaction.NewCatalogUpdate(&cfg)
52+
updater.CatalogName = "test"
53+
_, err := updater.Run(context.TODO())
54+
55+
Expect(err).NotTo(BeNil())
56+
Expect(err.Error()).To(ContainSubstring("unrecognized source type"))
57+
})
58+
59+
It("successfully updates catalog", func() {
60+
testCatalog := buildCatalog(
61+
"testCatalog",
62+
withCatalogSourceType(olmv1.SourceTypeImage),
63+
withCatalogPollInterval(5, "testCatalog"),
64+
withCatalogSourcePriority(1),
65+
)
66+
cfg := setupEnv(testCatalog)
67+
68+
updater := internalaction.NewCatalogUpdate(&cfg)
69+
updater.CatalogName = "testCatalog"
70+
updater.Priority = int32(1)
71+
updater.Labels = map[string]string{"c": "d"}
72+
updater.AvailabilityMode = string(olmv1.AvailabilityModeAvailable)
73+
updater.PollIntervalMinutes = int(5)
74+
catalog, err := updater.Run(context.TODO())
75+
76+
Expect(err).To(BeNil())
77+
Expect(testCatalog).NotTo(BeNil())
78+
Expect(maps.Equal(catalog.Labels, updater.Labels)).To(BeTrue())
79+
Expect(catalog.Spec.Priority).To(Equal(updater.Priority))
80+
Expect(catalog.Spec.Source.Image.PollIntervalMinutes).ToNot(BeNil())
81+
Expect(*catalog.Spec.Source.Image.PollIntervalMinutes).To(Equal(int(5)))
82+
Expect(catalog.Spec.AvailabilityMode).To(Equal(olmv1.AvailabilityMode(updater.AvailabilityMode)))
83+
})
84+
})

0 commit comments

Comments
 (0)