Skip to content

Implement ManagedServiceAccount resources reconciliation and tests#55

Draft
yxun wants to merge 29 commits into
stolostron:mainfrom
yxun:msa
Draft

Implement ManagedServiceAccount resources reconciliation and tests#55
yxun wants to merge 29 commits into
stolostron:mainfrom
yxun:msa

Conversation

@yxun

@yxun yxun commented Apr 29, 2026

Copy link
Copy Markdown
Collaborator

This PR adds implementations of ManagedServiceAccount reconciliation and tests in the controller.

It implements creation and cleanup of the ManagedServiceAccount related resources for each managed cluster in the ClusterSet.

It builds istio remote Secret resources and creates ManifestWork resources for distributing those Secrets so that istiod control plane can discover remote endpoints from remote cluster API server(s)

References:

Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
@openshift-ci

openshift-ci Bot commented Apr 29, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: yxun

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

The pull request process is described here

Details Needs approval from an approver in each of these files:

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

Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
@yxun yxun marked this pull request as draft April 29, 2026 17:03
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
@yxun yxun marked this pull request as ready for review May 2, 2026 15:18
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>

@mkolesnik mkolesnik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I see this only handles creating MSA but not updating or deleting it.
Is this planned to be handled later, or will you be updating this PR?

Comment thread pkg/hub/mesh/controller.go Outdated
"sigs.k8s.io/controller-runtime/pkg/reconcile"

meshv1alpha1 "github.com/stolostron/multicluster-mesh-addon/pkg/apis/mesh/v1alpha1"
msav1alpha1 "open-cluster-management.io/managed-serviceaccount/apis/authentication/v1alpha1"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should use v1beta1.

I know you were worried about the rotation.enabled field being deprecated, but the rotation.validity is still exposed AFAIK so there's no reason to use the older API.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I have updated this with the v1beta1 version.

Comment thread pkg/hub/mesh/controller.go Outdated
// CreateManagedServiceAccount creates a ManagedServiceAccount resource for a cluster in the ClusterSet
func (r *Reconciler) CreateManagedServiceAccount(ctx context.Context, cluster clusterv1.ManagedCluster, mesh *meshv1alpha1.MultiClusterMesh) error {
klog.Infof("Creating a ManagedServiceAccount for a managed cluster: %s", cluster.Name)
validity, err := time.ParseDuration(mesh.Spec.Security.Discovery.TokenValidity) // this is derived from the MultiClusterMesh spec.security.discovery.tokenValidity

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hmm right now in our API the TokenValidity field is defined as a sting that

	// Supports hours (h), days (d), weeks (w), or months (m)

This parsing won't work well, but I wonder if we should just change the type of TokenValidity to be metav1.Duration?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I think so. Changing that TokenValidity type to be metav1.Duration will help aligning it with the following struct field.
https://pkg.go.dev/open-cluster-management.io/managed-serviceaccount@v0.10.0/apis/authentication/v1beta1#ManagedServiceAccountRotation

I will update this in the mesh/v1alpha1 types.

Comment thread pkg/hub/mesh/controller.go Outdated
msa := &msav1alpha1.ManagedServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-%s", cluster.Name, mesh.Name), // Naming convention: <cluster-name>-<mesh-name>
Namespace: cluster.Name,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You should add labels to the resource so it can be properly deleted.
If you're adding deletion later, then I'm fine with not adding them right now.

Comment thread pkg/hub/mesh/controller.go Outdated
},
Spec: msav1alpha1.ManagedServiceAccountSpec{
Rotation: msav1alpha1.ManagedServiceAccountRotation{
Enabled: false,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why false?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

// Enabled prescribes whether the ServiceAccount token will be rotated before it expires.
// Deprecated: All ServiceAccount tokens will be rotated before they expire regardless of this field.

I thought we don't want to rotate that ServiceAccount token. Anyway, I can set that to true or not set it. The default value is true.

Comment thread pkg/hub/mesh/controller.go Outdated

// Create ManagedServiceAccount resources for each managed cluster
for _, cluster := range clusters {
if err := r.CreateManagedServiceAccount(ctx, cluster, mesh); err != nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What if it already exists?
I reckon this'll fail?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes, the CreateManagedServiceAccount call would fail if the resource already exists. I have updated this part by checking an existing resource first.

@@ -0,0 +1,314 @@
---

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This filed shouldn't be checked in

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I have updated the Makefile target and removed this additional crd yaml file in this PR.

Comment thread test/integration/suite_test.go Outdated
CRDDirectoryPaths: []string{
filepath.Join("..", "..", "config", "crd"), // Custom MultiClusterMesh CRD
filepath.Join("..", "..", "test", "integration", "crds", "ocm"), // OCM CRDs
filepath.Join("..", "..", "test", "integration", "external-crds", "ocm"), // OCM ManagedServiceAccount CRD

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I reckon we can just keep them in the same directory as other OCM test crds, or at most in a subdirectory there

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

right, the Makefile update-test-crds target is pulling that crd yaml in the same ocm test crds directory now.

Comment thread test/integration/controller_test.go Outdated
Version: "v1alpha1",
})

Expect(k8sClient.List(context.Background(), list, client.InNamespace(cluster1))).To(Succeed())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You should add test that validity gets passed if set by user

Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
@yxun

yxun commented May 18, 2026

Copy link
Copy Markdown
Collaborator Author

I see this only handles creating MSA but not updating or deleting it. Is this planned to be handled later, or will you be updating this PR?

I have updated the part of the controller code. If the cluster has an existing ManagedServiceAccount resource with the naming convention , it will skip creating or updating it.

I can add a TODO and will implement updating existing resources in a follow up PR.

yxun added 2 commits May 19, 2026 08:43
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
Comment thread pkg/apis/mesh/v1alpha1/types.go Outdated
// Supports hours (h), days (d), weeks (w), or months (m)
// It is a wrapper around time.Duration which supports correct marshaling to YAML and JSON
// +optional
// +kubebuilder:default="1m"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Shouldn't default be updated?

(1m == 1 month, but feel free to use a different default if you think its more sane)

Comment thread pkg/hub/mesh/controller.go Outdated
"sigs.k8s.io/controller-runtime/pkg/reconcile"

meshv1alpha1 "github.com/stolostron/multicluster-mesh-addon/pkg/apis/mesh/v1alpha1"
msav1v1beta1 "open-cluster-management.io/managed-serviceaccount/apis/authentication/v1beta1"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
msav1v1beta1 "open-cluster-management.io/managed-serviceaccount/apis/authentication/v1beta1"
msav1beta1 "open-cluster-management.io/managed-serviceaccount/apis/authentication/v1beta1"

Did you mean this?

Comment thread pkg/hub/mesh/controller.go Outdated
}

// Create ManagedServiceAccount resources for each managed cluster
msaList := &unstructured.UnstructuredList{}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why use unstructured?

You should register the scheme (in main.go) and use the typed structure directly

Comment thread pkg/hub/mesh/controller.go Outdated
})

