Skip to content

Commit efb2a2a

Browse files
committed
fix(operatorgroups): write out CSV status on OperatorGroup issues
- Adds 3 new CSV transition reasons: NoOperatorGroup, TooManyOperatorGroups, and UnsupportedOperatorGroup - Transitions CSVs to failed with the approriate status reason whenever an OperatorGroup issue is detected - OperatorGroup reconciliation annotates CSVs in any phase - Update InstallModes supports logic
1 parent 63aa1e1 commit efb2a2a

File tree

8 files changed

+682
-326
lines changed

8 files changed

+682
-326
lines changed

Documentation/design/building-your-csv.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,12 @@ The metadata section contains general metadata around the name, version and othe
236236

237237
**Selectors** (optional): A label selector to identify related resources. Set this to select on current labels applied to this CSV object (if applicable).
238238

239+
**InstallModes**: A set of `InstallMode`s that tell OLM which `OperatorGroup`s an Operator can belong to. Belonging to an `OperatorGroup` means that OLM provides the set of targetted namespaces as an annotation on the Operator's CSV and any deployments defined therin. These deployments can then untilize [the Downward API](https://kubernetes.io/docs/tasks/inject-data-application/downward-api-volume-expose-pod-information/#the-downward-api) to inject the list of namespaces into its container(s). An `InstallMode` consists of an `InstallModeType` field and a boolean `Supported` field. There are four `InstallModeTypes`:
240+
* `OwnNamespace`: If supported, the set of namespaces targetted by an `OperatorGroup` must contain the namespace the Operator is to be installed in.
241+
* `SingleNamespace`: If supported, the set of namespaces targetted by an `OperatorGroup` can be of length 1.
242+
* `MultiNamespace`: If supported, the set of namespaces targetted by an `OperatorGroup` can be of length >= 1. Any Operator supporting `MultiNamespace` implicitly supports `SingleNamespace` as well.
243+
* `AllNamespaces`: If supported, the Operator can support an `OperatorGroup` that selects all namespaces with a targetted set = [""]. Any Operator supporting `AllNamespaces` implicity supports `OwnNamespace` as well.
244+
239245
Here's an example:
240246

241247
```keywords: ['etcd', 'key value', 'database', 'coreos', 'open source']
@@ -264,6 +270,15 @@ Here's an example:
264270
icon:
265271
- base64data: <base64-encoded-data>
266272
mediatype: image/png
273+
installModes:
274+
- type: OwnNamespace
275+
supported: true
276+
- type: SingleNamespace
277+
supported: true
278+
- type: MultiNamespace
279+
supported: false
280+
- type: AllNamespaces
281+
supported: true
267282
```
268283
269284
## Operator Install

pkg/api/apis/operators/v1alpha1/clusterserviceversion.go

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ func (c *ClusterServiceVersion) IsObsolete() bool {
7171
return false
7272
}
7373

