Ignore API not enabled errors when reading project

When reading a project, both App Engine and Billing would fail if
_neither_ the default project the provider was configured with nor the
project being targeted had the App Engine Admin or Billing APIs
(respectively) enabled. We didn't catch this because our source project
obviously has both enabled.

This fixes the matter by checking the error returned from each of those,
and if it looks like an API not enabled error, logging it at warning
level instead of returning it as an error, which will let the read
proceed as usual.
This commit is contained in:
Paddy Carver 2018-05-22 16:59:33 -07:00
parent ed36405b02
commit 4c40febd4b
2 changed files with 26 additions and 4 deletions

View File

@ -348,10 +348,11 @@ func resourceGoogleProjectRead(d *schema.ResourceData, meta interface{}) error {
// Read the billing account // Read the billing account
ba, err := config.clientBilling.Projects.GetBillingInfo(prefixedProject(pid)).Do() ba, err := config.clientBilling.Projects.GetBillingInfo(prefixedProject(pid)).Do()
if err != nil { if err != nil && !isApiNotEnabledError(err) {
return fmt.Errorf("Error reading billing account for project %q: %v", prefixedProject(pid), err) return fmt.Errorf("Error reading billing account for project %q: %v", prefixedProject(pid), err)
} } else if isApiNotEnabledError(err) {
if ba.BillingAccountName != "" { log.Printf("[WARN] Billing info API not enabled, please enable it to read billing info about project %q: %s", pid, err.Error())
} else if ba.BillingAccountName != "" {
// BillingAccountName is contains the resource name of the billing account // BillingAccountName is contains the resource name of the billing account
// associated with the project, if any. For example, // associated with the project, if any. For example,
// `billingAccounts/012345-567890-ABCDEF`. We care about the ID and not // `billingAccounts/012345-567890-ABCDEF`. We care about the ID and not
@ -371,10 +372,12 @@ func resourceGoogleProjectRead(d *schema.ResourceData, meta interface{}) error {
// shouldn't. So this tries to read it, sets it to empty if none exists, // shouldn't. So this tries to read it, sets it to empty if none exists,
// or sets it in state if one does exist. // or sets it in state if one does exist.
app, err := config.clientAppEngine.Apps.Get(pid).Do() app, err := config.clientAppEngine.Apps.Get(pid).Do()
if err != nil && !isGoogleApiErrorWithCode(err, 404) { if err != nil && !isGoogleApiErrorWithCode(err, 404) && !isApiNotEnabledError(err) {
return fmt.Errorf("Error retrieving App Engine application %q: %s", pid, err.Error()) return fmt.Errorf("Error retrieving App Engine application %q: %s", pid, err.Error())
} else if isGoogleApiErrorWithCode(err, 404) { } else if isGoogleApiErrorWithCode(err, 404) {
d.Set("app_engine", []map[string]interface{}{}) d.Set("app_engine", []map[string]interface{}{})
} else if isApiNotEnabledError(err) {
log.Printf("[WARN] App Engine Admin API not enabled, please enable it to read App Engine info about project %q: %s", pid, err.Error())
} else { } else {
appBlocks, err := flattenAppEngineApp(app) appBlocks, err := flattenAppEngineApp(app)
if err != nil { if err != nil {

View File

@ -147,6 +147,25 @@ func isGoogleApiErrorWithCode(err error, errCode int) bool {
return ok && gerr != nil && gerr.Code == errCode return ok && gerr != nil && gerr.Code == errCode
} }
func isApiNotEnabledError(err error) bool {
gerr, ok := errwrap.GetType(err, &googleapi.Error{}).(*googleapi.Error)
if !ok {
return false
}
if gerr == nil {
return false
}
if gerr.Code != 403 {
return false
}
for _, e := range gerr.Errors {
if e.Reason == "accessNotConfigured" {
return true
}
}
return false
}
func isConflictError(err error) bool { func isConflictError(err error) bool {
if e, ok := err.(*googleapi.Error); ok && e.Code == 409 { if e, ok := err.(*googleapi.Error); ok && e.Code == 409 {
return true return true