package infrastructure import ( "context" "encoding/json" "errors" "fmt" "oc-datacenter/conf" authv1 "k8s.io/api/authentication/v1" v1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" ) type KubernetesService struct { Set *kubernetes.Clientset } func NewKubernetesService() (Infrastructure, error) { config := &rest.Config{ Host: conf.GetConfig().KubeHost + ":" + conf.GetConfig().KubePort, TLSClientConfig: rest.TLSClientConfig{ CAData: []byte(conf.GetConfig().KubeCA), CertData: []byte(conf.GetConfig().KubeCert), KeyData: []byte(conf.GetConfig().KubeData), }, } // Create clientset clientset, err := kubernetes.NewForConfig(config) fmt.Println("NewForConfig", clientset, err) if err != nil { return nil, errors.New("Error creating Kubernetes client: " + err.Error()) } if clientset == nil { return nil, errors.New("Error creating Kubernetes client: clientset is nil") } return &KubernetesService{ Set: clientset, }, nil } func (k *KubernetesService) CreateNamespace(ctx context.Context, ns string) error { // Define the namespace namespace := &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: ns, }, } // Create the namespace fmt.Println("Creating namespace...", k.Set) if _, err := k.Set.CoreV1().Namespaces().Create(ctx, namespace, metav1.CreateOptions{}); err != nil { return errors.New("Error creating namespace: " + err.Error()) } fmt.Println("Namespace created successfully!") return nil } func (k *KubernetesService) CreateServiceAccount(ctx context.Context, ns string) error { // Create the ServiceAccount object serviceAccount := &v1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: "sa-" + ns, Namespace: ns, }, } // Create the ServiceAccount in the specified namespace _, err := k.Set.CoreV1().ServiceAccounts(ns).Create(ctx, serviceAccount, metav1.CreateOptions{}) if err != nil { return errors.New("Failed to create ServiceAccount: " + err.Error()) } return nil } func (k *KubernetesService) CreateRole(ctx context.Context, ns string, role string, groups [][]string, resources [][]string, verbs [][]string) error { // Create the Role object if len(groups) != len(resources) || len(resources) != len(verbs) { return errors.New("Invalid input: groups, resources, and verbs must have the same length") } rules := []rbacv1.PolicyRule{} for i, group := range groups { rules = append(rules, rbacv1.PolicyRule{ APIGroups: group, Resources: resources[i], Verbs: verbs[i], }) } r := &rbacv1.Role{ ObjectMeta: metav1.ObjectMeta{ Name: role, Namespace: ns, }, Rules: rules, } // Create the Role in the specified namespace _, err := k.Set.RbacV1().Roles(ns).Create(ctx, r, metav1.CreateOptions{}) if err != nil { return errors.New("Failed to create Role: " + err.Error()) } return nil } func (k *KubernetesService) CreateRoleBinding(ctx context.Context, ns string, roleBinding string, role string) error { // Create the RoleBinding object rb := &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ Name: roleBinding, Namespace: ns, }, Subjects: []rbacv1.Subject{ { Kind: "ServiceAccount", Name: "sa-" + ns, Namespace: ns, }, }, RoleRef: rbacv1.RoleRef{ Kind: "Role", Name: role, APIGroup: "rbac.authorization.k8s.io", }, } // Create the RoleBinding in the specified namespace _, err := k.Set.RbacV1().RoleBindings(ns).Create(ctx, rb, metav1.CreateOptions{}) if err != nil { return errors.New("Failed to create RoleBinding: " + err.Error()) } return nil } func (k *KubernetesService) DeleteNamespace(ctx context.Context, ns string) error { // Delete the namespace if err := k.Set.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{}); err != nil { return errors.New("Error deleting namespace: " + err.Error()) } fmt.Println("Namespace deleted successfully!") return nil } func (k *KubernetesService) GetToken(ctx context.Context, ns string, duration int) (string, error) { // Define TokenRequest (valid for 1 hour) d := int64(duration) tokenRequest := &authv1.TokenRequest{ Spec: authv1.TokenRequestSpec{ ExpirationSeconds: &d, // 1 hour validity }, } // Generate the token token, err := k.Set.CoreV1(). ServiceAccounts(ns). CreateToken(ctx, "sa-"+ns, tokenRequest, metav1.CreateOptions{}) if err != nil { return "", errors.New("Failed to create token for ServiceAccount: " + err.Error()) } return token.Status.Token, nil } func (k *KubernetesService) GetTargets(ctx context.Context) ([]string,error){ var listTargets []string resp, err := k.Set.RESTClient(). Get(). AbsPath("/apis/multicluster.admiralty.io/v1alpha1/targets"). DoRaw(ctx) // from https://stackoverflow.com/questions/60764908/how-to-access-kubernetes-crd-using-client-go if err != nil { fmt.Println("TODO : handle the error generated when contacting kube API") fmt.Println("Error from k8s API : ", err) return nil,err } fmt.Println(string(resp)) var targetDict map[string]interface{} err = json.Unmarshal(resp,&targetDict) if err != nil { fmt.Println("TODO: handle the error when unmarshalling k8s API response") return nil, err } b, _ := json.MarshalIndent(targetDict,""," ") fmt.Println(string(b)) data := targetDict["items"].([]interface{}) for _, item := range data { var metadata metav1.ObjectMeta item := item.(map[string]interface{}) byteMetada, err := json.Marshal(item["metadata"]) if err != nil { fmt.Println("Error while Marshalling metadata field") return nil,err } err = json.Unmarshal(byteMetada,&metadata) if err != nil { fmt.Println("Error while Unmarshalling metadata field to the library object") return nil,err } listTargets = append(listTargets, metadata.Name) } // parse targets to retrieve the info we need // fmt.Println(targetDict) return listTargets,nil }