Skip to content

Commit ba40d6d

Browse files
committed
quick and dirty
1 parent fd756db commit ba40d6d

File tree

2 files changed

+212
-0
lines changed

2 files changed

+212
-0
lines changed

cmd/olm/manager.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,19 @@ func Manager(ctx context.Context, debug bool) (ctrl.Manager, error) {
9191
return nil, err
9292
}
9393

94+
olmConfigReconciler, err := operators.NewOLMConfigReconcilerReconciler(
95+
mgr.GetClient(),
96+
ctrl.Log.WithName("controllers").WithName("olmconfig"),
97+
mgr.GetScheme(),
98+
)
99+
if err != nil {
100+
return nil, err
101+
}
102+
103+
if err = olmConfigReconciler.SetupWithManager(mgr); err != nil {
104+
return nil, err
105+
}
106+
94107
if feature.Gate.Enabled(feature.OperatorLifecycleManagerV1) {
95108
// Setup a new controller to reconcile Operators
96109
operatorReconciler, err := operators.NewOperatorReconciler(
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
package operators
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strconv"
7+
8+
"github.com/go-logr/logr"
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
"k8s.io/apimachinery/pkg/labels"
11+
"k8s.io/apimachinery/pkg/runtime"
12+
"k8s.io/apimachinery/pkg/selection"
13+
ctrl "sigs.k8s.io/controller-runtime"
14+
"sigs.k8s.io/controller-runtime/pkg/builder"
15+
"sigs.k8s.io/controller-runtime/pkg/client"
16+
"sigs.k8s.io/controller-runtime/pkg/event"
17+
"sigs.k8s.io/controller-runtime/pkg/predicate"
18+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
19+
20+
operatorsv1 "github.com/operator-framework/api/pkg/operators/v1"
21+
"github.com/operator-framework/api/pkg/operators/v1alpha1"
22+
operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
23+
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm"
24+
)
25+
26+
// OLMConfigReconciler reconciles an OperatorCondition object.
27+
type OLMConfigReconciler struct {
28+
client.Client
29+
log logr.Logger
30+
}
31+
32+
// +kubebuilder:rbac:groups=operators.coreos.com,resources=olmconfig,verbs=get;list;update;patch;delete
33+
// +kubebuilder:rbac:groups=operators.coreos.com,resources=olmconfig/status,verbs=update;patch
34+
35+
// SetupWithManager adds the OLMConfigReconciler reconciler to the given controller manager.
36+
func (r *OLMConfigReconciler) SetupWithManager(mgr ctrl.Manager) error {
37+
p := predicate.Funcs{
38+
CreateFunc: func(e event.CreateEvent) bool {
39+
if e.Object.GetName() != "cluster" {
40+
return false
41+
}
42+
return true
43+
},
44+
DeleteFunc: func(e event.DeleteEvent) bool {
45+
if e.Object.GetName() != "cluster" {
46+
return false
47+
}
48+
return true
49+
},
50+
UpdateFunc: func(e event.UpdateEvent) bool {
51+
if e.ObjectOld.GetName() != "cluster" {
52+
return false
53+
}
54+
return true
55+
},
56+
GenericFunc: func(e event.GenericEvent) bool {
57+
if e.Object.GetName() != "cluster" {
58+
return false
59+
}
60+
return true
61+
},
62+
}
63+
64+
return ctrl.NewControllerManagedBy(mgr).
65+
For(&operatorsv1.OLMConfig{}, builder.WithPredicates(p)).
66+
Complete(r)
67+
}
68+
69+
// NewOLMConfigReconcilerReconciler constructs and returns an OLMConfigReconciler.
70+
// As a side effect, the given scheme has operator discovery types added to it.
71+
func NewOLMConfigReconcilerReconciler(cli client.Client, log logr.Logger, scheme *runtime.Scheme) (*OLMConfigReconciler, error) {
72+
// Add watched types to scheme.
73+
if err := AddToScheme(scheme); err != nil {
74+
return nil, err
75+
}
76+
77+
return &OLMConfigReconciler{
78+
Client: cli,
79+
log: log,
80+
}, nil
81+
}
82+
83+
// Implement reconcile.Reconciler so the controller can reconcile objects
84+
var _ reconcile.Reconciler = &OLMConfigReconciler{}
85+
86+
func (r *OLMConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
87+
// Set up a convenient log object so we don't have to type request over and over again
88+
log := r.log.WithValues("request", req)
89+
log.V(2).Info("reconciling olmconfig %s/%s", req.Namespace, req.Name)
90+
91+
olmConfig := &operatorsv1.OLMConfig{}
92+
err := r.Client.Get(context.TODO(), req.NamespacedName, olmConfig)
93+
if err != nil {
94+
log.V(1).Error(err, "Unable to find olmConfig %s", req.Name)
95+
return ctrl.Result{}, err
96+
}
97+
98+
// Update the condition spec if it has changed
99+
needsUpdate := false
100+
if ok := updateOrAddCondition(olmConfig, enableCopiedCSVsCondition(olmConfig)); ok {
101+
r.log.Info("Copying CSVs status has changed, updating status")
102+
needsUpdate = true
103+
104+
// ping all cluster scoped csvs.
105+
operatorGroups := &operatorsv1.OperatorGroupList{}
106+
if err := r.Client.List(ctx, operatorGroups, &client.ListOptions{Namespace: ""}); err != nil {
107+
return ctrl.Result{}, err
108+
}
109+
110+
for _, operatorGroup := range operatorGroups.Items {
111+
namespaceSet := olm.NewNamespaceSet(operatorGroup.Status.Namespaces)
112+
if !namespaceSet.IsAllNamespaces() {
113+
r.log.Info(fmt.Sprintf("operatorGroup %s/%s is not allNamespace mode, skipping", operatorGroup.GetNamespace(), operatorGroup.GetName()))
114+
continue
115+
}
116+
r.log.Info(fmt.Sprintf("operatorGroup %s/%s is allNamespace mode, processing", operatorGroup.GetNamespace(), operatorGroup.GetName()))
117+
118+
requirement, err := labels.NewRequirement(v1alpha1.CopiedLabelKey, selection.DoesNotExist, []string{})
119+
if err != nil {
120+
return ctrl.Result{}, err
121+
}
122+
123+
labels := labels.NewSelector().Add(*requirement)
124+
125+
csvs := &operatorsv1alpha1.ClusterServiceVersionList{}
126+
err = r.Client.List(ctx, csvs, &client.ListOptions{
127+
LabelSelector: labels,
128+
Namespace: operatorGroup.GetNamespace(),
129+
})
130+
if err != nil {
131+
return ctrl.Result{}, err
132+
}
133+
134+
for _, csv := range csvs.Items {
135+
if csv.GetAnnotations() == nil {
136+
csv.Annotations = map[string]string{}
137+
}
138+
copiedAnnoationKey := "olm.operators.io/enableCopiedCSVs"
139+
if csv.GetAnnotations()[copiedAnnoationKey] == strconv.FormatBool(*olmConfig.Spec.Features.EnableCopiedCSVs) {
140+
continue
141+
}
142+
csv.Annotations[copiedAnnoationKey] = strconv.FormatBool(*olmConfig.Spec.Features.EnableCopiedCSVs)
143+
if err := r.Client.Update(ctx, &csv); err != nil {
144+
return ctrl.Result{}, err
145+
}
146+
}
147+
148+
}
149+
150+
}
151+
152+
if needsUpdate {
153+
if err := r.Client.Status().Update(ctx, olmConfig); err != nil {
154+
return ctrl.Result{Requeue: true}, err
155+
}
156+
}
157+
158+
r.log.Info("No update needed")
159+
return ctrl.Result{}, nil
160+
}
161+
162+
func enableCopiedCSVsCondition(olmConfig *operatorsv1.OLMConfig) metav1.Condition {
163+
condition := metav1.Condition{
164+
Reason: "EnableCopiedCSVs",
165+
LastTransitionTime: metav1.Now(),
166+
ObservedGeneration: olmConfig.GetGeneration(),
167+
Type: "ready",
168+
}
169+
170+
if olmConfig.CopiedCSVsAreEnabled() {
171+
condition.Message = "OLM will create Copied CSVs for cluster scoped operators"
172+
condition.Status = metav1.ConditionTrue
173+
} else {
174+
condition.Message = "OLM will not create Copied CSVs for cluster scoped operators"
175+
condition.Status = metav1.ConditionFalse
176+
}
177+
return condition
178+
}
179+
180+
func conditionsAreEqual(a, b metav1.Condition) bool {
181+
return a.Reason == b.Reason &&
182+
a.ObservedGeneration == b.ObservedGeneration &&
183+
a.Message == b.Message &&
184+
a.Status == b.Status
185+
}
186+
187+
func updateOrAddCondition(olmConfig *operatorsv1.OLMConfig, condition metav1.Condition) bool {
188+
for i, c := range olmConfig.Status.Conditions {
189+
if c.Reason == condition.Reason {
190+
if conditionsAreEqual(c, condition) {
191+
return false
192+
}
193+
olmConfig.Status.Conditions[i] = condition
194+
return true
195+
}
196+
}
197+
olmConfig.Status.Conditions = append(olmConfig.Status.Conditions, condition)
198+
return true
199+
}

0 commit comments

Comments
 (0)