74+
// IsCopied returns true if the CSV has been copied and false otherwise.
75+
func (c *ClusterServiceVersion) IsCopied() bool {
76+
operatorNamespace, ok := c.GetAnnotations()[OperatorGroupNamespaceAnnotationKey]
77+
if c.Status.Reason == CSVReasonCopied || ok && c.GetNamespace() != operatorNamespace {
78+
return true
79+
}
80+
return false
81+
}
82+
7483
// NewInstallModeSet returns an InstallModeSet instantiated from the given list of InstallModes.
7584
// If the given list is not a set, an error is returned.
7685
func NewInstallModeSet(modes []InstallMode) (InstallModeSet, error) {
@@ -86,22 +95,29 @@ func NewInstallModeSet(modes []InstallMode) (InstallModeSet, error) {
8695
}
8796

8897
// Supports returns an error if the InstallModeSet does not support configuration for
89-
// the given list of namespaces.
90-
func (set InstallModeSet) Supports(namespaces []string) error {
91-
// Return an error if set contains incompatible supported modes
92-
// for the number of namespaces given.
98+
// the given operatorNamespace and list of target namespaces.
99+
func (set InstallModeSet) Supports(operatorNamespace string, namespaces []string) error {
93100
numNamespaces := len(namespaces)
94101
if !set[InstallModeTypeAllNamespaces] && numNamespaces == 1 && namespaces[0] == v1.NamespaceAll {
95102
return fmt.Errorf("%s InstallModeType not supported, cannot configure to watch all namespaces", InstallModeTypeAllNamespaces)
96103
}
97104

98-
if !set[InstallModeTypeSingleNamespace] && numNamespaces == 1 && namespaces[0] != v1.NamespaceAll {
105+
if !set[InstallModeTypeSingleNamespace] && !set[InstallModeTypeMultiNamespace] && numNamespaces == 1 && namespaces[0] != v1.NamespaceAll {
99106
return fmt.Errorf("%s InstallModeType not supported, cannot configure to watch one namespace", InstallModeTypeSingleNamespace)
100107
}
101108

102109
if !set[InstallModeTypeMultiNamespace] && numNamespaces > 1 {
103110
return fmt.Errorf("%s InstallModeType not supported, cannot configure to watch %d namespaces", InstallModeTypeMultiNamespace, numNamespaces)
104111
}
105112

113+
for i, namespace := range namespaces {
114+
if !set[InstallModeTypeOwnNamespace] && namespace == operatorNamespace {
115+
return fmt.Errorf("%s InstallModeType not supported, cannot configure to watch own namespace", InstallModeTypeOwnNamespace)
116+
}
117+
if i > 0 && namespace == v1.NamespaceAll {
118+
return fmt.Errorf("Invalid selected namespaces, NamespaceAll found when |selected namespaces| > 1")
119+
}
120+
}
121+
106122
return nil
107123
}

pkg/api/apis/operators/v1alpha1/clusterserviceversion_test.go

Lines changed: 84 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,11 @@ func TestIsObsolete(t *testing.T) {
107107

108108
func TestSupports(t *testing.T) {
109109
tests := []struct {
110-
description string
111-
installModeSet InstallModeSet
112-
namespaces []string
113-
expectedErr error
110+
description string
111+
installModeSet InstallModeSet
112+
operatorNamespace string
113+
namespaces []string
114+
expectedErr error
114115
}{
115116
{
116117
description: "NoNamespaces",
@@ -120,8 +121,9 @@ func TestSupports(t *testing.T) {
120121
InstallModeTypeMultiNamespace: true,
121122
InstallModeTypeAllNamespaces: true,
122123
},
123-
namespaces: []string{},
124-
expectedErr: nil,
124+
operatorNamespace: "operators",
125+
namespaces: []string{},
126+
expectedErr: nil,
125127
},
126128
{
127129
description: "OneNamespace",
@@ -131,8 +133,9 @@ func TestSupports(t *testing.T) {
131133
InstallModeTypeMultiNamespace: true,
132134
InstallModeTypeAllNamespaces: true,
133135
},
134-
namespaces: []string{"ns-0"},
135-
expectedErr: nil,
136+
operatorNamespace: "operators",
137+
namespaces: []string{"ns-0"},
138+
expectedErr: nil,
136139
},
137140
{
138141
description: "MultipleNamespaces/MultiNamespaceUnsupported",
@@ -142,19 +145,57 @@ func TestSupports(t *testing.T) {
142145
InstallModeTypeMultiNamespace: false,
143146
InstallModeTypeAllNamespaces: true,
144147
},
145-
namespaces: []string{"ns-0", "ns-1"},
146-
expectedErr: fmt.Errorf("%s InstallModeType not supported, cannot configure to watch 2 namespaces", InstallModeTypeMultiNamespace),
148+
operatorNamespace: "operators",
149+
namespaces: []string{"ns-0", "ns-1"},
150+
expectedErr: fmt.Errorf("%s InstallModeType not supported, cannot configure to watch 2 namespaces", InstallModeTypeMultiNamespace),
147151
},
148152
{
149-
description: "SingleNamespace/SingleNamespaceUnsupported",
153+
description: "MultipleNamespaces/OwnNamespaceUnsupported",
154+
installModeSet: InstallModeSet{
155+
InstallModeTypeOwnNamespace: false,
156+
InstallModeTypeSingleNamespace: true,
157+
InstallModeTypeMultiNamespace: true,
158+
InstallModeTypeAllNamespaces: true,
159+
},
160+
operatorNamespace: "operators",
161+
namespaces: []string{"ns-0", "ns-1", "operators"},
162+
expectedErr: fmt.Errorf("%s InstallModeType not supported, cannot configure to watch own namespace", InstallModeTypeOwnNamespace),
163+
},
164+
{
165+
description: "SingleNamespace/SingleAndMultiNamespaceUnsupported",
150166
installModeSet: InstallModeSet{
151167
InstallModeTypeOwnNamespace: true,
152168
InstallModeTypeSingleNamespace: false,
169+
InstallModeTypeMultiNamespace: false,
170+
InstallModeTypeAllNamespaces: true,
171+
},
172+
operatorNamespace: "operators",
173+
namespaces: []string{"ns-0"},
174+
expectedErr: fmt.Errorf("%s InstallModeType not supported, cannot configure to watch one namespace", InstallModeTypeSingleNamespace),
175+
},
176+
{
177+
description: "SingleNamespace/MultiNamespaceDecomposes",
178+
installModeSet: InstallModeSet{
179+
InstallModeTypeOwnNamespace: true,
180+
InstallModeTypeSingleNamespace: false,
181+
InstallModeTypeMultiNamespace: true,
182+
InstallModeTypeAllNamespaces: true,
183+
},
184+
operatorNamespace: "operators",
185+
namespaces: []string{"ns-0"},
186+
expectedErr: nil,
187+
},
188+
{
189+
description: "SingleNamespace/OwnNamespaceUnsupported",
190+
installModeSet: InstallModeSet{
191+
InstallModeTypeOwnNamespace: false,
192+
InstallModeTypeSingleNamespace: true,
153193
InstallModeTypeMultiNamespace: true,
154194
InstallModeTypeAllNamespaces: true,
155195
},
156-
namespaces: []string{"ns-0"},
157-
expectedErr: fmt.Errorf("%s InstallModeType not supported, cannot configure to watch one namespace", InstallModeTypeSingleNamespace),
196+
operatorNamespace: "operators",
197+
namespaces: []string{"operators"},
198+
expectedErr: fmt.Errorf("%s InstallModeType not supported, cannot configure to watch own namespace", InstallModeTypeOwnNamespace),
158199
},
159200
{
160201
description: "AllNamespaces/AllNamespacesSupported",
@@ -164,8 +205,9 @@ func TestSupports(t *testing.T) {
164205
InstallModeTypeMultiNamespace: true,
165206
InstallModeTypeAllNamespaces: true,
166207
},
167-
namespaces: []string{corev1.NamespaceAll},
168-
expectedErr: nil,
208+
operatorNamespace: "operators",
209+
namespaces: []string{corev1.NamespaceAll},
210+
expectedErr: nil,
169211
},
170212
{
171213
description: "AllNamespaces/AllNamespacesUnsupported",
@@ -175,39 +217,44 @@ func TestSupports(t *testing.T) {
175217
InstallModeTypeMultiNamespace: true,
176218
InstallModeTypeAllNamespaces: false,
177219
},
178-
namespaces: []string{corev1.NamespaceAll},
179-
expectedErr: fmt.Errorf("%s InstallModeType not supported, cannot configure to watch all namespaces", InstallModeTypeAllNamespaces),
220+
operatorNamespace: "operators",
221+
namespaces: []string{corev1.NamespaceAll},
222+
expectedErr: fmt.Errorf("%s InstallModeType not supported, cannot configure to watch all namespaces", InstallModeTypeAllNamespaces),
180223
},
181224
{
182-
description: "NoNamespaces/EmptyInstallModeSet",
183-
installModeSet: InstallModeSet{},
184-
namespaces: []string{},
185-
expectedErr: nil,
225+
description: "NoNamespaces/EmptyInstallModeSet",
226+
installModeSet: InstallModeSet{},
227+
operatorNamespace: "",
228+
namespaces: []string{},
229+
expectedErr: nil,
186230
},
187231
{
188-
description: "MultipleNamespaces/EmptyInstallModeSet",
189-
installModeSet: InstallModeSet{},
190-
namespaces: []string{"ns-0", "ns-1"},
191-
expectedErr: fmt.Errorf("%s InstallModeType not supported, cannot configure to watch 2 namespaces", InstallModeTypeMultiNamespace),
232+
description: "MultipleNamespaces/EmptyInstallModeSet",
233+
installModeSet: InstallModeSet{},
234+
operatorNamespace: "operators",
235+
namespaces: []string{"ns-0", "ns-1"},
236+
expectedErr: fmt.Errorf("%s InstallModeType not supported, cannot configure to watch 2 namespaces", InstallModeTypeMultiNamespace),
192237
},
193238
{
194-
description: "SingleNamespace/EmptyInstallModeSet",
195-
installModeSet: InstallModeSet{},
196-
namespaces: []string{"ns-0"},
197-
expectedErr: fmt.Errorf("%s InstallModeType not supported, cannot configure to watch one namespace", InstallModeTypeSingleNamespace),
239+
description: "SingleNamespace/EmptyInstallModeSet",
240+
installModeSet: InstallModeSet{},
241+
operatorNamespace: "operators",
242+
namespaces: []string{"ns-0"},
243+
expectedErr: fmt.Errorf("%s InstallModeType not supported, cannot configure to watch one namespace", InstallModeTypeSingleNamespace),
198244
},
199245
{
200-
description: "AllNamespaces/EmptyInstallModeSet",
201-
installModeSet: InstallModeSet{},
202-
namespaces: []string{corev1.NamespaceAll},
203-
expectedErr: fmt.Errorf("%s InstallModeType not supported, cannot configure to watch all namespaces", InstallModeTypeAllNamespaces),
246+
description: "AllNamespaces/EmptyInstallModeSet",
247+
installModeSet: InstallModeSet{},
248+
operatorNamespace: "operators",
249+
namespaces: []string{corev1.NamespaceAll},
250+
expectedErr: fmt.Errorf("%s InstallModeType not supported, cannot configure to watch all namespaces", InstallModeTypeAllNamespaces),
204251
},
205252
}
206253

207-
for _, test := range tests {
208-
t.Run(test.description, func(t *testing.T) {
209-
err := test.installModeSet.Supports(test.namespaces)
210-
require.Equal(t, err, test.expectedErr)
254+
for _, tt := range tests {
255+
t.Run(tt.description, func(t *testing.T) {
256+
err := tt.installModeSet.Supports(tt.operatorNamespace, tt.namespaces)
257+
require.Equal(t, tt.expectedErr, err)
211258
})
212259
}
213260
}

pkg/api/apis/operators/v1alpha1/clusterserviceversion_types.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ import (
1414
)
1515

1616
const (
17-
ClusterServiceVersionAPIVersion = operators.GroupName + "/" + GroupVersion
18-
ClusterServiceVersionKind = "ClusterServiceVersion"
17+
ClusterServiceVersionAPIVersion = operators.GroupName + "/" + GroupVersion
18+
ClusterServiceVersionKind = "ClusterServiceVersion"
19+
OperatorGroupNamespaceAnnotationKey = "olm.operatorNamespace"
1920
)
2021

2122
// InstallModeType is a supported type of install mode for CSV installation
@@ -227,7 +228,11 @@ const (
227228
CSVReasonAPIServiceResourcesNeedReinstall ConditionReason = "APIServiceResourcesNeedReinstall"
228229
CSVReasonAPIServiceInstallFailed ConditionReason = "APIServiceInstallFailed"
229230
CSVReasonCopied ConditionReason = "Copied"
230-
CSVReasonInstallModeNotSupported ConditionReason = "InstallModeNotSupported"
231+
CSVReasonInvalidInstallModes ConditionReason = "InvalidInstallModes"
232+
CSVReasonNoTargetNamespaces ConditionReason = "NoTargetNamespaces"
233+
CSVReasonUnsupportedOperatorGroup ConditionReason = "UnsupportedOperatorGroup"
234+
CSVReasonNoOperatorGroup ConditionReason = "NoOperatorGroup"
235+
CSVReasonTooManyOperatorGroups ConditionReason = "TooManyOperatorGroups"
231236
)
232237

233238
// Conditions appear in the status as a record of state transitions on the ClusterServiceVersion

0 commit comments

Comments
 (0)