We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Any chance of getting this playbook to work without cinder ? 
#### Description

Provide a brief description of your issue here. For example:

We have access to an openstack without cinder. Any chance of getting this playbook to work without cinder ? 



##### Version

Please put the following version information in the code block
indicated below.

* Your ansible version per `ansible --version`

If you're operating from a **git clone**:

* The output of `git describe`


If you're running from playbooks installed via RPM or
`atomic-openshift-utils`

* The output of `rpm -q atomic-openshift-utils openshift-ansible`

Place the output between the code block below:

```
$ ansible --version
ansible 2.5.0
  config file = /home/arthur/local/openshift/ansible.cfg
  configured module search path = [u'/home/arthur/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/arthur/.virtualenvs/ansible/local/lib/python2.7/site-packages/ansible
  executable location = /home/arthur/.virtualenvs/ansible/bin/ansible
  python version = 2.7.14 (default, Sep 23 2017, 22:06:14) [GCC 7.2.0]

$ git describe
openshift-ansible-3.10.0-0.15.0-9-gf28aba492
```

##### Steps To Reproduce

When I saw the following comment in all.yml 
```
# If you want to use the VM storage instead of Cinder volumes, set this to `true`.
```
I thought this might be possible but I get the following error when executing the ansible playbook : 

```
$ ansible-playbook [snip]
[snip]
 in endpoint_data_for     raise
exceptions.EndpointNotFound(msg) keystoneauth1.exceptions.catalog.EndpointNotFound: public
endpoint for volumev2 service in RegionOne region not found
[snip]
$ openstack volume list
public endpoint for volumev2 service in RegionOne region not found

```



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `playbooks/openstack/inventory.py`
Content:
```
1 #!/usr/bin/env python
2 """
3 This is an Ansible dynamic inventory for OpenStack.
4 
5 It requires your OpenStack credentials to be set in clouds.yaml or your shell
6 environment.
7 
8 """
9 
10 from __future__ import print_function
11 
12 from collections import Mapping
13 import json
14 import os
15 
16 import shade
17 
18 
19 def base_openshift_inventory(cluster_hosts):
20     '''Set the base openshift inventory.'''
21     inventory = {}
22 
23     masters = [server.name for server in cluster_hosts
24                if server.metadata['host-type'] == 'master']
25 
26     etcd = [server.name for server in cluster_hosts
27             if server.metadata['host-type'] == 'etcd']
28     if not etcd:
29         etcd = masters
30 
31     infra_hosts = [server.name for server in cluster_hosts
32                    if server.metadata['host-type'] == 'node' and
33                    server.metadata['sub-host-type'] == 'infra']
34 
35     app = [server.name for server in cluster_hosts
36            if server.metadata['host-type'] == 'node' and
37            server.metadata['sub-host-type'] == 'app']
38 
39     cns = [server.name for server in cluster_hosts
40            if server.metadata['host-type'] == 'cns']
41 
42     nodes = list(set(masters + infra_hosts + app + cns))
43 
44     dns = [server.name for server in cluster_hosts
45            if server.metadata['host-type'] == 'dns']
46 
47     load_balancers = [server.name for server in cluster_hosts
48                       if server.metadata['host-type'] == 'lb']
49 
50     osev3 = list(set(nodes + etcd + load_balancers))
51 
52     inventory['cluster_hosts'] = {'hosts': [s.name for s in cluster_hosts]}
53     inventory['OSEv3'] = {'hosts': osev3}
54     inventory['masters'] = {'hosts': masters}
55     inventory['etcd'] = {'hosts': etcd}
56     inventory['nodes'] = {'hosts': nodes}
57     inventory['infra_hosts'] = {'hosts': infra_hosts}
58     inventory['app'] = {'hosts': app}
59     inventory['glusterfs'] = {'hosts': cns}
60     inventory['dns'] = {'hosts': dns}
61     inventory['lb'] = {'hosts': load_balancers}
62     inventory['localhost'] = {'ansible_connection': 'local'}
63 
64     return inventory
65 
66 
67 def get_docker_storage_mountpoints(volumes):
68     '''Check volumes to see if they're being used for docker storage'''
69     docker_storage_mountpoints = {}
70     for volume in volumes:
71         if volume.metadata.get('purpose') == "openshift_docker_storage":
72             for attachment in volume.attachments:
73                 if attachment.server_id in docker_storage_mountpoints:
74                     docker_storage_mountpoints[attachment.server_id].append(attachment.device)
75                 else:
76                     docker_storage_mountpoints[attachment.server_id] = [attachment.device]
77     return docker_storage_mountpoints
78 
79 
80 def _get_hostvars(server, docker_storage_mountpoints):
81     ssh_ip_address = server.public_v4 or server.private_v4
82     hostvars = {
83         'ansible_host': ssh_ip_address
84     }
85 
86     public_v4 = server.public_v4 or server.private_v4
87     if public_v4:
88         hostvars['public_v4'] = server.public_v4
89         hostvars['openshift_public_ip'] = server.public_v4
90     # TODO(shadower): what about multiple networks?
91     if server.private_v4:
92         hostvars['private_v4'] = server.private_v4
93         hostvars['openshift_ip'] = server.private_v4
94 
95         # NOTE(shadower): Yes, we set both hostname and IP to the private
96         # IP address for each node. OpenStack doesn't resolve nodes by
97         # name at all, so using a hostname here would require an internal
98         # DNS which would complicate the setup and potentially introduce
99         # performance issues.
100         hostvars['openshift_hostname'] = server.metadata.get(
101             'openshift_hostname', server.private_v4)
102     hostvars['openshift_public_hostname'] = server.name
103 
104     if server.metadata['host-type'] == 'cns':
105         hostvars['glusterfs_devices'] = ['/dev/nvme0n1']
106 
107     node_labels = server.metadata.get('node_labels')
108     # NOTE(shadower): the node_labels value must be a dict not string
109     if not isinstance(node_labels, Mapping):
110         node_labels = json.loads(node_labels)
111 
112     if node_labels:
113         hostvars['openshift_node_labels'] = node_labels
114 
115     # check for attached docker storage volumes
116     if 'os-extended-volumes:volumes_attached' in server:
117         if server.id in docker_storage_mountpoints:
118             hostvars['docker_storage_mountpoints'] = ' '.join(
119                 docker_storage_mountpoints[server.id])
120     return hostvars
121 
122 
123 def build_inventory():
124     '''Build the dynamic inventory.'''
125     cloud = shade.openstack_cloud()
126 
127     # TODO(shadower): filter the servers based on the `OPENSHIFT_CLUSTER`
128     # environment variable.
129     cluster_hosts = [
130         server for server in cloud.list_servers()
131         if 'metadata' in server and 'clusterid' in server.metadata]
132 
133     inventory = base_openshift_inventory(cluster_hosts)
134 
135     for server in cluster_hosts:
136         if 'group' in server.metadata:
137             group = server.metadata.get('group')
138             if group not in inventory:
139                 inventory[group] = {'hosts': []}
140             inventory[group]['hosts'].append(server.name)
141 
142     inventory['_meta'] = {'hostvars': {}}
143 
144     # cinder volumes used for docker storage
145     docker_storage_mountpoints = get_docker_storage_mountpoints(
146         cloud.list_volumes())
147     for server in cluster_hosts:
148         inventory['_meta']['hostvars'][server.name] = _get_hostvars(
149             server,
150             docker_storage_mountpoints)
151 
152     stout = _get_stack_outputs(cloud)
153     if stout is not None:
154         try:
155             inventory['localhost'].update({
156                 'openshift_openstack_api_lb_provider':
157                 stout['api_lb_provider'],
158                 'openshift_openstack_api_lb_port_id':
159                 stout['api_lb_vip_port_id'],
160                 'openshift_openstack_api_lb_sg_id':
161                 stout['api_lb_sg_id']})
162         except KeyError:
163             pass  # Not an API load balanced deployment
164 
165         try:
166             inventory['OSEv3']['vars'] = _get_kuryr_vars(cloud, stout)
167         except KeyError:
168             pass  # Not a kuryr deployment
169     return inventory
170 
171 
172 def _get_stack_outputs(cloud_client):
173     """Returns a dictionary with the stack outputs"""
174     cluster_name = os.getenv('OPENSHIFT_CLUSTER', 'openshift-cluster')
175 
176     stack = cloud_client.get_stack(cluster_name)
177     if stack is None or stack['stack_status'] not in (
178             'CREATE_COMPLETE', 'UPDATE_COMPLETE'):
179         return None
180 
181     data = {}
182     for output in stack['outputs']:
183         data[output['output_key']] = output['output_value']
184     return data
185 
186 
187 def _get_kuryr_vars(cloud_client, data):
188     """Returns a dictionary of Kuryr variables resulting of heat stacking"""
189     settings = {}
190     settings['kuryr_openstack_pod_subnet_id'] = data['pod_subnet']
191     settings['kuryr_openstack_worker_nodes_subnet_id'] = data['vm_subnet']
192     settings['kuryr_openstack_service_subnet_id'] = data['service_subnet']
193     settings['kuryr_openstack_pod_sg_id'] = data['pod_access_sg_id']
194     settings['kuryr_openstack_pod_project_id'] = (
195         cloud_client.current_project_id)
196 
197     settings['kuryr_openstack_auth_url'] = cloud_client.auth['auth_url']
198     settings['kuryr_openstack_username'] = cloud_client.auth['username']
199     settings['kuryr_openstack_password'] = cloud_client.auth['password']
200     if 'user_domain_id' in cloud_client.auth:
201         settings['kuryr_openstack_user_domain_name'] = (
202             cloud_client.auth['user_domain_id'])
203     else:
204         settings['kuryr_openstack_user_domain_name'] = (
205             cloud_client.auth['user_domain_name'])
206     # FIXME(apuimedo): consolidate kuryr controller credentials into the same
207     #                  vars the openstack playbook uses.
208     settings['kuryr_openstack_project_id'] = cloud_client.current_project_id
209     if 'project_domain_id' in cloud_client.auth:
210         settings['kuryr_openstack_project_domain_name'] = (
211             cloud_client.auth['project_domain_id'])
212     else:
213         settings['kuryr_openstack_project_domain_name'] = (
214             cloud_client.auth['project_domain_name'])
215     return settings
216 
217 
218 if __name__ == '__main__':
219     print(json.dumps(build_inventory(), indent=4, sort_keys=True))
220
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/playbooks/openstack/inventory.py b/playbooks/openstack/inventory.py
--- a/playbooks/openstack/inventory.py
+++ b/playbooks/openstack/inventory.py
@@ -13,6 +13,7 @@
 import json
 import os
 
+from keystoneauth1.exceptions.catalog import EndpointNotFound
 import shade
 
 
@@ -141,9 +142,14 @@
 
     inventory['_meta'] = {'hostvars': {}}
 
+    # Some clouds don't have Cinder. That's okay:
+    try:
+        volumes = cloud.list_volumes()
+    except EndpointNotFound:
+        volumes = []
+
     # cinder volumes used for docker storage
-    docker_storage_mountpoints = get_docker_storage_mountpoints(
-        cloud.list_volumes())
+    docker_storage_mountpoints = get_docker_storage_mountpoints(volumes)
     for server in cluster_hosts:
         inventory['_meta']['hostvars'][server.name] = _get_hostvars(
             server,

{"golden_diff": "diff --git a/playbooks/openstack/inventory.py b/playbooks/openstack/inventory.py\n--- a/playbooks/openstack/inventory.py\n+++ b/playbooks/openstack/inventory.py\n@@ -13,6 +13,7 @@\n import json\n import os\n \n+from keystoneauth1.exceptions.catalog import EndpointNotFound\n import shade\n \n \n@@ -141,9 +142,14 @@\n \n     inventory['_meta'] = {'hostvars': {}}\n \n+    # Some clouds don't have Cinder. That's okay:\n+    try:\n+        volumes = cloud.list_volumes()\n+    except EndpointNotFound:\n+        volumes = []\n+\n     # cinder volumes used for docker storage\n-    docker_storage_mountpoints = get_docker_storage_mountpoints(\n-        cloud.list_volumes())\n+    docker_storage_mountpoints = get_docker_storage_mountpoints(volumes)\n     for server in cluster_hosts:\n         inventory['_meta']['hostvars'][server.name] = _get_hostvars(\n             server,\n", "issue": "Any chance of getting this playbook to work without cinder ? \n#### Description\r\n\r\nProvide a brief description of your issue here. For example:\r\n\r\nWe have access to an openstack without cinder. Any chance of getting this playbook to work without cinder ? \r\n\r\n\r\n\r\n##### Version\r\n\r\nPlease put the following version information in the code block\r\nindicated below.\r\n\r\n* Your ansible version per `ansible --version`\r\n\r\nIf you're operating from a **git clone**:\r\n\r\n* The output of `git describe`\r\n\r\n\r\nIf you're running from playbooks installed via RPM or\r\n`atomic-openshift-utils`\r\n\r\n* The output of `rpm -q atomic-openshift-utils openshift-ansible`\r\n\r\nPlace the output between the code block below:\r\n\r\n```\r\n$ ansible --version\r\nansible 2.5.0\r\n  config file = /home/arthur/local/openshift/ansible.cfg\r\n  configured module search path = [u'/home/arthur/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']\r\n  ansible python module location = /home/arthur/.virtualenvs/ansible/local/lib/python2.7/site-packages/ansible\r\n  executable location = /home/arthur/.virtualenvs/ansible/bin/ansible\r\n  python version = 2.7.14 (default, Sep 23 2017, 22:06:14) [GCC 7.2.0]\r\n\r\n$ git describe\r\nopenshift-ansible-3.10.0-0.15.0-9-gf28aba492\r\n```\r\n\r\n##### Steps To Reproduce\r\n\r\nWhen I saw the following comment in all.yml \r\n```\r\n# If you want to use the VM storage instead of Cinder volumes, set this to `true`.\r\n```\r\nI thought this might be possible but I get the following error when executing the ansible playbook : \r\n\r\n```\r\n$ ansible-playbook [snip]\r\n[snip]\r\n in endpoint_data_for     raise\r\nexceptions.EndpointNotFound(msg) keystoneauth1.exceptions.catalog.EndpointNotFound: public\r\nendpoint for volumev2 service in RegionOne region not found\r\n[snip]\r\n$ openstack volume list\r\npublic endpoint for volumev2 service in RegionOne region not found\r\n\r\n```\r\n\r\n\n", "before_files": [{"content": "#!/usr/bin/env python\n\"\"\"\nThis is an Ansible dynamic inventory for OpenStack.\n\nIt requires your OpenStack credentials to be set in clouds.yaml or your shell\nenvironment.\n\n\"\"\"\n\nfrom __future__ import print_function\n\nfrom collections import Mapping\nimport json\nimport os\n\nimport shade\n\n\ndef base_openshift_inventory(cluster_hosts):\n    '''Set the base openshift inventory.'''\n    inventory = {}\n\n    masters = [server.name for server in cluster_hosts\n               if server.metadata['host-type'] == 'master']\n\n    etcd = [server.name for server in cluster_hosts\n            if server.metadata['host-type'] == 'etcd']\n    if not etcd:\n        etcd = masters\n\n    infra_hosts = [server.name for server in cluster_hosts\n                   if server.metadata['host-type'] == 'node' and\n                   server.metadata['sub-host-type'] == 'infra']\n\n    app = [server.name for server in cluster_hosts\n           if server.metadata['host-type'] == 'node' and\n           server.metadata['sub-host-type'] == 'app']\n\n    cns = [server.name for server in cluster_hosts\n           if server.metadata['host-type'] == 'cns']\n\n    nodes = list(set(masters + infra_hosts + app + cns))\n\n    dns = [server.name for server in cluster_hosts\n           if server.metadata['host-type'] == 'dns']\n\n    load_balancers = [server.name for server in cluster_hosts\n                      if server.metadata['host-type'] == 'lb']\n\n    osev3 = list(set(nodes + etcd + load_balancers))\n\n    inventory['cluster_hosts'] = {'hosts': [s.name for s in cluster_hosts]}\n    inventory['OSEv3'] = {'hosts': osev3}\n    inventory['masters'] = {'hosts': masters}\n    inventory['etcd'] = {'hosts': etcd}\n    inventory['nodes'] = {'hosts': nodes}\n    inventory['infra_hosts'] = {'hosts': infra_hosts}\n    inventory['app'] = {'hosts': app}\n    inventory['glusterfs'] = {'hosts': cns}\n    inventory['dns'] = {'hosts': dns}\n    inventory['lb'] = {'hosts': load_balancers}\n    inventory['localhost'] = {'ansible_connection': 'local'}\n\n    return inventory\n\n\ndef get_docker_storage_mountpoints(volumes):\n    '''Check volumes to see if they're being used for docker storage'''\n    docker_storage_mountpoints = {}\n    for volume in volumes:\n        if volume.metadata.get('purpose') == \"openshift_docker_storage\":\n            for attachment in volume.attachments:\n                if attachment.server_id in docker_storage_mountpoints:\n                    docker_storage_mountpoints[attachment.server_id].append(attachment.device)\n                else:\n                    docker_storage_mountpoints[attachment.server_id] = [attachment.device]\n    return docker_storage_mountpoints\n\n\ndef _get_hostvars(server, docker_storage_mountpoints):\n    ssh_ip_address = server.public_v4 or server.private_v4\n    hostvars = {\n        'ansible_host': ssh_ip_address\n    }\n\n    public_v4 = server.public_v4 or server.private_v4\n    if public_v4:\n        hostvars['public_v4'] = server.public_v4\n        hostvars['openshift_public_ip'] = server.public_v4\n    # TODO(shadower): what about multiple networks?\n    if server.private_v4:\n        hostvars['private_v4'] = server.private_v4\n        hostvars['openshift_ip'] = server.private_v4\n\n        # NOTE(shadower): Yes, we set both hostname and IP to the private\n        # IP address for each node. OpenStack doesn't resolve nodes by\n        # name at all, so using a hostname here would require an internal\n        # DNS which would complicate the setup and potentially introduce\n        # performance issues.\n        hostvars['openshift_hostname'] = server.metadata.get(\n            'openshift_hostname', server.private_v4)\n    hostvars['openshift_public_hostname'] = server.name\n\n    if server.metadata['host-type'] == 'cns':\n        hostvars['glusterfs_devices'] = ['/dev/nvme0n1']\n\n    node_labels = server.metadata.get('node_labels')\n    # NOTE(shadower): the node_labels value must be a dict not string\n    if not isinstance(node_labels, Mapping):\n        node_labels = json.loads(node_labels)\n\n    if node_labels:\n        hostvars['openshift_node_labels'] = node_labels\n\n    # check for attached docker storage volumes\n    if 'os-extended-volumes:volumes_attached' in server:\n        if server.id in docker_storage_mountpoints:\n            hostvars['docker_storage_mountpoints'] = ' '.join(\n                docker_storage_mountpoints[server.id])\n    return hostvars\n\n\ndef build_inventory():\n    '''Build the dynamic inventory.'''\n    cloud = shade.openstack_cloud()\n\n    # TODO(shadower): filter the servers based on the `OPENSHIFT_CLUSTER`\n    # environment variable.\n    cluster_hosts = [\n        server for server in cloud.list_servers()\n        if 'metadata' in server and 'clusterid' in server.metadata]\n\n    inventory = base_openshift_inventory(cluster_hosts)\n\n    for server in cluster_hosts:\n        if 'group' in server.metadata:\n            group = server.metadata.get('group')\n            if group not in inventory:\n                inventory[group] = {'hosts': []}\n            inventory[group]['hosts'].append(server.name)\n\n    inventory['_meta'] = {'hostvars': {}}\n\n    # cinder volumes used for docker storage\n    docker_storage_mountpoints = get_docker_storage_mountpoints(\n        cloud.list_volumes())\n    for server in cluster_hosts:\n        inventory['_meta']['hostvars'][server.name] = _get_hostvars(\n            server,\n            docker_storage_mountpoints)\n\n    stout = _get_stack_outputs(cloud)\n    if stout is not None:\n        try:\n            inventory['localhost'].update({\n                'openshift_openstack_api_lb_provider':\n                stout['api_lb_provider'],\n                'openshift_openstack_api_lb_port_id':\n                stout['api_lb_vip_port_id'],\n                'openshift_openstack_api_lb_sg_id':\n                stout['api_lb_sg_id']})\n        except KeyError:\n            pass  # Not an API load balanced deployment\n\n        try:\n            inventory['OSEv3']['vars'] = _get_kuryr_vars(cloud, stout)\n        except KeyError:\n            pass  # Not a kuryr deployment\n    return inventory\n\n\ndef _get_stack_outputs(cloud_client):\n    \"\"\"Returns a dictionary with the stack outputs\"\"\"\n    cluster_name = os.getenv('OPENSHIFT_CLUSTER', 'openshift-cluster')\n\n    stack = cloud_client.get_stack(cluster_name)\n    if stack is None or stack['stack_status'] not in (\n            'CREATE_COMPLETE', 'UPDATE_COMPLETE'):\n        return None\n\n    data = {}\n    for output in stack['outputs']:\n        data[output['output_key']] = output['output_value']\n    return data\n\n\ndef _get_kuryr_vars(cloud_client, data):\n    \"\"\"Returns a dictionary of Kuryr variables resulting of heat stacking\"\"\"\n    settings = {}\n    settings['kuryr_openstack_pod_subnet_id'] = data['pod_subnet']\n    settings['kuryr_openstack_worker_nodes_subnet_id'] = data['vm_subnet']\n    settings['kuryr_openstack_service_subnet_id'] = data['service_subnet']\n    settings['kuryr_openstack_pod_sg_id'] = data['pod_access_sg_id']\n    settings['kuryr_openstack_pod_project_id'] = (\n        cloud_client.current_project_id)\n\n    settings['kuryr_openstack_auth_url'] = cloud_client.auth['auth_url']\n    settings['kuryr_openstack_username'] = cloud_client.auth['username']\n    settings['kuryr_openstack_password'] = cloud_client.auth['password']\n    if 'user_domain_id' in cloud_client.auth:\n        settings['kuryr_openstack_user_domain_name'] = (\n            cloud_client.auth['user_domain_id'])\n    else:\n        settings['kuryr_openstack_user_domain_name'] = (\n            cloud_client.auth['user_domain_name'])\n    # FIXME(apuimedo): consolidate kuryr controller credentials into the same\n    #                  vars the openstack playbook uses.\n    settings['kuryr_openstack_project_id'] = cloud_client.current_project_id\n    if 'project_domain_id' in cloud_client.auth:\n        settings['kuryr_openstack_project_domain_name'] = (\n            cloud_client.auth['project_domain_id'])\n    else:\n        settings['kuryr_openstack_project_domain_name'] = (\n            cloud_client.auth['project_domain_name'])\n    return settings\n\n\nif __name__ == '__main__':\n    print(json.dumps(build_inventory(), indent=4, sort_keys=True))\n", "path": "playbooks/openstack/inventory.py"}], "after_files": [{"content": "#!/usr/bin/env python\n\"\"\"\nThis is an Ansible dynamic inventory for OpenStack.\n\nIt requires your OpenStack credentials to be set in clouds.yaml or your shell\nenvironment.\n\n\"\"\"\n\nfrom __future__ import print_function\n\nfrom collections import Mapping\nimport json\nimport os\n\nfrom keystoneauth1.exceptions.catalog import EndpointNotFound\nimport shade\n\n\ndef base_openshift_inventory(cluster_hosts):\n    '''Set the base openshift inventory.'''\n    inventory = {}\n\n    masters = [server.name for server in cluster_hosts\n               if server.metadata['host-type'] == 'master']\n\n    etcd = [server.name for server in cluster_hosts\n            if server.metadata['host-type'] == 'etcd']\n    if not etcd:\n        etcd = masters\n\n    infra_hosts = [server.name for server in cluster_hosts\n                   if server.metadata['host-type'] == 'node' and\n                   server.metadata['sub-host-type'] == 'infra']\n\n    app = [server.name for server in cluster_hosts\n           if server.metadata['host-type'] == 'node' and\n           server.metadata['sub-host-type'] == 'app']\n\n    cns = [server.name for server in cluster_hosts\n           if server.metadata['host-type'] == 'cns']\n\n    nodes = list(set(masters + infra_hosts + app + cns))\n\n    dns = [server.name for server in cluster_hosts\n           if server.metadata['host-type'] == 'dns']\n\n    load_balancers = [server.name for server in cluster_hosts\n                      if server.metadata['host-type'] == 'lb']\n\n    osev3 = list(set(nodes + etcd + load_balancers))\n\n    inventory['cluster_hosts'] = {'hosts': [s.name for s in cluster_hosts]}\n    inventory['OSEv3'] = {'hosts': osev3}\n    inventory['masters'] = {'hosts': masters}\n    inventory['etcd'] = {'hosts': etcd}\n    inventory['nodes'] = {'hosts': nodes}\n    inventory['infra_hosts'] = {'hosts': infra_hosts}\n    inventory['app'] = {'hosts': app}\n    inventory['glusterfs'] = {'hosts': cns}\n    inventory['dns'] = {'hosts': dns}\n    inventory['lb'] = {'hosts': load_balancers}\n    inventory['localhost'] = {'ansible_connection': 'local'}\n\n    return inventory\n\n\ndef get_docker_storage_mountpoints(volumes):\n    '''Check volumes to see if they're being used for docker storage'''\n    docker_storage_mountpoints = {}\n    for volume in volumes:\n        if volume.metadata.get('purpose') == \"openshift_docker_storage\":\n            for attachment in volume.attachments:\n                if attachment.server_id in docker_storage_mountpoints:\n                    docker_storage_mountpoints[attachment.server_id].append(attachment.device)\n                else:\n                    docker_storage_mountpoints[attachment.server_id] = [attachment.device]\n    return docker_storage_mountpoints\n\n\ndef _get_hostvars(server, docker_storage_mountpoints):\n    ssh_ip_address = server.public_v4 or server.private_v4\n    hostvars = {\n        'ansible_host': ssh_ip_address\n    }\n\n    public_v4 = server.public_v4 or server.private_v4\n    if public_v4:\n        hostvars['public_v4'] = server.public_v4\n        hostvars['openshift_public_ip'] = server.public_v4\n    # TODO(shadower): what about multiple networks?\n    if server.private_v4:\n        hostvars['private_v4'] = server.private_v4\n        hostvars['openshift_ip'] = server.private_v4\n\n        # NOTE(shadower): Yes, we set both hostname and IP to the private\n        # IP address for each node. OpenStack doesn't resolve nodes by\n        # name at all, so using a hostname here would require an internal\n        # DNS which would complicate the setup and potentially introduce\n        # performance issues.\n        hostvars['openshift_hostname'] = server.metadata.get(\n            'openshift_hostname', server.private_v4)\n    hostvars['openshift_public_hostname'] = server.name\n\n    if server.metadata['host-type'] == 'cns':\n        hostvars['glusterfs_devices'] = ['/dev/nvme0n1']\n\n    node_labels = server.metadata.get('node_labels')\n    # NOTE(shadower): the node_labels value must be a dict not string\n    if not isinstance(node_labels, Mapping):\n        node_labels = json.loads(node_labels)\n\n    if node_labels:\n        hostvars['openshift_node_labels'] = node_labels\n\n    # check for attached docker storage volumes\n    if 'os-extended-volumes:volumes_attached' in server:\n        if server.id in docker_storage_mountpoints:\n            hostvars['docker_storage_mountpoints'] = ' '.join(\n                docker_storage_mountpoints[server.id])\n    return hostvars\n\n\ndef build_inventory():\n    '''Build the dynamic inventory.'''\n    cloud = shade.openstack_cloud()\n\n    # TODO(shadower): filter the servers based on the `OPENSHIFT_CLUSTER`\n    # environment variable.\n    cluster_hosts = [\n        server for server in cloud.list_servers()\n        if 'metadata' in server and 'clusterid' in server.metadata]\n\n    inventory = base_openshift_inventory(cluster_hosts)\n\n    for server in cluster_hosts:\n        if 'group' in server.metadata:\n            group = server.metadata.get('group')\n            if group not in inventory:\n                inventory[group] = {'hosts': []}\n            inventory[group]['hosts'].append(server.name)\n\n    inventory['_meta'] = {'hostvars': {}}\n\n    # Some clouds don't have Cinder. That's okay:\n    try:\n        volumes = cloud.list_volumes()\n    except EndpointNotFound:\n        volumes = []\n\n    # cinder volumes used for docker storage\n    docker_storage_mountpoints = get_docker_storage_mountpoints(volumes)\n    for server in cluster_hosts:\n        inventory['_meta']['hostvars'][server.name] = _get_hostvars(\n            server,\n            docker_storage_mountpoints)\n\n    stout = _get_stack_outputs(cloud)\n    if stout is not None:\n        try:\n            inventory['localhost'].update({\n                'openshift_openstack_api_lb_provider':\n                stout['api_lb_provider'],\n                'openshift_openstack_api_lb_port_id':\n                stout['api_lb_vip_port_id'],\n                'openshift_openstack_api_lb_sg_id':\n                stout['api_lb_sg_id']})\n        except KeyError:\n            pass  # Not an API load balanced deployment\n\n        try:\n            inventory['OSEv3']['vars'] = _get_kuryr_vars(cloud, stout)\n        except KeyError:\n            pass  # Not a kuryr deployment\n    return inventory\n\n\ndef _get_stack_outputs(cloud_client):\n    \"\"\"Returns a dictionary with the stack outputs\"\"\"\n    cluster_name = os.getenv('OPENSHIFT_CLUSTER', 'openshift-cluster')\n\n    stack = cloud_client.get_stack(cluster_name)\n    if stack is None or stack['stack_status'] not in (\n            'CREATE_COMPLETE', 'UPDATE_COMPLETE'):\n        return None\n\n    data = {}\n    for output in stack['outputs']:\n        data[output['output_key']] = output['output_value']\n    return data\n\n\ndef _get_kuryr_vars(cloud_client, data):\n    \"\"\"Returns a dictionary of Kuryr variables resulting of heat stacking\"\"\"\n    settings = {}\n    settings['kuryr_openstack_pod_subnet_id'] = data['pod_subnet']\n    settings['kuryr_openstack_worker_nodes_subnet_id'] = data['vm_subnet']\n    settings['kuryr_openstack_service_subnet_id'] = data['service_subnet']\n    settings['kuryr_openstack_pod_sg_id'] = data['pod_access_sg_id']\n    settings['kuryr_openstack_pod_project_id'] = (\n        cloud_client.current_project_id)\n\n    settings['kuryr_openstack_auth_url'] = cloud_client.auth['auth_url']\n    settings['kuryr_openstack_username'] = cloud_client.auth['username']\n    settings['kuryr_openstack_password'] = cloud_client.auth['password']\n    if 'user_domain_id' in cloud_client.auth:\n        settings['kuryr_openstack_user_domain_name'] = (\n            cloud_client.auth['user_domain_id'])\n    else:\n        settings['kuryr_openstack_user_domain_name'] = (\n            cloud_client.auth['user_domain_name'])\n    # FIXME(apuimedo): consolidate kuryr controller credentials into the same\n    #                  vars the openstack playbook uses.\n    settings['kuryr_openstack_project_id'] = cloud_client.current_project_id\n    if 'project_domain_id' in cloud_client.auth:\n        settings['kuryr_openstack_project_domain_name'] = (\n            cloud_client.auth['project_domain_id'])\n    else:\n        settings['kuryr_openstack_project_domain_name'] = (\n            cloud_client.auth['project_domain_name'])\n    return settings\n\n\nif __name__ == '__main__':\n    print(json.dumps(build_inventory(), indent=4, sort_keys=True))\n", "path": "playbooks/openstack/inventory.py"}]}