From 98d2972c31a37222281cbcf97e8d9b22740a6fc5 Mon Sep 17 00:00:00 2001 From: The Magician Date: Tue, 8 Jan 2019 18:32:27 -0800 Subject: [PATCH] Add Kms bootstrap step for terraform tests (#2837) Signed-off-by: Modular Magician --- google/bootstrap_utils_test.go | 105 ++++++++++++++++++ google/provider_test.go | 4 + ...resource_compute_instance_template_test.go | 73 ++---------- 3 files changed, 117 insertions(+), 65 deletions(-) create mode 100644 google/bootstrap_utils_test.go diff --git a/google/bootstrap_utils_test.go b/google/bootstrap_utils_test.go new file mode 100644 index 00000000..8da2e031 --- /dev/null +++ b/google/bootstrap_utils_test.go @@ -0,0 +1,105 @@ +package google + +import ( + "fmt" + "log" + "os" + "testing" + + "google.golang.org/api/cloudkms/v1" +) + +var SharedKeyRing = "tftest-shared-keyring-1" +var SharedCyptoKey = "tftest-shared-key-1" + +type bootstrappedKMS struct { + *cloudkms.KeyRing + *cloudkms.CryptoKey +} + +/** +* BootstrapKMSkey will return a KMS key that can be used in tests that are +* testing KMS integration with other resources. +* +* This will either return an existing key or create one if it hasn't been created +* in the project yet. The motivation is because keyrings don't get deleted and we +* don't want a linear growth of disabled keyrings in a project. We also don't want +* to incur the overhead of creating a new project for each test that needs to use +* a KMS key. +**/ +func BootstrapKMSKey(t *testing.T) bootstrappedKMS { + if v := os.Getenv("TF_ACC"); v == "" { + log.Println("Acceptance tests and bootstrapping skipped unless env 'TF_ACC' set") + + // If not running acceptance tests, return an empty object + return bootstrappedKMS{ + &cloudkms.KeyRing{}, + &cloudkms.CryptoKey{}, + } + } + + projectID := getTestProjectFromEnv() + locationID := "global" + keyRingParent := fmt.Sprintf("projects/%s/locations/%s", projectID, locationID) + keyRingName := fmt.Sprintf("%s/keyRings/%s", keyRingParent, SharedKeyRing) + keyParent := fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", projectID, locationID, SharedKeyRing) + keyName := fmt.Sprintf("%s/cryptoKeys/%s", keyParent, SharedCyptoKey) + + config := Config{ + Credentials: getTestCredsFromEnv(), + Project: getTestProjectFromEnv(), + Region: getTestRegionFromEnv(), + Zone: getTestZoneFromEnv(), + } + + if err := config.loadAndValidate(); err != nil { + t.Errorf("Unable to bootstrap KMS key: %s", err) + } + + // Get or Create the hard coded shared keyring for testing + kmsClient := config.clientKms + keyRing, err := kmsClient.Projects.Locations.KeyRings.Get(keyRingName).Do() + if err != nil { + if isGoogleApiErrorWithCode(err, 404) { + keyRing, err = kmsClient.Projects.Locations.KeyRings.Create(keyRingParent, &cloudkms.KeyRing{}). + KeyRingId(SharedKeyRing).Do() + if err != nil { + t.Errorf("Unable to bootstrap KMS key. Cannot create keyRing: %s", err) + } + } else { + t.Errorf("Unable to bootstrap KMS key. Cannot retrieve keyRing: %s", err) + } + } + + if keyRing == nil { + t.Fatalf("Unable to bootstrap KMS key. keyRing is nil!") + } + + // Get or Create the hard coded, shared crypto key for testing + cryptoKey, err := kmsClient.Projects.Locations.KeyRings.CryptoKeys.Get(keyName).Do() + if err != nil { + if isGoogleApiErrorWithCode(err, 404) { + newKey := cloudkms.CryptoKey{ + Purpose: "ENCRYPT_DECRYPT", + } + + cryptoKey, err = kmsClient.Projects.Locations.KeyRings.CryptoKeys.Create(keyParent, &newKey). + CryptoKeyId(SharedCyptoKey).Do() + if err != nil { + t.Errorf("Unable to bootstrap KMS key. Cannot create new CryptoKey: %s", err) + } + + } else { + t.Errorf("Unable to bootstrap KMS key. Cannot call CryptoKey service: %s", err) + } + } + + if cryptoKey == nil { + t.Fatalf("Unable to bootstrap KMS key. CryptoKey is nil!") + } + + return bootstrappedKMS{ + keyRing, + cryptoKey, + } +} diff --git a/google/provider_test.go b/google/provider_test.go index d738ea9b..dacfcac5 100644 --- a/google/provider_test.go +++ b/google/provider_test.go @@ -178,6 +178,10 @@ func getTestRegionFromEnv() string { return multiEnvSearch(regionEnvVars) } +func getTestZoneFromEnv() string { + return multiEnvSearch(zoneEnvVars) +} + func getTestOrgFromEnv(t *testing.T) string { skipIfEnvNotSet(t, orgEnvVars...) return multiEnvSearch(orgEnvVars) diff --git a/google/resource_compute_instance_template_test.go b/google/resource_compute_instance_template_test.go index fb986819..c729623d 100644 --- a/google/resource_compute_instance_template_test.go +++ b/google/resource_compute_instance_template_test.go @@ -476,13 +476,7 @@ func TestAccComputeInstanceTemplate_EncryptKMS(t *testing.T) { t.Parallel() var instanceTemplate compute.InstanceTemplate - - org := getTestOrgFromEnv(t) - pid := "tf-test-" + acctest.RandString(10) - billingAccount := getTestBillingAccountFromEnv(t) - diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) - keyRingName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) - keyName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) + kms := BootstrapKMSKey(t) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -490,7 +484,7 @@ func TestAccComputeInstanceTemplate_EncryptKMS(t *testing.T) { CheckDestroy: testAccCheckComputeInstanceTemplateDestroy, Steps: []resource.TestStep{ { - Config: testAccComputeInstanceTemplate_encryptionKMS(pid, pname, org, billingAccount, diskName, keyRingName, keyName), + Config: testAccComputeInstanceTemplate_encryptionKMS(kms.CryptoKey.Name), Check: resource.ComposeTestCheckFunc( testAccCheckComputeInstanceTemplateExists("google_compute_instance_template.foobar", &instanceTemplate), ), @@ -1186,7 +1180,7 @@ func testAccComputeInstanceTemplate_subnet_xpn(org, billingId, projectName strin resource "google_compute_shared_vpc_host_project" "host_project" { project = "${google_project_service.host_project.project}" } - + resource "google_project" "service_project" { name = "Test Project XPN Service" project_id = "%s-service" @@ -1347,7 +1341,7 @@ resource "google_compute_instance_template" "foobar" { // Note that unlike compute instances, instance templates seem to be // only able to specify the netmask here. Trying a full CIDR string - // results in: + // results in: // Invalid value for field 'resource.properties.networkInterfaces[0].aliasIpRanges[0].ipCidrRange': // '172.16.0.0/24'. Alias IP CIDR range must be a valid netmask starting with '/' (e.g. '/24') alias_ip_range { @@ -1423,64 +1417,13 @@ resource "google_compute_instance_template" "foobar" { }`, i, DEFAULT_MIN_CPU_TEST_VALUE) } -func testAccComputeInstanceTemplate_encryptionKMS(pid, pname, org, billing, diskName, keyRingName, keyName string) string { +func testAccComputeInstanceTemplate_encryptionKMS(kmsLink string) string { return fmt.Sprintf(` -resource "google_project" "project" { - project_id = "%s" - name = "%s" - org_id = "%s" - billing_account = "%s" -} - data "google_compute_image" "my_image" { family = "debian-9" project = "debian-cloud" } -resource "google_project_services" "apis" { - project = "${google_project.project.project_id}" - - services = [ - "oslogin.googleapis.com", - "compute.googleapis.com", - "cloudkms.googleapis.com", - "appengine.googleapis.com", - ] -} - -resource "google_project_iam_member" "kms-project-binding" { - project = "${google_project.project.project_id}" - role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" - member = "serviceAccount:service-${google_project.project.number}@compute-system.iam.gserviceaccount.com" - - depends_on = ["google_project_services.apis"] -} - -resource "google_kms_crypto_key_iam_binding" "kms-key-binding" { - crypto_key_id = "${google_kms_crypto_key.my_crypto_key.self_link}" - role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" - - members = [ - "serviceAccount:service-${google_project.project.number}@compute-system.iam.gserviceaccount.com", - ] - - depends_on = ["google_project_services.apis"] -} - -resource "google_kms_key_ring" "my_key_ring" { - name = "%s" - project = "${google_project.project.project_id}" - location = "us-central1" - - depends_on = ["google_project_services.apis"] -} - -resource "google_kms_crypto_key" "my_crypto_key" { - name = "%s" - key_ring = "${google_kms_key_ring.my_key_ring.self_link}" -} - - resource "google_compute_instance_template" "foobar" { name = "instancet-test-%s" machine_type = "n1-standard-1" @@ -1489,8 +1432,8 @@ resource "google_compute_instance_template" "foobar" { disk { source_image = "${data.google_compute_image.my_image.self_link}" disk_encryption_key { - kms_key_self_link = "${google_kms_crypto_key.my_crypto_key.self_link}" - } + kms_key_self_link = "%s" + } } network_interface { @@ -1504,5 +1447,5 @@ resource "google_compute_instance_template" "foobar" { labels = { my_label = "foobar" } -}`, pid, pname, org, billing, keyRingName, keyName, acctest.RandString(10)) +}`, acctest.RandString(10), kmsLink) }