diff --git a/cmd/application_delete.go b/cmd/application_delete.go index aadd9cba..457243e2 100644 --- a/cmd/application_delete.go +++ b/cmd/application_delete.go @@ -4,10 +4,13 @@ import ( "context" "fmt" "os" + "strings" + "time" "github.com/pterm/pterm" - "github.com/qovery/qovery-cli/utils" "github.com/spf13/cobra" + + "github.com/qovery/qovery-cli/utils" ) var applicationDeleteCmd = &cobra.Command{ @@ -23,6 +26,18 @@ var applicationDeleteCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if applicationName == "" && applicationNames == "" { + utils.PrintlnError(fmt.Errorf("use either --application \"\" or --applications \", \" but not both at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + if applicationName != "" && applicationNames != "" { + utils.PrintlnError(fmt.Errorf("you can't use --application and --applications at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + client := utils.GetQoveryClient(tokenType, token) _, _, envId, err := getOrganizationProjectEnvironmentContextResourcesIds(client) @@ -32,6 +47,48 @@ var applicationDeleteCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if applicationNames != "" { + // wait until service is ready + for { + if utils.IsEnvironmentInATerminalState(envId, client) { + break + } + + utils.Println(fmt.Sprintf("Waiting for environment %s to be ready..", pterm.FgBlue.Sprintf(envId))) + time.Sleep(5 * time.Second) + } + + applications, _, err := client.ApplicationsApi.ListApplication(context.Background(), envId).Execute() + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + var serviceIds []string + for _, applicationName := range strings.Split(applicationNames, ",") { + trimmedApplicationName := strings.TrimSpace(applicationName) + serviceIds = append(serviceIds, utils.FindByApplicationName(applications.GetResults(), trimmedApplicationName).Id) + } + + // stop multiple services + _, err = utils.DeleteServices(client, envId, serviceIds, utils.ApplicationType) + if watchFlag { + utils.WatchEnvironment(envId, "unused", client) + } else { + utils.Println(fmt.Sprintf("Deleting applications %s in progress..", pterm.FgBlue.Sprintf(applicationNames))) + } + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + return + } + applications, _, err := client.ApplicationsApi.ListApplication(context.Background(), envId).Execute() if err != nil { @@ -51,6 +108,10 @@ var applicationDeleteCmd = &cobra.Command{ msg, err := utils.DeleteService(client, envId, application.Id, utils.ApplicationType, watchFlag) + if watchFlag { + utils.WatchEnvironment(envId, "unused", client) + } + if err != nil { utils.PrintlnError(err) os.Exit(1) @@ -76,7 +137,6 @@ func init() { applicationDeleteCmd.Flags().StringVarP(&projectName, "project", "", "", "Project Name") applicationDeleteCmd.Flags().StringVarP(&environmentName, "environment", "", "", "Environment Name") applicationDeleteCmd.Flags().StringVarP(&applicationName, "application", "n", "", "Application Name") + applicationDeleteCmd.Flags().StringVarP(&applicationNames, "applications", "", "", "Application Names (comma separated) Example: --applications \"app1,app2,app3\"") applicationDeleteCmd.Flags().BoolVarP(&watchFlag, "watch", "w", false, "Watch application status until it's ready or an error occurs") - - _ = applicationDeleteCmd.MarkFlagRequired("application") } diff --git a/cmd/application_deploy.go b/cmd/application_deploy.go index 5873b3ab..c8eb5e8a 100644 --- a/cmd/application_deploy.go +++ b/cmd/application_deploy.go @@ -3,12 +3,14 @@ package cmd import ( "context" "fmt" + "os" + "time" + "github.com/pterm/pterm" - "github.com/qovery/qovery-cli/utils" "github.com/qovery/qovery-client-go" "github.com/spf13/cobra" - "os" - "time" + + "github.com/qovery/qovery-cli/utils" ) var applicationDeployCmd = &cobra.Command{ @@ -25,7 +27,7 @@ var applicationDeployCmd = &cobra.Command{ } if applicationName == "" && applicationNames == "" { - utils.PrintlnError(fmt.Errorf("use neither --application \"\" nor --applications \", \"")) + utils.PrintlnError(fmt.Errorf("use either --application \"\" or --applications \", \" but not both at the same time")) os.Exit(1) panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } diff --git a/cmd/application_stop.go b/cmd/application_stop.go index 44b9968e..2eecf8d6 100644 --- a/cmd/application_stop.go +++ b/cmd/application_stop.go @@ -4,10 +4,13 @@ import ( "context" "fmt" "os" + "strings" + "time" "github.com/pterm/pterm" - "github.com/qovery/qovery-cli/utils" "github.com/spf13/cobra" + + "github.com/qovery/qovery-cli/utils" ) var applicationStopCmd = &cobra.Command{ @@ -23,6 +26,18 @@ var applicationStopCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if applicationName == "" && applicationNames == "" { + utils.PrintlnError(fmt.Errorf("use either --application \"\" or --applications \", \" but not both at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + if applicationName != "" && applicationNames != "" { + utils.PrintlnError(fmt.Errorf("you can't use --application and --applications at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + client := utils.GetQoveryClient(tokenType, token) _, _, envId, err := getOrganizationProjectEnvironmentContextResourcesIds(client) @@ -32,6 +47,49 @@ var applicationStopCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if applicationNames != "" { + // wait until service is ready + for { + if utils.IsEnvironmentInATerminalState(envId, client) { + break + } + + utils.Println(fmt.Sprintf("Waiting for environment %s to be ready..", pterm.FgBlue.Sprintf(envId))) + time.Sleep(5 * time.Second) + } + + applications, _, err := client.ApplicationsApi.ListApplication(context.Background(), envId).Execute() + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + var serviceIds []string + for _, applicationName := range strings.Split(applicationNames, ",") { + trimmedApplicationName := strings.TrimSpace(applicationName) + serviceIds = append(serviceIds, utils.FindByApplicationName(applications.GetResults(), trimmedApplicationName).Id) + } + + // stop multiple services + _, err = utils.StopServices(client, envId, serviceIds, utils.ApplicationType) + + if watchFlag { + utils.WatchEnvironment(envId, "unused", client) + } else { + utils.Println(fmt.Sprintf("Stopping applications %s in progress..", pterm.FgBlue.Sprintf(applicationNames))) + } + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + return + } + applications, _, err := client.ApplicationsApi.ListApplication(context.Background(), envId).Execute() if err != nil { @@ -76,8 +134,7 @@ func init() { applicationStopCmd.Flags().StringVarP(&projectName, "project", "", "", "Project Name") applicationStopCmd.Flags().StringVarP(&environmentName, "environment", "", "", "Environment Name") applicationStopCmd.Flags().StringVarP(&applicationName, "application", "n", "", "Application Name") + applicationStopCmd.Flags().StringVarP(&applicationNames, "applications", "", "", "Application Names (comma separated) Example: --applications \"app1,app2,app3\"") applicationStopCmd.Flags().StringVarP(&applicationCommitId, "commit-id", "c", "", "Application Commit ID") applicationStopCmd.Flags().BoolVarP(&watchFlag, "watch", "w", false, "Watch application status until it's ready or an error occurs") - - _ = applicationStopCmd.MarkFlagRequired("application") } diff --git a/cmd/container_delete.go b/cmd/container_delete.go index 31c76b0a..bf784929 100644 --- a/cmd/container_delete.go +++ b/cmd/container_delete.go @@ -4,10 +4,13 @@ import ( "context" "fmt" "os" + "strings" + "time" "github.com/pterm/pterm" - "github.com/qovery/qovery-cli/utils" "github.com/spf13/cobra" + + "github.com/qovery/qovery-cli/utils" ) var containerDeleteCmd = &cobra.Command{ @@ -23,6 +26,18 @@ var containerDeleteCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if containerName == "" && containerNames == "" { + utils.PrintlnError(fmt.Errorf("use either --container \"\" or --containers \", \" but not both at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + if containerName != "" && containerNames != "" { + utils.PrintlnError(fmt.Errorf("you can't use --container and --containers at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + client := utils.GetQoveryClient(tokenType, token) _, _, envId, err := getOrganizationProjectEnvironmentContextResourcesIds(client) @@ -32,6 +47,48 @@ var containerDeleteCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if containerNames != "" { + // wait until service is ready + for { + if utils.IsEnvironmentInATerminalState(envId, client) { + break + } + + utils.Println(fmt.Sprintf("Waiting for environment %s to be ready..", pterm.FgBlue.Sprintf(envId))) + time.Sleep(5 * time.Second) + } + + containers, _, err := client.ContainersApi.ListContainer(context.Background(), envId).Execute() + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + var serviceIds []string + for _, containerName := range strings.Split(containerNames, ",") { + trimmedContainerName := strings.TrimSpace(containerName) + serviceIds = append(serviceIds, utils.FindByContainerName(containers.GetResults(), trimmedContainerName).Id) + } + + _, err = utils.DeleteServices(client, envId, serviceIds, utils.ContainerType) + + if watchFlag { + utils.WatchEnvironment(envId, "unused", client) + } else { + utils.Println(fmt.Sprintf("Deleting containers %s in progress..", pterm.FgBlue.Sprintf(containerNames))) + } + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + return + } + containers, _, err := client.ContainersApi.ListContainer(context.Background(), envId).Execute() if err != nil { @@ -76,7 +133,6 @@ func init() { containerDeleteCmd.Flags().StringVarP(&projectName, "project", "", "", "Project Name") containerDeleteCmd.Flags().StringVarP(&environmentName, "environment", "", "", "Environment Name") containerDeleteCmd.Flags().StringVarP(&containerName, "container", "n", "", "Container Name") + containerDeleteCmd.Flags().StringVarP(&containerNames, "containers", "", "", "Container Names (comma separated) (ex: --containers \"container1,container2\")") containerDeleteCmd.Flags().BoolVarP(&watchFlag, "watch", "w", false, "Watch container status until it's ready or an error occurs") - - _ = containerDeleteCmd.MarkFlagRequired("container") } diff --git a/cmd/container_deploy.go b/cmd/container_deploy.go index 6615e698..8110f62a 100644 --- a/cmd/container_deploy.go +++ b/cmd/container_deploy.go @@ -7,9 +7,10 @@ import ( "time" "github.com/pterm/pterm" - "github.com/qovery/qovery-cli/utils" "github.com/qovery/qovery-client-go" "github.com/spf13/cobra" + + "github.com/qovery/qovery-cli/utils" ) var containerDeployCmd = &cobra.Command{ @@ -26,7 +27,7 @@ var containerDeployCmd = &cobra.Command{ } if containerName == "" && containerNames == "" { - utils.PrintlnError(fmt.Errorf("use neither --cronjob \"\" nor --cronjobs \", \"")) + utils.PrintlnError(fmt.Errorf("use either --cronjob \"\" or --cronjobs \", \" but not both at the same time")) os.Exit(1) panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } diff --git a/cmd/container_stop.go b/cmd/container_stop.go index 3ea195a6..4b7a4af1 100644 --- a/cmd/container_stop.go +++ b/cmd/container_stop.go @@ -4,10 +4,13 @@ import ( "context" "fmt" "os" + "strings" + "time" "github.com/pterm/pterm" - "github.com/qovery/qovery-cli/utils" "github.com/spf13/cobra" + + "github.com/qovery/qovery-cli/utils" ) var containerStopCmd = &cobra.Command{ @@ -23,6 +26,18 @@ var containerStopCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if containerName == "" && containerNames == "" { + utils.PrintlnError(fmt.Errorf("use either --container \"\" or --containers \", \" but not both at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + if containerName != "" && containerNames != "" { + utils.PrintlnError(fmt.Errorf("you can't use --container and --containers at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + client := utils.GetQoveryClient(tokenType, token) _, _, envId, err := getOrganizationProjectEnvironmentContextResourcesIds(client) @@ -32,6 +47,49 @@ var containerStopCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if containerNames != "" { + // wait until service is ready + for { + if utils.IsEnvironmentInATerminalState(envId, client) { + break + } + + utils.Println(fmt.Sprintf("Waiting for environment %s to be ready..", pterm.FgBlue.Sprintf(envId))) + time.Sleep(5 * time.Second) + } + + containers, _, err := client.ContainersApi.ListContainer(context.Background(), envId).Execute() + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + var serviceIds []string + for _, containerName := range strings.Split(containerNames, ",") { + trimmedContainerName := strings.TrimSpace(containerName) + serviceIds = append(serviceIds, utils.FindByContainerName(containers.GetResults(), trimmedContainerName).Id) + } + + // stop multiple services + _, err = utils.StopServices(client, envId, serviceIds, utils.ContainerType) + + if watchFlag { + utils.WatchEnvironment(envId, "unused", client) + } else { + utils.Println(fmt.Sprintf("Stopping containers %s in progress..", pterm.FgBlue.Sprintf(containerNames))) + } + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + return + } + containers, _, err := client.ContainersApi.ListContainer(context.Background(), envId).Execute() if err != nil { @@ -76,7 +134,6 @@ func init() { containerStopCmd.Flags().StringVarP(&projectName, "project", "", "", "Project Name") containerStopCmd.Flags().StringVarP(&environmentName, "environment", "", "", "Environment Name") containerStopCmd.Flags().StringVarP(&containerName, "container", "n", "", "Container Name") + containerStopCmd.Flags().StringVarP(&containerNames, "containers", "", "", "Container Names (comma separated) (ex: --containers \"container1,container2\")") containerStopCmd.Flags().BoolVarP(&watchFlag, "watch", "w", false, "Watch container status until it's ready or an error occurs") - - _ = containerStopCmd.MarkFlagRequired("container") } diff --git a/cmd/cronjob_delete.go b/cmd/cronjob_delete.go index 2847eb59..518424f6 100644 --- a/cmd/cronjob_delete.go +++ b/cmd/cronjob_delete.go @@ -2,11 +2,15 @@ package cmd import ( "fmt" - "github.com/pterm/pterm" "os" + "strings" + "time" + + "github.com/pterm/pterm" - "github.com/qovery/qovery-cli/utils" "github.com/spf13/cobra" + + "github.com/qovery/qovery-cli/utils" ) var cronjobDeleteCmd = &cobra.Command{ @@ -22,6 +26,18 @@ var cronjobDeleteCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if cronjobName == "" && cronjobNames == "" { + utils.PrintlnError(fmt.Errorf("use either --cronjob \"\" or --cronjobs \", \" but not both at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + if cronjobName != "" && cronjobNames != "" { + utils.PrintlnError(fmt.Errorf("you can't use --cronjob and --cronjobs at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + client := utils.GetQoveryClient(tokenType, token) _, _, envId, err := getOrganizationProjectEnvironmentContextResourcesIds(client) @@ -31,6 +47,48 @@ var cronjobDeleteCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if cronjobNames != "" { + // wait until service is ready + for { + if utils.IsEnvironmentInATerminalState(envId, client) { + break + } + + utils.Println(fmt.Sprintf("Waiting for environment %s to be ready..", pterm.FgBlue.Sprintf(envId))) + time.Sleep(5 * time.Second) + } + + cronjobs, err := ListCronjobs(envId, client) + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + var serviceIds []string + for _, cronjobName := range strings.Split(cronjobNames, ",") { + trimmedCronjobName := strings.TrimSpace(cronjobName) + serviceIds = append(serviceIds, utils.FindByJobName(cronjobs, trimmedCronjobName).Id) + } + + _, err = utils.DeleteServices(client, envId, serviceIds, utils.JobType) + + if watchFlag { + utils.WatchEnvironment(envId, "unused", client) + } else { + utils.Println(fmt.Sprintf("Deleting cronjobs %s in progress..", pterm.FgBlue.Sprintf(cronjobNames))) + } + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + return + } + cronjobs, err := ListCronjobs(envId, client) if err != nil { @@ -75,7 +133,6 @@ func init() { cronjobDeleteCmd.Flags().StringVarP(&projectName, "project", "", "", "Project Name") cronjobDeleteCmd.Flags().StringVarP(&environmentName, "environment", "", "", "Environment Name") cronjobDeleteCmd.Flags().StringVarP(&cronjobName, "cronjob", "n", "", "Cronjob Name") + cronjobDeleteCmd.Flags().StringVarP(&cronjobNames, "cronjobs", "", "", "Cronjob Names (comma separated) (ex: --cronjobs \"cron1,cron2\")") cronjobDeleteCmd.Flags().BoolVarP(&watchFlag, "watch", "w", false, "Watch cronjob status until it's ready or an error occurs") - - _ = cronjobDeleteCmd.MarkFlagRequired("cronjob") } diff --git a/cmd/cronjob_deploy.go b/cmd/cronjob_deploy.go index 8d7dbd55..ba92f786 100644 --- a/cmd/cronjob_deploy.go +++ b/cmd/cronjob_deploy.go @@ -2,13 +2,15 @@ package cmd import ( "fmt" - "github.com/pterm/pterm" "os" "time" - "github.com/qovery/qovery-cli/utils" + "github.com/pterm/pterm" + "github.com/qovery/qovery-client-go" "github.com/spf13/cobra" + + "github.com/qovery/qovery-cli/utils" ) var cronjobDeployCmd = &cobra.Command{ @@ -25,7 +27,7 @@ var cronjobDeployCmd = &cobra.Command{ } if cronjobName == "" && cronjobNames == "" { - utils.PrintlnError(fmt.Errorf("use neither --cronjob \"\" nor --cronjobs \", \"")) + utils.PrintlnError(fmt.Errorf("use either --cronjob \"\" or --cronjobs \", \" but not both at the same time")) os.Exit(1) panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } diff --git a/cmd/cronjob_stop.go b/cmd/cronjob_stop.go index 6aebbaac..e1efee0b 100644 --- a/cmd/cronjob_stop.go +++ b/cmd/cronjob_stop.go @@ -2,11 +2,15 @@ package cmd import ( "fmt" - "github.com/pterm/pterm" "os" + "strings" + "time" + + "github.com/pterm/pterm" - "github.com/qovery/qovery-cli/utils" "github.com/spf13/cobra" + + "github.com/qovery/qovery-cli/utils" ) var cronjobStopCmd = &cobra.Command{ @@ -22,6 +26,18 @@ var cronjobStopCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if cronjobName == "" && cronjobNames == "" { + utils.PrintlnError(fmt.Errorf("use either --cronjob \"\" or --cronjobs \", \" but not both at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + if cronjobName != "" && cronjobNames != "" { + utils.PrintlnError(fmt.Errorf("you can't use --cronjob and --cronjobs at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + client := utils.GetQoveryClient(tokenType, token) _, _, envId, err := getOrganizationProjectEnvironmentContextResourcesIds(client) @@ -31,6 +47,49 @@ var cronjobStopCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if cronjobNames != "" { + // wait until service is ready + for { + if utils.IsEnvironmentInATerminalState(envId, client) { + break + } + + utils.Println(fmt.Sprintf("Waiting for environment %s to be ready..", pterm.FgBlue.Sprintf(envId))) + time.Sleep(5 * time.Second) + } + + cronjobs, err := ListCronjobs(envId, client) + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + var serviceIds []string + for _, cronjobName := range strings.Split(cronjobNames, ",") { + trimmedCronjobName := strings.TrimSpace(cronjobName) + serviceIds = append(serviceIds, utils.FindByJobName(cronjobs, trimmedCronjobName).Id) + } + + // stop multiple services + _, err = utils.StopServices(client, envId, serviceIds, utils.JobType) + + if watchFlag { + utils.WatchEnvironment(envId, "unused", client) + } else { + utils.Println(fmt.Sprintf("Stopping cronjobs %s in progress..", pterm.FgBlue.Sprintf(cronjobNames))) + } + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + return + } + cronjobs, err := ListCronjobs(envId, client) if err != nil { @@ -75,7 +134,6 @@ func init() { cronjobStopCmd.Flags().StringVarP(&projectName, "project", "", "", "Project Name") cronjobStopCmd.Flags().StringVarP(&environmentName, "environment", "", "", "Environment Name") cronjobStopCmd.Flags().StringVarP(&cronjobName, "cronjob", "n", "", "Cronjob Name") + cronjobStopCmd.Flags().StringVarP(&cronjobNames, "cronjobs", "", "", "Cronjob Names (comma separated) (ex: --cronjobs \"cron1,cron2\")") cronjobStopCmd.Flags().BoolVarP(&watchFlag, "watch", "w", false, "Watch cronjob status until it's ready or an error occurs") - - _ = cronjobStopCmd.MarkFlagRequired("cronjob") } diff --git a/cmd/database.go b/cmd/database.go index 97692f8e..e413aa75 100644 --- a/cmd/database.go +++ b/cmd/database.go @@ -1,12 +1,15 @@ package cmd import ( - "github.com/qovery/qovery-cli/utils" - "github.com/spf13/cobra" "os" + + "github.com/spf13/cobra" + + "github.com/qovery/qovery-cli/utils" ) var databaseName string +var databaseNames string var showCredentials bool var databaseCmd = &cobra.Command{ Use: "database", diff --git a/cmd/database_delete.go b/cmd/database_delete.go index 1d5a54a4..ec906cb2 100644 --- a/cmd/database_delete.go +++ b/cmd/database_delete.go @@ -4,10 +4,13 @@ import ( "context" "fmt" "os" + "strings" + "time" "github.com/pterm/pterm" - "github.com/qovery/qovery-cli/utils" "github.com/spf13/cobra" + + "github.com/qovery/qovery-cli/utils" ) var databaseDeleteCmd = &cobra.Command{ @@ -23,6 +26,18 @@ var databaseDeleteCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if databaseName == "" && databaseNames == "" { + utils.PrintlnError(fmt.Errorf("use either --database \"\" or --databases \", \" but not both at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + if databaseName != "" && databaseNames != "" { + utils.PrintlnError(fmt.Errorf("you can't use --database and --databases at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + client := utils.GetQoveryClient(tokenType, token) _, _, envId, err := getOrganizationProjectEnvironmentContextResourcesIds(client) @@ -32,6 +47,49 @@ var databaseDeleteCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if databaseNames != "" { + // wait until service is ready + for { + if utils.IsEnvironmentInATerminalState(envId, client) { + break + } + + utils.Println(fmt.Sprintf("Waiting for environment %s to be ready..", pterm.FgBlue.Sprintf(envId))) + time.Sleep(5 * time.Second) + } + + databases, _, err := client.DatabasesApi.ListDatabase(context.Background(), envId).Execute() + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + var serviceIds []string + for _, databaseName := range strings.Split(databaseNames, ",") { + trimmedDatabaseName := strings.TrimSpace(databaseName) + serviceIds = append(serviceIds, utils.FindByDatabaseName(databases.GetResults(), trimmedDatabaseName).Id) + } + + // stop multiple services + _, err = utils.DeleteServices(client, envId, serviceIds, utils.DatabaseType) + + if watchFlag { + utils.WatchEnvironment(envId, "unused", client) + } else { + utils.Println(fmt.Sprintf("Deleting databases %s in progress..", pterm.FgBlue.Sprintf(databaseNames))) + } + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + return + } + databases, _, err := client.DatabasesApi.ListDatabase(context.Background(), envId).Execute() if err != nil { @@ -76,7 +134,6 @@ func init() { databaseDeleteCmd.Flags().StringVarP(&projectName, "project", "", "", "Project Name") databaseDeleteCmd.Flags().StringVarP(&environmentName, "environment", "", "", "Environment Name") databaseDeleteCmd.Flags().StringVarP(&databaseName, "database", "n", "", "Database Name") + databaseDeleteCmd.Flags().StringVarP(&databaseNames, "databases", "", "", "Database Names (comma separated) Example: --databases \"db1,db2\"") databaseDeleteCmd.Flags().BoolVarP(&watchFlag, "watch", "w", false, "Watch database status until it's ready or an error occurs") - - _ = databaseDeleteCmd.MarkFlagRequired("database") } diff --git a/cmd/database_stop.go b/cmd/database_stop.go index 3b1a762e..84686bee 100644 --- a/cmd/database_stop.go +++ b/cmd/database_stop.go @@ -4,10 +4,13 @@ import ( "context" "fmt" "os" + "strings" + "time" "github.com/pterm/pterm" - "github.com/qovery/qovery-cli/utils" "github.com/spf13/cobra" + + "github.com/qovery/qovery-cli/utils" ) var databaseStopCmd = &cobra.Command{ @@ -23,6 +26,18 @@ var databaseStopCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if databaseName == "" && databaseNames == "" { + utils.PrintlnError(fmt.Errorf("use either --database \"\" or --databases \", \" but not both at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + if databaseName != "" && databaseNames != "" { + utils.PrintlnError(fmt.Errorf("you can't use --database and --databases at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + client := utils.GetQoveryClient(tokenType, token) _, _, envId, err := getOrganizationProjectEnvironmentContextResourcesIds(client) @@ -32,6 +47,49 @@ var databaseStopCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if databaseNames != "" { + // wait until service is ready + for { + if utils.IsEnvironmentInATerminalState(envId, client) { + break + } + + utils.Println(fmt.Sprintf("Waiting for environment %s to be ready..", pterm.FgBlue.Sprintf(envId))) + time.Sleep(5 * time.Second) + } + + databases, _, err := client.DatabasesApi.ListDatabase(context.Background(), envId).Execute() + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + var serviceIds []string + for _, databaseName := range strings.Split(databaseNames, ",") { + trimmedDatabaseName := strings.TrimSpace(databaseName) + serviceIds = append(serviceIds, utils.FindByDatabaseName(databases.GetResults(), trimmedDatabaseName).Id) + } + + // stop multiple services + _, err = utils.StopServices(client, envId, serviceIds, utils.DatabaseType) + + if watchFlag { + utils.WatchEnvironment(envId, "unused", client) + } else { + utils.Println(fmt.Sprintf("Stopping databases %s in progress..", pterm.FgBlue.Sprintf(databaseNames))) + } + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + return + } + databases, _, err := client.DatabasesApi.ListDatabase(context.Background(), envId).Execute() if err != nil { @@ -76,7 +134,6 @@ func init() { databaseStopCmd.Flags().StringVarP(&projectName, "project", "", "", "Project Name") databaseStopCmd.Flags().StringVarP(&environmentName, "environment", "", "", "Environment Name") databaseStopCmd.Flags().StringVarP(&databaseName, "database", "n", "", "Database Name") + databaseStopCmd.Flags().StringVarP(&databaseNames, "databases", "", "", "Database Names (comma separated) Example: --databases \"db1,db2\"") databaseStopCmd.Flags().BoolVarP(&watchFlag, "watch", "w", false, "Watch database status until it's ready or an error occurs") - - _ = databaseStopCmd.MarkFlagRequired("database") } diff --git a/cmd/lifecycle_delete.go b/cmd/lifecycle_delete.go index 97e3b3e5..e5bdec24 100644 --- a/cmd/lifecycle_delete.go +++ b/cmd/lifecycle_delete.go @@ -2,11 +2,15 @@ package cmd import ( "fmt" - "github.com/pterm/pterm" "os" + "strings" + "time" + + "github.com/pterm/pterm" - "github.com/qovery/qovery-cli/utils" "github.com/spf13/cobra" + + "github.com/qovery/qovery-cli/utils" ) var lifecycleDeleteCmd = &cobra.Command{ @@ -22,6 +26,18 @@ var lifecycleDeleteCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if lifecycleName == "" && lifecycleNames == "" { + utils.PrintlnError(fmt.Errorf("use either --lifecycle \"\" or --lifecycles \", \" but not both at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + if lifecycleName != "" && lifecycleNames != "" { + utils.PrintlnError(fmt.Errorf("you can't use --lifecycle and --lifecycles at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + client := utils.GetQoveryClient(tokenType, token) _, _, envId, err := getOrganizationProjectEnvironmentContextResourcesIds(client) @@ -31,6 +47,49 @@ var lifecycleDeleteCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if lifecycleNames != "" { + // wait until service is ready + for { + if utils.IsEnvironmentInATerminalState(envId, client) { + break + } + + utils.Println(fmt.Sprintf("Waiting for environment %s to be ready..", pterm.FgBlue.Sprintf(envId))) + time.Sleep(5 * time.Second) + } + + lifecycles, err := ListLifecycleJobs(envId, client) + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + var serviceIds []string + for _, lifecycleName := range strings.Split(lifecycleNames, ",") { + trimmedLifecycleName := strings.TrimSpace(lifecycleName) + serviceIds = append(serviceIds, utils.FindByJobName(lifecycles, trimmedLifecycleName).Id) + } + + // stop multiple services + _, err = utils.DeleteServices(client, envId, serviceIds, utils.JobType) + + if watchFlag { + utils.WatchEnvironment(envId, "unused", client) + } else { + utils.Println(fmt.Sprintf("Deleting lifecycle jobs %s in progress..", pterm.FgBlue.Sprintf(lifecycleNames))) + } + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + return + } + lifecycles, err := ListLifecycleJobs(envId, client) if err != nil { @@ -75,7 +134,6 @@ func init() { lifecycleDeleteCmd.Flags().StringVarP(&projectName, "project", "", "", "Project Name") lifecycleDeleteCmd.Flags().StringVarP(&environmentName, "environment", "", "", "Environment Name") lifecycleDeleteCmd.Flags().StringVarP(&lifecycleName, "lifecycle", "n", "", "Lifecycle Job Name") + lifecycleDeleteCmd.Flags().StringVarP(&lifecycleNames, "lifecycles", "", "", "Lifecycle Job Names (comma separated) (ex: --lifecycles \"lifecycle1,lifecycle2\")") lifecycleDeleteCmd.Flags().BoolVarP(&watchFlag, "watch", "w", false, "Watch lifecycle job status until it's ready or an error occurs") - - _ = lifecycleDeleteCmd.MarkFlagRequired("lifecycle") } diff --git a/cmd/lifecycle_deploy.go b/cmd/lifecycle_deploy.go index 21119d8e..272e9bd2 100644 --- a/cmd/lifecycle_deploy.go +++ b/cmd/lifecycle_deploy.go @@ -2,13 +2,15 @@ package cmd import ( "fmt" - "github.com/pterm/pterm" "os" "time" - "github.com/qovery/qovery-cli/utils" + "github.com/pterm/pterm" + "github.com/qovery/qovery-client-go" "github.com/spf13/cobra" + + "github.com/qovery/qovery-cli/utils" ) var lifecycleDeployCmd = &cobra.Command{ @@ -25,7 +27,7 @@ var lifecycleDeployCmd = &cobra.Command{ } if lifecycleName == "" && lifecycleNames == "" { - utils.PrintlnError(fmt.Errorf("use neither --lifecycle \"\" nor --lifecycles \", \"")) + utils.PrintlnError(fmt.Errorf("use either --lifecycle \"\" or --lifecycles \", \" but not both at the same time")) os.Exit(1) panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } diff --git a/cmd/lifecycle_stop.go b/cmd/lifecycle_stop.go index c615e4e7..9fe4608a 100644 --- a/cmd/lifecycle_stop.go +++ b/cmd/lifecycle_stop.go @@ -2,11 +2,15 @@ package cmd import ( "fmt" - "github.com/pterm/pterm" "os" + "strings" + "time" + + "github.com/pterm/pterm" - "github.com/qovery/qovery-cli/utils" "github.com/spf13/cobra" + + "github.com/qovery/qovery-cli/utils" ) var lifecycleStopCmd = &cobra.Command{ @@ -22,6 +26,18 @@ var lifecycleStopCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if lifecycleName == "" && lifecycleNames == "" { + utils.PrintlnError(fmt.Errorf("use either --lifecycle \"\" or --lifecycles \", \" but not both at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + if lifecycleName != "" && lifecycleNames != "" { + utils.PrintlnError(fmt.Errorf("you can't use --lifecycle and --lifecycles at the same time")) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + client := utils.GetQoveryClient(tokenType, token) _, _, envId, err := getOrganizationProjectEnvironmentContextResourcesIds(client) @@ -31,6 +47,49 @@ var lifecycleStopCmd = &cobra.Command{ panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 } + if lifecycleNames != "" { + // wait until service is ready + for { + if utils.IsEnvironmentInATerminalState(envId, client) { + break + } + + utils.Println(fmt.Sprintf("Waiting for environment %s to be ready..", pterm.FgBlue.Sprintf(envId))) + time.Sleep(5 * time.Second) + } + + lifecycles, err := ListLifecycleJobs(envId, client) + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + var serviceIds []string + for _, lifecycleName := range strings.Split(lifecycleNames, ",") { + trimmedLifecycleName := strings.TrimSpace(lifecycleName) + serviceIds = append(serviceIds, utils.FindByJobName(lifecycles, trimmedLifecycleName).Id) + } + + // stop multiple services + _, err = utils.StopServices(client, envId, serviceIds, utils.JobType) + + if watchFlag { + utils.WatchEnvironment(envId, "unused", client) + } else { + utils.Println(fmt.Sprintf("Stopping lifecycle jobs %s in progress..", pterm.FgBlue.Sprintf(lifecycleNames))) + } + + if err != nil { + utils.PrintlnError(err) + os.Exit(1) + panic("unreachable") // staticcheck false positive: https://staticcheck.io/docs/checks#SA5011 + } + + return + } + lifecycles, err := ListLifecycleJobs(envId, client) if err != nil { @@ -75,7 +134,6 @@ func init() { lifecycleStopCmd.Flags().StringVarP(&projectName, "project", "", "", "Project Name") lifecycleStopCmd.Flags().StringVarP(&environmentName, "environment", "", "", "Environment Name") lifecycleStopCmd.Flags().StringVarP(&lifecycleName, "lifecycle", "n", "", "Lifecycle Name") + lifecycleStopCmd.Flags().StringVarP(&lifecycleNames, "lifecycles", "", "", "Lifecycle Job Names (comma separated) (ex: --lifecycles \"lifecycle1,lifecycle2\")") lifecycleStopCmd.Flags().BoolVarP(&watchFlag, "watch", "w", false, "Watch lifecycle status until it's ready or an error occurs") - - _ = lifecycleStopCmd.MarkFlagRequired("lifecycle") } diff --git a/utils/qovery.go b/utils/qovery.go index 8281b74b..d7baeaa0 100644 --- a/utils/qovery.go +++ b/utils/qovery.go @@ -3,12 +3,13 @@ package utils import ( "errors" "fmt" - "github.com/qovery/qovery-cli/variable" "os" "strconv" "strings" "time" + "github.com/qovery/qovery-cli/variable" + "github.com/pterm/pterm" "github.com/manifoldco/promptui" @@ -51,14 +52,14 @@ func GetQoveryClient(tokenType AccessTokenType, token AccessToken) *qovery.APICl } func SelectRole(organization *Organization) (*Role, error) { - tokenType, token, err := GetAccessToken() - if err != nil { - return nil, err - } + tokenType, token, err := GetAccessToken() + if err != nil { + return nil, err + } - client := GetQoveryClient(tokenType, token) + client := GetQoveryClient(tokenType, token) - roles, res, err := client.OrganizationMainCallsApi.ListOrganizationAvailableRoles(context.Background(), string(organization.ID)).Execute() + roles, res, err := client.OrganizationMainCallsApi.ListOrganizationAvailableRoles(context.Background(), string(organization.ID)).Execute() if err != nil { return nil, err } @@ -1581,6 +1582,108 @@ func DeleteService(client *qovery.APIClient, envId string, serviceId string, ser return DeleteService(client, envId, serviceId, serviceType, watchFlag) } +func DeleteServices(client *qovery.APIClient, envId string, serviceIds []string, serviceType ServiceType) (string, error) { + statuses, _, err := client.EnvironmentMainCallsApi.GetEnvironmentStatuses(context.Background(), envId).Execute() + + if err != nil { + return "", err + } + + cannotDelete := false + serviceIdsSet := map[string]struct{}{} + for _, value := range serviceIds { + serviceIdsSet[value] = struct{}{} + } + + if IsTerminalState(statuses.GetEnvironment().State) { + switch serviceType { + case ApplicationType: + for _, application := range statuses.GetApplications() { + if _, ok := serviceIdsSet[application.Id]; ok && !IsTerminalState(application.State) { + cannotDelete = true + } + } + if !cannotDelete { + _, err := client.EnvironmentActionsApi. + DeleteSelectedServices(context.Background(), envId). + EnvironmentServiceIdsAllRequest(qovery.EnvironmentServiceIdsAllRequest{ + ApplicationIds: serviceIds, + }). + Execute() + if err != nil { + return "", err + } + + return "", nil + } + case DatabaseType: + for _, database := range statuses.GetDatabases() { + if _, ok := serviceIdsSet[database.Id]; ok && !IsTerminalState(database.State) { + cannotDelete = true + } + } + if !cannotDelete { + _, err := client.EnvironmentActionsApi. + DeleteSelectedServices(context.Background(), envId). + EnvironmentServiceIdsAllRequest(qovery.EnvironmentServiceIdsAllRequest{ + DatabaseIds: serviceIds, + }). + Execute() + if err != nil { + return "", err + } + + return "", nil + } + case ContainerType: + for _, container := range statuses.GetContainers() { + if _, ok := serviceIdsSet[container.Id]; ok && !IsTerminalState(container.State) { + cannotDelete = true + } + } + if !cannotDelete { + _, err := client.EnvironmentActionsApi. + DeleteSelectedServices(context.Background(), envId). + EnvironmentServiceIdsAllRequest(qovery.EnvironmentServiceIdsAllRequest{ + ContainerIds: serviceIds, + }). + Execute() + if err != nil { + return "", err + } + + return "", nil + } + case JobType: + for _, job := range statuses.GetJobs() { + if _, ok := serviceIdsSet[job.Id]; ok && !IsTerminalState(job.State) { + cannotDelete = true + } + } + if !cannotDelete { + _, err := client.EnvironmentActionsApi. + DeleteSelectedServices(context.Background(), envId). + EnvironmentServiceIdsAllRequest(qovery.EnvironmentServiceIdsAllRequest{ + JobIds: serviceIds, + }). + Execute() + if err != nil { + return "", err + } + + return "", nil + } + } + } + + PrintlnInfo("waiting for previous deployment to be completed...") + + // sleep here to avoid too many requests + time.Sleep(5 * time.Second) + + return DeleteServices(client, envId, serviceIds, serviceType) +} + func DeployService(client *qovery.APIClient, envId string, serviceId string, serviceType ServiceType, request interface{}, watchFlag bool) (string, error) { statuses, _, err := client.EnvironmentMainCallsApi.GetEnvironmentStatuses(context.Background(), envId).Execute() @@ -1746,7 +1849,7 @@ func RedeployService(client *qovery.APIClient, envId string, serviceId string, s return RedeployService(client, envId, serviceId, serviceType, watchFlag) } -func StopService(client *qovery.APIClient, envId string, serviceId string, serviceType ServiceType, watchFlag bool) (string, error) { +func StopService(client *qovery.APIClient, envId string, serviceIds string, serviceType ServiceType, watchFlag bool) (string, error) { statuses, _, err := client.EnvironmentMainCallsApi.GetEnvironmentStatuses(context.Background(), envId).Execute() if err != nil { @@ -1757,14 +1860,14 @@ func StopService(client *qovery.APIClient, envId string, serviceId string, servi switch serviceType { case ApplicationType: for _, application := range statuses.GetApplications() { - if application.Id == serviceId && IsTerminalState(application.State) { - _, _, err := client.ApplicationActionsApi.StopApplication(context.Background(), serviceId).Execute() + if application.Id == serviceIds && IsTerminalState(application.State) { + _, _, err := client.ApplicationActionsApi.StopApplication(context.Background(), serviceIds).Execute() if err != nil { return "", err } if watchFlag { - WatchApplication(serviceId, envId, client) + WatchApplication(serviceIds, envId, client) } return "", nil @@ -1772,14 +1875,14 @@ func StopService(client *qovery.APIClient, envId string, serviceId string, servi } case DatabaseType: for _, database := range statuses.GetDatabases() { - if database.Id == serviceId && IsTerminalState(database.State) { - _, _, err := client.DatabaseActionsApi.StopDatabase(context.Background(), serviceId).Execute() + if database.Id == serviceIds && IsTerminalState(database.State) { + _, _, err := client.DatabaseActionsApi.StopDatabase(context.Background(), serviceIds).Execute() if err != nil { return "", err } if watchFlag { - WatchDatabase(serviceId, envId, client) + WatchDatabase(serviceIds, envId, client) } return "", nil @@ -1787,14 +1890,14 @@ func StopService(client *qovery.APIClient, envId string, serviceId string, servi } case ContainerType: for _, container := range statuses.GetContainers() { - if container.Id == serviceId && IsTerminalState(container.State) { - _, _, err := client.ContainerActionsApi.StopContainer(context.Background(), serviceId).Execute() + if container.Id == serviceIds && IsTerminalState(container.State) { + _, _, err := client.ContainerActionsApi.StopContainer(context.Background(), serviceIds).Execute() if err != nil { return "", err } if watchFlag { - WatchContainer(serviceId, envId, client) + WatchContainer(serviceIds, envId, client) } return "", nil @@ -1802,14 +1905,14 @@ func StopService(client *qovery.APIClient, envId string, serviceId string, servi } case JobType: for _, job := range statuses.GetJobs() { - if job.Id == serviceId && IsTerminalState(job.State) { - _, _, err := client.JobActionsApi.StopJob(context.Background(), serviceId).Execute() + if job.Id == serviceIds && IsTerminalState(job.State) { + _, _, err := client.JobActionsApi.StopJob(context.Background(), serviceIds).Execute() if err != nil { return "", err } if watchFlag { - WatchJob(serviceId, envId, client) + WatchJob(serviceIds, envId, client) } return "", nil @@ -1823,7 +1926,109 @@ func StopService(client *qovery.APIClient, envId string, serviceId string, servi // sleep here to avoid too many requests time.Sleep(5 * time.Second) - return StopService(client, envId, serviceId, serviceType, watchFlag) + return StopService(client, envId, serviceIds, serviceType, watchFlag) +} + +func StopServices(client *qovery.APIClient, envId string, serviceIds []string, serviceType ServiceType) (string, error) { + statuses, _, err := client.EnvironmentMainCallsApi.GetEnvironmentStatuses(context.Background(), envId).Execute() + + if err != nil { + return "", err + } + + cannotStop := false + serviceIdsSet := map[string]struct{}{} + for _, value := range serviceIds { + serviceIdsSet[value] = struct{}{} + } + + if IsTerminalState(statuses.GetEnvironment().State) { + switch serviceType { + case ApplicationType: + for _, application := range statuses.GetApplications() { + if _, ok := serviceIdsSet[application.Id]; ok && !IsTerminalState(application.State) { + cannotStop = true + } + } + if !cannotStop { + _, err := client.EnvironmentActionsApi. + StopSelectedServices(context.Background(), envId). + EnvironmentServiceIdsAllRequest(qovery.EnvironmentServiceIdsAllRequest{ + ApplicationIds: serviceIds, + }). + Execute() + if err != nil { + return "", err + } + + return "", nil + } + case DatabaseType: + for _, database := range statuses.GetDatabases() { + if _, ok := serviceIdsSet[database.Id]; ok && !IsTerminalState(database.State) { + cannotStop = true + } + } + if !cannotStop { + _, err := client.EnvironmentActionsApi. + StopSelectedServices(context.Background(), envId). + EnvironmentServiceIdsAllRequest(qovery.EnvironmentServiceIdsAllRequest{ + DatabaseIds: serviceIds, + }). + Execute() + if err != nil { + return "", err + } + + return "", nil + } + case ContainerType: + for _, container := range statuses.GetContainers() { + if _, ok := serviceIdsSet[container.Id]; ok && !IsTerminalState(container.State) { + cannotStop = true + } + } + if !cannotStop { + _, err := client.EnvironmentActionsApi. + StopSelectedServices(context.Background(), envId). + EnvironmentServiceIdsAllRequest(qovery.EnvironmentServiceIdsAllRequest{ + ContainerIds: serviceIds, + }). + Execute() + if err != nil { + return "", err + } + + return "", nil + } + case JobType: + for _, job := range statuses.GetJobs() { + if _, ok := serviceIdsSet[job.Id]; ok && !IsTerminalState(job.State) { + cannotStop = true + } + } + if !cannotStop { + _, err := client.EnvironmentActionsApi. + StopSelectedServices(context.Background(), envId). + EnvironmentServiceIdsAllRequest(qovery.EnvironmentServiceIdsAllRequest{ + JobIds: serviceIds, + }). + Execute() + if err != nil { + return "", err + } + + return "", nil + } + } + } + + PrintlnInfo("waiting for previous deployment to be completed...") + + // sleep here to avoid too many requests + time.Sleep(5 * time.Second) + + return StopServices(client, envId, serviceIds, serviceType) } func ToJobRequest(job qovery.JobResponse) qovery.JobRequest {