Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ var handwrittenResources = map[string]*schema.Resource{
"google_folder_organization_policy": resourcemanager.ResourceGoogleFolderOrganizationPolicy(),
{{- if ne $.TargetVersionName "ga" }}
"google_folder_service_identity": resourcemanager.ResourceFolderServiceIdentity(),
"google_organization_service_identity": resourcemanager.ResourceOrganizationServiceIdentity(),
{{- end }}
"google_logging_billing_account_sink": logging.ResourceLoggingBillingAccountSink(),
"google_logging_billing_account_exclusion": logging.ResourceLoggingExclusion(logging.BillingAccountLoggingExclusionSchema, logging.NewBillingAccountLoggingExclusionUpdater, logging.BillingAccountLoggingExclusionIdParseFunc),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
{{- if ne $.TargetVersionName "ga" -}}
package resourcemanager

import (
"fmt"
"log"
"time"

"github.com/hashicorp/terraform-provider-google/google/services/serviceusage"
"github.com/hashicorp/terraform-provider-google/google/tpgresource"
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func ResourceOrganizationServiceIdentity() *schema.Resource {
return &schema.Resource{
Create: resourceOrganizationServiceIdentityCreate,
Read: resourceOrganizationServiceIdentityRead,
Delete: resourceOrganizationServiceIdentityDelete,

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(20 * time.Minute),
Read: schema.DefaultTimeout(10 * time.Minute),
Delete: schema.DefaultTimeout(20 * time.Minute),
},

CustomizeDiff: customdiff.All(
tpgresource.DefaultProviderProject,
),

Schema: map[string]*schema.Schema{
"service": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"organization": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"email": {
Type: schema.TypeString,
Computed: true,
},
"member": {
Type: schema.TypeString,
Computed: true,
Description: `The Identity of the Google managed service account in the form 'serviceAccount:{email}'. This value is often used to refer to the service account in order to grant IAM permissions.`,
},
},
UseJSONNumber: true,
}
}

func resourceOrganizationServiceIdentityCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*transport_tpg.Config)
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
if err != nil {
return err
}

url, err := tpgresource.ReplaceVars(d, config, "{{"{{"}}ServiceUsageBasePath{{"}}"}}organizations/{{"{{"}}organization{{"}}"}}/services/{{"{{"}}service{{"}}"}}:generateServiceIdentity")
if err != nil {
return err
}

billingProject := ""

// err == nil indicates that the billing_project value was found
if bp, err := tpgresource.GetBillingProject(d, config); err == nil {
billingProject = bp
}
if err != nil {
return err
}

res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
Config: config,
Method: "POST",
Project: billingProject,
RawURL: url,
UserAgent: userAgent,
Timeout: d.Timeout(schema.TimeoutCreate),
})
if err != nil {
return fmt.Errorf("Error creating Organization Service Identity: %s", err)
}

var opRes map[string]interface{}
err = serviceusage.ServiceUsageOperationWaitTimeWithResponse(
config, res, &opRes, billingProject, "Creating Organization Service Identity", userAgent,
d.Timeout(schema.TimeoutCreate))
if err != nil {
return err
}

log.Printf("[DEBUG] Finished creating Organization Service Identity %q: %#v", d.Id(), res)

id, err := tpgresource.ReplaceVars(d, config, "organizations/{{"{{"}}organization{{"}}"}}/services/{{"{{"}}service{{"}}"}}")
if err != nil {
return fmt.Errorf("Error constructing id: %s", err)
}
d.SetId(id)

// This API may not return the service identity's details, even if the relevant
// Google API is configured for service identities.
if emailVal, ok := opRes["email"]; ok {
email, ok := emailVal.(string)
if !ok {
return fmt.Errorf("unexpected type for email: got %T, want string", email)
}
if err := d.Set("email", email); err != nil {
return fmt.Errorf("Error setting email: %s", err)
}
if err := d.Set("member", "serviceAccount:"+email); err != nil {
return fmt.Errorf("Error setting member: %s", err)
}
}
return nil
}

