Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 1 addition & 69 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,10 @@ import (
// to ensure that exec-entrypoint and run can make use of them.
_ "k8s.io/client-go/plugin/pkg/client/auth"

"k8s.io/apimachinery/pkg/api/errors"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
crclient "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/manager"
Expand All @@ -46,9 +44,6 @@ import (
"github.com/hybrid-cloud-patterns/patterns-operator/version"
consolev1 "github.com/openshift/api/console/v1"
operatorv1 "github.com/openshift/api/operator/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
//+kubebuilder:scaffold:imports
)

Expand Down Expand Up @@ -85,12 +80,6 @@ func main() {

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

// Create initial config map for gitops
err := createPatternsOperatorConfigMap()
if err != nil {
setupLog.Error(err, "unable to create config map")
}

mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
HealthProbeBindAddress: probeAddr,
Expand Down Expand Up @@ -120,7 +109,7 @@ func main() {
setupLog.Error(err, "unable to add console plugin runnable")
}

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

// Creates the patterns operator configmap
// This will include configuration parameters that
// will allow operator configuration
func createPatternsOperatorConfigMap() error {
config, err := ctrl.GetConfig()
if err != nil {
return fmt.Errorf("failed to get config: %s", err)
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return fmt.Errorf("failed to call NewForConfig: %s", err)
}

configMap := corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
Kind: "ConfigMap",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: controllers.OperatorConfigMap,
Namespace: controllers.DetectOperatorNamespace(),
},
}

_, err = clientset.CoreV1().ConfigMaps(controllers.DetectOperatorNamespace()).Get(context.Background(), controllers.OperatorConfigMap, metav1.GetOptions{})
if err != nil && errors.IsNotFound(err) {
// if the configmap does not exist we create an empty one
_, err = clientset.CoreV1().ConfigMaps(controllers.DetectOperatorNamespace()).Create(context.Background(), &configMap, metav1.CreateOptions{})
if err != nil {
return err
}
} else {
// if we had an error that is not IsNotFound we need to return it
return err
}
return nil
}

