From 054d1b0efdee6bd145f2469ffa0ccbd1e8436aa6 Mon Sep 17 00:00:00 2001 From: Andrew Peabody Date: Fri, 15 Nov 2024 16:07:44 -0800 Subject: [PATCH] feat(blueprint-test): add cai helper (#2689) --- infra/blueprint-test/pkg/cai/cai.go | 82 +++++++++++++++++++++++++ infra/blueprint-test/test/cai_test.go | 70 +++++++++++++++++++++ infra/blueprint-test/test/setup/main.tf | 12 ++-- 3 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 infra/blueprint-test/pkg/cai/cai.go create mode 100644 infra/blueprint-test/test/cai_test.go diff --git a/infra/blueprint-test/pkg/cai/cai.go b/infra/blueprint-test/pkg/cai/cai.go new file mode 100644 index 00000000000..58474edf721 --- /dev/null +++ b/infra/blueprint-test/pkg/cai/cai.go @@ -0,0 +1,82 @@ +/** + * Copyright 2024 Google LLC + * + * 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 cai provides a set of helpers to interact with Cloud Asset Inventory +package cai + +import ( + "fmt" + "strings" + "testing" + "time" + + "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/gcloud" + "github.com/tidwall/gjson" +) + +type CmdCfg struct { + sleep int // minutes to sleep prior to CAI retreval. default: 2 + assetTypes []string // asset types to retrieve. empty: all + args []string // arguments to pass to call +} + +type cmdOption func(*CmdCfg) + +// newCmdConfig sets defaults and options +func newCmdConfig(opts ...cmdOption) (*CmdCfg) { + caiOpts := &CmdCfg{ + sleep: 2, + assetTypes: nil, + args: nil, + } + + for _, opt := range opts { + opt(caiOpts) + } + + if caiOpts.assetTypes != nil { + caiOpts.args = []string{"--asset-types", strings.Join(caiOpts.assetTypes, ",")} + } + caiOpts.args = append(caiOpts.args, "--content-type", "resource") + + return caiOpts +} + +// Set custom sleep minutes +func WithSleep(sleep int) cmdOption { + return func(f *CmdCfg) { + f.sleep = sleep + } +} + +// Set asset types +func WithAssetTypes(assetTypes []string) cmdOption { + return func(f *CmdCfg) { + f.assetTypes = assetTypes + } +} + +// GetProjectResources returns the cloud asset inventory resources for a project as a gjson.Result +func GetProjectResources(t testing.TB, project string, opts ...cmdOption) gjson.Result { + caiOpts := newCmdConfig(opts...) + + // Cloud Asset Inventory offers best-effort data freshness. + t.Logf("Sleeping for %d minutes before retrieving Cloud Asset Inventory...", caiOpts.sleep) + time.Sleep(time.Duration(caiOpts.sleep) * time.Minute) + + cmd := fmt.Sprintf("asset list --project %s", project) + return gcloud.Runf(t, strings.Join(append([]string{cmd}, caiOpts.args...), " ")) +} diff --git a/infra/blueprint-test/test/cai_test.go b/infra/blueprint-test/test/cai_test.go new file mode 100644 index 00000000000..54c6de41ea4 --- /dev/null +++ b/infra/blueprint-test/test/cai_test.go @@ -0,0 +1,70 @@ +/** + * Copyright 2024 Google LLC + * + * 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 test + +import ( + "encoding/base64" + "fmt" + "testing" + + "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/cai" + "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/gcloud" + "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/tft" + "github.com/stretchr/testify/assert" +) + +func TestGetProjectResources(t *testing.T) { + tests := []struct { + name string + assetTypes []string + wantKeyPath string + wantVal string + }{ + {name: "all", assetTypes: nil, wantKeyPath: "resource.data.nodeConfig.imageType", wantVal: "COS_CONTAINERD"}, + {name: "cluster", assetTypes: []string{"container.googleapis.com/Cluster", "compute.googleapis.com/Project"}, wantKeyPath: "resource.data.nodeConfig.imageType", wantVal: "COS_CONTAINERD"}, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + assert := assert.New(t) + + tfBlueprint := tft.NewTFBlueprintTest(t, + tft.WithTFDir("setup"), + ) + + clusterResourceName := fmt.Sprintf("//container.googleapis.com/projects/%s/locations/%s/clusters/%s", + tfBlueprint.GetStringOutput("project_id"), + tfBlueprint.GetStringOutput("cluster_region"), + tfBlueprint.GetStringOutput("cluster_name"), + ) + + projectResourceName := fmt.Sprintf("//compute.googleapis.com/projects/%s", + tfBlueprint.GetStringOutput("project_id"), + ) + + // Use the test SA for cai call + credDec, _ := base64.StdEncoding.DecodeString(tfBlueprint.GetStringOutput("sa_key")) + gcloud.ActivateCredsAndEnvVars(t, string(credDec)) + + cai := cai.GetProjectResources(t, tfBlueprint.GetStringOutput("project_id"), cai.WithAssetTypes(tt.assetTypes)) + assert.Equal(tfBlueprint.GetStringOutput("project_id"), cai.Get("#(name=\"" + projectResourceName + "\").resource.data.name").String(), "project_id exists in cai") + assert.Equal(tt.wantVal, cai.Get("#(name=\"" + clusterResourceName + "\")." + tt.wantKeyPath).String(), "correct cluster image type") + }) + } +} diff --git a/infra/blueprint-test/test/setup/main.tf b/infra/blueprint-test/test/setup/main.tf index a3baceec096..27dcdff20e7 100644 --- a/infra/blueprint-test/test/setup/main.tf +++ b/infra/blueprint-test/test/setup/main.tf @@ -21,13 +21,15 @@ locals { "roles/iam.serviceAccountUser", "roles/vpcaccess.admin", "roles/serviceusage.serviceUsageAdmin", - "roles/container.admin" + "roles/container.admin", + "roles/cloudasset.viewer", + "roles/serviceusage.serviceUsageConsumer" ] } module "project" { source = "terraform-google-modules/project-factory/google" - version = "~> 14.0" + version = "~> 17.0" name = "ci-bptest" random_project_id = "true" @@ -36,13 +38,15 @@ module "project" { billing_account = var.billing_account default_service_account = "DEPRIVILEGE" + deletion_policy = "DELETE" activate_apis = [ "cloudresourcemanager.googleapis.com", "compute.googleapis.com", "serviceusage.googleapis.com", "vpcaccess.googleapis.com", - "container.googleapis.com" + "container.googleapis.com", + "cloudasset.googleapis.com" ] } @@ -66,6 +70,6 @@ resource "google_service_account_key" "key" { module "kubernetes-engine_example_simple_autopilot_public" { source = "terraform-google-modules/kubernetes-engine/google//examples/simple_autopilot_public" - version = "~> 30.0" + version = "~> 34.0" project_id = module.project.project_id }