// There is no read endpoint for this API.
func resourceOrganizationServiceIdentityRead(d *schema.ResourceData, meta interface{}) error {
return nil
}

// There is no delete endpoint for this API.
func resourceOrganizationServiceIdentityDelete(d *schema.ResourceData, meta interface{}) error {
return nil
}
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{{ if ne $.TargetVersionName "ga" -}}
resource: 'google_organization_service_identity'
generation_type: 'handwritten'
api_service_name: 'serviceusage.googleapis.com'
api_version: 'v1'
api_resource_type_kind: 'Service'
fields:
- field: 'email'
- field: 'member'
- field: 'organization'
- field: 'service'
{{ end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{{- if ne $.TargetVersionName "ga" -}}
package resourcemanager_test

import (
"fmt"
"strings"
"testing"
"github.com/hashicorp/terraform-provider-google/google/acctest"
"github.com/hashicorp/terraform-provider-google/google/envvar"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)

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

context := map[string]interface{}{
"org_id": envvar.GetTestOrgFromEnv(t),
"random_suffix ": acctest.RandString(t, 5),
}

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
Steps: []resource.TestStep{
{
Config: testGoogleOrganizationServiceIdentity_basic(context),
Check: resource.ComposeTestCheckFunc(
// Email field should be non-empty and contain at least an "@".
resource.TestCheckResourceAttrWith("google_organization_service_identity.osconfig_sa", "email", func(value string) error {
if strings.Contains(value, "@") {
return nil
}
return fmt.Errorf("osconfig_sa service identity email value was %s, expected a valid email", value)
}),
// Member field should start with "serviceAccount:"
resource.TestCheckResourceAttrWith("google_organization_service_identity.osconfig_sa", "member", func(value string) error {
if !strings.HasPrefix(value, "serviceAccount:") {
return fmt.Errorf("osconfig_sa organization service identity member value %q does not start with 'serviceAccount:'", value)
}
return nil
}),
),
},
},
})
}

func testGoogleOrganizationServiceIdentity_basic(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_organization_service_identity" "osconfig_sa" {
organization = "%{org_id}"
service = "osconfig.googleapis.com"
}
`, context)
}
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
subcategory: "Cloud Platform"
description: |-
Generate organization service identity for a service.
---

# google_organization_service_identity

Generate organization service identity for a service.

~> **Warning:** This resource is in beta, and should be used with the terraform-provider-google-beta provider.
See [Provider Versions](../guides/provider_versions.html.markdown) for more details on beta resources.

~> **Note:** Once created, this resource cannot be updated or destroyed. These
actions are a no-op.

~> **Note:** This resource can be used to retrieve the emails of the [Google-managed organization service accounts](https://cloud.google.com/iam/docs/service-agents)
of the APIs that Google has configured with a Service Identity. You can run `gcloud beta services identity create --service SERVICE_NAME.googleapis.com --organization ORGANIZATION` to
verify if an API supports this.

To get more information about Service Identity, see:

* [API documentation](https://cloud.google.com/service-usage/docs/reference/rest/v1beta1/services/generateServiceIdentity)

## Example Usage - Organization Service Identity Basic

```hcl
resource "google_organization_service_identity" "osconfig_sa" {
provider = google-beta
organization = "123456789"
service = "osconfig.googleapis.com"
}

resource "google_organization_iam_member" "admin" {
org_id = "123456789"
role = "roles/osconfig.serviceAgent"
member = google_organization_service_identity.osconfig_sa.member
}
```

## Argument Reference

The following arguments are supported:

* `service` -
(Required)
The service to generate identity for.

- - -

* `organization` - (Required) The organization in which the resource belongs.

## Attributes Reference

In addition to the arguments listed above, the following computed attributes are exported:

* `email` - The email address of the Google managed service account.
* `member` - The Identity of the Google managed service account in the form 'serviceAccount:{email}'. This value is often used to refer to the service account in order to grant IAM permissions.

## Import

This resource does not support import.

## Timeouts

This resource provides the following
[Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: configuration options:

* `create` - Default is 20 minutes.
Loading