Skip to content

Commit 176bf33

Browse files
Merge pull request #758 from njhale/fix-conflict-detection
fix(csv): properly detect apiservice and crd conflicts
2 parents 840d806 + c5a4d5f commit 176bf33

File tree

9 files changed

+206
-170
lines changed

9 files changed

+206
-170
lines changed

go.sum

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA
112112
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
113113
github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f h1:ShTPMJQes6tubcjzGMODIVG5hlrCeImaBnZzKF2N8SM=
114114
github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
115-
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=
115+
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:BWIsLfhgKhV5g/oF34aRjniBHLTZe5DNekSjbAjIS6c=
116116
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
117117
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
118118
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
@@ -132,7 +132,6 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH
132132
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
133133
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
134134
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
135-
github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE=
136135
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
137136
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
138137
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -322,5 +321,5 @@ k8s.io/kube-openapi v0.0.0-20181031203759-72693cb1fadd h1:ggv/Vfza0i5xuhUZyYyxcc
322321
k8s.io/kube-openapi v0.0.0-20181031203759-72693cb1fadd/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
323322
k8s.io/kubernetes v1.11.7-beta.0.0.20181219023948-b875d52ea96d/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
324323
k8s.io/kubernetes v1.11.8-beta.0.0.20190124204751-3a10094374f2/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
325-
k8s.io/kubernetes v1.11.9-beta.0.0.20190311041124-ede55fd57298 h1:CMsSK4yqJD0IfftutHd0XjYoJTsrtx983MpdKFd8c74=
324+
k8s.io/kubernetes v1.11.9-beta.0.0.20190311041124-ede55fd57298 h1:vVWtHOzTn3+uHbF0nZUlTrwFfbxPn2ZM3chxhAIUzg0=
326325
k8s.io/kubernetes v1.11.9-beta.0.0.20190311041124-ede55fd57298/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@ var uncopiableReasons = map[ConditionReason]struct{}{
3030
CSVReasonCannotModifyStaticOperatorGroupProvidedAPIs: {},
3131
}
3232

