package controllers import ( "context" "errors" "fmt" "log" "strings" "github.com/joho/godotenv" "git.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/kube" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" ctrl "sigs.k8s.io/controller-runtime" ) type Environemnt struct { Controller ctrl.Manager UserID string Data *EnvironemntData Token string } type EnvironemntData struct { Name string Provider string Kubernetes string HetznerData HetznerData } type HetznerData struct { ServerLocation string ServerType string } func (e *EnvironemntData) buildVars() string { vars := fmt.Sprintf("SP_PROVIDER=%s\nSP_KUBERNETES=%s", e.providerFmt(), e.kubernetesFmt()) return vars } func (e *EnvironemntData) providerFmt() string { res := strings.Replace(e.Provider, "PROVIDER_", "", -1) return strings.ToLower(res) } func (e *EnvironemntData) kubernetesFmt() string { res := strings.Replace(e.Kubernetes, "KUBERNETES_", "", -1) return strings.ToLower(res) } func (env *Environemnt) isNsVerified(ctx context.Context) error { client := env.Controller.GetClient() ns := &corev1.Namespace{} if err := client.Get(ctx, types.NamespacedName{Name: env.UserID}, ns); err != nil { return err } val, ok := ns.GetLabels()["email-verified"] if !ok || val == "false" { return errors.New("User email is not verified, can't create an new env") } return nil } // Create environment should create a new configmap in the user's namespace // using a token that belongs to the user. func (env *Environemnt) Create(ctx context.Context) error { if err := env.isNsVerified(ctx); err != nil { log.Println("Can't verify ns") return err } env.Controller.GetClient() conf := &rest.Config{ Host: "https://kubernetes.default.svc.cluster.local:443", BearerToken: env.Token, TLSClientConfig: rest.TLSClientConfig{ Insecure: true, }, } controller, err := ctrl.NewManager(conf, ctrl.Options{}) if err != nil { return err } obj := corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: env.Data.Name, Namespace: env.UserID, Labels: map[string]string{ "component": "bootstrap", "kind": "environment", }, }, Data: map[string]string{ "vars": env.Data.buildVars(), }, } if err := kube.Create(ctx, controller.GetClient(), &obj, false); err != nil { return err } return nil } func (env *Environemnt) Delete(ctx context.Context) error { env.Controller.GetClient() conf := &rest.Config{ Host: "https://kubernetes.default.svc.cluster.local:443", BearerToken: env.Token, TLSClientConfig: rest.TLSClientConfig{ Insecure: true, }, } controller, err := ctrl.NewManager(conf, ctrl.Options{}) if err != nil { return err } obj := corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: env.Data.Name, Namespace: env.UserID, Labels: map[string]string{ "component": "bootstrap", }, }, Data: map[string]string{ "vars": env.Data.buildVars(), }, } if err := kube.Delete(ctx, controller.GetClient(), &obj, false); err != nil { return err } return nil } func (env *Environemnt) ListEnvs(ctx context.Context) ([]string, error) { env.Controller.GetClient() conf := &rest.Config{ Host: "https://kubernetes.default.svc.cluster.local:443", BearerToken: env.Token, TLSClientConfig: rest.TLSClientConfig{ Insecure: true, }, } clientset, err := kubernetes.NewForConfig(conf) if err != nil { return []string{}, err } secrets, err := clientset.CoreV1().ConfigMaps(env.UserID).List(ctx, metav1.ListOptions{LabelSelector: "kind=environment"}) if err != nil { return []string{}, err } result := []string{} log.Println(secrets) for _, env := range secrets.Items { result = append(result, env.Name) } return result, nil } func (env *Environemnt) Get(ctx context.Context) error { env.Controller.GetClient() conf := &rest.Config{ Host: "https://kubernetes.default.svc.cluster.local:443", BearerToken: env.Token, TLSClientConfig: rest.TLSClientConfig{ Insecure: true, }, } clientset, err := kubernetes.NewForConfig(conf) if err != nil { return err } envData, err := clientset.CoreV1().ConfigMaps(env.UserID).Get(ctx, env.Data.Name, metav1.GetOptions{}) if err != nil { return err } res, err := godotenv.Unmarshal(envData.Data["vars"]) if err != nil { return err } env.Data.Provider = res["SP_PROVIDER"] env.Data.Kubernetes = res["SP_KUBERNETES"] return nil }