@@ -138,54 +138,61 @@ func resourceGoogleServiceAccountCreate(d *schema.ResourceData, meta interface{}
138138 ServiceAccount : sa ,
139139 }
140140
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 ()
142143 if err != nil {
143144 gerr , ok := err .(* googleapi.Error )
144145 alreadyExists := ok && gerr .Code == 409 && d .Get ("create_ignore_already_exists" ).(bool )
145146 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
149166 } else {
150167 return fmt .Errorf ("Error creating service account: %s" , err )
151168 }
152169 }
153170
154171 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 )
171173
172174 // 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.
174177 // 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+ )
180185
181186 // We can't guarantee complete consistency even after polling,
182187 // so sleep for some additional time to reduce the likelihood of
183188 // eventual consistency failures.
184189 time .Sleep (10 * time .Second )
185190
186- return resourceGoogleServiceAccountRead ( d , meta )
191+ return nil
187192}
188193
194+ // PollReadFunc for checking Service Account existence.
195+ // If resourceData is not nil, it will be updated with the response.
189196func resourceServiceAccountPollRead (d * schema.ResourceData , meta interface {}) transport_tpg.PollReadFunc {
190197 return func () (map [string ]interface {}, error ) {
191198 config := meta .(* transport_tpg.Config )
@@ -217,6 +224,10 @@ func resourceGoogleServiceAccountRead(d *schema.ResourceData, meta interface{})
217224 return transport_tpg .HandleNotFoundError (err , d , fmt .Sprintf ("Service Account %q" , d .Id ()))
218225 }
219226
227+ return populateResourceData (d , sa )
228+ }
229+
230+ func populateResourceData (d * schema.ResourceData , sa * iam.ServiceAccount ) error {
220231 if err := d .Set ("email" , sa .Email ); err != nil {
221232 return fmt .Errorf ("Error setting email: %s" , err )
222233 }
0 commit comments