for _, cluster := range clusters {
if err := r.List(ctx, msaList, client.InNamespace(cluster.Name),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why not simply use client.Get?

e.g.

  existing := &msav1beta1.ManagedServiceAccount{}
  if err := r.Get(ctx, types.NamespacedName{Name: msaName, Namespace: cluster.Name}, existing) ...

Comment thread pkg/hub/mesh/controller.go Outdated
}

// CreateManagedServiceAccount creates a ManagedServiceAccount resource for a cluster in the ClusterSet
func (r *Reconciler) CreateManagedServiceAccount(ctx context.Context, cluster clusterv1.ManagedCluster, mesh *meshv1alpha1.MultiClusterMesh) error {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
func (r *Reconciler) CreateManagedServiceAccount(ctx context.Context, cluster clusterv1.ManagedCluster, mesh *meshv1alpha1.MultiClusterMesh) error {
func (r *Reconciler) createManagedServiceAccount(ctx context.Context, cluster clusterv1.ManagedCluster, mesh *meshv1alpha1.MultiClusterMesh) error {

No reason to make it public

Comment thread test/integration/controller_test.go Outdated
util.CreateMultiClusterMesh(ctx, k8sClient, meshName, testNs, testClusterSet, meshv1alpha1.OperatorConfig{})
awaitReconcileFinished()

list := &unstructured.UnstructuredList{}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Here also, no need to use unstructured, especially since you registered the type in the test schema

Comment thread test/integration/controller_test.go Outdated

specData := map[string]interface{}{
"rotation": map[string]interface{}{
"validity": "24h0m",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You set it but didn't check it.

Also I think setting custom fields is better checked in a separate test (It)

Comment thread pkg/hub/mesh/controller.go Outdated

msa := &msav1v1beta1.ManagedServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-%s", cluster.Name, mesh.Name), // Naming convention: <cluster-name>-<mesh-name>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think a better convention would be something like <mesh-namespace>-<mesh-name>-istio-reader

Either way cluster name is stuttering since the ns is already the cluster name in this case.

We can further discuss naming convention on #72 as well.

Comment thread test/integration/controller_test.go Outdated
Expect(k8sClient.List(context.Background(), list, client.InNamespace(cluster2))).To(Succeed())
})

When("the ManagedServiceAccount resource exists", func() {

Copy link
Copy Markdown
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 makes sense as an integration test.

We don't expect MSA resource to be created by the user externally, which is what this test implies.

We expect them to exist in concurrent reconciliation of the same mesh, in which case the correct tests should test that mesh is updated.

Comment thread test/integration/controller_test.go Outdated
Comment on lines +255 to +256
Expect(k8sClient.List(context.Background(), list, client.InNamespace(cluster1))).To(Succeed())
Expect(k8sClient.List(context.Background(), list, client.InNamespace(cluster2))).To(Succeed())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These don't really test that the MSA were created as expected.

For all we know, they might've been created by something else, or by the controller but not as we expected them

yxun added 2 commits May 21, 2026 07:06
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
yxun added 2 commits May 26, 2026 09:24
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
@yxun yxun marked this pull request as draft June 1, 2026 12:36
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
yxun added 2 commits June 4, 2026 14:59
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
@yxun yxun marked this pull request as ready for review June 8, 2026 20:42
@yxun yxun changed the title Implement ManagedServiceAccount resources creation Implement ManagedServiceAccount resources reconciliation and tests Jun 8, 2026
yxun added 5 commits June 8, 2026 17:04
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
Signed-off-by: Yuanlin Xu <yuanlin.xu@redhat.com>
@yxun

yxun commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator Author

/hold

@yxun

yxun commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator Author

This PR has been broken into the following four small PRs. All following comments will be addressed in the small PRs.
I will close this original one when all the small PRs are merged.

https://github.com/stolostron/multicluster-mesh-addon/pull/ ? (pending for resolving pr 130 first)

@openshift-ci

openshift-ci Bot commented Jun 16, 2026

Copy link
Copy Markdown

PR needs rebase.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

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.

2 participants