Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement reconciliation for ManagedCluster and create ManagedClusterView #219

Merged

Conversation

vbnrh
Copy link
Member

@vbnrh vbnrh commented Jul 4, 2024

  • Added reconciliation logic for ManagedCluster
  • Added tests for ManagedClusterReconciler reconciliation logic and ensure ManagedClusterViews function.
  • Reconciliation for ManagedCluster creates ManagedClusterView which pulls the ‘odf-info’ configmap onto the hub.
  • Updated RBAC rules in config/rbac/role.yaml to include permissions for ManagedClusterView resources. (ManagedCluster RBAC already there)
  • Plumbing to make the controllers work like the items above
  • Updated go.mod and go.sum to include github.com/stolostron/multicloud-operators-foundation.

@openshift-ci openshift-ci bot added the approved label Jul 4, 2024
config/rbac/role.yaml Outdated Show resolved Hide resolved
controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
controllers/utils/acm.go Outdated Show resolved Hide resolved
controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
@@ -140,6 +142,15 @@ func (o *ManagerOptions) runManager() {
os.Exit(1)
}

if err = (&ManagedClusterReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to pass the Scheme here, we can get it from client using Client.Scheme()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would be the difference between both ways ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could probably remove the Scheme from the ManagedClusterReconciler, we arent using it anywhere.

controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
@vbnrh
Copy link
Member Author

vbnrh commented Jul 9, 2024

/test integration-test

@@ -140,6 +142,15 @@ func (o *ManagerOptions) runManager() {
os.Exit(1)
}

if err = (&ManagedClusterReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could probably remove the Scheme from the ManagedClusterReconciler, we arent using it anywhere.

controllers/utils/acm.go Outdated Show resolved Hide resolved
@vbnrh vbnrh force-pushed the odfinfo-pull-configmap branch 3 times, most recently from 409a44a to 35359fa Compare July 9, 2024 11:42
@@ -71,6 +71,7 @@ const spokeClusterRoleBindingName = "spoke-clusterrole-bindings"
//+kubebuilder:rbac:groups=addon.open-cluster-management.io,resources=managedclusteraddons/status,verbs=*
//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;create;update;watch
//+kubebuilder:rbac:groups=console.openshift.io,resources=consoleplugins,verbs=get;list;create;update;watch
// +kubebuilder:rbac:groups=view.open-cluster-management.io,resources=managedclusterviews,verbs=get;list;watch;create;update
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a question: shouldn't this be added to managedcluster_controller file ?? instead of here...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kubebuilder will add the required permissions for the pod to the role manifest automatically. All controllers run in the same container.

Copy link
Contributor

@SanjalKatiyar SanjalKatiyar Jul 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, but I assumed it was more of a good practice to add RBACs on top of respective reconciler, rather than spreading it across multiple unrelated files...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. It is good practice to have RBACs close to the controllers that require it. We haven't followed that well enough in this repo, but I think we should start doing it. End result is the same, but this makes it easy to argue about why a particular RBAC was added.

controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
@@ -71,6 +71,7 @@ const spokeClusterRoleBindingName = "spoke-clusterrole-bindings"
//+kubebuilder:rbac:groups=addon.open-cluster-management.io,resources=managedclusteraddons/status,verbs=*
//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;create;update;watch
//+kubebuilder:rbac:groups=console.openshift.io,resources=consoleplugins,verbs=get;list;create;update;watch
// +kubebuilder:rbac:groups=view.open-cluster-management.io,resources=managedclusterviews,verbs=get;list;watch;create;update
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. It is good practice to have RBACs close to the controllers that require it. We haven't followed that well enough in this repo, but I think we should start doing it. End result is the same, but this makes it easy to argue about why a particular RBAC was added.

controllers/utils/acm.go Outdated Show resolved Hide resolved
controllers/utils/acm.go Outdated Show resolved Hide resolved
controllers/utils/acm.go Outdated Show resolved Hide resolved
controllers/utils/acm.go Outdated Show resolved Hide resolved
@vbnrh
Copy link
Member Author

vbnrh commented Jul 16, 2024

  • Added initialization for ManagedClusterViewReconciler in manager.go to setup the ManagedClusterView controller.
  • Creates or updates configMap odf-client-info which maps client to it provider cluster
  • Created comprehensive unit tests to cover the creation and update scenarios of the ConfigMap.

controllers/managedclusterview_controller.go Outdated Show resolved Hide resolved
Comment on lines 69 to 74
DeleteFunc: func(e event.DeleteEvent) bool {
return false
},
GenericFunc: func(e event.GenericEvent) bool {
return false
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to explicitly specify the Delete and Generic? won't it default to false?

Comment on lines 163 to 189
ownerExists := false
for _, ownerRef := range configMap.OwnerReferences {
if ownerRef.UID == managedClusterView.UID {
ownerExists = true
break
}
}

if !ownerExists {
ownerRef := *metav1.NewControllerRef(&managedClusterView, viewv1beta1.GroupVersion.WithKind("ManagedClusterView"))
logger.Info("OwnerRef added", "UID", string(ownerRef.UID))
configMap.OwnerReferences = append(configMap.OwnerReferences, ownerRef)
}
return nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can replace it with controller-util to make it simpler?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have access to scheme which is required for setOwnerReference function

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use c.Scheme() ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used it but it was not getting set somehow. The tests were failing. I will look into this later

Name: ClientInfoConfigMapName,
Namespace: operatorNamespace,
},
Data: configMapData,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to set the data here, we can do it inside the CreateOrUpdate directly

Comment on lines 124 to 148
if strings.HasSuffix(key, ".config.yaml") {
var config StorageClusterConfig
err := json.Unmarshal([]byte(value), &config)
if err != nil {
return fmt.Errorf("failed to unmarshal config data for key %s: %v", key, err)
}

providerInfo := config
providerInfo.Clients = nil
providerInfo.ProviderClusterName = managedClusterView.Namespace

providerInfoJSON, err := json.Marshal(providerInfo)
if err != nil {
return fmt.Errorf("failed to marshal provider info: %v", err)
}

for _, client := range config.Clients {
reverseLookup[client] = string(providerInfoJSON)
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should change once we have changed the struct

NamespacedName types.NamespacedName `yaml:"namespacedName"`
StorageProviderEndpoint string `yaml:"storageProviderEndpoint"`
CephClusterFSID string `yaml:"cephClusterFSID"`
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a temporary addition till the api is exported on OCS operator

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 155 to 158
for _, client := range odfInfo.Clients {
clientInfo := ClientInfo{
ClusterID: client.ClusterID,
Name: client.Name,
ProviderInfo: providerInfo,
}
clientInfoMap[client.Name] = clientInfo
}
}

configMapData := make(map[string]string)
for clientName, clientInfo := range clientInfoMap {
clientInfoJSON, err := json.Marshal(clientInfo)
if err != nil {
return fmt.Errorf("failed to marshal client info: %v", err)
}
configMapData[clientName] = string(clientInfoJSON)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The key we use in the configMap for reverse lookup is storageClient Name, two different managed clusters can have the storageClient Name. What do you think about using ClientName/ManagedClusterName (of the client cluster) as the key for the configMap?
We can get the managedClusterName of the client cluster here by referencing the openshift Cluster Version UUID provided in the odfInfo .clients.clusterId

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense.
Added func to fetch ManagedCluster via the clusterId.
Added another field called clientManagedClusterName to ClientInfo
The key is changed from client.Name to clientManagedClusterName/client.Name

@vbnrh vbnrh force-pushed the odfinfo-pull-configmap branch 2 times, most recently from 50cb833 to d5f5de3 Compare July 17, 2024 10:41
@vbnrh
Copy link
Member Author

vbnrh commented Jul 17, 2024

/test unit-test

1 similar comment
@vbnrh
Copy link
Member Author

vbnrh commented Jul 17, 2024

/test unit-test

@vbnrh
Copy link
Member Author

vbnrh commented Jul 17, 2024

/test integration-test

controllers/managedcluster_controller.go Show resolved Hide resolved
controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
controllers/managedclusterview_controller.go Show resolved Hide resolved
controllers/managedclusterview_controller.go Outdated Show resolved Hide resolved
controllers/managedclusterview_controller.go Outdated Show resolved Hide resolved
controllers/managedclusterview_controller.go Outdated Show resolved Hide resolved
controllers/managedclusterview_controller_test.go Outdated Show resolved Hide resolved
controllers/managedclusterview_controller.go Outdated Show resolved Hide resolved
controllers/managedclusterview_controller.go Outdated Show resolved Hide resolved
Copy link
Contributor

@umangachapagain umangachapagain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Squash the first 2 commits and last 2 commits. Everything else looks good to me.

@openshift-ci openshift-ci bot added the lgtm label Jul 19, 2024
Copy link
Contributor

openshift-ci bot commented Jul 19, 2024

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: umangachapagain, vbnrh

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:
  • OWNERS [umangachapagain,vbnrh]

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
controllers/managedcluster_controller.go Outdated Show resolved Hide resolved
controllers/managedclusterview_controller.go Outdated Show resolved Hide resolved
controllers/managedclusterview_controller.go Outdated Show resolved Hide resolved
controllers/managedcluster_controller.go Show resolved Hide resolved
controllers/mirrorpeer_controller.go Show resolved Hide resolved
@openshift-ci openshift-ci bot removed the lgtm label Jul 19, 2024
…lusterView

- Added reconciliation logic for `ManagedCluster`
- Added tests for `ManagedClusterReconciler` reconciliation logic and ensure ManagedClusterViews function.
- Reconciliation for ManagedCluster creates ManagedClusterView which pulls the ‘odf-info’ configmap onto the hub.
- Updated RBAC rules in `config/rbac/role.yaml` to include permissions for ManagedClusterView resources. (ManagedCluster RBAC already there)
- Plumbing to make the controllers work like the items above
- Updated go.mod and go.sum to include `github.com/stolostron/multicloud-operators-foundation`.
- Fixes to functions, tests and adding new predicate

Signed-off-by: vbadrina <[email protected]>
- Added initialization for ManagedClusterViewReconciler in manager.go to setup the ManagedClusterView controller.
- Creates or updates configMap odf-client-info which maps client to it provider cluster
- Created comprehensive unit tests to cover the creation and update scenarios of the ConfigMap.

Signed-off-by: vbadrina <[email protected]>
@rewantsoni
Copy link
Member

/lgtm

@openshift-ci openshift-ci bot added the lgtm label Jul 19, 2024
@openshift-merge-bot openshift-merge-bot bot merged commit 7cfca25 into red-hat-storage:main Jul 19, 2024
11 checks passed
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

const MCVLabelKey = "multicluster.odf.openshift.io/cluster"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is used anywhere...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we replaced with the createdBy label for MCO , i will remove it later

}

return ctrl.NewControllerManagedBy(mgr).
For(&clusterv1.ManagedCluster{}, builder.WithPredicates(managedClusterPredicate, predicate.ResourceVersionChangedPredicate{})).
Owns(&viewv1beta1.ManagedClusterView{}).
Owns(&corev1.ConfigMap{}).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any need to reconcile this on the owned ConfigMaps ?? It's not like we are managing cleanup of MCV or anything here, was there some other reason ??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is done to ensure that MC reconcile is triggered whenever there are events for the ConfigMap. To ensure the desired ConfigMap is always present..

Copy link
Contributor

@SanjalKatiyar SanjalKatiyar Jul 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConfigMap is created by MCV controller, not by MC controller, right ?? my question was, if any event occurs on that ConfigMap, why we need to reconcile MC controller (which creates MCV)... which edge case am I missing ??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Configmap cannot be owned by MCV as they will be in different namespaces. It can be owned by cluster scoped resource like MC. Which will propagate events to eventually reconcile the configmap to desired state

Comment on lines +136 to +149
for _, client := range odfInfo.Clients {
managedCluster, err := utils.GetManagedClusterById(ctx, c, client.ClusterID)
if err != nil {
return err
}
clientInfo := ClientInfo{
ClusterID: client.ClusterID,
Name: client.Name,
ProviderInfo: providerInfo,
ClientManagedClusterName: managedCluster.Name,
}
clientInfoMap[fmt.Sprintf("%s/%s", managedCluster.Name, client.Name)] = clientInfo
}
}
Copy link
Contributor

@SanjalKatiyar SanjalKatiyar Jul 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What will happen in case of Multiple StorageCluster scenario (normal 1 internal + 1 external on same OCP) (no Provider-Client) ??

  1. Won't fmt.Sprintf("%s/%s", managedCluster.Name, client.Name) give exact same "key" in both cases ??
  2. Assuming that there will always be one client for internal (somehow), what happens to external mode cluster ?? This ConfigMap won't store info about external cluster, right ??

Copy link
Contributor

@SanjalKatiyar SanjalKatiyar Jul 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if this ConfigMap is only for Provider-Client use case and not for other deployments. Because it make sense if so, but I am not sure why to make it so specific.

@vbnrh
Copy link
Member Author

vbnrh commented Jul 22, 2024

Isn't it conceptually incorrect to call it client-info ConfigMap ?? There can be non-Provider deployments as well (eg: normal internal, external), this flow will remain same for that.
Same is true for the entity which will consume this ConfigMap (say console), used while creating a DRPolicy, which is unrelated to just Provider-Client. Am I missing anything ??

 or purpose of this ConfigMap is to only be used by Provider-Client cases ?? in which case I don't think it is very useful for console.

Let me know if this ConfigMap is only for Provider-Client use case and not for other deployments. Because it make sense if so, but I am not sure why to make it so specific.

@SanjalKatiyar
For the above queries, the purpose of the current configmap was to serve as a quick everse lookup for clients for provider consumer scenarios. The current configmap could not be used due to the way data is structured, there will be lot of redundant data. We will add and extend the design later releases to add to the same or a different configmap for non provider mode deployments

For now, UI may need to consume MCV's created by MCO directly.

@SanjalKatiyar
Copy link
Contributor

SanjalKatiyar commented Jul 22, 2024

@SanjalKatiyar For the above queries, the purpose of the current configmap was to serve as a quick everse lookup for clients for provider consumer scenarios. The current configmap could not be used due to the way data is structured, there will be lot of redundant data. We will add and extend the design later releases to add to the same or a different configmap for non provider mode deployments

For now, UI may need to consume MCV's created by MCO directly.

Thanks for the confirmation (that was my guess too).
But, is Provider specific current ConfigMap needed by any operator ?? I mean why are we creating it at all ?? and if we are then we should have created it for all use cases instead of specific case, it's just a re-arrangement of data.

Keeping key as clusterName/storageClusterName/storageClusterNamespace should have reduced the current redundancy as well IIUC.

But anyway, this is just a question. My main concern has already been answered. Console will rely on MCV, instead of the ConfigMap.

@vbnrh
Copy link
Member Author

vbnrh commented Jul 22, 2024

@SanjalKatiyar For the above queries, the purpose of the current configmap was to serve as a quick everse lookup for clients for provider consumer scenarios. The current configmap could not be used due to the way data is structured, there will be lot of redundant data. We will add and extend the design later releases to add to the same or a different configmap for non provider mode deployments
For now, UI may need to consume MCV's created by MCO directly.

Thanks for the confirmation (that was my guess too). But, is Provider specific current ConfigMap needed by any operator ?? I mean why are we creating it at all ?? and if we are then we should have created it for all use cases instead of specific case, it's just a re-arrangement of data.

Keeping key as clusterName/storageClusterName/storageClusterNamespace should have reduced the current redundancy as well IIUC.

But anyway, this is just a question. My main concern has already been answered. Console will rely on MCV, instead of the ConfigMap.

This won't function as reverse lookup for client information as we may need to look through all keys. Your concern is valid though, we will work upon the design to cover all scenarios.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants