diff --git a/addons/agent_mirrorpeer_controller.go b/addons/agent_mirrorpeer_controller.go index b919ee58..9baa6ed9 100644 --- a/addons/agent_mirrorpeer_controller.go +++ b/addons/agent_mirrorpeer_controller.go @@ -46,11 +46,12 @@ import ( // MirrorPeerReconciler reconciles a MirrorPeer object type MirrorPeerReconciler struct { - HubClient client.Client - Scheme *runtime.Scheme - SpokeClient client.Client - SpokeClusterName string - Logger *slog.Logger + HubClient client.Client + Scheme *runtime.Scheme + SpokeClient client.Client + SpokeClusterName string + OdfOperatorNamespace string + Logger *slog.Logger } // Reconcile is part of the main kubernetes reconciliation loop which aims to @@ -174,7 +175,6 @@ func (r *MirrorPeerReconciler) Reconcile(ctx context.Context, req ctrl.Request) return ctrl.Result{}, err } if err == nil { - // TODO: Replace it with exported type from ocs-operator type OnboardingTicket struct { ID string `json:"id"` ExpirationDate int64 `json:"expirationDate,string"` @@ -196,7 +196,7 @@ func (r *MirrorPeerReconciler) Reconcile(ctx context.Context, req ctrl.Request) } } logger.Info("Creating a new onboarding token", "Token", token.Name) - err = createStorageClusterPeerTokenSecret(ctx, r.HubClient, r.Scheme, r.SpokeClusterName, "openshift-storage", mirrorPeer, scr) //TODO: get odfOperatorNamespace from addon flags + err = createStorageClusterPeerTokenSecret(ctx, r.HubClient, r.Scheme, r.SpokeClusterName, r.OdfOperatorNamespace, mirrorPeer, scr) if err != nil { logger.Error("Failed to create StorageCluster peer token on the hub.", "error", err) return ctrl.Result{}, err diff --git a/addons/manager.go b/addons/manager.go index 517d327d..9188f449 100644 --- a/addons/manager.go +++ b/addons/manager.go @@ -86,6 +86,7 @@ type AddonAgentOptions struct { ProbeAddr string HubKubeconfigFile string SpokeClusterName string + OdfOperatorNamespace string DRMode string DevMode bool } @@ -99,6 +100,7 @@ func (o *AddonAgentOptions) AddFlags(cmd *cobra.Command) { "Enabling this will ensure there is only one active controller manager.") flags.StringVar(&o.HubKubeconfigFile, "hub-kubeconfig", o.HubKubeconfigFile, "Location of kubeconfig file to connect to hub cluster.") flags.StringVar(&o.SpokeClusterName, "cluster-name", o.SpokeClusterName, "Name of spoke cluster.") + flags.StringVar(&o.OdfOperatorNamespace, "odf-operator-namespace", o.OdfOperatorNamespace, "Namespace of ODF operator on the spoke cluster.") flags.StringVar(&o.DRMode, "mode", o.DRMode, "The DR mode of token exchange addon. Valid values are: 'sync', 'async'") flags.BoolVar(&o.DevMode, "dev", false, "Set to true for dev environment (Text logging)") } @@ -184,11 +186,12 @@ func runHubManager(ctx context.Context, options AddonAgentOptions, logger *slog. } if err = (&MirrorPeerReconciler{ - Scheme: mgr.GetScheme(), - HubClient: mgr.GetClient(), - SpokeClient: spokeClient, - SpokeClusterName: options.SpokeClusterName, - Logger: logger.With("controller", "MirrorPeerReconciler"), + Scheme: mgr.GetScheme(), + HubClient: mgr.GetClient(), + SpokeClient: spokeClient, + SpokeClusterName: options.SpokeClusterName, + OdfOperatorNamespace: options.OdfOperatorNamespace, + Logger: logger.With("controller", "MirrorPeerReconciler"), }).SetupWithManager(mgr); err != nil { logger.Error("Failed to create MirrorPeer controller", "controller", "MirrorPeer", "error", err) os.Exit(1) diff --git a/addons/setup/addon_setup.go b/addons/setup/addon_setup.go index 4b0218c6..992eca56 100644 --- a/addons/setup/addon_setup.go +++ b/addons/setup/addon_setup.go @@ -84,10 +84,22 @@ func (a *Addons) Manifests(cluster *clusterv1.ManagedCluster, addon *addonapiv1a groups := agent.DefaultGroups(cluster.Name, a.AddonName) user := agent.DefaultUser(cluster.Name, a.AddonName, a.AddonName) + var odfOperatorNamespace string + if utils.HasRequiredODFKey(cluster) { + odfOperatorNamespacedName, err := utils.GetNamespacedNameForClusterInfo(*cluster) + if err != nil { + return objects, fmt.Errorf("error while getting ODF operator namespace on the spoke cluster %q. %w", cluster.Name, err) + } + odfOperatorNamespace = odfOperatorNamespacedName.Namespace + } else { + return objects, fmt.Errorf("error while getting ODF operator namespace on the spoke cluster %q. Expected ClusterClaim does not exist", cluster.Name) + } + manifestConfig := struct { KubeConfigSecret string ClusterName string AddonInstallNamespace string + OdfOperatorNamespace string Image string DRMode string Group string @@ -95,6 +107,7 @@ func (a *Addons) Manifests(cluster *clusterv1.ManagedCluster, addon *addonapiv1a }{ KubeConfigSecret: fmt.Sprintf("%s-hub-kubeconfig", a.AddonName), AddonInstallNamespace: installNamespace, + OdfOperatorNamespace: odfOperatorNamespace, ClusterName: cluster.Name, Image: a.AgentImage, DRMode: addon.Annotations[utils.DRModeAnnotationKey], diff --git a/addons/setup/tokenexchange-manifests/spoke_deployment.yaml b/addons/setup/tokenexchange-manifests/spoke_deployment.yaml index e4e78084..8dfa9fae 100644 --- a/addons/setup/tokenexchange-manifests/spoke_deployment.yaml +++ b/addons/setup/tokenexchange-manifests/spoke_deployment.yaml @@ -44,6 +44,7 @@ spec: - "addons" - "--hub-kubeconfig=/var/run/hub/kubeconfig" - "--cluster-name={{ .ClusterName }}" + - "--odf-operator-namespace={{ .OdfOperatorNamespace }}" - "--mode={{ .DRMode }}" volumeMounts: - name: hub-config diff --git a/controllers/managedcluster_controller.go b/controllers/managedcluster_controller.go index 7e15828a..47b6c5a5 100644 --- a/controllers/managedcluster_controller.go +++ b/controllers/managedcluster_controller.go @@ -4,13 +4,11 @@ import ( "context" "fmt" "log/slog" - "strings" "github.com/red-hat-storage/odf-multicluster-orchestrator/controllers/utils" viewv1beta1 "github.com/stolostron/multicloud-operators-foundation/pkg/apis/view/v1beta1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" clusterv1 "open-cluster-management.io/api/cluster/v1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -25,10 +23,6 @@ type ManagedClusterReconciler struct { Logger *slog.Logger } -const ( - OdfInfoClusterClaimNamespacedName = "odfinfo.odf.openshift.io" -) - func (r *ManagedClusterReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { logger := r.Logger.With("ManagedCluster", req.NamespacedName) logger.Info("Reconciling ManagedCluster") @@ -51,16 +45,6 @@ func (r *ManagedClusterReconciler) Reconcile(ctx context.Context, req reconcile. return ctrl.Result{}, nil } -func hasRequiredODFKey(mc *clusterv1.ManagedCluster) bool { - claims := mc.Status.ClusterClaims - for _, claim := range claims { - if claim.Name == OdfInfoClusterClaimNamespacedName { - return true - } - } - return false - -} func (r *ManagedClusterReconciler) SetupWithManager(mgr ctrl.Manager) error { r.Logger.Info("Setting up ManagedClusterReconciler with manager") managedClusterPredicate := predicate.Funcs{ @@ -69,14 +53,14 @@ func (r *ManagedClusterReconciler) SetupWithManager(mgr ctrl.Manager) error { if !ok { return false } - return hasRequiredODFKey(obj) + return utils.HasRequiredODFKey(obj) }, CreateFunc: func(e event.CreateEvent) bool { obj, ok := e.Object.(*clusterv1.ManagedCluster) if !ok { return false } - return hasRequiredODFKey(obj) + return utils.HasRequiredODFKey(obj) }, } @@ -89,7 +73,7 @@ func (r *ManagedClusterReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r *ManagedClusterReconciler) processManagedClusterViews(ctx context.Context, managedCluster clusterv1.ManagedCluster) error { resourceType := "ConfigMap" - odfInfoConfigMapNamespacedName, err := getNamespacedNameForClusterInfo(managedCluster) + odfInfoConfigMapNamespacedName, err := utils.GetNamespacedNameForClusterInfo(managedCluster) if err != nil { return fmt.Errorf("error while getting NamespacedName of the %s. %w", resourceType, err) } @@ -114,18 +98,3 @@ func (r *ManagedClusterReconciler) processManagedClusterViews(ctx context.Contex return nil } - -func getNamespacedNameForClusterInfo(managedCluster clusterv1.ManagedCluster) (types.NamespacedName, error) { - clusterClaims := managedCluster.Status.ClusterClaims - for _, claim := range clusterClaims { - if claim.Name == OdfInfoClusterClaimNamespacedName { - namespacedName := strings.Split(claim.Value, "/") - if len(namespacedName) != 2 { - return types.NamespacedName{}, fmt.Errorf("invalid format for namespaced name claim: expected 'namespace/name', got '%s'", claim.Value) - } - return types.NamespacedName{Namespace: namespacedName[0], Name: namespacedName[1]}, nil - } - } - - return types.NamespacedName{}, fmt.Errorf("cannot find ClusterClaim %q in ManagedCluster status", OdfInfoClusterClaimNamespacedName) -} diff --git a/controllers/managedcluster_controller_test.go b/controllers/managedcluster_controller_test.go index cfed12ee..5436bfad 100644 --- a/controllers/managedcluster_controller_test.go +++ b/controllers/managedcluster_controller_test.go @@ -50,7 +50,7 @@ func TestManagedClusterReconcile(t *testing.T) { Status: clusterv1.ManagedClusterStatus{ ClusterClaims: []clusterv1.ManagedClusterClaim{ { - Name: OdfInfoClusterClaimNamespacedName, + Name: utils.OdfInfoClusterClaimNamespacedName, Value: "openshift-storage/odf-info", }, }, @@ -86,7 +86,7 @@ func TestProcessManagedClusterViews(t *testing.T) { Status: clusterv1.ManagedClusterStatus{ ClusterClaims: []clusterv1.ManagedClusterClaim{ { - Name: OdfInfoClusterClaimNamespacedName, + Name: utils.OdfInfoClusterClaimNamespacedName, Value: "openshift-storage/odf-info", }, }, @@ -127,7 +127,7 @@ func TestProcessManagedClusterViews(t *testing.T) { Status: clusterv1.ManagedClusterStatus{ ClusterClaims: []clusterv1.ManagedClusterClaim{ { - Name: OdfInfoClusterClaimNamespacedName, + Name: utils.OdfInfoClusterClaimNamespacedName, Value: "openshift-storage/odf-info", }, }, @@ -166,7 +166,7 @@ func TestProcessManagedClusterViews(t *testing.T) { Status: clusterv1.ManagedClusterStatus{ ClusterClaims: []clusterv1.ManagedClusterClaim{ { - Name: OdfInfoClusterClaimNamespacedName, + Name: utils.OdfInfoClusterClaimNamespacedName, Value: "openshift-storage/odf-info", }, }, @@ -194,7 +194,7 @@ func Test_getNamespacedNameForClusterInfo(t *testing.T) { Status: clusterv1.ManagedClusterStatus{ ClusterClaims: []clusterv1.ManagedClusterClaim{ { - Name: OdfInfoClusterClaimNamespacedName, + Name: utils.OdfInfoClusterClaimNamespacedName, Value: "namespace/name", }, }, @@ -223,7 +223,7 @@ func Test_getNamespacedNameForClusterInfo(t *testing.T) { Status: clusterv1.ManagedClusterStatus{ ClusterClaims: []clusterv1.ManagedClusterClaim{ { - Name: OdfInfoClusterClaimNamespacedName, + Name: utils.OdfInfoClusterClaimNamespacedName, Value: "invalidformat", }, }, diff --git a/controllers/utils/managedcluster.go b/controllers/utils/managedcluster.go index 94157f04..afe674c1 100644 --- a/controllers/utils/managedcluster.go +++ b/controllers/utils/managedcluster.go @@ -3,13 +3,18 @@ package utils import ( "context" "fmt" + "strings" "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/types" clusterv1 "open-cluster-management.io/api/cluster/v1" "sigs.k8s.io/controller-runtime/pkg/client" ) -const clusterIDLabelKey = "clusterID" +const ( + clusterIDLabelKey = "clusterID" + OdfInfoClusterClaimNamespacedName = "odfinfo.odf.openshift.io" +) // GetManagedClusterById fetches a ManagedCluster by its cluster ID label func GetManagedClusterById(ctx context.Context, c client.Client, clusterId string) (*clusterv1.ManagedCluster, error) { @@ -34,3 +39,29 @@ func GetManagedClusterById(ctx context.Context, c client.Client, clusterId strin // Return the first matching ManagedCluster (there should only be one) return &managedClusterList.Items[0], nil } + +func GetNamespacedNameForClusterInfo(managedCluster clusterv1.ManagedCluster) (types.NamespacedName, error) { + clusterClaims := managedCluster.Status.ClusterClaims + for _, claim := range clusterClaims { + if claim.Name == OdfInfoClusterClaimNamespacedName { + namespacedName := strings.Split(claim.Value, "/") + if len(namespacedName) != 2 { + return types.NamespacedName{}, fmt.Errorf("invalid format for namespaced name claim: expected 'namespace/name', got '%s'", claim.Value) + } + return types.NamespacedName{Namespace: namespacedName[0], Name: namespacedName[1]}, nil + } + } + + return types.NamespacedName{}, fmt.Errorf("cannot find ClusterClaim %q in ManagedCluster status", OdfInfoClusterClaimNamespacedName) +} + +func HasRequiredODFKey(mc *clusterv1.ManagedCluster) bool { + claims := mc.Status.ClusterClaims + for _, claim := range claims { + if claim.Name == OdfInfoClusterClaimNamespacedName { + return true + } + } + return false + +}