xci: osa: Add initial dynamic inventory from PDF/IDF files 29/56929/10
authorMarkos Chandras <mchandras@suse.de>
Tue, 1 May 2018 15:38:13 +0000 (16:38 +0100)
committerMarkos Chandras <mchandras@suse.de>
Wed, 9 May 2018 07:15:47 +0000 (08:15 +0100)
The PDF and IDF files contain all the information we need for the
virtual XCI deployment, so we can use it to create a dynamic inventory
and get rid of all the static ones which could easily get outdated
as PDF and IDF files evolve over time.

This inital version of the dynamic inventory contains a lot of
unnecessary generated information but we do that in order to ease
the migration from static files to the dynamic inventory. The dynamic
inventory will be improved in the future as we consume more and more
information from the PDF and IDF files.

Change-Id: Id9f07a61c67a5cffcbc18079a341e5d395020a27
Signed-off-by: Markos Chandras <mchandras@suse.de>
15 files changed:
xci/installer/osa/deploy.sh
xci/installer/osa/files/aio/flavor-vars.yml [deleted file]
xci/installer/osa/files/aio/inventory [deleted file]
xci/installer/osa/files/ha/flavor-vars.yml [deleted file]
xci/installer/osa/files/ha/inventory [deleted file]
xci/installer/osa/files/mini/flavor-vars.yml [deleted file]
xci/installer/osa/files/mini/inventory [deleted file]
xci/installer/osa/files/noha/flavor-vars.yml [deleted file]
xci/installer/osa/files/noha/inventory [deleted file]
xci/installer/osa/playbooks/configure-opnfvhost.yml
xci/installer/osa/playbooks/configure-targethosts.yml
xci/playbooks/dynamic_inventory.py [new file with mode: 0755]
xci/playbooks/roles/bootstrap-host/tasks/network_debian.yml
xci/playbooks/roles/bootstrap-host/tasks/network_redhat.yml
xci/playbooks/roles/bootstrap-host/tasks/network_suse.yml

index 6dada3f..c3a6eb8 100755 (executable)
@@ -58,7 +58,7 @@ echo "Info: Configuring opnfv deployment host for openstack-ansible"
 echo "-----------------------------------------------------------------------"
 cd $OSA_XCI_PLAYBOOKS
 ansible-galaxy install -r ${XCI_PATH}/xci/files/requirements.yml -p $HOME/.ansible/roles
-ansible-playbook ${XCI_ANSIBLE_PARAMS} -i ${XCI_FLAVOR_ANSIBLE_FILE_PATH}/inventory \
+ansible-playbook ${XCI_ANSIBLE_PARAMS} -i ${XCI_PLAYBOOKS}/dynamic_inventory.py \
     configure-opnfvhost.yml
 echo "-----------------------------------------------------------------------"
 echo "Info: Configured opnfv deployment host for openstack-ansible"
@@ -78,7 +78,7 @@ if [[ $XCI_FLAVOR != "aio" ]]; then
     echo "Info: Configuring target hosts for openstack-ansible"
     echo "-----------------------------------------------------------------------"
     cd $OSA_XCI_PLAYBOOKS
-    ansible-playbook ${XCI_ANSIBLE_PARAMS} -i ${XCI_FLAVOR_ANSIBLE_FILE_PATH}/inventory \
+    ansible-playbook ${XCI_ANSIBLE_PARAMS} -i ${XCI_PLAYBOOKS}/dynamic_inventory.py \
         configure-targethosts.yml
     echo "-----------------------------------------------------------------------"
     echo "Info: Configured target hosts"
