Adds declaring disk device to use on overcloud nodes 55/25255/6
authorTim Rozet <trozet@redhat.com>
Wed, 30 Nov 2016 16:03:02 +0000 (11:03 -0500)
committerTim Rozet <trozet@redhat.com>
Tue, 20 Dec 2016 21:16:31 +0000 (21:16 +0000)
Now in inventory file a user can declare 'disk_device' which will allow
the user to specify which disk on their overcloud server to use for
installation.  The variable can be a comma delimited list, which will
search in order post-introspection for the first device on the node that
exists.  The default disk used will be sda for deployments.

Currently defining a per node disk is not supported by OSCLI, so
although defined that way in Apex inventory, only the last definition
will be used for all nodes.

Other changes include:
 - Various fixes in inventory parsing
 - Makes bash writing a common function
 - Introspection now enabled for baremetal deployments

JIRA: APEX-296

Change-Id: I330d91eb17408ccfceb7a99c25edbae5ce6d848d
Signed-off-by: Tim Rozet <trozet@redhat.com>
config/inventory/pod_example_settings.yaml
docs/installationprocedure/baremetal.rst
lib/overcloud-deploy-functions.sh
lib/parse-functions.sh
lib/python/apex/common/constants.py
lib/python/apex/common/utils.py
lib/python/apex/deploy_settings.py
lib/python/apex/inventory.py
lib/python/apex/network_settings.py
lib/python/apex_python_utils.py
tests/test_apex_inventory.py

index 3e34abe..c08b30c 100644 (file)
@@ -8,6 +8,7 @@ nodes:
     cpus: 2
     memory: 8192
     disk: 40
+    disk_device: sdb
     arch: "x86_64"
     capabilities: "profile:control"
   node2:
@@ -19,6 +20,7 @@ nodes:
     cpus: 2
     memory: 8192
     disk: 40
+    disk_device: sdb
     arch: "x86_64"
     capabilities: "profile:control"
   node3:
@@ -30,6 +32,7 @@ nodes:
     cpus: 2
     memory: 8192
     disk: 40
+    disk_device: sdb
     arch: "x86_64"
     capabilities: "profile:control"
   node4:
@@ -41,6 +44,7 @@ nodes:
     cpus: 2
     memory: 8192
     disk: 40
+    disk_device: sdb
     arch: "x86_64"
     capabilities: "profile:compute"
   node5:
@@ -52,5 +56,6 @@ nodes:
     cpus: 2
     memory: 8192
     disk: 40
+    disk_device: sdb
     arch: "x86_64"
     capabilities: "profile:compute"
index 15c80c3..83cda32 100644 (file)
@@ -202,6 +202,7 @@ IPMI configuration information gathered in section
     - ``cpus``: (Introspected*) CPU cores available
     - ``memory``: (Introspected*) Memory available in Mib
     - ``disk``: (Introspected*) Disk space available in Gb
+    - ``disk_device``: (Opt***) Root disk device to use for installation
     - ``arch``: (Introspected*) System architecture
     - ``capabilities``: (Opt**) Node's role in deployment
         values: profile:control or profile:compute
@@ -213,6 +214,14 @@ IPMI configuration information gathered in section
     ** If capabilities profile is not specified then Apex will select node's roles
     in the OPNFV cluster in a non-deterministic fashion.
 
+    \*** disk_device declares which hard disk to use as the root device for
+    installation.  The format is a comma delimited list of devices, such as
+    "sda,sdb,sdc".  The disk chosen will be the first device in the list which
+    is found by introspection to exist on the system.  Currently, only a single
+    definition is allowed for all nodes.  Therefore if multiple disk_device
+    definitions occur within the inventory, only the last definition on a node
+    will be used for all nodes.
+
 Creating the Settings Files
 ---------------------------
 
index 216fa6c..e1e6630 100755 (executable)
@@ -289,11 +289,19 @@ openstack overcloud image upload
 
 echo "Configuring undercloud and discovering nodes"
 openstack baremetal import --json instackenv.json
-openstack baremetal configure boot
+
 bash -x set_perf_images.sh ${performance_roles[@]}
