Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for oauth and oidc tokens to cloud_scheduler_job #4222

Merged
merged 1 commit into from
Aug 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 225 additions & 0 deletions google/resource_cloud_scheduler_job.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,55 @@ import (
"github.com/hashicorp/terraform/helper/schema"
)

// Both oidc and oauth headers cannot be set
func validateAuthHeaders(diff *schema.ResourceDiff, v interface{}) error {
httpBlock := diff.Get("http_target.0").(map[string]interface{})

if httpBlock != nil {
oauth := httpBlock["oauth_token"]
oidc := httpBlock["oidc_token"]

if oauth != nil && oidc != nil {
if len(oidc.([]interface{})) > 0 && len(oauth.([]interface{})) > 0 {
return fmt.Errorf("Error in http_target: only one of oauth_token or oidc_token can be specified, but not both.")
}
}
}

return nil
}

func authHeaderDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
// If generating an `oauth_token` and `scope` is not provided in the configuration,
// the default "https://www.googleapis.com/auth/cloud-platform" scope will be used.
// Similarly, if generating an `oidc_token` and `audience` is not provided in the
// configuration, the URI specified in target will be used. Although not in the
// configuration, in both cases the default is returned in the object, but is not in.
// state. We suppress the diff if the values are these defaults but are not stored in state.

b := strings.Split(k, ".")
if b[0] == "http_target" && len(b) > 4 {
block := b[2]
attr := b[4]

if block == "oauth_token" && attr == "scope" {
if old == canonicalizeServiceScope("cloud-platform") && new == "" {
return true
}
}

if block == "oidc_token" && attr == "audience" {
uri := d.Get(strings.Join(b[0:2], ".") + ".uri")
if old == uri && new == "" {
return true
}
}

}

return false
}

func resourceCloudSchedulerJob() *schema.Resource {
return &schema.Resource{
Create: resourceCloudSchedulerJobCreate,
Expand All @@ -41,6 +90,8 @@ func resourceCloudSchedulerJob() *schema.Resource {
Delete: schema.DefaultTimeout(4 * time.Minute),
},

CustomizeDiff: validateAuthHeaders,

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Expand Down Expand Up @@ -145,6 +196,48 @@ func resourceCloudSchedulerJob() *schema.Resource {
Optional: true,
ForceNew: true,
},
"oauth_token": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
DiffSuppressFunc: authHeaderDiffSuppress,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"scope": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"service_account_email": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
},
},
},
"oidc_token": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
DiffSuppressFunc: authHeaderDiffSuppress,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"audience": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"service_account_email": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
},
},
},
},
},
ConflictsWith: []string{"pubsub_target", "app_engine_http_target"},
Expand Down Expand Up @@ -620,6 +713,10 @@ func flattenCloudSchedulerJobHttpTarget(v interface{}, d *schema.ResourceData) i
flattenCloudSchedulerJobHttpTargetBody(original["body"], d)
transformed["headers"] =
flattenCloudSchedulerJobHttpTargetHeaders(original["headers"], d)
transformed["oauth_token"] =
flattenCloudSchedulerJobHttpTargetOauthToken(original["oauthToken"], d)
transformed["oidc_token"] =
flattenCloudSchedulerJobHttpTargetOidcToken(original["oidcToken"], d)
return []interface{}{transformed}
}
func flattenCloudSchedulerJobHttpTargetUri(v interface{}, d *schema.ResourceData) interface{} {
Expand Down Expand Up @@ -659,6 +756,52 @@ func flattenCloudSchedulerJobHttpTargetHeaders(v interface{}, d *schema.Resource
return headers
}

func flattenCloudSchedulerJobHttpTargetOauthToken(v interface{}, d *schema.ResourceData) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
if len(original) == 0 {
return nil
}
transformed := make(map[string]interface{})
transformed["service_account_email"] =
flattenCloudSchedulerJobHttpTargetOauthTokenServiceAccountEmail(original["serviceAccountEmail"], d)
transformed["scope"] =
flattenCloudSchedulerJobHttpTargetOauthTokenScope(original["scope"], d)
return []interface{}{transformed}
}
func flattenCloudSchedulerJobHttpTargetOauthTokenServiceAccountEmail(v interface{}, d *schema.ResourceData) interface{} {
return v
}

func flattenCloudSchedulerJobHttpTargetOauthTokenScope(v interface{}, d *schema.ResourceData) interface{} {
return v
}

func flattenCloudSchedulerJobHttpTargetOidcToken(v interface{}, d *schema.ResourceData) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
if len(original) == 0 {
return nil
}
transformed := make(map[string]interface{})
transformed["service_account_email"] =
flattenCloudSchedulerJobHttpTargetOidcTokenServiceAccountEmail(original["serviceAccountEmail"], d)
transformed["audience"] =
flattenCloudSchedulerJobHttpTargetOidcTokenAudience(original["audience"], d)
return []interface{}{transformed}
}
func flattenCloudSchedulerJobHttpTargetOidcTokenServiceAccountEmail(v interface{}, d *schema.ResourceData) interface{} {
return v
}