diff --git a/xci/installer/osa/files/aio/flavor-vars.yml b/xci/installer/osa/files/aio/flavor-vars.yml
deleted file mode 100644 (file)
index 6ac1e0f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
----
-# this file is added intentionally in order to simplify putting files in place
-# in future, it might contain vars specific to this flavor
diff --git a/xci/installer/osa/files/aio/inventory b/xci/installer/osa/files/aio/inventory
deleted file mode 100644 (file)
index fa2a100..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-[deployment]
-opnfv ansible_ssh_host=192.168.122.2
diff --git a/xci/installer/osa/files/ha/flavor-vars.yml b/xci/installer/osa/files/ha/flavor-vars.yml
deleted file mode 100644 (file)
index 167502c..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
----
-host_info: {
-    'opnfv': {
-        'VLAN_IP': '192.168.122.2',
-        'MGMT_IP': '172.29.236.10',
-        'VXLAN_IP': '172.29.240.10',
-        'STORAGE_IP': '172.29.244.10'
-    },
-    'controller00': {
-        'VLAN_IP': '192.168.122.3',
-        'MGMT_IP': '172.29.236.11',
-        'VXLAN_IP': '172.29.240.11',
-        'STORAGE_IP': '172.29.244.11'
-    },
-    'controller01': {
-        'VLAN_IP': '192.168.122.4',
-        'MGMT_IP': '172.29.236.12',
-        'VXLAN_IP': '172.29.240.12',
-        'STORAGE_IP': '172.29.244.12'
-    },
-    'controller02': {
-        'VLAN_IP': '192.168.122.5',
-        'MGMT_IP': '172.29.236.13',
-        'VXLAN_IP': '172.29.240.13',
-        'STORAGE_IP': '172.29.244.13'
-    },
-    'compute00': {
-        'VLAN_IP': '192.168.122.6',
-        'MGMT_IP': '172.29.236.14',
-        'VXLAN_IP': '172.29.240.14',
-        'STORAGE_IP': '172.29.244.14'
-    },
-    'compute01': {
-        'VLAN_IP': '192.168.122.7',
-        'MGMT_IP': '172.29.236.15',
-        'VXLAN_IP': '172.29.240.15',
-        'STORAGE_IP': '172.29.244.15'
-    }
-}
diff --git a/xci/installer/osa/files/ha/inventory b/xci/installer/osa/files/ha/inventory
deleted file mode 100644 (file)
index f5d882e..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-[deployment]
-opnfv ansible_ssh_host=192.168.122.2
-
-[controller]
-controller00 ansible_ssh_host=192.168.122.3
-controller01 ansible_ssh_host=192.168.122.4
-controller02 ansible_ssh_host=192.168.122.5
-
-[compute]
-compute00 ansible_ssh_host=192.168.122.6
-compute01 ansible_ssh_host=192.168.122.7
-
-[openstack:children]
-controller
-compute
diff --git a/xci/installer/osa/files/mini/flavor-vars.yml b/xci/installer/osa/files/mini/flavor-vars.yml
deleted file mode 100644 (file)
index 0d446ba..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
----
-host_info: {
-    'opnfv': {
-        'VLAN_IP': '192.168.122.2',
-        'MGMT_IP': '172.29.236.10',
-        'VXLAN_IP': '172.29.240.10',
-        'STORAGE_IP': '172.29.244.10'
-    },
-    'controller00': {
-        'VLAN_IP': '192.168.122.3',
-        'MGMT_IP': '172.29.236.11',
-        'VXLAN_IP': '172.29.240.11',
-        'STORAGE_IP': '172.29.244.11'
-    },
-    'compute00': {
-        'VLAN_IP': '192.168.122.4',
-        'MGMT_IP': '172.29.236.12',
-        'VXLAN_IP': '172.29.240.12',
-        'STORAGE_IP': '172.29.244.12'
-    },
-}
diff --git a/xci/installer/osa/files/mini/inventory b/xci/installer/osa/files/mini/inventory
deleted file mode 100644 (file)
index 4224131..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-[deployment]
-opnfv ansible_ssh_host=192.168.122.2
-
-[controller]
-controller00 ansible_ssh_host=192.168.122.3
-
-[compute]
-compute00 ansible_ssh_host=192.168.122.4
-
-[openstack:children]
-controller
-compute
diff --git a/xci/installer/osa/files/noha/flavor-vars.yml b/xci/installer/osa/files/noha/flavor-vars.yml
deleted file mode 100644 (file)
index 3c69a34..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
----
-host_info: {
-    'opnfv': {
-        'VLAN_IP': '192.168.122.2',
-        'MGMT_IP': '172.29.236.10',
-        'VXLAN_IP': '172.29.240.10',
-        'STORAGE_IP': '172.29.244.10'
-    },
-    'controller00': {
-        'VLAN_IP': '192.168.122.3',
-        'MGMT_IP': '172.29.236.11',
-        'VXLAN_IP': '172.29.240.11',
-        'STORAGE_IP': '172.29.244.11'
-    },
-    'compute00': {
-        'VLAN_IP': '192.168.122.4',
-        'MGMT_IP': '172.29.236.12',
-        'VXLAN_IP': '172.29.240.12',
-        'STORAGE_IP': '172.29.244.12'
-    },
-    'compute01': {
-        'VLAN_IP': '192.168.122.5',
-        'MGMT_IP': '172.29.236.13',
-        'VXLAN_IP': '172.29.240.13',
-        'STORAGE_IP': '172.29.244.13'
-    }
-}
diff --git a/xci/installer/osa/files/noha/inventory b/xci/installer/osa/files/noha/inventory
deleted file mode 100644 (file)
index 0e3b8d8..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-[deployment]
-opnfv ansible_ssh_host=192.168.122.2
-
-[controller]
-controller00 ansible_ssh_host=192.168.122.3
-
-[compute]
-compute00 ansible_ssh_host=192.168.122.4
-compute01 ansible_ssh_host=192.168.122.5
-
-[openstack:children]
-controller
-compute
index e277098..c92abd9 100644 (file)
@@ -26,7 +26,6 @@
         file: "{{ item }}"
       with_items:
         - "{{ xci_path }}/xci/var/{{ ansible_os_family }}.yml"
