Skip to content

Commit e57f40b

Browse files
committed
cmd: exit 1 if cdk, cloudformation or terraform fail
If the diff or deploy fail then we want to ensure that telophase exits with a non-zero status code. This makes it easier to use in a script with set -e to show up as red when telophasecli is used in CI
1 parent 9bc3d8d commit e57f40b

File tree

6 files changed

+61
-17
lines changed

6 files changed

+61
-17
lines changed

cmd/deploy.go

+14-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package cmd
22

33
import (
4-
"fmt"
4+
"log"
55
"strings"
66

77
"github.com/santiago-labs/telophasecli/cmd/runner"
88
"github.com/santiago-labs/telophasecli/resourceoperation"
9+
"golang.org/x/sync/errgroup"
910

1011
"github.com/spf13/cobra"
1112
)
@@ -34,20 +35,27 @@ var deployCmd = &cobra.Command{
3435
Run: func(cmd *cobra.Command, args []string) {
3536

3637
if err := validateTargets(); err != nil {
37-
fmt.Println(err)
38-
return
38+
log.Fatal("error validating targets err:", err)
3939
}
4040
var consoleUI runner.ConsoleUI
4141
parsedTargets := filterEmptyStrings(strings.Split(targets, ","))
42+
var g errgroup.Group
43+
4244
if useTUI {
4345
consoleUI = runner.NewTUI()
44-
go ProcessOrgEndToEnd(consoleUI, resourceoperation.Deploy, parsedTargets)
46+
g.Go(func() error {
47+
return ProcessOrgEndToEnd(consoleUI, resourceoperation.Deploy, parsedTargets)
48+
})
4549
} else {
4650
consoleUI = runner.NewSTDOut()
47-
ProcessOrgEndToEnd(consoleUI, resourceoperation.Deploy, parsedTargets)
51+
if err := ProcessOrgEndToEnd(consoleUI, resourceoperation.Deploy, parsedTargets); err != nil {
52+
log.Fatal("error during processing")
53+
}
4854
}
4955

5056
consoleUI.Start()
51-
57+
if err := g.Wait(); err != nil {
58+
log.Fatal("error during processing")
59+
}
5260
},
5361
}

cmd/diff.go

+14-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package cmd
22

33
import (
4-
"fmt"
4+
"log"
55
"strings"
66

77
"github.com/santiago-labs/telophasecli/cmd/runner"
88
"github.com/santiago-labs/telophasecli/resourceoperation"
9+
"golang.org/x/sync/errgroup"
910

1011
"github.com/spf13/cobra"
1112
)
@@ -25,20 +26,28 @@ var diffCmd = &cobra.Command{
2526
Run: func(cmd *cobra.Command, args []string) {
2627

2728
if err := validateTargets(); err != nil {
28-
fmt.Println(err)
29-
return
29+
log.Fatal("error validating targets err:", err)
3030
}
3131
var consoleUI runner.ConsoleUI
3232
parsedTargets := filterEmptyStrings(strings.Split(targets, ","))
3333

34+
var g errgroup.Group
35+
3436
if useTUI {
3537
consoleUI = runner.NewTUI()
36-
go ProcessOrgEndToEnd(consoleUI, resourceoperation.Diff, parsedTargets)
38+
g.Go(func() error {
39+
return ProcessOrgEndToEnd(consoleUI, resourceoperation.Diff, parsedTargets)
40+
})
3741
} else {
3842
consoleUI = runner.NewSTDOut()
39-
ProcessOrgEndToEnd(consoleUI, resourceoperation.Diff, parsedTargets)
43+
if err := ProcessOrgEndToEnd(consoleUI, resourceoperation.Diff, parsedTargets); err != nil {
44+
log.Fatal("error during processing")
45+
}
4046
}
4147

4248
consoleUI.Start()
49+
if err := g.Wait(); err != nil {
50+
log.Fatal("error during processing")
51+
}
4352
},
4453
}

