2024-05-04 17:48:19 +00:00
|
|
|
package controllers
|
|
|
|
|
|
|
|
import (
|
2024-05-10 09:43:55 +00:00
|
|
|
"bytes"
|
2024-05-04 17:48:19 +00:00
|
|
|
"context"
|
|
|
|
b64 "encoding/base64"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
2024-05-05 18:06:26 +00:00
|
|
|
"strings"
|
2024-05-10 09:43:55 +00:00
|
|
|
"text/template"
|
2024-05-04 17:48:19 +00:00
|
|
|
|
2024-05-06 08:44:08 +00:00
|
|
|
"git.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/helm"
|
2024-05-04 17:48:19 +00:00
|
|
|
"git.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/kube"
|
2024-05-06 08:44:08 +00:00
|
|
|
"git.badhouseplants.net/softplayer/softplayer-backend/internal/types/helmrelease"
|
2024-05-04 17:48:19 +00:00
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"gopkg.in/yaml.v2"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
|
|
"k8s.io/client-go/rest"
|
|
|
|
ctrl "sigs.k8s.io/controller-runtime"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Application struct {
|
|
|
|
Controller ctrl.Manager
|
|
|
|
UserID string
|
|
|
|
Data *ApplicationData
|
|
|
|
Token string
|
|
|
|
}
|
|
|
|
|
|
|
|
type ApplicationData struct {
|
|
|
|
UUID string
|
|
|
|
Name string
|
|
|
|
Description string
|
|
|
|
Application string
|
|
|
|
Version string
|
|
|
|
Environemnt string
|
|
|
|
Config map[string]string
|
|
|
|
RawConfig string
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create environment should create a new configmap in the user's namespace
|
|
|
|
// using a token that belongs to the user.
|
|
|
|
func (app *Application) Create(ctx context.Context) error {
|
|
|
|
app.Data.UUID = uuid.New().String()
|
|
|
|
// if err := app.isNsVerified(ctx); err != nil {
|
|
|
|
// log.Println("Can't verify ns")
|
|
|
|
// return err
|
|
|
|
// }
|
|
|
|
|
|
|
|
app.Controller.GetClient()
|
|
|
|
conf := &rest.Config{
|
|
|
|
Host: "https://kubernetes.default.svc.cluster.local:443",
|
|
|
|
BearerToken: app.Token,
|
|
|
|
TLSClientConfig: rest.TLSClientConfig{
|
|
|
|
Insecure: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
controller, err := ctrl.NewManager(conf, ctrl.Options{})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-05-06 08:44:08 +00:00
|
|
|
helmEntry := helm.NewHelm()
|
|
|
|
release := &helm.ReleaseData{
|
2024-05-04 17:48:19 +00:00
|
|
|
Name: app.Data.Name,
|
|
|
|
Chart: app.Data.Application,
|
|
|
|
Version: app.Data.Version,
|
2024-05-10 10:46:17 +00:00
|
|
|
RepositoryURL: "oci://registry.badhouseplants.net/softplayer/helm",
|
2024-05-04 17:48:19 +00:00
|
|
|
RepositoryKind: "oci",
|
|
|
|
RepositoryName: "softplayer",
|
|
|
|
}
|
2024-05-05 11:32:40 +00:00
|
|
|
goPath := os.TempDir() + "/softplayer"
|
2024-05-04 17:48:19 +00:00
|
|
|
if err := os.MkdirAll(goPath, 0777); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-05-06 08:44:08 +00:00
|
|
|
path, err := helmEntry.PullChart(goPath, release)
|
2024-05-04 17:48:19 +00:00
|
|
|
if err != nil {
|
|
|
|
logrus.Error("0")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cfgSchemaPath, err := os.ReadFile(fmt.Sprintf("%s/%s/config.yaml", goPath, path))
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("yamlFile.Get err #%v ", err)
|
|
|
|
}
|
|
|
|
logrus.Info(string(cfgSchemaPath))
|
|
|
|
cfgSchema := map[string]*helmrelease.PrettyConfigSchema{}
|
|
|
|
err = yaml.Unmarshal(cfgSchemaPath, cfgSchema)
|
|
|
|
if err != nil {
|
|
|
|
logrus.Error("1")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cfg := &helmrelease.HelmRelease{
|
|
|
|
Helm: helmrelease.Helm{
|
|
|
|
Release: app.Data.Name,
|
|
|
|
Chart: helmrelease.Chart{
|
|
|
|
Name: app.Data.Application,
|
|
|
|
Version: app.Data.Version,
|
|
|
|
},
|
|
|
|
Repo: helmrelease.Repo{
|
2024-05-10 10:04:51 +00:00
|
|
|
URL: "oci://registry.badhouseplants.net/softplayer/helm",
|
2024-05-04 17:48:19 +00:00
|
|
|
Type: "oci",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Config: helmrelease.Config{},
|
|
|
|
}
|
|
|
|
if len(app.Data.Config) > 0 {
|
|
|
|
for key, val := range app.Data.Config {
|
|
|
|
value, ok := cfgSchema[key]
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("unsuported config entry: %s", key)
|
|
|
|
}
|
2024-05-10 09:43:55 +00:00
|
|
|
tmpl, err := template.New("prettyconfig").Parse(val)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
var tmplRes bytes.Buffer
|
2024-05-10 10:53:00 +00:00
|
|
|
if err := tmpl.Execute(&tmplRes, app.Data); err != nil {
|
2024-05-10 09:43:55 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-05-04 17:48:19 +00:00
|
|
|
cfg.Config.Pretty = append(cfg.Config.Pretty, helmrelease.PrettyConfig{
|
|
|
|
Key: key,
|
|
|
|
Path: value.Path,
|
2024-05-10 09:43:55 +00:00
|
|
|
Value: tmplRes.String(),
|
2024-05-04 17:48:19 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
} else if len(app.Data.RawConfig) > 0 {
|
|
|
|
cfg.Config.Raw = app.Data.RawConfig
|
|
|
|
}
|
|
|
|
|
|
|
|
cfgYaml, err := yaml.Marshal(cfg)
|
|
|
|
if err != nil {
|
|
|
|
logrus.Error("2")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
logrus.Info(string(cfgYaml))
|
|
|
|
|
2024-05-05 18:06:26 +00:00
|
|
|
formattedName := strings.ToLower(b64.StdEncoding.EncodeToString([]byte(app.Data.Application + app.Data.Name)))
|
2024-05-04 17:48:19 +00:00
|
|
|
appSecret := corev1.Secret{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
2024-05-05 18:06:26 +00:00
|
|
|
Name: formattedName[0:20],
|
2024-05-04 17:48:19 +00:00
|
|
|
Namespace: app.UserID,
|
|
|
|
Labels: map[string]string{
|
|
|
|
"component": "install",
|
|
|
|
"kind": "action",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
StringData: map[string]string{
|
2024-05-10 11:40:38 +00:00
|
|
|
"values.yaml": string(cfgYaml),
|
2024-05-04 17:48:19 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2024-05-05 18:14:07 +00:00
|
|
|
if err := kube.Create(ctx, controller.GetClient(), &appSecret, false); err != nil {
|
2024-05-04 17:48:19 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// func (env *Environemnt) Update(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
|
|
|
|
// }
|
|
|
|
// oldEnv := &Environemnt{
|
|
|
|
// Controller: env.Controller,
|
|
|
|
// UserID: env.UserID,
|
|
|
|
// Token: env.Token,
|
|
|
|
// Data: &ApplicationData{
|
|
|
|
// UUID: env.Data.UUID,
|
|
|
|
// },
|
|
|
|
// }
|
|
|
|
|
|
|
|
// if err := oldEnv.Get(ctx); err != nil {
|
|
|
|
// return err
|
|
|
|
// }
|
|
|
|
|
|
|
|
// // Check whter immutable fields are changed
|
|
|
|
|
|
|
|
// if oldEnv.Data.Provider != env.Data.Provider {
|
|
|
|
// return errors.New("provider can't be changed")
|
|
|
|
// }
|
|
|
|
// if oldEnv.Data.Location != env.Data.Location {
|
|
|
|
// return errors.New("location can't be changed")
|
|
|
|
// }
|
|
|
|
|
|
|
|
// vars, err := env.Data.buildVars()
|
|
|
|
// if err != nil {
|
|
|
|
// return err
|
|
|
|
// }
|
|
|
|
// obj := corev1.ConfigMap{
|
|
|
|
// ObjectMeta: metav1.ObjectMeta{
|
|
|
|
// Name: env.Data.UUID,
|
|
|
|
// Namespace: env.UserID,
|
|
|
|
// Labels: map[string]string{
|
|
|
|
// "component": "bootstrap",
|
|
|
|
// "kind": "environment",
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// Data: map[string]string{
|
|
|
|
// "name": env.Data.Name,
|
|
|
|
// "description": env.Data.Description,
|
|
|
|
// "vars": vars,
|
|
|
|
// },
|
|
|
|
// }
|
|
|
|
|
|
|
|
// if err := kube.Update(ctx, controller.GetClient(), &obj); 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.UUID,
|
|
|
|
// Namespace: env.UserID,
|
|
|
|
// Labels: map[string]string{
|
|
|
|
// "component": "bootstrap",
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// }
|
|
|
|
// if err := kube.Delete(ctx, controller.GetClient(), &obj, false); err != nil {
|
|
|
|
// return err
|
|
|
|
// }
|
|
|
|
|
|
|
|
// return nil
|
|
|
|
// }
|
|
|
|
|
|
|
|
// func (env *Environemnt) ListEnvs(ctx context.Context) ([]*Environemnt, 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 nil, err
|
|
|
|
// }
|
|
|
|
// configmaps, err := clientset.CoreV1().ConfigMaps(env.UserID).List(ctx, metav1.ListOptions{LabelSelector: "kind=environment"})
|
|
|
|
// if err != nil {
|
|
|
|
// return nil, err
|
|
|
|
// }
|
|
|
|
|
|
|
|
// result := []*Environemnt{}
|
|
|
|
// for _, cm := range configmaps.Items {
|
|
|
|
// i := &Environemnt{}
|
|
|
|
// data := &ApplicationData{
|
|
|
|
// UUID: cm.GetName(),
|
|
|
|
// }
|
|
|
|
// i.Token = env.Token
|
|
|
|
// i.UserID = env.UserID
|
|
|
|
// i.Data = data
|
|
|
|
// i.Controller = env.Controller
|
|
|
|
// if err := i.Get(ctx); err != nil {
|
|
|
|
// return nil, err
|
|
|
|
// }
|
|
|
|
// result = append(result, i)
|
|
|
|
// }
|
|
|
|
// 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.UUID, metav1.GetOptions{})
|
|
|
|
// if err != nil {
|
|
|
|
// return err
|
|
|
|
// }
|
|
|
|
|
|
|
|
// res, err := godotenv.Unmarshal(envData.Data["vars"])
|
|
|
|
// if err != nil {
|
|
|
|
// return err
|
|
|
|
// }
|
|
|
|
|
|
|
|
// if val, ok := envData.Data["name"]; ok {
|
|
|
|
// env.Data.Name = val
|
|
|
|
// } else {
|
|
|
|
// env.Data.Name = ""
|
|
|
|
// }
|
|
|
|
|
|
|
|
// if val, ok := envData.Data["description"]; ok {
|
|
|
|
// env.Data.Description = val
|
|
|
|
// } else {
|
|
|
|
// env.Data.Description = ""
|
|
|
|
// }
|
|
|
|
|
|
|
|
// if val, ok := res["SP_PROVIDER"]; ok {
|
|
|
|
// env.Data.Provider = val
|
|
|
|
// } else {
|
|
|
|
// env.Data.Provider = ""
|
|
|
|
// }
|
|
|
|
// if val, ok := res["SP_KUBERNETES"]; ok {
|
|
|
|
// env.Data.Kubernetes = val
|
|
|
|
// } else {
|
|
|
|
// env.Data.Kubernetes = ""
|
|
|
|
// }
|
|
|
|
// if val, ok := res["SP_SERVER_TYPE"]; ok {
|
|
|
|
// env.Data.ServerType = val
|
|
|
|
// } else {
|
|
|
|
// env.Data.ServerType = ""
|
|
|
|
// }
|
|
|
|
// if val, ok := res["SP_SERVER_LOCATION"]; ok {
|
|
|
|
// env.Data.Location = val
|
|
|
|
// } else {
|
|
|
|
// env.Data.Location = ""
|
|
|
|
// }
|
|
|
|
|
|
|
|
// return nil
|
|
|
|
// }
|