apex integration 13/33413/4
authorzhihui wu <wu.zhihui1@zte.com.cn>
Mon, 17 Apr 2017 08:16:45 +0000 (16:16 +0800)
committerzhihui wu <wu.zhihui1@zte.com.cn>
Tue, 18 Apr 2017 01:04:40 +0000 (09:04 +0800)
Change-Id: Ief21554dfa7cd79e7ed0cb1615f6dbf079cb6077
Signed-off-by: zhihui wu <wu.zhihui1@zte.com.cn>
qtip/ansible_library/modules/apex.py [new file with mode: 0644]
tests/data/external/apex/baremetal_info.json [new file with mode: 0755]
tests/data/external/apex/server_info.json [new file with mode: 0755]
tests/unit/ansible_library/modules/apex_test.py [new file with mode: 0644]

diff --git a/qtip/ansible_library/modules/apex.py b/qtip/ansible_library/modules/apex.py
new file mode 100644 (file)
index 0000000..218440b
--- /dev/null
@@ -0,0 +1,133 @@
+#!/usr/bin/python
+
+###############################################################
+# Copyright (c) 2017 ZTE Corporation
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+from collections import defaultdict
+import json
+import re
+
+from ansible.module_utils.basic import AnsibleModule
+
+
+ANSIBLE_METADATA = {'metadata_version': '1.0',
+                    'status': ['preview'],
+                    'supported_by': 'community'}
+
+DOCUMENTATION = '''
+---
+module: apex
+short_description: collecting facts from apex environments
+description:
+    - Use this module to create a dynamic inventory from apex undercloud.
+version_added: "2.2"
+author: "Zhihui Wu"
+options:
+notes:
+requirements:
+    - Host 'apex-undercloud' is in ~/.ssh/config
+'''
+
+RETURN = '''
+ansible_facts:
+  description: facts collected for ansible
+  returned: success
+  type: dictionary
+  contains:
+    hosts:
+      description: host grouped by hostname, cluster, role and manufacture
+      type: dict
+    hosts_meta:
+      description: hosts meta data indexed by hostname
+      type: dict
+'''
+
+EXAMPLES = '''
+---
+- hosts: apex-undercloud
+  tasks:
+  - name: collect facts of apex hosts
+    apex:
+  - debug: var=hostvarsi
+  - name: add compute node to ansible inventory
+    add_host:
+      name: "{{ hosts_meta[item]['ip'] }}"
+      groups: compute
+      ansible_user: root
+      ansible_ssh_common_args: '-o StrictHostKeyChecking=No -o ProxyJump=apex-master'
+    with_items: "{{ hosts.compute }}"
+- hosts: compute
+  tasks:
+  - name: check ssh connection
+    ping:
+'''
+
+
+def generate_inventory(baremetal_info, server_info):
+    """Generate ansible inventory from node list in json format
+
+    Modified from https://github.com/martineg/ansible-apex-inventory/blob/master/apex.py
+    """
+
+    hosts = defaultdict(list)
+    hosts_meta = {}
+
+    for node in baremetal_info:
+        if node['Provisioning State'].lower() == 'active':
+            role = re.findall('.+profile:(\w+)$', node['Properties']['capabilities'])[0]
+            for server in server_info:
+                if server['ID'] == node['Instance UUID']:
+                    node_ip = re.findall('.+=(\d+.\d+.\d+.\d+)$', server['Networks'])[0]
+                    hosts[role].append(node_ip)
+                    # To match ssh.cfg.j2 template
+                    hosts_meta[node_ip] = {'ansible_ssh_host': node_ip}
+
+    for host in hosts:
+        hosts[host].sort()
+
+    return {'hosts': hosts, 'hosts_meta': hosts_meta}
+
+
+def main():
+    module = AnsibleModule(argument_spec=dict())
+
+    (rc, out, err) = module.run_command(['source ~/stackrc'])
+
+    if rc is not None and rc != 0:
+        return module.fail_json(msg=err)
+
+    cmd = [module.get_bin_path('openstack', True),
+           'baremetal',
+           'list',
+           '--fields instance_uuid properties provision_state',
+           '--format json']
+    (rc, out, err) = module.run_command(cmd)
+
+    if rc is not None and rc != 0:
+        return module.fail_json(msg=err)
+
+    baremetal_info = json.loads(out)
+
+    cmd = [module.get_bin_path('openstack', True),
+           'server',
+           'list',
+           '--format json']
+    (rc, out, err) = module.run_command(cmd)
+
+    if rc is not None and rc != 0:
+        return module.fail_json(msg=err)
+
+    server_info = json.loads(out)
+
+    module.exit_json(changed=False,
+                     ansible_facts=generate_inventory(baremetal_info, server_info))
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tests/data/external/apex/baremetal_info.json b/tests/data/external/apex/baremetal_info.json
new file mode 100755 (executable)
index 0000000..8efe4e7
--- /dev/null
@@ -0,0 +1,57 @@
+[
+  {
+    "Properties": {
+      "memory_mb": "8192",
+      "cpu_arch": "x86_64",
+      "local_gb": "41",
+      "cpus": "4",
+      "capabilities": "boot_option:local,profile:compute"
+    },
+    "Provisioning State": "active",
+    "Instance UUID": "367827af-966c-4c91-bad4-d8dc12750eac"
+  },
+  {
+    "Properties": {
+      "memory_mb": "8192",
+      "cpu_arch": "x86_64",
+      "local_gb": "41",
+      "cpus": "4",
+      "capabilities": "boot_option:local,profile:compute"
+    },
+    "Provisioning State": "active",
+    "Instance UUID": "f214f844-ec4d-4f33-9d16-9aa21ade3cb4"
+  },
+  {
+    "Properties": {
+      "memory_mb": "8192",
+      "cpu_arch": "x86_64",
+      "local_gb": "41",
+      "cpus": "4",
+      "capabilities": "boot_option:local,profile:control"
+    },
+    "Provisioning State": "active",
+    "Instance UUID": "06234a4d-45fb-4930-bf8a-9b1627b1621f"
+  },
+  {
+    "Properties": {
+      "memory_mb": "8192",
+      "cpu_arch": "x86_64",
+      "local_gb": "41",
+      "cpus": "4",
+      "capabilities": "boot_option:local,profile:control"
+    },
+    "Provisioning State": "active",
+    "Instance UUID": "6dfd4c85-8a05-49ea-bd73-15dbaf84fa9b"
+  },
+  {
+    "Properties": {
+      "memory_mb": "8192",
+      "cpu_arch": "x86_64",
+      "local_gb": "41",
+      "cpus": "4",
+      "capabilities": "boot_option:local,profile:control"
+    },
+    "Provisioning State": "active",
+    "Instance UUID": "25b73b47-7c22-4f58-8ff3-ba5d714baa7c"
+  }
+]
diff --git a/tests/data/external/apex/server_info.json b/tests/data/external/apex/server_info.json
new file mode 100755 (executable)
index 0000000..71bc40c
--- /dev/null
@@ -0,0 +1,37 @@
+[
+  {
+    "Status": "ACTIVE",
+    "Networks": "ctlplane=192.0.2.9",
+    "ID": "06234a4d-45fb-4930-bf8a-9b1627b1621f",
+    "Image Name": "overcloud-full",
+    "Name": "overcloud-controller-2"
+  },
+  {
+    "Status": "ACTIVE",
+    "Networks": "ctlplane=192.0.2.7",
+    "ID": "6dfd4c85-8a05-49ea-bd73-15dbaf84fa9b",
+    "Image Name": "overcloud-full",
+    "Name": "overcloud-controller-0"
+  },
+  {
+    "Status": "ACTIVE",
+    "Networks": "ctlplane=192.0.2.8",
+    "ID": "25b73b47-7c22-4f58-8ff3-ba5d714baa7c",
+    "Image Name": "overcloud-full",
+    "Name": "overcloud-controller-1"
+  },
+  {
+    "Status": "ACTIVE",
+    "Networks": "ctlplane=192.0.2.6",
+    "ID": "f214f844-ec4d-4f33-9d16-9aa21ade3cb4",
+    "Image Name": "overcloud-full",
+    "Name": "overcloud-novacompute-0"
+  },
+  {
+    "Status": "ACTIVE",
+    "Networks": "ctlplane=192.0.2.5",
+    "ID": "367827af-966c-4c91-bad4-d8dc12750eac",
+    "Image Name": "overcloud-full",
+    "Name": "overcloud-novacompute-1"
+  }
+]
\ No newline at end of file
diff --git a/tests/unit/ansible_library/modules/apex_test.py b/tests/unit/ansible_library/modules/apex_test.py
new file mode 100644 (file)
index 0000000..8a1d067
--- /dev/null
@@ -0,0 +1,30 @@
+###############################################################
+# Copyright (c) 2017 ZTE Corporation
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+import json
+import os
+
+from qtip.ansible_library.modules import apex
+
+
+def test_generate_inventory(data_root):
+    baremetal_info = json.load(open(os.path.join(data_root, 'external',
+                                                 'apex', 'baremetal_info.json')))
+    server_info = json.load(open(os.path.join(data_root, 'external',
+                                              'apex', 'server_info.json')))
+    inventory = apex.generate_inventory(baremetal_info, server_info)
+    assert dict(inventory['hosts']) == {
+        u'compute': [u'192.0.2.5', u'192.0.2.6'],
+        u'control': [u'192.0.2.7', u'192.0.2.8', u'192.0.2.9']}
+    assert dict(inventory['hosts_meta']) == {
+        u'192.0.2.5': {'ansible_ssh_host': u'192.0.2.5'},
+        u'192.0.2.6': {'ansible_ssh_host': u'192.0.2.6'},
+        u'192.0.2.7': {'ansible_ssh_host': u'192.0.2.7'},
+        u'192.0.2.8': {'ansible_ssh_host': u'192.0.2.8'},
+        u'192.0.2.9': {'ansible_ssh_host': u'192.0.2.9'}}