Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 15 additions & 18 deletions pkg/hub/controllers/cluster/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -507,27 +507,24 @@ func (r *Reconciler) updateDashboardCreds(ctx context.Context, cr *hubv1alpha1.C
log := logger.FromContext(ctx)
log.Info("Updating kubernetes dashboard creds")

sa := &corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: KubeSliceDashboardSA,
Namespace: controllers.ControlPlaneNamespace,
},
}
if err := r.MeshClient.Get(ctx, types.NamespacedName{Name: sa.Name, Namespace: controllers.ControlPlaneNamespace}, sa); err != nil {
log.Error(err, "Error getting service account")
secretList := &corev1.SecretList{}
if err := r.MeshClient.List(ctx, secretList, client.InNamespace(controllers.ControlPlaneNamespace)); err != nil {
log.Error(err, "Error listing secrets for dashboard credentials")
return err
}

if len(sa.Secrets) == 0 {
err := fmt.Errorf("ServiceAccount has no secret")
log.Error(err, "Error getting service account secret")
return err
var secret *corev1.Secret
for i := range secretList.Items {
s := &secretList.Items[i]
if s.Type == corev1.SecretTypeServiceAccountToken &&
s.Annotations[corev1.ServiceAccountNameKey] == KubeSliceDashboardSA {
secret = s
break
}
}

secret := &corev1.Secret{}
err := r.MeshClient.Get(ctx, types.NamespacedName{Name: sa.Secrets[0].Name, Namespace: controllers.ControlPlaneNamespace}, secret)
if err != nil {
log.Error(err, "Error getting service account's secret")
if secret == nil {
err := fmt.Errorf("no token secret found for ServiceAccount %s", KubeSliceDashboardSA)
log.Error(err, "Error getting dashboard token secret")
return err
}

Expand Down Expand Up @@ -556,7 +553,7 @@ func (r *Reconciler) updateDashboardCreds(ctx context.Context, cr *hubv1alpha1.C
Data: secretData,
}
log.Info("creating secret on hub", "hubSecret", hubSecret.Name)
err = r.Create(ctx, &hubSecret)
err := r.Create(ctx, &hubSecret)
if apierrors.IsAlreadyExists(err) {
err = r.Update(ctx, &hubSecret)
}
Expand Down
81 changes: 81 additions & 0 deletions pkg/hub/controllers/cluster/reconciler_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cluster
import (
"context"
"errors"
"os"
"testing"
"time"

Expand Down Expand Up @@ -408,6 +409,86 @@ func TestUpdateNetworkStatus(t *testing.T) {
}
}

func Test_updateDashboardCreds(t *testing.T) {
tests := []struct {
name string
ctx context.Context
loadMocks MockClientCall
err error
}{
{
"no token secret found for dashboard SA — returns error",
context.WithValue(context.Background(), types.NamespacedName{}, testClusterObj),
func(clientMock *utilmock.MockClient, ctx context.Context) {
clientMock.On("List",
mock.IsType(ctx),
mock.IsType(&corev1.SecretList{}),
mock.Anything,
).Return(nil) // empty list — no matching secret
},
errors.New("no token secret found for ServiceAccount kubeslice-kubernetes-dashboard"),
},
{
"token secret found via annotation — credentials updated successfully",
context.WithValue(context.Background(), types.NamespacedName{}, testClusterObj),
func(clientMock *utilmock.MockClient, ctx context.Context) {
clientMock.On("List",
mock.IsType(ctx),
mock.IsType(&corev1.SecretList{}),
mock.Anything,
).Return(nil).Run(func(args mock.Arguments) {
list := args.Get(1).(*corev1.SecretList)
list.Items = []corev1.Secret{{
ObjectMeta: metav1.ObjectMeta{
Name: "kubeslice-kubernetes-dashboard-token",
Namespace: ControlPlaneNamespace,
Annotations: map[string]string{
corev1.ServiceAccountNameKey: KubeSliceDashboardSA,
},
},
Type: corev1.SecretTypeServiceAccountToken,
Data: map[string][]byte{
"token": []byte("test-token"),
"ca.crt": []byte("test-ca"),
},
}}
})
clientMock.On("Create",
mock.IsType(ctx),
mock.IsType(&corev1.Secret{}),
mock.IsType([]k8sclient.CreateOption(nil)),
).Return(nil)
clientMock.On("Update",
mock.IsType(ctx),
mock.IsType(&hubv1alpha1.Cluster{}),
mock.IsType([]k8sclient.UpdateOption(nil)),
).Return(nil)
},
nil,
},
}

os.Setenv("CLUSTER_NAME", "test-cluster")
os.Setenv("HUB_PROJECT_NAMESPACE", "kubeslice-avesha")
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ctx := test.ctx
clientMock := utilmock.NewClient()
mf, _ := metrics.NewMetricsFactory(prometheus.NewRegistry(), metrics.MetricsFactoryOptions{})
r := NewReconciler(clientMock, clientMock, nil, mf)
test.loadMocks(clientMock, ctx)
err := r.updateDashboardCreds(ctx, &hubv1alpha1.Cluster{})
if test.err != nil && err != nil {
if test.err.Error() != err.Error() {
t.Error("Expected error:", test.err, " but got ", err)
}
} else if test.err != err {
t.Error("Expected error:", test.err, " but got ", err)
}
})
}
}

func Test_isNsmInstalled(t *testing.T) {
tests := []struct {
name string
Expand Down