forked from GoogleCloudPlatform/magic-modules
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for GCS managed folders (GoogleCloudPlatform#10786)
Co-authored-by: Stephen Lewis (Burrows) <stephen.r.burrows@gmail.com>
- Loading branch information
1 parent
1b36b93
commit 142d5df
Showing
7 changed files
with
1,137 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
# Copyright 2024 Google Inc. | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
--- !ruby/object:Api::Resource | ||
name: 'ManagedFolder' | ||
kind: 'storage#managedFolder' | ||
base_url: 'b/{{bucket}}/managedFolders' | ||
self_link: 'b/{{bucket}}/managedFolders/{{%name}}' | ||
id_format: '{{bucket}}/{{name}}' | ||
delete_url: 'b/{{bucket}}/managedFolders/{{%name}}' | ||
has_self_link: true | ||
immutable: true | ||
skip_sweeper: true # Skipping sweeper since this is a child resource. | ||
description: | | ||
A Google Cloud Storage Managed Folder. | ||
You can apply Identity and Access Management (IAM) policies to | ||
managed folders to grant principals access only to the objects | ||
within the managed folder, which lets you more finely control access | ||
for specific data sets and tables within a bucket. You can nest | ||
managed folders up to 15 levels deep, including the parent managed | ||
folder. | ||
Managed folders can only be created in buckets that have uniform | ||
bucket-level access enabled. | ||
references: !ruby/object:Api::Resource::ReferenceLinks | ||
guides: | ||
'Official Documentation': 'https://cloud.google.com/storage/docs/managed-folders' | ||
api: 'https://cloud.google.com/storage/docs/json_api/v1/managedFolder' | ||
# iam_policy: handwritten in mmv1/third_party/terraform/services/storage/iam_storage_managed_folder.go | ||
import_format: | ||
- '{{bucket}}/managedFolders/{{%name}}' | ||
- '{{bucket}}/{{%name}}' | ||
examples: | ||
- !ruby/object:Provider::Terraform::Examples | ||
name: 'storage_managed_folder_basic' | ||
primary_resource_id: 'folder' | ||
vars: | ||
bucket_name: 'my-bucket' | ||
parameters: | ||
- !ruby/object:Api::Type::ResourceRef | ||
name: 'bucket' | ||
resource: 'Bucket' | ||
imports: 'name' | ||
description: 'The name of the bucket that contains the managed folder.' | ||
required: true | ||
- !ruby/object:Api::Type::String | ||
name: 'name' | ||
description: | | ||
The name of the managed folder expressed as a path. Must include | ||
trailing '/'. For example, `example_dir/example_dir2/`. | ||
required: true | ||
# The API returns values with trailing slashes, even if not | ||
# provided. Enforcing trailing slashes prevents diffs and ensures | ||
# consistent output. | ||
validation: !ruby/object:Provider::Terraform::Validation | ||
regex: '/$' | ||
properties: | ||
- !ruby/object:Api::Type::String | ||
name: createTime | ||
description: | | ||
The timestamp at which this managed folder was created. | ||
output: true | ||
- !ruby/object:Api::Type::String | ||
name: updateTime | ||
description: | | ||
The timestamp at which this managed folder was most recently updated. | ||
output: true | ||
- !ruby/object:Api::Type::String | ||
name: metageneration | ||
description: | | ||
The metadata generation of the managed folder. | ||
output: true |
10 changes: 10 additions & 0 deletions
10
mmv1/templates/terraform/examples/storage_managed_folder_basic.tf.erb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
resource "google_storage_bucket" "bucket" { | ||
name = "<%= ctx[:vars]['bucket_name'] %>" | ||
location = "EU" | ||
uniform_bucket_level_access = true | ||
} | ||
|
||
resource "google_storage_managed_folder" "<%= ctx[:primary_resource_id] %>" { | ||
bucket = google_storage_bucket.bucket.name | ||
name = "managed/folder/name/" | ||
} |
2 changes: 2 additions & 0 deletions
2
mmv1/templates/terraform/iam/example_config_body/storage_managed_folder.tf.erb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
bucket = google_storage_managed_folder.folder.bucket | ||
managed_folder = google_storage_managed_folder.folder.name |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
184 changes: 184 additions & 0 deletions
184
mmv1/third_party/terraform/services/storage/iam_storage_managed_folder.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
package storage | ||
|
||
import ( | ||
"fmt" | ||
"net/url" | ||
|
||
"github.com/hashicorp/errwrap" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
"google.golang.org/api/cloudresourcemanager/v1" | ||
|
||
"github.com/hashicorp/terraform-provider-google/google/tpgiamresource" | ||
"github.com/hashicorp/terraform-provider-google/google/tpgresource" | ||
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" | ||
"github.com/hashicorp/terraform-provider-google/google/verify" | ||
) | ||
|
||
var StorageManagedFolderIamSchema = map[string]*schema.Schema{ | ||
"bucket": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
"managed_folder": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, | ||
ValidateFunc: verify.ValidateRegexp(`/$`), | ||
}, | ||
} | ||
|
||
type StorageManagedFolderIamUpdater struct { | ||
bucket string | ||
managedFolder string | ||
d tpgresource.TerraformResourceData | ||
Config *transport_tpg.Config | ||
} | ||
|
||
func StorageManagedFolderIamUpdaterProducer(d tpgresource.TerraformResourceData, config *transport_tpg.Config) (tpgiamresource.ResourceIamUpdater, error) { | ||
values := make(map[string]string) | ||
|
||
if v, ok := d.GetOk("bucket"); ok { | ||
values["bucket"] = v.(string) | ||
} | ||
|
||
if v, ok := d.GetOk("managed_folder"); ok { | ||
values["managed_folder"] = v.(string) | ||
} | ||
|
||
u := &StorageManagedFolderIamUpdater{ | ||
bucket: values["bucket"], | ||
managedFolder: values["managed_folder"], | ||
d: d, | ||
Config: config, | ||
} | ||
|
||
if err := d.Set("bucket", u.bucket); err != nil { | ||
return nil, fmt.Errorf("Error setting bucket: %s", err) | ||
} | ||
if err := d.Set("managed_folder", u.managedFolder); err != nil { | ||
return nil, fmt.Errorf("Error setting managed_folder: %s", err) | ||
} | ||
|
||
return u, nil | ||
} | ||
|
||
func StorageManagedFolderIdParseFunc(d *schema.ResourceData, config *transport_tpg.Config) error { | ||
values := make(map[string]string) | ||
|
||
m, err := tpgresource.GetImportIdQualifiers([]string{"(?P<bucket>[^/]+)/managedFolders/(?P<managed_folder>.+)", "(?P<bucket>[^/]+)/(?P<managed_folder>.+)"}, d, config, d.Id()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
for k, v := range m { | ||
values[k] = v | ||
} | ||
|
||
u := &StorageManagedFolderIamUpdater{ | ||
bucket: values["bucket"], | ||
managedFolder: values["managed_folder"], | ||
d: d, | ||
Config: config, | ||
} | ||
if err := d.Set("bucket", u.bucket); err != nil { | ||
return fmt.Errorf("Error setting bucket: %s", err) | ||
} | ||
if err := d.Set("managed_folder", u.managedFolder); err != nil { | ||
return fmt.Errorf("Error setting managed_folder: %s", err) | ||
} | ||
d.SetId(u.GetResourceId()) | ||
return nil | ||
} | ||
|
||
func (u *StorageManagedFolderIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) { | ||
url, err := u.qualifyManagedFolderUrl("iam") | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var obj map[string]interface{} | ||
url, err = transport_tpg.AddQueryParams(url, map[string]string{"optionsRequestedPolicyVersion": fmt.Sprintf("%d", tpgiamresource.IamPolicyVersion)}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
userAgent, err := tpgresource.GenerateUserAgentString(u.d, u.Config.UserAgent) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
policy, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ | ||
Config: u.Config, | ||
Method: "GET", | ||
RawURL: url, | ||
UserAgent: userAgent, | ||
Body: obj, | ||
}) | ||
if err != nil { | ||
return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) | ||
} | ||
|
||
out := &cloudresourcemanager.Policy{} | ||
err = tpgresource.Convert(policy, out) | ||
if err != nil { | ||
return nil, errwrap.Wrapf("Cannot convert a policy to a resource manager policy: {{err}}", err) | ||
} | ||
|
||
return out, nil | ||
} | ||
|
||
func (u *StorageManagedFolderIamUpdater) SetResourceIamPolicy(policy *cloudresourcemanager.Policy) error { | ||
json, err := tpgresource.ConvertToMap(policy) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
obj := json | ||
|
||
url, err := u.qualifyManagedFolderUrl("iam") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
userAgent, err := tpgresource.GenerateUserAgentString(u.d, u.Config.UserAgent) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ | ||
Config: u.Config, | ||
Method: "PUT", | ||
RawURL: url, | ||
UserAgent: userAgent, | ||
Body: obj, | ||
Timeout: u.d.Timeout(schema.TimeoutCreate), | ||
}) | ||
if err != nil { | ||
return errwrap.Wrapf(fmt.Sprintf("Error setting IAM policy for %s: {{err}}", u.DescribeResource()), err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (u *StorageManagedFolderIamUpdater) qualifyManagedFolderUrl(methodIdentifier string) (string, error) { | ||
urlTemplate := fmt.Sprintf("{{StorageBasePath}}b/%s/managedFolders/%s/%s", u.bucket, url.PathEscape(u.managedFolder), methodIdentifier) | ||
url, err := tpgresource.ReplaceVars(u.d, u.Config, urlTemplate) | ||
if err != nil { | ||
return "", err | ||
} | ||
return url, nil | ||
} | ||
|
||
func (u *StorageManagedFolderIamUpdater) GetResourceId() string { | ||
return fmt.Sprintf("b/%s/managedFolders/%s", u.bucket, u.managedFolder) | ||
} | ||
|
||
func (u *StorageManagedFolderIamUpdater) GetMutexKey() string { | ||
return fmt.Sprintf("iam-storage-managedfolder-%s", u.GetResourceId()) | ||
} | ||
|
||
func (u *StorageManagedFolderIamUpdater) DescribeResource() string { | ||
return fmt.Sprintf("storage managedfolder %q", u.GetResourceId()) | ||
} |
Oops, something went wrong.