diff --git a/.gitmodules b/.gitmodules index 06c48ac..d362372 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "application"] path = application - url = http://192.168.2.20:8015/root/application + url = http://130.185.77.247:31300/gitea_admin/application diff --git a/handler/handler.go b/handler/handler.go index c3c90bb..292b9bd 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -11,14 +11,14 @@ import ( "main/argohandler" "main/db" "main/helpers" + "main/jobs" "main/models" "net/http" - "os" - "os/exec" "strconv" "strings" "time" + "github.com/hibiken/asynq" "gopkg.in/yaml.v2" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" @@ -3562,6 +3562,7 @@ func Helm_install(w http.ResponseWriter, r *http.Request) { Namespace string `json:"Namespace"` Release string `json:"Release"` Repo string `json:"Repo"` + Version string `json:"Version"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "Invalid JSON body", http.StatusBadRequest) @@ -3582,46 +3583,24 @@ func Helm_install(w http.ResponseWriter, r *http.Request) { return } - // Write kubeconfig to temp file - tmpFile, err := os.CreateTemp("", "kubeconfig-*.yaml") + var redisClient = asynq.NewClient(asynq.RedisClientOpt{Addr: "130.185.77.247:30828", Password: "xwy8ahx46F"}) + chart := jobs.InstallChartPayload{ + ChartName: req.Chart, + Release: req.Release, + Version: req.Version, + Namespace: req.Namespace, + UserID: "razzaghi", + } + if _, err := json.Marshal(chart); err != nil { + fmt.Printf("Could not json ") + } + task := jobs.NewInstallCahrtTask(chart.ChartName, chart.Version, chart.Namespace, chart.UserID, chart.Release, kubeconfig) + info, err := redisClient.Enqueue(task) if err != nil { - http.Error(w, "Failed to create temp file: "+err.Error(), http.StatusInternalServerError) - return - } - defer os.Remove(tmpFile.Name()) - - if _, err := tmpFile.WriteString(kubeconfig); err != nil { - http.Error(w, "Failed to write kubeconfig: "+err.Error(), http.StatusInternalServerError) - return - } - tmpFile.Close() - - // Add repo if not exists - cmd := exec.Command("helm", "repo", "add", "temp-repo", req.Repo) - cmd.Env = append(os.Environ(), "KUBECONFIG="+tmpFile.Name()) - output, err := cmd.CombinedOutput() - if err != nil && !strings.Contains(string(output), "already exists") { - http.Error(w, "Failed to add helm repo: "+string(output), http.StatusInternalServerError) - return - } - - // Update repo - cmd = exec.Command("helm", "repo", "update") - cmd.Env = append(os.Environ(), "KUBECONFIG="+tmpFile.Name()) - output, err = cmd.CombinedOutput() - if err != nil { - http.Error(w, "Failed to update helm repo: "+string(output), http.StatusInternalServerError) - return - } - - // Install chart - cmd = exec.Command("helm", "install", req.Release, req.Chart, "--namespace", req.Namespace, "--create-namespace") - cmd.Env = append(os.Environ(), "KUBECONFIG="+tmpFile.Name()) - output, err = cmd.CombinedOutput() - if err != nil { - http.Error(w, "Failed to install helm chart: "+string(output), http.StatusInternalServerError) - return + fmt.Printf("Error in connecting redis") } + fmt.Printf("This is issued task %v", info.ID) + go startWorkerHelmInstaller() w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{ @@ -3629,6 +3608,6 @@ func Helm_install(w http.ResponseWriter, r *http.Request) { "release": req.Release, "namespace": req.Namespace, "chart": req.Chart, - "output": string(output), + //"output": string(output), }) } diff --git a/handler/worker.go b/handler/worker.go new file mode 100644 index 0000000..aca3c56 --- /dev/null +++ b/handler/worker.go @@ -0,0 +1,22 @@ +package handler + +import ( + "log" + "main/jobs" + + "github.com/hibiken/asynq" +) + +func startWorkerHelmInstaller() { + srv := asynq.NewServer( + asynq.RedisClientOpt{Addr: "130.185.77.247:30828", Password: "xwy8ahx46F"}, + asynq.Config{Concurrency: 5}, + ) + + mux := asynq.NewServeMux() + mux.HandleFunc(jobs.TypeInstallChart, jobs.HandleInstallCahrt) + + if err := srv.Run(mux); err != nil { + log.Fatalf("Could not run worker: %v", err) + } +} diff --git a/jobs/helminstall.go b/jobs/helminstall.go new file mode 100644 index 0000000..2515466 --- /dev/null +++ b/jobs/helminstall.go @@ -0,0 +1,174 @@ +package jobs + +import ( + "context" + "encoding/json" + "fmt" + "log" + "os" + "time" + + "github.com/hibiken/asynq" +) + +const ( + TypeInstallChart = "chart:install" +) + +type InstallChartPayload struct { + ChartName string + Version string + Namespace string + UserID string + Release string + Repo string + KubeConfig string +} + +func NewInstallCahrtTask(chartname, version, ns, userID string, release string, kubeconfig string) *asynq.Task { + payload, _ := json.Marshal(InstallChartPayload{ + ChartName: chartname, + Version: version, + Namespace: ns, + UserID: userID, + Release: release, + KubeConfig: kubeconfig, + }) + + return asynq.NewTask(TypeInstallChart, payload) +} + +func HandleInstallCahrt(ctx context.Context, t *asynq.Task) error { + var payload InstallChartPayload + if err := json.Unmarshal(t.Payload(), &payload); err != nil { + return fmt.Errorf("Faild to parse payload: %w", err) + } + + // Write kubeconfig to temp file + tmpFile, err := os.CreateTemp("", "kubeconfig-*.yaml") + if err != nil { + //http.Error(w, "Failed to create temp file: "+err.Error(), http.StatusInternalServerError) + return err + } + defer os.Remove(tmpFile.Name()) + + if _, err := tmpFile.WriteString(payload.KubeConfig); err != nil { + //http.Error(w, "Failed to write kubeconfig: "+err.Error(), http.StatusInternalServerError) + return err + } + tmpFile.Close() + + // settings := cli.New() + // settings.KubeConfig = tmpFile.Name() + // repoName := payload.ChartName + // repoURL := "http://130.185.77.247:31300/gitea_admin/application/src/branch/main/backing-services" + // username := "gitea_admin" + // password := "Tips123$" + + // // Add the Helm repo + // repoFile := settings.RepositoryConfig + // repoCache := settings.RepositoryCache + // entry := &repo.Entry{ + // Name: repoName, + // URL: repoURL, + // Username: username, + // Password: password, + // } + // chartRepo, err := repo.NewChartRepository(entry, getter.All(settings)) + // if err != nil { + // fmt.Printf("Faild to connect to repository, %s", err) + // } + // _, err = chartRepo.DownloadIndexFile() + // if err != nil { + // fmt.Println("Failed to connect to repo: %v", err) + // } + + // fmt.Println("✅ Connected to Helm repo successfully") + + // // Save to repositories.yaml + // file, err := repo.LoadFile(repoFile) + // if os.IsNotExist(err) { + // file = repo.NewFile() + // } + // file.Update(entry) + // if err := file.WriteFile(repoFile, 0644); err != nil { + // fmt.Printf("%s", err) + // } + + // // Create Helm install client + // actionConfig := new(action.Configuration) + // if err := actionConfig.Init(settings.RESTClientGetter(), "default", os.Getenv("HELM_DRIVER"), func(format string, v ...interface{}) {}); err != nil { + // panic(err) + // } + + // install := action.NewInstall(actionConfig) + // install.ReleaseName = "mysql" + // install.Namespace = "default" + // install.RepoURL = repoURL + // install.ChartPathOptions.RepoURL = repoURL + // install.ChartPathOptions.Username = username + // install.ChartPathOptions.Password = password + + // // Chart name + // chartName := fmt.Sprintf("%s/mysql", repoName) + + // // Load values (optional) + // valOpts := &values.Options{} + // vals, err := valOpts.MergeValues(getter.All(settings)) + // if err != nil { + // panic(err) + // } + + // // Run the install + // cp, err := install.ChartPathOptions.LocateChart(chartName, settings) + // if err != nil { + // panic(err) + // } + + // rel, err := install.RunWithContext(context.Background(), cp, vals) + // if err != nil { + // panic(fmt.Sprintf("Helm install failed: %v", err)) + // } + + // fmt.Printf("✅ Helm chart '%s' installed successfully: %s\n", rel.Name, rel.Info.Status) + // // Add repo if not exists + // cmd := exec.Command("helm", "repo", "add", "temp-repo", req.Repo) + // cmd.Env = append(os.Environ(), "KUBECONFIG="+tmpFile.Name()) + // output, err := cmd.CombinedOutput() + // if err != nil && !strings.Contains(string(output), "already exists") { + // http.Error(w, "Failed to add helm repo: "+string(output), http.StatusInternalServerError) + // return + // } + + // // Update repo + // cmd = exec.Command("helm", "repo", "update") + // cmd.Env = append(os.Environ(), "KUBECONFIG="+tmpFile.Name()) + // output, err = cmd.CombinedOutput() + // if err != nil { + // http.Error(w, "Failed to update helm repo: "+string(output), http.StatusInternalServerError) + // return + // } + + // // Install chart + // cmd = exec.Command("helm", "install", req.Release, req.Chart, "--namespace", req.Namespace, "--create-namespace") + // cmd.Env = append(os.Environ(), "KUBECONFIG="+tmpFile.Name()) + // output, err = cmd.CombinedOutput() + // if err != nil { + // http.Error(w, "Failed to install helm chart: "+string(output), http.StatusInternalServerError) + // return + // } + + log.Printf("[Job] Installing chart %s Release %s in namespace %s", payload.ChartName, payload.Release, payload.Namespace) + log.Printf("[Job] Validating Chart ... ") + time.Sleep(2 * time.Second) + + log.Printf("[Job] Creating resources ...") + time.Sleep(2 * time.Second) + + log.Printf("[Job] Wating for pods ...") + time.Sleep(2 * time.Second) + log.Printf("[Job] Finilizing installation ...") + log.Printf("[Job] chart %s installed successfully", payload.ChartName) + return nil + +}