Skip to content

Commit

Permalink
Backport Add provider attribute universe_domain
Browse files Browse the repository at this point in the history
Backporting GoogleCloudPlatform/magic-modules#8657

Add provider attribute universe_domain
provider: added `universe_domain` attribute as a provider attribute
  • Loading branch information
cheftako committed Mar 15, 2024
1 parent dcd267e commit 08450c1
Show file tree
Hide file tree
Showing 13 changed files with 394 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ var OrgTargetEnvVars = []string{
"GOOGLE_ORG_2",
}

var UniverseDomainEnvVars = []string{
"GOOGLE_UNIVERSE_DOMAIN",
}

// This is the billing account that will be charged for the infrastructure used during testing. For
// that reason, it is also the billing account used for creating new projects.
var BillingAccountEnvVars = []string{
Expand Down Expand Up @@ -113,6 +117,12 @@ func GetTestCredsFromEnv() string {
return transport_tpg.MultiEnvSearch(CredsEnvVars)
}

// Returns googleapis.com if there's no universe set.
func GetTestUniverseDomainFromEnv(t *testing.T) string {
SkipIfEnvNotSet(t, IdentityUserEnvVars...)
return transport_tpg.MultiEnvSearch(UniverseDomainEnvVars)
}

// AccTestPreCheck ensures at least one of the region env variables is set.
func GetTestRegionFromEnv() string {
return transport_tpg.MultiEnvSearch(RegionEnvVars)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type ProviderModel struct {
UserProjectOverride types.Bool `tfsdk:"user_project_override"`
RequestTimeout types.String `tfsdk:"request_timeout"`
RequestReason types.String `tfsdk:"request_reason"`
UniverseDomain types.String `tfsdk:"universe_domain"`

// Generated Products
AccessApprovalCustomEndpoint types.String `tfsdk:"access_approval_custom_endpoint"`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest,
"request_reason": schema.StringAttribute{
Optional: true,
},

"universe_domain": schema.StringAttribute{
Optional: true,
},
// Generated Products
"access_approval_custom_endpoint": &schema.StringAttribute{
Optional: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type FrameworkProviderConfig struct {
RequestBatcherServiceUsage *transport_tpg.RequestBatcher
Scopes types.List
TokenSource oauth2.TokenSource
UniverseDomain types.String
UserAgent string
UserProjectOverride types.Bool

Expand Down Expand Up @@ -337,6 +338,8 @@ func (p *FrameworkProviderConfig) LoadAndValidateFramework(ctx context.Context,
p.Zone = data.Zone
p.UserProjectOverride = data.UserProjectOverride
p.PollInterval = 10 * time.Second
p.Project = data.Project
p.UniverseDomain = data.UniverseDomain
p.RequestBatcherServiceUsage = transport_tpg.NewRequestBatcher("Service Usage", ctx, batchingConfig)
p.RequestBatcherIam = transport_tpg.NewRequestBatcher("IAM", ctx, batchingConfig)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ package provider

import (
"context"
"encoding/json"
"fmt"
"os"
"strings"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
Expand Down Expand Up @@ -208,6 +210,11 @@ func Provider() *schema.Provider {
Elem: &schema.Schema{Type: schema.TypeString},
},

"universe_domain": {
Type: schema.TypeString,
Optional: true,
},

"batching": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -1991,6 +1998,43 @@ func ProviderConfigure(ctx context.Context, d *schema.ResourceData, p *schema.Pr
})
}

// set universe_domain based on the service account key file.
if config.Credentials != "" {
contents, _, err := verify.PathOrContents(config.Credentials)
if err != nil {
return nil, diag.FromErr(fmt.Errorf("error loading service account credentials: %s", err))
}
var content map[string]any

if err := json.Unmarshal([]byte(contents), &content); err != nil {
return nil, diag.FromErr(err)
}

if content["universe_domain"] != nil {
config.UniverseDomain = content["universe_domain"].(string)
}
}

// Check if the user provided a value from the universe_domain field
if v, ok := d.GetOk("universe_domain"); ok {
if config.UniverseDomain == "" {
config.UniverseDomain = v.(string)
} else if v.(string) != config.UniverseDomain {
if _, err := os.Stat(config.Credentials); err == nil {
return nil, diag.FromErr(fmt.Errorf("'%s' does not match the universe domain '%s' already set in the credential file '%s'. The 'universe_domain' provider configuration can not be used to override the universe domain that is defined in the active credential. Set the 'universe_domain' provider configuration when universe domain information is not already available in the credential, e.g. when authenticating with a JWT token.", v, config.UniverseDomain, config.Credentials))
} else {
return nil, diag.FromErr(fmt.Errorf("'%s' does not match the universe domain '%s' supplied directly to Terraform. The 'universe_domain' provider configuration can not be used to override the universe domain that is defined in the active credential. Set the 'universe_domain' provider configuration when universe domain information is not already available in the credential, e.g. when authenticating with a JWT token.", v, config.UniverseDomain))
}
}
}

// Replace hostname by the universe_domain field.
if config.UniverseDomain != "" && config.UniverseDomain != "googleapis.com" {
for key, basePath := range transport_tpg.DefaultBasePaths {
transport_tpg.DefaultBasePaths[key] = strings.ReplaceAll(basePath, "googleapis.com", config.UniverseDomain)
}
}

// Given that impersonate_service_account is a secondary auth method, it has
// no conflicts to worry about. We pull the env var in a DefaultFunc.
if v, ok := d.GetOk("impersonate_service_account"); ok {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package universe_test

import (
"fmt"
"strings"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"

"github.com/hashicorp/terraform-provider-google/google/acctest"
"github.com/hashicorp/terraform-provider-google/google/envvar"
"github.com/hashicorp/terraform-provider-google/google/tpgresource"
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
)

func TestAccUniverseDomainDisk(t *testing.T) {
// Skip this test in all env since this can only run in specific test project.
t.Skip()

universeDomain := envvar.GetTestUniverseDomainFromEnv(t)

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckComputeDiskDestroyProducer(t),
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccUniverseDomain_basic_disk(universeDomain),
},
},
})
}

func TestAccDefaultUniverseDomainDisk(t *testing.T) {
universeDomain := "googleapis.com"

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckComputeDiskDestroyProducer(t),
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccUniverseDomain_basic_disk(universeDomain),
},
},
})
}

