Skip to content

Commit c70be8e

Browse files
committed
add test for user_project_override
1 parent 74ab0a8 commit c70be8e

File tree

1 file changed

+153
-1
lines changed

1 file changed

+153
-1
lines changed

third_party/terraform/utils/provider_test.go.erb

+153-1
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@ import (
55
"fmt"
66
"io/ioutil"
77
"os"
8+
"regexp"
89
"strings"
910
"testing"
11+
"time"
1012

13+
"github.com/hashicorp/terraform/helper/acctest"
14+
"github.com/hashicorp/terraform/helper/resource"
1115
"github.com/hashicorp/terraform/helper/schema"
1216
"github.com/hashicorp/terraform/terraform"
1317
"github.com/terraform-providers/terraform-provider-random/random"
@@ -196,13 +200,52 @@ func TestAccProviderBasePath_setInvalidBasePath(t *testing.T) {
196200
CheckDestroy: testAccCheckComputeAddressDestroy,
197201
Steps: []resource.TestStep{
198202
{
199-
Config: testAccProviderBasePath_setBasePath("https://www.example.com/compute/beta/", acctest.RandString(10)),
203+
Config: testAccProviderBasePath_setBasePath("https://www.example.com/compute/beta/", acctest.RandString(10)),
200204
ExpectError: regexp.MustCompile("got HTTP response code 404 with body"),
201205
},
202206
},
203207
})
204208
}
205209

210+
func TestAccProviderUserProjectOverride(t *testing.T) {
211+
t.Parallel()
212+
213+
org := getTestOrgFromEnv(t)
214+
billing := getTestBillingAccountFromEnv(t)
215+
pid := "terraform-" + acctest.RandString(10)
216+
sa := "terraform-" + acctest.RandString(10)
217+
218+
resource.Test(t, resource.TestCase{
219+
PreCheck: func() { testAccPreCheck(t) },
220+
Providers: testAccProviders,
221+
// No TestDestroy since that's not really the point of this test
222+
Steps: []resource.TestStep{
223+
{
224+
Config: testAccProviderUserProjectOverride(pid, pname, org, billing, sa),
225+
Check: func(s *terraform.State) error {
226+
time.Sleep(2 * time.Minute)
227+
return nil
228+
},
229+
},
230+
{
231+
Config: testAccProviderUserProjectOverride_step2(pid, pname, org, billing, sa, false),
232+
ExpectError: regexp.MustCompile("Binary Authorization API has not been used"),
233+
},
234+
{
235+
Config: testAccProviderUserProjectOverride_step2(pid, pname, org, billing, sa, true),
236+
},
237+
{
238+
ResourceName: "google_binary_authorization_policy.project-2-policy",
239+
ImportState: true,
240+
ImportStateVerify: true,
241+
},
242+
{
243+
Config: testAccProviderUserProjectOverride_step3(pid, pname, org, billing, sa, true),
244+
},
245+
},
246+
})
247+
}
248+
206249
func testAccProviderBasePath_setBasePath(endpoint, name string) string {
207250
return fmt.Sprintf(`
208251
provider "google" {
@@ -214,6 +257,115 @@ resource "google_compute_address" "default" {
214257
}`, endpoint, name)
215258
}
216259

