From 8a43d850abb4ab464be854bbb76e3d3763f5d056 Mon Sep 17 00:00:00 2001 From: jaskaransarkaria Date: Wed, 2 Oct 2024 15:55:53 +0100 Subject: [PATCH 1/2] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20environmentApply?= =?UTF-8?q?=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/cloud-platform_environment_apply.md | 44 ++- doc/cloud-platform_environment_destroy.md | 44 ++- doc/cloud-platform_environment_plan.md | 45 ++- pkg/commands/environment.go | 6 +- .../{environmentApply.go => apply.go} | 338 ------------------ ...environmentApply_test.go => apply_test.go} | 0 pkg/environment/destroy.go | 122 +++++++ pkg/environment/init.go | 30 ++ pkg/environment/namespace.go | 98 +++++ pkg/environment/plan.go | 113 ++++++ 10 files changed, 429 insertions(+), 411 deletions(-) rename pkg/environment/{environmentApply.go => apply.go} (50%) rename pkg/environment/{environmentApply_test.go => apply_test.go} (100%) create mode 100644 pkg/environment/destroy.go create mode 100644 pkg/environment/init.go create mode 100644 pkg/environment/plan.go diff --git a/doc/cloud-platform_environment_apply.md b/doc/cloud-platform_environment_apply.md index c7698c63..4de39941 100644 --- a/doc/cloud-platform_environment_apply.md +++ b/doc/cloud-platform_environment_apply.md @@ -4,25 +4,24 @@ Perform a terraform apply and kubectl apply for a given namespace ### Synopsis - - Perform a kubectl apply and a terraform apply for a given namespace using either -namespace flag or the - the namespace in the given PR Id/Number - - Along with the mandatory input flag, the below environments variables needs to be set - TF_VAR_cluster_name - e.g. "cp-1902-02" to get the vpc details for some modules like rds, es - TF_VAR_cluster_state_bucket - State where the cluster state is stored - TF_VAR_cluster_state_key - folder name/state key inside the state bucket where cluster state is stored - TF_VAR_github_owner - Github owner: ministryofjustice - TF_VAR_github_token - Personal access token with repo scope to push github action secrets - TF_VAR_kubernetes_cluster - Full name of the Cluster e.g. XXXXXX.gr7.eu-west2.eks.amazonaws.com - PINGDOM_API_TOKEN - API Token to access pingdom - PIPELINE_TERRAFORM_STATE_LOCK_TABLE - DynamoDB table where the state lock is stored - PIPELINE_STATE_BUCKET - State bucket where the environments state is stored e.g cloud-platform-terraform-state - PIPELINE_STATE_KEY_PREFIX - State key/ folder where the environments terraform state is stored e.g cloud-platform-environments - PIPELINE_STATE_REGION - State region of the bucket e.g. eu-west-1 - PIPELINE_CLUSTER - Cluster name/folder inside namespaces/ in cloud-platform-environments - PIPELINE_CLUSTER_STATE - Cluster name/folder inside the state bucket where the environments terraform state is stored - + Perform a kubectl apply and a terraform apply for a given namespace using either -namespace flag or the + the namespace in the given PR Id/Number + + Along with the mandatory input flag, the below environments variables needs to be set + TF_VAR_cluster_name - e.g. "cp-1902-02" to get the vpc details for some modules like rds, es + TF_VAR_cluster_state_bucket - State where the cluster state is stored + TF_VAR_cluster_state_key - folder name/state key inside the state bucket where cluster state is stored + TF_VAR_github_owner - Github owner: ministryofjustice + TF_VAR_github_token - Personal access token with repo scope to push github action secrets + TF_VAR_kubernetes_cluster - Full name of the Cluster e.g. XXXXXX.gr7.eu-west2.eks.amazonaws.com + PINGDOM_API_TOKEN - API Token to access pingdom + PIPELINE_TERRAFORM_STATE_LOCK_TABLE - DynamoDB table where the state lock is stored + PIPELINE_STATE_BUCKET - State bucket where the environments state is stored e.g cloud-platform-terraform-state + PIPELINE_STATE_KEY_PREFIX - State key/ folder where the environments terraform state is stored e.g cloud-platform-environments + PIPELINE_STATE_REGION - State region of the bucket e.g. eu-west-1 + PIPELINE_CLUSTER - Cluster name/folder inside namespaces/ in cloud-platform-environments + PIPELINE_CLUSTER_STATE - Cluster name/folder inside the state bucket where the environments terraform state is stored + ``` cloud-platform environment apply [flags] @@ -31,7 +30,7 @@ cloud-platform environment apply [flags] ### Examples ``` -$ cloud-platform environment apply -n +cloud-platform environment apply -n ``` @@ -50,7 +49,7 @@ $ cloud-platform environment apply -n --is-apply-pipeline is this running in the apply pipelines --kubecfg string path to kubeconfig file (default "/home/runner/.kube/config") -n, --namespace string Namespace which you want to perform the apply - --prNumber int Pull request ID or number to which you want to perform the apply + --pr-number int Pull request ID or number to which you want to perform the apply --redact Redact the terraform output before printing (default true) ``` @@ -62,5 +61,4 @@ $ cloud-platform environment apply -n ### SEE ALSO -* [cloud-platform environment](cloud-platform_environment.md) - Cloud Platform Environment actions - +* [cloud-platform environment](cloud-platform_environment.md) - Cloud Platform Environment actions diff --git a/doc/cloud-platform_environment_destroy.md b/doc/cloud-platform_environment_destroy.md index b230e3ef..2d0e14f3 100644 --- a/doc/cloud-platform_environment_destroy.md +++ b/doc/cloud-platform_environment_destroy.md @@ -4,25 +4,24 @@ Perform a terraform destroy and kubectl delete for a given namespace ### Synopsis - - Perform a kubectl destroy and a terraform delete for a given namespace using either -namespace flag or the - the namespace in the given PR Id/Number - - Along with the mandatory input flag, the below environments variables needs to be set - TF_VAR_cluster_name - e.g. "cp-1902-02" to get the vpc details for some modules like rds, es - TF_VAR_cluster_state_bucket - State where the cluster state is stored - TF_VAR_cluster_state_key - folder name/state key inside the state bucket where cluster state is stored - TF_VAR_github_owner - Github owner: ministryofjustice - TF_VAR_github_token - Personal access token with repo scope to push github action secrets - TF_VAR_kubernetes_cluster - Full name of the Cluster e.g. XXXXXX.gr7.eu-west2.eks.amazonaws.com - PINGDOM_API_TOKEN - API Token to access pingdom - PIPELINE_TERRAFORM_STATE_LOCK_TABLE - DynamoDB table where the state lock is stored - PIPELINE_STATE_BUCKET - State bucket where the environments state is stored e.g cloud-platform-terraform-state - PIPELINE_STATE_KEY_PREFIX - State key/ folder where the environments terraform state is stored e.g cloud-platform-environments - PIPELINE_STATE_REGION - State region of the bucket e.g. eu-west-1 - PIPELINE_CLUSTER - Cluster name/folder inside namespaces/ in cloud-platform-environments - PIPELINE_CLUSTER_STATE - Cluster name/folder inside the state bucket where the environments terraform state is stored - + Perform a kubectl destroy and a terraform delete for a given namespace using either -namespace flag or the + the namespace in the given PR Id/Number + + Along with the mandatory input flag, the below environments variables needs to be set + TF_VAR_cluster_name - e.g. "cp-1902-02" to get the vpc details for some modules like rds, es + TF_VAR_cluster_state_bucket - State where the cluster state is stored + TF_VAR_cluster_state_key - folder name/state key inside the state bucket where cluster state is stored + TF_VAR_github_owner - Github owner: ministryofjustice + TF_VAR_github_token - Personal access token with repo scope to push github action secrets + TF_VAR_kubernetes_cluster - Full name of the Cluster e.g. XXXXXX.gr7.eu-west2.eks.amazonaws.com + PINGDOM_API_TOKEN - API Token to access pingdom + PIPELINE_TERRAFORM_STATE_LOCK_TABLE - DynamoDB table where the state lock is stored + PIPELINE_STATE_BUCKET - State bucket where the environments state is stored e.g cloud-platform-terraform-state + PIPELINE_STATE_KEY_PREFIX - State key/ folder where the environments terraform state is stored e.g cloud-platform-environments + PIPELINE_STATE_REGION - State region of the bucket e.g. eu-west-1 + PIPELINE_CLUSTER - Cluster name/folder inside namespaces/ in cloud-platform-environments + PIPELINE_CLUSTER_STATE - Cluster name/folder inside the state bucket where the environments terraform state is stored + ``` cloud-platform environment destroy [flags] @@ -31,7 +30,7 @@ cloud-platform environment destroy [flags] ### Examples ``` -$ cloud-platform environment destroy -n +cloud-platform environment destroy -n ``` @@ -44,7 +43,7 @@ $ cloud-platform environment destroy -n -h, --help help for destroy --kubecfg string path to kubeconfig file (default "/home/runner/.kube/config") -n, --namespace string Namespace which you want to perform the destroy - --prNumber int Pull request ID or number to which you want to perform the destroy + --pr-number int Pull request ID or number to which you want to perform the destroy --redact Redact the terraform output before printing (default true) --skip-prod-destroy skip prod namespaces from destroy namespace (default true) ``` @@ -57,5 +56,4 @@ $ cloud-platform environment destroy -n ### SEE ALSO -* [cloud-platform environment](cloud-platform_environment.md) - Cloud Platform Environment actions - +* [cloud-platform environment](cloud-platform_environment.md) - Cloud Platform Environment actions diff --git a/doc/cloud-platform_environment_plan.md b/doc/cloud-platform_environment_plan.md index 26fc1390..769fd262 100644 --- a/doc/cloud-platform_environment_plan.md +++ b/doc/cloud-platform_environment_plan.md @@ -1,29 +1,27 @@ ## cloud-platform environment plan Perform a terraform plan and kubectl apply --dry-run=client for a given namespace using either -namespace flag or the - the namespace in the given PR Id/Number + the namespace in the given PR Id/Number ### Synopsis - - Perform a kubectl apply --dry-run=client and a terraform plan for a given namespace using either -namespace flag or the - the namespace in the given PR Id/Number - - Along with the mandatory input flag, the below environments variables needs to be set - TF_VAR_cluster_name - e.g. "cp-1902-02" to get the vpc details for some modules like rds, es - TF_VAR_cluster_state_bucket - State where the cluster state is stored - TF_VAR_cluster_state_key - folder name/state key inside the state bucket where cluster state is stored - TF_VAR_github_owner - Github owner: ministryofjustice - TF_VAR_github_token - Personal access token with repo scope to push github action secrets - TF_VAR_kubernetes_cluster - Full name of the Cluster e.g. XXXXXX.gr7.eu-west2.eks.amazonaws.com - PINGDOM_API_TOKEN - API Token to access pingdom - PIPELINE_TERRAFORM_STATE_LOCK_TABLE - DynamoDB table where the state lock is stored - PIPELINE_STATE_BUCKET - State bucket where the environments state is stored e.g cloud-platform-terraform-state - PIPELINE_STATE_KEY_PREFIX - State key/ folder where the environments terraform state is stored e.g cloud-platform-environments - PIPELINE_STATE_REGION - State region of the bucket e.g. eu-west-1 - PIPELINE_CLUSTER - Cluster name/folder inside namespaces/ in cloud-platform-environments - PIPELINE_CLUSTER_STATE - Cluster name/folder inside the state bucket where the environments terraform state is stored. for "live" the state is stored under "live-1.cloud-platform.service..." - + Perform a kubectl apply --dry-run=client and a terraform plan for a given namespace using either -namespace flag or the + the namespace in the given PR Id/Number + + Along with the mandatory input flag, the below environments variables needs to be set + TF_VAR_cluster_name - e.g. "cp-1902-02" to get the vpc details for some modules like rds, es + TF_VAR_cluster_state_bucket - State where the cluster state is stored + TF_VAR_cluster_state_key - folder name/state key inside the state bucket where cluster state is stored + TF_VAR_github_owner - Github owner: ministryofjustice + TF_VAR_github_token - Personal access token with repo scope to push github action secrets + TF_VAR_kubernetes_cluster - Full name of the Cluster e.g. XXXXXX.gr7.eu-west2.eks.amazonaws.com + PINGDOM_API_TOKEN - API Token to access pingdom + PIPELINE_TERRAFORM_STATE_LOCK_TABLE - DynamoDB table where the state lock is stored + PIPELINE_STATE_BUCKET - State bucket where the environments state is stored e.g cloud-platform-terraform-state + PIPELINE_STATE_KEY_PREFIX - State key/ folder where the environments terraform state is stored e.g cloud-platform-environments + PIPELINE_STATE_REGION - State region of the bucket e.g. eu-west-1 + PIPELINE_CLUSTER - Cluster name/folder inside namespaces/ in cloud-platform-environments + PIPELINE_CLUSTER_STATE - Cluster name/folder inside the state bucket where the environments terraform state is stored. for "live" the state is stored under "live-1.cloud-platform.service..." ``` cloud-platform environment plan [flags] @@ -32,7 +30,7 @@ cloud-platform environment plan [flags] ### Examples ``` -$ cloud-platform environment plan +cloud-platform environment plan ``` @@ -45,7 +43,7 @@ $ cloud-platform environment plan -h, --help help for plan --kubecfg string path to kubeconfig file (default "/home/runner/.kube/config") -n, --namespace string Namespace which you want to perform the plan - --prNumber int Pull request ID or number to which you want to perform the plan + --pr-number int Pull request ID or number to which you want to perform the plan --redact Redact the terraform output before printing (default true) ``` @@ -57,5 +55,4 @@ $ cloud-platform environment plan ### SEE ALSO -* [cloud-platform environment](cloud-platform_environment.md) - Cloud Platform Environment actions - +* [cloud-platform environment](cloud-platform_environment.md) - Cloud Platform Environment actions diff --git a/pkg/commands/environment.go b/pkg/commands/environment.go index 1ebd9b12..57b7f3cd 100644 --- a/pkg/commands/environment.go +++ b/pkg/commands/environment.go @@ -61,7 +61,7 @@ func addEnvironmentCmd(topLevel *cobra.Command) { environmentApplyCmd.Flags().IntVar(&optFlags.BatchApplySize, "batch-apply-size", 0, "Number of namespaces to apply in a batch") environmentApplyCmd.Flags().BoolVar(&optFlags.EnableApplySkip, "enable-apply-skip", false, "Enable skipping apply for a namespace") environmentApplyCmd.Flags().StringVarP(&optFlags.Namespace, "namespace", "n", "", "Namespace which you want to perform the apply") - environmentApplyCmd.Flags().IntVar(&optFlags.PRNumber, "prNumber", 0, "Pull request ID or number to which you want to perform the apply") + environmentApplyCmd.Flags().IntVar(&optFlags.PRNumber, "pr-number", 0, "Pull request ID or number to which you want to perform the apply") // Re-use the environmental variable TF_VAR_github_token to call Github Client which is needed to perform terraform operations on each namespace environmentApplyCmd.Flags().StringVar(&optFlags.GithubToken, "github-token", os.Getenv("TF_VAR_github_token"), "Personal access Token from Github ") environmentApplyCmd.Flags().StringVar(&optFlags.KubecfgPath, "kubecfg", filepath.Join(homedir.HomeDir(), ".kube", "config"), "path to kubeconfig file") @@ -78,7 +78,7 @@ func addEnvironmentCmd(topLevel *cobra.Command) { environmentCreateCmd.Flags().StringVarP(&answersFile, "answers-file", "a", "", "Path to the answers file") // e.g. if this is the Pull request to perform the apply: https://github.com/ministryofjustice/cloud-platform-environments/pull/8370, the pr ID is 8370. - environmentDestroyCmd.Flags().IntVar(&optFlags.PRNumber, "prNumber", 0, "Pull request ID or number to which you want to perform the destroy") + environmentDestroyCmd.Flags().IntVar(&optFlags.PRNumber, "pr-number", 0, "Pull request ID or number to which you want to perform the destroy") environmentDestroyCmd.Flags().StringVarP(&optFlags.Namespace, "namespace", "n", "", "Namespace which you want to perform the destroy") // Re-use the environmental variable TF_VAR_github_token to call Github Client which is needed to perform terraform operations on each namespace @@ -97,7 +97,7 @@ func addEnvironmentCmd(topLevel *cobra.Command) { } // e.g. if this is the Pull request to perform the apply: https://github.com/ministryofjustice/cloud-platform-environments/pull/8370, the pr ID is 8370. - environmentPlanCmd.Flags().IntVar(&optFlags.PRNumber, "prNumber", 0, "Pull request ID or number to which you want to perform the plan") + environmentPlanCmd.Flags().IntVar(&optFlags.PRNumber, "pr-number", 0, "Pull request ID or number to which you want to perform the plan") environmentPlanCmd.Flags().StringVarP(&optFlags.Namespace, "namespace", "n", "", "Namespace which you want to perform the plan") // Re-use the environmental variable TF_VAR_github_token to call Github Client which is needed to perform terraform operations on each namespace diff --git a/pkg/environment/environmentApply.go b/pkg/environment/apply.go similarity index 50% rename from pkg/environment/environmentApply.go rename to pkg/environment/apply.go index a2bc84e1..ccc659e9 100644 --- a/pkg/environment/environmentApply.go +++ b/pkg/environment/apply.go @@ -6,16 +6,9 @@ import ( "os" "strings" - gogithub "github.com/google/go-github/github" - - tfjson "github.com/hashicorp/terraform-json" - "github.com/kelseyhightower/envconfig" "github.com/ministryofjustice/cloud-platform-cli/pkg/github" "github.com/ministryofjustice/cloud-platform-cli/pkg/slack" "github.com/ministryofjustice/cloud-platform-cli/pkg/util" - "github.com/ministryofjustice/cloud-platform-environments/pkg/authenticate" - "github.com/ministryofjustice/cloud-platform-environments/pkg/namespace" - v1 "k8s.io/api/core/v1" ) // Options are used to configure plan/apply sessions. @@ -78,67 +71,6 @@ func NewApply(opt Options) *Apply { return &apply } -func (a *Apply) Initialize() { - var reqEnvVars RequiredEnvVars - err := envconfig.Process("", &reqEnvVars) - if err != nil { - log.Fatalln("Environment variables required to perform terraform operations not set:", err.Error()) - } - a.RequiredEnvVars.clustername = reqEnvVars.clustername - a.RequiredEnvVars.clusterstatebucket = reqEnvVars.clusterstatebucket - a.RequiredEnvVars.kubernetescluster = reqEnvVars.kubernetescluster - a.RequiredEnvVars.githubowner = reqEnvVars.githubowner - a.RequiredEnvVars.githubtoken = reqEnvVars.githubtoken - a.RequiredEnvVars.SlackBotToken = reqEnvVars.SlackBotToken - a.RequiredEnvVars.SlackWebhookUrl = reqEnvVars.SlackWebhookUrl - a.RequiredEnvVars.pingdomapitoken = reqEnvVars.pingdomapitoken - - // Set KUBE_CONFIG_PATH to the path of the kubeconfig file - // This is needed for terraform to be able to connect to the cluster when a different kubecfg is passed - if err := os.Setenv("KUBE_CONFIG_PATH", a.Options.KubecfgPath); err != nil { - log.Fatalln("KUBE_CONFIG_PATH environment variable cant be set:", err.Error()) - } -} - -// Plan is the entry point for performing a namespace plan. -// It checks if the working directory is in cloud-platform-environments, checks if a PR number or a namespace is given -// If a namespace is given, it perform a `kubectl apply --dry-run=client` and a terraform init and plan of that namespace -// else checks for PR number and get the list of changed namespaces in the PR. Then does the `kubectl apply --dry-run=client` and -// terraform init and plan of all the namespaces changed in the PR -func (a *Apply) Plan() error { - if a.Options.PRNumber == 0 && a.Options.Namespace == "" { - return fmt.Errorf("either a PR Id/Number or a namespace is required to perform plan") - } - - // If a namespace is given as a flag, then perform a plan for the given namespace. - if a.Options.Namespace != "" { - err := a.planNamespace() - if err != nil { - return err - } - return nil - } else { - files, err := a.GithubClient.GetChangedFiles(a.Options.PRNumber) - if err != nil { - return fmt.Errorf("failed to fetch list of changed files: %s in PR %v", err, a.Options.PRNumber) - } - - changedNamespaces, err := nsChangedInPR(files, a.Options.ClusterDir, false) - if err != nil { - fmt.Println("failed to get list of changed namespaces in PR:", err) - return err - } - for _, namespace := range changedNamespaces { - a.Options.Namespace = namespace - err = a.planNamespace() - if err != nil { - return err - } - } - } - return nil -} - // Apply is the entry point for performing a namespace apply. // It checks if the working directory is in cloud-platform-environments, checks if a PR number or a namespace is given // If a namespace is given, it perform a kubectl apply and a terraform init and apply of that namespace @@ -193,63 +125,6 @@ func (a *Apply) Apply() error { return nil } -// Destroy is the entry point for performing a namespace destroy. -// It checks if the working directory is in cloud-platform-environments, checks if a PR number is given and merged -// The method get the list of namespaces that are deleted in that merger PR, and for all namespaces in the PR does the -// terraform init and destroy and do a kubectl delete -func (a *Apply) Destroy() error { - fmt.Println("Destroying Namespaces in PR", a.Options.PRNumber) - if a.Options.PRNumber == 0 { - err := fmt.Errorf("a PR ID/Number is required to perform destroy") - return err - } - isMerged, err := a.GithubClient.IsMerged(a.Options.PRNumber) - if err != nil { - return err - } - if isMerged { - changedNamespaces, err := a.nsCreateRawChangedFilesInPR(a.Options.ClusterDir, a.Options.PRNumber) - if err != nil { - return err - } - if len(changedNamespaces) == 0 { - fmt.Println("No namespaces to destroy") - return nil - } - - fmt.Println("Namespaces removed in PR", changedNamespaces) - - kubeClient, err := authenticate.CreateClientFromConfigFile(a.Options.KubecfgPath, a.Options.ClusterCtx) - if err != nil { - return err - } - - // GetAllNamespacesFromCluster - namespaces, err := namespace.GetAllNamespacesFromCluster(kubeClient) - if err != nil { - return err - } - - for _, namespace := range changedNamespaces { - a.Options.Namespace = namespace - if a.Options.SkipProdDestroy && isProductionNs(namespace, namespaces) { - err := fmt.Errorf("cannot destroy production namespace with skip-prod-destroy flag set to true") - return err - } - // Check if the namespace is present in the folder - if _, err = os.Stat(a.Options.Namespace); err != nil { - fmt.Println("Destroying Namespace:", namespace) - err = a.destroyNamespace() - if err != nil { - return err - } - } - } - } - - return nil -} - // ApplyAll is the entry point for performing a namespace apply on all namespaces. // It checks if the working directory is in cloud-platform-environments, get the list of namespace folders and perform kubectl apply // and terraform init and apply of the namespace @@ -326,19 +201,6 @@ func (a *Apply) applyNamespaceDirs(chunkFolder []string) error { return nil } -// planKubectl calls the applier -> applyKubectl with dry-run enabled and return the output from applier -func (a *Apply) planKubectl() (string, error) { - log.Printf("Running kubectl dry-run for namespace: %v in directory %v", a.Options.Namespace, a.Dir) - - outputKubectl, err := a.Applier.KubectlApply(a.Options.Namespace, a.Dir, true) - if err != nil { - err := fmt.Errorf("error running kubectl on namespace %s: in directory: %v, %v\n %v", a.Options.Namespace, a.Dir, err, outputKubectl) - return "", err - } - - return outputKubectl, nil -} - // applyKubectl calls the applier -> applyKubectl with dry-run disabled and return the output from applier func (a *Apply) applyKubectl() (string, error) { log.Printf("Running kubectl for namespace: %v in directory %v", a.Options.Namespace, a.Dir) @@ -365,20 +227,6 @@ func (a *Apply) deleteKubectl() (string, error) { return outputKubectl, nil } -// planTerraform calls applier -> TerraformInitAndPlan and prints the output from applier -func (a *Apply) planTerraform() (*tfjson.Plan, string, error) { - log.Printf("Running Terraform Plan for namespace: %v", a.Options.Namespace) - - tfFolder := a.Dir + "/resources" - - tfPlan, outputTerraform, err := a.Applier.TerraformInitAndPlan(a.Options.Namespace, tfFolder) - if err != nil { - err := fmt.Errorf("error running terraform on namespace %s: %v \n %v", a.Options.Namespace, err, outputTerraform) - return nil, "", err - } - return tfPlan, outputTerraform, nil -} - // applyTerraform calls applier -> TerraformInitAndApply and prints the output from applier func (a *Apply) applyTerraform() (string, error) { log.Printf("Running Terraform Apply for namespace: %v", a.Options.Namespace) @@ -411,58 +259,6 @@ func (a *Apply) applyTerraform() (string, error) { return outputTerraform, nil } -// destroyTerraform calls applier -> TerraformInitAndDestroy and prints the output from applier -func (a *Apply) destroyTerraform() (string, error) { - log.Printf("Running Terraform Destroy for namespace: %v", a.Options.Namespace) - - tfFolder := a.Dir + "/resources" - - outputTerraform, err := a.Applier.TerraformInitAndDestroy(a.Options.Namespace, tfFolder) - if err != nil { - err := fmt.Errorf("error running terraform on namespace %s: %v \n %v", a.Options.Namespace, err, outputTerraform) - return "", err - } - return outputTerraform, nil -} - -// planNamespace intiates a new Apply object with options and env variables, and calls the -// applyKubectl with dry-run enabled and calls applier TerraformInitAndPlan and prints the output -func (a *Apply) planNamespace() error { - applier := NewApply(*a.Options) - repoPath := "namespaces/" + a.Options.ClusterDir + "/" + a.Options.Namespace - - if util.IsYamlFileExists(repoPath) { - outputKubectl, err := applier.planKubectl() - if err != nil { - return err - } - - fmt.Println("\nOutput of kubectl:", outputKubectl) - } else { - fmt.Printf("Namespace %s does not have yaml resources folder, skipping kubectl apply --dry-run\n", a.Options.Namespace) - } - - exists, err := util.IsFilePathExists(repoPath + "/resources") - if err == nil && exists { - tfPlan, outputTerraform, err := applier.planTerraform() - if err != nil { - return err - } - - fmt.Println("\nOutput of terraform:") - - commentErr := CreateComment(a.GithubClient, tfPlan, a.Options.PRNumber) - if commentErr != nil { - fmt.Printf("\nError posting comment: %v", commentErr) - } - - util.RedactedEnv(os.Stdout, outputTerraform, a.Options.RedactedEnv) - } else { - fmt.Printf("Namespace %s does not have terraform resources folder, skipping terraform plan\n", a.Options.Namespace) - } - return nil -} - // secretBlockerExists takes a filepath (usually a namespace name i.e. namespaces/live.../mynamespace) // and checks if the file SECRET_ROTATE_BLOCK exists. func secretBlockerExists(filePath string) bool { @@ -552,137 +348,3 @@ func (a *Apply) applyNamespace() error { } return nil } - -// destroyNamespace intiates a apply object with options and env variables, and calls the -// calls applier TerraformInitAndDestroy, applyKubectl with dry-run disabled and prints the output -func (a *Apply) destroyNamespace() error { - repoPath := "namespaces/" + a.Options.ClusterDir + "/" + a.Options.Namespace - - if _, err := os.Stat(repoPath); os.IsNotExist(err) { - fmt.Printf("Namespace %s does not exist, skipping destroy\n", a.Options.Namespace) - return nil - } - - applier := NewApply(*a.Options) - - exists, err := util.IsFilePathExists(repoPath + "/resources") - if err == nil && exists { - outputTerraform, err := applier.destroyTerraform() - if err != nil { - return err - } - - fmt.Println("\nOutput of terraform:") - util.RedactedEnv(os.Stdout, outputTerraform, a.Options.RedactedEnv) - - if util.IsYamlFileExists(repoPath) { - outputKubectl, err := applier.deleteKubectl() - if err != nil { - return err - } - - fmt.Println("\nOutput of kubectl:", outputKubectl) - } else { - fmt.Printf("Namespace %s does not have yaml resources folder, skipping kubectl delete", a.Options.Namespace) - } - - } else { - fmt.Printf("Namespace %s does not have terraform resources folder, skipping terraform destroy", a.Options.Namespace) - } - return nil -} - -// nsCreateRawChangedFilesInPR get the list of changed files for a given PR. checks if the file is deleted and -// write the deleted file to the namespace folder -func (a *Apply) nsCreateRawChangedFilesInPR(cluster string, prNumber int) ([]string, error) { - files, err := a.GithubClient.GetChangedFiles(prNumber) - if err != nil { - return nil, fmt.Errorf("failed to fetch list of changed files: %s", err) - } - - namespaces, err := nsChangedInPR(files, a.Options.ClusterDir, true) - if err != nil { - return nil, fmt.Errorf("failed to get namespace for destroy from the PR: %s", err) - } - if len(namespaces) == 0 { - fmt.Println("No namespace found in the PR for destroy") - return nil, nil - } - canCreate, err := canCreateNamespaces(namespaces, cluster) - if err != nil { - return nil, fmt.Errorf("failed to create namespace for destroy: %s", err) - } - if !canCreate { - fmt.Println("Cannot create namespace for destroy") - return nil, nil - } - - // Get the contents of the CommitFile from RawURL - // https://developer.github.com/v3/repos/contents/#get-contents - - for _, file := range files { - data, err := util.GetGithubRawContents(file.GetRawURL()) - if err != nil { - return nil, fmt.Errorf("failed to get raw contents: %s", err) - } - // Create List with changed files - if err := os.WriteFile(*file.Filename, data, 0644); err != nil { - return nil, fmt.Errorf("failed to write file list: %s", err) - } - } - return namespaces, nil -} - -// nsChangedInPR get the list of changed files for a given PR. checks if the namespaces exists in the given cluster -// folder and return the list of namespaces. -func nsChangedInPR(files []*gogithub.CommitFile, cluster string, isDeleted bool) ([]string, error) { - var namespaceNames []string - for _, file := range files { - // check of the file is a deleted file - if isDeleted && *file.Status != "removed" { - fmt.Println("some of files are not marked for deletion: file", *file.Filename, "is not deleted") - return nil, nil - } - - // namespaces filepaths are assumed to come in - // the format: namespaces/.cloud-platform.service.justice.gov.uk/ - s := strings.Split(*file.Filename, "/") - // only get namespaces from the folder that belong to the given cluster and - // ignore changes outside namespace directories - if len(s) > 1 && s[1] == cluster { - namespaceNames = append(namespaceNames, s[2]) - } - } - return util.DeduplicateList(namespaceNames), nil -} - -func canCreateNamespaces(namespaces []string, cluster string) (bool, error) { - wd, _ := os.Getwd() - for _, ns := range namespaces { - // make directory if it doesn't exist - if _, err := os.Stat(wd + "/namespaces/" + cluster + "/" + ns); err != nil { - err := os.Mkdir(wd+"/namespaces/"+cluster+"/"+ns, 0755) - if err != nil { - return false, fmt.Errorf("error creating namespaces directory: %s", err) - } - err = os.Mkdir(wd+"/namespaces/"+cluster+"/"+ns+"/resources", 0755) - if err != nil { - return false, fmt.Errorf("error creating resources directory: %s", err) - } - } else { - fmt.Printf("namespace %s exists in the environments repo, skipping destroy", ns) - return false, nil - } - } - return true, nil -} - -func isProductionNs(nsInPR string, namespaces []v1.Namespace) bool { - for _, ns := range namespaces { - is_prod := ns.Labels["cloud-platform.justice.gov.uk/is-production"] == "true" - if ns.Name == nsInPR && is_prod { - return true - } - } - return false -} diff --git a/pkg/environment/environmentApply_test.go b/pkg/environment/apply_test.go similarity index 100% rename from pkg/environment/environmentApply_test.go rename to pkg/environment/apply_test.go diff --git a/pkg/environment/destroy.go b/pkg/environment/destroy.go new file mode 100644 index 00000000..0848fc13 --- /dev/null +++ b/pkg/environment/destroy.go @@ -0,0 +1,122 @@ +package environment + +import ( + "fmt" + "log" + "os" + + "github.com/ministryofjustice/cloud-platform-environments/pkg/authenticate" + "github.com/ministryofjustice/cloud-platform-environments/pkg/namespace" + + "github.com/ministryofjustice/cloud-platform-cli/pkg/util" +) + +// Destroy is the entry point for performing a namespace destroy. +// It checks if the working directory is in cloud-platform-environments, checks if a PR number is given and merged +// The method get the list of namespaces that are deleted in that merger PR, and for all namespaces in the PR does the +// terraform init and destroy and do a kubectl delete +func (a *Apply) Destroy() error { + fmt.Println("Destroying Namespaces in PR", a.Options.PRNumber) + if a.Options.PRNumber == 0 { + err := fmt.Errorf("a PR ID/Number is required to perform destroy") + return err + } + isMerged, err := a.GithubClient.IsMerged(a.Options.PRNumber) + if err != nil { + return err + } + if isMerged { + changedNamespaces, err := a.nsCreateRawChangedFilesInPR(a.Options.ClusterDir, a.Options.PRNumber) + if err != nil { + return err + } + if len(changedNamespaces) == 0 { + fmt.Println("No namespaces to destroy") + return nil + } + + fmt.Println("Namespaces removed in PR", changedNamespaces) + + kubeClient, err := authenticate.CreateClientFromConfigFile(a.Options.KubecfgPath, a.Options.ClusterCtx) + if err != nil { + return err + } + + // GetAllNamespacesFromCluster + namespaces, err := namespace.GetAllNamespacesFromCluster(kubeClient) + if err != nil { + return err + } + + for _, namespace := range changedNamespaces { + a.Options.Namespace = namespace + if a.Options.SkipProdDestroy && isProductionNs(namespace, namespaces) { + err := fmt.Errorf("cannot destroy production namespace with skip-prod-destroy flag set to true") + return err + } + // Check if the namespace is present in the folder + if _, err = os.Stat(a.Options.Namespace); err != nil { + fmt.Println("Destroying Namespace:", namespace) + err = a.destroyNamespace() + if err != nil { + return err + } + } + } + } + + return nil +} + +// destroyTerraform calls applier -> TerraformInitAndDestroy and prints the output from applier +func (a *Apply) destroyTerraform() (string, error) { + log.Printf("Running Terraform Destroy for namespace: %v", a.Options.Namespace) + + tfFolder := a.Dir + "/resources" + + outputTerraform, err := a.Applier.TerraformInitAndDestroy(a.Options.Namespace, tfFolder) + if err != nil { + err := fmt.Errorf("error running terraform on namespace %s: %v \n %v", a.Options.Namespace, err, outputTerraform) + return "", err + } + return outputTerraform, nil +} + +// destroyNamespace intiates a apply object with options and env variables, and calls the +// calls applier TerraformInitAndDestroy, applyKubectl with dry-run disabled and prints the output +func (a *Apply) destroyNamespace() error { + repoPath := "namespaces/" + a.Options.ClusterDir + "/" + a.Options.Namespace + + if _, err := os.Stat(repoPath); os.IsNotExist(err) { + fmt.Printf("Namespace %s does not exist, skipping destroy\n", a.Options.Namespace) + return nil + } + + applier := NewApply(*a.Options) + + exists, err := util.IsFilePathExists(repoPath + "/resources") + if err == nil && exists { + outputTerraform, err := applier.destroyTerraform() + if err != nil { + return err + } + + fmt.Println("\nOutput of terraform:") + util.RedactedEnv(os.Stdout, outputTerraform, a.Options.RedactedEnv) + + if util.IsYamlFileExists(repoPath) { + outputKubectl, err := applier.deleteKubectl() + if err != nil { + return err + } + + fmt.Println("\nOutput of kubectl:", outputKubectl) + } else { + fmt.Printf("Namespace %s does not have yaml resources folder, skipping kubectl delete", a.Options.Namespace) + } + + } else { + fmt.Printf("Namespace %s does not have terraform resources folder, skipping terraform destroy", a.Options.Namespace) + } + return nil +} diff --git a/pkg/environment/init.go b/pkg/environment/init.go new file mode 100644 index 00000000..d4777529 --- /dev/null +++ b/pkg/environment/init.go @@ -0,0 +1,30 @@ +package environment + +import ( + "log" + "os" + + "github.com/kelseyhightower/envconfig" +) + +func (a *Apply) Initialize() { + var reqEnvVars RequiredEnvVars + err := envconfig.Process("", &reqEnvVars) + if err != nil { + log.Fatalln("Environment variables required to perform terraform operations not set:", err.Error()) + } + a.RequiredEnvVars.clustername = reqEnvVars.clustername + a.RequiredEnvVars.clusterstatebucket = reqEnvVars.clusterstatebucket + a.RequiredEnvVars.kubernetescluster = reqEnvVars.kubernetescluster + a.RequiredEnvVars.githubowner = reqEnvVars.githubowner + a.RequiredEnvVars.githubtoken = reqEnvVars.githubtoken + a.RequiredEnvVars.SlackBotToken = reqEnvVars.SlackBotToken + a.RequiredEnvVars.SlackWebhookUrl = reqEnvVars.SlackWebhookUrl + a.RequiredEnvVars.pingdomapitoken = reqEnvVars.pingdomapitoken + + // Set KUBE_CONFIG_PATH to the path of the kubeconfig file + // This is needed for terraform to be able to connect to the cluster when a different kubecfg is passed + if err := os.Setenv("KUBE_CONFIG_PATH", a.Options.KubecfgPath); err != nil { + log.Fatalln("KUBE_CONFIG_PATH environment variable cant be set:", err.Error()) + } +} diff --git a/pkg/environment/namespace.go b/pkg/environment/namespace.go index 97b0f069..71280634 100644 --- a/pkg/environment/namespace.go +++ b/pkg/environment/namespace.go @@ -5,7 +5,10 @@ import ( "os" "strings" + gogithub "github.com/google/go-github/github" + "github.com/ministryofjustice/cloud-platform-cli/pkg/util" "gopkg.in/yaml.v2" + v1 "k8s.io/api/core/v1" ) const NamespaceYamlFile = "00-namespace.yaml" @@ -84,3 +87,98 @@ func (ns *Namespace) parseYaml(yamlData []byte) error { return nil } + +// nsCreateRawChangedFilesInPR get the list of changed files for a given PR. checks if the file is deleted and +// write the deleted file to the namespace folder +func (a *Apply) nsCreateRawChangedFilesInPR(cluster string, prNumber int) ([]string, error) { + files, err := a.GithubClient.GetChangedFiles(prNumber) + if err != nil { + return nil, fmt.Errorf("failed to fetch list of changed files: %s", err) + } + + namespaces, err := nsChangedInPR(files, a.Options.ClusterDir, true) + if err != nil { + return nil, fmt.Errorf("failed to get namespace for destroy from the PR: %s", err) + } + if len(namespaces) == 0 { + fmt.Println("No namespace found in the PR for destroy") + return nil, nil + } + canCreate, err := canCreateNamespaces(namespaces, cluster) + if err != nil { + return nil, fmt.Errorf("failed to create namespace for destroy: %s", err) + } + if !canCreate { + fmt.Println("Cannot create namespace for destroy") + return nil, nil + } + + // Get the contents of the CommitFile from RawURL + // https://developer.github.com/v3/repos/contents/#get-contents + + for _, file := range files { + data, err := util.GetGithubRawContents(file.GetRawURL()) + if err != nil { + return nil, fmt.Errorf("failed to get raw contents: %s", err) + } + // Create List with changed files + if err := os.WriteFile(*file.Filename, data, 0644); err != nil { + return nil, fmt.Errorf("failed to write file list: %s", err) + } + } + return namespaces, nil +} + +// nsChangedInPR get the list of changed files for a given PR. checks if the namespaces exists in the given cluster +// folder and return the list of namespaces. +func nsChangedInPR(files []*gogithub.CommitFile, cluster string, isDeleted bool) ([]string, error) { + var namespaceNames []string + for _, file := range files { + // check of the file is a deleted file + if isDeleted && *file.Status != "removed" { + fmt.Println("some of files are not marked for deletion: file", *file.Filename, "is not deleted") + return nil, nil + } + + // namespaces filepaths are assumed to come in + // the format: namespaces/.cloud-platform.service.justice.gov.uk/ + s := strings.Split(*file.Filename, "/") + // only get namespaces from the folder that belong to the given cluster and + // ignore changes outside namespace directories + if len(s) > 1 && s[1] == cluster { + namespaceNames = append(namespaceNames, s[2]) + } + } + return util.DeduplicateList(namespaceNames), nil +} + +func canCreateNamespaces(namespaces []string, cluster string) (bool, error) { + wd, _ := os.Getwd() + for _, ns := range namespaces { + // make directory if it doesn't exist + if _, err := os.Stat(wd + "/namespaces/" + cluster + "/" + ns); err != nil { + err := os.Mkdir(wd+"/namespaces/"+cluster+"/"+ns, 0755) + if err != nil { + return false, fmt.Errorf("error creating namespaces directory: %s", err) + } + err = os.Mkdir(wd+"/namespaces/"+cluster+"/"+ns+"/resources", 0755) + if err != nil { + return false, fmt.Errorf("error creating resources directory: %s", err) + } + } else { + fmt.Printf("namespace %s exists in the environments repo, skipping destroy", ns) + return false, nil + } + } + return true, nil +} + +func isProductionNs(nsInPR string, namespaces []v1.Namespace) bool { + for _, ns := range namespaces { + is_prod := ns.Labels["cloud-platform.justice.gov.uk/is-production"] == "true" + if ns.Name == nsInPR && is_prod { + return true + } + } + return false +} diff --git a/pkg/environment/plan.go b/pkg/environment/plan.go new file mode 100644 index 00000000..47cae60e --- /dev/null +++ b/pkg/environment/plan.go @@ -0,0 +1,113 @@ +package environment + +import ( + "fmt" + "log" + "os" + + tfjson "github.com/hashicorp/terraform-json" + "github.com/ministryofjustice/cloud-platform-cli/pkg/util" +) + +// planKubectl calls the applier -> applyKubectl with dry-run enabled and return the output from applier +func (a *Apply) planKubectl() (string, error) { + log.Printf("Running kubectl dry-run for namespace: %v in directory %v", a.Options.Namespace, a.Dir) + + outputKubectl, err := a.Applier.KubectlApply(a.Options.Namespace, a.Dir, true) + if err != nil { + err := fmt.Errorf("error running kubectl on namespace %s: in directory: %v, %v\n %v", a.Options.Namespace, a.Dir, err, outputKubectl) + return "", err + } + + return outputKubectl, nil +} + +// Plan is the entry point for performing a namespace plan. +// It checks if the working directory is in cloud-platform-environments, checks if a PR number or a namespace is given +// If a namespace is given, it perform a `kubectl apply --dry-run=client` and a terraform init and plan of that namespace +// else checks for PR number and get the list of changed namespaces in the PR. Then does the `kubectl apply --dry-run=client` and +// terraform init and plan of all the namespaces changed in the PR +func (a *Apply) Plan() error { + if a.Options.PRNumber == 0 && a.Options.Namespace == "" { + return fmt.Errorf("either a PR Id/Number or a namespace is required to perform plan") + } + + // If a namespace is given as a flag, then perform a plan for the given namespace. + if a.Options.Namespace != "" { + err := a.planNamespace() + if err != nil { + return err + } + return nil + } else { + files, err := a.GithubClient.GetChangedFiles(a.Options.PRNumber) + if err != nil { + return fmt.Errorf("failed to fetch list of changed files: %s in PR %v", err, a.Options.PRNumber) + } + + changedNamespaces, err := nsChangedInPR(files, a.Options.ClusterDir, false) + if err != nil { + fmt.Println("failed to get list of changed namespaces in PR:", err) + return err + } + for _, namespace := range changedNamespaces { + a.Options.Namespace = namespace + err = a.planNamespace() + if err != nil { + return err + } + } + } + return nil +} + +// planTerraform calls applier -> TerraformInitAndPlan and prints the output from applier +func (a *Apply) planTerraform() (*tfjson.Plan, string, error) { + log.Printf("Running Terraform Plan for namespace: %v", a.Options.Namespace) + + tfFolder := a.Dir + "/resources" + + tfPlan, outputTerraform, err := a.Applier.TerraformInitAndPlan(a.Options.Namespace, tfFolder) + if err != nil { + err := fmt.Errorf("error running terraform on namespace %s: %v \n %v", a.Options.Namespace, err, outputTerraform) + return nil, "", err + } + return tfPlan, outputTerraform, nil +} + +// planNamespace intiates a new Apply object with options and env variables, and calls the +// applyKubectl with dry-run enabled and calls applier TerraformInitAndPlan and prints the output +func (a *Apply) planNamespace() error { + applier := NewApply(*a.Options) + repoPath := "namespaces/" + a.Options.ClusterDir + "/" + a.Options.Namespace + + if util.IsYamlFileExists(repoPath) { + outputKubectl, err := applier.planKubectl() + if err != nil { + return err + } + + fmt.Println("\nOutput of kubectl:", outputKubectl) + } else { + fmt.Printf("Namespace %s does not have yaml resources folder, skipping kubectl apply --dry-run\n", a.Options.Namespace) + } + + exists, err := util.IsFilePathExists(repoPath + "/resources") + if err == nil && exists { + tfPlan, outputTerraform, err := applier.planTerraform() + if err != nil { + return err + } + + fmt.Println("\nOutput of terraform:") + + commentErr := CreateComment(a.GithubClient, tfPlan, a.Options.PRNumber) + if commentErr != nil { + fmt.Printf("\nError posting comment: %v", commentErr) + } + util.RedactedEnv(os.Stdout, outputTerraform, a.Options.RedactedEnv) + } else { + fmt.Printf("Namespace %s does not have terraform resources folder, skipping terraform plan\n", a.Options.Namespace) + } + return nil +} From a2ed8afee156111f9f3c91e0c18a0e32a94c9dc9 Mon Sep 17 00:00:00 2001 From: jaskaransarkaria Date: Wed, 2 Oct 2024 15:22:57 +0000 Subject: [PATCH 2/2] docs(cobra): update auto-generated documentation --- doc/cloud-platform_environment_apply.md | 44 +++++++++++----------- doc/cloud-platform_environment_destroy.md | 44 +++++++++++----------- doc/cloud-platform_environment_plan.md | 45 ++++++++++++----------- 3 files changed, 70 insertions(+), 63 deletions(-) diff --git a/doc/cloud-platform_environment_apply.md b/doc/cloud-platform_environment_apply.md index 4de39941..41f24a2b 100644 --- a/doc/cloud-platform_environment_apply.md +++ b/doc/cloud-platform_environment_apply.md @@ -4,24 +4,25 @@ Perform a terraform apply and kubectl apply for a given namespace ### Synopsis - Perform a kubectl apply and a terraform apply for a given namespace using either -namespace flag or the - the namespace in the given PR Id/Number - - Along with the mandatory input flag, the below environments variables needs to be set - TF_VAR_cluster_name - e.g. "cp-1902-02" to get the vpc details for some modules like rds, es - TF_VAR_cluster_state_bucket - State where the cluster state is stored - TF_VAR_cluster_state_key - folder name/state key inside the state bucket where cluster state is stored - TF_VAR_github_owner - Github owner: ministryofjustice - TF_VAR_github_token - Personal access token with repo scope to push github action secrets - TF_VAR_kubernetes_cluster - Full name of the Cluster e.g. XXXXXX.gr7.eu-west2.eks.amazonaws.com - PINGDOM_API_TOKEN - API Token to access pingdom - PIPELINE_TERRAFORM_STATE_LOCK_TABLE - DynamoDB table where the state lock is stored - PIPELINE_STATE_BUCKET - State bucket where the environments state is stored e.g cloud-platform-terraform-state - PIPELINE_STATE_KEY_PREFIX - State key/ folder where the environments terraform state is stored e.g cloud-platform-environments - PIPELINE_STATE_REGION - State region of the bucket e.g. eu-west-1 - PIPELINE_CLUSTER - Cluster name/folder inside namespaces/ in cloud-platform-environments - PIPELINE_CLUSTER_STATE - Cluster name/folder inside the state bucket where the environments terraform state is stored - + + Perform a kubectl apply and a terraform apply for a given namespace using either -namespace flag or the + the namespace in the given PR Id/Number + + Along with the mandatory input flag, the below environments variables needs to be set + TF_VAR_cluster_name - e.g. "cp-1902-02" to get the vpc details for some modules like rds, es + TF_VAR_cluster_state_bucket - State where the cluster state is stored + TF_VAR_cluster_state_key - folder name/state key inside the state bucket where cluster state is stored + TF_VAR_github_owner - Github owner: ministryofjustice + TF_VAR_github_token - Personal access token with repo scope to push github action secrets + TF_VAR_kubernetes_cluster - Full name of the Cluster e.g. XXXXXX.gr7.eu-west2.eks.amazonaws.com + PINGDOM_API_TOKEN - API Token to access pingdom + PIPELINE_TERRAFORM_STATE_LOCK_TABLE - DynamoDB table where the state lock is stored + PIPELINE_STATE_BUCKET - State bucket where the environments state is stored e.g cloud-platform-terraform-state + PIPELINE_STATE_KEY_PREFIX - State key/ folder where the environments terraform state is stored e.g cloud-platform-environments + PIPELINE_STATE_REGION - State region of the bucket e.g. eu-west-1 + PIPELINE_CLUSTER - Cluster name/folder inside namespaces/ in cloud-platform-environments + PIPELINE_CLUSTER_STATE - Cluster name/folder inside the state bucket where the environments terraform state is stored + ``` cloud-platform environment apply [flags] @@ -30,7 +31,7 @@ cloud-platform environment apply [flags] ### Examples ``` -cloud-platform environment apply -n +$ cloud-platform environment apply -n ``` @@ -49,7 +50,7 @@ cloud-platform environment apply -n --is-apply-pipeline is this running in the apply pipelines --kubecfg string path to kubeconfig file (default "/home/runner/.kube/config") -n, --namespace string Namespace which you want to perform the apply - --pr-number int Pull request ID or number to which you want to perform the apply + --pr-number int Pull request ID or number to which you want to perform the apply --redact Redact the terraform output before printing (default true) ``` @@ -61,4 +62,5 @@ cloud-platform environment apply -n ### SEE ALSO -* [cloud-platform environment](cloud-platform_environment.md) - Cloud Platform Environment actions +* [cloud-platform environment](cloud-platform_environment.md) - Cloud Platform Environment actions + diff --git a/doc/cloud-platform_environment_destroy.md b/doc/cloud-platform_environment_destroy.md index 2d0e14f3..9082559a 100644 --- a/doc/cloud-platform_environment_destroy.md +++ b/doc/cloud-platform_environment_destroy.md @@ -4,24 +4,25 @@ Perform a terraform destroy and kubectl delete for a given namespace ### Synopsis - Perform a kubectl destroy and a terraform delete for a given namespace using either -namespace flag or the - the namespace in the given PR Id/Number - - Along with the mandatory input flag, the below environments variables needs to be set - TF_VAR_cluster_name - e.g. "cp-1902-02" to get the vpc details for some modules like rds, es - TF_VAR_cluster_state_bucket - State where the cluster state is stored - TF_VAR_cluster_state_key - folder name/state key inside the state bucket where cluster state is stored - TF_VAR_github_owner - Github owner: ministryofjustice - TF_VAR_github_token - Personal access token with repo scope to push github action secrets - TF_VAR_kubernetes_cluster - Full name of the Cluster e.g. XXXXXX.gr7.eu-west2.eks.amazonaws.com - PINGDOM_API_TOKEN - API Token to access pingdom - PIPELINE_TERRAFORM_STATE_LOCK_TABLE - DynamoDB table where the state lock is stored - PIPELINE_STATE_BUCKET - State bucket where the environments state is stored e.g cloud-platform-terraform-state - PIPELINE_STATE_KEY_PREFIX - State key/ folder where the environments terraform state is stored e.g cloud-platform-environments - PIPELINE_STATE_REGION - State region of the bucket e.g. eu-west-1 - PIPELINE_CLUSTER - Cluster name/folder inside namespaces/ in cloud-platform-environments - PIPELINE_CLUSTER_STATE - Cluster name/folder inside the state bucket where the environments terraform state is stored - + + Perform a kubectl destroy and a terraform delete for a given namespace using either -namespace flag or the + the namespace in the given PR Id/Number + + Along with the mandatory input flag, the below environments variables needs to be set + TF_VAR_cluster_name - e.g. "cp-1902-02" to get the vpc details for some modules like rds, es + TF_VAR_cluster_state_bucket - State where the cluster state is stored + TF_VAR_cluster_state_key - folder name/state key inside the state bucket where cluster state is stored + TF_VAR_github_owner - Github owner: ministryofjustice + TF_VAR_github_token - Personal access token with repo scope to push github action secrets + TF_VAR_kubernetes_cluster - Full name of the Cluster e.g. XXXXXX.gr7.eu-west2.eks.amazonaws.com + PINGDOM_API_TOKEN - API Token to access pingdom + PIPELINE_TERRAFORM_STATE_LOCK_TABLE - DynamoDB table where the state lock is stored + PIPELINE_STATE_BUCKET - State bucket where the environments state is stored e.g cloud-platform-terraform-state + PIPELINE_STATE_KEY_PREFIX - State key/ folder where the environments terraform state is stored e.g cloud-platform-environments + PIPELINE_STATE_REGION - State region of the bucket e.g. eu-west-1 + PIPELINE_CLUSTER - Cluster name/folder inside namespaces/ in cloud-platform-environments + PIPELINE_CLUSTER_STATE - Cluster name/folder inside the state bucket where the environments terraform state is stored + ``` cloud-platform environment destroy [flags] @@ -30,7 +31,7 @@ cloud-platform environment destroy [flags] ### Examples ``` -cloud-platform environment destroy -n +$ cloud-platform environment destroy -n ``` @@ -43,7 +44,7 @@ cloud-platform environment destroy -n -h, --help help for destroy --kubecfg string path to kubeconfig file (default "/home/runner/.kube/config") -n, --namespace string Namespace which you want to perform the destroy - --pr-number int Pull request ID or number to which you want to perform the destroy + --pr-number int Pull request ID or number to which you want to perform the destroy --redact Redact the terraform output before printing (default true) --skip-prod-destroy skip prod namespaces from destroy namespace (default true) ``` @@ -56,4 +57,5 @@ cloud-platform environment destroy -n ### SEE ALSO -* [cloud-platform environment](cloud-platform_environment.md) - Cloud Platform Environment actions +* [cloud-platform environment](cloud-platform_environment.md) - Cloud Platform Environment actions + diff --git a/doc/cloud-platform_environment_plan.md b/doc/cloud-platform_environment_plan.md index 769fd262..039f6962 100644 --- a/doc/cloud-platform_environment_plan.md +++ b/doc/cloud-platform_environment_plan.md @@ -1,27 +1,29 @@ ## cloud-platform environment plan Perform a terraform plan and kubectl apply --dry-run=client for a given namespace using either -namespace flag or the - the namespace in the given PR Id/Number + the namespace in the given PR Id/Number ### Synopsis - Perform a kubectl apply --dry-run=client and a terraform plan for a given namespace using either -namespace flag or the - the namespace in the given PR Id/Number - - Along with the mandatory input flag, the below environments variables needs to be set - TF_VAR_cluster_name - e.g. "cp-1902-02" to get the vpc details for some modules like rds, es - TF_VAR_cluster_state_bucket - State where the cluster state is stored - TF_VAR_cluster_state_key - folder name/state key inside the state bucket where cluster state is stored - TF_VAR_github_owner - Github owner: ministryofjustice - TF_VAR_github_token - Personal access token with repo scope to push github action secrets - TF_VAR_kubernetes_cluster - Full name of the Cluster e.g. XXXXXX.gr7.eu-west2.eks.amazonaws.com - PINGDOM_API_TOKEN - API Token to access pingdom - PIPELINE_TERRAFORM_STATE_LOCK_TABLE - DynamoDB table where the state lock is stored - PIPELINE_STATE_BUCKET - State bucket where the environments state is stored e.g cloud-platform-terraform-state - PIPELINE_STATE_KEY_PREFIX - State key/ folder where the environments terraform state is stored e.g cloud-platform-environments - PIPELINE_STATE_REGION - State region of the bucket e.g. eu-west-1 - PIPELINE_CLUSTER - Cluster name/folder inside namespaces/ in cloud-platform-environments - PIPELINE_CLUSTER_STATE - Cluster name/folder inside the state bucket where the environments terraform state is stored. for "live" the state is stored under "live-1.cloud-platform.service..." + + Perform a kubectl apply --dry-run=client and a terraform plan for a given namespace using either -namespace flag or the + the namespace in the given PR Id/Number + + Along with the mandatory input flag, the below environments variables needs to be set + TF_VAR_cluster_name - e.g. "cp-1902-02" to get the vpc details for some modules like rds, es + TF_VAR_cluster_state_bucket - State where the cluster state is stored + TF_VAR_cluster_state_key - folder name/state key inside the state bucket where cluster state is stored + TF_VAR_github_owner - Github owner: ministryofjustice + TF_VAR_github_token - Personal access token with repo scope to push github action secrets + TF_VAR_kubernetes_cluster - Full name of the Cluster e.g. XXXXXX.gr7.eu-west2.eks.amazonaws.com + PINGDOM_API_TOKEN - API Token to access pingdom + PIPELINE_TERRAFORM_STATE_LOCK_TABLE - DynamoDB table where the state lock is stored + PIPELINE_STATE_BUCKET - State bucket where the environments state is stored e.g cloud-platform-terraform-state + PIPELINE_STATE_KEY_PREFIX - State key/ folder where the environments terraform state is stored e.g cloud-platform-environments + PIPELINE_STATE_REGION - State region of the bucket e.g. eu-west-1 + PIPELINE_CLUSTER - Cluster name/folder inside namespaces/ in cloud-platform-environments + PIPELINE_CLUSTER_STATE - Cluster name/folder inside the state bucket where the environments terraform state is stored. for "live" the state is stored under "live-1.cloud-platform.service..." + ``` cloud-platform environment plan [flags] @@ -30,7 +32,7 @@ cloud-platform environment plan [flags] ### Examples ``` -cloud-platform environment plan +$ cloud-platform environment plan ``` @@ -43,7 +45,7 @@ cloud-platform environment plan -h, --help help for plan --kubecfg string path to kubeconfig file (default "/home/runner/.kube/config") -n, --namespace string Namespace which you want to perform the plan - --pr-number int Pull request ID or number to which you want to perform the plan + --pr-number int Pull request ID or number to which you want to perform the plan --redact Redact the terraform output before printing (default true) ``` @@ -55,4 +57,5 @@ cloud-platform environment plan ### SEE ALSO -* [cloud-platform environment](cloud-platform_environment.md) - Cloud Platform Environment actions +* [cloud-platform environment](cloud-platform_environment.md) - Cloud Platform Environment actions +