Skip to content

Commit

Permalink
Manage client pairings via createManifestWorkForClusterPairingConfigMap
Browse files Browse the repository at this point in the history
- Added `ClientID` to `ClientInfo` struct for unique client identification.
- Updated `Reconcile` to invoke `createManifestWorkForClusterPairingConfigMap`.
- Implemented `createManifestWorkForClusterPairingConfigMap` to manage client pairings via ConfigMap in ManifestWork.
- Ensured each client is paired with exactly one other client in the ConfigMap.
- Added helper functions `DecodeConfigMap` and `GetManifestWork` in utils.
- Updated dependencies in `go.mod` and `go.sum`.

Signed-off-by: vbadrina <[email protected]>
  • Loading branch information
vbnrh committed Nov 12, 2024
1 parent f183d8a commit 5899bfa
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 33 deletions.
2 changes: 2 additions & 0 deletions controllers/managedclusterview_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type ClientInfo struct {
Name string `json:"name"`
ProviderInfo ProviderInfo `json:"providerInfo,omitempty"`
ClientManagedClusterName string `json:"clientManagedClusterName,omitempty"`
ClientID string `json:"clientId"`
}

func (r *ManagedClusterViewReconciler) SetupWithManager(mgr ctrl.Manager) error {
Expand Down Expand Up @@ -158,6 +159,7 @@ func createOrUpdateConfigMap(ctx context.Context, c client.Client, managedCluste
Name: client.Name,
ProviderInfo: providerInfo,
ClientManagedClusterName: managedCluster.Name,
ClientID: client.ClientID,
}
clientInfoJSON, err := json.Marshal(clientInfo)
if err != nil {
Expand Down
61 changes: 31 additions & 30 deletions controllers/managedclusterview_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,20 @@ func TestCreateOrUpdateConfigMap(t *testing.T) {

data := map[string]string{
"openshift-storage_ocs-storagecluster.config.yaml": `
version: "4.Y.Z"
deploymentType: "internal"
clients:
- name: "client1"
clusterId: "cluster1"
storageCluster:
namespacedName:
name: "ocs-storagecluster"
namespace: "openshift-storage"
storageProviderEndpoint: ""
cephClusterFSID: "7a3d6b81-a55d-44fe-84d0-46c67cd395ca"
storageSystemName: "ocs-storagecluster-storagesystem"
`,
version: "4.Y.Z"
deploymentType: "internal"
clients:
- name: "client1"
clusterId: "cluster1"
clientId: "client1"
storageCluster:
namespacedName:
name: "ocs-storagecluster"
namespace: "openshift-storage"
storageProviderEndpoint: ""
cephClusterFSID: "7a3d6b81-a55d-44fe-84d0-46c67cd395ca"
storageSystemName: "ocs-storagecluster-storagesystem"
`,
}
ownerRefs := []metav1.OwnerReference{
*metav1.NewControllerRef(mc1, clusterv1.SchemeGroupVersion.WithKind("ManagedCluster")),
Expand All @@ -104,35 +105,35 @@ func TestCreateOrUpdateConfigMap(t *testing.T) {
assert.NotNil(t, cm)

expectedData := map[string]string{
"cluster1-name/client1": `{"clusterId":"cluster1","name":"client1","providerInfo":{"version":"4.Y.Z","deploymentType":"internal","storageSystemName":"ocs-storagecluster-storagesystem","providerManagedClusterName":"cluster1","namespacedName":{"Namespace":"openshift-storage","Name":"ocs-storagecluster"},"storageProviderEndpoint":"","cephClusterFSID":"7a3d6b81-a55d-44fe-84d0-46c67cd395ca"},"clientManagedClusterName":"cluster1-name"}`,
"cluster1-name/client1": `{"clusterId":"cluster1","name":"client1","providerInfo":{"version":"4.Y.Z","deploymentType":"internal","storageSystemName":"ocs-storagecluster-storagesystem","providerManagedClusterName":"cluster1","namespacedName":{"Namespace":"openshift-storage","Name":"ocs-storagecluster"},"storageProviderEndpoint":"","cephClusterFSID":"7a3d6b81-a55d-44fe-84d0-46c67cd395ca"},"clientManagedClusterName":"cluster1-name","clientId":"client1"}`,
}

assert.Equal(t, expectedData, cm.Data)
assert.Equal(t, 1, len(cm.OwnerReferences))
assert.Equal(t, mc1.Name, cm.OwnerReferences[0].Name)
assert.Equal(t, "ManagedCluster", cm.OwnerReferences[0].Kind)
assert.Equal(t, clusterv1.GroupVersion.String(), cm.OwnerReferences[0].APIVersion)

})

t.Run("Update ConfigMap with MCV in cluster2", func(t *testing.T) {
mc2 := createManagedCluster("cluster2-name", "cluster2")
ctx := context.TODO()
data := map[string]string{
"openshift-storage_ocs-storagecluster.config.yaml": `
version: "4.Y.Z"
deploymentType: "internal"
clients:
- name: "client2"
clusterId: "cluster2"
storageCluster:
namespacedName:
name: "ocs-storagecluster"
namespace: "openshift-storage"
storageProviderEndpoint: ""
cephClusterFSID: "8b3d6b81-b55d-55fe-94d0-56c67cd495ca"
storageSystemName: "ocs-storagecluster-storagesystem"
`,
version: "4.Y.Z"
deploymentType: "internal"
clients:
- name: "client2"
clusterId: "cluster2"
clientId: "client2"
storageCluster:
namespacedName:
name: "ocs-storagecluster"
namespace: "openshift-storage"
storageProviderEndpoint: ""
cephClusterFSID: "8b3d6b81-b55d-55fe-94d0-56c67cd495ca"
storageSystemName: "ocs-storagecluster-storagesystem"
`,
}
ownerRefs := []metav1.OwnerReference{
*metav1.NewControllerRef(mc2, clusterv1.SchemeGroupVersion.WithKind("ManagedCluster")),
Expand All @@ -151,8 +152,8 @@ func TestCreateOrUpdateConfigMap(t *testing.T) {
assert.NotNil(t, cm)

expectedData := map[string]string{
"cluster1-name/client1": `{"clusterId":"cluster1","name":"client1","providerInfo":{"version":"4.Y.Z","deploymentType":"internal","storageSystemName":"ocs-storagecluster-storagesystem","providerManagedClusterName":"cluster1","namespacedName":{"Namespace":"openshift-storage","Name":"ocs-storagecluster"},"storageProviderEndpoint":"","cephClusterFSID":"7a3d6b81-a55d-44fe-84d0-46c67cd395ca"},"clientManagedClusterName":"cluster1-name"}`,
"cluster2-name/client2": `{"clusterId":"cluster2","name":"client2","providerInfo":{"version":"4.Y.Z","deploymentType":"internal","storageSystemName":"ocs-storagecluster-storagesystem","providerManagedClusterName":"cluster2","namespacedName":{"Namespace":"openshift-storage","Name":"ocs-storagecluster"},"storageProviderEndpoint":"","cephClusterFSID":"8b3d6b81-b55d-55fe-94d0-56c67cd495ca"},"clientManagedClusterName":"cluster2-name"}`,
"cluster1-name/client1": `{"clusterId":"cluster1","name":"client1","providerInfo":{"version":"4.Y.Z","deploymentType":"internal","storageSystemName":"ocs-storagecluster-storagesystem","providerManagedClusterName":"cluster1","namespacedName":{"Namespace":"openshift-storage","Name":"ocs-storagecluster"},"storageProviderEndpoint":"","cephClusterFSID":"7a3d6b81-a55d-44fe-84d0-46c67cd395ca"},"clientManagedClusterName":"cluster1-name","clientId":"client1"}`,
"cluster2-name/client2": `{"clusterId":"cluster2","name":"client2","providerInfo":{"version":"4.Y.Z","deploymentType":"internal","storageSystemName":"ocs-storagecluster-storagesystem","providerManagedClusterName":"cluster2","namespacedName":{"Namespace":"openshift-storage","Name":"ocs-storagecluster"},"storageProviderEndpoint":"","cephClusterFSID":"8b3d6b81-b55d-55fe-94d0-56c67cd495ca"},"clientManagedClusterName":"cluster2-name","clientId":"client2"}`,
}

assert.Equal(t, expectedData, cm.Data)
Expand Down
94 changes: 94 additions & 0 deletions controllers/mirrorpeer_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,10 +259,104 @@ func (r *MirrorPeerReconciler) Reconcile(ctx context.Context, req ctrl.Request)
logger.Error("Failed to create StorageClusterPeer", "error", err)
return result, err
}

result, err = createManifestWorkForClusterPairingConfigMap(ctx, r.Client, logger, mirrorPeer)
if err != nil {
logger.Error("Failed to create ManifestWork for ClusterPairingConfigMap", "error", err)
return result, err
}
}
return r.updateMirrorPeerStatus(ctx, mirrorPeer)
}

func createManifestWorkForClusterPairingConfigMap(ctx context.Context, client client.Client, logger *slog.Logger, mirrorPeer multiclusterv1alpha1.MirrorPeer) (ctrl.Result, error) {
clientInfoMap, err := fetchClientInfoConfigMap(ctx, client)
if err != nil {
if k8serrors.IsNotFound(err) {
logger.Info("Client info config map not found. Retrying request another time...")
return ctrl.Result{Requeue: true}, nil
}
return ctrl.Result{}, err
}

items := mirrorPeer.Spec.Items

ci1, err := getClientInfoFromConfigMap(clientInfoMap.Data, getKey(items[0].ClusterName, items[0].StorageClusterRef.Name))
if err != nil {
return ctrl.Result{}, err
}
ci2, err := getClientInfoFromConfigMap(clientInfoMap.Data, getKey(items[1].ClusterName, items[1].StorageClusterRef.Name))
if err != nil {
return ctrl.Result{}, err
}

if err := updateProviderConfigMap(ctx, client, mirrorPeer, ci1, ci2); err != nil {
return ctrl.Result{}, err
}

if err := updateProviderConfigMap(ctx, client, mirrorPeer, ci2, ci1); err != nil {
return ctrl.Result{}, err
}

return ctrl.Result{}, nil
}

// updateProviderConfigMap updates the ConfigMap on the provider with the new client pairing
func updateProviderConfigMap(ctx context.Context, client client.Client, mirrorPeer multiclusterv1alpha1.MirrorPeer, providerClientInfo ClientInfo, pairedClientInfo ClientInfo) error {
providerName := providerClientInfo.ProviderInfo.ProviderManagedClusterName
manifestWorkName := "dr-client-pair"
manifestWorkNamespace := providerName

// Attempt to get the existing ManifestWork
manifestWork, err := utils.GetManifestWork(ctx, client, manifestWorkName, manifestWorkNamespace)
var configMap *corev1.ConfigMap

if err != nil {
if k8serrors.IsNotFound(err) {
// ManifestWork does not exist; create a new ConfigMap
configMap = &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "dr-client-pair-config",
},
Data: make(map[string]string),
}
} else {
return fmt.Errorf("failed to get ManifestWork: %w", err)
}
} else {
// Decode existing ConfigMap
if len(manifestWork.Spec.Workload.Manifests) == 0 {
return fmt.Errorf("ManifestWork %s has no manifests", manifestWorkName)
}
objJson := manifestWork.Spec.Workload.Manifests[0].RawExtension.Raw
configMap, err = utils.DecodeConfigMap(objJson)
if err != nil {
return fmt.Errorf("failed to decode ConfigMap: %w", err)
}
}

configMap.Data[providerClientInfo.ClientID] = pairedClientInfo.ClientID

updatedObjJson, err := json.Marshal(configMap)
if err != nil {
return fmt.Errorf("failed to marshal updated ConfigMap: %w", err)
}

ownerRef := metav1.OwnerReference{
APIVersion: mirrorPeer.APIVersion,
Kind: mirrorPeer.Kind,
Name: mirrorPeer.Name,
UID: mirrorPeer.UID,
}

_, err = utils.CreateOrUpdateManifestWork(ctx, client, manifestWorkName, manifestWorkNamespace, updatedObjJson, ownerRef)
if err != nil {
return fmt.Errorf("failed to update ManifestWork for provider %s: %w", providerName, err)
}

return nil
}

