From eab023f8dbfa39732fa646b7649305be0c19e96a Mon Sep 17 00:00:00 2001
From: Andy Hill <hillad@gmail.com>
Date: Wed, 1 Oct 2014 19:56:08 -0400
Subject: [PATCH] Add xenserver_facts module

This module gathers facts about a XenServer host, gathering them in a single
connection instead of multiple xe commands.
---
 .../modules/extras/cloud/xenserver_facts.py   | 196 ++++++++++++++++++
 1 file changed, 196 insertions(+)
 create mode 100644 lib/ansible/modules/extras/cloud/xenserver_facts.py

diff --git a/lib/ansible/modules/extras/cloud/xenserver_facts.py b/lib/ansible/modules/extras/cloud/xenserver_facts.py
new file mode 100644
index 00000000000..1977f9fe2b8
--- /dev/null
+++ b/lib/ansible/modules/extras/cloud/xenserver_facts.py
@@ -0,0 +1,196 @@
+#!/usr/bin/python -tt
+# 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/>.
+
+
+DOCUMENTATION = '''
+---
+module: xenserver_facts
+version_added: 1.7
+short_description: get facts reported on xenserver
+description:
+  - Reads data out of XenAPI, can be used instead of multiple xe commands.
+author: Andy Hill, Tim Rupp
+'''
+
+import platform
+import sys
+import XenAPI
+
+EXAMPLES = '''
+- name: Gather facts from xenserver
+   xenserver:
+
+- name: Print running VMs
+  debug: msg="{{ item }}"
+  with_items: xs_vms.keys()
+  when: xs_vms[item]['power_state'] == "Running"
+
+TASK: [Print running VMs] ***********************************************************
+skipping: [10.13.0.22] => (item=CentOS 4.7 (32-bit))
+ok: [10.13.0.22] => (item=Control domain on host: 10.0.13.22) => {
+    "item": "Control domain on host: 10.0.13.22",
+    "msg": "Control domain on host: 10.0.13.22"
+}
+'''
+
+class XenServerFacts:
+    def __init__(self):
+        self.codes = {
+            '5.5.0': 'george',
+            '5.6.100': 'oxford',
+            '6.0.0': 'boston',
+            '6.1.0': 'tampa',
+            '6.2.0': 'clearwater'
+        }
+
+    @property
+    def version(self):
+        # Be aware! Deprecated in Python 2.6!
+        result = platform.dist()[1]
+        return result
+
+    @property
+    def codename(self):
+        if self.version in self.codes:
+            result = self.codes[self.version]
+        else:
+            result = None
+
+        return result
+
+
+def get_xenapi_session():
+    try:
+        session = XenAPI.xapi_local()
+        session.xenapi.login_with_password('', '')
+        return session
+    except XenAPI.Failure:
+        sys.exit(1)
+
+
+def get_networks(session):
+    recs = session.xenapi.network.get_all_records()
+    xs_networks = {}
+    networks = change_keys(recs, key='uuid')
+    for network in networks.itervalues():
+        xs_networks[network['name_label']] = network
+    return xs_networks
+
+
+def get_pifs(session):
+    recs = session.xenapi.PIF.get_all_records()
+    pifs = change_keys(recs, key='uuid')
+    xs_pifs = {}
+    devicenums = range(0, 7)
+    for pif in pifs.itervalues():
+        for eth in devicenums:
+            interface_name = "eth%s" % (eth)
+            bond_name = interface_name.replace('eth', 'bond')
+            if pif['device'] == interface_name:
+                xs_pifs[interface_name] = pif
+            elif pif['device'] == bond_name:
+                xs_pifs[bond_name] = pif
+    return xs_pifs
+
+
+def get_vlans(session):
+    recs = session.xenapi.VLAN.get_all_records()
+    return change_keys(recs, key='tag')
+
+
+def change_keys(recs, key='uuid', filter_func=None):
+    """
+    Take a xapi dict, and make the keys the value of recs[ref][key].
+
+    Preserves the ref in rec['ref']
+
+    """
+    new_recs = {}
+
+    for ref, rec in recs.iteritems():
+        if filter_func is not None and not filter_func(rec):
+            continue
+
+        new_recs[rec[key]] = rec
+        new_recs[rec[key]]['ref'] = ref
+
+    return new_recs
+
+def get_host(session):
+    """Get the host"""
+    host_recs = session.xenapi.host.get_all()
+    # We only have one host, so just return its entry
+    return session.xenapi.host.get_record(host_recs[0])
+
+def get_vms(session):
+    xs_vms = {}
+    recs = session.xenapi.VM.get_all()
+    if not recs:
+        return None
+
+    vms = change_keys(recs, key='uuid')
+    for vm in vms.itervalues():
+       xs_vms[vm['name_label']] = vm
+    return xs_vms
+
+
+def get_srs(session):
+    xs_srs = {}
+    recs = session.xenapi.SR.get_all()
+    if not recs:
+        return None
+    srs = change_keys(recs, key='uuid')
+    for sr in srs.itervalues():
+       xs_srs[sr['name_label']] = sr
+    return xs_srs
+
+def main():
+    module = AnsibleModule({})
+
+    obj = XenServerFacts()
+    session = get_xenapi_session()
+
+
+    data = {
+        'xenserver_version': obj.version,
+        'xenserver_codename': obj.codename
+    }
+
+    xs_networks = get_networks(session)
+    xs_pifs = get_pifs(session)
+    xs_vlans = get_vlans(session)
+    xs_vms = get_vms(session)
+    xs_srs = get_srs(session)
+
+    if xs_vlans:
+        data['xs_vlans'] = xs_vlans
+    if xs_pifs:
+        data['xs_pifs'] = xs_pifs
+    if xs_networks:
+        data['xs_networks'] = xs_networks
+
+    if xs_vms:
+        data['xs_vms'] = xs_vms
+
+    if xs_srs:
+        data['xs_srs'] = xs_srs
+
+    module.exit_json(ansible=data)
+
+# this is magic, see lib/ansible/module_common.py
+#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
+
+main()