diff --git a/README.md b/README.md index 82a8dff..841ecc7 100644 --- a/README.md +++ b/README.md @@ -31,14 +31,15 @@ Alongside this project, I am developing a seperate web-based dashboard that can - [ ] Configuration - [x] Custom configuration path (passed to the daemon with a flag `--config`) - + - [ ] Daemon instance remembers config path (*so you don't have to pass `--config` everytime you run an ipc command*) - [ ] Daemon listen port (kind of implemented, could be cleaner) - [x] Declarative Server configuration (Create servers in config) + - [ ] More configuration options - [ ] Server management - [x] Create servers - [x] Automatic server binary downloading by version - - [ ] Delete servers + - [x] Delete servers - [x] Start/Stop servers - [ ] Server configuration - [x] Download correct configuration template for version (see availible templates [here](https://git.bellsworne.tech/chrisbell/vssm_config_templates)) diff --git a/daemon.go b/daemon.go index 5de396b..45c6da9 100644 --- a/daemon.go +++ b/daemon.go @@ -45,6 +45,7 @@ func StartDaemon(cfg *AppConfig, configPath string) error { mux.HandleFunc("/instances/command", ds.handleCommand) mux.HandleFunc("/instances/list", ds.handleList) mux.HandleFunc("/instances/logs", ds.handleGetLogs) + mux.HandleFunc("/instances/delete", ds.handleDelete) corsWrappedHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") @@ -389,3 +390,75 @@ func (ds *DaemonServer) handleGetLogs(w http.ResponseWriter, r *http.Request) { http.Error(w, fmt.Sprintf("Failed encoding log matrix: %v", err), http.StatusInternalServerError) } } + +func (ds *DaemonServer) handleDelete(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + + name := r.URL.Query().Get("name") + if name == "" { + http.Error(w, "Missing name parameter", http.StatusBadRequest) + return + } + + purge := false + purgeParam := r.URL.Query().Get("purge") + if purgeParam != "" { + result, err := strconv.ParseBool(purgeParam) + if err != nil { + http.Error(w, "Invalid value for 'purge' parameter", http.StatusBadRequest) + return + } + purge = result + } + + if ds.reloadConfig() != nil { + http.Error(w, "Could not reload config", http.StatusInternalServerError) + return + } + + ds.Lock() + defer ds.Unlock() + + ds.procManager.RLock() + defer ds.procManager.RUnlock() + + _, exists := ds.cfg.Instances[name] + if !exists { + http.Error(w, fmt.Sprintf("Cannot delete instance '%s'; Does not exist.", name), http.StatusBadRequest) + return + } + + if _, running := ds.procManager.ActiveInstances[name]; running { + http.Error(w, fmt.Sprintf("Cannot delete instance '%s'; It is currently running.", name), http.StatusBadRequest) + return + } + + delete(ds.cfg.Instances, name) + + data, err := json.MarshalIndent(ds.cfg, "", " ") + if err != nil { + http.Error(w, fmt.Sprintf("Failed processing profile adjustments: %v", err), http.StatusInternalServerError) + return + } + + if err := os.WriteFile(ds.configPath, data, 0644); err != nil { + http.Error(w, fmt.Sprintf("Failed saving configuration adjustments to disk: %v", err), http.StatusInternalServerError) + return + } + + if purge { + path := filepath.Join(ds.cfg.Storage.InstancesDir, name) + err := os.RemoveAll(path) + if err != nil { + http.Error(w, fmt.Sprintf("Failed to delete instance from disk: %v", err), http.StatusInternalServerError) + return + } + } + + w.WriteHeader(http.StatusOK) + fmt.Fprintf(w, "Successfully deleted instance %s", name) + +} diff --git a/main.go b/main.go index 24be728..abc40a6 100644 --- a/main.go +++ b/main.go @@ -11,6 +11,7 @@ import ( "net/url" "os" "path/filepath" + "strconv" "text/tabwriter" ) @@ -93,6 +94,19 @@ func main() { case "show-config": fmt.Printf("%v", cfg.Storage.AppDataDir) + case "delete": + if len(args) < 2 { + log.Fatalf("Usage: vssm delete ") + } + + name := args[1] + + deleteCmd := flag.NewFlagSet("delete", flag.ExitOnError) + purge := deleteCmd.Bool("purge", false, "Delete instance files from disk") + deleteCmd.Parse(args[2:]) + + sendIPCRequest(cfg, "POST", fmt.Sprintf("/instances/delete?name=%s&purge=%s", url.QueryEscape(name), url.QueryEscape(strconv.FormatBool(*purge))), nil) + default: printUsage() }