cmd/iac.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ func runIAC(
1616
consoleUI runner.ConsoleUI,
1717
cmd int,
1818
accts []resource.Account,
19-
) {
19+
) error {
2020
var wg sync.WaitGroup
2121

22+
var once sync.Once
23+
var retError error
24+
2225
for i := range accts {
2326
wg.Add(1)
2427
go func(acct resource.Account) {
@@ -40,6 +43,9 @@ func runIAC(
4043

4144
for _, op := range ops {
4245
if err := op.Call(ctx); err != nil {
46+
once.Do(func() {
47+
retError = err
48+
})
4349
consoleUI.Print(fmt.Sprintf("%v", err), acct)
4450
return
4551
}
@@ -48,6 +54,8 @@ func runIAC(
4854
}
4955

5056
wg.Wait()
57+
58+
return retError
5159
}
5260
func contains(e string, s []string) bool {
5361
for _, a := range s {

cmd/root.go

+22-5
Original file line numberDiff line numberDiff line change
@@ -36,24 +36,28 @@ func Execute() {
3636
}
3737
}
3838

39-
func ProcessOrgEndToEnd(consoleUI runner.ConsoleUI, cmd int, targets []string) {
39+
func setOpsError() error {
40+
return fmt.Errorf("error running operations")
41+
}
42+
43+
func ProcessOrgEndToEnd(consoleUI runner.ConsoleUI, cmd int, targets []string) error {
4044
ctx := context.Background()
4145
orgClient := awsorgs.New()
4246
rootAWSOU, err := ymlparser.NewParser(orgClient).ParseOrganization(ctx, orgFile)
4347
if err != nil {
4448
consoleUI.Print(fmt.Sprintf("error: %s", err), resource.Account{AccountID: "error", AccountName: "error"})
45-
return
49+
return oops.Wrapf(err, "ParseOrg")
4650
}
4751

4852
if rootAWSOU == nil {
4953
consoleUI.Print("Could not parse AWS Organization", resource.Account{AccountID: "error", AccountName: "error"})
50-
return
54+
return oops.Errorf("No root AWS OU")
5155
}
5256

5357
mgmtAcct, err := resolveMgmtAcct(ctx, orgClient, rootAWSOU)
5458
if err != nil {
5559
consoleUI.Print(fmt.Sprintf("Could not fetch AWS Management Account: %s", err), resource.Account{AccountID: "error", AccountName: "error"})
56-
return
60+
return oops.Wrapf(err, "resolveMgmtAcct")
5761
}
5862

5963
var deployStacks bool
@@ -72,6 +76,11 @@ func ProcessOrgEndToEnd(consoleUI runner.ConsoleUI, cmd int, targets []string) {
7276
}
7377
}
7478

79+
// opsError is the error we return eventually. We want to allow partially
80+
// applied operations across organizations, IaC, and SCPs so we only return
81+
// this error in the end.
82+
var opsError error
83+
7584
if len(targets) == 0 || deployOrganization {
7685
orgOps := resourceoperation.CollectOrganizationUnitOps(
7786
ctx, consoleUI, orgClient, mgmtAcct, rootAWSOU, cmd,
@@ -88,6 +97,7 @@ func ProcessOrgEndToEnd(consoleUI runner.ConsoleUI, cmd int, targets []string) {
8897
err := op.Call(ctx)
8998
if err != nil {
9099
consoleUI.Print(fmt.Sprintf("Error on AWS Organization Operation: %v", err), *mgmtAcct)
100+
opsError = setOpsError()
91101
}
92102
}
93103
}
@@ -105,7 +115,11 @@ func ProcessOrgEndToEnd(consoleUI runner.ConsoleUI, cmd int, targets []string) {
105115
consoleUI.Print("No accounts to deploy.", *mgmtAcct)
106116
}
107117

108-
runIAC(ctx, consoleUI, cmd, accountsToApply)
118+
err := runIAC(ctx, consoleUI, cmd, accountsToApply)
119+
if err != nil {
120+
consoleUI.Print("No accounts to deploy.", *mgmtAcct)
121+
opsError = setOpsError()
122+
}
109123
}
110124

111125
if len(targets) == 0 || deploySCP {
@@ -124,14 +138,17 @@ func ProcessOrgEndToEnd(consoleUI runner.ConsoleUI, cmd int, targets []string) {
124138
err := op.Call(ctx)
125139
if err != nil {
126140
consoleUI.Print(fmt.Sprintf("Error on SCP Operation: %v", err), *scpAdmin)
141+
opsError = setOpsError()
127142
}
128143
}
129144

130145
if len(scpOps) == 0 {
131146
consoleUI.Print("No Service Control Policies to deploy.", *scpAdmin)
132147
}
133148
}
149+
134150
consoleUI.Print("Done.\n", *mgmtAcct)
151+
return opsError
135152
}
136153

137154
func validateTargets() error {

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/samsarahq/go/oops v0.0.0-20220211150445-4b291d6feac4
1414
github.com/spf13/cobra v1.7.0
1515
github.com/stretchr/testify v1.8.4
16+
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
1617
gopkg.in/yaml.v3 v3.0.1
1718
)
1819

go.sum

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
6666
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
6767
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
6868
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
69+
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
6970
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
7071
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
7172
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

0 commit comments

Comments
 (0)