Skip to content

Commit 3238b1f

Browse files
authored
Merge branch 'GoogleCloudPlatform:main' into fix/25305-take2
2 parents 5ed2f49 + f746dc6 commit 3238b1f

File tree

803 files changed

+38476
-3565
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

803 files changed

+38476
-3565
lines changed

.ci/containers/build-environment/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 1777 "$GOPATH"
1717
WORKDIR $GOPATH
1818

1919
# terraform binary used by tfv/tgc
20-
COPY --from=hashicorp/terraform:1.11.0 /bin/terraform /bin/terraform
20+
COPY --from=hashicorp/terraform:1.14.3 /bin/terraform /bin/terraform
2121

2222
SHELL ["/bin/bash", "-c"]
2323

.ci/containers/go-plus/Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ RUN apt-get update && \
2929
apt-get clean && \
3030
rm -rf /var/lib/apt/lists/*
3131

32-
RUN wget https://releases.hashicorp.com/terraform/1.11.0/terraform_1.11.0_linux_amd64.zip \
33-
&& unzip terraform_1.11.0_linux_amd64.zip \
34-
&& rm terraform_1.11.0_linux_amd64.zip \
32+
RUN wget https://releases.hashicorp.com/terraform/1.14.3/terraform_1.14.3_linux_amd64.zip \
33+
&& unzip terraform_1.14.3_linux_amd64.zip \
34+
&& rm terraform_1.14.3_linux_amd64.zip \
3535
&& mv ./terraform /bin/terraform

.ci/gcb-ingest-test-data.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
steps:
3+
- name: 'gcr.io/graphite-docker-images/go-plus'
4+
id: collect-nightly-test-status
5+
entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh'
6+
secretEnv: ["TEAMCITY_TOKEN"]
7+
args:
8+
- 'collect-nightly-test-status'
9+
- $_CUSTOM_DATE
10+
11+
timeout: 3600s
12+
options:
13+
machineType: 'N1_HIGHCPU_32'
14+
15+
logsBucket: 'gs://cloudbuild-ingest-test-data-logs'
16+
availableSecrets:
17+
secretManager:
18+
- versionName: projects/673497134629/secrets/teamcity-token/versions/latest
19+
env: TEAMCITY_TOKEN

.ci/gcb-test-failure-ticket.yaml

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,11 @@
11
---
22
steps:
3-
- name: 'gcr.io/graphite-docker-images/go-plus'
4-
id: collect-nightly-test-status
5-
entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh'
6-
secretEnv: ["TEAMCITY_TOKEN"]
7-
args:
8-
- 'collect-nightly-test-status'
9-
- $_CUSTOM_DATE
103
- name: 'gcr.io/graphite-docker-images/go-plus'
114
id: create-test-failure-ticket
125
entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh'
136
secretEnv: ["GITHUB_TOKEN"]
14-
waitFor: ["collect-nightly-test-status"]
157
args:
168
- 'create-test-failure-ticket'
17-
- name: 'ubuntu'
18-
args: ['sleep', '120']
199
- name: 'gcr.io/graphite-docker-images/go-plus'
2010
id: manage-test-failure-ticket
2111
entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh'
@@ -31,7 +21,5 @@ options:
3121
logsBucket: 'gs://cloudbuild-test-failure-ticket-logs'
3222
availableSecrets:
3323
secretManager:
34-
- versionName: projects/673497134629/secrets/teamcity-token/versions/latest
35-
env: TEAMCITY_TOKEN
3624
- versionName: projects/673497134629/secrets/github-classic--repo-workflow/versions/latest
3725
env: GITHUB_TOKEN

.ci/infra/terraform/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ module "project-services" {
295295
"firebaseremoteconfig.googleapis.com",
296296
"firebaserules.googleapis.com",
297297
"firebasestorage.googleapis.com",
298+
"firebasevertexai.googleapis.com",
298299
"firestore.googleapis.com",
299300
"firestorekeyvisualizer.googleapis.com",
300301
"gkebackup.googleapis.com",

.ci/magician/cmd/collect_nightly_test_status.go

Lines changed: 187 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ import (
2121
"magician/provider"
2222
"magician/teamcity"
2323
utils "magician/utility"
24+
"net/url"
2425
"os"
26+
"regexp"
2527
"strconv"
2628
"strings"
2729
"time"
@@ -43,7 +45,9 @@ type TestInfo struct {
4345
Status string `json:"status"`
4446
Service string `json:"service"`
4547
Resource string `json:"resource"`
48+
CommitSha string `json:"commit_sha"`
4649
ErrorMessage string `json:"error_message"`
50+
ErrorType string `json:"error_type"`
4751
LogLink string `json:"log_link"`
4852
ProviderVersion string `json:"provider_version"`
4953
QueuedDate time.Time `json:"queued_date"`
@@ -83,24 +87,27 @@ var collectNightlyTestStatusCmd = &cobra.Command{
8387
tc := teamcity.NewClient(env["TEAMCITY_TOKEN"])
8488
gcs := cloudstorage.NewClient()
8589

86-
now := time.Now()
87-
8890
loc, err := time.LoadLocation("America/Los_Angeles")
8991
if err != nil {
9092
return fmt.Errorf("Error loading location: %s", err)
9193
}
92-
date := now.In(loc)
94+
95+
now := time.Now().In(loc)
96+
year, month, day := now.Date()
97+
9398
customDate := args[0]
9499
// check if a specific date is provided
95100
if customDate != "" {
96101
parsedDate, err := time.Parse("2006-01-02", customDate) // input format YYYY-MM-DD
97-
// Set the time to 7pm PT
98-
date = time.Date(parsedDate.Year(), parsedDate.Month(), parsedDate.Day(), 19, 0, 0, 0, loc)
99102
if err != nil {
100103
return fmt.Errorf("invalid input time format: %w", err)
101104
}
105+
year, month, day = parsedDate.Date()
102106
}
103107

108+
// Set the time to 7pm PT
109+
date := time.Date(year, month, day, 19, 0, 0, 0, loc)
110+
104111
return execCollectNightlyTestStatus(date, tc, gcs)
105112
},
106113
}
@@ -133,10 +140,40 @@ func execCollectNightlyTestStatus(now time.Time, tc TeamcityClient, gcs Cloudsto
133140
}
134141

135142
func createTestReport(pVersion provider.Version, tc TeamcityClient, gcs CloudstorageClient, formattedStartCut, formattedFinishCut, date string) error {
143+
144+
baseLocator := fmt.Sprintf("count:500,project:%s,branch:refs/heads/nightly-test,queuedDate:(date:%s,condition:before),queuedDate:(date:%s,condition:after)", pVersion.TeamCityNightlyProjectName(), formattedFinishCut, formattedStartCut)
145+
fields := "build(id,buildTypeId,buildConfName,webUrl,number,queuedDate,startDate,finishDate)"
146+
params := url.Values{}
147+
148+
// Check Queued Builds
149+
params.Set("locator", fmt.Sprintf("%s,state:queued", baseLocator))
150+
queuedBuilds, err := tc.GetBuilds(params)
151+
if err != nil {
152+
return fmt.Errorf("failed to get queued builds: %w", err)
153+
}
154+
if len(queuedBuilds.Builds) > 0 {
155+
fmt.Printf("%s Test unfinished: there are still %d builds queued.\n", strings.ToUpper(pVersion.String()), len(queuedBuilds.Builds))
156+
return nil
157+
}
158+
159+
// Check Running Builds
160+
params.Set("locator", fmt.Sprintf("%s,state:running,tag:cron-trigger", baseLocator))
161+
params.Set("fields", fields)
162+
runningBuilds, err := tc.GetBuilds(params)
163+
if err != nil {
164+
return fmt.Errorf("failed to get running builds: %w", err)
165+
}
166+
if len(runningBuilds.Builds) > 0 {
167+
fmt.Printf("%s Test unfinished: there are still %d builds running.\n", strings.ToUpper(pVersion.String()), len(runningBuilds.Builds))
168+
return nil
169+
}
170+
136171
// Get all service test builds
137-
builds, err := tc.GetBuilds(pVersion.TeamCityNightlyProjectName(), formattedFinishCut, formattedStartCut)
172+
params.Set("locator", fmt.Sprintf("%s,state:finished,tag:cron-trigger", baseLocator))
173+
params.Set("fields", fields)
174+
builds, err := tc.GetBuilds(params)
138175
if err != nil {
139-
return err
176+
return fmt.Errorf("failed to get finished builds: %w", err)
140177
}
141178

142179
var testInfoList []TestInfo
@@ -163,12 +200,14 @@ func createTestReport(pVersion provider.Version, tc TeamcityClient, gcs Cloudsto
163200

164201
for _, testResult := range serviceTestResults.TestResults {
165202
var errorMessage string
203+
var errorType string
166204
// Get test debug log gcs link
167205
logLink := fmt.Sprintf("https://storage.cloud.google.com/teamcity-logs/nightly/%s/%s/%s/debug-%s-%s-%s-%s.txt", pVersion.TeamCityNightlyProjectName(), date, build.Number, pVersion.ProviderName(), build.Number, strconv.Itoa(build.Id), testResult.Name)
168206
// Get concise error message for failed and skipped tests
169207
// Skipped tests have a status of "UNKNOWN" on TC
170208
if testResult.Status == "FAILURE" || testResult.Status == "UNKNOWN" {
171209
errorMessage = convertErrorMessage(testResult.ErrorMessage)
210+
errorType = categorizeError(errorMessage)
172211
}
173212

174213
queuedTime, err := time.Parse(tcTimeFormat, build.QueuedDate)
@@ -189,7 +228,9 @@ func createTestReport(pVersion provider.Version, tc TeamcityClient, gcs Cloudsto
189228
Status: testResult.Status,
190229
Service: serviceName,
191230
Resource: convertTestNameToResource(testResult.Name),
231+
CommitSha: build.Number,
192232
ErrorMessage: errorMessage,
233+
ErrorType: errorType,
193234
LogLink: logLink,
194235
ProviderVersion: strings.ToUpper(pVersion.String()),
195236
Duration: testResult.Duration,
@@ -251,6 +292,145 @@ func convertErrorMessage(rawErrorMessage string) string {
251292
return strings.TrimSpace(rawErrorMessage[startIndex:endIndex])
252293
}
253294

295+
var (
296+
reSubnetNotReady = regexp.MustCompile(`The resource '[^']+/subnetworks/[^']+' is not ready`)
297+
reApiEnv = regexp.MustCompile(`has not been used in project (ci-test-project-188019|1067888929963|ci-test-project-nightly-ga|594424405950|ci-test-project-nightly-beta|653407317329|tf-vcr-private|808590572184) before or it is disabled`)
298+
reAttrSet = regexp.MustCompile(`Attribute '[^']+' expected to be set`)
299+
reQuotaLimit = regexp.MustCompile(`Quota limit '[^']+' has been exceeded`)
300+
reGoogleApi4xx = regexp.MustCompile(`googleapi: Error 4\d\d`)
301+
reGoogleApi5xx = regexp.MustCompile(`googleapi: Error 5\d\d`)
302+
reGoogleApiGeneric = regexp.MustCompile(`googleapi: Error`)
303+
)
304+
305+
func categorizeError(errMsg string) string {
306+
if strings.Contains(errMsg, "Error code 13") {
307+
return "Error code 13"
308+
}
309+
if strings.Contains(errMsg, "Precondition check failed") {
310+
return "Precondition check failed"
311+
}
312+
313+
// Diff Category
314+
if strings.Contains(errMsg, "After applying this test step, the plan was not empty") ||
315+
strings.Contains(errMsg, "After applying this test step and performing a `terraform refresh`") ||
316+
strings.Contains(errMsg, "Expected a non-empty plan, but got an empty plan") ||
317+
strings.Contains(errMsg, "error: Check failed") {
318+
return "Diff"
319+
}
320+
321+
if strings.Contains(errMsg, "timeout while waiting for state") {
322+
return "Operation timeout"
323+
}
324+
325+
// Regex: Subnetwork not ready
326+
if reSubnetNotReady.MatchString(errMsg) {
327+
return "Subnetwork not ready"
328+
}
329+
330+
// ImportStateVerify Category
331+
if strings.Contains(errMsg, "ImportStateVerify attributes not equivalent") ||
332+
strings.Contains(errMsg, "Cannot import non-existent remote object") ||
333+
strings.Contains(errMsg, "Error: Unexpected Import Identifier") {
334+
return "ImportStateVerify"
335+
}
336+
337+
// Deprecated (Case-insensitive check)
338+
if strings.Contains(strings.ToLower(errMsg), "deprecated") {
339+
return "Deprecated"
340+
}
341+
342+
if strings.Contains(errMsg, "Provider produced inconsistent result after apply") &&
343+
strings.Contains(errMsg, "Root object was present, but now absent") {
344+
return "Root object was present, but now absent"
345+
}
346+
347+
if strings.Contains(errMsg, "Provider produced inconsistent final plan") {
348+
return "Provider produced inconsistent final plan"
349+
}
350+
351+
// API Enablement
352+
if reApiEnv.MatchString(errMsg) {
353+
return "API enablement (Test environment)"
354+
}
355+
if strings.Contains(errMsg, "has not been used in project") && strings.Contains(errMsg, "before or it is disabled") {
356+
return "API enablement (Created project)"
357+
}
358+
359+
if strings.Contains(errMsg, "does not have required permissions") {
360+
return "Permissions"
361+
}
362+
if strings.Contains(errMsg, "bootstrap_iam_test_utils.go") {
363+
return "Bootstrapping"
364+
}
365+
366+
// Bad Config Category
367+
if strings.Contains(errMsg, "Inconsistent dependency lock file") ||
368+
strings.Contains(errMsg, "Invalid resource type") ||
369+
strings.Contains(errMsg, "Blocks of type") && strings.Contains(errMsg, "are not expected here") ||
370+
strings.Contains(errMsg, "Conflicting configuration arguments") ||
371+
reAttrSet.MatchString(errMsg) {
372+
return "Bad config"
373+
}
374+
375+
// Quota Category
376+
if strings.Contains(errMsg, "Quota exhausted") ||
377+
strings.Contains(errMsg, "Quota exceeded") ||
378+
strings.Contains(errMsg, "You do not have quota") ||
379+
reQuotaLimit.MatchString(errMsg) {
380+
return "Quota"
381+
}
382+
383+
if strings.Contains(errMsg, "does not have enough resources available") {
384+
return "Resource availability"
385+
}
386+
387+
// API Create/Read/Update/Delete
388+
if strings.Contains(errMsg, "Error: Error waiting to create") ||
389+
strings.Contains(errMsg, "Error: Error waiting for Create") ||
390+
strings.Contains(errMsg, "Error: Error waiting for creating") ||
391+
strings.Contains(errMsg, "Error: Error creating") ||
392+
strings.Contains(errMsg, "was created in the error state") ||
393+
strings.Contains(errMsg, "Error: Error changing instance status after creation:") {
394+
return "API Create"
395+
}
396+
397+
if strings.Contains(errMsg, "Error: Error reading") {
398+
return "API Read"
399+
}
400+
401+
if strings.Contains(errMsg, "Error setting IAM policy") ||
402+
strings.Contains(errMsg, "Error applying IAM policy") {
403+
return "API IAM"
404+
}
405+
406+
if strings.Contains(errMsg, "Error: Error waiting for Updating") ||
407+
strings.Contains(errMsg, "Error: Error updating") {
408+
return "API Update"
409+
}
410+
411+
if strings.Contains(errMsg, "Error: Error waiting for Deleting") ||
412+
strings.Contains(errMsg, "Error running post-test destroy") {
413+
return "API Delete"
414+
}
415+
416+
// Google API Errors (Order matters: check specific codes before generic)
417+
if reGoogleApi4xx.MatchString(errMsg) {
418+
return "API (4xx)"
419+
}
420+
if reGoogleApi5xx.MatchString(errMsg) {
421+
return "API (5xx)"
422+
}
423+
if reGoogleApiGeneric.MatchString(errMsg) ||
424+
strings.Contains(errMsg, "Error: Error when reading or editing") ||
425+
strings.Contains(errMsg, "Error: Error waiting") ||
426+
strings.Contains(errMsg, "unable to queue the operation") ||
427+
strings.Contains(errMsg, "Error waiting for Switching runtime") {
428+
return "API (Other)"
429+
}
430+
431+
return "Other"
432+
}
433+
254434
func init() {
255435
rootCmd.AddCommand(collectNightlyTestStatusCmd)
256436
}

0 commit comments

Comments
 (0)