Repository: ansible/ansible

Issue:
os_quota blows up if cloud does not expose a volume service API
##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
module/cloud/openstack/os_quota.py

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.2.1.0
  config file = 
  configured module search path = Default w/o overrides
```

##### CONFIGURATION
<!---
I'm using the new os_quota module from the devel branch of ansible, with ansible 2.2.1.0
-->

##### OS / ENVIRONMENT
n/a
##### SUMMARY

The module first attempts to gather existing quotas for the project.  It does this for compute, network, and volume.  If a cloud does not supply one of these (in my case a volume v2 api), the module blows up.

##### STEPS TO REPRODUCE

<!--- Paste example playbooks or commands between quotes below -->
```
- os_quota:
    cloud: mycloud
    name: demoproject
    cores: 100
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
I'd expect non-volume related quotas to be updated appropriately.

##### ACTUAL RESULTS
https://gist.github.com/gandelman-a/330d6c4d8ba162de928ff407b82b8350


Discussion:
cc @emonty @shrews @juliakreger @j2sol @rcarrillocruz @thingee
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
I hit the same issue

Resolving patch:
diff --git a/lib/ansible/modules/cloud/openstack/os_quota.py b/lib/ansible/modules/cloud/openstack/os_quota.py
--- a/lib/ansible/modules/cloud/openstack/os_quota.py
+++ b/lib/ansible/modules/cloud/openstack/os_quota.py
@@ -290,6 +290,7 @@
 
 try:
     import shade
+    from keystoneauth1 import exceptions
     HAS_SHADE = True
 except ImportError:
     HAS_SHADE = False
@@ -307,11 +308,19 @@ def _get_compute_quotas(cloud, project):
 
     return cloud.get_compute_quotas(project)
 
-def _get_quotas(cloud, project):
+def _get_quotas(module, cloud, project):
 
     quota = {}
-    quota['volume'] = _get_volume_quotas(cloud, project)
-    quota['network'] = _get_network_quotas(cloud, project)
+    try:
+        quota['volume'] = _get_volume_quotas(cloud, project)
+    except exceptions.EndpointNotFound:
+        module.warn("No public endpoint for volumev2 service was found. Ignoring volume quotas.")
+
+    try:
+        quota['network'] = _get_network_quotas(cloud, project)
+    except exceptions.EndpointNotFound:
+        module.warn("No public endpoint for network service was found. Ignoring network quotas.")
+
     quota['compute'] = _get_compute_quotas(cloud, project)
 
     for quota_type in quota.keys():
@@ -432,7 +441,7 @@ def main():
                 module.params[k] = int(v)
 
         #Get current quota values
-        project_quota_output = _get_quotas(cloud, cloud_params['name'])
+        project_quota_output = _get_quotas(module, cloud, cloud_params['name'])
         changes_required = False
 
         if module.params['state'] == "absent":
@@ -461,7 +470,7 @@ def main():
                     else:
                         module.fail_json(msg=str(e), extra_data=e.extra_data)
 
-            project_quota_output = _get_quotas(cloud, cloud_params['name'])
+            project_quota_output = _get_quotas(module, cloud, cloud_params['name'])
             changes_required = True
 
 
@@ -480,7 +489,7 @@ def main():
                     quota_call(cloud_params['name'], **quota_change_request[quota_type])
 
                 #Get quota state post changes for validation
-                project_quota_update = _get_quotas(cloud, cloud_params['name'])
+                project_quota_update = _get_quotas(module, cloud, cloud_params['name'])
 
                 if project_quota_output == project_quota_update:
                     module.fail_json(msg='Could not apply quota update')


Test patch: