@@ -5,9 +5,13 @@ import (
5
5
"fmt"
6
6
"io/ioutil"
7
7
"os"
8
+ "regexp"
8
9
"strings"
9
10
"testing"
11
+ "time"
10
12
13
+ "github.com/hashicorp/terraform/helper/acctest"
14
+ "github.com/hashicorp/terraform/helper/resource"
11
15
"github.com/hashicorp/terraform/helper/schema"
12
16
"github.com/hashicorp/terraform/terraform"
13
17
"github.com/terraform-providers/terraform-provider-random/random"
@@ -196,13 +200,52 @@ func TestAccProviderBasePath_setInvalidBasePath(t *testing.T) {
196
200
CheckDestroy: testAccCheckComputeAddressDestroy,
197
201
Steps: []resource.TestStep{
198
202
{
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)),
200
204
ExpectError: regexp.MustCompile("got HTTP response code 404 with body"),
201
205
},
202
206
},
203
207
})
204
208
}
205
209
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
+
206
249
func testAccProviderBasePath_setBasePath(endpoint, name string) string {
207
250
return fmt.Sprintf(`
208
251
provider "google" {
@@ -214,6 +257,115 @@ resource "google_compute_address" "default" {
214
257
}`, endpoint, name)
215
258
}
216
259
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
+
217
369
// getTestRegion has the same logic as the provider's getRegion, to be used in tests.
218
370
func getTestRegion(is *terraform.InstanceState, config *Config) (string, error) {
219
371
if res, ok := is.Attributes["region"]; ok {
0 commit comments