From 9585d1ca7275899e7ac41fc7542f8d69da29e45e Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Thu, 9 Jan 2025 09:33:49 -0800 Subject: [PATCH] Management will now run the following files: at the indicated step of un/installation. --- backend/internal/processes/installer.go | 58 +++++++++++++---- backend/internal/processes/uninstaller.go | 79 ++++++++++++++++++++++- 2 files changed, 125 insertions(+), 12 deletions(-) diff --git a/backend/internal/processes/installer.go b/backend/internal/processes/installer.go index b7d17c0a..fedeff33 100644 --- a/backend/internal/processes/installer.go +++ b/backend/internal/processes/installer.go @@ -15,6 +15,7 @@ import ( "math/rand" "os" "os/exec" + "path" "path/filepath" "regexp" "strings" @@ -39,7 +40,7 @@ func fetchMandatoryVars() ([]terraform.Varstruct, error) { func startApplicationInstallTerraform(appConfig *config.AppConfig, location string, application *types.InstalledMarketplaceApplication, meta *marketplace.MarketplaceMetadata, db database.Datastore) { log.Errorf("Application name is: %s", application.Name) terraform.AddApplicationToStack(appConfig, location, meta, application, db) - executeTerraformInstall(db, appConfig, meta, application) + executeTerraformInstall(db, appConfig, meta, application, location) } func InstallMarketplaceApplication(appConfig *config.AppConfig, location string, installParams *types.ApplicationInstallParams, meta *marketplace.MarketplaceMetadata, db database.Datastore, sync bool) error { @@ -55,14 +56,14 @@ func InstallMarketplaceApplication(appConfig *config.AppConfig, location string, terraformModuleName := fmt.Sprintf("%s-%s", installParams.DeploymentName, string(randomChars)) application := &types.InstalledMarketplaceApplication{ - Name: installParams.Name, - Version: installParams.Version, - DeploymentName: installParams.DeploymentName, - PackageName: meta.Name, - Source: meta.Package, - Status: "STAGED", - TerraformModuleName: terraformModuleName, - Variables: installParams.Variables, + Name: installParams.Name, + Version: installParams.Version, + DeploymentName: installParams.DeploymentName, + PackageName: meta.Name, + Source: meta.Package, + Status: "STAGED", + TerraformModuleName: terraformModuleName, + Variables: installParams.Variables, } db.StoreInstalledMarketplaceApplication(application) @@ -84,7 +85,7 @@ func InstallMarketplaceApplication(appConfig *config.AppConfig, location string, } } -func executeTerraformInstall(db database.Datastore, appConfig *config.AppConfig, meta *marketplace.MarketplaceMetadata, application *types.InstalledMarketplaceApplication) error { +func executeTerraformInstall(db database.Datastore, appConfig *config.AppConfig, meta *marketplace.MarketplaceMetadata, application *types.InstalledMarketplaceApplication, location string) error { // Create install_logs directory if it doesn't exist logDir := filepath.Join(appConfig.Workdir, "install_logs") if err := os.MkdirAll(logDir, 0755); err != nil && !os.IsExist(err) { @@ -109,6 +110,27 @@ func executeTerraformInstall(db database.Datastore, appConfig *config.AppConfig, fetchAllApplications(db) logfile := filepath.Join(logDir, fmt.Sprintf("%s_%s_install_log", application.Name, application.DeploymentName)) + + // Open the log file in append mode + fileHandle, err := os.OpenFile(logfile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + log.Fatalf("error opening log file: %s", err) + } + defer fileHandle.Close() + + // Check for and run pre-uninstall script if it exists + preInstallScript := path.Join(location, "pre-install.sh") + if _, err := os.Stat(preInstallScript); err == nil { + fileHandle.WriteString("pre-install.sh found, running...\n") + application.Status = "RUNNING PRE-INSTALL SCRIPT" + db.UpdateInstalledMarketplaceApplication(application) + err := runShellScript(application, db, preInstallScript, fileHandle) + if err != nil { + fileHandle.WriteString(err.Error()) + return err + } + } + err = terraform.RunTerraformLogOutToFile(appConfig, logfile, executor, "") if err != nil { @@ -128,6 +150,20 @@ func executeTerraformInstall(db database.Datastore, appConfig *config.AppConfig, fetchAllApplications(db) return err } + + // Check for and run post-install script if it exists + postInstallScript := path.Join(location, "post-install.sh") + if _, err := os.Stat(postInstallScript); err == nil { + log.Errorf("post-install.sh found, running...") + fileHandle.WriteString("post-install.sh found, running...\n") + application.Status = "RUNNING POST-INSTALL SCRIPT" + db.UpdateInstalledMarketplaceApplication(application) + err := runShellScript(application, db, postInstallScript, fileHandle) + if err != nil { + return err + } + } + application.Status = "COMPLETE" db.UpdateInstalledMarketplaceApplication(application) fetchAllApplications(db) @@ -270,7 +306,7 @@ func TriggerInstall(store database.Datastore, applicationInstallParams *types.Ap func TriggerUninstall(wsManager *websocket.WebSocketManager, userid string, store database.Datastore, received *marketplace.Uninstall, conf *config.AppConfig) error { if received.All == true { return UninstallAll(conf, wsManager, userid, received) - } + } // else { // return UninstallApplication(received.Application, received.DeploymentName, received.DisplayName, conf, store, wsManager, userid) // } diff --git a/backend/internal/processes/uninstaller.go b/backend/internal/processes/uninstaller.go index 118ede20..301eddc1 100644 --- a/backend/internal/processes/uninstaller.go +++ b/backend/internal/processes/uninstaller.go @@ -16,6 +16,7 @@ import ( "path" // "strconv" "fmt" + "os/exec" "strings" ) @@ -50,6 +51,62 @@ func UninstallAll(conf *config.AppConfig, conn *websocket.WebSocketManager, user return nil } +func runShellScript(application *types.InstalledMarketplaceApplication, store database.Datastore, scriptPath string, fileHandle *os.File) error { + filename := path.Base(scriptPath) + application.Status = fmt.Sprintf("RUNNING SCRIPT: %s", filename) + store.UpdateInstalledMarketplaceApplication(application) + scriptDir := path.Dir(scriptPath) + cmd := exec.Command("/bin/sh", scriptPath) + cmd.Dir = scriptDir + cmd.Env = os.Environ() // Inherit parent environment + + // Create pipes for stdout and stderr + stdout, err := cmd.StdoutPipe() + if err != nil { + return fmt.Errorf("failed to create stdout pipe: %w", err) + } + stderr, err := cmd.StderrPipe() + if err != nil { + return fmt.Errorf("failed to create stderr pipe: %w", err) + } + + // Start the command + if err := cmd.Start(); err != nil { + return fmt.Errorf("failed to start script: %w", err) + } + + // Create scanner for stdout + outScanner := bufio.NewScanner(stdout) + go func() { + for outScanner.Scan() { + outString := fmt.Sprintf("Script stdout: %s\n", outScanner.Text()) + if fileHandle != nil { + fileHandle.WriteString(outString) + } + log.Infof(outString) + } + }() + + // Create scanner for stderr + errScanner := bufio.NewScanner(stderr) + go func() { + for errScanner.Scan() { + outString := fmt.Sprintf("Script stderr: %s\n", errScanner.Text()) + if fileHandle != nil { + fileHandle.WriteString(outString) + } + log.Infof(outString) + } + }() + + // Wait for command to complete + if err := cmd.Wait(); err != nil { + return fmt.Errorf("script failed: %w", err) + } + + return nil +} + func UninstallApplication(application *types.InstalledMarketplaceApplication, conf *config.AppConfig, store database.Datastore) error { // Create uninstall_logs directory if it doesn't exist logDir := path.Join(conf.Workdir, "uninstall_logs") @@ -63,8 +120,21 @@ func UninstallApplication(application *types.InstalledMarketplaceApplication, co application.Status = "UNINSTALLING" store.UpdateInstalledMarketplaceApplication(application) + // Check for and run pre-uninstall script if it exists + preUninstallScript := path.Join(conf.Workdir, "terraform", "modules", application.Name, application.Version, "pre-uninstall.sh") + fileHandle, err := os.OpenFile(logfile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + log.Fatalf("error opening log file: %s", err) + } + defer fileHandle.Close() + + err = runShellScript(application, store, preUninstallScript, fileHandle) + if err != nil { + return err + } + // Run a terraform destroy on the module to be uninstalled - err := terraform.DestroyTerraformModule(conf, logfile, executor, application.TerraformModuleName) + err = terraform.DestroyTerraformModule(conf, logfile, executor, application.TerraformModuleName) if err != nil { return err } @@ -128,6 +198,13 @@ func UninstallApplication(application *types.InstalledMarketplaceApplication, co return err } + // Check for and run pre-uninstall script if it exists + postUninstallScript := path.Join(conf.Workdir, "terraform", "modules", application.Name, application.Version, "post-uninstall.sh") + err := runShellScript(application, store, postUninstallScript, fileHandle) + if err != nil { + return err + } + return nil } }