Skip to content

Commit b8911ee

Browse files
committed
internal/pkg/action/operator_install.go: improve operator group logic
improve handling for detecting invalid install modes: - fail if operator does not support any install modes (this _should_ be caught earlier by bundle validation) - fail if SingleNamespace or MultiNamespace contains <currentNamespace>, but OwnNamespace is not supported by operator - use OwnNamespace instead of SingleNamespace=<currentNamespace> - install mode must be explicitly set for SingleNamespace and MultiNamespace
1 parent 6e04316 commit b8911ee

File tree

1 file changed

+105
-68
lines changed

1 file changed

+105
-68
lines changed

internal/pkg/action/operator_install.go

Lines changed: 105 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,6 @@ func (i *OperatorInstall) BindFlags(fs *pflag.FlagSet) {
5151
}
5252

5353
func (i *OperatorInstall) Run(ctx context.Context) (*v1alpha1.ClusterServiceVersion, error) {
54-
og, err := i.getOperatorGroup(ctx)
55-
if err != nil {
56-
return nil, err
57-
}
58-
5954
pm, err := i.getPackageManifest(ctx)
6055
if err != nil {
6156
return nil, fmt.Errorf("get package manifest: %v", err)
@@ -65,24 +60,8 @@ func (i *OperatorInstall) Run(ctx context.Context) (*v1alpha1.ClusterServiceVers
6560
if err != nil {
6661
return nil, fmt.Errorf("get package channel: %v", err)
6762
}
68-
supported := getSupportedInstallModes(pc.CurrentCSVDesc.InstallModes)
69-
if !i.InstallMode.IsEmpty() {
70-
supported = supported.Intersection(sets.NewString(string(i.InstallMode.InstallModeType)))
71-
if supported.Len() == 0 {
72-
return nil, fmt.Errorf("operator %q does not support install mode %q", pm.Name, i.InstallMode.InstallModeType)
73-
}
74-
}
7563

76-
if og == nil {
77-
if i.CreateOperatorGroup {
78-
if og, err = i.createOperatorGroup(ctx, supported); err != nil {
79-
return nil, fmt.Errorf("create operator group: %v", err)
80-
}
81-
log.Printf("operatorgroup %q created", og.Name)
82-
} else {
83-
return nil, fmt.Errorf("namespace %q has no existing operator group; use --create-operator-group to create one automatically", i.config.Namespace)
84-
}
85-
} else if err := i.validateOperatorGroup(*og, supported); err != nil {
64+
if _, err := i.ensureOperatorGroup(ctx, pm, pc); err != nil {
8665
return nil, err
8766
}
8867

@@ -111,6 +90,81 @@ func (i *OperatorInstall) Run(ctx context.Context) (*v1alpha1.ClusterServiceVers
11190
return csv, nil
11291
}
11392

93+
func (i *OperatorInstall) getPackageManifest(ctx context.Context) (*operatorsv1.PackageManifest, error) {
94+
pm := &operatorsv1.PackageManifest{}
95+
key := types.NamespacedName{
96+
Namespace: i.config.Namespace,
97+
Name: i.Package,
98+
}
99+
if err := i.config.Client.Get(ctx, key, pm); err != nil {
100+
return nil, err
101+
}
102+
return pm, nil
103+
}
104+
105+
func (i *OperatorInstall) getPackageChannel(pm *operatorsv1.PackageManifest) (*operatorsv1.PackageChannel, error) {
106+
if i.Channel == "" {
107+
i.Channel = pm.Status.DefaultChannel
108+
}
109+
var packageChannel *operatorsv1.PackageChannel
110+
for _, ch := range pm.Status.Channels {
111+
if ch.Name == i.Channel {
112+
packageChannel = &ch
113+
}
114+
}
115+
if packageChannel == nil {
116+
return nil, fmt.Errorf("channel %q does not exist for package %q", i.Channel, i.Package)
117+
}
118+
return packageChannel, nil
119+
}
120+
121+
func (i *OperatorInstall) ensureOperatorGroup(ctx context.Context, pm *operatorsv1.PackageManifest, pc *operatorsv1.PackageChannel) (*v1.OperatorGroup, error) {
122+
og, err := i.getOperatorGroup(ctx)
123+
if err != nil {
124+
return nil, err
125+
}
126+
127+
supported := getSupportedInstallModes(pc.CurrentCSVDesc.InstallModes)
128+
if supported.Len() == 0 {
129+
return nil, fmt.Errorf("operator %q is not installable: no supported install modes", pm.Name)
130+
}
131+
132+
if !i.InstallMode.IsEmpty() {
133+
if i.InstallMode.InstallModeType == v1alpha1.InstallModeTypeSingleNamespace || i.InstallMode.InstallModeType == v1alpha1.InstallModeTypeMultiNamespace {
134+
targetNsSet := sets.NewString(i.InstallMode.TargetNamespaces...)
135+
if !supported.Has(string(v1alpha1.InstallModeTypeOwnNamespace)) && targetNsSet.Has(i.config.Namespace) {
136+
return nil, fmt.Errorf("cannot watch namespace %q: operator %q does not support install mode %q", i.config.Namespace, pm.Name, v1alpha1.InstallModeTypeOwnNamespace)
137+
}
138+
}
139+
if i.InstallMode.InstallModeType == v1alpha1.InstallModeTypeSingleNamespace && i.InstallMode.TargetNamespaces[0] == i.config.Namespace {
140+
return nil, fmt.Errorf("use install mode %q to watch operator's namespace %q", v1alpha1.InstallModeTypeOwnNamespace, i.config.Namespace)
141+
}
142+
143+
supported = supported.Intersection(sets.NewString(string(i.InstallMode.InstallModeType)))
144+
if supported.Len() == 0 {
145+
return nil, fmt.Errorf("operator %q does not support install mode %q", pm.Name, i.InstallMode.InstallModeType)
146+
}
147+
}
148+
149+
if og == nil {
150+
if i.CreateOperatorGroup {
151+
targetNamespaces, err := i.getTargetNamespaces(supported)
152+
if err != nil {
153+
return nil, err
154+
}
155+
if og, err = i.createOperatorGroup(ctx, targetNamespaces); err != nil {
156+
return nil, fmt.Errorf("create operator group: %v", err)
157+
}
158+
log.Printf("operatorgroup %q created", og.Name)
159+
} else {
160+
return nil, fmt.Errorf("namespace %q has no existing operator group; use --create-operator-group to create one automatically", i.config.Namespace)
161+
}
162+
} else if err := i.validateOperatorGroup(*og, supported); err != nil {
163+
return nil, err
164+
}
165+
return og, nil
166+
}
167+
114168
func (i OperatorInstall) getOperatorGroup(ctx context.Context) (*v1.OperatorGroup, error) {
115169
ogs := &v1.OperatorGroupList{}
116170
err := i.config.Client.List(ctx, ogs, client.InNamespace(i.config.Namespace))
@@ -128,34 +182,43 @@ func (i OperatorInstall) getOperatorGroup(ctx context.Context) (*v1.OperatorGrou
128182
}
129183
}
130184

131-
func (i *OperatorInstall) getPackageManifest(ctx context.Context) (*operatorsv1.PackageManifest, error) {
132-
pm := &operatorsv1.PackageManifest{}
133-
key := types.NamespacedName{
134-
Namespace: i.config.Namespace,
135-
Name: i.Package,
136-
}
137-
if err := i.config.Client.Get(ctx, key, pm); err != nil {
138-
return nil, err
185+
func getSupportedInstallModes(csvInstallModes []v1alpha1.InstallMode) sets.String {
186+
supported := sets.NewString()
187+
for _, im := range csvInstallModes {
188+
if im.Supported {
189+
supported.Insert(string(im.Type))
190+
}
139191
}
140-
return pm, nil
192+
return supported
141193
}
142194

143-
func (i *OperatorInstall) createOperatorGroup(ctx context.Context, supported sets.String) (*v1.OperatorGroup, error) {
144-
og := &v1.OperatorGroup{}
145-
og.SetName(i.config.Namespace)
146-
og.SetNamespace(i.config.Namespace)
147-
195+
func (i *OperatorInstall) getTargetNamespaces(supported sets.String) ([]string, error) {
148196
switch {
149-
case supported.HasAny(
150-
string(v1alpha1.InstallModeTypeAllNamespaces),
151-
string(v1alpha1.InstallModeTypeSingleNamespace),
152-
string(v1alpha1.InstallModeTypeMultiNamespace)):
153-
og.Spec.TargetNamespaces = i.InstallMode.TargetNamespaces
197+
case supported.Has(string(v1alpha1.InstallModeTypeAllNamespaces)):
198+
return nil, nil
154199
case supported.Has(string(v1alpha1.InstallModeTypeOwnNamespace)):
155-
og.Spec.TargetNamespaces = []string{i.config.Namespace}
200+
return []string{i.config.Namespace}, nil
201+
case supported.Has(string(v1alpha1.InstallModeTypeSingleNamespace)):
202+
if len(i.InstallMode.TargetNamespaces) != 1 {
203+
return nil, fmt.Errorf("install mode %q requires explicit target namespace", v1alpha1.InstallModeTypeSingleNamespace)
204+
}
205+
return i.InstallMode.TargetNamespaces, nil
206+
case supported.Has(string(v1alpha1.InstallModeTypeMultiNamespace)):
207+
if len(i.InstallMode.TargetNamespaces) == 0 {
208+
return nil, fmt.Errorf("install mode %q requires explicit target namespaces", v1alpha1.InstallModeTypeMultiNamespace)
209+
}
210+
return i.InstallMode.TargetNamespaces, nil
156211
default:
157212
return nil, fmt.Errorf("no supported install modes")
158213
}
214+
}
215+
216+
func (i *OperatorInstall) createOperatorGroup(ctx context.Context, targetNamespaces []string) (*v1.OperatorGroup, error) {
217+
og := &v1.OperatorGroup{}
218+
og.SetName(i.config.Namespace)
219+
og.SetNamespace(i.config.Namespace)
220+
og.Spec.TargetNamespaces = targetNamespaces
221+
159222
if err := i.config.Client.Create(ctx, og); err != nil {
160223
return nil, err
161224
}
@@ -184,32 +247,6 @@ func (i *OperatorInstall) validateOperatorGroup(og v1.OperatorGroup, supported s
184247
panic(fmt.Sprintf("unknown install mode %q", i.InstallMode.InstallModeType))
185248
}
186249

187-
func getSupportedInstallModes(csvInstallModes []v1alpha1.InstallMode) sets.String {
188-
supported := sets.NewString()
189-
for _, im := range csvInstallModes {
190-
if im.Supported {
191-
supported.Insert(string(im.Type))
192-
}
193-
}
194-
return supported
195-
}
196-
197-
func (i *OperatorInstall) getPackageChannel(pm *operatorsv1.PackageManifest) (*operatorsv1.PackageChannel, error) {
198-
if i.Channel == "" {
199-
i.Channel = pm.Status.DefaultChannel
200-
}
201-
var packageChannel *operatorsv1.PackageChannel
202-
for _, ch := range pm.Status.Channels {
203-
if ch.Name == i.Channel {
204-
packageChannel = &ch
205-
}
206-
}
207-
if packageChannel == nil {
208-
return nil, fmt.Errorf("channel %q does not exist for package %q", i.Channel, i.Package)
209-
}
210-
return packageChannel, nil
211-
}
212-
213250
func (i *OperatorInstall) createSubscription(ctx context.Context, pm *operatorsv1.PackageManifest, pc *operatorsv1.PackageChannel) (*v1alpha1.Subscription, error) {
214251
opts := []subscription.Option{
215252
subscription.InstallPlanApproval(i.Approval.Approval),

0 commit comments

Comments
 (0)