This repository has been archived by the owner on Oct 29, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
openstack_inventory.py
executable file
·243 lines (188 loc) · 8.2 KB
/
openstack_inventory.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#!/usr/bin/env python
################################################################################
# Dynamic inventory generation for Ansible
# Author: Giuseppe Paterno' [email protected]
# Derived from a script by [email protected]
# Released under the MIT License (MIT)
#
# This Python script generates a dynamic inventory based on OpenStack instances.
# Check the included README.md
#
################################################################################
from __future__ import print_function
from novaclient import client
from openstackclient.common import utils
import os, sys, json
import argparse
import openstackclient
import novaclient
def main(args):
parser = argparse.ArgumentParser(description='Process ansible inventory')
parser.add_argument('server', nargs="*", default=None, help='openstack server instance')
parser.add_argument('--sudo', action='store_true', default=None, help='Turn on sudo in Ansible')
parser.add_argument('--no-sudo', action='store_true', default=None, help='Turn off sudo in Ansible')
parser.add_argument('--user', default=None, help='User used in Ansible to connect')
parser.add_argument('--no-user', action='store_true', default=None, help='Remove default user for host')
parser.add_argument('--role', action='append', help='Set role to server (can use multiple times)')
parser.add_argument('--no-roles', action='store_true', default=None, help='Delete all roles from server')
parser.add_argument('--list', action='store_true', default=None, help='List inventory')
values = parser.parse_args()
# Setup novaclient
credentials = getOsCredentialsFromEnvironment()
nt = client.Client(credentials['VERSION'],
credentials['USERNAME'],
credentials['PASSWORD'],
credentials['TENANT_NAME'],
credentials['AUTH_URL'],
service_type="compute")
# If we have an option, proces tags
if len(values.server) > 0:
for server in values.server:
try:
ostack_server = utils.find_resource(nt.servers, server)
except openstackclient.common.exceptions.CommandError:
print("Server %s not found" % server)
sys.exit(1)
# Set roles
if values.role is not None and len(values.role) > 0:
nt.servers.set_meta_item(ostack_server, 'roles', ','.join(values.role))
# Delete roles
if values.no_roles:
try:
nt.servers.delete_meta(ostack_server, ['roles'])
except novaclient.exceptions.NotFound:
pass
# Add sudo
if values.sudo:
addAnsibleHostVar(nt, ostack_server, 'ansible_sudo', 'yes')
# Delete sudo
if values.no_sudo:
# Extract ansible_host_vars metadata and unpack it
deleteAnsibleHostVar(nt, ostack_server, 'ansible_sudo')
# Add user
if values.user is not None:
addAnsibleHostVar(nt, ostack_server, 'ansible_ssh_user', values.user)
# remove user tags
if values.no_user:
deleteAnsibleHostVar(nt, ostack_server, 'ansible_ssh_user')
sys.exit(0)
# Invoking without parameter, let's dump
# the inventory
inventory = {}
inventory['_meta'] = { 'hostvars': {} }
for server in nt.servers.list():
floatingIp = getFloatingIpFromServerForNetwork(server)
if floatingIp:
for group in getAnsibleHostGroupsFromServer(nt, server.id):
addServerToHostGroup(group, floatingIp, inventory)
host_vars = getAnsibleHostVarsFromServer(nt, server.id)
if host_vars:
addServerHostVarsToHostVars(host_vars, floatingIp, inventory)
dumpInventoryAsJson(inventory)
## Delete an asible var from metadata
def deleteAnsibleHostVar(novaclient, server, variable):
if 'ansible_host_vars' in server.metadata:
host_vars_list = server.metadata['ansible_host_vars'].split(';')
host_vars = {}
for host_var_list in host_vars_list:
key, value = host_var_list.split('->')
host_vars[key] = value
# If we have the var, let's put letete it
if variable in host_vars:
del host_vars[variable]
# Delete the metadata if empty
if len(host_vars) == 0:
novaclient.servers.delete_meta(server, ['ansible_host_vars'])
return
# pack again and set meta
host_vars_list = []
for key in host_vars.keys():
host_vars_list.append("%s->%s" % (key, host_vars[key]))
novaclient.servers.set_meta_item(server, 'ansible_host_vars', ';'.join(host_vars_list))
## Add an ansible var to metadata
def addAnsibleHostVar(novaclient, server, ansible_variable, ansible_value):
host_vars = {}
if 'ansible_host_vars' in server.metadata:
host_vars_list = server.metadata['ansible_host_vars'].split(';')
for host_var_list in host_vars_list:
if host_var_list != '':
key, value = host_var_list.split('->')
host_vars[key] = value
# Add variable
host_vars[ansible_variable] = ansible_value
# pack again and set meta
host_vars_list = []
for key in host_vars.keys():
host_vars_list.append("%s->%s" % (key, host_vars[key]))
novaclient.servers.set_meta_item(server, 'ansible_host_vars', ';'.join(host_vars_list))
def getOsCredentialsFromEnvironment():
credentials = {}
# Try to get Compute API version, otherwise default to v2
if 'OS_COMPUTE_API_VERSION' in os.environ:
credentials['VERSION'] = os.environ['OS_COMPUTE_API_VERSION']
else:
credentials['VERSION'] = "2"
try:
credentials['USERNAME'] = os.environ['OS_USERNAME']
credentials['PASSWORD'] = os.environ['OS_PASSWORD']
credentials['TENANT_NAME'] = os.environ['OS_TENANT_NAME']
credentials['AUTH_URL'] = os.environ['OS_AUTH_URL']
except KeyError as e:
print("ERROR: environment variable %s is not defined" % e, file=sys.stderr)
sys.exit(-1)
return credentials
def getAnsibleHostGroupsFromServer(novaClient, serverId):
metadata = getMetaDataFromServer(novaClient, serverId, 'roles')
if metadata:
return metadata.split(',')
else:
return ['default']
def getMetaDataFromServer(novaClient, serverId, key):
try:
return novaClient.servers.get(serverId).metadata[key]
except KeyError:
return None
def getAnsibleHostVarsFromServer(novaClient, serverId):
metadata = getMetaDataFromServer(novaClient, serverId, 'ansible_host_vars')
if metadata:
host_vars = {}
for kv in metadata.split(';'):
key, values = kv.split('->')
if ',' in values:
values = values.split(',')
host_vars[key] = values
return host_vars
else:
return None
def getFloatingIpFromServerForNetwork(server):
floating = None
fixed = None
# Assuming only one network for the host
# extract floating if setted, otherwise return
# fixed IP as we're assuming a provider network or
# a site-2-site VPN
net = server.addresses.keys()[0]
for addr in server.addresses[net]:
if addr['OS-EXT-IPS:type'] == 'floating':
floating = addr['addr']
if addr['OS-EXT-IPS:type'] == 'fixed':
fixed = addr['addr']
if floating is not None:
return floating
if floating is None and fixed is not None:
return fixed
return None
def addServerToHostGroup(group, floatingIp, inventory):
host_group = inventory.get(group, {})
hosts = host_group.get('hosts', [])
hosts.append(floatingIp)
host_group['hosts'] = hosts
inventory[group] = host_group
def addServerHostVarsToHostVars(host_vars, floatingIp, inventory):
inventory_host_vars = inventory['_meta']['hostvars'].get(floatingIp, {})
inventory_host_vars.update(host_vars)
inventory['_meta']['hostvars'][floatingIp] = inventory_host_vars
def dumpInventoryAsJson(inventory):
print(json.dumps(inventory, indent=4))
if __name__ == "__main__":
main(sys.argv)