@@ -18,6 +18,13 @@ import (
18
18
"go.uber.org/zap"
19
19
)
20
20
21
+ const (
22
+ projectPrefix = "projects/"
23
+ folderPrefix = "folders/"
24
+ orgPrefix = "organizations/"
25
+ unknownOrg = orgPrefix + "unknown"
26
+ )
27
+
21
28
// AncestryManager is the interface that fetch ancestors for a resource.
22
29
type AncestryManager interface {
23
30
// Ancestors returns a list of ancestors.
@@ -73,8 +80,11 @@ func (m *manager) initAncestryCache(entries map[string]string) error {
73
80
if err != nil {
74
81
return err
75
82
}
76
- // ancestry path should include the item itself
77
- if ancestors [0 ] != key {
83
+ // The ancestry path should include the item itself, unless both the key and ancestor
84
+ // have the projects/ prefix, indicating the key is a project ID and the ancestry is
85
+ // project number. CAI ancestors use the project number, so that is preferred if it
86
+ // is available.
87
+ if ancestors [0 ] != key && ! (strings .HasPrefix (key , projectPrefix ) && strings .HasPrefix (ancestors [0 ], projectPrefix )) {
78
88
ancestors = append ([]string {key }, ancestors ... )
79
89
}
80
90
m .store (key , ancestors )
@@ -88,7 +98,7 @@ func parseAncestryKey(val string) (string, error) {
88
98
ix := strings .LastIndex (key , "/" )
89
99
if ix == - 1 {
90
100
// If not containing /, then treat it as a project.
91
- return fmt . Sprintf ( "projects/%s" , key ) , nil
101
+ return projectPrefix + key , nil
92
102
} else {
93
103
k := key [:ix ]
94
104
if k == "projects" || k == "folders" || k == "organizations" {
@@ -127,24 +137,15 @@ func (m *manager) fetchAncestors(config *transport_tpg.Config, tfData tpgresourc
127
137
128
138
orgID , orgOK := getOrganizationFromResource (tfData )
129
139
if orgOK {
130
- orgKey = orgID
131
- if ! strings .HasPrefix (orgKey , "organizations/" ) {
132
- orgKey = fmt .Sprintf ("organizations/%s" , orgKey )
133
- }
140
+ orgKey = ensurePrefix (orgID , orgPrefix )
134
141
}
135
142
folderID , folderOK := getFolderFromResource (tfData )
136
143
if folderOK {
137
- folderKey = folderID
138
- if ! strings .HasPrefix (folderKey , "folders/" ) {
139
- folderKey = fmt .Sprintf ("folders/%s" , folderKey )
140
- }
144
+ folderKey = ensurePrefix (folderID , folderPrefix )
141
145
}
142
146
project , _ := m .getProjectFromResource (tfData , config , cai )
143
147
if project != "" {
144
- projectKey = project
145
- if ! strings .HasPrefix (projectKey , "projects/" ) {
146
- projectKey = fmt .Sprintf ("projects/%s" , project )
147
- }
148
+ projectKey = ensurePrefix (project , projectPrefix )
148
149
}
149
150
150
151
switch cai .Type {
@@ -154,7 +155,7 @@ func (m *manager) fetchAncestors(config *transport_tpg.Config, tfData tpgresourc
154
155
} else if orgOK {
155
156
key = orgKey
156
157
} else {
157
- return []string {"organizations/unknown" }, nil
158
+ return []string {unknownOrg }, nil
158
159
}
159
160
case "cloudresourcemanager.googleapis.com/Organization" :
160
161
if ! orgOK {
@@ -168,7 +169,7 @@ func (m *manager) fetchAncestors(config *transport_tpg.Config, tfData tpgresourc
168
169
} else if projectKey != "" {
169
170
key = projectKey
170
171
} else {
171
- return []string {"organizations/unknown" }, nil
172
+ return []string {unknownOrg }, nil
172
173
}
173
174
case "cloudresourcemanager.googleapis.com/Project" , "cloudbilling.googleapis.com/ProjectBillingInfo" :
174
175
// for google_project and google_project_iam resources
@@ -183,7 +184,7 @@ func (m *manager) fetchAncestors(config *transport_tpg.Config, tfData tpgresourc
183
184
// only folder_id or org_id is allowed for google_project
184
185
if orgOK {
185
186
// no need to use API to fetch ancestors
186
- ancestors = append (ancestors , fmt . Sprintf ( "organizations/%s" , orgID ) )
187
+ ancestors = append (ancestors , orgPrefix + orgID )
187
188
return ancestors , nil
188
189
}
189
190
if folderOK {
@@ -199,13 +200,13 @@ func (m *manager) fetchAncestors(config *transport_tpg.Config, tfData tpgresourc
199
200
200
201
// neither folder_id nor org_id is specified
201
202
if projectKey == "" {
202
- return []string {"organizations/unknown" }, nil
203
+ return []string {unknownOrg }, nil
203
204
}
204
205
key = projectKey
205
206
206
207
default :
207
208
if projectKey == "" {
208
- return []string {"organizations/unknown" }, nil
209
+ return []string {unknownOrg }, nil
209
210
}
210
211
key = projectKey
211
212
}
@@ -220,16 +221,16 @@ func (m *manager) getAncestorsWithCache(key string) ([]string, error) {
220
221
ancestors = append (ancestors , cachedAncestors ... )
221
222
break
222
223
}
223
- if strings .HasPrefix (cur , "organizations/" ) {
224
+ if strings .HasPrefix (cur , orgPrefix ) {
224
225
ancestors = append (ancestors , cur )
225
226
break
226
227
}
227
228
if m .resourceManagerV3 == nil || m .resourceManagerV1 == nil {
228
229
return nil , fmt .Errorf ("resourceManager required to fetch ancestry for %s from the API" , cur )
229
230
}
230
- if strings .HasPrefix (cur , "projects" ) {
231
+ if strings .HasPrefix (cur , projectPrefix ) {
231
232
// fall back to use v1 API GetAncestry to avoid requiring extra folder permission
232
- projectID := strings .TrimPrefix (cur , "projects/" )
233
+ projectID := strings .TrimPrefix (cur , projectPrefix )
233
234
var resp * crmv1.GetAncestryResponse
234
235
var err error
235
236
err = transport_tpg .Retry (transport_tpg.RetryOptions {
@@ -325,9 +326,9 @@ func normalizeAncestry(val string) string {
325
326
old string
326
327
new string
327
328
}{
328
- {"organization/" , "organizations/" },
329
- {"folder/" , "folders/" },
330
- {"project/" , "projects/" },
329
+ {"organization/" , orgPrefix },
330
+ {"folder/" , folderPrefix },
331
+ {"project/" , projectPrefix },
331
332
} {
332
333
val = strings .ReplaceAll (val , r .old , r .new )
333
334
}
@@ -383,3 +384,10 @@ type NoOpAncestryManager struct{}
383
384
func (* NoOpAncestryManager ) Ancestors (config * transport_tpg.Config , tfData tpgresource.TerraformResourceData , cai * resources.Asset ) ([]string , string , error ) {
384
385
return nil , "" , nil
385
386
}
387
+
388
+ func ensurePrefix (s , pre string ) string {
389
+ if strings .HasPrefix (s , pre ) {
390
+ return s
391
+ }
392
+ return pre + s
393
+ }
0 commit comments