[robot] Add libraries and resources used by the suite

Add a series of libraries and resources that are used by the suite setup
and test cases functionality.

-  Libraries - Libraries written in python mostly to serve the
        installation and deployment of StarlingX from robot test cases.
-  Resources – Libraries in robot format that are used as a
         pool of keywords to be used by the entire set of test
         cases.
-  Utils – Libraries written in python that expose
         functionality to configure the framework at host
         machine level.
-  Variables – Global variables that are
          used to setup the framework as well as
          test cases.

Story: 2004828
Task: 29004

Depends-On: I6ead335412150fb8d64a6abf7909cf702d0d248c
Change-Id: I796dcaf71089424dd37a050691fd0ee003ad3176
Signed-off-by: Jose Perez Carranza <jose.perez.carranza@intel.com>
changes/25/676225/6
Jose Perez Carranza 2019-08-12 10:45:17 -05:00
parent 3b98a48102
commit 2d3d047a8c
24 changed files with 4270 additions and 0 deletions

View File

@ -0,0 +1,29 @@
# Table of contents
- [iso_setup python module](#iso_setup-python-module)
# iso_setup python module
The iso_setup.py in this folder provides the capability to setup a StarlingX
iso with specific configuration, this configuration comes from the `config.ini`
file.
The **config.ini** file in the section `iso_installer` contains the
variable `KERNEL_OPTION` which can have the following values.
| Value | Description |
| ----- | ------------------------------------------------------------ |
| 0 | Standard Controller Configuration > Serial Console > Standard Security Boot Profile |
| S0 | Standard Controller Configuration > Serial Console > Extended Security Boot Profile |
| 1 | Standard Controller Configuration > Graphical Console > Standard Security Boot Profile |
| S1 | Standard Controller Configuration > Graphical Console > Extended Security Boot Profile |
| 2 | All-in-one Controller Configuration > Serial Console > Standard Security Boot Profile |
| S2 | All-in-one Controller Configuration > Serial Console > Extended Security Boot Profile |
| 3 | All-in-one Controller Configuration > Graphical Console > Standard Security Boot Profile |
| S3 | All-in-one Controller Configuration > Graphical Console > Extended Security Boot Profile |
| 4 | All-in-one (lowlatency) Controller Configuration > Serial Console > Standard Security Boot Profile |
| S4 | All-in-one (lowlatency) Controller Configuration > Serial Console > Extended Security Boot Profile |
| 5 | All-in-one (lowlatency) Controller Configuration > Graphical Console > Standard Security Boot Profile |
| S5 | All-in-one (lowlatency) Controller Configuration > Graphical Console > Extended Security Boot Profile |

View File

@ -0,0 +1,430 @@
"""Provides a library of useful utilities for Robot Framework"""
import os
import configparser
import logging
import yaml
from Utils import bash_utils as bash
from Config import config
# create the logger object
LOG = logging.getLogger(__name__)
def update_config_ini(**kwargs):
"""Update a specific config.ini
This function update a the values from a specific config.ini file
:param kwargs: this is a dict that will contains the following values:
- config_ini: which is absolute path to the config.ini (obligatory
variable)
- config_section: which is the section to modify the variables
(optional variable)
- all others variables are dynamic and they are directly dependent of
the existing values in the config.ini, e.g:
*** How to use this function ***
- Example 1:
scenario : the config.ini has a unique variable in all sections
update_config_ini(
config_ini='path_to_config.init', LOG_PATH='some_value')
where LOG_PATH is an existing value in the config.ini.
You can use as many values you want, the only limitation is that
these must exist in the config.init file.
- Example 2:
scenario: the config.ini has duplicates variables in several sections
update_config_ini(
config_ini='path_to_config.init',
config_section='LOGICAL_INTERFACE_2', LOG_PATH='some_value')
where LOGICAL_INTERFACE_2 is an existing section in the config.ini,
please notice that the variables here must exists in the section
specified.
:return
This function returns a tuple with the following values:
- status: this can be the following values:
1. True, if some values from config.ini were modified
2. False, if there were no modifications
- message: a message with descriptive information about the
success/error
"""
status = False
message = None
if len(kwargs) < 2:
raise RuntimeError('a minimum of two variables are expected')
# obligatory variable
config_ini = kwargs['config_ini']
# optional variable
config_section = kwargs.get('config_section', False)
if not os.path.exists(config_ini):
raise IOError('{}: does not exists'.format(config_ini))
configurations = configparser.ConfigParser()
# preserve the variables from config.ini in upper case
configurations.optionxform = lambda option: option.upper()
configurations.read(config_ini)
# ------------------------ validation section ---------------------------
# checking if the section given is valid (if any)
if config_section and config_section not in configurations.sections():
message = '{}: section does not exists'.format(config_section)
return status, message
elif not config_section:
# checking if the values are in more than one section
duplicates = 0
for key, value in kwargs.items():
for section in configurations.sections():
if configurations.has_option(section, key):
duplicates += 1
if duplicates > 1:
status = False
message = ('{}: is in more than one section, please '
'set config_section'.format(key))
return status, message
duplicates = 0
# -----------------------------------------------------------------------
blacklist_keys = ['config_ini', 'config_section']
count = 0
# ------------------- update config values section ----------------------
if config_section:
# (the user provides a config_section)
# get a list of tuples without the values in the blacklist list
values = [x for x in kwargs.items() if x[0] not in blacklist_keys]
for _key, _value in values:
try:
_ = configurations[config_section][_key]
except KeyError:
message = '{}: key does not exists in the section :{}'.format(
_key, config_section)
return status, message
else:
configurations[config_section][_key] = _value
count += 1
status = True
else:
# (the user does not provides a config_section only values)
# modifying configurations according to the values
for section in configurations.sections():
for item in configurations.items(section):
for key, value in kwargs.items():
if key == item[0]:
configurations[section][item[0]] = value
count += 1
# -----------------------------------------------------------------------
if count != 0:
with open(config_ini, 'w') as configfile:
configurations.write(configfile)
status = True
message = '{}: was updated successfully'.format(os.path.basename(
config_ini))
return status, message
def string_to_dict(string_table):
"""Convert string table to dictionary
This function convert a string table output from a command executed in the
controller node into a dictionary.
Useful to parse the output in keys/values for Robot Framework.
@param string_table: the string table to convert into a dictionary, it
comes from the controller node through Robot Framework.
:return:
a dictionary with all the string table entries.
"""
# string_table variable comes from Robot Framework into a dictionary list
# in unicode format, so we need the following
# 1. converting string_table variable from unicode to ascii code
# 2. split in a list with line breaks
line_breaks_list = string_table['stdout'].encode('utf-8').split('\n')
robot_dictionary = {}
try:
# getting the table headers without empty spaces
table_headers = [
header.strip() for header in line_breaks_list[1].split('|')[1:-1]
]
except IndexError:
err_dict = {
'summary': {
'err': 'IndexError',
'cause': 'the command did not return a table'
}
}
robot_dictionary.update(err_dict)
return robot_dictionary
# the blacklist is used for build the body variable without the index on it
blacklist = [0, 1, 2, len(line_breaks_list) - 1]
body = list(filter(
lambda item: line_breaks_list.index(item) not in blacklist,
line_breaks_list))
table_data = [[v.strip() for v in i.strip('|').split('|')] for i in body]
robot_dictionary = {
table_headers[0]: {
i[0]: {
k: v for k, v in zip(table_headers[1:], i[1:])
} for i in table_data
}
}
return robot_dictionary
def get_cmd_boot_line():
"""Get a cmd boot line.
This function build a custom cmd line in order to boot the startlingx iso
:return:
cmd: the cmd line for boot the iso.
"""
kernel_option = config.get('iso_installer', 'KERNEL_OPTION')
vmlinuz = config.get('iso_installer', 'VMLINUZ')
consoles = config.get('iso_installer', 'CONSOLES')
serial = config.get('iso_installer', 'SERIAL')
opts_1 = config.get('iso_installer', 'OPTS_1')
sys_type_1 = config.get('iso_installer', 'SYS_TYPE_1')
sys_type_2 = config.get('iso_installer', 'SYS_TYPE_2')
sys_type_3 = config.get('iso_installer', 'SYS_TYPE_3')
opts_2 = config.get('iso_installer', 'OPTS_2')
sec_prof_1 = config.get('iso_installer', 'SEC_PROF_1')
sec_prof_2 = config.get('iso_installer', 'SEC_PROF_2')
initrd = config.get('iso_installer', 'INITRD')
cmd = False
serial = '{vmlinuz} {consoles} {ser} {opts}'.format(
vmlinuz=vmlinuz, consoles=consoles, ser=serial, opts=opts_1)
no_serial = '{vmlinuz} {consoles} {opts}'.format(
vmlinuz=vmlinuz, consoles=consoles, opts=opts_1)
if kernel_option == '0':
cmd = ('{serial} {sys_type} {opts} {sec_prof} {initrd}'.format(
serial=serial, sys_type=sys_type_1, opts=opts_2,
sec_prof=sec_prof_1, initrd=initrd))
elif kernel_option == 'S0':
cmd = ('{serial} {sys_type} {opts} {sec_prof} {initrd}'.format(
serial=serial, sys_type=sys_type_1, opts=opts_2,
sec_prof=sec_prof_2, initrd=initrd))
elif kernel_option == '1':
cmd = ('{no_serial} {sys_type} {opts} {sec_prof} {initrd}'.format(
no_serial=no_serial, sys_type=sys_type_1, opts=opts_2,
sec_prof=sec_prof_1, initrd=initrd))
elif kernel_option == 'S1':
cmd = ('{no_serial} {sys_type} {opts} {sec_prof} {initrd}'.format(
no_serial=no_serial, sys_type=sys_type_1, opts=opts_2,
sec_prof=sec_prof_2, initrd=initrd))
elif kernel_option == '2':
cmd = ('{serial} {sys_type} {opts} {sec_prof} {initrd}'.format(
serial=serial, sys_type=sys_type_2, opts=opts_2,
sec_prof=sec_prof_1, initrd=initrd))
elif kernel_option == 'S2':
cmd = ('{serial} {sys_type} {opts} {sec_prof} {initrd}'.format(
serial=serial, sys_type=sys_type_2, opts=opts_2,
sec_prof=sec_prof_2, initrd=initrd))
elif kernel_option == '3':
cmd = ('{no_serial} {sys_type} {opts} {sec_prof} {initrd}'.format(
no_serial=no_serial, sys_type=sys_type_2, opts=opts_2,
sec_prof=sec_prof_1, initrd=initrd))
elif kernel_option == 'S3':
cmd = ('{no_serial} {sys_type} {opts} {sec_prof} {initrd}'.format(
no_serial=no_serial, sys_type=sys_type_2, opts=opts_2,
sec_prof=sec_prof_2, initrd=initrd))
elif kernel_option == '4':
cmd = ('{serial} {sys_type} {opts} {sec_prof} {initrd}'.format(
serial=serial, sys_type=sys_type_3, opts=opts_2,
sec_prof=sec_prof_1, initrd=initrd))
elif kernel_option == 'S4':
cmd = ('{serial} {sys_type} {opts} {sec_prof} {initrd}'.format(
serial=serial, sys_type=sys_type_3, opts=opts_2,
sec_prof=sec_prof_2, initrd=initrd))
elif kernel_option == '5':
cmd = ('{no_serial} {sys_type} {opts} {sec_prof} {initrd}'.format(
no_serial=no_serial, sys_type=sys_type_3, opts=opts_2,
sec_prof=sec_prof_1, initrd=initrd))
elif kernel_option == 'S5':
cmd = ('{no_serial} {sys_type} {opts} {sec_prof} {initrd}'.format(
no_serial=no_serial, sys_type=sys_type_3, opts=opts_2,
sec_prof=sec_prof_2, initrd=initrd))
return cmd
def grub_checker(iso, mode, grub_option, grub_cmd):
"""Check a grub cmd boot line against the ones in the StarlingX ISO file
This function compare the grub cmd boot line built from get_cmd_boot_line
function against a StarlingX ISO file in order to check if this is still
valid.
Basically check if all the arguments from the ISO contains them in the
built one from the get_cmd_boot_line function.
:param iso: the iso to mount.
:param mode: the mode to check the grub cmd line, this can be vbios/uefi.
:param grub_option: the boot line to compare which could have the
following values:
- 0: Standard Controller Configuration > Serial Console >
Standard Security Boot Profile.
- S0: Standard Controller Configuration > Serial Console > Extended
Security Boot Profile
- 1: Standard Controller Configuration > Graphical Console >
Standard Security Boot Profile
- S1: Standard Controller Configuration > Graphical Console >
Extended Security Boot Profile
- 2: All-in-one Controller Configuration > Serial Console >
Standard Security Boot Profile
- S2: All-in-one Controller Configuration > Serial Console >
Extended Security Boot Profile
- 3: All-in-one Controller Configuration > Graphical Console >
Standard Security Boot Profile
- S3 All-in-one Controller Configuration > Graphical Console >
Extended Security Boot Profile
- 4: All-in-one (lowlatency) Controller Configuration >
Serial Console > Standard Security Boot Profile
- S4: All-in-one (lowlatency) Controller Configuration >
Serial Console > Extended Security Boot Profile
- 5: All-in-one (lowlatency) Controller Configuration >
Graphical Console > Standard Security Boot Profile
- S5: All-in-one (lowlatency) Controller Configuration >
Graphical Console > Extended Security Boot Profile
:param grub_cmd: the cmd line built from get_cmd_boot_line function
:return
- match: if the grub_cmd has all the elements from the iso
- mismatch: if the grub_cmd does not have all the elements from the iso
"""
allowed_grub_options = [
'0', 'S0', '1', 'S1', '2', 'S2', '3', 'S3', '4', 'S4', '5', 'S5']
if grub_option not in allowed_grub_options:
raise KeyError('grub boot number does not exists')
mount_point = '/tmp/cdrom'
if os.path.exists(mount_point) and os.path.ismount(mount_point):
bash.run_command('sudo umount -l {}'.format(mount_point),
raise_exception=True)
elif not os.path.exists(mount_point):
os.makedirs(mount_point)
# mounting the iso file
bash.run_command('sudo mount -o loop {} {}'.format(iso, mount_point),
raise_exception=True)
if mode == 'vbios':
grub = '{}/syslinux.cfg'.format(mount_point)
regex = '-e "label [0-9]" -e "label [A-Z][0-9]" -e append'
grub_extracted_lines = bash.run_command('grep {} {}'.format(
regex, grub))
grub_option_list = grub_extracted_lines[1].split('\n')
key_dict = []
values_dict = []
# Filling the lists
for line in grub_option_list:
current_line = line.strip()
if current_line.startswith('label'):
key_dict.append(current_line.replace('label ', ''))
elif current_line.startswith('append'):
values_dict.append(current_line)
# zipping the list in only one as a list of tuples
grub_list = zip(key_dict, values_dict)
grub_dict = dict()
# creating a dict with the grub entries
for key, value in grub_list:
grub_dict[key] = value
# comparing the grub boot line from the ISO with the one obtained from
# get_cmd_boot_line function
iso_boot_line = grub_dict[grub_option].split()
# removing blacklist elements from iso_boot_line
blacklist = [
i for i, word in enumerate(iso_boot_line)
if word.startswith('console')
]
for index in blacklist:
del iso_boot_line[index]
if set(grub_cmd.split()).issuperset(set(iso_boot_line)):
status = 'match'
else:
status = 'mismatch'
diff = [
element for element in iso_boot_line
if element not in grub_cmd.split()]
LOG.warn('missed params from cmd grub line')
for element in diff:
LOG.warn(element)
elif mode == 'uefi':
raise NotImplementedError
else:
raise IndexError('{}: not allowed'.format(mode))
# dismount the mount_point
bash.run_command('sudo umount -l {}'.format(mount_point),
raise_exception=True)
return status
def get_controllers_ip(env, config_file, config_type, lab_file):
"""Get IPs of the controllers from the specific stx configuration file
Args:
- config_file: The stx-configuration.ini file
- config_type: The type of configuration selected from the command
line.
Return:
- controller_data: Dictionary with the key name and the IP of the
controllers
"""
# Read Configurtion File
conf = yaml.safe_load(open(config_file))
cont_data = {}
# Get Controllers IP's
if config_type == 'simplex':
cont_data['IP_UNIT_0_ADDRESS'] = conf['external_oam_floating_address']
cont_data['IP_UNIT_1_ADDRESS'] = ''
else:
cont_data['IP_UNIT_0_ADDRESS'] = conf['external_oam_node_0_address']
cont_data['IP_UNIT_1_ADDRESS'] = conf['external_oam_node_1_address']
if env == 'baremetal':
# Get phyisical interfaces
conf_lab = yaml.safe_load(open(lab_file))
cont_data['OAM_IF'] = conf_lab['nodes']['controller-0']['oam_if']
cont_data['MGMT_IF'] = conf_lab['nodes']['controller-0']['mgmt_if']
return cont_data

View File

@ -0,0 +1,220 @@
"""Provides the capability to setup a StarlingX iso with specific
configuration"""
from imp import reload
import os
import getpass
import subprocess
import pexpect
import psutil
from Config import config
from Libraries import common
from Utils import logger
from Utils import network
# reloading config.ini
reload(config)
# Global variables
THIS_PATH = os.path.dirname(os.path.abspath(__file__))
PROJECT_PATH = os.path.dirname(THIS_PATH)
CURRENT_USER = getpass.getuser()
PASSWORD = config.get('credentials', 'STX_DEPLOY_USER_PSWD')
PROMPT = '$'
# setup the logger
LOG_FILENAME = 'iso_setup.log'
LOG_PATH = config.get('general', 'LOG_PATH')
LOG = logger.setup_logging(
'iso_setup', log_file='{path}/{filename}'.format(
path=LOG_PATH, filename=LOG_FILENAME), console_log=False)
class Installer(object):
"""Install a StarlingX ISO though serial console"""
def __init__(self):
self.child = pexpect.spawn(config.get('iso_installer', 'VIRSH_CMD'))
self.child.logfile = open('{}/iso_setup_console.txt'.format(
LOG_PATH), 'wb')
@staticmethod
def open_xterm_console():
"""Open a xterm console to visualize logs from serial connection"""
suite_path = os.path.dirname(THIS_PATH)
terminal = 'xterm'
terminal_title = '"controller-0 boot console"'
geometry = '-0+0' # upper right hand corner
os.environ['DISPLAY'] = ':0'
command = 'python {suite}/Utils/watcher.py {log_path}'.format(
suite=suite_path, log_path=LOG_PATH)
try:
pid_list = subprocess.check_output(['pidof', terminal]).split()
# killing all xterm active sessions
for pid in pid_list:
_pid = psutil.Process(int(pid))
# terminate the process
_pid.terminate()
if _pid.is_running():
# forces the process to terminate
_pid.suspend()
_pid.resume()
except subprocess.CalledProcessError:
LOG.info('There is not process for : {}'.format(terminal))
os.system('{term} -geometry {geo} -T {title} -e {cmd} &'.format(
term=terminal, geo=geometry, title=terminal_title, cmd=command))
def boot_installer(self):
"""Interact with the installation process at boot time
The aim of this function is send the appropriate arguments in order to
boot the ISO
"""
boot_timeout = int(config.get('iso_installer', 'BOOT_TIMEOUT'))
self.child.expect('Escape character')
LOG.info('connected to the VM (controller-0)')
# send a escape character
self.child.sendline('\x1b')
self.child.expect('boot:')
cmd_boot_line = common.get_cmd_boot_line()
self.child.sendline(cmd_boot_line)
LOG.info('kernel command line sent: {}'.format(cmd_boot_line))
# send a enter character
self.child.sendline('\r')
# setting a boot timeout
self.child.timeout = boot_timeout
self.child.expect('Loading vmlinuz')
LOG.info('Loading vmlinuz')
self.child.expect('Loading initrd.img')
LOG.info('Loading initrd.img')
self.child.expect('Starting installer, one moment...')
LOG.info('Starting installer ...')
self.child.expect('Performing post-installation setup tasks')
LOG.info('Performing post-installation setup tasks')
def first_login(self):
"""Change the password at first login"""
user_name = config.get('credentials', 'STX_DEPLOY_USER_NAME')
self.child.expect('localhost login:')
LOG.info('the system boot up correctly')
LOG.info('logging into the system')
self.child.sendline(user_name)
self.child.expect('Password:')
self.child.sendline(user_name)
LOG.info('setting a new password')
self.child.expect('UNIX password:')
self.child.sendline(user_name)
self.child.expect('New password:')
self.child.sendline(PASSWORD)
self.child.expect('Retype new password:')
self.child.sendline(PASSWORD)
self.child.expect('$')
LOG.info('the password was changed successfully')
def configure_temp_network(self):
"""Setup a temporal controller IP"""
controller_tmp_ip = config.get('iso_installer', 'CONTROLLER_TMP_IP')
controller_tmp_gateway = config.get(
'iso_installer', 'CONTROLLER_TMP_GATEWAY')
LOG.info('Configuring temporal network')
self.child.expect(PROMPT)
# -----------------------------
# getting OS network interfaces
timeout_before = self.child.timeout
self.child.timeout = 10
self.child.sendline('ls /sys/class/net')
cmd_stdout = []
try:
for stdout in self.child:
cmd_stdout.append(stdout.strip())
except pexpect.exceptions.TIMEOUT:
LOG.info('custom timeout reached')
network_interfaces = []
network_interfaces.extend(''.join(cmd_stdout[-1:]).split())
# returning to the original timeout value
self.child.timeout = timeout_before
controller_tmp_interface = network_interfaces[0]
# -----------------------------
self.child.sendline('sudo ip addr add {0}/24 dev {1}'.format(
controller_tmp_ip, controller_tmp_interface))
self.child.expect('Password:')
self.child.sendline(PASSWORD)
self.child.expect(PROMPT)
self.child.sendline('sudo ip link set {} up'.format(
controller_tmp_interface))
self.child.expect(PROMPT)
self.child.sendline('sudo ip route add default via {}'.format(
controller_tmp_gateway))
LOG.info('Network configured, testing ping')
self.child.sendline('ping -c 1 127.0.0.1')
self.child.expect('1 packets transmitted')
LOG.info('Ping successful')
# updating networks in the config.ini
configuration_file = os.path.join(
PROJECT_PATH, 'Config', 'config.ini')
configuration_type = config.get('general', 'CONFIGURATION_TYPE')
network.update_networks_config(
network_interfaces, configuration_file, configuration_type)
def config_controller(self, config_file):
"""Configure controller with provided configuration file
:param config_file: which is the configuration file for
config_controller
"""
config_controller_timeout = int(config.get(
'iso_installer', 'CONFIG_CONTROLLER_TIMEOUT'))
self.child.expect(PROMPT)
LOG.info('Applying configuration (this will take several minutes)')
self.child.sendline(
'sudo config_controller --force --config-file {}'
.format(config_file))
self.child.timeout = config_controller_timeout
self.child.expect('Configuration was applied')
LOG.info(self.child.before)
def finish_logging(self):
"""Stop logging and close log file"""
self.child.logfile.close()
LOG.info('Closing the log')
def install_iso():
"""Start the process of installing a StarlingX ISO"""
install_obj = Installer()
install_obj.open_xterm_console()
install_obj.boot_installer()
install_obj.first_login()
install_obj.configure_temp_network()
return install_obj
def config_controller(controller_connection, config_file):
"""Start controller configuration with specified configuration file
:param controller_connection: which is the connection stabilised through
to the controller
:param config_file: which is the configuration file for config_controller
"""
controller_connection.config_controller(config_file)
controller_connection.finish_logging()

View File

@ -0,0 +1,528 @@
"""Provides the capability to setup a StarlingX iso with specific
configuration"""
from ast import literal_eval
from imp import reload
import os
import re
from shutil import copyfile
from shutil import copytree
from shutil import rmtree
import sys
import threading
import pexpect
import yaml
from bash import bash
from Config import config
from Utils import logger
from Utils import network
from Utils.utils import isdir
# reloading config.ini
reload(config)
# Global variables
THIS_PATH = os.path.dirname(os.path.abspath(__file__))
PROJECT_PATH = os.path.dirname(THIS_PATH)
PROMPT = '$'
# Setup the logger
LOG_FILENAME = 'iso_setup_baremetal.log'
LOG_PATH = config.get('general', 'LOG_PATH')
LOG = logger.setup_logging('iso_setup_baremetal', log_file='{path}/{filename}'
.format(path=LOG_PATH, filename=LOG_FILENAME),
console_log=False)
class PxeServer(object):
"""Handle PXE services and mount ISO for Installation"""
def __init__(self, iso_path):
self.iso_path = iso_path
self.iso_name = os.path.basename(self.iso_path).replace('.iso', '')
self.tftp_dir = '/var/lib/tftpboot/uefi'
def mount_iso(self):
"""Mounting ISO and grabbing shim, grub.efi and grub.cfg files"""
# Mounting ISO on /mnt and on http server
mount_point = '/mnt'
http_mnt_point = '/var/www/html/stx'
tmp_mnt_point = '/tmp'
if os.listdir(mount_point):
LOG.info('{} is busy umounting'.format(mount_point))
umounting_attempts = 3
while umounting_attempts > 0:
umounting = bash('sudo umount -l {}'.format(mount_point))
if umounting.stderr and umounting_attempts:
LOG.info('Failed to umount {}, retrying...'.format(
mount_point))
elif umounting.stderr and not umounting_attempts:
LOG.info('Max umounting attempts reached, leaving '
'installation')
sys.exit(1)
else:
break
umounting_attempts -= 1
bash('sudo mount {0} {1}'.format(self.iso_path, mount_point))
LOG.info('Mounting ISO on {}'.format(mount_point))
if isdir(os.path.join(http_mnt_point, self.iso_name)):
LOG.info('Folder {0}/{1} already exists in http server, deleting '
'it.'.format(http_mnt_point, self.iso_name))
rmtree(os.path.join(http_mnt_point, self.iso_name))
copytree(mount_point, os.path.join(http_mnt_point, self.iso_name))
if isdir(os.path.join(tmp_mnt_point, self.iso_name)):
LOG.info('Folder {0}/{1} already exists in http server, deleting '
'it.'.format(tmp_mnt_point, self.iso_name))
rmtree(os.path.join(tmp_mnt_point, self.iso_name))
# Changing from RPM to CPIO format
LOG.info('Uncompressing RPM necessary files')
copytree(os.path.join(http_mnt_point, self.iso_name, 'Packages'),
os.path.join(tmp_mnt_point, self.iso_name, 'Packages'))
grub2_regex = re.compile('grub2-efi-x64-[0-9]')
os.chdir(os.path.join(tmp_mnt_point, self.iso_name, 'Packages'))
for package in os.listdir(
os.path.join(tmp_mnt_point, self.iso_name, 'Packages')):
if 'shim' in package or grub2_regex.search(package):
LOG.info('Found grub/shim file uncompressing it')
bash('rpm2cpio {} | cpio -dimv'.format(package))
# Copying shim, and grub files to tftpboot folder
# fixme: handle condition to make sure tftp_dir exists
if not os.path.isdir(self.tftp_dir):
os.makedirs(self.tftp_dir)
LOG.info('Copying grub and shim files to TFTP server')
for root, _, files in os.walk('/tmp/{}/Packages'.format(
self.iso_name)):
for package in files:
if any(boot_file in package for boot_file in ('shim.efi',
'grubx64.efi')):
copyfile(os.path.join(root, package),
os.path.join(self.tftp_dir, package))
if 'grub.cfg' in package:
copyfile(os.path.join(root, package),
os.path.join(self.tftp_dir, package))
copyfile(os.path.join(http_mnt_point, self.iso_name,
'EFI/BOOT/grub.cfg'),
os.path.join(self.tftp_dir, 'grub.cfg'))
# Copying vmlinuz and initrd
images_dir = os.path.join(self.tftp_dir, 'images')
if isdir(images_dir):
LOG.info('{} already exists, deleting directory.'.format(
images_dir))
rmtree(images_dir)
LOG.info('Copying vmlinuz and initrd files.')
copytree(os.path.join(mount_point, 'images/pxeboot'),
os.path.join(self.tftp_dir, 'images'))
@staticmethod
def check_pxe_services():
"""This function is intended to restart DHCP service
DHCP service needs to be restarted in order to grab the changes on the
dhcp config file"""
LOG.info('Checking PXE needed services')
services = ['dhcpd', 'tftp', 'httpd']
for service in services:
active_service = bash('sudo systemctl is-active {}'
.format(service))
if 'active' in active_service.stdout:
LOG.info('{} service is active'.format(service))
continue
else:
LOG.info('{} service is not active, restarting'
.format(service))
bash('sudo systemctl restart {}'.format(service))
def get_efi_boot_line(self, grub_dict):
"""Get linuxefi command and initrdefi command from grub_dict
Get linuxefi command and initrdefi command from grub_dict according to
specified option on configuration argument while running runner.py
"""
configuration_type = config.get('general', 'CONFIGURATION_TYPE')
http_server_ip = config.get('baremetal', 'HTTP_SERVER')
LOG.info('config_type')
LOG.info(configuration_type)
boot_lines = dict()
if configuration_type == 'simplex':
boot_lines = grub_dict['aio']['serial']['standard']
elif configuration_type == 'duplex':
boot_lines = grub_dict['aio']['serial']['standard']
elif configuration_type == 'multinode_controller_storage':
boot_lines = grub_dict['standard']['serial']['standard']
elif configuration_type == 'multinode_dedicated_storage':
boot_lines = grub_dict['standard']['serial']['standard']
prefix = 'uefi/images'
linuxefi_cmd = boot_lines['linuxefi']
linuxefi_http_cmd = list()
for parameter in linuxefi_cmd.split(' '):
if 'inst.ks' in parameter:
ks_file = parameter.split('/')[-1]
parameter = 'inst.ks=http://{server}/stx/{iso}/{ks_file}' \
.format(server=http_server_ip, iso=self.iso_name,
ks_file=ks_file)
linuxefi_http_cmd.append(parameter)
elif 'inst.stage2' in parameter:
parameter = 'inst.stage2=http://{server}/stx/{iso}' \
.format(server=http_server_ip, iso=self.iso_name)
linuxefi_http_cmd.append(parameter)
elif 'vmlinuz' in parameter:
parameter = '{prefix}{parameter}'.format(prefix=prefix,
parameter=parameter)
linuxefi_http_cmd.append(parameter)
else:
linuxefi_http_cmd.append(parameter)
inst_repo = 'inst.repo=http://{server}/stx/{iso}'\
.format(server=http_server_ip, iso=self.iso_name)
linuxefi_http_cmd.append(inst_repo)
boot_lines['linuxefi'] = ' '.join(linuxefi_http_cmd)
initrd_cmd = boot_lines['initrdefi']
initrd_prefix_cmd = list()
for parameter in initrd_cmd.split(' '):
if 'initrd.img' in parameter:
parameter = '{prefix}{parameter}'.format(prefix=prefix,
parameter=parameter)
initrd_prefix_cmd.append(parameter)
else:
initrd_prefix_cmd.append(parameter)
boot_lines['initrdefi'] = ' '.join(initrd_prefix_cmd)
return boot_lines
def handle_grub(self):
"""Pointing source files to http server on grub"""
installation_type = config.get('general', 'CONFIGURATION_TYPE')
grub_dict = analyze_grub(
os.path.join(self.tftp_dir, 'grub.cfg'))
grub_lines = self.get_efi_boot_line(grub_dict)
grub_entry = ("menuentry '{config}'{{\n{linuxefi}\n{initrdefi}\n}}"
.format(config=installation_type,
linuxefi=grub_lines['linuxefi'],
initrdefi=grub_lines['initrdefi']))
grub_timeout = 'timeout=5\n'
with open(os.path.join(self.tftp_dir, 'grub.cfg'), 'w') as grub_file:
grub_file.writelines(grub_timeout)
grub_file.write(grub_entry)
class Node(object):
"""Constructs a Node server that can be booted to pxe and also follow the
installation of STX system
"""
def __init__(self, node):
self.name = node['name']
self.personality = node['personality']
self.pxe_nic_mac = node['pxe_nic_mac']
self.bmc_ip = node['bmc_ip']
self.bmc_user = node['bmc_user']
self.bmc_pswd = node['bmc_pswd']
if self.name == 'controller-0':
self.installation_ip = node['installation_ip']
def boot_server_to_pxe(self):
"""Boot the installation target server using PXE server"""
LOG.info('Booting {} To PXE'.format(self.name))
LOG.info('Node {}: Setting PXE as first boot option'
.format(self.name))
set_pxe = bash('ipmitool -I lanplus -H {node_bmc_ip} '
'-U {node_bmc_user} -P {node_bmc_pswd} '
'chassis bootdev pxe'.format(
node_bmc_ip=self.bmc_ip,
node_bmc_user=self.bmc_user,
node_bmc_pswd=self.bmc_pswd))
if set_pxe.stderr:
LOG.info(set_pxe.stderr)
LOG.info('Node {}: Resetting target.'.format(self.name))
power_status = bash('ipmitool -I lanplus -H {node_bmc_ip} '
'-U {node_bmc_user} -P {node_bmc_pswd} '
'chassis power status'.format(
node_bmc_ip=self.bmc_ip,
node_bmc_user=self.bmc_user,
node_bmc_pswd=self.bmc_pswd))
if power_status.stderr:
LOG.info(set_pxe.stderr)
if "Chassis Power is on" in str(power_status):
power = bash('ipmitool -I lanplus -H {node_bmc_ip} '
'-U {node_bmc_user} -P {node_bmc_pswd} '
'chassis power reset'.format(
node_bmc_ip=self.bmc_ip,
node_bmc_user=self.bmc_user,
node_bmc_pswd=self.bmc_pswd))
else:
power = bash('ipmitool -I lanplus -H {node_bmc_ip} '
'-U {node_bmc_user} -P {node_bmc_pswd} '
'chassis power on'.format(
node_bmc_ip=self.bmc_ip,
node_bmc_user=self.bmc_user,
node_bmc_pswd=self.bmc_pswd))
if power.stderr:
LOG.info(power.stderr)
LOG.info('Node {}: Deactivating sol sessions.'.format(self.name))
kill_sol = bash('ipmitool -I lanplus -H {node_bmc_ip} '
'-U {node_bmc_user} -P {node_bmc_pswd} sol '
'deactivate'.format(node_bmc_ip=self.bmc_ip,
node_bmc_user=self.bmc_user,
node_bmc_pswd=self.bmc_pswd))
if kill_sol.stderr:
LOG.info(kill_sol.stderr)
def follow_node_installation(self):
"""This function is intended to follow nodes installation"""
user_name = config.get('credentials', 'STX_DEPLOY_USER_NAME')
password = config.get('credentials', 'STX_DEPLOY_USER_PSWD')
LOG.info('Node {}: Following node installation.'.format(self.name))
installation = pexpect.spawn(('ipmitool -I lanplus -H {node_bmc_ip} '
'-U {node_bmc_user} -P {node_bmc_pswd} '
'sol activate')
.format(node_bmc_ip=self.bmc_ip,
node_bmc_user=self.bmc_user,
node_bmc_pswd=self.bmc_pswd))
installation.logfile = open('{}/iso_setup_installation.txt'.format(
LOG_PATH), 'wb')
installation.timeout = int(config.get('iso_installer', 'BOOT_TIMEOUT'))
installation.expect('Start PXE over IPv4.')
LOG.info('Node {}: Trying to boot using PXE'.format(self.name))
installation.expect('Linux version')
LOG.info('Node {}: Loading Linux Kernel'.format(self.name))
installation.expect('Welcome to')
LOG.info('Node {}: CentOS have been loaded'.format(self.name))
installation.expect('Starting installer, one moment...')
LOG.info('Node {}: Starting installer ...'.format(self.name))
installation.expect('Performing post-installation setup tasks')
LOG.info('Node {}: Performing post-installation setup tasks'
.format(self.name))
installation.expect('login:')
LOG.info('Node {}: the system boot up correctly'.format(self.name))
LOG.info('Node {}: logging into the system'.format(self.name))
installation.sendline(user_name)
installation.expect('Password:')
installation.sendline(user_name)
LOG.info('Node {}: setting a new password'.format(self.name))
installation.expect('UNIX password:')
installation.sendline(user_name)
installation.expect('New password:')
installation.sendline(password)
installation.expect('Retype new password:')
installation.sendline(password)
installation.expect('$')
LOG.info('Node {}: the password was changed successfully'
.format(self.name))
installation.close()
LOG.info('Node {}: Closing SOL session after successfully installation'
.format(self.name))
deactivate_sol = bash(('ipmitool -I lanplus -H {node_bmc_ip} '
'-U {node_bmc_user} -P {node_bmc_pswd} '
'sol deactivate')
.format(node_bmc_ip=self.bmc_ip,
node_bmc_user=self.bmc_user,
node_bmc_pswd=self.bmc_pswd))
if not deactivate_sol.stderr:
LOG.info('Node {}: SOL session closed successfully'
.format(self.name))
def analyze_grub(grub_cfg_file):
"""Get linuxefi command and initrdefi command from grub_dict
Get linuxefi command and initrdefi command from grub_dict according to
selected option in config file
"""
with open(grub_cfg_file, 'r') as grub:
lines = grub.readlines()
cmd_lines = list()
for line in lines:
if 'linuxefi' in line:
line = line.strip()
cmd_line = "'linuxefi': '{line}',".format(line=line)
cmd_lines.append(cmd_line)
elif 'initrdefi' in line:
line = line.strip()
cmd_line = "'initrdefi': '{line}'".format(line=line)
cmd_lines.append(cmd_line)
elif 'submenu' in line or 'menuentry' in line:
if re.search('--id=(.*) {', line):
menu_name = re.search('--id=(.*) {', line)
else:
menu_name = re.search("'(.*)'", line)
menu_name = menu_name.group(1)
line = "'{}': {{".format(menu_name)
cmd_lines.append(line)
elif '}' in line:
cmd_lines.append('},')
grub_menu = ''.join(cmd_lines) # type: str
grub_menu = '{{ {} }}'.format(grub_menu)
grub_dict = literal_eval(grub_menu)
return grub_dict
def mount_iso_on_pxe(iso):
""""Manage and enable PXE services"""
pxe_server = PxeServer(iso)
pxe_server.mount_iso()
pxe_server.handle_grub()
pxe_server.check_pxe_services()
def install_iso_master_controller():
"""Launch ISO installation on controller-0"""
nodes_file = os.path.join(os.environ['PYTHONPATH'], 'baremetal',
'baremetal_setup.yaml')
nodes = yaml.safe_load(open(nodes_file))
# Update config.ini with OAM and MGMT interfaces
network_interfaces = []
network_interfaces.insert(0, nodes['nodes']['controller-0']['oam_if'])
network_interfaces.insert(1, nodes['nodes']['controller-0']['mgmt_if'])
configuration_file = os.path.join(
PROJECT_PATH, 'Config', 'config.ini')
configuration_type = config.get('general', 'CONFIGURATION_TYPE')
network.update_networks_config(
network_interfaces, configuration_file, configuration_type)
# Installing STX on main controller
controller_0 = nodes['nodes']['controller-0']
master_controller = Node(controller_0)
master_controller.boot_server_to_pxe()
master_controller.follow_node_installation()
return master_controller
def get_controller0_ip():
"""Returns master controller IP"""
nodes_file = os.path.join(THIS_PATH, '..', 'BareMetal',
'installation_setup.yaml')
nodes = yaml.load(open(nodes_file))
controller_0 = nodes['controller-0']
master_controller = Node(controller_0)
return master_controller.installation_ip
def config_controller(config_file):
"""Configures master controller using its corresponding init file"""
config_controller_timeout = int(config.get(
'iso_installer', 'CONFIG_CONTROLLER_TIMEOUT'))
nodes_file = os.path.join(os.environ['PYTHONPATH'], 'baremetal',
'baremetal_setup.yaml')
nodes = yaml.safe_load(open(nodes_file))
controller_0 = nodes['nodes']['controller-0']
master_controller = Node(controller_0)
serial_cmd = ('ipmitool -I lanplus -H {node_bmc_ip} -U {node_bmc_user} '
'-P {node_bmc_pswd} sol activate'
.format(node_bmc_ip=master_controller.bmc_ip,
node_bmc_user=master_controller.bmc_user,
node_bmc_pswd=master_controller.bmc_pswd))
configuring_controller = pexpect.spawn(serial_cmd)
configuring_controller.logfile = open('{}/iso_setup_installation.txt'
.format(LOG_PATH), 'wb')
configuring_controller.sendline('\r')
configuring_controller.expect(PROMPT)
LOG.info('Applying configuration (this will take several minutes)')
configuring_controller.sendline('sudo config_controller --force --config-file {}'
.format(config_file))
configuring_controller.timeout = config_controller_timeout
configuring_controller.expect('Configuration was applied')
LOG.info(configuring_controller.before)
configuring_controller.logfile.close()
LOG.info('Closing the log')
configuring_controller.close()
closing_serial_connection = (
bash('ipmitool -I lanplus -H {node_bmc_ip} -U {node_bmc_user} '
'-P {node_bmc_pswd} sol deactivate'
.format(node_bmc_ip=master_controller.bmc_ip,
node_bmc_user=master_controller.bmc_user,
node_bmc_pswd=master_controller.bmc_pswd)))
if closing_serial_connection.stderr:
LOG.info(closing_serial_connection.stderr)
def install_secondary_nodes():
"""Installs STX on controller-1 and computes"""
nodes_file = os.path.join(THIS_PATH, '..', 'BareMetal',
'installation_setup.yml')
nodes = yaml.load(open(nodes_file))
# Removing controller-0 from Nodes
controller_0 = nodes.pop('controller-0')
master_controller = Node(controller_0)
serial_cmd = ('ipmitool -I lanplus -H {node_bmc_ip} -U {node_bmc_user} '
'-P {node_bmc_pswd} sol activate'
.format(node_bmc_ip=master_controller.bmc_ip,
node_bmc_user=master_controller.bmc_user,
node_bmc_pswd=master_controller.bmc_pswd))
controller_0_serial = pexpect.spawn(serial_cmd)
# Loading openrc
controller_0_serial.sendline('source /etc/nova/openrc')
# Adding nodes to master controller
nodes_instances = list()
node_names = nodes.keys()
for node_name in node_names:
node = Node(nodes[node_name])
nodes_instances.append(node)
controller_0_serial.sendline('system host-add -n {name} '
'-p {personality} -m {mac_address}'
.format(name=node.name,
personality=node.personality,
mac_address=node.pxe_nic_mac))
node.boot_server_to_pxe()
node_installation_threads = list()
for nodes_instance in nodes_instances:
thread = threading.Thread(
target=nodes_instance.follow_node_installation())
LOG.info('Starting installation on {}'.format(nodes_instance.name))
thread.start()
node_installation_threads.append(thread)
# Waiting for nodes to be installed
LOG.info('Waiting for nodes to be installed')
for node_installation_thread in node_installation_threads:
node_installation_thread.join()
LOG.info('All nodes have been installed successfully!')

View File

@ -0,0 +1,62 @@
*** Settings ***
Documentation Lock and Unlock compute and storage hosts. Swact a controller.
... Author(s):
... - Jose Perez Carranza <jose.perez.carranza@intel.com>
... - Juan Carlos Alonso <juan.carlos.alonso@intel.com>
Library SSHLibrary
Library Collections
Library OperatingSystem
Library Libraries/common.py
Library String
Variables Variables/Global.py
Variables Variables/config_init.py Config
... %{PYTHONPATH}/Config/config.ini
*** Keywords ***
Unlock Controller
[Arguments] ${controller_name}
[Documentation] Unlocks specified controller.
Wait Until Keyword Succeeds 15 min 10 sec Check Property Value
... ${controller_name} availability online
${result} Run Command system host-unlock ${controller_name} True
... 60
Wait Until Keyword Succeeds 20 min 5 sec Check Property Value
... ${controller_name} administrative unlocked
[Return] ${result}
Unlock Compute
[Arguments] ${compute}
[Documentation] Unlock specified compute.
Run Command system host-unlock ${compute} True 60 sec
Check Host Readiness ${compute}
Lock Node
[Documentation] Locks specified node.
[Arguments] ${controller_name}
Wait Until Keyword Succeeds 5 min 10 sec Check Property Value
... ${controller_name} availability available
${result} Run Command system host-lock ${controller_name} True
Wait Until Keyword Succeeds 5 min 10 sec Check Property Value
... ${controller_name} administrative locked
[Return] ${result}
Swact Controller
[Arguments] ${controller}
[Documentation] Swact the active controller and activates the SSH
... connection with the new active controller
${result} Run Command system host-swact ${controller} True
${new_act_cont} Set Variable If
... '${controller}'=='controller -0' controller-1 controller-0
Wait Until Keyword Succeeds 10 min 2 sec Check Host Task
... ${controller} Swact: Complete
Check Host Readiness ${new_act_cont} 1
# - Switch SSH connection to the Active Controller
Switch Controller Connection ${secondary_controller_connection}
... ${master_controller_connection}
Unlock Storage
[Arguments] ${storage}
[Documentation] Unlock specified storage node.
Run Command system host-unlock ${storage} True 60 sec
Check Host Readiness ${storage}

View File

@ -0,0 +1,93 @@
*** Settings ***
Documentation Checks the health of the PODs, kube system services and
... perform a helm override to openstack application.
... Author(s):
... - Jose Perez Carranza <jose.perez.carranza@intel.com>
... - Juan Carlos Alonso <juan.carlos.alonso@intel.com>
Library SSHLibrary
Library Collections
Library OperatingSystem
Library Libraries/common.py
Library String
Variables Variables/Global.py
Variables Variables/config_init.py Config
... %{PYTHONPATH}/Config/config.ini
*** Keywords ***
Check PODs Health
[Documentation] Check all OpenStack pods are healthy
${kubectl_cmd} Set Variable kubectl get pods --all-namespaces -o wide
${cmd} Catenate SEPARATOR=| ${kubectl_cmd} grep -v NAMESPACE
... grep -v Running grep -v Completed
&{result} Run Command ${cmd}
${value} Get From Dictionary ${result} stdout
Should Be Empty ${value}
Helm Override OpenStack
[Arguments] ${app_name} ${char_name} ${namespace}
[Documentation] Helm override for OpenStack nova chart and reset.
${kubectl_cmd} Set Variable system helm-override-update
${cmd} Catenate ${kubectl_cmd} --set conf.nova.DEFAULT.foo=bar
... ${app_name} ${char_name} ${namespace}
Run Command ${cmd} True
Check Helm Override OpenStack
[Documentation] Check nova-compute.conf is updated in all nova-compute
... containers.
${kubectl_cmd} Set Variable kubectl get pods --all-namespaces -o wide
${cmd} Catenate SEPARATOR=| ${kubectl_cmd} grep nova-compute
... awk '{print $2}'
&{result} Run Command ${cmd}
@{nova_pod_list} Convert Response To List ${result}
${kubectl_cmd} Set Variable kubectl exec -n openstack -it
: FOR ${nova_pod} IN @{nova_pod_list}
\ ${cmd} Catenate ${kubectl_cmd} ${nova_pod}
... -- grep foo /etc/nova/nova.conf
\ &{result} Run Command ${cmd}
\ Should Contain ${result.stdout} foo = bar
Check Kube System Services
[Documentation] Check pods status and kube-system services are
... displayed.
${kubectl_cmd} Set Variable kubectl get services -n kube-system
${cmd} Catenate SEPARATOR=| ${kubectl_cmd} grep -v NAME
... awk '{print $1}'
&{result} Run Command ${cmd}
${kubeb_systems} Get From Dictionary ${result} stdout
Should Contain ${kubeb_systems} ingress
Should Contain ${kubeb_systems} ingress-error-pages
Should Contain ${kubeb_systems} ingress-exporter
Should Contain ${kubeb_systems} kube-dns
Should Contain ${kubeb_systems} tiller-deploy
&{result} Run Command kubectl get deployments.apps -n kube-system
${kubeb_systems} Get From Dictionary ${result} stdout
Should Contain ${kubeb_systems} calico-kube-controllers
Should Contain ${kubeb_systems} coredns
Should Contain ${kubeb_systems} ingress-error-pages
Should Contain ${kubeb_systems} rbd-provisioner
Should Contain ${kubeb_systems} tiller-deploy
Create POD
[Arguments] ${pod_yml} ${pod_name}
[Documentation] Create a POD.
&{result} Run Command kubectl create -f ${pod_yml}
${value} Get From Dictionary ${result} stdout
Should Be Equal As Strings ${value} pod/${pod_name} created
Delete POD
[Arguments] ${pod_name}
[Documentation] Delete a POD.
&{result} Run Command kubectl delete pods ${pod_name} timeout=60
${value} Get From Dictionary ${result} stdout
Should Be Equal As Strings ${value} pod "${pod_name}" deleted
Check POD
[Arguments] ${pod_name}
[Documentation] Check if a POD is running.
${kubectl_cmd} Set Variable kubectl get pods -n default
${cmd} Catenate SEPARATOR=| ${kubectl_cmd} grep ${pod_name}
... awk '{print $3}'
&{result} Run Command ${cmd}
${status} Get From Dictionary ${result} stdout
Should Be Equal As Strings ${status} Running

View File

@ -0,0 +1,477 @@
*** Settings ***
Documentation Establish a SSH connection with the master controller to
... execute openstack commands to create networks, subnetworks, flavors,
... images, volumes, snapshots, instances, etc.
... Author(s):
... - Jose Perez Carranza <jose.perez.carranza@intel.com>
... - Juan Carlos Alonso <juan.carlos.alonso@intel.com>
Library Collections
Library SSHLibrary
Library String
Resource Resources/Utils.robot
Variables Variables/Global.py
*** Keywords ***
Run OS Command
[Arguments] ${cmd} ${fail_if_error}=False ${timeout}=${TIMEOUT+20}
[Documentation] Keyword to execute exclusively commands for OpenStack as
... it uses the proper token for OS authentication.
${load_os_token} Set Variable export OS_CLOUD=openstack_helm
${stdout} ${stderr} ${rc} Execute Command
... ${load_os_token} && ${cmd} return_stdout=True
... return_stderr=True return_rc=True timeout=${timeout}
${res} Create dictionary stdout=${stdout} stderr=${stderr}
... rc=${rc}
Run Keyword If ${rc} != 0 and ${fail_if_error} == True FAIL
... ${stderr}
[Return] ${res}
Create Network
[Arguments] ${network_name} ${additional_args}=${EMPTY}
... ${verbose}=TRUE
[Documentation] Create Network with openstack request.
${openstack_cmd} Set Variable openstack network create
${cmd} Catenate ${openstack_cmd} ${network_name}
... ${additional_args}
Run OS Command ${cmd} True 30 sec
Create Subnet
[Arguments] ${network_name} ${range_ip}
... ${additional_args}=${EMPTY}
[Documentation] Create SubNet for the Network with neutron request.
${openstack_cmd} Set Variable openstack subnet create
${cmd} Catenate ${openstack_cmd} --network ${network_name}
... --subnet-range ${range_ip} ${additional_args}
Run OS Command ${cmd} True 30 sec
Create Flavor
[Arguments] ${ram} ${vcpus} ${disk} ${name}
... ${extra_args}=${EMPTY}
[Documentation] Create a flavor with specified values.
${openstack_cmd} Set Variable openstack flavor create
${cmd} Catenate ${openstack_cmd} --ram ${ram} --disk ${disk}
... --vcpus ${vcpus} --public --id auto ${extra_args}
... ${name}
Run OS Command ${cmd} True 3 min
Create Image
[Arguments] ${file_path} ${disk_format} ${name}
[Documentation] Create image from a given .img file.
SSHLibrary.File Should Exist ${file_path}
${openstack_cmd} Set Variable openstack image create
${cmd} Catenate ${openstack_cmd} --file ${file_path}
... --disk-format ${disk_format} --public ${name}
Run OS Command ${cmd} True 3 min
Wait Until Keyword Succeeds 5 min 10 sec Check Field Value
... image ${name} status active
Create Volume
[Arguments] ${size} ${image} ${bootable} ${name}
[Documentation] Create Volume.
${openstack_cmd} Set Variable openstack volume create
${cmd} Catenate ${openstack_cmd} --size ${size}
... --image ${image} ${bootable} ${name}
Run OS Command ${cmd} True 30 sec
Wait Until Keyword Succeeds 10 min 10 sec Check Field Value
... volume ${name} status available
Create Snapshot
[Arguments] ${volume} ${name}
[Documentation] Create Snapshot.
Run OS Command
... openstack volume snapshot create --volume ${volume} ${name}
... True 30 sec
Wait Until Keyword Succeeds 5 min 10 sec Check Field Value
... volume snapshot ${name} status available
Create Stack
[Arguments] ${stack_name} ${stack_template} ${net_id}
[Documentation] Create Stack
${openstack_cmd} Set Variable openstack stack create --template
${cmd} Catenate ${openstack_cmd} ${stack_template}
... ${stack_name} --parameter "NetID=${net_id}"
${output} Run OS Command ${cmd}
Wait Until Keyword Succeeds 5 min 10 sec Check Field Value
... stack ${stack_name} stack_status CREATE_COMPLETE
${openstack_cmd} Set Variable openstack server list
${cmd} Catenate SEPARATOR=| ${openstack_cmd} awk '{print$4}'
... grep -v "Name"
&{result} Run OS Command ${cmd} True 30 sec
@{vm_list} Convert Response To List ${result}
: FOR ${vm} IN @{vm_list}
\ Wait Until Keyword Succeeds 5 min 10 sec Check Field Value
... server ${vm} status ACTIVE
\ Wait Until Keyword Succeeds 5 min 10 sec Check Field Value
... server ${vm} power_state Running
Create Instance
[Arguments] ${net_name} ${vm_name} ${image} ${flavor}
[Documentation] Create a VM Instances with the net id of the Netowrk
... flavor and image