-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #176 from ans-group/lb-tf-deploy-wrapper
Provide wrapper for Terraform to handle loadbalancer deployments
- Loading branch information
Showing
5 changed files
with
145 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
package loadbalancer | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"os" | ||
"os/exec" | ||
"slices" | ||
"strings" | ||
|
||
"github.com/ans-group/cli/internal/pkg/factory" | ||
"github.com/ans-group/sdk-go/pkg/service/loadbalancer" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
const clusterIDsOutputKey string = "loadbalancer_cluster_ids" | ||
|
||
func loadbalancerTerraformCmd(f factory.ClientFactory) *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "terraform", | ||
Short: "Terraform wrapper for handling deployments", | ||
Long: "Wraps Terraform to automatically deploy your changes after a successful apply. You must " + | ||
fmt.Sprintf("ensure you have configured a Terraform output called '%s' which ", clusterIDsOutputKey) + | ||
"contains the IDs of your loadbalancer clusters. After applying your Terraform configuration, " + | ||
"we'll deploy your staged changes to the loadbalancer.", | ||
Example: "ans loadbalancer terraform apply", | ||
DisableFlagParsing: true, | ||
RunE: loadbalancerCobraRunEFunc(f, loadbalancerTerraform), | ||
} | ||
|
||
return cmd | ||
} | ||
|
||
func loadbalancerTerraform(service loadbalancer.LoadBalancerService, cmd *cobra.Command, args []string) error { | ||
// Because we disable flag parsing, we'll need to handle --help ourselves | ||
if slices.Contains(args, "-h") || slices.Contains(args, "--help") || len(args) == 0 { | ||
return cmd.Help() | ||
} | ||
|
||
binPath, err := findTerraformBinary() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if err := runTerraform(binPath, args); err != nil { | ||
return err | ||
} | ||
|
||
// If we're not applying the configuration then exit now | ||
if !slices.Contains(args, "apply") { | ||
return nil | ||
} | ||
|
||
fmt.Printf("\nTerraform run complete, deploying the configuration to the loadbalancer...\n") | ||
|
||
clusterIDs, err := getClusterIDs(binPath) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fmt.Printf("Deploying cluster(s): %s\n\n", | ||
strings.Trim(strings.Join(strings.Fields(fmt.Sprint(clusterIDs)), ", "), "[]")) | ||
|
||
haveErrors := false | ||
for _, clusterID := range clusterIDs { | ||
fmt.Printf("Deploying %d... ", clusterID) | ||
err = service.DeployCluster(clusterID) | ||
if err != nil { | ||
haveErrors = true | ||
fmt.Printf("failed to deploy cluster: %d: %s\n", clusterID, err) | ||
} else { | ||
fmt.Printf("ok\n\n") | ||
} | ||
} | ||
|
||
if haveErrors { | ||
return fmt.Errorf("\nans: some clusters failed to deploy, please see above output") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func findTerraformBinary() (string, error) { | ||
path, err := exec.LookPath("terraform") | ||
if err != nil { | ||
path, err = exec.LookPath("tofu") | ||
if err != nil { | ||
return "", fmt.Errorf("ans: no terraform or tofu binaries found in path") | ||
} | ||
} | ||
return path, nil | ||
} | ||
|
||
func runTerraform(binPath string, args []string) error { | ||
tfCmd := exec.Command(binPath, args...) | ||
tfCmd.Stdout = os.Stdout | ||
tfCmd.Stderr = os.Stderr | ||
tfCmd.Stdin = os.Stdin | ||
|
||
if err := tfCmd.Run(); err != nil { | ||
var exitError *exec.ExitError | ||
if errors.As(err, &exitError) { | ||
return fmt.Errorf("ans: %s exited with %d, aborting deployment", binPath, exitError.ExitCode()) | ||
} | ||
return fmt.Errorf("ans: error running %s: %s", binPath, err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func getClusterIDs(binPath string) ([]int, error) { | ||
// Get the cluster ID from Terraform | ||
output, err := exec.Command(binPath, "output", "-json", clusterIDsOutputKey).CombinedOutput() | ||
if err != nil { | ||
fmt.Printf("%s\n", string(output)) | ||
return nil, fmt.Errorf("ans: deployment failed: failed to get %s output from terraform, cannot deploy: %s", | ||
clusterIDsOutputKey, err) | ||
} | ||
|
||
var clusterIDs []int | ||
err = json.Unmarshal(output, &clusterIDs) | ||
if err != nil { | ||
return nil, fmt.Errorf("ans: deployment failed: failed to unmarshal Terraform output from key '%s': %s", | ||
clusterIDsOutputKey, err) | ||
} | ||
|
||
if len(clusterIDs) == 0 { | ||
return nil, fmt.Errorf("ans: deployment failed: no cluster IDs found in Terraform output key '%s'", | ||
clusterIDsOutputKey) | ||
} | ||
|
||
return clusterIDs, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
module github.com/ans-group/cli | ||
|
||
go 1.20 | ||
go 1.21 | ||
|
||
require ( | ||
github.com/ans-group/sdk-go v1.17.0 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters