Add dynamic inventory for oVirt version 4 and RHV version 4 (#17910)
* Add dynamic inventory for oVirt version 4 and RHV version 4 * Add affinity labels and groups to output
This commit is contained in:
parent
77eba2f1cf
commit
563017f7ec
3 changed files with 260 additions and 0 deletions
|
@ -31,3 +31,4 @@ ovirt_api_secrets =
|
|||
ovirt_url =
|
||||
ovirt_username =
|
||||
ovirt_password =
|
||||
ovirt_ca_file =
|
||||
|
|
258
contrib/inventory/ovirt4.py
Executable file
258
contrib/inventory/ovirt4.py
Executable file
|
@ -0,0 +1,258 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2016 Red Hat, Inc.
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
"""
|
||||
oVirt dynamic inventory script
|
||||
=================================
|
||||
|
||||
Generates dynamic inventory file for oVirt.
|
||||
|
||||
Script will return following attributes for each virtual machine:
|
||||
- id
|
||||
- name
|
||||
- host
|
||||
- cluster
|
||||
- status
|
||||
- description
|
||||
- fqdn
|
||||
- os_type
|
||||
- template
|
||||
- tags
|
||||
- statistics
|
||||
- devices
|
||||
|
||||
When run in --list mode, virtual machines are grouped by the following categories:
|
||||
- cluster
|
||||
- tag
|
||||
- status
|
||||
|
||||
Note: If there is some virtual machine which has has more tags it will be in both tag
|
||||
records.
|
||||
|
||||
Examples:
|
||||
# Execute update of system on webserver virtual machine:
|
||||
|
||||
$ ansible -i contrib/inventory/ovirt4.py webserver -m yum -a "name=* state=latest"
|
||||
|
||||
# Get webserver virtual machine information:
|
||||
|
||||
$ contrib/inventory/ovirt4.py --host webserver
|
||||
|
||||
Author: Ondra Machacek (@machacekondra)
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import ConfigParser
|
||||
import os
|
||||
import sys
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
try:
|
||||
import ovirtsdk4 as sdk
|
||||
import ovirtsdk4.types as otypes
|
||||
except ImportError:
|
||||
print('oVirt inventory script requires ovirt-engine-sdk-python >= 4.0.0')
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def parse_args():
|
||||
"""
|
||||
Create command line parser for oVirt dynamic inventory script.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Ansible dynamic inventory script for oVirt.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--list',
|
||||
action='store_true',
|
||||
default=True,
|
||||
help='Get data of all virtual machines (default: True).',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--host',
|
||||
help='Get data of virtual machines running on specified host.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--pretty',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Pretty format (default: False).',
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def create_connection():
|
||||
"""
|
||||
Create a connection to oVirt engine API.
|
||||
"""
|
||||
# Get the path of the configuration file, by default use
|
||||
# 'ovirt.ini' file in script directory:
|
||||
default_path = os.path.join(
|
||||
os.path.dirname(os.path.realpath(__file__)),
|
||||
'ovirt.ini',
|
||||
)
|
||||
config_path = os.environ.get('OVIRT_INI_PATH', default_path)
|
||||
|
||||
# Create parser and add ovirt section if it doesn't exist:
|
||||
config = ConfigParser.SafeConfigParser(
|
||||
defaults={
|
||||
'ovirt_url': None,
|
||||
'ovirt_username': None,
|
||||
'ovirt_password': None,
|
||||
'ovirt_ca_file': None,
|
||||
}
|
||||
)
|
||||
if not config.has_section('ovirt'):
|
||||
config.add_section('ovirt')
|
||||
config.read(config_path)
|
||||
|
||||
# Create a connection with options defined in ini file:
|
||||
return sdk.Connection(
|
||||
url=config.get('ovirt', 'ovirt_url'),
|
||||
username=config.get('ovirt', 'ovirt_username'),
|
||||
password=config.get('ovirt', 'ovirt_password'),
|
||||
ca_file=config.get('ovirt', 'ovirt_ca_file', None),
|
||||
insecure=config.get('ovirt', 'ovirt_ca_file', None) is None,
|
||||
)
|
||||
|
||||
|
||||
def get_dict_of_struct(connection, vm):
|
||||
"""
|
||||
Transform SDK Vm Struct type to Python dictionary.
|
||||
"""
|
||||
if vm is None:
|
||||
return dict()
|
||||
|
||||
vms_service = connection.system_service().vms_service()
|
||||
clusters_service = connection.system_service().clusters_service()
|
||||
vm_service = vms_service.vm_service(vm.id)
|
||||
devices = vm_service.reported_devices_service().list()
|
||||
tags = vm_service.tags_service().list()
|
||||
stats = vm_service.statistics_service().list()
|
||||
labels = vm_service.affinity_labels_service().list()
|
||||
groups = clusters_service.cluster_service(
|
||||
vm.cluster.id
|
||||
).affinity_groups_service().list()
|
||||
|
||||
return {
|
||||
'id': vm.id,
|
||||
'name': vm.name,
|
||||
'host': connection.follow_link(vm.host).name if vm.host else None,
|
||||
'cluster': connection.follow_link(vm.cluster).name,
|
||||
'status': str(vm.status),
|
||||
'description': vm.description,
|
||||
'fqdn': vm.fqdn,
|
||||
'os_type': vm.os.type,
|
||||
'template': connection.follow_link(vm.template).name,
|
||||
'tags': [tag.name for tag in tags],
|
||||
'affinity_labels': [label.name for label in labels],
|
||||
'affinity_groups': [
|
||||
group.name for group in groups
|
||||
if vm.name in [vm.name for vm in connection.follow_link(group.vms)]
|
||||
],
|
||||
'statistics': dict(
|
||||
(stat.name, stat.values[0].datum) for stat in stats
|
||||
),
|
||||
'devices': dict(
|
||||
(device.name, [ip.address for ip in device.ips]) for device in devices
|
||||
),
|
||||
'ansible_host': devices[0].ips[0].address if len(devices) > 0 else None,
|
||||
}
|
||||
|
||||
|
||||
def get_data(connection, vm_name=None):
|
||||
"""
|
||||
Obtain data of `vm_name` if specified, otherwise obtain data of all vms.
|
||||
"""
|
||||
vms_service = connection.system_service().vms_service()
|
||||
clusters_service = connection.system_service().clusters_service()
|
||||
|
||||
if vm_name:
|
||||
vm = vms_service.list(search='name=%s' % vm_name) or [None]
|
||||
data = get_dict_of_struct(
|
||||
connection=connection,
|
||||
vm=vm[0],
|
||||
)
|
||||
else:
|
||||
vms = dict()
|
||||
data = defaultdict(list)
|
||||
for vm in vms_service.list():
|
||||
name = vm.name
|
||||
vm_service = vms_service.vm_service(vm.id)
|
||||
cluster_service = clusters_service.cluster_service(vm.cluster.id)
|
||||
|
||||
# Add vm to vms dict:
|
||||
vms[name] = get_dict_of_struct(connection, vm)
|
||||
|
||||
# Add vm to cluster group:
|
||||
cluster_name = connection.follow_link(vm.cluster).name
|
||||
data['cluster_%s' % cluster_name].append(name)
|
||||
|
||||
# Add vm to tag group:
|
||||
tags_service = vm_service.tags_service()
|
||||
for tag in tags_service.list():
|
||||
data['tag_%s' % tag.name].append(name)
|
||||
|
||||
# Add vm to status group:
|
||||
data['status_%s' % vm.status].append(name)
|
||||
|
||||
# Add vm to affinity group:
|
||||
for group in cluster_service.affinity_groups_service().list():
|
||||
if vm.name in [
|
||||
v.name for v in connection.follow_link(group.vms)
|
||||
]:
|
||||
data['affinity_group_%s' % group.name].append(vm.name)
|
||||
|
||||
# Add vm to affinity label group:
|
||||
affinity_labels_service = vm_service.affinity_labels_service()
|
||||
for label in affinity_labels_service.list():
|
||||
data['affinity_label_%s' % label.name].append(name)
|
||||
|
||||
data["_meta"] = {
|
||||
'hostvars': vms,
|
||||
}
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
connection = create_connection()
|
||||
|
||||
print(
|
||||
json.dumps(
|
||||
obj=get_data(
|
||||
connection=connection,
|
||||
vm_name=args.host,
|
||||
),
|
||||
sort_keys=args.pretty,
|
||||
indent=args.pretty * 2,
|
||||
)
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
1
contrib/inventory/rhv.py
Symbolic link
1
contrib/inventory/rhv.py
Symbolic link
|
@ -0,0 +1 @@
|
|||
ovirt4.py
|
Loading…
Reference in a new issue