func getKey(clusterName, clientName string) string {
return fmt.Sprintf("%s/%s", clusterName, clientName)
}
Expand Down
23 changes: 23 additions & 0 deletions controllers/utils/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (

corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)
Expand Down Expand Up @@ -44,3 +46,24 @@ func SplitKeyForNamespacedName(key string) types.NamespacedName {
namespacedName := strings.Split(splitKey[0], "_") // [openshift-storage,ocs-storagecluster]
return types.NamespacedName{Namespace: namespacedName[0], Name: namespacedName[1]}
}

func DecodeConfigMap(objJson []byte) (*corev1.ConfigMap, error) {
scheme := runtime.NewScheme()
err := corev1.AddToScheme(scheme)
if err != nil {
return nil, fmt.Errorf("failed to add to scheme in decode config map: %w", err)
}
decoder := serializer.NewCodecFactory(scheme).UniversalDeserializer()

obj, _, err := decoder.Decode(objJson, nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to decode objJson: %w", err)
}

configMap, ok := obj.(*corev1.ConfigMap)
if !ok {
return nil, fmt.Errorf("decoded object is not a ConfigMap")
}

return configMap, nil
}
14 changes: 14 additions & 0 deletions controllers/utils/manifestwork.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
workv1 "open-cluster-management.io/api/work/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
Expand Down Expand Up @@ -43,3 +44,16 @@ func CreateOrUpdateManifestWork(ctx context.Context, c client.Client, name strin

return operationResult, nil
}