260+
// Set up two projects. Project 1 has a service account that is used to create a
261+
// binauthz policy in project 2. The binauthz API is only enabled in project 2,
262+
// which causes the create to fail unless user_project_override is set to true.
263+
func testAccProviderUserProjectOverride(pid, name, org, billing, sa string) string {
264+
return fmt.Sprintf(`
265+
provider "google" {
266+
scopes = [
267+
"https://www.googleapis.com/auth/cloud-platform",
268+
"https://www.googleapis.com/auth/userinfo.email",
269+
]
270+
}
271+
272+
resource "google_project" "project-1" {
273+
project_id = "%s"
274+
name = "%s"
275+
org_id = "%s"
276+
billing_account = "%s"
277+
}
278+
279+
resource "google_service_account" "project-1" {
280+
project = google_project.project-1.project_id
281+
account_id = "%s"
282+
}
283+
284+
resource "google_project" "project-2" {
285+
project_id = "%s-2"
286+
name = "%s-2"
287+
org_id = "%s"
288+
billing_account = "%s"
289+
}
290+
291+
resource "google_project_service" "project-2-binauthz" {
292+
project = google_project.project-2.project_id
293+
service = "binaryauthorization.googleapis.com"
294+
}
295+
296+
// Permission needed for user_project_override
297+
resource "google_project_iam_member" "project-2-serviceusage" {
298+
project = google_project.project-2.project_id
299+
role = "roles/serviceusage.serviceUsageConsumer"
300+
member = "serviceAccount:${google_service_account.project-1.email}"
301+
}
302+
303+
resource "google_project_iam_member" "project-2-binauthz" {
304+
project = google_project.project-2.project_id
305+
role = "roles/binaryauthorization.policyEditor"
306+
member = "serviceAccount:${google_service_account.project-1.email}"
307+
}
308+
309+
data "google_client_openid_userinfo" "me" {}
310+
311+
// Enable the test runner to get an access token on behalf of
312+
// the project 1 service account
313+
resource "google_service_account_iam_member" "token-creator-iam" {
314+
service_account_id = google_service_account.project-1.name
315+
role = "roles/iam.serviceAccountTokenCreator"
316+
member = "serviceAccount:${data.google_client_openid_userinfo.me.email}"
317+
}
318+
`, pid, name, org, billing, sa, pid, name, org, billing)
319+
}
320+
321+
func testAccProviderUserProjectOverride_step2(pid, name, org, billing, sa string, override bool) string {
322+
return fmt.Sprintf(`
323+
// See step 3 below, which is really step 2 minus the binauthz policy.
324+
// Step 3 exists because provider configurations can't be removed while objects
325+
// created by that provider still exist in state. Step 3 will remove the
326+
// binauthz policy so the whole config can be deleted.
327+
%s
328+
329+
resource "google_binary_authorization_policy" "project-2-policy" {
330+
provider = google.project-1-token
331+
project = google_project.project-2.project_id
332+
333+
admission_whitelist_patterns {
334+
name_pattern= "gcr.io/google_containers/*"
335+
}
336+
337+
default_admission_rule {
338+
evaluation_mode = "ALWAYS_DENY"
339+
enforcement_mode = "ENFORCED_BLOCK_AND_AUDIT_LOG"
340+
}
341+
}
342+
`, testAccProviderUserProjectOverride_step3(pid, name, org, billing, sa, override))
343+
}
344+
345+
func testAccProviderUserProjectOverride_step3(pid, name, org, billing, sa string, override bool) string {
346+
return fmt.Sprintf(`
347+
%s
348+
349+
data "google_service_account_access_token" "project-1-token" {
350+
// This data source would have a depends_on t
351+
// google_service_account_iam_binding.token-creator-iam, but depends_on
352+
// in data sources makes them always have a diff in apply:
353+
// https://www.terraform.io/docs/configuration/data-sources.html#data-resource-dependencies
354+
// Instead, rely on the other test step completing before this one.
355+
356+
target_service_account = google_service_account.project-1.email
357+
scopes = ["userinfo-email", "https://www.googleapis.com/auth/cloud-platform"]
358+
lifetime = "300s"
359+
}
360+
361+
provider "google" {
362+
alias = "project-1-token"
363+
access_token = data.google_service_account_access_token.project-1-token.access_token
364+
user_project_override = %v
365+
}
366+
`, testAccProviderUserProjectOverride(pid, name, org, billing, sa), override)
367+
}
368+
217369
// getTestRegion has the same logic as the provider's getRegion, to be used in tests.
218370
func getTestRegion(is *terraform.InstanceState, config *Config) (string, error) {
219371
if res, ok := is.Attributes["region"]; ok {

0 commit comments

Comments
 (0)