-        - "{{ xci_flavor_ansible_file_path }}/flavor-vars.yml"
     - name: Set facts for remote deployment
       set_fact:
         remote_xci_path: "{{ ansible_env.HOME }}/releng-xci"
@@ -74,7 +73,6 @@
         - { src: "{{ openstack_osa_path }}/etc/openstack_deploy/env.d", dest: "{{ openstack_osa_etc_path }}" }
         - { src: "{{ openstack_osa_path }}/etc/openstack_deploy/conf.d", dest: "{{ openstack_osa_etc_path }}" }
         - { src: "{{ openstack_osa_path }}/etc/openstack_deploy/user_secrets.yml", dest: "{{ openstack_osa_etc_path }}" }
-        - { src: "{{ remote_xci_flavor_files }}/inventory", dest: "{{ remote_xci_playbooks }}" }
         - { src: "{{ remote_xci_flavor_files }}/openstack_user_config.yml", dest: "{{ openstack_osa_etc_path }}" }
         - { src: "{{ remote_xci_flavor_files }}/user_variables.yml", dest: "{{ openstack_osa_etc_path }}" }
         - { src: "{{ remote_xci_flavor_files }}/ceph.yml", dest: "{{ openstack_osa_etc_path }}/conf.d/", cond: xci_ceph_enabled }
index cb817cf..a5d2923 100644 (file)
@@ -17,7 +17,6 @@
         file: "{{ item }}"
       with_items:
         - "{{ xci_path }}/xci/var/{{ ansible_os_family }}.yml"
-        - "{{ xci_flavor_ansible_file_path }}/flavor-vars.yml"
   roles:
     - role: peru.proxy_settings
       proxy_settings_http_proxy: "{{ lookup('env','http_proxy') }}"
