@@ -16,6 +16,7 @@ import (
16
16
17
17
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
18
18
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/certs"
19
+ olmerrors "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/errors"
19
20
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
20
21
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
21
22
)
@@ -40,8 +41,31 @@ func (a *Operator) shouldRotateCerts(csv *v1alpha1.ClusterServiceVersion) bool {
40
41
return false
41
42
}
42
43
44
+ // apiServiceResourceErrorsActionable returns true if OLM can do something about any one
45
+ // of the apiService errors in errs; otherwise returns false
46
+ //
47
+ // This method can be used to determine if a CSV in a failed state due to APIService
48
+ // issues can resolve them by reinstalling
49
+ func (a * Operator ) apiServiceResourceErrorsActionable (errs []error ) bool {
50
+ for _ , err := range errs {
51
+ switch err .(type ) {
52
+ case olmerrors.UnadoptableError :
53
+ return false
54
+ }
55
+ }
56
+
57
+ return true
58
+ }
59
+
43
60
// checkAPIServiceResources checks if all expected generated resources for the given APIService exist
44
- func (a * Operator ) checkAPIServiceResources (csv * v1alpha1.ClusterServiceVersion , hashFunc certs.PEMHash ) error {
61
+ func (a * Operator ) checkAPIServiceResources (csv * v1alpha1.ClusterServiceVersion , hashFunc certs.PEMHash ) []error {
62
+ errs := []error {}
63
+ owners := []ownerutil.Owner {csv }
64
+ // Get replacing CSV if exists
65
+ replacement , _ := a .lister .OperatorsV1alpha1 ().ClusterServiceVersionLister ().ClusterServiceVersions (csv .GetNamespace ()).Get (csv .Spec .Replaces )
66
+ if replacement != nil {
67
+ owners = append (owners , replacement )
68
+ }
45
69
ruleChecker := install .NewCSVRuleChecker (a .lister .RbacV1 ().RoleLister (), a .lister .RbacV1 ().RoleBindingLister (), a .lister .RbacV1 ().ClusterRoleLister (), a .lister .RbacV1 ().ClusterRoleBindingLister (), csv )
46
70
for _ , desc := range csv .GetOwnedAPIServiceDescriptions () {
47
71
apiServiceName := fmt .Sprintf ("%s.%s" , desc .Version , desc .Group )
@@ -51,59 +75,76 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
51
75
"apiservice" : apiServiceName ,
52
76
})
53
77
54
- serviceName := APIServiceNameToServiceName (apiServiceName )
55
- service , err := a .lister .CoreV1 ().ServiceLister ().Services (csv .GetNamespace ()).Get (serviceName )
78
+ apiService , err := a .lister .APIRegistrationV1 ().APIServiceLister ().Get (apiServiceName )
56
79
if err != nil {
57
- logger .WithField ("service" , serviceName ).Warnf ("could not retrieve generated Service" )
58
- return err
80
+ logger .Warnf ("could not retrieve generated APIService" )
81
+ errs = append (errs , err )
82
+ continue
59
83
}
60
84
61
- apiService , err := a .lister .APIRegistrationV1 ().APIServiceLister ().Get (apiServiceName )
85
+ // Check if the APIService is adoptable
86
+ if ! ownerutil .OwnersIntersect (owners , apiService .GetLabels ()) {
87
+ err := olmerrors .NewUnadoptableError ("" , apiServiceName )
88
+ logger .WithError (err ).Warn ("found unadoptable apiservice" )
89
+ errs = append (errs , err )
90
+ return errs
91
+ }
92
+
93
+ serviceName := APIServiceNameToServiceName (apiServiceName )
94
+ service , err := a .lister .CoreV1 ().ServiceLister ().Services (csv .GetNamespace ()).Get (serviceName )
62
95
if err != nil {
63
- logger .Warnf ("could not retrieve generated APIService" )
64
- return err
96
+ logger .WithField ("service" , serviceName ).Warnf ("could not retrieve generated Service" )
97
+ errs = append (errs , err )
98
+ continue
65
99
}
66
100
67
101
// Check if the APIService points to the correct service
68
102
if apiService .Spec .Service .Name != serviceName || apiService .Spec .Service .Namespace != csv .GetNamespace () {
69
103
logger .WithFields (log.Fields {"service" : apiService .Spec .Service .Name , "serviceNamespace" : apiService .Spec .Service .Namespace }).Warnf ("APIService service reference mismatch" )
70
- return fmt .Errorf ("APIService service reference mismatch" )
104
+ errs = append (errs , fmt .Errorf ("APIService service reference mismatch" ))
105
+ continue
71
106
}
72
107
73
108
// Check if CA is Active
74
109
caBundle := apiService .Spec .CABundle
75
110
ca , err := certs .PEMToCert (caBundle )
76
111
if err != nil {
77
112
logger .Warnf ("could not convert APIService CA bundle to x509 cert" )
78
- return err
113
+ errs = append (errs , err )
114
+ continue
79
115
}
80
116
if ! certs .Active (ca ) {
81
117
logger .Warnf ("CA cert not active" )
82
- return fmt .Errorf ("CA cert not active" )
118
+ errs = append (errs , fmt .Errorf ("CA cert not active" ))
119
+ continue
83
120
}
84
121
85
122
// Check if serving cert is active
86
123
secretName := apiServiceName + "-cert"
87
124
secret , err := a .lister .CoreV1 ().SecretLister ().Secrets (csv .GetNamespace ()).Get (secretName )
88
125
if err != nil {
89
126
logger .WithField ("secret" , secretName ).Warnf ("could not retrieve generated Secret" )
90
- return err
127
+ errs = append (errs , err )
128
+ continue
91
129
}
92
130
cert , err := certs .PEMToCert (secret .Data ["tls.crt" ])
93
131
if err != nil {
94
132
logger .Warnf ("could not convert serving cert to x509 cert" )
95
- return err
133
+ errs = append (errs , err )
134
+ continue
96
135
}
97
136
if ! certs .Active (cert ) {
98
137
logger .Warnf ("serving cert not active" )
99
- return fmt .Errorf ("serving cert not active" )
138
+ errs = append (errs , fmt .Errorf ("serving cert not active" ))
139
+ continue
100
140
}
101
141
102
142
// Check if CA hash matches expected
103
143
caHash := hashFunc (caBundle )
104
144
if hash , ok := secret .GetAnnotations ()[OLMCAHashAnnotationKey ]; ! ok || hash != caHash {
105
145
logger .WithField ("secret" , secretName ).Warnf ("secret CA cert hash does not match expected" )
106
- return fmt .Errorf ("secret %s CA cert hash does not match expected" , secretName )
146
+ errs = append (errs , fmt .Errorf ("secret %s CA cert hash does not match expected" , secretName ))
147
+ continue
107
148
}
108
149
109
150
// Check if serving cert is trusted by the CA
@@ -113,19 +154,22 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
113
154
}
114
155
for _ , host := range hosts {
115
156
if err := certs .VerifyCert (ca , cert , host ); err != nil {
116
- return fmt .Errorf ("could not verify cert: %s" , err .Error ())
157
+ errs = append (errs , fmt .Errorf ("could not verify cert: %s" , err .Error ()))
158
+ continue
117
159
}
118
160
}
119
161
120
162
// Ensure the existing Deployment has a matching CA hash annotation
121
163
deployment , err := a .lister .AppsV1 ().DeploymentLister ().Deployments (csv .GetNamespace ()).Get (desc .DeploymentName )
122
164
if k8serrors .IsNotFound (err ) || err != nil {
123
165
logger .WithField ("deployment" , desc .DeploymentName ).Warnf ("expected Deployment could not be retrieved" )
124
- return err
166
+ errs = append (errs , err )
167
+ continue
125
168
}
126
169
if hash , ok := deployment .Spec .Template .GetAnnotations ()[OLMCAHashAnnotationKey ]; ! ok || hash != caHash {
127
170
logger .WithField ("deployment" , desc .DeploymentName ).Warnf ("Deployment CA cert hash does not match expected" )
128
- return fmt .Errorf ("Deployment %s CA cert hash does not match expected" , desc .DeploymentName )
171
+ errs = append (errs , fmt .Errorf ("Deployment %s CA cert hash does not match expected" , desc .DeploymentName ))
172
+ continue
129
173
}
130
174
131
175
// Ensure the Deployment's ServiceAccount exists
@@ -136,7 +180,8 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
136
180
serviceAccount , err := a .lister .CoreV1 ().ServiceAccountLister ().ServiceAccounts (deployment .GetNamespace ()).Get (serviceAccountName )
137
181
if err != nil {
138
182
logger .WithField ("serviceaccount" , serviceAccountName ).Warnf ("could not retrieve ServiceAccount" )
139
- return err
183
+ errs = append (errs , err )
184
+ continue
140
185
}
141
186
142
187
// Ensure RBAC permissions for the APIService are correct
@@ -158,15 +203,17 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
158
203
authReaderRole , err := a .lister .RbacV1 ().RoleLister ().Roles ("kube-system" ).Get ("extension-apiserver-authentication-reader" )
159
204
if err != nil {
160
205
logger .Warnf ("could not retrieve Role extension-apiserver-authentication-reader" )
161
- return err
206
+ errs = append (errs , err )
207
+ continue
162
208
}
163
209
rulesMap ["kube-system" ] = append (rulesMap ["kube-system" ], authReaderRole .Rules ... )
164
210
165
211
// system:auth-delegator
166
212
authDelegatorClusterRole , err := a .lister .RbacV1 ().ClusterRoleLister ().Get ("system:auth-delegator" )
167
213
if err != nil {
168
214
logger .Warnf ("could not retrieve ClusterRole system:auth-delegator" )
169
- return err
215
+ errs = append (errs , err )
216
+ continue
170
217
}
171
218
rulesMap [metav1 .NamespaceAll ] = append (rulesMap [metav1 .NamespaceAll ], authDelegatorClusterRole .Rules ... )
172
219
@@ -175,17 +222,19 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
175
222
satisfied , err := ruleChecker .RuleSatisfied (serviceAccount , namespace , rule )
176
223
if err != nil {
177
224
logger .WithField ("rule" , fmt .Sprintf ("%+v" , rule )).Warnf ("error checking Rule" )
178
- return err
225
+ errs = append (errs , err )
226
+ continue
179
227
}
180
228
if ! satisfied {
181
229
logger .WithField ("rule" , fmt .Sprintf ("%+v" , rule )).Warnf ("Rule not satisfied" )
182
- return fmt .Errorf ("Rule %+v not satisfied" , rule )
230
+ errs = append (errs , fmt .Errorf ("Rule %+v not satisfied" , rule ))
231
+ continue
183
232
}
184
233
}
185
234
}
186
235
}
187
236
188
- return nil
237
+ return errs
189
238
}
190
239
191
240
func (a * Operator ) isAPIServiceAvailable (apiService * apiregistrationv1.APIService ) bool {
@@ -639,8 +688,14 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
639
688
}
640
689
apiService .SetName (apiServiceName )
641
690
} else {
691
+ owners := []ownerutil.Owner {csv }
692
+ // Get replacing CSV
693
+ replaces , err := a .lister .OperatorsV1alpha1 ().ClusterServiceVersionLister ().ClusterServiceVersions (csv .GetNamespace ()).Get (csv .Spec .Replaces )
694
+ if err == nil {
695
+ owners = append (owners , replaces )
696
+ }
642
697
// check if the APIService is adoptable
643
- if ! ownerutil .AdoptableLabels ( csv , apiService .GetLabels ()) {
698
+ if ! ownerutil .OwnersIntersect ( owners , apiService .GetLabels ()) {
644
699
return nil , fmt .Errorf ("pre-existing APIService %s is not adoptable" , apiServiceName )
645
700
}
646
701
}
0 commit comments