Skip to content

Commit

Permalink
Merge branch 'GoogleCloudPlatform:main' into extra-attributes-saml-su…
Browse files Browse the repository at this point in the history
…pport
  • Loading branch information
omkark-google authored Feb 14, 2025
2 parents ed4437f + 3eeeb73 commit e2c62bc
Show file tree
Hide file tree
Showing 880 changed files with 36,773 additions and 7,028 deletions.
15 changes: 0 additions & 15 deletions .ci/containers/build-environment/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# Stage 1: Building Go dependencies
FROM golang:1.23-bullseye AS builder

# Set working directory
Expand All @@ -11,11 +10,6 @@ ADD "https://raw.githubusercontent.com/GoogleCloudPlatform/magic-modules/main/tp
# Install the go dependencies
RUN go mod download

# Stage 2: Creating the final imag
FROM ruby:3.1-bullseye

# golang
COPY --from=golang:1.23-bullseye /usr/local/go /usr/local/go
ENV GOPATH /go
ENV PATH /usr/local/go/bin:$PATH
ENV PATH $GOPATH/bin:$PATH
Expand All @@ -38,12 +32,3 @@ RUN git config --global user.email "[email protected]"

RUN go install golang.org/x/tools/cmd/goimports@d088b475e3360caabc032aaee1dc66351d4e729a
RUN go install github.com/github/[email protected]+incompatible

ADD "https://raw.githubusercontent.com/GoogleCloudPlatform/magic-modules/refs/heads/legacy-ruby/mmv1/Gemfile" Gemfile
ADD "https://raw.githubusercontent.com/GoogleCloudPlatform/magic-modules/refs/heads/legacy-ruby/mmv1/Gemfile.lock" Gemfile.lock
RUN bundle install
RUN rm Gemfile Gemfile.lock

# Copy Go dependencies from builder stage
COPY --from=builder /go/pkg /go/pkg

19 changes: 19 additions & 0 deletions .ci/gcb-test-failure-ticket.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
steps:
- name: 'gcr.io/graphite-docker-images/go-plus'
id: gcb-test-failure-ticket
entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh'
secretEnv: ["TEAMCITY_TOKEN"]
args:
- 'collect-nightly-test-status'
- $_CUSTOM_DATE

timeout: 3600s
options:
machineType: 'N1_HIGHCPU_32'

