@@ -138,54 +138,61 @@ func resourceGoogleServiceAccountCreate(d *schema.ResourceData, meta interface{}
138
138
ServiceAccount : sa ,
139
139
}
140
140
141
- sa , err = config .NewIamClient (userAgent ).Projects .ServiceAccounts .Create ("projects/" + project , r ).Do ()
141
+ iamClient := config .NewIamClient (userAgent )
142
+ sa , err = iamClient .Projects .ServiceAccounts .Create ("projects/" + project , r ).Do ()
142
143
if err != nil {
143
144
gerr , ok := err .(* googleapi.Error )
144
145
alreadyExists := ok && gerr .Code == 409 && d .Get ("create_ignore_already_exists" ).(bool )
145
146
if alreadyExists {
146
- sa = & iam.ServiceAccount {
147
- Name : fmt .Sprintf ("projects/%s/serviceAccounts/%s@%s.iam.gserviceaccount.com" , project , aid , project ),
148
- }
147
+ fullServiceAccountName := fmt .Sprintf ("projects/%s/serviceAccounts/%s@%s.iam.gserviceaccount.com" , project , aid , project )
148
+ err = transport_tpg .Retry (transport_tpg.RetryOptions {
149
+ RetryFunc : func () (operr error ) {
150
+ sa , saerr := iamClient .Projects .ServiceAccounts .Get (fullServiceAccountName ).Do ()
151
+
152
+ if saerr != nil {
153
+ return saerr
154
+ }
155
+
156
+ d .SetId (sa .Name )
157
+ return populateResourceData (d , sa )
158
+ },
159
+ Timeout : d .Timeout (schema .TimeoutCreate ),
160
+ ErrorRetryPredicates : []transport_tpg.RetryErrorPredicateFunc {
161
+ transport_tpg .IsNotFoundRetryableError ("service account creation" ),
162
+ },
163
+ })
164
+
165
+ return nil
149
166
} else {
150
167
return fmt .Errorf ("Error creating service account: %s" , err )
151
168
}
152
169
}
153
170
154
171
d .SetId (sa .Name )
155
-
156
- err = transport_tpg .Retry (transport_tpg.RetryOptions {
157
- RetryFunc : func () (operr error ) {
158
- _ , saerr := config .NewIamClient (userAgent ).Projects .ServiceAccounts .Get (d .Id ()).Do ()
159
- return saerr
160
- },
161
- Timeout : d .Timeout (schema .TimeoutCreate ),
162
- ErrorRetryPredicates : []transport_tpg.RetryErrorPredicateFunc {
163
- transport_tpg .IsNotFoundRetryableError ("service account creation" ),
164
- transport_tpg .IsForbiddenIamServiceAccountRetryableError ("service account creation" ),
165
- },
166
- })
167
-
168
- if err != nil {
169
- return fmt .Errorf ("Error reading service account after creation: %s" , err )
170
- }
172
+ populateResourceData (d , sa )
171
173
172
174
// We poll until the resource is found due to eventual consistency issue
173
- // on part of the api https://cloud.google.com/iam/docs/overview#consistency
175
+ // on part of the api https://cloud.google.com/iam/docs/overview#consistency.
176
+ // Wait for at least 3 successful responses in a row to ensure result is consistent.
174
177
// IAM API returns 403 when the queried SA is not found, so we must ignore both 404 & 403 errors
175
- err = transport_tpg .PollingWaitTime (resourceServiceAccountPollRead (d , meta ), transport_tpg .PollCheckForExistenceWith403 , "Creating Service Account" , d .Timeout (schema .TimeoutCreate ), 1 )
176
-
177
- if err != nil {
178
- return err
179
- }
178
+ transport_tpg .PollingWaitTime (
179
+ resourceServiceAccountPollRead (d , meta ),
180
+ transport_tpg .PollCheckForExistence ,
181
+ "Creating Service Account" ,
182
+ d .Timeout (schema .TimeoutCreate ),
183
+ 3 , // Number of consecutive occurences.
184
+ )
180
185
181
186
// We can't guarantee complete consistency even after polling,
182
187
// so sleep for some additional time to reduce the likelihood of
183
188
// eventual consistency failures.
184
189
time .Sleep (10 * time .Second )
185
190
186
- return resourceGoogleServiceAccountRead ( d , meta )
191
+ return nil
187
192
}
188
193
194
+ // PollReadFunc for checking Service Account existence.
195
+ // If resourceData is not nil, it will be updated with the response.
189
196
func resourceServiceAccountPollRead (d * schema.ResourceData , meta interface {}) transport_tpg.PollReadFunc {
190
197
return func () (map [string ]interface {}, error ) {
191
198
config := meta .(* transport_tpg.Config )
@@ -217,6 +224,10 @@ func resourceGoogleServiceAccountRead(d *schema.ResourceData, meta interface{})
217
224
return transport_tpg .HandleNotFoundError (err , d , fmt .Sprintf ("Service Account %q" , d .Id ()))
218
225
}
219
226
227
+ return populateResourceData (d , sa )
228
+ }
229
+
230
+ func populateResourceData (d * schema.ResourceData , sa * iam.ServiceAccount ) error {
220
231
if err := d .Set ("email" , sa .Email ); err != nil {
221
232
return fmt .Errorf ("Error setting email: %s" , err )
222
233
}
0 commit comments