@@ -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,36 @@ 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 , err := a .lister .OperatorsV1alpha1 ().ClusterServiceVersionLister ().ClusterServiceVersions (csv .GetNamespace ()).Get (csv .Spec .Replaces )
66
+ if err != nil && k8serrors .IsNotFound (err ) == false {
67
+ a .Log .Debugf ("Replacement error regarding CSV (%v): %v" , csv .GetName (), err )
68
+ errs = append (errs , err )
69
+ return errs
70
+ }
71
+ if replacement != nil {
72
+ owners = append (owners , replacement )
73
+ }
45
74
ruleChecker := install .NewCSVRuleChecker (a .lister .RbacV1 ().RoleLister (), a .lister .RbacV1 ().RoleBindingLister (), a .lister .RbacV1 ().ClusterRoleLister (), a .lister .RbacV1 ().ClusterRoleBindingLister (), csv )
46
75
for _ , desc := range csv .GetOwnedAPIServiceDescriptions () {
47
76
apiServiceName := fmt .Sprintf ("%s.%s" , desc .Version , desc .Group )
@@ -51,59 +80,76 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
51
80
"apiservice" : apiServiceName ,
52
81
})
53
82
54
- serviceName := APIServiceNameToServiceName (apiServiceName )
55
- service , err := a .lister .CoreV1 ().ServiceLister ().Services (csv .GetNamespace ()).Get (serviceName )
83
+ apiService , err := a .lister .APIRegistrationV1 ().APIServiceLister ().Get (apiServiceName )
56
84
if err != nil {
57
- logger .WithField ("service" , serviceName ).Warnf ("could not retrieve generated Service" )
58
- return err
85
+ logger .Warnf ("could not retrieve generated APIService" )
86
+ errs = append (errs , err )
87
+ continue
59
88
}
60
89
61
- apiService , err := a .lister .APIRegistrationV1 ().APIServiceLister ().Get (apiServiceName )
90
+ // Check if the APIService is adoptable
91
+ if ! ownerutil .OwnersIntersect (owners , apiService ) {
92
+ err := olmerrors .NewUnadoptableError ("" , apiServiceName )
93
+ logger .WithError (err ).Warn ("found unadoptable apiservice" )
94
+ errs = append (errs , err )
95
+ return errs
96
+ }
97
+
98
+ serviceName := APIServiceNameToServiceName (apiServiceName )
99
+ service , err := a .lister .CoreV1 ().ServiceLister ().Services (csv .GetNamespace ()).Get (serviceName )
62
100
if err != nil {
63
- logger .Warnf ("could not retrieve generated APIService" )
64
- return err
101
+ logger .WithField ("service" , serviceName ).Warnf ("could not retrieve generated Service" )
102
+ errs = append (errs , err )
103
+ continue
65
104
}
66
105
67
106
// Check if the APIService points to the correct service
68
107
if apiService .Spec .Service .Name != serviceName || apiService .Spec .Service .Namespace != csv .GetNamespace () {
69
108
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" )
109
+ errs = append (errs , fmt .Errorf ("APIService service reference mismatch" ))
110
+ continue
71
111
}
72
112
73
113
// Check if CA is Active
74
114
caBundle := apiService .Spec .CABundle
75
115
ca , err := certs .PEMToCert (caBundle )
76
116
if err != nil {
77
117
logger .Warnf ("could not convert APIService CA bundle to x509 cert" )
78
- return err
118
+ errs = append (errs , err )
119
+ continue
79
120
}
80
121
if ! certs .Active (ca ) {
81
122
logger .Warnf ("CA cert not active" )
82
- return fmt .Errorf ("CA cert not active" )
123
+ errs = append (errs , fmt .Errorf ("CA cert not active" ))
124
+ continue
83
125
}
84
126
85
127
// Check if serving cert is active
86
128
secretName := apiServiceName + "-cert"
87
129
secret , err := a .lister .CoreV1 ().SecretLister ().Secrets (csv .GetNamespace ()).Get (secretName )
88
130
if err != nil {
89
131
logger .WithField ("secret" , secretName ).Warnf ("could not retrieve generated Secret" )
90
- return err
132
+ errs = append (errs , err )
133
+ continue
91
134
}
92
135
cert , err := certs .PEMToCert (secret .Data ["tls.crt" ])
93
136
if err != nil {
94
137
logger .Warnf ("could not convert serving cert to x509 cert" )
95
- return err
138
+ errs = append (errs , err )
139
+ continue
96
140
}
97
141
if ! certs .Active (cert ) {
98
142
logger .Warnf ("serving cert not active" )
99
- return fmt .Errorf ("serving cert not active" )
143
+ errs = append (errs , fmt .Errorf ("serving cert not active" ))
144
+ continue
100
145
}
101
146
102
147
// Check if CA hash matches expected
103
148
caHash := hashFunc (caBundle )
104
149
if hash , ok := secret .GetAnnotations ()[OLMCAHashAnnotationKey ]; ! ok || hash != caHash {
105
150
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 )
151
+ errs = append (errs , fmt .Errorf ("secret %s CA cert hash does not match expected" , secretName ))
152
+ continue
107
153
}
108
154
109
155
// Check if serving cert is trusted by the CA
@@ -113,19 +159,22 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
113
159
}
114
160
for _ , host := range hosts {
115
161
if err := certs .VerifyCert (ca , cert , host ); err != nil {
116
- return fmt .Errorf ("could not verify cert: %s" , err .Error ())
162
+ errs = append (errs , fmt .Errorf ("could not verify cert: %s" , err .Error ()))
163
+ continue
117
164
}
118
165
}
119
166
120
167
// Ensure the existing Deployment has a matching CA hash annotation
121
168
deployment , err := a .lister .AppsV1 ().DeploymentLister ().Deployments (csv .GetNamespace ()).Get (desc .DeploymentName )
122
169
if k8serrors .IsNotFound (err ) || err != nil {
123
170
logger .WithField ("deployment" , desc .DeploymentName ).Warnf ("expected Deployment could not be retrieved" )
124
- return err
171
+ errs = append (errs , err )
172
+ continue
125
173
}
126
174
if hash , ok := deployment .Spec .Template .GetAnnotations ()[OLMCAHashAnnotationKey ]; ! ok || hash != caHash {
127
175
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 )
176
+ errs = append (errs , fmt .Errorf ("Deployment %s CA cert hash does not match expected" , desc .DeploymentName ))
177
+ continue
129
178
}
130
179
131
180
// Ensure the Deployment's ServiceAccount exists
@@ -136,7 +185,8 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
136
185
serviceAccount , err := a .lister .CoreV1 ().ServiceAccountLister ().ServiceAccounts (deployment .GetNamespace ()).Get (serviceAccountName )
137
186
if err != nil {
138
187
logger .WithField ("serviceaccount" , serviceAccountName ).Warnf ("could not retrieve ServiceAccount" )
139
- return err
188
+ errs = append (errs , err )
189
+ continue
140
190
}
141
191
142
192
// Ensure RBAC permissions for the APIService are correct
@@ -158,15 +208,17 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
158
208
authReaderRole , err := a .lister .RbacV1 ().RoleLister ().Roles ("kube-system" ).Get ("extension-apiserver-authentication-reader" )
159
209
if err != nil {
160
210
logger .Warnf ("could not retrieve Role extension-apiserver-authentication-reader" )
161
- return err
211
+ errs = append (errs , err )
212
+ continue
162
213
}
163
214
rulesMap ["kube-system" ] = append (rulesMap ["kube-system" ], authReaderRole .Rules ... )
164
215
165
216
// system:auth-delegator
166
217
authDelegatorClusterRole , err := a .lister .RbacV1 ().ClusterRoleLister ().Get ("system:auth-delegator" )
167
218
if err != nil {
168
219
logger .Warnf ("could not retrieve ClusterRole system:auth-delegator" )
169
- return err
220
+ errs = append (errs , err )
221
+ continue
170
222
}
171
223
rulesMap [metav1 .NamespaceAll ] = append (rulesMap [metav1 .NamespaceAll ], authDelegatorClusterRole .Rules ... )
172
224
@@ -175,17 +227,19 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
175
227
satisfied , err := ruleChecker .RuleSatisfied (serviceAccount , namespace , rule )
176
228
if err != nil {
177
229
logger .WithField ("rule" , fmt .Sprintf ("%+v" , rule )).Warnf ("error checking Rule" )
178
- return err
230
+ errs = append (errs , err )
231
+ continue
179
232
}
180
233
if ! satisfied {
181
234
logger .WithField ("rule" , fmt .Sprintf ("%+v" , rule )).Warnf ("Rule not satisfied" )
182
- return fmt .Errorf ("Rule %+v not satisfied" , rule )
235
+ errs = append (errs , fmt .Errorf ("Rule %+v not satisfied" , rule ))
236
+ continue
183
237
}
184
238
}
185
239
}
186
240
}
187
241
188
- return nil
242
+ return errs
189
243
}
190
244
191
245
func (a * Operator ) isAPIServiceAvailable (apiService * apiregistrationv1.APIService ) bool {
@@ -639,8 +693,14 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
639
693
}
640
694
apiService .SetName (apiServiceName )
641
695
} else {
696
+ owners := []ownerutil.Owner {csv }
697
+ // Get replacing CSV
698
+ replaces , err := a .lister .OperatorsV1alpha1 ().ClusterServiceVersionLister ().ClusterServiceVersions (csv .GetNamespace ()).Get (csv .Spec .Replaces )
699
+ if err == nil {
700
+ owners = append (owners , replaces )
701
+ }
642
702
// check if the APIService is adoptable
643
- if ! ownerutil .AdoptableLabels ( csv , apiService . GetLabels () ) {
703
+ if ! ownerutil .OwnersIntersect ( owners , apiService ) {
644
704
return nil , fmt .Errorf ("pre-existing APIService %s is not adoptable" , apiServiceName )
645
705
}
646
706
}
0 commit comments