diff --git a/xci/playbooks/dynamic_inventory.py b/xci/playbooks/dynamic_inventory.py
new file mode 100755 (executable)
index 0000000..8f49874
--- /dev/null
@@ -0,0 +1,153 @@
+#!/usr/bin/python
+# coding utf-8
+
+# SPDX-license-identifier: Apache-2.0
+##############################################################################
+# Copyright (c) 2018 SUSE LINUX GmbH.
+# 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
+##############################################################################
+#
+# Based on https://raw.githubusercontent.com/ansible/ansible/devel/contrib/inventory/cobbler.py
+
+import argparse
+import os
+import sys
+import yaml
+import json
+
+
+class XCIInventory(object):
+    def __init__(self):
+        super(XCIInventory, self).__init__()
+        self.inventory = {}
+        self.inventory['all'] = {}
+        self.inventory['all']['hosts'] = []
+        self.inventory['all']['vars'] = {}
+        self.inventory['_meta'] = {}
+        self.inventory['_meta']['hostvars'] = {}
+        self.installer = os.environ.get('INSTALLER_TYPE', 'osa')
+        self.flavor = os.environ.get('XCI_FLAVOR', 'mini')
+
+        # Static information for opnfv host for now
+        self.add_host('opnfv')
+        self.add_hostvar('opnfv', 'ansible_ssh_host', '192.168.122.2')
+        self.add_to_group('deployment', 'opnfv')
+        self.add_to_group('opnfv', 'opnfv')
+
+        self.opnfv_networks = {}
+        self.opnfv_networks['opnfv'] = {}
+        self.opnfv_networks['opnfv']['admin'] = '172.29.236.10'
+        self.opnfv_networks['opnfv']['public'] = '192.168.122.2'
+        self.opnfv_networks['opnfv']['private'] = '172.29.240.10'
+        self.opnfv_networks['opnfv']['storage'] = '172.29.244.10'
+
+        self.read_pdf_idf()
+
+        self.parse_args()
+
+        if self.args.host:
+            self.dump(self.get_host_info(self.args.host))
+        else:
+            self.dump(self.inventory)
+
+    def parse_args(self):
+        parser = argparse.ArgumentParser(description='Produce an Ansible inventory based on PDF/IDF XCI files')
+        parser.add_argument('--list', action='store_true', default=True, help='List XCI hosts (default: True)')
+        parser.add_argument('--host', action='store', help='Get all the variables about a specific host')
+        self.args = parser.parse_args()
+
+    def read_pdf_idf(self):
+        pdf_file = os.path.dirname(os.path.realpath(__file__)) + "/../var/pdf.yml"
+        idf_file = os.path.dirname(os.path.realpath(__file__)) + "/../var/idf.yml"
+        nodes = []
+        host_networks = {}
+
+        with open(pdf_file) as f:
+            try:
+                pdf = yaml.safe_load(f)
+            except yaml.YAMLError as e:
+                print(e)
+                sys.exit(1)
+
+        with open(idf_file) as f:
+            try:
+                idf = yaml.safe_load(f)
+            except yaml.YAMLError as e:
+                print(e)
+                sys.exit(1)
+
+        valid_host = (host for host in idf['xci'][self.installer]['nodes_roles'] \
+                      if host in idf['xci']['flavors'][self.flavor] \
+                      and host != 'opnfv')
+
+        for host in valid_host:
+            nodes.append(host)
+            hostname = idf['xci'][self.installer]['hostnames'][host]
+            self.add_host(hostname)
+            for role in idf['xci'][self.installer]['nodes_roles'][host]:
+                self.add_to_group(role, hostname)
+
+            pdf_host_info = filter(lambda x: x['name'] == host, pdf['nodes'])[0]
+            native_vlan_if = filter(lambda x: x['vlan'] == 'native', pdf_host_info['interfaces'])
+            self.add_hostvar(hostname, 'ansible_host', native_vlan_if[0]['address'])
+            host_networks[hostname] = {}
+            # And now record the rest of the information
+            for network in idf['idf']['net_config'].keys():
+                network_interface_num = idf['idf']['net_config'][network]['interface']
+                host_networks[hostname][network] = pdf_host_info['interfaces'][int(network_interface_num)]['address']
+
+            host_networks.update(self.opnfv_networks)
+
+            self.add_groupvar('all', 'host_info', host_networks)
+
+        # Now add the additional groups
+        for parent in idf['xci'][self.installer]['groups'].keys():
+            map(lambda x: self.add_group(x, parent), idf['xci'][self.installer]['groups'][parent])
+
+    def dump(self, data):
+        print (json.dumps(data, sort_keys=True, indent=2))
+
+    def add_host(self, host):
+        self.inventory['all']['hosts'].append(host)
+
+    def hosts(self):
+        return self.inventory['all']['hosts']
+
+    def add_group(self, group, parent = 'all'):
+        if parent not in self.inventory.keys():
+            self.inventory[parent] = {}
+        if 'children' not in self.inventory[parent]:
+            self.inventory[parent]['children'] = []
+        self.inventory[parent]['children'].append(group)
+
+    def add_to_group(self, group, host):
+        if group not in self.inventory.keys():
+            self.inventory[group] = []
+        self.inventory[group].append(host)
+
+    def add_hostvar(self, host, param, value):
+        if host not in self.hostvars():
+            self.inventory['_meta']['hostvars'][host] = {}
+        self.inventory['_meta']['hostvars'][host].update({param: value})
+
+    def add_groupvar(self, group, param, value):
+        if group not in self.groupvars(group):
+            self.inventory[group]['vars'] = {}
+        self.inventory[group]['vars'].update({param: value})
+
+    def hostvars(self):
+        return iter(self.inventory['_meta']['hostvars'].keys())
+
+    def groupvars(self, group):
+        return iter(self.inventory[group]['vars'].keys())
+
+    def get_host_info(self, host):
+        return self.inventory['_meta']['hostvars'][host]
+
+if __name__ == '__main__':
+    XCIInventory()
+
+# vim: set ts=4 sw=4 expandtab:
index ddca58b..380e4c5 100644 (file)
     - { name: "{{ ansible_local.xci.network.xci_interface }}.10", vlan_id: 10 }
     - { name: "{{ ansible_local.xci.network.xci_interface }}.30", vlan_id: 30 }
     - { name: "{{ ansible_local.xci.network.xci_interface }}.20", vlan_id: 20 }
