@@ -2,17 +2,49 @@ package kubernetes
22
33import (
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+
1543func 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+ }
0 commit comments