221 lines
7.7 KiB
Python
221 lines
7.7 KiB
Python
"""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 : %s', 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: %s', 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().decode('utf-8'))
|
|
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()
|