-    - { name: "br-mgmt", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}.10", ip: "{{ host_info[inventory_hostname].MGMT_IP }}", prefix: "255.255.252.0" }
-    - { name: "br-vxlan", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}.30", ip: "{{ host_info[inventory_hostname].VXLAN_IP }}", prefix: "255.255.252.0" }
-    - { name: "br-vlan", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}", ip: "{{ host_info[inventory_hostname].VLAN_IP }}", prefix: "255.255.255.0", gateway: "192.168.122.1" }
-    - { name: "br-storage", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}.20", ip: "{{ host_info[inventory_hostname].STORAGE_IP }}", prefix: "255.255.252.0" }
+    - { name: "br-mgmt", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}.10", ip: "{{ host_info[inventory_hostname].admin }}", prefix: "255.255.252.0" }
+    - { name: "br-vxlan", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}.30", ip: "{{ host_info[inventory_hostname].private }}", prefix: "255.255.252.0" }
+    - { name: "br-vlan", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}", ip: "{{ host_info[inventory_hostname].public }}", prefix: "255.255.255.0", gateway: "192.168.122.1" }
+    - { name: "br-storage", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}.20", ip: "{{ host_info[inventory_hostname].storage }}", prefix: "255.255.252.0" }
   loop_control:
     label: "{{ item.name }}"
 
index 8c98203..9dce50b 100644 (file)
     - { name: "{{ ansible_local.xci.network.xci_interface }}.10", bridge: "br-mgmt"   , vlan_id: 10 }
     - { name: "{{ ansible_local.xci.network.xci_interface }}.20", bridge: "br-storage", vlan_id: 20 }
     - { name: "{{ ansible_local.xci.network.xci_interface }}.30", bridge: "br-vxlan"  , vlan_id: 30 }
-    - { name: "br-vlan"   , ip: "{{ host_info[inventory_hostname].VLAN_IP }}",    prefix: 24 }
-    - { name: "br-mgmt"   , ip: "{{ host_info[inventory_hostname].MGMT_IP }}",    prefix: 22 }
-    - { name: "br-storage", ip: "{{ host_info[inventory_hostname].STORAGE_IP }}", prefix: 22 }
-    - { name: "br-vxlan"  , ip: "{{ host_info[inventory_hostname].VXLAN_IP }}",   prefix: 22 }
+    - { name: "br-vlan"   , ip: "{{ host_info[inventory_hostname].public }}",    prefix: 24 }
+    - { name: "br-mgmt"   , ip: "{{ host_info[inventory_hostname].admin }}",    prefix: 22 }
+    - { name: "br-storage", ip: "{{ host_info[inventory_hostname].storage }}", prefix: 22 }
+    - { name: "br-vxlan"  , ip: "{{ host_info[inventory_hostname].private}}",   prefix: 22 }
   loop_control:
     label: "{{ item.name }}"
 
index 6ad1316..b1059c8 100644 (file)
     - { name: "{{ ansible_local.xci.network.xci_interface }}.10", vlan_id: 10 }
     - { name: "{{ ansible_local.xci.network.xci_interface }}.30", vlan_id: 30 }
     - { name: "{{ ansible_local.xci.network.xci_interface }}.20", vlan_id: 20 }
-    - { name: "br-mgmt", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}.10", ip: "{{ host_info[inventory_hostname].MGMT_IP }}/22" }
-    - { name: "br-vxlan", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}.30", ip: "{{ host_info[inventory_hostname].VXLAN_IP }}/22" }
-    - { name: "br-vlan", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}", ip: "{{ host_info[inventory_hostname].VLAN_IP }}/24" }
-    - { name: "br-storage", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}.20", ip: "{{ host_info[inventory_hostname].STORAGE_IP }}/22" }
+    - { name: "br-mgmt", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}.10", ip: "{{ host_info[inventory_hostname].admin }}/22" }
+    - { name: "br-vxlan", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}.30", ip: "{{ host_info[inventory_hostname].private }}/22" }
+    - { name: "br-vlan", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}", ip: "{{ host_info[inventory_hostname].public }}/24" }
+    - { name: "br-storage", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}.20", ip: "{{ host_info[inventory_hostname].storage }}/22" }
   loop_control:
     label: "{{ item.name }}"