worker/api/stack.go (136 lines of code) (raw):
// Copyright (c) 2022 EPAM Systems, Inc.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package api
import (
"errors"
"fmt"
"io"
"log"
"net/http"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"github.com/agilestacks/stack-disposer/disposer/config"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/gorilla/mux"
)
func UndeployStackHandler(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
args := make([]string, 0)
verbose := false
verbose, _ = strconv.ParseBool(query.Get("verbose"))
if verbose {
args = append(args, "--verbose")
}
commit := query.Get("commit")
vars := mux.Vars(r)
sandboxId := vars["sandboxId"]
stackId := vars["stackId"]
log.Println("Undeploying", stackId)
dir := filepath.Join(config.GitDir, stackId)
err := checkout(dir, commit)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
stackDir := filepath.Join(dir, sandboxId)
_, err = os.Stat(stackDir)
if os.IsNotExist(err) {
log.Printf("Sandbox type '%s' not found", sandboxId)
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(fmt.Sprint(err)))
return
}
_, err = os.Stat(filepath.Join(stackDir, "hub.yaml"))
if os.IsNotExist(err) {
log.Printf("File hub.yaml for sandbox type '%s' not found", sandboxId)
w.WriteHeader(http.StatusNotFound)
return
}
err = undeploy(stackDir, stackId, args...)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent)
}
func undeploy(stackDir string, stackId string, args ...string) error {
subCommands := make([]string, 0)
subCommands = append(subCommands, "stack", "init", stackId, "--force")
subCommands = append(subCommands, args...)
err := hubCommand(stackDir, subCommands...)
if err != nil {
log.Println(err)
log.Println("Failed to initialize stack", stackId)
return err
}
err = hubCommand(stackDir, "stack", "undeploy")
if err != nil {
log.Println(err)
log.Println("Failed to undeploy stack", stackId)
return err
}
log.Printf("Stack %s is undeployed", stackId)
return nil
}
func hubCommand(dir string, args ...string) error {
log.Printf("Execute: hub %s at %s", strings.Join(args, " "), dir)
cmd := exec.Command("hub", args...)
cmd.Dir = dir
if config.Verbose {
cmd.Stdout = log.Writer()
cmd.Stderr = log.Writer()
}
err := cmd.Run()
if err != nil {
return err
}
return nil
}
func checkout(dir string, commit string) error {
log.Println("Prepare sandboxes repository", dir, commit)
if !plumbing.IsHash(commit) {
return errors.New(fmt.Sprint("invalid commit hash", commit))
}
var progress io.Writer
if config.Verbose {
progress = log.Writer()
}
repo, err := git.PlainClone(dir, false, &git.CloneOptions{
URL: config.GitUrl,
Progress: progress,
})
if err != nil {
repo, err = git.PlainOpen(dir)
if err != nil {
log.Println("Unable to open git repo:", err)
return err
}
}
refHash := plumbing.NewHash(commit)
if len(commit) <= 0 {
ref, err := repo.Head()
if err != nil {
log.Println("Unable to retrive ref to HEAD of git repo:", err)
return err
}
refHash = ref.Hash()
}
wt, err := repo.Worktree()
if err != nil {
log.Println("Unable to read work tree of git repo:", err)
return err
}
log.Println("Checkout", refHash)
err = wt.Checkout(&git.CheckoutOptions{
Hash: refHash,
Force: true,
Keep: false,
})
if err != nil {
log.Println("Unable to checkout git repo:", err)
return err
}
return nil
}