Files
3c9dc03159 Add imagePullSecrets support to cluster-manager helm chart (#1539)
* Add configurable image pull secrets to cluster-manager
Allow referencing existing pull secrets via images.imagePullSecrets in the
cluster-manager Helm chart. Propagate the configured secret name to hub
components through the operator --image-pull-secret-name flag, including
cluster importer renderers and registration controller RBAC.

Signed-off-by: Enin <enin.kaduk@docker.com>

* Require .name if imagePullSecrets is set, trim ws in normalization of imagePullSecrets

Signed-off-by: Enin <enin.kaduk@docker.com>

* update-csv

Signed-off-by: Mike Ng <ming@redhat.com>

---------

Signed-off-by: Enin <enin.kaduk@docker.com>
Signed-off-by: Mike Ng <ming@redhat.com>
Co-authored-by: Mike Ng <ming@redhat.com>
2026-07-09 06:03:57 +00:00

175 lines
6.8 KiB
Go

package clustermanager
import (
"context"
"os"
"time"
"github.com/openshift/library-go/pkg/controller/controllercmd"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/client-go/informers"
corev1informers "k8s.io/client-go/informers/core/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/klog/v2"
operatorclient "open-cluster-management.io/api/client/operator/clientset/versioned"
operatorinformer "open-cluster-management.io/api/client/operator/informers/externalversions"
tlslib "open-cluster-management.io/sdk-go/pkg/tls"
"open-cluster-management.io/ocm/pkg/operator/helpers"
"open-cluster-management.io/ocm/pkg/operator/operators/clustermanager/controllers/certrotationcontroller"
"open-cluster-management.io/ocm/pkg/operator/operators/clustermanager/controllers/clustermanagercontroller"
"open-cluster-management.io/ocm/pkg/operator/operators/clustermanager/controllers/crdstatuccontroller"
"open-cluster-management.io/ocm/pkg/operator/operators/clustermanager/controllers/migrationcontroller"
clustermanagerstatuscontroller "open-cluster-management.io/ocm/pkg/operator/operators/clustermanager/controllers/statuscontroller"
)
type Options struct {
SkipRemoveCRDs bool
ControlPlaneNodeLabelSelector string
DeploymentReplicas int32
EnableSyncLabels bool
ImagePullSecretName string
}
// RunClusterManagerOperator starts a new cluster manager operator
func (o *Options) RunClusterManagerOperator(ctx context.Context, controllerContext *controllercmd.ControllerContext) error {
// setting up contextual logger
logger := klog.NewKlogr()
podName := os.Getenv("POD_NAME")
if podName != "" {
logger = logger.WithValues("podName", podName)
}
ctx = klog.NewContext(ctx, logger)
// Build kubclient client and informer for managed cluster
kubeClient, err := kubernetes.NewForConfig(controllerContext.KubeConfig)
if err != nil {
return err
}
newOneTermInformer := func(name string) informers.SharedInformerFactory {
return informers.NewSharedInformerFactoryWithOptions(kubeClient, 5*time.Minute,
informers.WithTweakListOptions(func(options *metav1.ListOptions) {
options.FieldSelector = fields.OneTermEqualSelector("metadata.name", name).String()
}))
}
signerSecretInformer := newOneTermInformer(helpers.SignerSecret)
registrationSecretInformer := newOneTermInformer(helpers.RegistrationWebhookSecret)
workSecretInformer := newOneTermInformer(helpers.WorkWebhookSecret)
addonSecretInformer := newOneTermInformer(helpers.AddonWebhookSecret)
grpcServerSecretInformer := newOneTermInformer(helpers.GRPCServerSecret)
placementDebugSecretInformer := newOneTermInformer(helpers.PlacementDebugServingCertSecret)
configmapInformer := newOneTermInformer(helpers.CaBundleConfigmap)
deploymentInformer := informers.NewSharedInformerFactoryWithOptions(kubeClient, 5*time.Minute,
informers.WithTweakListOptions(func(options *metav1.ListOptions) {
selector := &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: helpers.HubLabelKey,
Operator: metav1.LabelSelectorOpExists,
},
},
}
options.LabelSelector = metav1.FormatLabelSelector(selector)
}))
secretInformers := map[string]corev1informers.SecretInformer{
helpers.SignerSecret: signerSecretInformer.Core().V1().Secrets(),
helpers.RegistrationWebhookSecret: registrationSecretInformer.Core().V1().Secrets(),
helpers.WorkWebhookSecret: workSecretInformer.Core().V1().Secrets(),
helpers.AddonWebhookSecret: addonSecretInformer.Core().V1().Secrets(),
helpers.GRPCServerSecret: grpcServerSecretInformer.Core().V1().Secrets(),
helpers.PlacementDebugServingCertSecret: placementDebugSecretInformer.Core().V1().Secrets(),
}
// Build operator client and informer
operatorClient, err := operatorclient.NewForConfig(controllerContext.KubeConfig)
if err != nil {
return err
}
operatorInformer := operatorinformer.NewSharedInformerFactory(operatorClient, 5*time.Minute)
// Load TLS config and start watching for changes. The watcher restarts the process
// when the ConfigMap changes so the new TLS settings are applied.
currentTLSConfig, err := tlslib.StartTLSConfigMapWatcher(ctx, kubeClient, controllerContext.OperatorNamespace,
func() {
logger.Info("TLS ConfigMap changed, restarting", "component", "cluster-manager operator")
os.Exit(0)
},
)
if err != nil {
if ctx.Err() != nil {
return nil
}
return err
}
tlsMinVersion := tlslib.VersionToString(currentTLSConfig.MinVersion)
tlsCipherSuites := tlslib.CipherSuitesToString(currentTLSConfig.CipherSuites)
logger.Info("TLS configuration loaded", "minVersion", tlsMinVersion, "cipherSuites", tlsCipherSuites)
clusterManagerController := clustermanagercontroller.NewClusterManagerController(
kubeClient,
controllerContext.KubeConfig,
operatorClient.OperatorV1().ClusterManagers(),
operatorInformer.Operator().V1().ClusterManagers(),
deploymentInformer.Apps().V1().Deployments(),
configmapInformer.Core().V1().ConfigMaps(),
o.SkipRemoveCRDs,
o.ControlPlaneNodeLabelSelector,
o.DeploymentReplicas,
controllerContext.OperatorNamespace,
o.EnableSyncLabels,
imagePullSecretNameFromOptions(o),
tlsMinVersion,
tlsCipherSuites,
)
statusController := clustermanagerstatuscontroller.NewClusterManagerStatusController(
operatorClient.OperatorV1().ClusterManagers(),
operatorInformer.Operator().V1().ClusterManagers(),
deploymentInformer.Apps().V1().Deployments())
certRotationController := certrotationcontroller.NewCertRotationController(
kubeClient,
secretInformers,
configmapInformer.Core().V1().ConfigMaps(),
operatorInformer.Operator().V1().ClusterManagers())
crdMigrationController := migrationcontroller.NewCRDMigrationController(
controllerContext.KubeConfig,
kubeClient,
operatorClient.OperatorV1().ClusterManagers(),
operatorInformer.Operator().V1().ClusterManagers())
crdStatusController := crdstatuccontroller.NewCRDStatusController(
controllerContext.KubeConfig,
kubeClient,
operatorInformer.Operator().V1().ClusterManagers())
go operatorInformer.Start(ctx.Done())
go deploymentInformer.Start(ctx.Done())
go signerSecretInformer.Start(ctx.Done())
go registrationSecretInformer.Start(ctx.Done())
go workSecretInformer.Start(ctx.Done())
go addonSecretInformer.Start(ctx.Done())
go grpcServerSecretInformer.Start(ctx.Done())
go placementDebugSecretInformer.Start(ctx.Done())
go configmapInformer.Start(ctx.Done())
go clusterManagerController.Run(ctx, 1)
go statusController.Run(ctx, 1)
go certRotationController.Run(ctx, 1)
go crdMigrationController.Run(ctx, 1)
go crdStatusController.Run(ctx, 1)
<-ctx.Done()
return nil
}
func imagePullSecretNameFromOptions(o *Options) string {
return helpers.NormalizeImagePullSecretName(o.ImagePullSecretName)
}