From 920a25a02b5d1deacbdece7d233c9f4af41d4f13 Mon Sep 17 00:00:00 2001 From: redpinecube Date: Mon, 4 Aug 2025 10:39:26 -0500 Subject: [PATCH 1/3] implement : VerifyControlPlaneOnHostingCluster Signed-off-by: redpinecube --- pkg/kubeconfig/extensions.go | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/pkg/kubeconfig/extensions.go b/pkg/kubeconfig/extensions.go index 16bb0468..c223b538 100644 --- a/pkg/kubeconfig/extensions.go +++ b/pkg/kubeconfig/extensions.go @@ -19,6 +19,10 @@ package kubeconfig import ( "encoding/json" "fmt" + tenancyv1alpha1 "github.com/kubestellar/kubeflex/api/v1alpha1" + "github.com/kubestellar/kubeflex/cmd/kflex/common" + "github.com/kubestellar/kubeflex/pkg/client" + "k8s.io/client-go/tools/clientcmd" "time" corev1 "k8s.io/api/core/v1" @@ -234,12 +238,32 @@ func CheckHostingClusterContextName(kconf clientcmdapi.Config) string { } } -func VerifyControlPlaneOnHostingCluster(kconf clientcmdapi.Config, ctxName string) string { - // TODO: implement actual control plane verification logic - return DiagnosisStatusOK +func VerifyControlPlaneOnHostingCluster(cp common.CP, ctxName string) string { + c, err := client.GetClient(cp.Kubeconfig) + if err != nil { + return DiagnosisStatusCritical + } + + var controlPlanes tenancyv1alpha1.ControlPlaneList + if err := c.List(cp.Ctx, &controlPlanes); err != nil { + return DiagnosisStatusCritical + } + + for _, controlPlane := range controlPlanes.Items { + if controlPlane.Name == ctxName { + return DiagnosisStatusOK + } + } + + return DiagnosisStatusMissing } -func CheckContextScopeKubeflexExtensionSet(kconf clientcmdapi.Config, ctxName string) string { +func CheckContextScopeKubeflexExtensionSet(cp common.CP, ctxName string) string { + kconf, err := clientcmd.LoadFromFile(cp.Kubeconfig) + if err != nil { + return DiagnosisStatusCritical + } + ctx, ok := kconf.Contexts[ctxName] if !ok { return DiagnosisStatusMissing // Context not found @@ -269,7 +293,7 @@ func CheckContextScopeKubeflexExtensionSet(kconf clientcmdapi.Config, ctxName st return DiagnosisStatusWarning } - status := VerifyControlPlaneOnHostingCluster(kconf, ctxName) + status := VerifyControlPlaneOnHostingCluster(cp, ctxName) if status != DiagnosisStatusOK { return status } From 30be101a7f0856b4d145660b5426097aecdacd5a Mon Sep 17 00:00:00 2001 From: redpinecube Date: Mon, 4 Aug 2025 11:01:43 -0500 Subject: [PATCH 2/3] update tests for CheckContextScopeKubeflexExtension Signed-off-by: redpinecube --- pkg/kubeconfig/extensions_test.go | 42 ++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/pkg/kubeconfig/extensions_test.go b/pkg/kubeconfig/extensions_test.go index ba899649..d8ba6ea3 100644 --- a/pkg/kubeconfig/extensions_test.go +++ b/pkg/kubeconfig/extensions_test.go @@ -2,6 +2,9 @@ package kubeconfig import ( "fmt" + "github.com/kubestellar/kubeflex/cmd/kflex/common" + "k8s.io/client-go/tools/clientcmd" + "os" "testing" "k8s.io/apimachinery/pkg/runtime" @@ -206,6 +209,27 @@ func TestCheckHostingClusterContextNameSingle(t *testing.T) { } } +func writeKubeconfigToTempFile(t *testing.T, kconf *api.Config) string { + data, err := clientcmd.Write(*kconf) + if err != nil { + t.Fatalf("failed to serialize kubeconfig: %v", err) + } + + tmpfile, err := os.CreateTemp("", "kubeconfig-*.yaml") + if err != nil { + t.Fatalf("failed to create temp file: %v", err) + } + + if _, err := tmpfile.Write(data); err != nil { + t.Fatalf("failed to write kubeconfig: %v", err) + } + if err := tmpfile.Close(); err != nil { + t.Fatalf("failed to close temp file: %v", err) + } + + return tmpfile.Name() +} + func TestCheckContextScopeKubeflexExtensionSetNoKubeflexExtensions(t *testing.T) { kconf := api.NewConfig() kconf.Clusters["cluster1"] = &api.Cluster{Server: "https://example.com:6443"} @@ -216,7 +240,11 @@ func TestCheckContextScopeKubeflexExtensionSetNoKubeflexExtensions(t *testing.T) } kconf.CurrentContext = "ctx1" - result := CheckContextScopeKubeflexExtensionSet(*kconf, "ctx1") + tmpFile := writeKubeconfigToTempFile(t, kconf) + defer os.Remove(tmpFile) + + cp := common.NewCP(tmpFile) + result := CheckContextScopeKubeflexExtensionSet(cp, "ctx1") if result != DiagnosisStatusMissing { t.Errorf("Expected %s, got %s", DiagnosisStatusMissing, result) } @@ -237,7 +265,11 @@ func TestCheckContextScopeKubeflexExtensionSetNoData(t *testing.T) { } kconf.CurrentContext = "ctx1" - result := CheckContextScopeKubeflexExtensionSet(*kconf, "ctx1") + tmpFile := writeKubeconfigToTempFile(t, kconf) + defer os.Remove(tmpFile) + + cp := common.NewCP(tmpFile) + result := CheckContextScopeKubeflexExtensionSet(cp, "ctx1") if result != DiagnosisStatusCritical { t.Errorf("Expected %s, got %s", DiagnosisStatusCritical, result) } @@ -258,7 +290,11 @@ func TestCheckContextScopeKubeflexExtensionSetPartialData(t *testing.T) { } kconf.CurrentContext = "ctx1" - result := CheckContextScopeKubeflexExtensionSet(*kconf, "ctx1") + tmpFile := writeKubeconfigToTempFile(t, kconf) + defer os.Remove(tmpFile) + + cp := common.NewCP(tmpFile) + result := CheckContextScopeKubeflexExtensionSet(cp, "ctx1") if result != DiagnosisStatusWarning { t.Errorf("Expected %s, got %s", DiagnosisStatusWarning, result) } From e47904d0a30f7466f4a61ae21e1bf6d3adb9931b Mon Sep 17 00:00:00 2001 From: redpinecube Date: Mon, 4 Aug 2025 13:17:18 -0500 Subject: [PATCH 3/3] implement : CountKubeflexControlPlaneContexts Signed-off-by: redpinecube --- pkg/kubeconfig/extensions.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pkg/kubeconfig/extensions.go b/pkg/kubeconfig/extensions.go index c223b538..781e768f 100644 --- a/pkg/kubeconfig/extensions.go +++ b/pkg/kubeconfig/extensions.go @@ -300,3 +300,30 @@ func CheckContextScopeKubeflexExtensionSet(cp common.CP, ctxName string) string return DiagnosisStatusOK } + +func CountKubeflexControlPlaneContexts(kconf clientcmdapi.Config) int { + count := 0 + + for _, ctx := range kconf.Contexts { + ext := ctx.Extensions + if ext == nil { + continue + } + + runtimeObj, ok := ext[ExtensionKubeflexKey] + if !ok { + continue + } + + var extData RuntimeKubeflexExtension + if err := ConvertRuntimeObjectToRuntimeExtension(runtimeObj, &extData); err != nil { + continue + } + + if cpName, ok := extData.Data[ExtensionControlPlaneName]; ok && cpName != "" { + count++ + } + } + + return count +}