Skip to content

Commit 0fa0689

Browse files
feat: Add support for creating folders in buckets with folders variable (#59)
1 parent 840eb79 commit 0fa0689

File tree

8 files changed

+39
-0
lines changed

8 files changed

+39
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Functional examples are included in the
5353
| bucket\_viewers | Map of lowercase unprefixed name => comma-delimited IAM-style bucket viewers. | map | `<map>` | no |
5454
| creators | IAM-style members who will be granted roles/storage.objectCreators on all buckets. | list(string) | `<list>` | no |
5555
| encryption\_key\_names | Optional map of lowercase unprefixed name => string, empty strings are ignored. | map | `<map>` | no |
56+
| folders | Map of lowercase unprefixed name => list of top level folder objects. | map | `<map>` | no |
5657
| force\_destroy | Optional map of lowercase unprefixed name => boolean, defaults to false. | map | `<map>` | no |
5758
| labels | Labels to be attached to the buckets | map | `<map>` | no |
5859
| lifecycle\_rules | List of lifecycle rules to configure. Format is the same as described in provider documentation https://www.terraform.io/docs/providers/google/r/storage_bucket.html#lifecycle_rule except condition.matches_storage_class should be a comma delimited string. | object | `<list>` | no |

examples/multiple_buckets/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This example illustrates how to use the `cloud-storage` module.
88
| Name | Description | Type | Default | Required |
99
|------|-------------|:----:|:-----:|:-----:|
1010
| bucket\_policy\_only | Disable ad-hoc ACLs on specified buckets. Defaults to true. Map of lowercase unprefixed name => boolean | map(string) | n/a | yes |
11+
| folders | Top level bucket folders. Map of lowercase unprefixed name => list of folders to create. | map | n/a | yes |
1112
| names | Names of the buckets to create. | list(string) | n/a | yes |
1213
| prefix | Prefix used to generate bueckt names. | string | n/a | yes |
1314
| project\_id | The ID of the project in which to provision resources. | string | n/a | yes |

examples/multiple_buckets/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ module "cloud_storage" {
2424
prefix = var.prefix
2525
names = var.names
2626
bucket_policy_only = var.bucket_policy_only
27+
folders = var.folders
2728

2829
lifecycle_rules = [{
2930
action = {

examples/multiple_buckets/variables.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,8 @@ variable "bucket_policy_only" {
3333
description = "Disable ad-hoc ACLs on specified buckets. Defaults to true. Map of lowercase unprefixed name => boolean"
3434
type = map(string)
3535
}
36+
37+
variable "folders" {
38+
description = "Top level bucket folders. Map of lowercase unprefixed name => list of folders to create."
39+
type = map
40+
}

main.tf

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@
1616

1717
locals {
1818
prefix = var.prefix == "" ? "" : join("-", list(var.prefix, lower(var.location), ""))
19+
folder_list = flatten([
20+
for bucket, folders in var.folders : [
21+
for folder in folders : {
22+
bucket = bucket,
23+
folder = folder
24+
}
25+
]
26+
])
1927
}
2028

2129
resource "google_storage_bucket" "buckets" {
@@ -123,3 +131,10 @@ resource "google_storage_bucket_iam_binding" "viewers" {
123131
),
124132
)
125133
}
134+
135+
resource "google_storage_bucket_object" "folders" {
136+
for_each = { for obj in local.folder_list : "${obj.bucket}_${obj.folder}" => obj }
137+
bucket = element(google_storage_bucket.buckets.*.name, index(var.names, each.value.bucket))
138+
name = "${each.value.folder}/" # Declaring an object with a trailing '/' creates a directory
139+
content = "foo" # Note that the content string isn't actually used, but is only there since the resource requires it
140+
}

test/fixtures/multiple_buckets/main.tf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ module "example" {
2929
project_id = var.project_id
3030
prefix = "multiple-buckets-${random_string.prefix.result}"
3131
names = ["one", "two"]
32+
folders = {
33+
"two" = ["dev", "prod"]
34+
}
3235

3336
bucket_policy_only = {
3437
"one" = true

test/integration/multiple_buckets/controls/gsutil.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@
2424
its(:stdout) { should include attribute('names').values[1] }
2525
end
2626

27+
describe command("gsutil ls gs://#{attribute("names_list")[1]}") do
28+
its(:exit_status) { should eq 0 }
29+
its(:stderr) { should eq "" }
30+
its(:stdout) { should include "gs://#{attribute("names_list")[1]}/dev/" }
31+
its(:stdout) { should include "gs://#{attribute("names_list")[1]}/prod/" }
32+
end
33+
2734
describe command("gsutil bucketpolicyonly get gs://#{attribute("names_list")[0]}") do
2835
its(:exit_status) { should eq 0 }
2936
its(:stderr) { should eq "" }

variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ variable "labels" {
107107
default = {}
108108
}
109109

110+
variable "folders" {
111+
description = "Map of lowercase unprefixed name => list of top level folder objects."
112+
type = map
113+
default = {}
114+
}
115+
110116
# we need flags to allow member lists to contain dynamic elements
111117

112118
variable "set_admin_roles" {

0 commit comments

Comments
 (0)