-#if [[ -z "$virtual" ]]; then
-#  openstack baremetal introspection bulk start
-#fi
+if [[ -z "$virtual" ]]; then
+  openstack baremetal introspection bulk start
+  if [[ -n "$root_disk_list" ]]; then
+    openstack baremetal configure boot -root-device=${root_disk_list}
+  else
+    openstack baremetal configure boot
+  fi
+else
+  openstack baremetal configure boot
+fi
+
 echo "Configuring flavors"
 for flavor in baremetal control compute; do
   echo -e "${blue}INFO: Updating flavor: \${flavor}${reset}"
index 84da75c..b1a61c3 100755 (executable)
@@ -59,6 +59,7 @@ parse_deploy_settings() {
 ##params: none
 ##usage: parse_inventory_file
 parse_inventory_file() {
+  local output
   if [ "$virtual" == "TRUE" ]; then inv_virt="--virtual"; fi
   if [[ "$ha_enabled" == "True" ]]; then inv_ha="--ha"; fi
   instackenv_output=$(python3 -B $LIB/python/apex_python_utils.py parse-inventory -f $INVENTORY_FILE $inv_virt $inv_ha)
@@ -69,5 +70,12 @@ cat > instackenv.json << EOF
 $instackenv_output
 EOF
 EOI
+  if output=$(python3 -B $LIB/python/apex_python_utils.py parse-inventory -f $INVENTORY_FILE $inv_virt $inv_ha --export-bash); then
+    echo -e "${blue}${output}${reset}"
+    eval "$output"
+  else
+    echo -e "${red}ERROR: Failed to parse inventory bash settings file ${INVENTORY_FILE}${reset}"
+    exit 1
+  fi
 
 }
index 741bb4f..3aa28ea 100644 (file)
@@ -27,3 +27,4 @@ COMPUTE_PRE = "OS::TripleO::ComputeExtraConfigPre"
 CONTROLLER_PRE = "OS::TripleO::ControllerExtraConfigPre"
 PRE_CONFIG_DIR = "/usr/share/openstack-tripleo-heat-templates/puppet/" \
                  "extraconfig/pre_deploy/"
+DEFAULT_ROOT_DEV = 'sda'
index d623638..8e6896f 100644 (file)
@@ -21,3 +21,11 @@ def parse_yaml(yaml_file):
     with open(yaml_file) as f:
         parsed_dict = yaml.safe_load(f)
         return parsed_dict
+
+
+def write_str(bash_str, path=None):
+    if path:
+        with open(path, 'w') as file:
+            file.write(bash_str)
+    else:
+        print(bash_str)
index e2d37c8..3133d7f 100644 (file)
@@ -11,6 +11,8 @@
 import yaml
 import logging
 
+from .common import utils
+
 REQ_DEPLOY_SETTINGS = ['sdn_controller',
                        'odl_version',
                        'sdn_l3',
@@ -165,12 +167,7 @@ class DeploySettings(dict):
         if 'performance' in self['deploy_options']:
             bash_str += self._dump_performance()
         bash_str += self._dump_deploy_options_array()
-
-        if path:
-            with open(path, 'w') as file:
-                file.write(bash_str)
-        else:
-            print(bash_str)
+        utils.write_str(bash_str, path)
 
 
 class DeploySettingsException(Exception):
index 711eb18..ce16ef4 100644 (file)
 import yaml
 import json
 
+from .common import constants
+from .common import utils
+
 
 class Inventory(dict):
     """
     This class parses an APEX inventory yaml file into an object. It
     generates or detects all missing fields for deployment.
 
-    It then collapses one level of identifcation from the object to
+    It then collapses one level of identification from the object to
     convert it to a structure that can be dumped into a json file formatted
     such that Triple-O can read the resulting json as an instackenv.json file.
     """
     def __init__(self, source, ha=True, virtual=False):
         init_dict = {}
+        self.root_device = constants.DEFAULT_ROOT_DEV
         if isinstance(source, str):
             with open(source, 'r') as inventory_file:
                 yaml_dict = yaml.safe_load(inventory_file)
@@ -40,8 +44,13 @@ class Inventory(dict):
             node['pm_user'] = node['ipmi_user']
             node['mac'] = [node['mac_address']]
 
-            for i in ('ipmi_ip', 'ipmi_pass', 'ipmi_user', 'mac_address'):
-                del i
+            for i in ('ipmi_ip', 'ipmi_pass', 'ipmi_user', 'mac_address',
+                      'disk_device'):
+                if i == 'disk_device' and 'disk_device' in node.keys():
+                    self.root_device = node[i]
+                else:
+                    continue
+                del node[i]
 
             return node
 
@@ -53,7 +62,7 @@ class Inventory(dict):
                                      'nodes for HA baremetal deployment')
         elif len(self['nodes']) < 2:
             raise InventoryException('You must provide at least 2 nodes '
-                                     'for non-HA baremetal deployment${reset}')
+                                     'for non-HA baremetal deployment')
 
         if virtual:
             self['arch'] = 'x86_64'