func GetManifestWork(ctx context.Context, c client.Client, manifestWorkName string, namespace string) (*workv1.ManifestWork, error) {
var manifestWork workv1.ManifestWork

if err := c.Get(ctx, types.NamespacedName{
Name: manifestWorkName,
Namespace: namespace,
}, &manifestWork); err != nil {
return nil, fmt.Errorf("failed to get ManifestWork %s in namespace %s: %w", manifestWorkName, namespace, err)
}

return &manifestWork, nil
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
github.com/openshift/api v0.0.0-20240828125535-01b3675ba7b3
github.com/openshift/library-go v0.0.0-20240124134907-4dfbf6bc7b11
github.com/ramendr/ramen/api v0.0.0-20241001141243-29d6f22ad237
github.com/red-hat-storage/ocs-operator/api/v4 v4.0.0-20241111204837-199e115469a1
github.com/red-hat-storage/ocs-operator/api/v4 v4.0.0-20241112092644-99fdb662050d
github.com/rook/rook/pkg/apis v0.0.0-20240828225153-88eab510dd2b
github.com/spf13/cobra v1.8.1
github.com/stolostron/multicloud-operators-foundation v0.0.0-20220824091202-e9cd9710d009
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -731,8 +731,8 @@ github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoG
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/ramendr/ramen/api v0.0.0-20241001141243-29d6f22ad237 h1:ig6ePD0yopC5Qi5BRmhsIsKaOkdsGXTSmG3HTYIpquo=
github.com/ramendr/ramen/api v0.0.0-20241001141243-29d6f22ad237/go.mod h1:nO6VM/+PEhcPGyFIQJdhY6ip822cA61PAy/s6IjenAA=
github.com/red-hat-storage/ocs-operator/api/v4 v4.0.0-20241111204837-199e115469a1 h1:3fZJ6LVBgriKYuhBCSz0X5wYuyivcxhrbG9XaMhUt3M=
github.com/red-hat-storage/ocs-operator/api/v4 v4.0.0-20241111204837-199e115469a1/go.mod h1:fcFoM7FdQba/2m0CecUGNu38JaTt8quRKXhCqt8C3Jg=
github.com/red-hat-storage/ocs-operator/api/v4 v4.0.0-20241112092644-99fdb662050d h1:+5S4F665PL+8TK9OGHX/2A+N9jPoT2PRHO69g7z7ZLk=
github.com/red-hat-storage/ocs-operator/api/v4 v4.0.0-20241112092644-99fdb662050d/go.mod h1:fcFoM7FdQba/2m0CecUGNu38JaTt8quRKXhCqt8C3Jg=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
Expand Down

0 comments on commit 5899bfa

Please sign in to comment.