Skip to content

Commit

Permalink
Add support for oauth and oidc tokens to cloud_scheduler_job
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <[email protected]>
  • Loading branch information
megan07 authored and modular-magician committed Aug 14, 2019
1 parent d120333 commit bbaa23f
Show file tree
Hide file tree
Showing 4 changed files with 411 additions and 1 deletion.
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

0 comments on commit bbaa23f

Please sign in to comment.