Skip to content

Commit 9942678

Browse files
Merge pull request #592 from sector2000/add-configmap-ownership
Set Patterns Operator config ConfigMap ownership to Pattern CR
2 parents a7b70b0 + cfec363 commit 9942678

10 files changed

Lines changed: 145 additions & 263 deletions

cmd/main.go

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,10 @@ import (
2929
// to ensure that exec-entrypoint and run can make use of them.
3030
_ "k8s.io/client-go/plugin/pkg/client/auth"
3131

32-
"k8s.io/apimachinery/pkg/api/errors"
3332
k8sruntime "k8s.io/apimachinery/pkg/runtime"
3433
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
3534
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
3635
ctrl "sigs.k8s.io/controller-runtime"
37-
crclient "sigs.k8s.io/controller-runtime/pkg/client"
3836
"sigs.k8s.io/controller-runtime/pkg/healthz"
3937
"sigs.k8s.io/controller-runtime/pkg/log/zap"
4038
"sigs.k8s.io/controller-runtime/pkg/manager"
@@ -46,9 +44,6 @@ import (
4644
"github.com/hybrid-cloud-patterns/patterns-operator/version"
4745
consolev1 "github.com/openshift/api/console/v1"
4846
operatorv1 "github.com/openshift/api/operator/v1"
49-
corev1 "k8s.io/api/core/v1"
50-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
51-
"k8s.io/client-go/kubernetes"
5247
//+kubebuilder:scaffold:imports
5348
)
5449

@@ -85,12 +80,6 @@ func main() {
8580

8681
setupLog.Info("detected operator namespace", "namespace", controllers.DetectOperatorNamespace())
8782

88-
// Create initial config map for gitops
89-
err := createPatternsOperatorConfigMap()
90-
if err != nil {
91-
setupLog.Error(err, "unable to create config map")
92-
}
93-
9483
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
9584
Scheme: scheme,
9685
HealthProbeBindAddress: probeAddr,
@@ -120,7 +109,7 @@ func main() {
120109
setupLog.Error(err, "unable to add console plugin runnable")
121110
}
122111

123-
analyticsEnabled := areAnalyticsEnabled(mgr.GetAPIReader())
112+
analyticsEnabled := strings.ToLower(os.Getenv("ANALYTICS")) != "false"
124113
setupLog.Info("analytics enabled", "enabled", analyticsEnabled)
125114
if err = (&controllers.PatternReconciler{
126115
Client: mgr.GetClient(),
@@ -162,44 +151,6 @@ func printVersion() {
162151
setupLog.Info(fmt.Sprintf("Build Date: %s", version.BuildDate))
163152
}
164153

165-
// Creates the patterns operator configmap
166-
// This will include configuration parameters that
167-
// will allow operator configuration
168-
func createPatternsOperatorConfigMap() error {
169-
config, err := ctrl.GetConfig()
170-
if err != nil {
171-
return fmt.Errorf("failed to get config: %s", err)
172-
}
173-
clientset, err := kubernetes.NewForConfig(config)
174-
if err != nil {
175-
return fmt.Errorf("failed to call NewForConfig: %s", err)
176-
}
177-
178-
configMap := corev1.ConfigMap{
179-
TypeMeta: metav1.TypeMeta{
180-
Kind: "ConfigMap",
181-
APIVersion: "v1",
182-
},
183-
ObjectMeta: metav1.ObjectMeta{
184-
Name: controllers.OperatorConfigMap,
185-
Namespace: controllers.DetectOperatorNamespace(),
186-
},
187-
}
188-
189-
_, err = clientset.CoreV1().ConfigMaps(controllers.DetectOperatorNamespace()).Get(context.Background(), controllers.OperatorConfigMap, metav1.GetOptions{})
190-
if err != nil && errors.IsNotFound(err) {
191-
// if the configmap does not exist we create an empty one
192-
_, err = clientset.CoreV1().ConfigMaps(controllers.DetectOperatorNamespace()).Create(context.Background(), &configMap, metav1.CreateOptions{})
193-
if err != nil {
194-
return err
195-
}
196-
} else {
197-
// if we had an error that is not IsNotFound we need to return it
198-
return err
199-
}
200-
return nil
201-
}
202-
203154
func registerComponentOrExit(mgr manager.Manager, f func(*k8sruntime.Scheme) error) {
204155
// Setup Scheme for all resources
205156
if err := f(mgr.GetScheme()); err != nil {
@@ -208,22 +159,3 @@ func registerComponentOrExit(mgr manager.Manager, f func(*k8sruntime.Scheme) err
208159
}
209160
setupLog.Info(fmt.Sprintf("Component registered: %v", reflect.ValueOf(f)))
210161
}
211-
212-
// areAnalyticsEnabled determines whether analytics are enabled.
213-
// Precedence: Operator ConfigMap key "analytics.enabled" (true/false) > ENV ANALYTICS (false means disabled)
214-
func areAnalyticsEnabled(reader crclient.Reader) bool {
215-
enabled := strings.ToLower(os.Getenv("ANALYTICS")) != "false"
216-
217-
var cm corev1.ConfigMap
218-
err := reader.Get(context.Background(), crclient.ObjectKey{Namespace: controllers.DetectOperatorNamespace(), Name: controllers.OperatorConfigMap}, &cm)
219-
if err != nil {
220-
setupLog.Error(err, "error reading operator configmap for analytics setting")
221-
return enabled
222-
}
223-
224-
if v, ok := cm.Data["analytics.enabled"]; ok {
225-
return strings.EqualFold(v, "true")
226-
}
227-
228-
return enabled
229-
}

cmd/main_test.go

Lines changed: 0 additions & 74 deletions
This file was deleted.

internal/controller/argo.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func newArgoCD(name, namespace string, patternsOperatorConfig PatternsOperatorCo
6262
"g, cluster-admins, role:admin",
6363
"g, admin, role:admin",
6464
}
65-
for argoAdmin := range strings.SplitSeq(patternsOperatorConfig.getValueWithDefault("gitops.additionalArgoAdmins"), ",") {
65+
for argoAdmin := range strings.SplitSeq(patternsOperatorConfig.getStringValue("gitops.additionalArgoAdmins"), ",") {
6666
argoAdmin = strings.TrimSpace(argoAdmin)
6767
if argoAdmin != "" {
6868
argoPolicies = append(argoPolicies, "g, "+argoAdmin+", role:admin")
@@ -160,7 +160,7 @@ health_status.message = "An install plan for a subscription is pending installat
160160
return health_status`,
161161
},
162162
}
163-
if strings.EqualFold(patternsOperatorConfig.getValueWithDefault("gitops.applicationHealthCheckEnabled"), "true") {
163+
if patternsOperatorConfig.getBoolValue("gitops.applicationHealthCheckEnabled") {
164164
// As of ArgoCD 1.8 the Application health check was dropped (see https://github.com/argoproj/argo-cd/issues/3781),
165165
// but in app-of-apps pattern this is needed in order to implement children apps dependencies via sync-waves
166166
resourceHealthChecks = append(resourceHealthChecks, argooperator.ResourceHealthCheck{
@@ -978,9 +978,9 @@ func newArgoGiteaApplication(p *api.Pattern, patternsOperatorConfig PatternsOper
978978
},
979979
Project: "default",
980980
Source: &argoapi.ApplicationSource{
981-
RepoURL: patternsOperatorConfig.getValueWithDefault("gitea.helmRepoUrl"),
982-
TargetRevision: patternsOperatorConfig.getValueWithDefault("gitea.chartVersion"),
983-
Chart: patternsOperatorConfig.getValueWithDefault("gitea.chartName"),
981+
RepoURL: patternsOperatorConfig.getStringValue("gitea.helmRepoUrl"),
982+
TargetRevision: patternsOperatorConfig.getStringValue("gitea.chartVersion"),
983+
Chart: patternsOperatorConfig.getStringValue("gitea.chartName"),
984984
Helm: &argoapi.ApplicationSourceHelm{
985985
Parameters: parameters,
986986
},

internal/controller/defaults.go

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -85,30 +85,3 @@ const (
8585

8686
// Experimental Capabilities that can be enabled
8787
// Currently none
88-
89-
var DefaultPatternsOperatorConfig = map[string]string{
90-
"gitops.catalogSource": GitOpsDefaultCatalogSource,
91-
"gitops.channel": GitOpsDefaultChannel,
92-
"gitops.sourceNamespace": GitOpsDefaultCatalogSourceNamespace,
93-
"gitops.installApprovalPlan": GitOpsDefaultApprovalPlan,
94-
"gitops.csv": GitOpsDefaultCSV,
95-
"gitops.additionalArgoAdmins": "",
96-
"gitops.applicationHealthCheckEnabled": "false",
97-
"gitea.chartName": GiteaChartName,
98-
"gitea.helmRepoUrl": GiteaHelmRepoUrl,
99-
"gitea.chartVersion": GiteaDefaultChartVersion,
100-
"analytics.enabled": "true",
101-
"catalog.image": "",
102-
}
103-
104-
type PatternsOperatorConfig map[string]string
105-
106-
func (g PatternsOperatorConfig) getValueWithDefault(k string) string {
107-
if v, present := g[k]; present {
108-
return v
109-
}
110-
if defaultValue, present := DefaultPatternsOperatorConfig[k]; present {
111-
return defaultValue
112-
}
113-
return ""
114-
}

internal/controller/pattern_controller.go

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"github.com/go-logr/logr"
3535
"github.com/hybrid-cloud-patterns/patterns-operator/internal/controller/console"
3636

37+
corev1 "k8s.io/api/core/v1"
3738
kerrors "k8s.io/apimachinery/pkg/api/errors"
3839
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3940
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -149,14 +150,21 @@ func (r *PatternReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
149150
return reconcile.Result{}, err
150151
}
151152

152-
patternsOperatorConfig := DefaultPatternsOperatorConfig
153+
var patternsOperatorConfig PatternsOperatorConfig
153154

154-
configCM, err := GetPatternsOperatorConfigMap()
155-
// If we hit an error that is not related to the configmap not existing bubble it up
156-
if err != nil && !kerrors.IsNotFound(err) {
155+
// We try to get the configuration ConfigMap. The method getPatternsOperatorConfigMap returns nil, nil if the ConfigMap doesn't exist
156+
configCM, err := r.getPatternsOperatorConfigMap()
157+
if err != nil {
157158
return r.actionPerformed(instance, "failed to get the configuration ConfigMap", err)
158159
}
159-
if configCM != nil {
160+
if configCM == nil { // If the ConfigMap doesn't exist, we create it
161+
if err = r.createPatternsOperatorConfigMap(instance); err != nil {
162+
return r.actionPerformed(instance, "failed to create the configuration ConfigMap", err)
163+
}
164+
} else { // If the ConfigMap exists, we set the ownership and get the configuration from Data
165+
if err = r.setPatternsOperatorConfigMapOwnership(configCM, instance); err != nil {
166+
return r.actionPerformed(instance, "failed to set ownership of configuration ConfigMap", err)
167+
}
160168
patternsOperatorConfig = configCM.Data
161169
}
162170

@@ -398,8 +406,8 @@ func (r *PatternReconciler) reconcileGitOpsSubscription(qualifiedInstance *api.P
398406
if err := controllerutil.RemoveOwnerReference(qualifiedInstance, currentSub, r.Scheme); err == nil {
399407
changed = true
400408
}
401-
operatorConfigMap, cmErr := GetPatternsOperatorConfigMap()
402-
if cmErr == nil {
409+
operatorConfigMap, cmErr := r.getPatternsOperatorConfigMap()
410+
if cmErr == nil && operatorConfigMap != nil {
403411
if err := controllerutil.RemoveOwnerReference(operatorConfigMap, currentSub, r.Scheme); err == nil {
404412
changed = true
405413
}
@@ -907,6 +915,7 @@ func (r *PatternReconciler) SetupWithManager(mgr ctrl.Manager) error {
907915
var ctrlErr error
908916
r.ctrl, ctrlErr = ctrl.NewControllerManagedBy(mgr).
909917
For(&api.Pattern{}).
918+
Owns(&corev1.ConfigMap{}).
910919
Build(r)
911920
return ctrlErr
912921
}
@@ -1325,6 +1334,53 @@ func (r *PatternReconciler) getLocalGit(p *api.Pattern) (string, error) {
13251334
return "", nil
13261335
}
13271336

1337+
func (r *PatternReconciler) createPatternsOperatorConfigMap(p *api.Pattern) error {
1338+
configMap := corev1.ConfigMap{
1339+
TypeMeta: metav1.TypeMeta{
1340+
Kind: "ConfigMap",
1341+
APIVersion: "v1",
1342+
},
1343+
ObjectMeta: metav1.ObjectMeta{
1344+
Name: OperatorConfigMap,
1345+
Namespace: DetectOperatorNamespace(),
1346+
},
1347+
}
1348+
if err := controllerutil.SetControllerReference(p, &configMap, r.Scheme); err != nil {
1349+
return err
1350+
}
1351+
if _, err := r.fullClient.CoreV1().ConfigMaps(DetectOperatorNamespace()).Create(context.Background(), &configMap, metav1.CreateOptions{}); err != nil {
1352+
return err
1353+
}
1354+
return nil
1355+
}
1356+
1357+
func (r *PatternReconciler) getPatternsOperatorConfigMap() (*corev1.ConfigMap, error) {
1358+
cm, err := r.fullClient.CoreV1().ConfigMaps(DetectOperatorNamespace()).Get(context.Background(), OperatorConfigMap, metav1.GetOptions{})
1359+
if err != nil {
1360+
if kerrors.IsNotFound(err) {
1361+
return nil, nil
1362+
} else {
1363+
return nil, err
1364+
}
1365+
}
1366+
return cm, nil
1367+
}
1368+
1369+
func (r *PatternReconciler) setPatternsOperatorConfigMapOwnership(cm *corev1.ConfigMap, p *api.Pattern) error {
1370+
controllerRef := metav1.GetControllerOf(cm)
1371+
if controllerRef != nil && controllerRef.UID == p.GetUID() && controllerRef.Kind == p.Kind && controllerRef.APIVersion == p.APIVersion {
1372+
return nil
1373+
}
1374+
if err := controllerutil.SetControllerReference(p, cm, r.Scheme); err != nil {
1375+
return err
1376+
}
1377+
_, err := r.fullClient.CoreV1().ConfigMaps(DetectOperatorNamespace()).Update(context.Background(), cm, metav1.UpdateOptions{})
1378+
if err != nil {
1379+
return err
1380+
}
1381+
return nil
1382+
}
1383+
13281384
func DropLocalGitPaths() error {
13291385
// If there is a completely new local folder, let's remove the old one
13301386
// User changed the target repo
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package controllers
2+
3+
import (
4+
"strings"
5+
)
6+
7+
type PatternsOperatorConfig map[string]string
8+
9+
var DefaultPatternsOperatorConfig = PatternsOperatorConfig{
10+
"gitops.catalogSource": GitOpsDefaultCatalogSource,
11+
"gitops.channel": GitOpsDefaultChannel,
12+
"gitops.sourceNamespace": GitOpsDefaultCatalogSourceNamespace,
13+
"gitops.installApprovalPlan": GitOpsDefaultApprovalPlan,
14+
"gitops.csv": GitOpsDefaultCSV,
15+
"gitops.additionalArgoAdmins": "",
16+
"gitops.applicationHealthCheckEnabled": "false",
17+
"gitea.chartName": GiteaChartName,
18+
"gitea.helmRepoUrl": GiteaHelmRepoUrl,
19+
"gitea.chartVersion": GiteaDefaultChartVersion,
20+
"catalog.image": "",
21+
}
22+
23+
func (g PatternsOperatorConfig) getStringValue(k string) string {
24+
if v, present := g[k]; present {
25+
return v
26+
} else {
27+
return DefaultPatternsOperatorConfig[k]
28+
}
29+
}
30+
31+
func (g PatternsOperatorConfig) getBoolValue(k string) bool {
32+
if v, present := g[k]; present {
33+
return strings.EqualFold(v, "true")
34+
} else {
35+
return strings.EqualFold(DefaultPatternsOperatorConfig[k], "true")
36+
}
37+
}

0 commit comments

Comments
 (0)