Skip to content

Commit 0aa2d2d

Browse files
committed
add gitlab support
1 parent dde61fe commit 0aa2d2d

File tree

15 files changed

+644
-317
lines changed

15 files changed

+644
-317
lines changed

helpers/foundation-deployer/README.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Helper tool to deploy the Terraform example foundation using Cloud Build and Clo
1616
Your environment need to use the same [Terraform](https://www.terraform.io/downloads.html) version used on the build pipeline.
1717
Otherwise, you might experience Terraform state snapshot lock errors.
1818

19-
Version 1.5.7 is the last version before the license model change. To use a later version of Terraform, ensure that the Terraform version used in the Operational System to manually execute part of the steps in `3-networks` and `4-projects` is the same version configured in the following code
19+
Version 1.5.7 is the last version before the license model change. To use a later version of Terraform, ensure that the Terraform version used in the Operating System to manually execute part of the steps in `3-networks` and `4-projects` is the same version configured in the following code
2020

2121
- 0-bootstrap/modules/jenkins-agent/variables.tf
2222
```
@@ -73,7 +73,7 @@ Version 1.5.7 is the last version before the license model change. To use a late
7373

7474
### Prepare the deploy environment
7575

76-
- Create a directory in the file system to host the Cloud Source repositories the will be created and a copy of the terraform example foundation.
76+
- Create a directory in the file system to host the Git Repositories that will be created (Cloud Source repositories, Github , or GitLab) and a copy of the terraform example foundation repository.
7777
- Clone the `terraform-example-foundation` repository on this directory.
7878

7979
```text
@@ -106,10 +106,6 @@ Version 1.5.7 is the last version before the license model change. To use a late
106106

107107
By default the foundation regional resources are deployed in `us-west1` and `us-central1` regions and multi-regional resources are deployed in the `US` multi-region.
108108

109-
In addition to the variables declared in the file `global.tfvars` for configuring location, there are two locals, `default_region1` and `default_region2`, in each one of the environments (`production`, `nonproduction`, and `development`) in the network steps (`3-networks-svpc` and `3-networks-hub-and-spoke`).
110-
They are located in the [main.tf](../../3-networks-svpc/envs/production/main.tf#L20-L21) files for each environments.
111-
Change the two locals **before** starting the deployment to deploy in other regions.
112-
113109
**Note:** the region used for the variable `default_region` in the file `global.tfvars` **MUST** be one of the regions used for the `default_region1` and `default_region2` locals.
114110

115111
### Application default credentials

helpers/foundation-deployer/gcp/gcp.go

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"context"
1919
"encoding/json"
2020
"fmt"
21-
"regexp"
2221
"strings"
2322
"time"
2423

@@ -27,6 +26,8 @@ import (
2726
"github.com/mitchellh/go-testing-interface"
2827
"github.com/tidwall/gjson"
2928

29+
localutil "github.com/terraform-google-modules/terraform-example-foundation/helpers/foundation-deployer/utils"
30+
3031
"github.com/terraform-google-modules/terraform-example-foundation/test/integration/testutils"
3132

3233
"google.golang.org/api/cloudbuild/v1"
@@ -51,20 +52,6 @@ type Build struct {
5152
CreateTime string `json:"createTime"`
5253
}
5354

54-
var (
55-
retryRegexp = map[*regexp.Regexp]string{}
56-
)
57-
58-
func init() {
59-
for e, m := range testutils.RetryableTransientErrors {
60-
r, err := regexp.Compile(fmt.Sprintf("(?s)%s", e)) //(?s) enables dot (.) to match newline.
61-
if err != nil {
62-
panic(fmt.Sprintf("failed to compile regex %s: %s", e, err.Error()))
63-
}
64-
retryRegexp[r] = m
65-
}
66-
}
67-
6855
type GCP struct {
6956
Runf func(t testing.TB, cmd string, args ...interface{}) gjson.Result
7057
RunCmd func(t testing.TB, cmd string, args ...interface{}) string
@@ -209,7 +196,8 @@ func (g GCP) WaitBuildSuccess(t testing.TB, project, region, repo, commitSha, fa
209196
}
210197

211198
if status != StatusSuccess {
212-
if !g.IsRetryableError(t, project, region, build) {
199+
logs := g.GetBuildLogs(t, project, region, build)
200+
if !localutil.IsRetryableError(t, logs) {
213201
return fmt.Errorf("%s\nSee:\nhttps://console.cloud.google.com/cloud-build/builds;region=%s/%s?project=%s\nfor details", failureMsg, region, build, project)
214202
}
215203
fmt.Println("build failed with retryable error. a new build will be triggered.")
@@ -230,21 +218,6 @@ func (g GCP) WaitBuildSuccess(t testing.TB, project, region, repo, commitSha, fa
230218
return fmt.Errorf("%s\nbuild failed after %d retries.\nSee Cloud Build logs for details", failureMsg, maxErrorRetries)
231219
}
232220

233-
// IsRetryableError checks the logs of a failed Cloud Build build
234-
// and verify if the error is a transient one and can be retried
235-
func (g GCP) IsRetryableError(t testing.TB, projectID, region, build string) bool {
236-
logs := g.GetBuildLogs(t, projectID, region, build)
237-
found := false
238-
for pattern, msg := range retryRegexp {
239-
if pattern.MatchString(logs) {
240-
found = true
241-
fmt.Printf("error '%s' is worth of a retry\n", msg)
242-
break
243-
}
244-
}
245-
return found
246-
}
247-
248221
// HasSccNotification checks if a Security Command Center notification exists
249222
func (g GCP) HasSccNotification(t testing.TB, orgID, sccName string) bool {
250223
filter := fmt.Sprintf("name=organizations/%s/locations/global/notificationConfigs/%s", orgID, sccName)

helpers/foundation-deployer/github/github.go

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ import (
2525
"github.com/google/go-github/v58/github"
2626
"github.com/mitchellh/go-testing-interface"
2727
"github.com/terraform-google-modules/terraform-example-foundation/test/integration/testutils"
28+
29+
localutil "github.com/terraform-google-modules/terraform-example-foundation/helpers/foundation-deployer/utils"
30+
2831
"golang.org/x/oauth2"
2932
)
3033

@@ -62,25 +65,30 @@ type GH struct {
6265
sleepTime time.Duration
6366
}
6467

68+
// NewGH creates a new wrapper for The GitHub API
6569
func NewGH() GH {
6670
return GH{
6771
TriggerNewBuild: triggerNewBuild,
6872
sleepTime: 20,
6973
}
7074
}
75+
// triggerNewBuild triggers a new action execution
7176
func triggerNewBuild(t testing.TB, ctx context.Context, owner, repo, token string, runID int64) (int64, string, string, error) {
72-
if token == "" {
73-
return 0, "", "", fmt.Errorf("GITHUB_TOKEN not set")
74-
}
75-
7677
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
7778
tc := oauth2.NewClient(ctx, ts)
7879
client := github.NewClient(tc)
7980

80-
_, err := client.Actions.RerunWorkflowByID(ctx, owner, repo, runID)
81+
resp, err := client.Actions.RerunWorkflowByID(ctx, owner, repo, runID)
8182
if err != nil {
8283
return 0, "", "", fmt.Errorf("Error re-running workflow: %v", err)
8384
}
85+
if resp.StatusCode != http.StatusCreated {
86+
bodyBytes, err := io.ReadAll(resp.Body)
87+
if err != nil {
88+
return 0, "", "", fmt.Errorf("Error re-running workflow status: %d body parsing error: %v", resp.StatusCode, err)
89+
}
90+
return 0, "", "", fmt.Errorf("Error re-running workflow status: %d body: %s", resp.StatusCode, string(bodyBytes))
91+
}
8492
opts := &github.ListWorkflowRunsOptions{
8593

8694
ListOptions: github.ListOptions{
@@ -120,7 +128,8 @@ func triggerNewBuild(t testing.TB, ctx context.Context, owner, repo, token strin
120128
return newRunID, status, conclusion, nil
121129
}
122130

123-
func (g GH) GetLastBuildState(t testing.TB, ctx context.Context, owner, repo, token string) (int64, string, string, error) {
131+
// GetLastActionState returns the state of the latest action
132+
func (g GH) GetLastActionState(t testing.TB, ctx context.Context, owner, repo, token string) (int64, string, string, error) {
124133
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
125134
tc := oauth2.NewClient(ctx, ts)
126135
client := github.NewClient(tc)
@@ -158,6 +167,7 @@ func (g GH) GetLastBuildState(t testing.TB, ctx context.Context, owner, repo, to
158167
return runID, status, conclusion, nil
159168
}
160169

170+
// GetActionState returns the state of a given action
161171
func (g GH) GetActionState(t testing.TB, ctx context.Context, owner, repo, token string, runID int64) (string, string, error) {
162172
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
163173
tc := oauth2.NewClient(ctx, ts)
@@ -180,6 +190,7 @@ func (g GH) GetActionState(t testing.TB, ctx context.Context, owner, repo, token
180190
return status, conclusion, nil
181191
}
182192

193+
// GetBuildLogs returns the execution logs of an action
183194
func (g GH) GetBuildLogs(t testing.TB, ctx context.Context, owner, repo, token string, runID int64) (string, error) {
184195
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
185196
tc := oauth2.NewClient(ctx, ts)
@@ -229,6 +240,7 @@ func (g GH) GetBuildLogs(t testing.TB, ctx context.Context, owner, repo, token s
229240
return "", nil
230241
}
231242

243+
// GetFinalActionState returns the final state of an action
232244
func (g GH) GetFinalActionState(t testing.TB, ctx context.Context, owner, repo, token string, runID int64, maxBuildRetry int) (string, string, error) {
233245
var status, conclusion string
234246
var err error
@@ -265,7 +277,7 @@ func (g GH) WaitBuildSuccess(t testing.TB, owner, repo, token string, failureMsg
265277
// wait action creation
266278
time.Sleep(30 * time.Second)
267279

268-
runID, status, conclusion, err = g.GetLastBuildState(t, ctx, owner, repo, token)
280+
runID, status, conclusion, err = g.GetLastActionState(t, ctx, owner, repo, token)
269281
if err != nil {
270282
return err
271283
}
@@ -282,7 +294,7 @@ func (g GH) WaitBuildSuccess(t testing.TB, owner, repo, token string, failureMsg
282294
if err != nil {
283295
return err
284296
}
285-
if !g.IsRetryableError(t, logs) {
297+
if localutil.IsRetryableError(t, logs) {
286298
return fmt.Errorf("%s\nSee:\nhttps://github.com/%s/%s/actions/runs/%d\nfor details", failureMsg, owner, repo, runID)
287299
}
288300
fmt.Println("build failed with retryable error. a new build will be triggered.")
@@ -302,17 +314,3 @@ func (g GH) WaitBuildSuccess(t testing.TB, owner, repo, token string, failureMsg
302314
}
303315
return fmt.Errorf("%s action failed after %d retries", failureMsg, maxErrorRetries)
304316
}
305-
306-
// IsRetryableError checks the logs of a failed Cloud Build build
307-
// and verify if the error is a transient one and can be retried
308-
func (g GH) IsRetryableError(t testing.TB, logs string) bool {
309-
found := false
310-
for pattern, msg := range retryRegexp {
311-
if pattern.MatchString(logs) {
312-
found = true
313-
fmt.Printf("error '%s' is worth of a retry\n", msg)
314-
break
315-
}
316-
}
317-
return found
318-
}

0 commit comments

Comments
 (0)