github.com/swisspost/terratest@v0.0.0-20230214120104-7ec6de2e1ae0/test/gcp/terraform_gcp_example_test.go (about) 1 //go:build gcp 2 // +build gcp 3 4 // NOTE: We use build tags to differentiate GCP testing for better isolation and parallelism when executing our tests. 5 6 package test 7 8 import ( 9 "fmt" 10 "strings" 11 "testing" 12 "time" 13 14 "github.com/gruntwork-io/terratest/modules/gcp" 15 "github.com/gruntwork-io/terratest/modules/random" 16 "github.com/gruntwork-io/terratest/modules/retry" 17 "github.com/gruntwork-io/terratest/modules/ssh" 18 "github.com/gruntwork-io/terratest/modules/terraform" 19 test_structure "github.com/gruntwork-io/terratest/modules/test-structure" 20 "github.com/stretchr/testify/assert" 21 ) 22 23 func TestTerraformGcpExample(t *testing.T) { 24 t.Parallel() 25 26 exampleDir := test_structure.CopyTerraformFolderToTemp(t, "../../", "examples/terraform-gcp-example") 27 28 // Get the Project Id to use 29 projectId := gcp.GetGoogleProjectIDFromEnvVar(t) 30 31 // Create all resources in the following zone 32 zone := "us-east1-b" 33 34 // Give the example bucket a unique name so we can distinguish it from any other bucket in your GCP account 35 expectedBucketName := fmt.Sprintf("terratest-gcp-example-%s", strings.ToLower(random.UniqueId())) 36 37 // Also give the example instance a unique name 38 expectedInstanceName := fmt.Sprintf("terratest-gcp-example-%s", strings.ToLower(random.UniqueId())) 39 40 // website::tag::1::Configure Terraform setting path to Terraform code, bucket name, and instance name. Construct 41 // the terraform options with default retryable errors to handle the most common retryable errors in terraform 42 // testing. 43 terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ 44 // The path to where our Terraform code is located 45 TerraformDir: exampleDir, 46 47 // Variables to pass to our Terraform code using -var options 48 Vars: map[string]interface{}{ 49 "gcp_project_id": projectId, 50 "zone": zone, 51 "instance_name": expectedInstanceName, 52 "bucket_name": expectedBucketName, 53 }, 54 }) 55 56 // website::tag::5::At the end of the test, run `terraform destroy` to clean up any resources that were created 57 defer terraform.Destroy(t, terraformOptions) 58 59 // website::tag::2::This will run `terraform init` and `terraform apply` and fail the test if there are any errors 60 terraform.InitAndApply(t, terraformOptions) 61 62 // Run `terraform output` to get the value of some of the output variables 63 bucketURL := terraform.Output(t, terraformOptions, "bucket_url") 64 instanceName := terraform.Output(t, terraformOptions, "instance_name") 65 66 // website::tag::3::Verify that the new bucket url matches the expected url 67 expectedURL := fmt.Sprintf("gs://%s", expectedBucketName) 68 assert.Equal(t, expectedURL, bucketURL) 69 70 // Verify that the Storage Bucket exists 71 gcp.AssertStorageBucketExists(t, expectedBucketName) 72 73 // Add a tag to the Compute Instance 74 instance := gcp.FetchInstance(t, projectId, instanceName) 75 instance.SetLabels(t, map[string]string{"testing": "testing-tag-value2"}) 76 77 // Check for the labels within a retry loop as it can sometimes take a while for the 78 // changes to propagate. 79 maxRetries := 12 80 timeBetweenRetries := 5 * time.Second 81 expectedText := "testing-tag-value2" 82 83 // website::tag::4::Check if the GCP instance contains a given tag. 84 retry.DoWithRetry(t, fmt.Sprintf("Checking Instance %s for labels", instanceName), maxRetries, timeBetweenRetries, func() (string, error) { 85 // Look up the tags for the given Instance ID 86 instance := gcp.FetchInstance(t, projectId, instanceName) 87 instanceLabels := instance.GetLabels(t) 88 89 testingTag, containsTestingTag := instanceLabels["testing"] 90 actualText := strings.TrimSpace(testingTag) 91 if !containsTestingTag { 92 return "", fmt.Errorf("Expected the tag 'testing' to exist") 93 } 94 95 if actualText != expectedText { 96 return "", fmt.Errorf("Expected GetLabelsForComputeInstanceE to return '%s' but got '%s'", expectedText, actualText) 97 } 98 99 return "", nil 100 }) 101 } 102 103 // Create a Compute Instance, and attempt to SSH in and run a command. 104 func TestSshAccessToComputeInstance(t *testing.T) { 105 t.Parallel() 106 107 exampleDir := test_structure.CopyTerraformFolderToTemp(t, "../../", "examples/terraform-gcp-example") 108 109 // Setup values for our Terraform apply 110 projectID := gcp.GetGoogleProjectIDFromEnvVar(t) 111 randomValidGcpName := gcp.RandomValidGcpName() 112 zone := gcp.GetRandomZone(t, projectID, ZonesThatSupportF1Micro, nil, nil) 113 114 terraformOptions := &terraform.Options{ 115 // The path to where our Terraform code is located 116 TerraformDir: exampleDir, 117 118 // Variables to pass to our Terraform code using -var options 119 Vars: map[string]interface{}{ 120 "gcp_project_id": projectID, 121 "instance_name": randomValidGcpName, 122 "bucket_name": randomValidGcpName, 123 "zone": zone, 124 }, 125 } 126 127 // At the end of the test, run `terraform destroy` to clean up any resources that were created 128 defer terraform.Destroy(t, terraformOptions) 129 130 // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 131 terraform.InitAndApply(t, terraformOptions) 132 133 // Run `terraform output` to get the value of an output variable 134 publicIp := terraform.Output(t, terraformOptions, "public_ip") 135 136 // Attempt to SSH and execute the command 137 instance := gcp.FetchInstance(t, projectID, randomValidGcpName) 138 139 sampleText := "Hello World" 140 sshUsername := "terratest" 141 142 keyPair := ssh.GenerateRSAKeyPair(t, 2048) 143 instance.AddSshKey(t, sshUsername, keyPair.PublicKey) 144 145 host := ssh.Host{ 146 Hostname: publicIp, 147 SshKeyPair: keyPair, 148 SshUserName: sshUsername, 149 } 150 151 maxRetries := 20 152 sleepBetweenRetries := 3 * time.Second 153 154 retry.DoWithRetry(t, "Attempting to SSH", maxRetries, sleepBetweenRetries, func() (string, error) { 155 output, err := ssh.CheckSshCommandE(t, host, fmt.Sprintf("echo '%s'", sampleText)) 156 if err != nil { 157 return "", err 158 } 159 160 if strings.TrimSpace(sampleText) != strings.TrimSpace(output) { 161 return "", fmt.Errorf("Expected: %s. Got: %s\n", sampleText, output) 162 } 163 164 return "", nil 165 }) 166 }