func testAccUniverseDomain_basic_disk(universeDomain string) string {
return fmt.Sprintf(`
provider "google" {
universe_domain = "%s"
}
resource "google_compute_instance_template" "instance_template" {
name = "demo-this"
machine_type = "n1-standard-1"
// boot disk
disk {
disk_size_gb = 20
}
network_interface {
network = "default"
}
}
`, universeDomain)
}

func testAccCheckComputeDiskDestroyProducer(t *testing.T) func(s *terraform.State) error {
return func(s *terraform.State) error {
for name, rs := range s.RootModule().Resources {
if rs.Type != "google_compute_disk" {
continue
}
if strings.HasPrefix(name, "data.") {
continue
}

config := acctest.GoogleProviderConfig(t)

url, err := tpgresource.ReplaceVarsForTest(config, rs, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/disks/{{name}}")
if err != nil {
return err
}

billingProject := ""

if config.BillingProject != "" {
billingProject = config.BillingProject
}

_, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
Config: config,
Method: "GET",
Project: billingProject,
RawURL: url,
UserAgent: config.UserAgent,
})
if err == nil {
return fmt.Errorf("ComputeDisk still exists at %s", url)
}
}

return nil
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package universe_test

import (
"fmt"
"strings"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"

"github.com/hashicorp/terraform-provider-google/google/acctest"
"github.com/hashicorp/terraform-provider-google/google/envvar"
"github.com/hashicorp/terraform-provider-google/google/tpgresource"
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
)

func TestAccUniverseDomainPubSub(t *testing.T) {
// Skip this test in all env since this can only run in specific test project.
t.Skip()

universeDomain := envvar.GetTestUniverseDomainFromEnv(t)
topic := fmt.Sprintf("tf-test-topic-%s", acctest.RandString(t, 10))
subscription := fmt.Sprintf("tf-test-sub-%s", acctest.RandString(t, 10))

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckPubsubSubscriptionDestroyProducer(t),
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccUniverseDomain_basic_pubsub(universeDomain, topic, subscription),
},
},
})
}

func testAccUniverseDomain_basic_pubsub(universeDomain, topic, subscription string) string {
return fmt.Sprintf(`
provider "google" {
universe_domain = "%s"
}
resource "google_pubsub_topic" "foo" {
name = "%s"
}
resource "google_pubsub_subscription" "foo" {
name = "%s"
topic = google_pubsub_topic.foo.id
message_retention_duration = "1200s"
retain_acked_messages = true
ack_deadline_seconds = 20
expiration_policy {
ttl = ""
}
enable_message_ordering = false
}
`, universeDomain, topic, subscription)
}

func testAccCheckPubsubSubscriptionDestroyProducer(t *testing.T) func(s *terraform.State) error {
return func(s *terraform.State) error {
for name, rs := range s.RootModule().Resources {
if rs.Type != "google_pubsub_subscription" {
continue
}
if strings.HasPrefix(name, "data.") {
continue
}

config := acctest.GoogleProviderConfig(t)

url, err := tpgresource.ReplaceVarsForTest(config, rs, "{{PubsubBasePath}}projects/{{project}}/subscriptions/{{name}}")
if err != nil {
return err
}

billingProject := ""

if config.BillingProject != "" {
billingProject = config.BillingProject
}

_, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
Config: config,
Method: "GET",
Project: billingProject,
RawURL: url,
UserAgent: config.UserAgent,
})
if err == nil {
return fmt.Errorf("PubsubSubscription still exists at %s", url)
}
}

return nil
}
}
Loading

0 comments on commit 08450c1

Please sign in to comment.