func registerComponentOrExit(mgr manager.Manager, f func(*k8sruntime.Scheme) error) {
// Setup Scheme for all resources
if err := f(mgr.GetScheme()); err != nil {
Expand All @@ -208,22 +159,3 @@ func registerComponentOrExit(mgr manager.Manager, f func(*k8sruntime.Scheme) err
}
setupLog.Info(fmt.Sprintf("Component registered: %v", reflect.ValueOf(f)))
}

// areAnalyticsEnabled determines whether analytics are enabled.
// Precedence: Operator ConfigMap key "analytics.enabled" (true/false) > ENV ANALYTICS (false means disabled)
func areAnalyticsEnabled(reader crclient.Reader) bool {
enabled := strings.ToLower(os.Getenv("ANALYTICS")) != "false"

var cm corev1.ConfigMap
err := reader.Get(context.Background(), crclient.ObjectKey{Namespace: controllers.DetectOperatorNamespace(), Name: controllers.OperatorConfigMap}, &cm)
if err != nil {
setupLog.Error(err, "error reading operator configmap for analytics setting")
return enabled
}

if v, ok := cm.Data["analytics.enabled"]; ok {
return strings.EqualFold(v, "true")
}

return enabled
}
74 changes: 0 additions & 74 deletions cmd/main_test.go

This file was deleted.

10 changes: 5 additions & 5 deletions internal/controller/argo.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func newArgoCD(name, namespace string, patternsOperatorConfig PatternsOperatorCo
"g, cluster-admins, role:admin",
"g, admin, role:admin",
}
for argoAdmin := range strings.SplitSeq(patternsOperatorConfig.getValueWithDefault("gitops.additionalArgoAdmins"), ",") {
for argoAdmin := range strings.SplitSeq(patternsOperatorConfig.getStringValue("gitops.additionalArgoAdmins"), ",") {
argoAdmin = strings.TrimSpace(argoAdmin)
if argoAdmin != "" {
argoPolicies = append(argoPolicies, "g, "+argoAdmin+", role:admin")
Expand Down Expand Up @@ -160,7 +160,7 @@ health_status.message = "An install plan for a subscription is pending installat
return health_status`,
},
}
if strings.EqualFold(patternsOperatorConfig.getValueWithDefault("gitops.applicationHealthCheckEnabled"), "true") {
if patternsOperatorConfig.getBoolValue("gitops.applicationHealthCheckEnabled") {
// As of ArgoCD 1.8 the Application health check was dropped (see https://github.com/argoproj/argo-cd/issues/3781),
// but in app-of-apps pattern this is needed in order to implement children apps dependencies via sync-waves
resourceHealthChecks = append(resourceHealthChecks, argooperator.ResourceHealthCheck{
Expand Down Expand Up @@ -978,9 +978,9 @@ func newArgoGiteaApplication(p *api.Pattern, patternsOperatorConfig PatternsOper
},
Project: "default",
Source: &argoapi.ApplicationSource{
RepoURL: patternsOperatorConfig.getValueWithDefault("gitea.helmRepoUrl"),
TargetRevision: patternsOperatorConfig.getValueWithDefault("gitea.chartVersion"),
Chart: patternsOperatorConfig.getValueWithDefault("gitea.chartName"),
RepoURL: patternsOperatorConfig.getStringValue("gitea.helmRepoUrl"),
TargetRevision: patternsOperatorConfig.getStringValue("gitea.chartVersion"),
Chart: patternsOperatorConfig.getStringValue("gitea.chartName"),
Helm: &argoapi.ApplicationSourceHelm{
Parameters: parameters,
},
Expand Down
27 changes: 0 additions & 27 deletions internal/controller/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,30 +85,3 @@ const (

// Experimental Capabilities that can be enabled
// Currently none

var DefaultPatternsOperatorConfig = map[string]string{
"gitops.catalogSource": GitOpsDefaultCatalogSource,
"gitops.channel": GitOpsDefaultChannel,
"gitops.sourceNamespace": GitOpsDefaultCatalogSourceNamespace,
"gitops.installApprovalPlan": GitOpsDefaultApprovalPlan,
"gitops.csv": GitOpsDefaultCSV,
"gitops.additionalArgoAdmins": "",
"gitops.applicationHealthCheckEnabled": "false",
"gitea.chartName": GiteaChartName,
"gitea.helmRepoUrl": GiteaHelmRepoUrl,
"gitea.chartVersion": GiteaDefaultChartVersion,
"analytics.enabled": "true",
"catalog.image": "",
}

type PatternsOperatorConfig map[string]string

func (g PatternsOperatorConfig) getValueWithDefault(k string) string {
if v, present := g[k]; present {
return v
}
if defaultValue, present := DefaultPatternsOperatorConfig[k]; present {
return defaultValue
}
return ""
}
70 changes: 63 additions & 7 deletions internal/controller/pattern_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/go-logr/logr"
"github.com/hybrid-cloud-patterns/patterns-operator/internal/controller/console"

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

patternsOperatorConfig := DefaultPatternsOperatorConfig
var patternsOperatorConfig PatternsOperatorConfig

configCM, err := GetPatternsOperatorConfigMap()
// If we hit an error that is not related to the configmap not existing bubble it up
if err != nil && !kerrors.IsNotFound(err) {
// We try to get the configuration ConfigMap. The method getPatternsOperatorConfigMap returns nil, nil if the ConfigMap doesn't exist
configCM, err := r.getPatternsOperatorConfigMap()
if err != nil {
return r.actionPerformed(instance, "failed to get the configuration ConfigMap", err)
}
if configCM != nil {
if configCM == nil { // If the ConfigMap doesn't exist, we create it
if err = r.createPatternsOperatorConfigMap(instance); err != nil {
return r.actionPerformed(instance, "failed to create the configuration ConfigMap", err)
}
} else { // If the ConfigMap exists, we set the ownership and get the configuration from Data
if err = r.setPatternsOperatorConfigMapOwnership(configCM, instance); err != nil {
return r.actionPerformed(instance, "failed to set ownership of configuration ConfigMap", err)
}
patternsOperatorConfig = configCM.Data
}

Expand Down Expand Up @@ -398,8 +406,8 @@ func (r *PatternReconciler) reconcileGitOpsSubscription(qualifiedInstance *api.P
if err := controllerutil.RemoveOwnerReference(qualifiedInstance, currentSub, r.Scheme); err == nil {
changed = true
}
operatorConfigMap, cmErr := GetPatternsOperatorConfigMap()
if cmErr == nil {
operatorConfigMap, cmErr := r.getPatternsOperatorConfigMap()
if cmErr == nil && operatorConfigMap != nil {
if err := controllerutil.RemoveOwnerReference(operatorConfigMap, currentSub, r.Scheme); err == nil {
changed = true
}
Expand Down Expand Up @@ -907,6 +915,7 @@ func (r *PatternReconciler) SetupWithManager(mgr ctrl.Manager) error {
var ctrlErr error
r.ctrl, ctrlErr = ctrl.NewControllerManagedBy(mgr).
For(&api.Pattern{}).
Owns(&corev1.ConfigMap{}).
Build(r)
return ctrlErr
}
Expand Down Expand Up @@ -1325,6 +1334,53 @@ func (r *PatternReconciler) getLocalGit(p *api.Pattern) (string, error) {
return "", nil
}

func (r *PatternReconciler) createPatternsOperatorConfigMap(p *api.Pattern) error {
configMap := corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
Kind: "ConfigMap",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: OperatorConfigMap,
Namespace: DetectOperatorNamespace(),
},
}
if err := controllerutil.SetControllerReference(p, &configMap, r.Scheme); err != nil {
return err
}
if _, err := r.fullClient.CoreV1().ConfigMaps(DetectOperatorNamespace()).Create(context.Background(), &configMap, metav1.CreateOptions{}); err != nil {
return err
}
return nil
}

func (r *PatternReconciler) getPatternsOperatorConfigMap() (*corev1.ConfigMap, error) {
cm, err := r.fullClient.CoreV1().ConfigMaps(DetectOperatorNamespace()).Get(context.Background(), OperatorConfigMap, metav1.GetOptions{})
if err != nil {
if kerrors.IsNotFound(err) {
return nil, nil
} else {
return nil, err
}
}
return cm, nil
}

func (r *PatternReconciler) setPatternsOperatorConfigMapOwnership(cm *corev1.ConfigMap, p *api.Pattern) error {
controllerRef := metav1.GetControllerOf(cm)
if controllerRef != nil && controllerRef.UID == p.GetUID() && controllerRef.Kind == p.Kind && controllerRef.APIVersion == p.APIVersion {
return nil
}
if err := controllerutil.SetControllerReference(p, cm, r.Scheme); err != nil {
return err
}
_, err := r.fullClient.CoreV1().ConfigMaps(DetectOperatorNamespace()).Update(context.Background(), cm, metav1.UpdateOptions{})
if err != nil {
return err
}
return nil
}

func DropLocalGitPaths() error {
// If there is a completely new local folder, let's remove the old one
// User changed the target repo
Expand Down
37 changes: 37 additions & 0 deletions internal/controller/patterns_operator_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package controllers

import (
"strings"
)

type PatternsOperatorConfig map[string]string

var DefaultPatternsOperatorConfig = PatternsOperatorConfig{
"gitops.catalogSource": GitOpsDefaultCatalogSource,
"gitops.channel": GitOpsDefaultChannel,
"gitops.sourceNamespace": GitOpsDefaultCatalogSourceNamespace,
"gitops.installApprovalPlan": GitOpsDefaultApprovalPlan,
"gitops.csv": GitOpsDefaultCSV,
"gitops.additionalArgoAdmins": "",
"gitops.applicationHealthCheckEnabled": "false",
"gitea.chartName": GiteaChartName,
"gitea.helmRepoUrl": GiteaHelmRepoUrl,
"gitea.chartVersion": GiteaDefaultChartVersion,
"catalog.image": "",
}

func (g PatternsOperatorConfig) getStringValue(k string) string {
if v, present := g[k]; present {
return v
} else {
return DefaultPatternsOperatorConfig[k]
}
}

func (g PatternsOperatorConfig) getBoolValue(k string) bool {
if v, present := g[k]; present {
return strings.EqualFold(v, "true")
} else {
return strings.EqualFold(DefaultPatternsOperatorConfig[k], "true")
}
}
Loading