33+
// SetPhaseWithEventIfChanged emits a Kubernetes event with details of a phase change and sets the current phase if phase, reason, or message would changed
34+
func (c *ClusterServiceVersion) SetPhaseWithEventIfChanged(phase ClusterServiceVersionPhase, reason ConditionReason, message string, now metav1.Time, recorder record.EventRecorder) {
35+
if c.Status.Phase == phase && c.Status.Reason == reason && c.Status.Message == message {
36+
return
37+
}
38+
39+
c.SetPhaseWithEvent(phase, reason, message, now, recorder)
40+
}
41+
42+
// SetPhaseWithEvent generates a Kubernetes event with details about the phase change and sets the current phase
3343
func (c *ClusterServiceVersion) SetPhaseWithEvent(phase ClusterServiceVersionPhase, reason ConditionReason, message string, now metav1.Time, recorder record.EventRecorder) {
3444
var eventtype string
3545
if phase == CSVPhaseFailed {

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ type APIResourceReference struct {
113113
Version string `json:"version"`
114114
}
115115

116+
// GetName returns the name of an APIService as derived from its group and version.
117+
func (d APIServiceDescription) GetName() string {
118+
return fmt.Sprintf("%s.%s", d.Version, d.Group)
119+
}
120+
116121
// CustomResourceDefinitions declares all of the CRDs managed or required by
117122
// an operator being ran by ClusterServiceVersion.
118123
//

pkg/controller/operators/olm/apiservices.go

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
rbacv1 "k8s.io/api/rbac/v1"
1212
k8serrors "k8s.io/apimachinery/pkg/api/errors"
1313
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14+
utilerrors "k8s.io/apimachinery/pkg/util/errors"
1415
"k8s.io/apimachinery/pkg/util/intstr"
1516
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
1617

@@ -41,42 +42,45 @@ func (a *Operator) shouldRotateCerts(csv *v1alpha1.ClusterServiceVersion) bool {
4142
return false
4243
}
4344

44-
// apiServiceResourceErrorsActionable returns true if OLM can do something about any one
45+
// apiServiceResourceErrorActionable returns true if OLM can do something about any one
4546
// of the apiService errors in errs; otherwise returns false
4647
//
4748
// This method can be used to determine if a CSV in a failed state due to APIService
4849
// 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-
}
50+
func (a *Operator) apiServiceResourceErrorActionable(err error) bool {
51+
filtered := utilerrors.FilterOut(err, func(e error) bool {
52+
_, unadoptable := e.(olmerrors.UnadoptableError)
53+
return !unadoptable
54+
})
55+
actionable := filtered == nil
5656

57-
return true
57+
return actionable
5858
}
5959

6060
// checkAPIServiceResources checks if all expected generated resources for the given APIService exist
61-
func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion, hashFunc certs.PEMHash) []error {
61+
func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion, hashFunc certs.PEMHash) error {
62+
logger := log.WithFields(log.Fields{
63+
"csv": csv.GetName(),
64+
"namespace": csv.GetNamespace(),
65+
})
66+
6267
errs := []error{}
6368
owners := []ownerutil.Owner{csv}
69+
6470
// 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
71+
replacing, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(csv.GetNamespace()).Get(csv.Spec.Replaces)
72+
if err != nil && !k8serrors.IsNotFound(err) {
73+
logger.WithError(err).Warn("could not get replacement csv")
74+
return err
7075
}
71-
if replacement != nil {
72-
owners = append(owners, replacement)
76+
if replacing != nil {
77+
owners = append(owners, replacing)
7378
}
79+
7480
ruleChecker := install.NewCSVRuleChecker(a.lister.RbacV1().RoleLister(), a.lister.RbacV1().RoleBindingLister(), a.lister.RbacV1().ClusterRoleLister(), a.lister.RbacV1().ClusterRoleBindingLister(), csv)
7581
for _, desc := range csv.GetOwnedAPIServiceDescriptions() {
76-
apiServiceName := fmt.Sprintf("%s.%s", desc.Version, desc.Group)
77-
logger := log.WithFields(log.Fields{
78-
"csv": csv.GetName(),
79-
"namespace": csv.GetNamespace(),
82+
apiServiceName := desc.GetName()
83+
logger := logger.WithFields(log.Fields{
8084
"apiservice": apiServiceName,
8185
})
8286

@@ -88,11 +92,11 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
8892
}
8993

9094
// Check if the APIService is adoptable
91-
if !ownerutil.OwnersIntersect(owners, apiService) {
95+
if !ownerutil.AdoptableLabels(apiService.GetLabels(), true, owners...) {
9296
err := olmerrors.NewUnadoptableError("", apiServiceName)
9397
logger.WithError(err).Warn("found unadoptable apiservice")
9498
errs = append(errs, err)
95-
return errs
99+
return utilerrors.NewAggregate(errs)
96100
}
97101

98102
serviceName := APIServiceNameToServiceName(apiServiceName)
@@ -239,7 +243,7 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
239243
}
240244
}
241245

242-
return errs
246+
return utilerrors.NewAggregate(errs)
243247
}
244248

245249
func (a *Operator) isAPIServiceAvailable(apiService *apiregistrationv1.APIService) bool {
@@ -251,10 +255,9 @@ func (a *Operator) isAPIServiceAvailable(apiService *apiregistrationv1.APIServic
251255
return false
252256
}
253257

254-
func (a *Operator) areAPIServicesAvailable(descs []v1alpha1.APIServiceDescription) (bool, error) {
255-
for _, desc := range descs {
256-
apiServiceName := fmt.Sprintf("%s.%s", desc.Version, desc.Group)
257-
apiService, err := a.lister.APIRegistrationV1().APIServiceLister().Get(apiServiceName)
258+
func (a *Operator) areAPIServicesAvailable(csv *v1alpha1.ClusterServiceVersion) (bool, error) {
259+
for _, desc := range csv.Spec.APIServiceDefinitions.Owned {
260+
apiService, err := a.lister.APIRegistrationV1().APIServiceLister().Get(desc.GetName())
258261
if k8serrors.IsNotFound(err) {
259262
return false, nil
260263
}
@@ -550,7 +553,7 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
550553
existingAuthDelegatorClusterRoleBinding, err := a.lister.RbacV1().ClusterRoleBindingLister().Get(authDelegatorClusterRoleBinding.GetName())
551554
if err == nil {
552555
// Check if the only owners are this CSV or in this CSV's replacement chain.
553-
if ownerutil.AdoptableLabels(csv, existingAuthDelegatorClusterRoleBinding.GetLabels()) {
556+
if ownerutil.AdoptableLabels(existingAuthDelegatorClusterRoleBinding.GetLabels(), true, csv) {
554557
ownerutil.AddOwnerLabels(authDelegatorClusterRoleBinding, csv)
555558
}
556559

@@ -593,7 +596,7 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
593596
existingAuthReaderRoleBinding, err := a.lister.RbacV1().RoleBindingLister().RoleBindings("kube-system").Get(authReaderRoleBinding.GetName())
594597
if err == nil {
595598
// Check if the only owners are this CSV or in this CSV's replacement chain.
596-
if ownerutil.AdoptableLabels(csv, existingAuthReaderRoleBinding.GetLabels()) {
599+
if ownerutil.AdoptableLabels(existingAuthReaderRoleBinding.GetLabels(), true, csv) {
597600
ownerutil.AddOwnerLabels(authReaderRoleBinding, csv)
598601
}
599602
// Attempt an update.
@@ -694,13 +697,15 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
694697
apiService.SetName(apiServiceName)
695698
} else {
696699
owners := []ownerutil.Owner{csv}
700+
697701
// Get replacing CSV
698702
replaces, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(csv.GetNamespace()).Get(csv.Spec.Replaces)
699703
if err == nil {
700704
owners = append(owners, replaces)
701705
}
706+
702707
// check if the APIService is adoptable
703-
if !ownerutil.OwnersIntersect(owners, apiService) {
708+
if !ownerutil.AdoptableLabels(apiService.GetLabels(), true, owners...) {
704709
return nil, fmt.Errorf("pre-existing APIService %s is not adoptable", apiServiceName)
705710
}
706711
}

0 commit comments

Comments
 (0)