@@ -122,54 +122,61 @@ func resourceGoogleServiceAccountCreate(d *schema.ResourceData, meta interface{}
122
122
ServiceAccount : sa ,
123
123
}
124
124
125
- sa , err = config .NewIamClient (userAgent ).Projects .ServiceAccounts .Create ("projects/" + project , r ).Do ()
125
+ iamClient := config .NewIamClient (userAgent )
126
+ sa , err = iamClient .Projects .ServiceAccounts .Create ("projects/" + project , r ).Do ()
126
127
if err != nil {
127
128
gerr , ok := err .(* googleapi.Error )
128
129
alreadyExists := ok && gerr .Code == 409 && d .Get ("create_ignore_already_exists" ).(bool )
129
130
if alreadyExists {
130
- sa = & iam.ServiceAccount {
131
- Name : fmt .Sprintf ("projects/%s/serviceAccounts/%s@%s.iam.gserviceaccount.com" , project , aid , project ),
132
- }
131
+ fullServiceAccountName := fmt .Sprintf ("projects/%s/serviceAccounts/%s@%s.iam.gserviceaccount.com" , project , aid , project )
132
+ err = transport_tpg .Retry (transport_tpg.RetryOptions {
133
+ RetryFunc : func () (operr error ) {
134
+ sa , saerr := iamClient .Projects .ServiceAccounts .Get (fullServiceAccountName ).Do ()
135
+
136
+ if saerr != nil {
137
+ return saerr
138
+ }
139
+
140
+ d .SetId (sa .Name )
141
+ return populateResourceData (d , sa )
142
+ },
143
+ Timeout : d .Timeout (schema .TimeoutCreate ),
144
+ ErrorRetryPredicates : []transport_tpg.RetryErrorPredicateFunc {
145
+ transport_tpg .IsNotFoundRetryableError ("service account creation" ),
146
+ },
147
+ })
148
+
149
+ return nil
133
150
} else {
134
151
return fmt .Errorf ("Error creating service account: %s" , err )
135
152
}
136
153
}
137
154
138
155
d .SetId (sa .Name )
139
-
140
- err = transport_tpg .Retry (transport_tpg.RetryOptions {
141
- RetryFunc : func () (operr error ) {
142
- _ , saerr := config .NewIamClient (userAgent ).Projects .ServiceAccounts .Get (d .Id ()).Do ()
143
- return saerr
144
- },
145
- Timeout : d .Timeout (schema .TimeoutCreate ),
146
- ErrorRetryPredicates : []transport_tpg.RetryErrorPredicateFunc {
147
- transport_tpg .IsNotFoundRetryableError ("service account creation" ),
148
- transport_tpg .IsForbiddenIamServiceAccountRetryableError ("service account creation" ),
149
- },
150
- })
151
-
152
- if err != nil {
153
- return fmt .Errorf ("Error reading service account after creation: %s" , err )
154
- }
156
+ populateResourceData (d , sa )
155
157
156
158
// We poll until the resource is found due to eventual consistency issue
157
- // on part of the api https://cloud.google.com/iam/docs/overview#consistency
159
+ // on part of the api https://cloud.google.com/iam/docs/overview#consistency.
160
+ // Wait for at least 3 successful responses in a row to ensure result is consistent.
158
161
// IAM API returns 403 when the queried SA is not found, so we must ignore both 404 & 403 errors
159
- err = transport_tpg .PollingWaitTime (resourceServiceAccountPollRead (d , meta ), transport_tpg .PollCheckForExistenceWith403 , "Creating Service Account" , d .Timeout (schema .TimeoutCreate ), 1 )
160
-
161
- if err != nil {
162
- return err
163
- }
162
+ transport_tpg .PollingWaitTime (
163
+ resourceServiceAccountPollRead (d , meta ),
164
+ transport_tpg .PollCheckForExistence ,
165
+ "Creating Service Account" ,
166
+ d .Timeout (schema .TimeoutCreate ),
167
+ 3 , // Number of consecutive occurences.
168
+ )
164
169
165
170
// We can't guarantee complete consistency even after polling,
166
171
// so sleep for some additional time to reduce the likelihood of
167
172
// eventual consistency failures.
168
173
time .Sleep (10 * time .Second )
169
174
170
- return resourceGoogleServiceAccountRead ( d , meta )
175
+ return nil
171
176
}
172
177
178
+ // PollReadFunc for checking Service Account existence.
179
+ // If resourceData is not nil, it will be updated with the response.
173
180
func resourceServiceAccountPollRead (d * schema.ResourceData , meta interface {}) transport_tpg.PollReadFunc {
174
181
return func () (map [string ]interface {}, error ) {
175
182
config := meta .(* transport_tpg.Config )
@@ -201,6 +208,10 @@ func resourceGoogleServiceAccountRead(d *schema.ResourceData, meta interface{})
201
208
return transport_tpg .HandleNotFoundError (err , d , fmt .Sprintf ("Service Account %q" , d .Id ()))
202
209
}
203
210
211
+ return populateResourceData (d , sa )
212
+ }
213
+
214
+ func populateResourceData (d * schema.ResourceData , sa * iam.ServiceAccount ) error {
204
215
if err := d .Set ("email" , sa .Email ); err != nil {
205
216
return fmt .Errorf ("Error setting email: %s" , err )
206
217
}
0 commit comments