Skip to content

Commit 49902de

Browse files
committed
add namespace scanning
1 parent cdbdbe2 commit 49902de

File tree

2 files changed

+106
-27
lines changed

2 files changed

+106
-27
lines changed

cmd/ctrlc/root/sync/kubernetes/kubernetes.go

Lines changed: 101 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,49 @@ package kubernetes
22

33
import (
44
"context"
5-
"encoding/json"
65
"fmt"
6+
"strings"
77

88
"github.com/MakeNowJust/heredoc/v2"
99
"github.com/charmbracelet/log"
10+
"github.com/ctrlplanedev/cli/internal/api"
1011
"github.com/spf13/cobra"
12+
"github.com/spf13/viper"
13+
corev1 "k8s.io/api/core/v1"
1114
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1215
"k8s.io/client-go/kubernetes"
1316
)
1417

18+
func processNamespace(_ context.Context, namespace corev1.Namespace) api.CreateResource {
19+
metadata := map[string]string{}
20+
for key, value := range namespace.Labels {
21+
metadata[fmt.Sprintf("tags/%s", key)] = value
22+
}
23+
24+
metadata["kubernetes/namespace"] = namespace.Name
25+
metadata["namespace/id"] = string(namespace.UID)
26+
metadata["namespace/api-version"] = namespace.APIVersion
27+
metadata["namespace/status"] = string(namespace.Status.Phase)
28+
29+
return api.CreateResource{
30+
Version: "ctrlplane.dev/kubernetes/namespace/v1",
31+
Kind: "KubernetesNamespace",
32+
Name: namespace.Name,
33+
Identifier: string(namespace.UID),
34+
Config: map[string]any{
35+
"id": string(namespace.UID),
36+
"name": namespace.Name,
37+
"status": namespace.Status.Phase,
38+
},
39+
Metadata: metadata,
40+
}
41+
}
42+
1543
func NewSyncKubernetesCmd() *cobra.Command {
44+
var clusterIdentifier string
45+
var providerName string
46+
var clusterName string
47+
1648
cmd := &cobra.Command{
1749
Use: "kubernetes",
1850
Short: "Sync Kubernetes resources on a cluster",
@@ -21,45 +53,93 @@ func NewSyncKubernetesCmd() *cobra.Command {
2153
`),
2254
RunE: func(cmd *cobra.Command, args []string) error {
2355
log.Info("Syncing Kubernetes resources on a cluster")
24-
config, clusterName, err := getKubeConfig()
56+
if clusterIdentifier == "" {
57+
clusterIdentifier = viper.GetString("cluster-identifier")
58+
}
59+
60+
config, configClusterName, err := getKubeConfig()
2561
if err != nil {
2662
return err
2763
}
2864

65+
if clusterName == "" {
66+
clusterName = configClusterName
67+
}
68+
2969
log.Info("Connected to cluster", "name", clusterName)
3070

3171
clientset, err := kubernetes.NewForConfig(config)
3272
if err != nil {
3373
return err
3474
}
3575

36-
pods, err := clientset.CoreV1().Pods("default").List(
37-
context.Background(), metav1.ListOptions{})
76+
namespaces, err := clientset.CoreV1().Namespaces().List(context.Background(), metav1.ListOptions{})
3877
if err != nil {
3978
return err
4079
}
4180

42-
if len(pods.Items) > 0 {
43-
log.Info("First two pods:")
44-
for i := 0; i < min(2, len(pods.Items)); i++ {
45-
pod := pods.Items[i]
46-
podJson, err := json.Marshal(pod)
47-
if err != nil {
48-
log.Error("Failed to marshal pod to JSON", "error", err)
49-
continue
50-
}
51-
fmt.Println(string(podJson))
52-
// log.Info("Pod", "json", string(podJson))
53-
}
54-
} else {
55-
log.Info("No pods found in default namespace")
81+
resources := []api.CreateResource{}
82+
for _, namespace := range namespaces.Items {
83+
resource := processNamespace(context.Background(), namespace)
84+
resources = append(resources, resource)
5685
}
5786

58-
return nil
87+
return upsertToCtrlplane(context.Background(), resources, clusterIdentifier, clusterName, providerName)
5988
},
6089
}
61-
62-
cmd.Flags().String("cluster", "", "The cluster to sync")
90+
cmd.Flags().StringVarP(&providerName, "provider", "p", "", "Name of the resource provider")
91+
cmd.Flags().StringVarP(&clusterIdentifier, "cluster-identifier", "c", "", "The identifier of the parent cluster in ctrlplane (if not provided, will use the CLUSTER_IDENTIFIER environment variable)")
92+
cmd.Flags().StringVarP(&clusterName, "cluster-name", "n", "", "The name of the cluster")
6393

6494
return cmd
6595
}
96+
97+
// upsertToCtrlplane handles upserting resources to Ctrlplane
98+
func upsertToCtrlplane(ctx context.Context, resources []api.CreateResource, clusterIdentifier string, clusterName string, providerName string) error {
99+
apiURL := viper.GetString("url")
100+
apiKey := viper.GetString("api-key")
101+
workspaceId := viper.GetString("workspace")
102+
103+
ctrlplaneClient, err := api.NewAPIKeyClientWithResponses(apiURL, apiKey)
104+
if err != nil {
105+
return fmt.Errorf("failed to create API client: %w", err)
106+
}
107+
108+
clusterResource, _ := ctrlplaneClient.GetResourceByIdentifierWithResponse(ctx, workspaceId, clusterIdentifier)
109+
if clusterResource.JSON200 != nil {
110+
for _, resource := range resources {
111+
for key, value := range clusterResource.JSON200.Metadata {
112+
if strings.HasPrefix(key, "tags/") {
113+
continue
114+
}
115+
if _, exists := resource.Metadata[key]; !exists {
116+
resource.Metadata[key] = value
117+
}
118+
}
119+
resource.Metadata["kubernetes/name"] = clusterResource.JSON200.Name
120+
}
121+
if clusterName == "" {
122+
clusterName = clusterResource.JSON200.Name
123+
}
124+
125+
}
126+
127+
if providerName == "" {
128+
providerName = fmt.Sprintf("kubernetes-cluster-%s", clusterName)
129+
}
130+
131+
log.Info("Using provider name", "provider", providerName)
132+
133+
rp, err := api.NewResourceProvider(ctrlplaneClient, workspaceId, providerName)
134+
if err != nil {
135+
return fmt.Errorf("failed to create resource provider: %w", err)
136+
}
137+
138+
upsertResp, err := rp.UpsertResource(ctx, resources)
139+
if err != nil {
140+
return fmt.Errorf("failed to upsert resources: %w", err)
141+
}
142+
143+
log.Info("Response from upserting resources", "status", upsertResp.Status)
144+
return nil
145+
}

cmd/ctrlc/root/sync/kubernetes/vcluster.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ func generateVclusterMetadata(vcluster find.VCluster, clusterMetadata api.Metada
102102
return metadata, nil
103103
}
104104

105-
func generateVclusterConfig(vcluster find.VCluster, clusterName string, clusterConfig map[string]interface{}) map[string]interface{} {
106-
vclusterConfig := make(map[string]interface{})
105+
func generateVclusterConfig(vcluster find.VCluster, clusterConfig map[string]any) map[string]any {
106+
vclusterConfig := make(map[string]any)
107107
vclusterConfig["name"] = vcluster.Name
108108
vclusterConfig["namespace"] = vcluster.Namespace
109109
vclusterConfig["status"] = getNormalizedVclusterStatus(vcluster.Status)
@@ -142,7 +142,7 @@ func getCreateResourceFromVcluster(vcluster find.VCluster, clusterResource Clust
142142
Kind: generateVclusterKind(clusterResource),
143143
Version: "ctrlplane.dev/kubernetes/cluster/v1",
144144
Metadata: metadata,
145-
Config: generateVclusterConfig(vcluster, clusterResource.Name, clonedParentConfig),
145+
Config: generateVclusterConfig(vcluster, clonedParentConfig),
146146
}
147147

148148
return resource, nil
@@ -249,9 +249,8 @@ func NewSyncVclusterCmd() *cobra.Command {
249249
}
250250
log.Infof("Upserted %d resources", len(resourcesToUpsert))
251251

252-
if err := createResourceRelationshipRule(cmd.Context(), rp, clusterResource); err != nil {
253-
return fmt.Errorf("failed to create resource relationship rule: %w", err)
254-
}
252+
createResourceRelationshipRule(cmd.Context(), rp, clusterResource)
253+
255254
return nil
256255
},
257256
}

0 commit comments

Comments
 (0)