logsBucket: 'gs://cloudbuild-test-failure-ticket-logs'
availableSecrets:
secretManager:
- versionName: projects/673497134629/secrets/teamcity-token/versions/latest
env: TEAMCITY_TOKEN
9 changes: 9 additions & 0 deletions .ci/infra/terraform/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ module "project-services" {
"logging.googleapis.com",
"looker.googleapis.com",
"managedidentities.googleapis.com",
"managedkafka.googleapis.com",
"memcache.googleapis.com",
"memorystore.googleapis.com",
"metastore.googleapis.com",
Expand All @@ -316,6 +317,7 @@ module "project-services" {
"osconfig.googleapis.com",
"oslogin.googleapis.com",
"parallelstore.googleapis.com",
"parametermanager.googleapis.com",
"privateca.googleapis.com",
"privilegedaccessmanager.googleapis.com",
"pubsub.googleapis.com",
Expand Down Expand Up @@ -467,6 +469,13 @@ resource "google_project_iam_member" "compute_agent_encrypter_decrypter" {
member = "serviceAccount:service-${google_project.proj.number}@compute-system.iam.gserviceaccount.com"
}

# TestAccColabRuntime_colabRuntimeBasicExample
# TestAccColabRuntime_colabRuntimeFullExample
resource "google_project_iam_member" "colab_admin_permissions" {
project = google_project.proj.project_id
role = "roles/aiplatform.colabEnterpriseAdmin"
member = "user:[email protected]"
}

data "google_organization" "org2" {
organization = var.org2_id
Expand Down
58 changes: 58 additions & 0 deletions .ci/magician/cloudstorage/bucket.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2025 Google LLC. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cloudstorage

import (
"context"
"fmt"
"io"
"os"
"time"

"cloud.google.com/go/storage"
)

func (gcs *Client) WriteToGCSBucket(bucket, object, filePath string) error {
ctx := context.Background()

client, err := storage.NewClient(ctx)
if err != nil {
return fmt.Errorf("storage.NewClient: %v", err)
}
defer client.Close()

file, err := os.Open(filePath)
if err != nil {
return fmt.Errorf("os.Open: %w", err)
}
defer file.Close()

ctx, cancel := context.WithTimeout(ctx, time.Second*50)
defer cancel()

writer := client.Bucket(bucket).Object(object).NewWriter(ctx)
writer.ContentType = "application/json"

if _, err = io.Copy(writer, file); err != nil {
return fmt.Errorf("io.Copy: %w", err)
}
if err := writer.Close(); err != nil {
return fmt.Errorf("Writer.Close: %w", err)
}

fmt.Printf("File uploaded to bucket %s as %s\n", bucket, object)
return nil
}
23 changes: 23 additions & 0 deletions .ci/magician/cloudstorage/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2025 Google LLC. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cloudstorage

type Client struct {
}

func NewClient() *Client {
return &Client{}
}
228 changes: 228 additions & 0 deletions .ci/magician/cmd/collect_nightly_test_status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
/*
* Copyright 2025 Google LLC. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cmd

import (
"fmt"
"magician/cloudstorage"
"magician/provider"
"magician/teamcity"
utils "magician/utility"
"os"
"strconv"
"strings"
"time"

"github.com/spf13/cobra"
)

const (
NIGHTLY_DATA_BUCKET = "nightly-test-data"
)

var cntsRequiredEnvironmentVariables = [...]string{
"TEAMCITY_TOKEN",
}

type TestInfo struct {
Name string `json:"name"`
Status string `json:"status"`
Service string `json:"service"`
ErrorMessage string `json:"error_message"`
LogLink string `json"log_link`
}

// collectNightlyTestStatusCmd represents the collectNightlyTestStatus command
var collectNightlyTestStatusCmd = &cobra.Command{
Use: "collect-nightly-test-status",
Short: "Collects and stores nightly test status",
Long: `This command collects nightly test status, stores the data in JSON files and upload the files to GCS.
The command expects the following argument(s):
1. Custom test date in YYYY-MM-DD format. default: ""(current time when the job is executed)
It then performs the following operations:
1. Collects nightly test status of the execution day or the specified test date (if provided)
2. Stores the collected data in JSON files
3. Uploads the JSON files to GCS
The following environment variables are required:
` + listCNTSRequiredEnvironmentVariables(),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
env := make(map[string]string)
for _, ev := range cntsRequiredEnvironmentVariables {
val, ok := os.LookupEnv(ev)
if !ok {
return fmt.Errorf("did not provide %s environment variable", ev)
}
env[ev] = val
}

tc := teamcity.NewClient(env["TEAMCITY_TOKEN"])
gcs := cloudstorage.NewClient()

now := time.Now()

loc, err := time.LoadLocation("America/Los_Angeles")
if err != nil {
return fmt.Errorf("Error loading location: %s", err)
}
date := now.In(loc)
customDate := args[0]
// check if a specific date is provided
if customDate != "" {
parsedDate, err := time.Parse("2006-01-02", customDate) // input format YYYY-MM-DD
// Set the time to 6pm PT
date = time.Date(parsedDate.Year(), parsedDate.Month(), parsedDate.Day(), 18, 0, 0, 0, loc)
if err != nil {
return fmt.Errorf("invalid input time format: %w", err)
}
}

return execCollectNightlyTestStatus(date, tc, gcs)
},
}

func listCNTSRequiredEnvironmentVariables() string {
var result string
for i, ev := range cntsRequiredEnvironmentVariables {
result += fmt.Sprintf("\t%2d. %s\n", i+1, ev)
}
return result
}

func execCollectNightlyTestStatus(now time.Time, tc TeamcityClient, gcs CloudstorageClient) error {
lastday := now.AddDate(0, 0, -1)
formattedStartCut := lastday.Format(time.RFC3339)
formattedFinishCut := now.Format(time.RFC3339)
date := now.Format("2006-01-02")

err := createTestReport(provider.GA, tc, gcs, formattedStartCut, formattedFinishCut, date)
if err != nil {
return fmt.Errorf("Error getting GA nightly test status: %w", err)
}

err = createTestReport(provider.Beta, tc, gcs, formattedStartCut, formattedFinishCut, date)
if err != nil {
return fmt.Errorf("Error getting Beta nightly test status: %w", err)
}

return nil
}

func createTestReport(pVersion provider.Version, tc TeamcityClient, gcs CloudstorageClient, formattedStartCut, formattedFinishCut, date string) error {
// Get all service test builds
builds, err := tc.GetBuilds(pVersion.TeamCityNightlyProjectName(), formattedFinishCut, formattedStartCut)
if err != nil {
return err
}

var testInfoList []TestInfo
for _, build := range builds.Builds {
// Get service package name
serviceName, err := convertServiceName(build.BuildTypeId)
if err != nil {
return fmt.Errorf("failed to convert test service name for %s: %v", build.BuildTypeId, err)
}
// Skip sweeper package
if serviceName == "sweeper" {
continue
}

// Get test results
serviceTestResults, err := tc.GetTestResults(build)
if err != nil {
return fmt.Errorf("failed to get test results: %v", err)
}
if len(serviceTestResults.TestResults) == 0 {
fmt.Printf("Service %s has no tests\n", serviceName)
continue
}

for _, testResult := range serviceTestResults.TestResults {
var errorMessage string
// Get test debug log gcs link
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)
// Get concise error message
if testResult.Status == "FAILURE" {
errorMessage = convertErrorMessage(testResult.ErrorMessage)
}
testInfoList = append(testInfoList, TestInfo{
Name: testResult.Name,
Status: testResult.Status,
Service: serviceName,
ErrorMessage: errorMessage,
LogLink: logLink,
})
}
}

// Write test status data to a JSON file
fmt.Println("Write test status")
testStatusFileName := fmt.Sprintf("%s-%s.json", date, pVersion.String())
err = utils.WriteToJson(testInfoList, testStatusFileName)
if err != nil {
return err
}

// Upload test status data file to gcs bucket
objectName := pVersion.String() + "/" + testStatusFileName
err = gcs.WriteToGCSBucket(NIGHTLY_DATA_BUCKET, objectName, testStatusFileName)
if err != nil {
return err
}

return nil
}

// convertServiceName extracts service package name from teamcity build type id
// input: TerraformProviders_GoogleCloud_GOOGLE_NIGHTLYTESTS_GOOGLE_PACKAGE_SECRETMANAGER
// output: secretmanager
func convertServiceName(servicePath string) (string, error) {
idx := strings.LastIndex(servicePath, "_")

if idx != -1 {
return strings.ToLower(servicePath[idx+1:]), nil
}
return "", fmt.Errorf("wrong service path format for %s", servicePath)
}

// convertErrorMessage returns concise error message
func convertErrorMessage(rawErrorMessage string) string {

startMarker := "------- Stdout: -------"
endMarker := "------- Stderr: -------"
startIndex := strings.Index(rawErrorMessage, startMarker)
endIndex := strings.Index(rawErrorMessage, endMarker)

if startIndex != -1 {
startIndex += len(startMarker)
} else {
startIndex = 0
}

if endIndex == -1 {
endIndex = len(rawErrorMessage)
}

return strings.TrimSpace(rawErrorMessage[startIndex:endIndex])
}

func init() {
rootCmd.AddCommand(collectNightlyTestStatusCmd)
}
Loading

0 comments on commit e2c62bc

Please sign in to comment.