@@ -67,6 +76,16 @@ class Inventory(dict):
     def dump_instackenv_json(self):
         print(json.dumps(dict(self), sort_keys=True, indent=4))
 
+    def dump_bash(self, path=None):
+        """
+        Prints settings for bash consumption.
+
+        If optional path is provided, bash string will be written to the file
+        instead of stdout.
+        """
+        bash_str = "{}={}\n".format('root_disk_list', str(self.root_device))
+        utils.write_str(bash_str, path)
+
 
 class InventoryException(Exception):
     def __init__(self, value):
index 64065ca..b04f141 100644 (file)
@@ -12,7 +12,7 @@ import logging
 import ipaddress
 
 from copy import copy
-
+from .common import utils
 from . import ip_utils
 from .common.constants import (
     CONTROLLER,
@@ -338,11 +338,7 @@ class NetworkSettings(dict):
         bash_str += flatten('dns_servers', self['dns_servers'], ' ')
         bash_str += flatten('domain_name', self['dns-domain'], ' ')
         bash_str += flatten('ntp_server', self['ntp_servers'][0], ' ')
-        if path:
-            with open(path, 'w') as file:
-                file.write(bash_str)
-        else:
-            print(bash_str)
+        utils.write_str(bash_str, path)
 
     def get_ip_addr_family(self,):
         """
index b0ebb27..e21d046 100755 (executable)
@@ -22,7 +22,6 @@ from apex import NetworkEnvironment
 from apex import DeploySettings
 from apex import Inventory
 from apex import ip_utils
-from apex.common.constants import ADMIN_NETWORK
 
 
 def parse_net_settings(args):
@@ -66,7 +65,10 @@ def run_clean(args):
 
 def parse_inventory(args):
     inventory = Inventory(args.file, ha=args.ha, virtual=args.virtual)
-    inventory.dump_instackenv_json()
+    if args.export_bash is True:
+        inventory.dump_bash()
+    else:
+        inventory.dump_instackenv_json()
 
 
 def find_ip(args):
@@ -200,6 +202,11 @@ def get_parser():
                            default=False,
                            action='store_true',
                            help='Indicate if deployment inventory is virtual')
+    inventory.add_argument('--export-bash',
+                           default=False,
+                           dest='export_bash',
+                           action='store_true',
+                           help='Export bash variables from inventory')
     inventory.set_defaults(func=parse_inventory)
 
     clean = subparsers.add_parser('clean',
index 08a3415..ec75856 100644 (file)
@@ -7,12 +7,16 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
 
+import sys
+
 from apex.inventory import Inventory
 from apex.inventory import InventoryException
 
 from nose.tools import assert_is_instance
 from nose.tools import assert_raises
 from nose.tools import assert_equal
+from nose.tools import assert_regexp_matches
+from io import StringIO
 
 inventory_files = ('intel_pod2_settings.yaml',
                    'nokia_pod1_settings.yaml',
@@ -59,3 +63,19 @@ class TestInventory(object):
         e = InventoryException("test")
         print(e)
         assert_is_instance(e, InventoryException)
+
+    def test_dump_bash_default(self):
+        i = Inventory('../config/inventory/intel_pod2_settings.yaml')
+        out = StringIO()
+        sys.stdout = out
+        i.dump_bash()
+        output = out.getvalue().strip()
+        assert_regexp_matches(output, 'root_disk_list=sda')
+
+    def test_dump_bash_set_root_device(self):
+        i = Inventory('../config/inventory/pod_example_settings.yaml')
+        out = StringIO()
+        sys.stdout = out
+        i.dump_bash()
+        output = out.getvalue().strip()
+        assert_regexp_matches(output, 'root_disk_list=sdb')