Skip to content

Commit a744ca1

Browse files
kautikdkDawid212
authored andcommitted
Add storage_project_management_hub resource. (GoogleCloudPlatform#12689)
1 parent aa3cd61 commit a744ca1

10 files changed

+687
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# Copyright 2025 Google Inc.
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
---
15+
# API resource name
16+
name: 'ProjectIntelligenceConfig'
17+
kind: 'storagecontrol#intelligenceconfig'
18+
# Resource description for the provider documentation.
19+
description: |
20+
The Project Storage Intelligence Config resource represents GCS Storage Intelligence operating on individual GCP project. Storage Intelligence Config is a singleton resource and individual instance exists on each GCP project.
21+
22+
Storage Intelligence is for Storage Admins to manage GCP storage assets at scale for performance, cost, security & compliance.
23+
24+
docs:
25+
warning: |
26+
Storage Intelligence Config is a singleton resource which cannot be created or deleted. A single instance of Storage Intelligence Config exist for each GCP Project. Terraform does not create or destroy this resource.
27+
Terraform resource creation for this resource is simply an update operation on existing resource with specified properties. Terraform deletion won't have any effect on this resource rather it will only remove it from the state file.
28+
29+
# URL for the resource's standard Get method. https://google.aip.dev/131
30+
self_link: 'projects/{{name}}/locations/global/intelligenceConfig'
31+
32+
custom_code:
33+
custom_create: 'templates/terraform/custom_create/storage_control_project_intelligence.go.tmpl'
34+
constants: 'templates/terraform/constants/storage_control_intelligence.go.tmpl'
35+
36+
# The HTTP verb used to update a resource. Allowed values: :POST, :PUT, :PATCH. Default: :PUT.
37+
update_verb: 'PATCH'
38+
# If true, the resource sets an `updateMask` query parameter listing modified
39+
# fields when updating the resource. If false, it does not.
40+
update_mask: true
41+
42+
exclude_delete: true
43+
44+
import_format:
45+
- 'projects/{{name}}/locations/global/intelligenceConfig'
46+
47+
# If true, code for handling long-running operations is generated along with
48+
# the resource. If false, that code is not generated.
49+
autogen_async: false
50+
51+
properties:
52+
- name: 'name'
53+
type: String
54+
required: true
55+
immutable: true
56+
url_param_only: true
57+
description: |
58+
Identifier of the GCP project. For GCP project, this field can be project name or project number.
59+
- name: 'editionConfig'
60+
type: String
61+
required: false
62+
default_from_api: true
63+
description: |
64+
Edition configuration of the Storage Intelligence resource. Valid values are INHERIT, DISABLED and STANDARD.
65+
- name: 'updateTime'
66+
type: String
67+
output: true
68+
description: |
69+
The time at which the Storage Intelligence Config resource is last updated.
70+
- name: 'filter'
71+
type: NestedObject
72+
diff_suppress_func: 'intelligenceFilterDiffSuppress'
73+
description: |
74+
Filter over location and bucket using include or exclude semantics. Resources that match the include or exclude filter are exclusively included or excluded from the Storage Intelligence plan.
75+
properties:
76+
- name: excludedCloudStorageBuckets
77+
type: NestedObject
78+
required: false
79+
description: |
80+
Buckets to exclude from the Storage Intelligence plan.
81+
conflicts:
82+
- 'filter.0.included_cloud_storage_buckets'
83+
at_least_one_of:
84+
- 'filter.0.included_cloud_storage_buckets'
85+
- 'filter.0.excluded_cloud_storage_buckets'
86+
- 'filter.0.included_cloud_storage_locations'
87+
- 'filter.0.excluded_cloud_storage_locations'
88+
diff_suppress_func: 'intelligenceFilterExcludedCloudStorageBucketsDiffSuppress'
89+
properties:
90+
- name: bucketIdRegexes
91+
required: true
92+
type: Array
93+
send_empty_value: true
94+
item_type:
95+
type: String
96+
description: |
97+
List of bucket id regexes to exclude in the storage intelligence plan.
98+
- name: includedCloudStorageBuckets
99+
type: NestedObject
100+
required: false
101+
description: |
102+
Buckets to include in the Storage Intelligence plan.
103+
conflicts:
104+
- 'filter.0.excluded_cloud_storage_buckets'
105+
at_least_one_of:
106+
- 'filter.0.included_cloud_storage_buckets'
107+
- 'filter.0.excluded_cloud_storage_buckets'
108+
- 'filter.0.included_cloud_storage_locations'
109+
- 'filter.0.excluded_cloud_storage_locations'
110+
diff_suppress_func: 'intelligenceFilterincludedCloudStorageBucketsDiffSuppress'
111+
properties:
112+
- name: bucketIdRegexes
113+
required: true
114+
send_empty_value: true
115+
type: Array
116+
item_type:
117+
type: String
118+
description: |
119+
List of bucket id regexes to exclude in the storage intelligence plan.
120+
- name: excludedCloudStorageLocations
121+
type: NestedObject
122+
required: false
123+
description: |
124+
Locations to exclude from the Storage Intelligence plan.
125+
conflicts:
126+
- 'filter.0.included_cloud_storage_locations'
127+
at_least_one_of:
128+
- 'filter.0.included_cloud_storage_buckets'
129+
- 'filter.0.excluded_cloud_storage_buckets'
130+
- 'filter.0.included_cloud_storage_locations'
131+
- 'filter.0.excluded_cloud_storage_locations'
132+
diff_suppress_func: 'intelligenceFilterExcludedCloudStorageLocationsDiffSuppress'
133+
properties:
134+
- name: locations
135+
type: Array
136+
required: true
137+
send_empty_value: true
138+
description: |
139+
List of locations.
140+
item_type:
141+
type: String
142+
- name: includedCloudStorageLocations
143+
type: NestedObject
144+
required: false
145+
description: |
146+
Locations to include in the Storage Intelligence plan.
147+
conflicts:
148+
- 'filter.0.excluded_cloud_storage_locations'
149+
at_least_one_of:
150+
- 'filter.0.included_cloud_storage_buckets'
151+
- 'filter.0.excluded_cloud_storage_buckets'
152+
- 'filter.0.included_cloud_storage_locations'
153+
- 'filter.0.excluded_cloud_storage_locations'
154+
diff_suppress_func: 'intelligenceFilterincludedCloudStorageLocationsDiffSuppress'
155+
properties:
156+
- name: locations
157+
type: Array
158+
required: true
159+
send_empty_value: true
160+
description: |
161+
List of locations.
162+
item_type:
163+
type: String
164+
- name: 'effectiveIntelligenceConfig'
165+
output: true
166+
description: |
167+
The Intelligence config that is effective for the resource.
168+
type: NestedObject
169+
properties:
170+
- name: intelligenceConfig
171+
type: String
172+
output: true
173+
description: |
174+
The Intelligence config resource that is applied for the target resource.
175+
- name: effectiveEdition
176+
type: String
177+
output: true
178+
description: |
179+
The `StorageIntelligence` edition that is applicable for the resource.
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright 2025 Google Inc.
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
---
15+
name: 'StorageControl'
16+
display_name: 'Cloud Storage Control'
17+
versions:
18+
- name: 'ga'
19+
base_url: 'https://storage.googleapis.com/v2/'
20+
scopes:
21+
- 'https://www.googleapis.com/auth/devstorage.full_control'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// API returns empty objects for nested empty lists so this behavior is
2+
// generating unnecessary diff. The below four functions mitigates that diff for
3+
// each individual filter fields.
4+
func intelligenceFilterExcludedCloudStorageLocationsDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
5+
if new == "1" && old == "0" {
6+
if v, ok := d.GetOkExists("filter.0.excluded_cloud_storage_locations.0.locations"); ok {
7+
l := v.([]interface{})
8+
if len(l) == 0 {
9+
return true
10+
}
11+
}
12+
}
13+
return false
14+
}
15+
16+
func intelligenceFilterExcludedCloudStorageBucketsDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
17+
if new == "1" && old == "0" {
18+
if v, ok := d.GetOkExists("filter.0.excluded_cloud_storage_buckets.0.bucket_id_regexes"); ok {
19+
l := v.([]interface{})
20+
if len(l) == 0 {
21+
return true
22+
}
23+
}
24+
}
25+
return false
26+
}
27+
28+
func intelligenceFilterincludedCloudStorageLocationsDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
29+
if new == "1" && old == "0" {
30+
if v, ok := d.GetOkExists("filter.0.included_cloud_storage_locations.0.locations"); ok {
31+
l := v.([]interface{})
32+
if len(l) == 0 {
33+
return true
34+
}
35+
}
36+
}
37+
return false
38+
}
39+
40+
41+
func intelligenceFilterincludedCloudStorageBucketsDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
42+
if new == "1" && old == "0" {
43+
if v, ok := d.GetOkExists("filter.0.included_cloud_storage_buckets.0.bucket_id_regexes"); ok {
44+
l := v.([]interface{})
45+
if len(l) == 0 {
46+
return true
47+
}
48+
}
49+
}
50+
return false
51+
}
52+
53+
// This is required to mitigate a diff generated by nested Diff Suppressions.
54+
// AtLeastOneOf prevents empty `filter` object but the nested diff suppressions
55+
// of suppressing empty list's diff can generate unnecessary empty `filter`
56+
// object.
57+
func intelligenceFilterDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
58+
if new == "1" && old == "0" {
59+
empty := true
60+
if _, ok := d.GetOkExists("filter.0.included_cloud_storage_buckets"); ok {
61+
if v, ok := d.GetOkExists("filter.0.included_cloud_storage_buckets.0.bucket_id_regexes"); ok {
62+
l := v.([]interface{})
63+
if len(l) != 0 {
64+
empty = false
65+
}
66+
}
67+
}
68+
if _, ok := d.GetOkExists("filter.0.excluded_cloud_storage_buckets"); ok {
69+
if v, ok := d.GetOkExists("filter.0.excluded_cloud_storage_buckets.0.bucket_id_regexes"); ok {
70+
l := v.([]interface{})
71+
if len(l) != 0 {
72+
empty = false
73+
}
74+
}
75+
}
76+
if _, ok := d.GetOkExists("filter.0.included_cloud_storage_locations"); ok {
77+
if v, ok := d.GetOkExists("filter.0.included_cloud_storage_locations.0.locations"); ok {
78+
l := v.([]interface{})
79+
if len(l) != 0 {
80+
empty = false
81+
}
82+
}
83+
}
84+
if _, ok := d.GetOkExists("filter.0.excluded_cloud_storage_locations"); ok {
85+
if v, ok := d.GetOkExists("filter.0.excluded_cloud_storage_locations.0.locations"); ok {
86+
l := v.([]interface{})
87+
if len(l) != 0 {
88+
empty = false
89+
}
90+
}
91+
}
92+
if empty {
93+
return true
94+
}
95+
}
96+
return false
97+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
2+
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
3+
if err != nil {
4+
return err
5+
}
6+
7+
obj := make(map[string]interface{})
8+
editionConfigProp, err := expandStorageControlProjectIntelligenceConfigEditionConfig(d.Get("edition_config"), d, config)
9+
if err != nil {
10+
return err
11+
} else if v, ok := d.GetOkExists("edition_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(editionConfigProp)) && (ok || !reflect.DeepEqual(v, editionConfigProp)) {
12+
obj["editionConfig"] = editionConfigProp
13+
}
14+
filterProp, err := expandStorageControlProjectIntelligenceConfigFilter(d.Get("filter"), d, config)
15+
if err != nil {
16+
return err
17+
} else if v, ok := d.GetOkExists("filter"); !tpgresource.IsEmptyValue(reflect.ValueOf(filterProp)) && (ok || !reflect.DeepEqual(v, filterProp)) {
18+
obj["filter"] = filterProp
19+
}
20+
21+
url, err := tpgresource.ReplaceVars(d, config, "{{"{{"}}StorageControlBasePath{{"}}"}}projects/{{"{{"}}name{{"}}"}}/locations/global/intelligenceConfig")
22+
if err != nil {
23+
return err
24+
}
25+
26+
log.Printf("[DEBUG] Patching IntelligenceConfig: %#v", obj)
27+
billingProject := ""
28+
29+
// err == nil indicates that the billing_project value was found
30+
if bp, err := tpgresource.GetBillingProject(d, config); err == nil {
31+
billingProject = bp
32+
}
33+
34+
headers := make(http.Header)
35+
updateMask := []string{"filter"}
36+
37+
if d.HasChange("edition_config") {
38+
updateMask = append(updateMask, "editionConfig")
39+
}
40+
// updateMask is a URL parameter but not present in the schema, so ReplaceVars
41+
// won't set it
42+
url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")})
43+
if err != nil {
44+
return err
45+
}
46+
47+
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
48+
Config: config,
49+
Method: "PATCH",
50+
Project: billingProject,
51+
RawURL: url,
52+
UserAgent: userAgent,
53+
Body: obj,
54+
Timeout: d.Timeout(schema.TimeoutCreate),
55+
Headers: headers,
56+
})
57+
if err != nil {
58+
return fmt.Errorf("Error patching IntelligenceConfig: %s", err)
59+
}
60+
61+
// Store the ID now
62+
id, err := tpgresource.ReplaceVars(d, config, "projects/{{"{{"}}name{{"}}"}}/locations/global/intelligenceConfig")
63+
if err != nil {
64+
return fmt.Errorf("Error constructing id: %s", err)
65+
}
66+
d.SetId(id)
67+
68+
log.Printf("[DEBUG] Finished patching intelligence config %q: %#v", d.Id(), res)
69+
70+
return resourceStorageControlProjectIntelligenceConfigRead(d, meta)

mmv1/third_party/terraform/.teamcity/components/inputs/services_beta.kt

+5
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,11 @@ var ServicesListBeta = mapOf(
756756
"displayName" to "Storage",
757757
"path" to "./google-beta/services/storage"
758758
),
759+
"storagecontrol" to mapOf(
760+
"name" to "storagecontrol",
761+
"displayName" to "Storagecontrol",
762+
"path" to "./google-beta/services/storagecontrol"
763+
),
759764
"storageinsights" to mapOf(
760765
"name" to "storageinsights",
761766
"displayName" to "Storageinsights",

mmv1/third_party/terraform/.teamcity/components/inputs/services_ga.kt

+5
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,11 @@ var ServicesListGa = mapOf(
751751
"displayName" to "Storage",
752752
"path" to "./google/services/storage"
753753
),
754+
"storagecontrol" to mapOf(
755+
"name" to "storagecontrol",
756+
"displayName" to "Storagecontrol",
757+
"path" to "./google/services/storagecontrol"
758+
),
754759
"storageinsights" to mapOf(
755760
"name" to "storageinsights",
756761
"displayName" to "Storageinsights",

0 commit comments

Comments
 (0)