func flattenCloudSchedulerJobHttpTargetOidcTokenAudience(v interface{}, d *schema.ResourceData) interface{} {
return v
}

func expandCloudSchedulerJobName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
var jobName string
project, err := getProject(d, config)
Expand Down Expand Up @@ -964,6 +1107,20 @@ func expandCloudSchedulerJobHttpTarget(v interface{}, d TerraformResourceData, c
transformed["headers"] = transformedHeaders
}

transformedOauthToken, err := expandCloudSchedulerJobHttpTargetOauthToken(original["oauth_token"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedOauthToken); val.IsValid() && !isEmptyValue(val) {
transformed["oauthToken"] = transformedOauthToken
}

transformedOidcToken, err := expandCloudSchedulerJobHttpTargetOidcToken(original["oidc_token"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedOidcToken); val.IsValid() && !isEmptyValue(val) {
transformed["oidcToken"] = transformedOidcToken
}

return transformed, nil
}

Expand All @@ -989,3 +1146,71 @@ func expandCloudSchedulerJobHttpTargetHeaders(v interface{}, d TerraformResource
}
return m, nil
}

func expandCloudSchedulerJobHttpTargetOauthToken(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedServiceAccountEmail, err := expandCloudSchedulerJobHttpTargetOauthTokenServiceAccountEmail(original["service_account_email"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedServiceAccountEmail); val.IsValid() && !isEmptyValue(val) {
transformed["serviceAccountEmail"] = transformedServiceAccountEmail
}

transformedScope, err := expandCloudSchedulerJobHttpTargetOauthTokenScope(original["scope"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedScope); val.IsValid() && !isEmptyValue(val) {
transformed["scope"] = transformedScope
}

return transformed, nil
}

func expandCloudSchedulerJobHttpTargetOauthTokenServiceAccountEmail(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandCloudSchedulerJobHttpTargetOauthTokenScope(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandCloudSchedulerJobHttpTargetOidcToken(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedServiceAccountEmail, err := expandCloudSchedulerJobHttpTargetOidcTokenServiceAccountEmail(original["service_account_email"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedServiceAccountEmail); val.IsValid() && !isEmptyValue(val) {
transformed["serviceAccountEmail"] = transformedServiceAccountEmail
}

transformedAudience, err := expandCloudSchedulerJobHttpTargetOidcTokenAudience(original["audience"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedAudience); val.IsValid() && !isEmptyValue(val) {
transformed["audience"] = transformedAudience
}

return transformed, nil
}

func expandCloudSchedulerJobHttpTargetOidcTokenServiceAccountEmail(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandCloudSchedulerJobHttpTargetOidcTokenAudience(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}
96 changes: 96 additions & 0 deletions google/resource_cloud_scheduler_job_generated_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,102 @@ resource "google_cloud_scheduler_job" "job" {
`, context)
}

func TestAccCloudSchedulerJob_schedulerJobOauthExample(t *testing.T) {
t.Parallel()

context := map[string]interface{}{
"project_name": getTestProjectFromEnv(),
"region": getTestRegionFromEnv(),
"random_suffix": acctest.RandString(10),
}

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudSchedulerJobDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudSchedulerJob_schedulerJobOauthExample(context),
},
{
ResourceName: "google_cloud_scheduler_job.job",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"region"},
},
},
})
}

func testAccCloudSchedulerJob_schedulerJobOauthExample(context map[string]interface{}) string {
return Nprintf(`
data "google_compute_default_service_account" "default" { }

resource "google_cloud_scheduler_job" "job" {
name = "test-job%{random_suffix}"
description = "test http job"
schedule = "*/8 * * * *"
time_zone = "America/New_York"

http_target {
http_method = "GET"
uri = "https://cloudscheduler.googleapis.com/v1/projects/%{project_name}/locations/%{region}/jobs"

oauth_token {
service_account_email = "${data.google_compute_default_service_account.default.email}"
}
}
}
`, context)
}

func TestAccCloudSchedulerJob_schedulerJobOidcExample(t *testing.T) {
t.Parallel()

context := map[string]interface{}{
"random_suffix": acctest.RandString(10),
}

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudSchedulerJobDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudSchedulerJob_schedulerJobOidcExample(context),
},
{
ResourceName: "google_cloud_scheduler_job.job",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"region"},
},
},
})
}

func testAccCloudSchedulerJob_schedulerJobOidcExample(context map[string]interface{}) string {
return Nprintf(`
data "google_compute_default_service_account" "default" { }

resource "google_cloud_scheduler_job" "job" {
name = "test-job%{random_suffix}"
description = "test http job"
schedule = "*/8 * * * *"
time_zone = "America/New_York"

http_target {
http_method = "GET"
uri = "https://example.com/ping"

oidc_token {
service_account_email = "${data.google_compute_default_service_account.default.email}"
}
}
}
`, context)
}

func testAccCheckCloudSchedulerJobDestroy(s *terraform.State) error {
for name, rs := range s.RootModule().Resources {
if rs.Type != "google_cloud_scheduler_job" {
Expand Down
Loading