2014-12-17 13:22:27 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
#
|
2015-04-28 07:20:48 +00:00
|
|
|
# (c) 2015, René Moser <mail@renemoser.net>
|
2014-12-17 13:22:27 +00:00
|
|
|
#
|
|
|
|
# This file is part of Ansible,
|
|
|
|
#
|
|
|
|
# Ansible is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# Ansible is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
######################################################################
|
|
|
|
|
|
|
|
"""
|
|
|
|
Ansible CloudStack external inventory script.
|
|
|
|
=============================================
|
|
|
|
|
|
|
|
Generates Ansible inventory from CloudStack. Configuration is read from
|
|
|
|
'cloudstack.ini'. If you need to pass the project, write a simple wrapper
|
|
|
|
script, e.g. project_cloudstack.sh:
|
|
|
|
|
|
|
|
#!/bin/bash
|
|
|
|
cloudstack.py --project <your_project> $@
|
|
|
|
|
|
|
|
|
|
|
|
When run against a specific host, this script returns the following attributes
|
|
|
|
based on the data obtained from CloudStack API:
|
|
|
|
|
|
|
|
"web01": {
|
|
|
|
"cpu_number": 2,
|
|
|
|
"nic": [
|
|
|
|
{
|
|
|
|
"ip": "10.102.76.98",
|
|
|
|
"mac": "02:00:50:99:00:01",
|
|
|
|
"type": "Isolated",
|
|
|
|
"netmask": "255.255.255.0",
|
|
|
|
"gateway": "10.102.76.1"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"ip": "10.102.138.63",
|
|
|
|
"mac": "06:b7:5a:00:14:84",
|
|
|
|
"type": "Shared",
|
|
|
|
"netmask": "255.255.255.0",
|
|
|
|
"gateway": "10.102.138.1"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"default_ip": "10.102.76.98",
|
|
|
|
"zone": "ZUERICH",
|
|
|
|
"created": "2014-07-02T07:53:50+0200",
|
|
|
|
"hypervisor": "VMware",
|
|
|
|
"memory": 2048,
|
|
|
|
"state": "Running",
|
|
|
|
"tags": [],
|
|
|
|
"cpu_speed": 1800,
|
|
|
|
"affinity_group": [],
|
|
|
|
"service_offering": "Small",
|
|
|
|
"cpu_used": "62%"
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-10-24 16:53:34 +00:00
|
|
|
usage: cloudstack.py [--list] [--host HOST] [--project PROJECT] [--domain DOMAIN]
|
2014-12-17 13:22:27 +00:00
|
|
|
"""
|
|
|
|
|
2015-08-28 06:18:13 +00:00
|
|
|
from __future__ import print_function
|
|
|
|
|
2015-04-28 07:20:48 +00:00
|
|
|
import sys
|
2014-12-17 13:22:27 +00:00
|
|
|
import argparse
|
2018-08-10 16:13:29 +00:00
|
|
|
import json
|
2014-12-17 13:22:27 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
from cs import CloudStack, CloudStackException, read_config
|
|
|
|
except ImportError:
|
2015-08-28 06:18:13 +00:00
|
|
|
print("Error: CloudStack library must be installed: pip install cs.",
|
|
|
|
file=sys.stderr)
|
2014-12-17 13:22:27 +00:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
class CloudStackInventory(object):
|
|
|
|
def __init__(self):
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
parser.add_argument('--host')
|
|
|
|
parser.add_argument('--list', action='store_true')
|
2018-01-14 19:42:31 +00:00
|
|
|
parser.add_argument('--tag', help="Filter machines by a tag. Should be in the form key=value.")
|
2014-12-17 13:22:27 +00:00
|
|
|
parser.add_argument('--project')
|
2016-10-24 16:53:34 +00:00
|
|
|
parser.add_argument('--domain')
|
2014-12-17 13:22:27 +00:00
|
|
|
|
|
|
|
options = parser.parse_args()
|
|
|
|
try:
|
|
|
|
self.cs = CloudStack(**read_config())
|
2017-02-28 18:14:03 +00:00
|
|
|
except CloudStackException:
|
2015-08-28 06:18:13 +00:00
|
|
|
print("Error: Could not connect to CloudStack API", file=sys.stderr)
|
2016-10-24 16:53:34 +00:00
|
|
|
|
|
|
|
domain_id = None
|
|
|
|
if options.domain:
|
|
|
|
domain_id = self.get_domain_id(options.domain)
|
2014-12-17 13:22:27 +00:00
|
|
|
|
2016-10-24 16:53:34 +00:00
|
|
|
project_id = None
|
2014-12-17 13:22:27 +00:00
|
|
|
if options.project:
|
2016-10-24 16:53:34 +00:00
|
|
|
project_id = self.get_project_id(options.project, domain_id)
|
2014-12-17 13:22:27 +00:00
|
|
|
|
|
|
|
if options.host:
|
2016-10-24 16:53:34 +00:00
|
|
|
data = self.get_host(options.host, project_id, domain_id)
|
2015-08-28 06:18:13 +00:00
|
|
|
print(json.dumps(data, indent=2))
|
2014-12-17 13:22:27 +00:00
|
|
|
|
|
|
|
elif options.list:
|
2018-01-14 19:42:31 +00:00
|
|
|
tags = dict()
|
|
|
|
if options.tag:
|
|
|
|
tags['tags[0].key'], tags['tags[0].value'] = options.tag.split('=')
|
|
|
|
data = self.get_list(project_id, domain_id, **tags)
|
2015-08-28 06:18:13 +00:00
|
|
|
print(json.dumps(data, indent=2))
|
2014-12-17 13:22:27 +00:00
|
|
|
else:
|
2018-01-14 19:42:31 +00:00
|
|
|
print("usage: --list [--tag <tag>] | --host <hostname> [--project <project>] [--domain <domain_path>]",
|
|
|
|
file=sys.stderr)
|
2014-12-17 13:22:27 +00:00
|
|
|
sys.exit(1)
|
|
|
|
|
2016-10-24 16:53:34 +00:00
|
|
|
def get_domain_id(self, domain):
|
|
|
|
domains = self.cs.listDomains(listall=True)
|
|
|
|
if domains:
|
|
|
|
for d in domains['domain']:
|
|
|
|
if d['path'].lower() == domain.lower():
|
|
|
|
return d['id']
|
|
|
|
print("Error: Domain %s not found." % domain, file=sys.stderr)
|
|
|
|
sys.exit(1)
|
2014-12-17 13:22:27 +00:00
|
|
|
|
2016-10-24 16:53:34 +00:00
|
|
|
def get_project_id(self, project, domain_id=None):
|
|
|
|
projects = self.cs.listProjects(domainid=domain_id)
|
2014-12-17 13:22:27 +00:00
|
|
|
if projects:
|
|
|
|
for p in projects['project']:
|
|
|
|
if p['name'] == project or p['id'] == project:
|
|
|
|
return p['id']
|
2015-08-28 06:18:13 +00:00
|
|
|
print("Error: Project %s not found." % project, file=sys.stderr)
|
2014-12-17 13:22:27 +00:00
|
|
|
sys.exit(1)
|
|
|
|
|
2018-01-14 19:42:31 +00:00
|
|
|
def get_host(self, name, project_id=None, domain_id=None, **kwargs):
|
2018-05-12 07:46:49 +00:00
|
|
|
hosts = self.cs.listVirtualMachines(projectid=project_id, domainid=domain_id, fetch_list=True, **kwargs)
|
2014-12-17 13:22:27 +00:00
|
|
|
data = {}
|
2015-02-10 08:50:41 +00:00
|
|
|
if not hosts:
|
|
|
|
return data
|
2018-05-12 07:46:49 +00:00
|
|
|
for host in hosts:
|
2014-12-17 13:22:27 +00:00
|
|
|
host_name = host['displayname']
|
|
|
|
if name == host_name:
|
|
|
|
data['zone'] = host['zonename']
|
|
|
|
if 'group' in host:
|
|
|
|
data['group'] = host['group']
|
|
|
|
data['state'] = host['state']
|
|
|
|
data['service_offering'] = host['serviceofferingname']
|
|
|
|
data['affinity_group'] = host['affinitygroup']
|
|
|
|
data['security_group'] = host['securitygroup']
|
|
|
|
data['cpu_number'] = host['cpunumber']
|
2018-12-01 01:00:41 +00:00
|
|
|
if 'cpu_speed' in host:
|
|
|
|
data['cpu_speed'] = host['cpuspeed']
|
2014-12-17 13:22:27 +00:00
|
|
|
if 'cpuused' in host:
|
|
|
|
data['cpu_used'] = host['cpuused']
|
|
|
|
data['memory'] = host['memory']
|
|
|
|
data['tags'] = host['tags']
|
2018-12-01 01:00:41 +00:00
|
|
|
if 'hypervisor' in host:
|
|
|
|
data['hypervisor'] = host['hypervisor']
|
2014-12-17 13:22:27 +00:00
|
|
|
data['created'] = host['created']
|
|
|
|
data['nic'] = []
|
|
|
|
for nic in host['nic']:
|
2018-12-01 01:00:41 +00:00
|
|
|
nicdata = {
|
2014-12-17 13:22:27 +00:00
|
|
|
'ip': nic['ipaddress'],
|
|
|
|
'mac': nic['macaddress'],
|
|
|
|
'netmask': nic['netmask'],
|
|
|
|
'gateway': nic['gateway'],
|
|
|
|
'type': nic['type'],
|
2018-12-01 01:00:41 +00:00
|
|
|
}
|
|
|
|
if 'ip6address' in nic:
|
|
|
|
nicdata['ip6'] = nic['ip6address']
|
|
|
|
if 'gateway' in nic:
|
|
|
|
nicdata['gateway'] = nic['gateway']
|
|
|
|
if 'netmask' in nic:
|
|
|
|
nicdata['netmask'] = nic['netmask']
|
|
|
|
data['nic'].append(nicdata)
|
2014-12-17 13:22:27 +00:00
|
|
|
if nic['isdefault']:
|
|
|
|
data['default_ip'] = nic['ipaddress']
|
2018-12-01 01:00:41 +00:00
|
|
|
if 'ip6address' in nic:
|
|
|
|
data['default_ip6'] = nic['ip6address']
|
2017-01-28 08:12:11 +00:00
|
|
|
break
|
2014-12-17 13:22:27 +00:00
|
|
|
return data
|
|
|
|
|
2018-01-14 19:42:31 +00:00
|
|
|
def get_list(self, project_id=None, domain_id=None, **kwargs):
|
2014-12-17 13:22:27 +00:00
|
|
|
data = {
|
|
|
|
'all': {
|
|
|
|
'hosts': [],
|
2017-02-28 18:14:03 +00:00
|
|
|
},
|
2014-12-17 13:22:27 +00:00
|
|
|
'_meta': {
|
|
|
|
'hostvars': {},
|
2017-02-28 18:14:03 +00:00
|
|
|
},
|
|
|
|
}
|
2014-12-17 13:22:27 +00:00
|
|
|
|
2016-10-24 16:53:34 +00:00
|
|
|
groups = self.cs.listInstanceGroups(projectid=project_id, domainid=domain_id)
|
2015-01-03 18:57:55 +00:00
|
|
|
if groups:
|
|
|
|
for group in groups['instancegroup']:
|
|
|
|
group_name = group['name']
|
2017-02-28 18:14:03 +00:00
|
|
|
if group_name and group_name not in data:
|
2015-01-03 18:57:55 +00:00
|
|
|
data[group_name] = {
|
2017-01-29 07:28:53 +00:00
|
|
|
'hosts': []
|
|
|
|
}
|
2014-12-17 13:22:27 +00:00
|
|
|
|
2018-05-12 07:46:49 +00:00
|
|
|
hosts = self.cs.listVirtualMachines(projectid=project_id, domainid=domain_id, fetch_list=True, **kwargs)
|
2015-02-10 08:50:41 +00:00
|
|
|
if not hosts:
|
|
|
|
return data
|
2018-05-12 07:46:49 +00:00
|
|
|
for host in hosts:
|
2014-12-17 13:22:27 +00:00
|
|
|
host_name = host['displayname']
|
|
|
|
data['all']['hosts'].append(host_name)
|
|
|
|
data['_meta']['hostvars'][host_name] = {}
|
2016-10-24 16:53:34 +00:00
|
|
|
|
|
|
|
# Make a group per zone
|
2014-12-17 13:22:27 +00:00
|
|
|
data['_meta']['hostvars'][host_name]['zone'] = host['zonename']
|
2016-10-24 16:53:34 +00:00
|
|
|
group_name = host['zonename']
|
|
|
|
if group_name not in data:
|
|
|
|
data[group_name] = {
|
|
|
|
'hosts': []
|
|
|
|
}
|
|
|
|
data[group_name]['hosts'].append(host_name)
|
|
|
|
|
2014-12-17 13:22:27 +00:00
|
|
|
if 'group' in host:
|
|
|
|
data['_meta']['hostvars'][host_name]['group'] = host['group']
|
|
|
|
data['_meta']['hostvars'][host_name]['state'] = host['state']
|
|
|
|
data['_meta']['hostvars'][host_name]['service_offering'] = host['serviceofferingname']
|
|
|
|
data['_meta']['hostvars'][host_name]['affinity_group'] = host['affinitygroup']
|
|
|
|
data['_meta']['hostvars'][host_name]['security_group'] = host['securitygroup']
|
|
|
|
data['_meta']['hostvars'][host_name]['cpu_number'] = host['cpunumber']
|
2018-12-01 01:00:41 +00:00
|
|
|
if 'cpuspeed' in host:
|
|
|
|
data['_meta']['hostvars'][host_name]['cpu_speed'] = host['cpuspeed']
|
2014-12-17 13:22:27 +00:00
|
|
|
if 'cpuused' in host:
|
|
|
|
data['_meta']['hostvars'][host_name]['cpu_used'] = host['cpuused']
|
|
|
|
data['_meta']['hostvars'][host_name]['created'] = host['created']
|
|
|
|
data['_meta']['hostvars'][host_name]['memory'] = host['memory']
|
|
|
|
data['_meta']['hostvars'][host_name]['tags'] = host['tags']
|
2018-12-01 01:00:41 +00:00
|
|
|
if 'hypervisor' in host:
|
|
|
|
data['_meta']['hostvars'][host_name]['hypervisor'] = host['hypervisor']
|
2014-12-17 13:22:27 +00:00
|
|
|
data['_meta']['hostvars'][host_name]['created'] = host['created']
|
|
|
|
data['_meta']['hostvars'][host_name]['nic'] = []
|
|
|
|
for nic in host['nic']:
|
2018-12-01 01:00:41 +00:00
|
|
|
nicdata = {
|
2014-12-17 13:22:27 +00:00
|
|
|
'ip': nic['ipaddress'],
|
|
|
|
'mac': nic['macaddress'],
|
|
|
|
'netmask': nic['netmask'],
|
|
|
|
'gateway': nic['gateway'],
|
|
|
|
'type': nic['type'],
|
2018-12-01 01:00:41 +00:00
|
|
|
}
|
|
|
|
if 'ip6address' in nic:
|
|
|
|
nicdata['ip6'] = nic['ip6address']
|
|
|
|
if 'gateway' in nic:
|
|
|
|
nicdata['gateway'] = nic['gateway']
|
|
|
|
if 'netmask' in nic:
|
|
|
|
nicdata['netmask'] = nic['netmask']
|
|
|
|
data['_meta']['hostvars'][host_name]['nic'].append(nicdata)
|
2014-12-17 13:22:27 +00:00
|
|
|
if nic['isdefault']:
|
|
|
|
data['_meta']['hostvars'][host_name]['default_ip'] = nic['ipaddress']
|
2018-12-01 01:00:41 +00:00
|
|
|
if 'ip6address' in nic:
|
|
|
|
data['_meta']['hostvars'][host_name]['default_ip6'] = nic['ip6address']
|
2014-12-17 13:22:27 +00:00
|
|
|
|
|
|
|
group_name = ''
|
|
|
|
if 'group' in host:
|
|
|
|
group_name = host['group']
|
|
|
|
|
|
|
|
if group_name and group_name in data:
|
|
|
|
data[group_name]['hosts'].append(host_name)
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
CloudStackInventory()
|