@@ -7,11 +7,13 @@ import (
77 "time"
88
99 "github.com/sirupsen/logrus"
10+ appsv1 "k8s.io/api/apps/v1"
1011 corev1 "k8s.io/api/core/v1"
1112 extv1beta1 "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions"
1213 k8serrors "k8s.io/apimachinery/pkg/api/errors"
1314 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1415 "k8s.io/apimachinery/pkg/labels"
16+ utilerrors "k8s.io/apimachinery/pkg/util/errors"
1517 utilruntime "k8s.io/apimachinery/pkg/util/runtime"
1618 "k8s.io/client-go/informers"
1719 "k8s.io/client-go/tools/cache"
@@ -305,7 +307,7 @@ func (a *Operator) syncObject(obj interface{}) (syncError error) {
305307 logger := a .Log .WithFields (logrus.Fields {
306308 "name" : metaObj .GetName (),
307309 "namespace" : metaObj .GetNamespace (),
308- "sel" : metaObj .GetSelfLink (),
310+ "self" : metaObj .GetSelfLink (),
309311 })
310312
311313 // Requeue all owner CSVs
@@ -572,7 +574,7 @@ func (a *Operator) syncCopyCSV(obj interface{}) (syncError error) {
572574 return
573575 }
574576
575- operatorGroup := a .operatorGroupForActiveCSV (logger , clusterServiceVersion )
577+ operatorGroup := a .operatorGroupFromAnnotations (logger , clusterServiceVersion )
576578 if operatorGroup == nil {
577579 logger .WithField ("reason" , "no operatorgroup found for active CSV" ).Debug ("skipping CSV resource copy to target namespaces" )
578580 return
@@ -607,8 +609,8 @@ func (a *Operator) syncCopyCSV(obj interface{}) (syncError error) {
607609 return
608610}
609611
610- // operatorGroupForCSV returns the OperatorGroup for the CSV only if the CSV is active one in the group
611- func (a * Operator ) operatorGroupForActiveCSV (logger * logrus.Entry , csv * v1alpha1.ClusterServiceVersion ) * v1alpha2.OperatorGroup {
612+ // operatorGroupFromAnnotations returns the OperatorGroup for the CSV only if the CSV is active one in the group
613+ func (a * Operator ) operatorGroupFromAnnotations (logger * logrus.Entry , csv * v1alpha1.ClusterServiceVersion ) * v1alpha2.OperatorGroup {
612614 annotations := csv .GetAnnotations ()
613615
614616 // Not part of a group yet
@@ -640,23 +642,63 @@ func (a *Operator) operatorGroupForActiveCSV(logger *logrus.Entry, csv *v1alpha1
640642 return nil
641643 }
642644
643- // targets, ok := annotations[v1alpha2.OperatorGroupTargetsAnnotationKey]
644- //
645- // // No target annotation
646- // if !ok {
647- // logger.Info("no olm.targetNamespaces annotation")
648- // return nil
649- // }
650- //
651- // // Target namespaces don't match
652- // if targets != strings.Join(operatorGroup.Status.Namespaces, ",") {
653- // logger.Info("olm.targetNamespaces annotation doesn't match operatorgroup status")
654- // return nil
655- // }
645+ targets , ok := annotations [v1alpha2 .OperatorGroupTargetsAnnotationKey ]
646+
647+ // No target annotation
648+ if ! ok {
649+ logger .Info ("no olm.targetNamespaces annotation" )
650+ return nil
651+ }
652+
653+ // Target namespaces don't match
654+ if targets != strings .Join (operatorGroup .Status .Namespaces , "," ) {
655+ logger .Info ("olm.targetNamespaces annotation doesn't match operatorgroup status" )
656+ return nil
657+ }
656658
657659 return operatorGroup
658660}
659661
662+ func (a * Operator ) operatorGroupForCSV (csv * v1alpha1.ClusterServiceVersion , logger * logrus.Entry ) (* v1alpha2.OperatorGroup , error ) {
663+ now := timeNow ()
664+
665+ // Attempt to associate an OperatorGroup with the CSV.
666+ operatorGroups , err := a .client .OperatorsV1alpha2 ().OperatorGroups (csv .GetNamespace ()).List (metav1.ListOptions {})
667+ if err != nil {
668+ logger .Errorf ("error occurred while attempting to associate csv with operatorgroup" )
669+ return nil , err
670+ }
671+ var operatorGroup * v1alpha2.OperatorGroup
672+
673+ switch len (operatorGroups .Items ) {
674+ case 0 :
675+ err = fmt .Errorf ("csv in namespace with no operatorgroups" )
676+ logger .Warn (err )
677+ csv .SetPhaseWithEvent (v1alpha1 .CSVPhaseFailed , v1alpha1 .CSVReasonNoOperatorGroup , err .Error (), now , a .recorder )
678+ return nil , err
679+ case 1 :
680+ operatorGroup = & operatorGroups .Items [0 ]
681+ logger = logger .WithField ("opgroup" , operatorGroup .GetName ())
682+ if a .operatorGroupAnnotationsDiffer (& csv .ObjectMeta , operatorGroup ) {
683+ a .setOperatorGroupAnnotations (& csv .ObjectMeta , operatorGroup , true )
684+ if _ , err := a .client .OperatorsV1alpha1 ().ClusterServiceVersions (csv .GetNamespace ()).Update (csv ); err != nil {
685+ logger .WithError (err ).Warn ("error adding operatorgroup annotations" )
686+ return nil , err
687+ }
688+ return nil , nil
689+ }
690+ logger .Info ("csv in operatorgroup" )
691+ return operatorGroup , nil
692+ default :
693+ err = fmt .Errorf ("csv created in namespace with multiple operatorgroups, can't pick one automatically" )
694+ logger .WithError (err ).Warn ("csv failed to become an operatorgroup member" )
695+ if csv .Status .Reason != v1alpha1 .CSVReasonTooManyOperatorGroups {
696+ csv .SetPhaseWithEvent (v1alpha1 .CSVPhaseFailed , v1alpha1 .CSVReasonTooManyOperatorGroups , err .Error (), now , a .recorder )
697+ }
698+ return nil , err
699+ }
700+ }
701+
660702// transitionCSVState moves the CSV status state machine along based on the current value and the current cluster state.
661703func (a * Operator ) transitionCSVState (in v1alpha1.ClusterServiceVersion ) (out * v1alpha1.ClusterServiceVersion , syncError error ) {
662704 logger := a .Log .WithFields (logrus.Fields {
@@ -681,44 +723,18 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
681723 return
682724 }
683725
684- // Attempt to associate an OperatorGroup with the CSV.
685- operatorGroups , err := a .lister . OperatorsV1alpha2 (). OperatorGroupLister (). OperatorGroups ( out . GetNamespace ()). List ( labels . Everything () )
686- if err ! = nil {
687- logger . Errorf ( "error occurred while attempting to associate csv with operatorgroup" )
726+ // Verify CSV operatorgroup (and update annotations if needed)
727+ operatorGroup , err := a .operatorGroupForCSV ( out , logger )
728+ if operatorGroup = = nil {
729+ // when err is nil, we still want to exit, but we don't want to re-add the csv ratelimited to the queue
688730 syncError = err
689- }
690- var operatorGroup * v1alpha2.OperatorGroup
691-
692- switch len (operatorGroups ) {
693- case 0 :
694- syncError = fmt .Errorf ("csv in namespace with no operatorgroups" )
695- logger .Warn (syncError .Error ())
696- out .SetPhaseWithEvent (v1alpha1 .CSVPhaseFailed , v1alpha1 .CSVReasonNoOperatorGroup , syncError .Error (), now , a .recorder )
731+ logger .WithField ("err" , err ).Info ("operatorgroup incorrect" )
697732 return
698- case 1 :
699- operatorGroup = a .operatorGroupForActiveCSV (logger , out )
700- if operatorGroup == nil {
701- operatorGroup = operatorGroups [0 ]
702- logger = logger .WithField ("opgroup" , operatorGroup .GetName ())
703-
704- if a .operatorGroupAnnotationsDiffer (& out .ObjectMeta , operatorGroup ) {
705- a .setOperatorGroupAnnotations (& out .ObjectMeta , operatorGroup , true )
706- if _ , err := a .client .OperatorsV1alpha1 ().ClusterServiceVersions (out .GetNamespace ()).Update (out ); err != nil {
707- logger .WithError (err ).Warn ("error adding operatorgroup annotations" )
708- syncError = err
709- }
710- }
733+ }
711734
712- return
713- }
714- logger .Info ("csv in operatorgroup" )
715- default :
716- syncError = fmt .Errorf ("csv created in namespace with multiple operatorgroups, can't pick one automatically" )
717- logger .WithError (syncError ).Warn ("csv failed to become an operatorgroup member" )
718- if out .Status .Reason != v1alpha1 .CSVReasonTooManyOperatorGroups {
719- out .SetPhaseWithEvent (v1alpha1 .CSVPhaseFailed , v1alpha1 .CSVReasonTooManyOperatorGroups , syncError .Error (), now , a .recorder )
720- }
721- return
735+ logger .Info ("updated annotations to match current operatorgroup" )
736+ if err := a .ensureDeploymentAnnotations (logger , out ); err != nil {
737+ return nil , err
722738 }
723739
724740 modeSet , err := v1alpha1 .NewInstallModeSet (out .Spec .InstallModes )
@@ -1305,3 +1321,51 @@ func (a *Operator) cleanupCSVDeployments(logger *logrus.Entry, csv *v1alpha1.Clu
13051321 }
13061322 }
13071323}
1324+
1325+ func (a * Operator ) ensureDeploymentAnnotations (logger * logrus.Entry , csv * v1alpha1.ClusterServiceVersion ) error {
1326+ // Get csv operatorgroup annotations
1327+ annotations := a .copyOperatorGroupAnnotations (& csv .ObjectMeta )
1328+
1329+ // Extract the InstallStrategy for the deployment
1330+ strategy , err := a .resolver .UnmarshalStrategy (csv .Spec .InstallStrategy )
1331+ if err != nil {
1332+ logger .Warn ("could not parse install strategy while cleaning up CSV deployment" )
1333+ return nil
1334+ }
1335+
1336+ // Assume the strategy is for a deployment
1337+ strategyDetailsDeployment , ok := strategy .(* install.StrategyDetailsDeployment )
1338+ if ! ok {
1339+ logger .Warnf ("could not cast install strategy as type %T" , strategyDetailsDeployment )
1340+ return nil
1341+ }
1342+
1343+ var depNames []string
1344+ for _ , dep := range strategyDetailsDeployment .DeploymentSpecs {
1345+ depNames = append (depNames , dep .Name )
1346+ }
1347+ existingDeployments , err := a .lister .AppsV1 ().DeploymentLister ().Deployments (csv .GetNamespace ()).List (labels .Everything ())
1348+ if err != nil {
1349+ return err
1350+ }
1351+
1352+ // compare deployments to see if any need to be created/updated
1353+ existingMap := map [string ]* appsv1.Deployment {}
1354+ for _ , d := range existingDeployments {
1355+ existingMap [d .GetName ()] = d
1356+ }
1357+
1358+ updateErrs := []error {}
1359+ for _ , dep := range existingMap {
1360+ if dep .Spec .Template .Annotations == nil {
1361+ dep .Spec .Template .Annotations = map [string ]string {}
1362+ }
1363+ for key , value := range annotations {
1364+ dep .Spec .Template .Annotations [key ] = value
1365+ }
1366+ if _ , _ , err := a .OpClient .UpdateDeployment (dep ); err != nil {
1367+ updateErrs = append (updateErrs , err )
1368+ }
1369+ }
1370+ return utilerrors .NewAggregate (updateErrs )
1371+ }
0 commit comments