[robot] Add configs and environment setup
Enable different configurations and setup requirements for deployment environments as well as pip requirements. - Config : Serie of configuration files to be used on deployment as well as exposed to the framework in order to use the values on the test cases. - Qemu : All artifacts needed to deploy the virtual machines that simulate the nodes on libvirt/qemu - Baremetal : Series of configuration files used to setup a deployment on a baremetal environment - requirements.txt, test-requirements.txt : series of packages needed by the suite to work on a python virtualenv. Depends-On: I796dcaf71089424dd37a050691fd0ee003ad3176 Change-Id: I34dfe1c01b27e5e8ce046de3305dd78c7f9d1383 Signed-off-by: Jose Perez Carranza <jose.perez.carranza@intel.com>changes/37/676237/6
parent
2d3d047a8c
commit
4ee20f9e40
|
@ -0,0 +1,54 @@
|
|||
[general]
|
||||
LOG_PATH = /tmp/logs
|
||||
IP_UNIT_0_ADDRESS = 10.10.10.3
|
||||
IP_UNIT_1_ADDRESS = 10.10.10.4
|
||||
CIRROS_FILE = cirros-0.4.0-x86_64-disk.qcow2
|
||||
CENTOS_FILE = CentOS-7-x86_64-GenericCloud.qcow2
|
||||
UBUNTU_FILE = xenial-server-cloudimg-amd64-disk1.qcow2
|
||||
WINDOWS_FILE = windows_server_2012_r2.qcow2
|
||||
APP_TARBALL = stx-openstack.tgz
|
||||
STX_ISO_FILE = bootimage.iso
|
||||
ENV_YAML_FILE = Qemu/qemu_setup.yaml
|
||||
CONFIGURATION_TYPE = simplex
|
||||
ENVIRONMENT = virtual
|
||||
CONFIGURATION_FILE = stx-simplex.yml
|
||||
|
||||
[credentials]
|
||||
STX_DEPLOY_USER_NAME = sysadmin
|
||||
STX_DEPLOY_USER_PSWD = St4rlingX*
|
||||
|
||||
[iso_installer]
|
||||
KERNEL_OPTION = 0
|
||||
VIRSH_CMD = virsh -c qemu:///system console controller-0
|
||||
VMLINUZ = vmlinuz append rootwait
|
||||
CONSOLES = console=tty0,115200 console=ttyS0,115200 inst.text
|
||||
SERIAL = serial
|
||||
OPTS_1 = inst.stage2=hd:LABEL=oe_iso_boot user_namespace.enable=1
|
||||
SYS_TYPE_1 = inst.ks=hd:LABEL=oe_iso_boot:/ks.cfg
|
||||
SYS_TYPE_2 = inst.ks=hd:LABEL=oe_iso_boot:/smallsystem_ks.cfg
|
||||
SYS_TYPE_3 = inst.ks=hd:LABEL=oe_iso_boot:/smallsystem_lowlatency_ks.cfg
|
||||
OPTS_2 = boot_device=sda rootfs_device=sda biosdevname=0 usbcore.autosuspend=-1 inst.gpt
|
||||
SEC_PROF_1 = security_profile=standard
|
||||
SEC_PROF_2 = security_profile=extended
|
||||
INITRD = initrd=initrd.img
|
||||
BOOT_TIMEOUT = 1200
|
||||
CONFIG_CONTROLLER_TIMEOUT = 3600
|
||||
CONTROLLER_TMP_IP = 10.10.10.3
|
||||
CONTROLLER_TMP_GATEWAY = 10.10.10.1
|
||||
|
||||
[logical_interface]
|
||||
OAM = enp2s1
|
||||
MGMT = enp2s2
|
||||
|
||||
[baremetal]
|
||||
HTTP_SERVER = 192.168.200.3
|
||||
|
||||
[dashboard]
|
||||
HORIZON_USERNAME = admin
|
||||
HORIZON_PASSWORD = St4rlingX*
|
||||
BROWSER = firefox
|
||||
PROFILE = nk0f1p65.automation
|
||||
|
||||
[qemu]
|
||||
XML = /etc/libvirt/qemu/networks/autostart/default.xml
|
||||
CONFIG_FILE = /etc/libvirt/qemu.conf
|
|
@ -0,0 +1,144 @@
|
|||
"""Config file parser and config file generator.
|
||||
|
||||
Configuration values will be read from a file called <CONFIG_FILE>.
|
||||
A config file with default values can be generated by running this module as a
|
||||
script and using the --generate option.
|
||||
|
||||
The config file is a standard INI file that contains [sections] and options.
|
||||
|
||||
Variables that are between %(option)s are interpolated automatically by the
|
||||
ConfigParser (with the caveat that they have to be in the same section).
|
||||
Variables that are between ${section:option} will be interpolated with the
|
||||
value from the appropriate section (similar to the way ConfigParse from
|
||||
Python3 works).
|
||||
|
||||
Example of a config file:
|
||||
|
||||
E.g.
|
||||
|
||||
[Section1]
|
||||
key_1 = value 1
|
||||
key_2 = value 2
|
||||
country = mexico
|
||||
|
||||
[section2]
|
||||
name = John
|
||||
lastname = Doe
|
||||
fullname = %(name)s %(lastname)s
|
||||
country = ${Section1:country}
|
||||
|
||||
To access config values from other modules follow this approach:
|
||||
|
||||
import Config.config as CONF
|
||||
full_name = CONF.get('section2', 'fullname')
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import configparser
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
CONFIG_FILE = os.path.join(os.path.dirname(__file__), 'config.ini')
|
||||
CONFIG = configparser.SafeConfigParser()
|
||||
|
||||
|
||||
def get(section, option, raw=False, variables=None):
|
||||
"""Wrapper function to mimic behavior of ConfigParse (Python3).
|
||||
|
||||
Python3 uses a ConfigParse that is different than the Python2 ConfigParser,
|
||||
it has some additional functionality. One of the biggest differences is
|
||||
that with ConfigParse you can interpolate variables from one section into
|
||||
another section of the config file. This functionality is not included in
|
||||
the ConfigParse. Since it is very useful, this function wraps the original
|
||||
get function from ConfigParser so it includes the missing interpolation.
|
||||
:param section: the section where the option to be gotten is
|
||||
:param option: the option to look for in the config file
|
||||
:param raw: all the '%' interpolations are expanded in the return values,
|
||||
unless the raw argument is true.
|
||||
:param variables: the option is looked up in variables (if provided)
|
||||
:return: the specified value from the config file
|
||||
"""
|
||||
# ensure file readed is up to date always
|
||||
CONFIG.read(CONFIG_FILE)
|
||||
original_option = CONFIG.get(section, option, raw=raw, vars=variables)
|
||||
# find all matches that have the following pattern: ${something}
|
||||
matches = re.findall(r'\$\{(.*?)\}', original_option)
|
||||
new_value = original_option
|
||||
for match in matches:
|
||||
# interpolate matches found with ${something} with the referenced
|
||||
# option from the appropriate section
|
||||
pattern = '${' + match + '}'
|
||||
value = match.split(':')
|
||||
foreign_value = CONFIG.get(value[0], value[1])
|
||||
new_value = new_value.replace(pattern, foreign_value)
|
||||
if original_option != new_value:
|
||||
CONFIG.set(section, option, new_value)
|
||||
|
||||
# return the interpolated value
|
||||
return CONFIG.get(section, option, raw=raw, vars=variables)
|
||||
|
||||
|
||||
def getint(section, option):
|
||||
"""Wrapper that returns the value as an integer.
|
||||
|
||||
:param section: the section where the option to be gotten is
|
||||
:param option: the option to look for in the config file
|
||||
:return: the specified value from the config file
|
||||
"""
|
||||
return int(CONFIG.get(section, option))
|
||||
|
||||
|
||||
def getfloat(section, option):
|
||||
"""Wrapper that returns the value as a float.
|
||||
|
||||
:param section: the section where the option to be gotten is
|
||||
:param option: the option to look for in the config file
|
||||
:return: the specified value from the config file
|
||||
"""
|
||||
return float(CONFIG.get(section, option))
|
||||
|
||||
|
||||
def getboolean(section, option):
|
||||
"""Wrapper that returns the value as a boolean.
|
||||
|
||||
:param section: the section where the option to be gotten is
|
||||
:param option: the option to look for in the config file
|
||||
:return: the specified value from the config file
|
||||
"""
|
||||
value = CONFIG.get(section, option)
|
||||
return value.lower() == 'true'
|
||||
|
||||
|
||||
def _unload_current_values():
|
||||
"""Removes current sections from the existing config object"""
|
||||
for section in CONFIG.sections():
|
||||
CONFIG.remove_section(section)
|
||||
|
||||
|
||||
def create_config():
|
||||
"""Creates the config file in the current directory"""
|
||||
if os.path.isfile(CONFIG_FILE):
|
||||
os.remove(CONFIG_FILE)
|
||||
with open(CONFIG_FILE, 'wb') as configfile:
|
||||
_unload_current_values()
|
||||
CONFIG.write(configfile)
|
||||
|
||||
|
||||
def parse_arguments():
|
||||
"""Parses arguments from the command line"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Config file generator')
|
||||
parser.add_argument(
|
||||
'--generate', action='store_true',
|
||||
help='Generates a config file with default values')
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ARGUMENTS = parse_arguments()
|
||||
if ARGUMENTS.generate:
|
||||
create_config()
|
||||
print('Config file created at: {name}'.format(name=CONFIG_FILE))
|
|
@ -0,0 +1,16 @@
|
|||
system_mode: duplex
|
||||
|
||||
dns_servers:
|
||||
- 8.8.8.8
|
||||
|
||||
docker_http_proxy: http://<url>:<port>
|
||||
docker_https_proxy: http://<url>:<port>
|
||||
|
||||
external_oam_subnet: 10.10.10.0/24
|
||||
external_oam_gateway_address: 10.10.10.1
|
||||
external_oam_floating_address: 10.10.10.2
|
||||
external_oam_node_0_address: 10.10.10.3
|
||||
external_oam_node_1_address: 10.10.10.4
|
||||
|
||||
ansible_become_pass: ANSIBLE_PASS
|
||||
admin_password: ADMIN_PASS
|
|
@ -0,0 +1,16 @@
|
|||
system_mode: duplex
|
||||
|
||||
dns_servers:
|
||||
- 8.8.8.8
|
||||
|
||||
docker_http_proxy: http://<url>:<port>
|
||||
docker_https_proxy: http://<url>:<port>
|
||||
|
||||
external_oam_subnet: 10.10.10.0/24
|
||||
external_oam_gateway_address: 10.10.10.1
|
||||
external_oam_floating_address: 10.10.10.2
|
||||
external_oam_node_0_address: 10.10.10.3
|
||||
external_oam_node_1_address: 10.10.10.4
|
||||
|
||||
ansible_become_pass: ANSIBLE_PASS
|
||||
admin_password: ADMIN_PASS
|
|
@ -0,0 +1,12 @@
|
|||
dns_servers:
|
||||
- 8.8.8.8
|
||||
|
||||
docker_http_proxy: http://<url>:<port>
|
||||
docker_https_proxy: http://<url>:<port>
|
||||
|
||||
external_oam_subnet: 10.10.10.0/24
|
||||
external_oam_gateway_address: 10.10.10.1
|
||||
external_oam_floating_address: 10.10.10.3
|
||||
|
||||
ansible_become_pass: ANSIBLE_PASS
|
||||
admin_password: ADMIN_PASS
|
|
@ -0,0 +1,155 @@
|
|||
[qemu_logo]: ./images/qemu_logo.png
|
||||
|
||||
![alt text][qemu_logo]
|
||||
|
||||
Table of Contents
|
||||
|
||||
- [qemu_setup.yml](#qemu_setupyml)
|
||||
- [Description](#description)
|
||||
- [Examples](#examples)
|
||||
- [1 controller + 2 compute](#1-controller--2-computes)
|
||||
- [parameters](#parameters)
|
||||
- [1 controller + 2 computes & 1 controller + 1 compute](#1-controller--2-computes--1-controller--1-compute)
|
||||
- [Highlights](#highlights)
|
||||
- [general_system_configurations section](#general_system_configurations-section)
|
||||
|
||||
# qemu_setup.yml
|
||||
The purpose of this configurations file is to setup easily QEMU in the host.
|
||||
|
||||
# Description
|
||||
YAML is a human-readable data serialization format that takes concepts from
|
||||
programming languages such as C, Perl, and Python, and ideas from XML and the
|
||||
data format of electronic mail.
|
||||
It is available for several programming languages.
|
||||
|
||||
# Examples
|
||||
|
||||
## 1 controller + 2 computes
|
||||
Please consider the following example to setup the following configuration:
|
||||
|
||||
`1 controller + 2 computes`
|
||||
|
||||
```yaml
|
||||
configuration_0:
|
||||
controller-0:
|
||||
controller_0_partition_a: 20
|
||||
controller_0_partition_b: 10
|
||||
controller_0_memory_size: 5120
|
||||
controller_0_system_cores: 2
|
||||
controller-0-compute-0:
|
||||
controller_0_compute_0_partition_a: 20
|
||||
controller_0_compute_0_partition_b: 20
|
||||
controller_0_compute_0_memory_size: 3072
|
||||
controller_0_compute_0_system_cores: 1
|
||||
controller-0-compute-1:
|
||||
controller_0_compute_1_partition_a: 20
|
||||
controller_0_compute_1_partition_b: 20
|
||||
controller_0_compute_1_memory_size: 3072
|
||||
controller_0_compute_1_system_cores: 1
|
||||
````
|
||||
|
||||
### parameters
|
||||
|
||||
**`@param: configuration_0`**: which contains the controller and the computes.<br>
|
||||
|
||||
**`@param: controller-0`**: which contains the following:<br>
|
||||
- `@param: controller_0_partition_a`: which is the controller 0 partition size
|
||||
A in GB.
|
||||
- `@param: controller_0_partition_b`: which is the controller 0 partition size
|
||||
B size in GB.
|
||||
- `@param: controller_0_memory_size`: which is the controller 0 memory size
|
||||
in MB.
|
||||
- `@param: controller_0_system_cores`: which is the controller 0 system cores
|
||||
to be assigned.
|
||||
|
||||
**`@param: controller-0-compute-0`**: which contains the following:<br>
|
||||
- `@param: controller_0_compute_0_partition_a`: which is the controller's
|
||||
compute 0 partition size A in GB.
|
||||
- `@param: controller_0_compute_0_partition_b`: which is the controller's
|
||||
compute 0 partition size B in GB.
|
||||
- `@param: controller_0_compute_0_memory_size`: which is the controller's
|
||||
compute 0 memory size B in MB.
|
||||
- `@param: controller_0_compute_0_system_cores`: which is the controller's
|
||||
compute 0 system cores to be assigned.
|
||||
|
||||
**`@param: controller-0-compute-1`**: which contains the following:<br>
|
||||
- `@param: controller_0_compute_1_partition_a`: which is the controller's
|
||||
compute 1 partition size A in GB.
|
||||
- `@param: controller_0_compute_1_partition_b`: which is the controller's
|
||||
compute 1 partition size B in GB.
|
||||
- `@param: controller_0_compute_1_memory_size`: which is the controller's
|
||||
compute 1 memory size B in MB.
|
||||
- `@param: controller_0_compute_1_system_cores`: which is the controller's
|
||||
compute 1 system cores to be assigned.
|
||||
|
||||
## 1 controller + 2 computes & 1 controller + 1 compute
|
||||
Please consider the following example to setup the following configuration:
|
||||
|
||||
`1 controller + 2 computes & 1 controller + 1 compute`
|
||||
|
||||
```yaml
|
||||
configuration_0:
|
||||
controller-0:
|
||||
controller_0_partition_a: 20
|
||||
controller_0_partition_b: 10
|
||||
controller_0_memory_size: 5120
|
||||
controller_0_system_cores: 2
|
||||
controller-0-compute-0:
|
||||
controller_0_compute_0_partition_a: 20
|
||||
controller_0_compute_0_partition_b: 20
|
||||
controller_0_compute_0_memory_size: 3072
|
||||
controller_0_compute_0_system_cores: 1
|
||||
controller-0-compute-1:
|
||||
controller_0_compute_1_partition_a: 20
|
||||
controller_0_compute_1_partition_b: 20
|
||||
controller_0_compute_1_memory_size: 3072
|
||||
controller_0_compute_1_system_cores: 1
|
||||
configuration_1:
|
||||
controller-1:
|
||||
controller_1_partition_a: 15
|
||||
controller_1_partition_b: 10
|
||||
controller_1_memory_size: 5120
|
||||
controller_1_system_cores: 2
|
||||
controller-1-compute-0:
|
||||
controller_1_compute_0_partition_a: 20
|
||||
controller_1_compute_0_partition_b: 20
|
||||
controller_1_compute_0_memory_size: 3072
|
||||
controller_1_compute_0_system_cores: 1
|
||||
```
|
||||
|
||||
:notebook: the parameters description are the same that the [section above](#parameters).
|
||||
|
||||
## Highlights
|
||||
Please consider the following when creating the yaml configuration file:
|
||||
|
||||
- The total sum of the partitions must not exceed of the total free disk space
|
||||
in the host.
|
||||
- The total sum of the memory size must not exceed of the total free memory
|
||||
size in the host.
|
||||
- The total sum of the system cores must not exceed of the total system cores
|
||||
subtracting the `os_system_cores` assigned in `general_system_configurations`
|
||||
section.
|
||||
|
||||
|
||||
## general_system_configurations section
|
||||
The general_system_configurations will be explained below:
|
||||
|
||||
```yaml
|
||||
general_system_configurations:
|
||||
os_system_memory: 1024
|
||||
disk_space_allocated_to_os: 20
|
||||
os_system_cores: 2
|
||||
default_mount_point: '/'
|
||||
```
|
||||
|
||||
**`@param: general_system_configurations`**: which contains the following:
|
||||
- `@param: os_system_memory`: which is the system memory reserved for the OS.
|
||||
- `@param: disk_space_allocated_to_os`: which is the disk space reserved for
|
||||
the OS.
|
||||
- `@param: os_system_cores`: which is the system cores reserved for the OS.
|
||||
- `@param: default_mount_point`: which is the mount point where the space in
|
||||
disk will be analyzed by the script.
|
||||
|
||||
:notebook: The first 3 params are used for system reservation and they are for
|
||||
the user's consideration in order to avoid that QEMU takes all the resources
|
||||
making slow the current system.
|
|
@ -0,0 +1,92 @@
|
|||
<domain type='kvm' id='187'>
|
||||
<name>NAME</name>
|
||||
<memory unit='UNIT'>MEMORY</memory>
|
||||
<currentMemory unit='UNIT'>MEMORY</currentMemory>
|
||||
<vcpu placement='static'>CORES</vcpu>
|
||||
<resource>
|
||||
<partition>/machine</partition>
|
||||
</resource>
|
||||
<os>
|
||||
<type arch='x86_64' machine='pc'>hvm</type>
|
||||
</os>
|
||||
<features>
|
||||
<acpi/>
|
||||
<apic/>
|
||||
<pae/>
|
||||
</features>
|
||||
<cpu match='exact'>
|
||||
<model fallback='forbid'>Nehalem</model>
|
||||
<topology sockets='1' cores='CORES' threads='1'/>
|
||||
<feature policy='require' name='vmx'/>
|
||||
<feature policy='optional' name='svm'/>
|
||||
</cpu>
|
||||
<clock offset='utc'/>
|
||||
<on_poweroff>destroy</on_poweroff>
|
||||
<on_reboot>restart</on_reboot>
|
||||
<on_crash>destroy</on_crash>
|
||||
<devices>
|
||||
<emulator>/usr/bin/qemu-system-x86_64</emulator>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='qcow2'/>
|
||||
<source file='DISK0'/>
|
||||
<backingStore/>
|
||||
<target dev='sda' bus='sata'/>
|
||||
<boot order='1'/>
|
||||
</disk>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='qcow2'/>
|
||||
<source file='DISK1'/>
|
||||
<backingStore/>
|
||||
<target dev='sdb' bus='sata'/>
|
||||
</disk>
|
||||
<interface type='bridge'>
|
||||
<source bridge='stxbr1'/>
|
||||
<target dev='vnet8'/>
|
||||
<model type='e1000'/>
|
||||
<alias name='net0'/>
|
||||
</interface>
|
||||
<interface type='bridge'>
|
||||
<source bridge='stxbr2'/>
|
||||
<target dev='vnet9'/>
|
||||
<model type='e1000'/>
|
||||
<boot order='2'/>
|
||||
<alias name='net1'/>
|
||||
</interface>
|
||||
<interface type='bridge'>
|
||||
<source bridge='stxbr3'/>
|
||||
<target dev='vnet10'/>
|
||||
<model type='virtio'/>
|
||||
<alias name='net2'/>
|
||||
</interface>
|
||||
<interface type='bridge'>
|
||||
<source bridge='stxbr4'/>
|
||||
<target dev='vnet11'/>
|
||||
<model type='virtio'/>
|
||||
<alias name='net3'/>
|
||||
</interface>
|
||||
<serial type='pty'>
|
||||
<source path='/dev/pts/12'/>
|
||||
<target port='0'/>
|
||||
<alias name='serial0'/>
|
||||
</serial>
|
||||
<console type='pty' tty='/dev/pts/12'>
|
||||
<source path='/dev/pts/12'/>
|
||||
<target type='serial' port='0'/>
|
||||
<alias name='serial0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='keyboard' bus='ps2'/>
|
||||
<graphics type='vnc' port='5903' autoport='yes' listen='127.0.0.1' keymap='en-us'>
|
||||
<listen type='address' address='127.0.0.1'/>
|
||||
</graphics>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
<alias name='video0'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
|
||||
</video>
|
||||
<memballoon model='virtio'>
|
||||
<alias name='balloon0'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
|
||||
</memballoon>
|
||||
</devices>
|
||||
</domain>
|
|
@ -0,0 +1,18 @@
|
|||
Controllers:
|
||||
controller-0:
|
||||
partition_a: 600
|
||||
partition_b: 100
|
||||
partition_d: 100
|
||||
memory_size: 25600
|
||||
system_cores: 6
|
||||
controller-1:
|
||||
partition_a: 600
|
||||
partition_b: 100
|
||||
partition_d: 100
|
||||
memory_size: 25600
|
||||
system_cores: 6
|
||||
general_system_configurations:
|
||||
os_system_memory: 1024
|
||||
disk_space_allocated_to_os: 20
|
||||
os_system_cores: 2
|
||||
default_mount_point: '/'
|
|
@ -0,0 +1,29 @@
|
|||
Controllers:
|
||||
controller-0:
|
||||
partition_a: 250
|
||||
partition_b: 250
|
||||
partition_d: 50
|
||||
memory_size: 16384
|
||||
system_cores: 4
|
||||
controller-1:
|
||||
partition_a: 250
|
||||
partition_b: 250
|
||||
partition_d: 50
|
||||
memory_size: 16384
|
||||
system_cores: 4
|
||||
Computes:
|
||||
compute-0:
|
||||
partition_a: 250
|
||||
partition_b: 250
|
||||
memory_size: 10240
|
||||
system_cores: 3
|
||||
compute-1:
|
||||
partition_a: 250
|
||||
partition_b: 250
|
||||
memory_size: 10240
|
||||
system_cores: 3
|
||||
general_system_configurations:
|
||||
os_system_memory: 1024
|
||||
disk_space_allocated_to_os: 20
|
||||
os_system_cores: 2
|
||||
default_mount_point: '/'
|
|
@ -0,0 +1,42 @@
|
|||
Controllers:
|
||||
controller-0:
|
||||
partition_a: 250
|
||||
partition_b: 250
|
||||
partition_d: 50
|
||||
memory_size: 16384
|
||||
system_cores: 4
|
||||
controller-1:
|
||||
partition_a: 250
|
||||
partition_b: 250
|
||||
partition_d: 50
|
||||
memory_size: 16384
|
||||
system_cores: 4
|
||||
Computes:
|
||||
compute-0:
|
||||
partition_a: 250
|
||||
partition_b: 250
|
||||
memory_size: 10240
|
||||
system_cores: 3
|
||||
compute-1:
|
||||
partition_a: 250
|
||||
partition_b: 250
|
||||
memory_size: 10240
|
||||
system_cores: 3
|
||||
Storages:
|
||||
storage-0:
|
||||
partition_a: 250
|
||||
partition_b: 250
|
||||
partition_d: 50
|
||||
memory_size: 6144
|
||||
system_cores: 3
|
||||
storage-1:
|
||||
partition_a: 250
|
||||
partition_b: 250
|
||||
partition_d: 50
|
||||
memory_size: 6144
|
||||
system_cores: 3
|
||||
general_system_configurations:
|
||||
os_system_memory: 1024
|
||||
disk_space_allocated_to_os: 20
|
||||
os_system_cores: 2
|
||||
default_mount_point: '/'
|
|
@ -0,0 +1,12 @@
|
|||
Controllers:
|
||||
controller-0:
|
||||
partition_a: 600
|
||||
partition_b: 100
|
||||
partition_d: 100
|
||||
memory_size: 25600
|
||||
system_cores: 6
|
||||
general_system_configurations:
|
||||
os_system_memory: 1024
|
||||
disk_space_allocated_to_os: 20
|
||||
os_system_cores: 2
|
||||
default_mount_point: '/'
|
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
|
@ -0,0 +1,106 @@
|
|||
<domain type='kvm' id='164'>
|
||||
<name>NAME</name>
|
||||
<memory unit='UNIT'>MEMORY</memory>
|
||||
<currentMemory unit='UNIT'>MEMORY</currentMemory>
|
||||
<vcpu placement='static'>CORES</vcpu>
|
||||
<resource>
|
||||
<partition>/machine</partition>
|
||||
</resource>
|
||||
<os>
|
||||
<type arch='x86_64' machine='pc'>hvm</type>
|
||||
</os>
|
||||
<features>
|
||||
<acpi/>
|
||||
<apic/>
|
||||
<pae/>
|
||||
</features>
|
||||
<cpu match='exact'>
|
||||
<model fallback='forbid'>Nehalem</model>
|
||||
<topology sockets='1' cores='CORES' threads='1'/>
|
||||
<feature policy='optional' name='vmx'/>
|
||||
<feature policy='optional' name='svm'/>
|
||||
</cpu>
|
||||
<clock offset='utc'/>
|
||||
<on_poweroff>destroy</on_poweroff>
|
||||
<on_reboot>restart</on_reboot>
|
||||
<on_crash>destroy</on_crash>
|
||||
<devices>
|
||||
<emulator>/usr/bin/qemu-system-x86_64</emulator>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='qcow2'/>
|
||||
<source file='DISK0'/>
|
||||
<backingStore/>
|
||||
<target dev='sda' bus='sata'/>
|
||||
<boot order='1'/>
|
||||
</disk>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='qcow2'/>
|
||||
<source file='DISK1'/>
|
||||
<backingStore/>
|
||||
<target dev='sdb' bus='sata'/>
|
||||
</disk>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='qcow2'/>
|
||||
<source file='DISK2'/>
|
||||
<backingStore/>
|
||||
<target dev='sdd' bus='sata'/>
|
||||
</disk>
|
||||
<disk type='file' device='cdrom'>
|
||||
<driver name='qemu' type='raw'/>
|
||||
<source file='ISO'/>
|
||||
<backingStore/>
|
||||
<target dev='sdc' bus='sata'/>
|
||||
<readonly/>
|
||||
<boot order='2'/>
|
||||
</disk>
|
||||
<interface type='network'>
|
||||
<source network='stx-nat'/>
|
||||
<target dev='vnet0'/>
|
||||
<model type='e1000'/>
|
||||
<alias name='net0'/>
|
||||
</interface>
|
||||
<interface type='bridge'>
|
||||
<source bridge='stxbr2'/>
|
||||
<target dev='vnet1'/>
|
||||
<model type='e1000'/>
|
||||
<alias name='net1'/>
|
||||
</interface>
|
||||
<interface type='bridge'>
|
||||
<source bridge='stxbr3'/>
|
||||
<target dev='vnet2'/>
|
||||
<model type='virtio'/>
|
||||
<alias name='net2'/>
|
||||
</interface>
|
||||
<interface type='bridge'>
|
||||
<source bridge='stxbr4'/>
|
||||
<target dev='vnet3'/>
|
||||
<model type='virtio'/>
|
||||
<alias name='net3'/>
|
||||
</interface>
|
||||
<serial type='pty'>
|
||||
<source path='/dev/pts/8'/>
|
||||
<target port='0'/>
|
||||
<alias name='serial0'/>
|
||||
</serial>
|
||||
<console type='pty' tty='/dev/pts/8'>
|
||||
<source path='/dev/pts/8'/>
|
||||
<target type='serial' port='0'/>
|
||||
<alias name='serial0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='keyboard' bus='ps2'/>
|
||||
<graphics type='vnc' port='5900' autoport='yes' listen='127.0.0.1' keymap='en-us'>
|
||||
<listen type='address' address='127.0.0.1'/>
|
||||
</graphics>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
<alias name='video0'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
|
||||
</video>
|
||||
<memballoon model='virtio'>
|
||||
<alias name='balloon0'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
|
||||
</memballoon>
|
||||
</devices>
|
||||
</domain>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<network>
|
||||
<name>stx-nat</name>
|
||||
<bridge name="stxbr1" stp="off"/>
|
||||
<forward mode="nat"/>
|
||||
<ip address="10.10.10.1" netmask="255.255.255.0">
|
||||
</ip>
|
||||
</network>
|
|
@ -0,0 +1,638 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""This module setup the controller(s)/computes(s) in the current host"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
from argparse import RawDescriptionHelpFormatter
|
||||
from imp import reload
|
||||
import multiprocessing
|
||||
import os
|
||||
import re
|
||||
from shutil import copy
|
||||
from shutil import rmtree
|
||||
import sys
|
||||
|
||||
# this needs to be exactly here after call network.delete_network_interfaces()
|
||||
# otherwise the suite local modules they will not be recognized
|
||||
# hence adding `noqa` to avoid linter issues.
|
||||
SUITE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.append(SUITE_DIR)
|
||||
|
||||
from Config import config # noqa: E402
|
||||
from Utils import bash_utils as bash # noqa: E402
|
||||
from Utils import logger # noqa: E402
|
||||
from Utils import network # noqa: E402
|
||||
from Utils import utils # noqa: E402
|
||||
import kmodpy # noqa: E402
|
||||
import yaml # noqa: E402
|
||||
|
||||
# reloading config.ini
|
||||
reload(config)
|
||||
|
||||
# Global variables
|
||||
THIS_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# setup the logger
|
||||
LOG_FILENAME = 'qemu_setup.log'
|
||||
LOG_PATH = config.get('general', 'LOG_PATH')
|
||||
LOG = logger.setup_logging(
|
||||
'qemu_setup', log_file='{path}/{filename}'.format(
|
||||
path=LOG_PATH, filename=LOG_FILENAME), console_log=False)
|
||||
|
||||
|
||||
def enable_nat_network():
|
||||
"""Enable NAT network for VMs
|
||||
|
||||
This function creates a NAT network to allow VM external connection
|
||||
needed for download docker images.
|
||||
|
||||
"""
|
||||
|
||||
nat_xml = os.path.join(THIS_PATH, 'nat-network.xml')
|
||||
nat_net_name = 'stx-nat'
|
||||
bash.run_command('sudo virsh net-define {}'.format(nat_xml))
|
||||
bash.run_command('sudo virsh net-start {}'.format(nat_net_name))
|
||||
|
||||
|
||||
def exit_dict_status(code):
|
||||
"""Exit status
|
||||
|
||||
The aim of this function is to provide a exit status in dictionary format
|
||||
as an string in order to grab it for robot for perform actions.
|
||||
|
||||
:param code: which is the exit status code
|
||||
code 0: which represents an exit status god.
|
||||
code 1: which represents an exit status bad.
|
||||
"""
|
||||
# defining the dictionary
|
||||
|
||||
if code == 1:
|
||||
LOG.info('status: FAIL')
|
||||
elif code == 0:
|
||||
LOG.info('status: PASS')
|
||||
else:
|
||||
LOG.error('exit code not valid')
|
||||
|
||||
sys.exit(code)
|
||||
|
||||
|
||||
def check_kernel_virtualization():
|
||||
"""Check kernel virtualization
|
||||
|
||||
Checks if Virtualization Technology is enabled in the BIOS and it is
|
||||
present in the kernel as a module.
|
||||
QEMU requires KVM (Kernel Virtualization Module) to run the nodes.
|
||||
"""
|
||||
_km = kmodpy.Kmod()
|
||||
module_list = [m for m in _km.list()]
|
||||
|
||||
virtualization = filter(lambda mod: mod[0] == 'kvm_intel', module_list)
|
||||
|
||||
if not virtualization:
|
||||
message = ('KVM (vmx) is disabled by your BIOS\nEnter your BIOS setup '
|
||||
'and enable Virtualization Technology (VT), and then hard '
|
||||
'power off/power on your system')
|
||||
raise OSError(message)
|
||||
|
||||
|
||||
def check_preconditions():
|
||||
"""Check host preconditions
|
||||
|
||||
The aim of this function is to check the requirements to run QEMU in the
|
||||
host.
|
||||
"""
|
||||
# if this script is running through ssh connection the following
|
||||
# environment variable needs to be setup in the host bashrc
|
||||
if 'DISPLAY' not in os.environ:
|
||||
LOG.info('configuring DISPLAY environment variable')
|
||||
os.environ['DISPLAY'] = ':0'
|
||||
|
||||
|
||||
def get_system_memory(configurations):
|
||||
"""Get the system memory
|
||||
|
||||
The aim of this function is to get the system memory to be setup with QEMU.
|
||||
|
||||
:param: configurations
|
||||
- which is an object with the values loaded from the yaml.
|
||||
:return:
|
||||
- system_free_memory: which is the total system free memory.
|
||||
- recommended_system_free_memory: which is the recommended system free
|
||||
memory.
|
||||
"""
|
||||
|
||||
# calculating the system memory to be assigned (value in megabytes)
|
||||
# os_system_memory will return 0 if either key1 or key2 does not exists
|
||||
os_system_memory = configurations.get(
|
||||
'general_system_configurations', 0).get("os_system_memory", 0)
|
||||
system_free_memory = map(
|
||||
int, os.popen('free -m | grep Mem').readlines()[-1][4:].split())[-1]
|
||||
# subtracting OS system memory
|
||||
recommended_system_free_memory = system_free_memory - os_system_memory
|
||||
|
||||
return system_free_memory, recommended_system_free_memory
|
||||
|
||||
|
||||
def get_free_disk_space(configurations):
|
||||
"""Get the system free disk space
|
||||
|
||||
The aim of this function if to get the system free disk in order to setup
|
||||
with QEMU.
|
||||
|
||||
:param: configurations
|
||||
- which is an object with the values loaded from the yaml.
|
||||
:return
|
||||
- system_free_disk_size: which is the total system free disk size in GB
|
||||
- r_system_free_disk_size: which is the recommended system
|
||||
free disk size in GB subtracting the disk_space_allocated_to_os
|
||||
from yaml configuration file for the host OS in order to avoid
|
||||
low performance.
|
||||
"""
|
||||
# disk_space_allocated_to_os will return 0 if either key1 or key2 does
|
||||
# not exists
|
||||
disk_space_allocated_to_os = configurations.get(
|
||||
'general_system_configurations', 0).get(
|
||||
"disk_space_allocated_to_os", 0)
|
||||
# the mount point in which will be calculated the free space in disk
|
||||
default_mount_point = configurations.get(
|
||||
'general_system_configurations', 0).get(
|
||||
"default_mount_point", '/')
|
||||
statvfs = os.statvfs(default_mount_point)
|
||||
# the following value will be get in megabytes
|
||||
system_free_disk_size = statvfs.f_frsize * statvfs.f_bavail / 1000000000
|
||||
# subtracting the 20% of the total disk free
|
||||
r_system_free_disk_size = (
|
||||
(100 - disk_space_allocated_to_os) * system_free_disk_size / 100)
|
||||
|
||||
return system_free_disk_size, r_system_free_disk_size
|
||||
|
||||
|
||||
def get_system_resources(configurations):
|
||||
"""Get resources from the current host
|
||||
|
||||
The aim of this function is to get resources for the virtual environment
|
||||
with QEMU in order to setup properly it and avoid configuration issues.
|
||||
|
||||
:param: configurations
|
||||
- which is an object with the values loaded from the yaml.
|
||||
:return:
|
||||
- recommended_system_free_memory: which is the recommended system free
|
||||
memory to be setup with QEMU.
|
||||
- system_free_disk_size: which is the total system free disk size.
|
||||
- r_system_free_disk_size: which is the recommended system
|
||||
- r_system_free_disk_size: which is the recommended system
|
||||
free disk size.
|
||||
- recommended_system_cores: which is the recommended system cores to be
|
||||
setup with QEMU.
|
||||
"""
|
||||
# os_system_cores will return 0 if either key1 or key2 does not exists
|
||||
os_system_cores = configurations.get(
|
||||
'general_system_configurations', 0).get("os_system_cores", 0)
|
||||
|
||||
# Getting the system free memory and the recommended system memory
|
||||
_, recommended_system_free_memory = get_system_memory(
|
||||
configurations)
|
||||
|
||||
# Getting the system free disk size and the recommended system free (GB)
|
||||
system_free_disk_size, r_system_free_disk_size = (
|
||||
get_free_disk_space(configurations))
|
||||
|
||||
# Calculating the system cores to be assigned to the controller/computes
|
||||
recommended_system_cores = multiprocessing.cpu_count() - os_system_cores
|
||||
|
||||
return (
|
||||
recommended_system_free_memory,
|
||||
system_free_disk_size, r_system_free_disk_size,
|
||||
recommended_system_cores)
|
||||
|
||||
|
||||
def check_system_resources(configurations):
|
||||
"""Check basic configurations.
|
||||
|
||||
The aim of this function is to check the following aspects before to
|
||||
proceed to configure the nodes.
|
||||
- checks if the disk setup by the user in the yaml is less than the
|
||||
recommended free space
|
||||
- checks if the memory size setup by the user in the yaml is less than the
|
||||
recommended memory size.
|
||||
- checks if the system cores setup by the user in the yaml is less than the
|
||||
recommended system cores.
|
||||
|
||||
:param configurations: which is the object that contains all the
|
||||
configurations from the yaml file.
|
||||
"""
|
||||
# checking how many configurations the yaml file has
|
||||
configurations_keys = configurations.keys()
|
||||
regex = re.compile('configuration_.')
|
||||
total_configurations = list(filter(regex.match, configurations_keys))
|
||||
|
||||
# getting the system recommendations
|
||||
(recommended_system_free_memory, _,
|
||||
r_system_free_disk_size,
|
||||
recommended_system_cores) = get_system_resources(configurations)
|
||||
|
||||
# iterating over the total configurations setup in yaml file in order to
|
||||
# get the disk/memory space assigned by the user
|
||||
user_memory_defined, user_disk_space_defined, user_system_cores_defined = (
|
||||
0, 0, 0)
|
||||
|
||||
for configuration in range(0, len(total_configurations)):
|
||||
# iterating over the configurations
|
||||
|
||||
current_controller = 'controller-{}'.format(configuration)
|
||||
# controller will return NoneType if either key1 or key2 does
|
||||
# not exists
|
||||
controller = configurations.get(
|
||||
'configuration_{}'.format(configuration), {}).get(
|
||||
'controller-{}'.format(configuration), {})
|
||||
controller_partition_a = int(controller.get(
|
||||
'controller_{}_partition_a'.format(configuration)))
|
||||
controller_partition_b = int(controller.get(
|
||||
'controller_{}_partition_b'.format(configuration)))
|
||||
controller_partition_d = int(controller.get(
|
||||
'controller_{}_partition_d'.format(configuration)))
|
||||
controller_memory = int(controller.get(
|
||||
'controller_{}_memory_size'.format(configuration)))
|
||||
controller_system_cores = int(controller.get(
|
||||
'controller_{}_system_cores'.format(configuration)))
|
||||
|
||||
# checking if the current controller at least has 1 cpu assigned in
|
||||
# order to avoid the following error:
|
||||
# error: XML error: Invalid CPU topology
|
||||
if controller_system_cores < 1:
|
||||
LOG.error('{}: must have assigned at least 1 core'.format(
|
||||
current_controller))
|
||||
exit_dict_status(1)
|
||||
|
||||
# checking how many computes the current controller has
|
||||
compute_keys = configurations.get('configuration_{}'.format(
|
||||
configuration), {}).keys()
|
||||
regex = re.compile('controller-{0}-compute-.'.format(configuration))
|
||||
total_computes = list(filter(regex.match, compute_keys))
|
||||
|
||||
for compute_number in range(0, len(total_computes)):
|
||||
current_compute = '{0}-compute-{1}'.format(
|
||||
current_controller, compute_number)
|
||||
# compute will return NoneType if either key1 or key2 does
|
||||
# not exists controller_1_compute_2:
|
||||
compute = configurations.get('configuration_{}'.format(
|
||||
configuration), {}).get(
|
||||
'controller-{0}-compute-{1}'.format(
|
||||
configuration, compute_number), {})
|
||||
compute_partition_a = int(compute.get(
|
||||
'controller_{0}_compute_{1}_partition_a'.format(
|
||||
configuration, compute_number)))
|
||||
compute_partition_b = int(compute.get(
|
||||
'controller_{0}_compute_{1}_partition_b'.format(
|
||||
configuration, compute_number)))
|
||||
compute_memory = int(compute.get(
|
||||
'controller_{0}_compute_{1}_memory_size'.format(
|
||||
configuration, compute_number)))
|
||||
compute_system_cores = int(compute.get(
|
||||
'controller_{0}_compute_{1}_system_cores'.format(
|
||||
configuration, compute_number)))
|
||||
|
||||
# checking if the current compute at least has 1 cpu assigned in
|
||||
# order to avoid the following error:
|
||||
# error: XML error: Invalid CPU topology
|
||||
if compute_system_cores < 1:
|
||||
LOG.error('{}: must have assigned at least 1 core'.format(
|
||||
current_compute))
|
||||
exit_dict_status(1)
|
||||
|
||||
# increasing the variables (computes loop)
|
||||
user_disk_space_defined = (
|
||||
user_disk_space_defined + compute_partition_a +
|
||||
compute_partition_b)
|
||||
user_memory_defined = user_memory_defined + compute_memory
|
||||
user_system_cores_defined = (
|
||||
user_system_cores_defined + compute_system_cores)
|
||||
|
||||
# increasing the variables (controller loop)
|
||||
user_disk_space_defined = (
|
||||
user_disk_space_defined + controller_partition_a +
|
||||
controller_partition_b + controller_partition_d)
|
||||
user_memory_defined = user_memory_defined + controller_memory
|
||||
user_system_cores_defined = (
|
||||
user_system_cores_defined + controller_system_cores)
|
||||
|
||||
# checking the conditions defined in the yaml
|
||||
if user_memory_defined > recommended_system_free_memory:
|
||||
LOG.error(
|
||||
'the memory defined in the yaml is greater than the recommended '
|
||||
'free memory')
|
||||
LOG.error('user memory defined : {}'.format(
|
||||
user_memory_defined))
|
||||
LOG.error('recommended system free memory : {}'.format(
|
||||
recommended_system_free_memory))
|
||||
exit_dict_status(1)
|
||||
elif user_disk_space_defined > r_system_free_disk_size:
|
||||
LOG.error(
|
||||
'the disk space defined in the yaml is greater than the '
|
||||
'recommended free disk size')
|
||||
LOG.error('user disk space defined : {}'.format(
|
||||
user_disk_space_defined))
|
||||
LOG.error('recommended system free disk size : {}'.format(
|
||||
r_system_free_disk_size))
|
||||
exit_dict_status(1)
|
||||
elif user_system_cores_defined > recommended_system_cores:
|
||||
LOG.error(
|
||||
'the system cores defined in the yaml is greater than the '
|
||||
'recommended system cores')
|
||||
LOG.error('user system cores defined : {}'.format(
|
||||
user_system_cores_defined))
|
||||
LOG.error('recommended system cores : {}'.format(
|
||||
recommended_system_cores))
|
||||
exit_dict_status(1)
|
||||
|
||||
|
||||
def setup_controller_computes(iso_file, configurations):
|
||||
"""Setup the configurations in the host
|
||||
|
||||
This function setup the network and the configurations from yaml in the
|
||||
current host.
|
||||
|
||||
:param iso_file: which is the absolute/relative path to the iso file which
|
||||
will be setup in the controller(s) node(s).
|
||||
:param configurations: which is the object that has all the configurations
|
||||
to be setup in the system.
|
||||
"""
|
||||
# define the module's variables
|
||||
libvirt_images_path = '/var/lib/libvirt/images'
|
||||
|
||||
# ----------------------------------
|
||||
# customize Qemu configuration files
|
||||
# ----------------------------------
|
||||
utils.qemu_configuration_files()
|
||||
|
||||
# ----------------------------------
|
||||
# configuring the network interfaces
|
||||
# ----------------------------------
|
||||
network.delete_network_interfaces()
|
||||
enable_nat_network()
|
||||
network.configure_network_interfaces()
|
||||
|
||||
# ------------------------------
|
||||
# clean qemu/libvirt environment
|
||||
# ------------------------------
|
||||
utils.clean_qemu_environment()
|
||||
|
||||
if os.path.exists(os.path.join(THIS_PATH, 'vms')):
|
||||
rmtree(os.path.join(THIS_PATH, 'vms'))
|
||||
|
||||
os.mkdir(os.path.join(THIS_PATH, 'vms'))
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# iterating over the total configurations setup in yaml file
|
||||
# ----------------------------------------------------------
|
||||
|
||||
for controller, values in configurations.get('Controllers').items():
|
||||
# iterating over the controllers
|
||||
controller_partition_a = int(values.get('partition_a'))
|
||||
controller_partition_b = int(values.get('partition_b'))
|
||||
controller_partition_d = int(values.get('partition_d'))
|
||||
controller_memory = int(values.get('memory_size'))
|
||||
controller_system_cores = int(values.get('system_cores'))
|
||||
|
||||
# creating controller's partitions in the system
|
||||
bash.run_command(
|
||||
'sudo qemu-img create -f qcow2 {0}/{1}-0.img {2}G'.format(
|
||||
libvirt_images_path, controller, controller_partition_a),
|
||||
raise_exception=True)
|
||||
bash.run_command(
|
||||
'sudo qemu-img create -f qcow2 {0}/{1}-1.img {2}G'.format(
|
||||
libvirt_images_path, controller, controller_partition_b),
|
||||
raise_exception=True)
|
||||
bash.run_command(
|
||||
'sudo qemu-img create -f qcow2 {0}/{1}-2.img {2}G'.format(
|
||||
libvirt_images_path, controller, controller_partition_d),
|
||||
raise_exception=True)
|
||||
|
||||
# Only controller-0 needs to have the ISO file in order to boot the
|
||||
# subsequent controllers
|
||||
# heck_controller = False if configuration == 'controller-0' else True
|
||||
|
||||
if controller == 'controller-0':
|
||||
bash.run_command(
|
||||
'sed -e "s,NAME,{0}," '
|
||||
'-e "s,ISO,{1}," '
|
||||
'-e "s,UNIT,MiB," '
|
||||
'-e "s,MEMORY,{2}," '
|
||||
'-e "s,CORES,{3}," '
|
||||
'-e "s,DISK0,{4}/{0}-0.img," '
|
||||
'-e "s,DISK1,{4}/{0}-1.img," '
|
||||
'-e "s,DISK2,{4}/{0}-2.img," '
|
||||
'-e "s,destroy,restart," {5}/master_controller.xml > '
|
||||
'{5}/vms/{0}.xml'.format(
|
||||
controller, iso_file, controller_memory,
|
||||
controller_system_cores, libvirt_images_path, THIS_PATH),
|
||||
raise_exception=True)
|
||||
else:
|
||||
# this mean that is the controller-N
|
||||
# modifying xml parameters for the current controller
|
||||
bash.run_command(
|
||||
'sed -e "s,NAME,{0}," '
|
||||
'-e "s,UNIT,MiB," '
|
||||
'-e "s,MEMORY,{1}," '
|
||||
'-e "s,CORES,{2}," '
|
||||
'-e "s,DISK0,{3}/{0}-0.img," '
|
||||
'-e "s,DISK1,{3}/{0}-1.img," '
|
||||
'-e "s,DISK2,{3}/{0}-2.img," '
|
||||
'-e "s,destroy,restart," {4}/slave_controller.xml > '
|
||||
'{4}/vms/{0}.xml'.format(
|
||||
controller, controller_memory,
|
||||
controller_system_cores, libvirt_images_path, THIS_PATH),
|
||||
raise_exception=True)
|
||||
|
||||
# the following command define a domain and it does not start it and
|
||||
# makes it persistent even after shutdown
|
||||
bash.run_command('sudo virsh define {0}/vms/{1}.xml'.format(
|
||||
THIS_PATH, controller))
|
||||
|
||||
# starting only the controller-0 which is the one with ISO in the xml
|
||||
if controller == 'controller-0':
|
||||
# the following command start a domain
|
||||
bash.run_command('sudo virsh start {}'.format(
|
||||
controller), raise_exception=True)
|
||||
|
||||
if 'Computes' in configurations:
|
||||
for compute, values in configurations.get('Computes').items():
|
||||
# iterating over the computes
|
||||
compute_partition_a = int(values.get('partition_a'))
|
||||
compute_partition_b = int(values.get('partition_b'))
|
||||
compute_memory = int(values.get('memory_size'))
|
||||
compute_system_cores = int(values.get('system_cores'))
|
||||
|
||||
# copy the compute.xml to vms folder
|
||||
origin = os.path.join(THIS_PATH, 'compute.xml')
|
||||
destination = os.path.join(THIS_PATH,
|
||||
'vms', '{}.xml'.format(compute))
|
||||
|
||||
copy(origin, destination)
|
||||
|
||||
# creating both compute's partitions in the system
|
||||
bash.run_command(
|
||||
'sudo qemu-img create -f qcow2 {0}/{1}-0.img {2}G'.format(
|
||||
libvirt_images_path, compute, compute_partition_a),
|
||||
raise_exception=True)
|
||||
bash.run_command(
|
||||
'sudo qemu-img create -f qcow2 {0}/{1}-1.img {2}G'.format(
|
||||
libvirt_images_path, compute, compute_partition_b),
|
||||
raise_exception=True)
|
||||
|
||||
# modifying xml compute parameters
|
||||
bash.run_command(
|
||||
'sed -i -e "s,NAME,{0}," '
|
||||
'-e "s,UNIT,MiB," '
|
||||
'-e "s,MEMORY,{1}," '
|
||||
'-e "s,CORES,{2}," '
|
||||
'-e "s,destroy,restart," '
|
||||
'-e "s,DISK0,{3}/{0}-0.img," '
|
||||
'-e "s,DISK1,{3}/{0}-1.img," '
|
||||
'{4}/vms/{0}.xml'.format(compute, compute_memory,
|
||||
compute_system_cores, libvirt_images_path, THIS_PATH),
|
||||
raise_exception=True)
|
||||
|
||||
# creating the computes according to the XML, the following command
|
||||
# create a domain but it does not start it and makes it persistent
|
||||
# even after shutdown
|
||||
bash.run_command('sudo virsh define {0}/vms/{1}.xml'.format(
|
||||
THIS_PATH, compute))
|
||||
|
||||
if 'Storages' in configurations:
|
||||
for storage, values in configurations.get('Storages').items():
|
||||
# iterating over the storage
|
||||
storage_partition_a = int(values.get('partition_a'))
|
||||
storage_partition_b = int(values.get('partition_b'))
|
||||
storage_memory = int(values.get('memory_size'))
|
||||
storage_system_cores = int(values.get('system_cores'))
|
||||
|
||||
# copy the storage.xml to vms folder
|
||||
origin = os.path.join(THIS_PATH, 'storage.xml')
|
||||
destination = os.path.join(THIS_PATH,
|
||||
'vms', '{}.xml'.format(storage))
|
||||
|
||||
copy(origin, destination)
|
||||
|
||||
# creating both storage's partitions in the system
|
||||
bash.run_command(
|
||||
'sudo qemu-img create -f qcow2 {0}/{1}-0.img {2}G'.format(
|
||||
libvirt_images_path, storage, storage_partition_a),
|
||||
raise_exception=True)
|
||||
bash.run_command(
|
||||
'sudo qemu-img create -f qcow2 {0}/{1}-1.img {2}G'.format(
|
||||
libvirt_images_path, storage, storage_partition_b),
|
||||
raise_exception=True)
|
||||
|
||||
# modifying xml storage parameters
|
||||
bash.run_command(
|
||||
'sed -i -e "s,NAME,{0}," '
|
||||
'-e "s,UNIT,MiB," '
|
||||
'-e "s,MEMORY,{1}," '
|
||||
'-e "s,CORES,{2}," '
|
||||
'-e "s,destroy,restart," '
|
||||
'-e "s,DISK0,{3}/{0}-0.img," '
|
||||
'-e "s,DISK1,{3}/{0}-1.img," '
|
||||
'{4}/vms/{0}.xml'.format(storage, storage_memory,
|
||||
storage_system_cores, libvirt_images_path, THIS_PATH),
|
||||
raise_exception=True)
|
||||
|
||||
# creating the storage according to the XML, the following command
|
||||
# create a domain but it does not start it and makes it persistent
|
||||
# even after shutdown
|
||||
bash.run_command('sudo virsh define {0}/vms/{1}.xml'.format(
|
||||
THIS_PATH, storage))
|
||||
|
||||
# opening the graphical interface
|
||||
if bash.is_process_running('virt-manager'):
|
||||
# in order that virt-manager takes the new configurations from the yaml
|
||||
# file, is needed to kill it and start again.
|
||||
LOG.info('Virtual Machine Manager is active, killing it ...')
|
||||
bash.run_command('sudo kill -9 $(pgrep -x virt-manager)',
|
||||
raise_exception=True)
|
||||
|
||||
# opening Virtual Machine Manager
|
||||
bash.run_command('sudo virt-manager', raise_exception=True)
|
||||
# opening the controller console
|
||||
bash.run_command('virt-manager -c qemu:///system --show-domain-console '
|
||||
'controller-0', raise_exception=True)
|
||||
exit_dict_status(0)
|
||||
|
||||
|
||||
def setup_qemu(iso_file, configuration_file):
|
||||
"""Setup StarlingX
|
||||
|
||||
The aim of this function is to setup StarlingX in a smart way in order
|
||||
to avoid configuration issues.
|
||||
|
||||
:param iso_file: the iso file to be configured in the controller(s).
|
||||
:param configuration_file: the yaml configuration file.
|
||||
"""
|
||||
# before to run anything, KVM needs to be checked it this is present in the
|
||||
# current host
|
||||
check_kernel_virtualization()
|
||||
|
||||
# check the host requirements
|
||||
check_preconditions()
|
||||
|
||||
# loading all the configurations from yaml file
|
||||
configurations = yaml.safe_load(open(configuration_file))
|
||||
|
||||
# fixme(Humberto): check_system_resources is commented out due
|
||||
# check is giving problems when configuring an instance on qemu virtual
|
||||
# machine, for now this will be commented until more investigation is done
|
||||
|
||||
# this part will check the values given in the yaml
|
||||
# check_system_resources(configurations)
|
||||
|
||||
# setting the controller/computes nodes
|
||||
setup_controller_computes(iso_file, configurations)
|
||||
|
||||
|
||||
def arguments():
|
||||
"""Provides a set of arguments
|
||||
|
||||
Defined arguments must be specified in this function in order to interact
|
||||
with the others functions in this module.
|
||||
"""
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=RawDescriptionHelpFormatter, description='''
|
||||
Program description:
|
||||
This is a tool for setup virtual environments with libvirt/Qemu in the host.
|
||||
maintainer : humberto.i.perez.rodriguez@intel.com''',
|
||||
epilog='StarlingX |https://opendev.org/starlingx/test/',
|
||||
usage='%(prog)s [options]')
|
||||
group_mandatory = parser.add_argument_group('mandatory arguments')
|
||||
group_mandatory.add_argument(
|
||||
'-i', '--iso', dest='iso', required=True,
|
||||
help='the iso file to be setup in the controller')
|
||||
parser.add_argument(
|
||||
'-c', '--configuration', dest='configuration',
|
||||
help='the Qemu configuration file in yaml format. The default '
|
||||
'configuration file is qemu_setup.yaml in this folder')
|
||||
args = parser.parse_args()
|
||||
|
||||
# checks if the iso file given exists
|
||||
if not os.path.isfile(args.iso):
|
||||
print('{0}: does not exists, please verify it'.format(args.iso))
|
||||
exit_dict_status(1)
|
||||
|
||||
# checks if the configuration exists
|
||||
configuration_file = os.path.join(THIS_PATH, 'qemu_setup.yaml')
|
||||
if args.configuration:
|
||||
configuration_file = args.configuration
|
||||
|
||||
if not os.path.exists(configuration_file):
|
||||
print('{0}: does not exists, please verify it'.format(
|
||||
configuration_file))
|
||||
exit_dict_status(1)
|
||||
|
||||
setup_qemu(args.iso, configuration_file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
arguments()
|
|
@ -0,0 +1,32 @@
|
|||
configuration_0:
|
||||
controller-0:
|
||||
controller_0_partition_a: 200
|
||||
controller_0_partition_b: 200
|
||||
controller_0_memory_size: 10240
|
||||
controller_0_system_cores: 4
|
||||
controller-0-compute-0:
|
||||
controller_0_compute_0_partition_a: 200
|
||||
controller_0_compute_0_partition_b: 200
|
||||
controller_0_compute_0_memory_size: 16384
|
||||
controller_0_compute_0_system_cores: 4
|
||||
controller-0-compute-1:
|
||||
controller_0_compute_1_partition_a: 200
|
||||
controller_0_compute_1_partition_b: 200
|
||||
controller_0_compute_1_memory_size: 16384
|
||||
controller_0_compute_1_system_cores: 4
|
||||
configuration_1:
|
||||
controller-1:
|
||||
controller_1_partition_a: 200
|
||||
controller_1_partition_b: 200
|
||||
controller_1_memory_size: 10240
|
||||
controller_1_system_cores: 4
|
||||
controller-1-compute-0:
|
||||
controller_1_compute_0_partition_a: 200
|
||||
controller_1_compute_0_partition_b: 200
|
||||
controller_1_compute_0_memory_size: 3072
|
||||
controller_1_compute_0_system_cores: 2
|
||||
general_system_configurations:
|
||||
os_system_memory: 1024
|
||||
disk_space_allocated_to_os: 20
|
||||
os_system_cores: 2
|
||||
default_mount_point: '/'
|
|
@ -0,0 +1,99 @@
|
|||
<domain type='kvm' id='164'>
|
||||
<name>NAME</name>
|
||||
<memory unit='UNIT'>MEMORY</memory>
|
||||
<currentMemory unit='UNIT'>MEMORY</currentMemory>
|
||||
<vcpu placement='static'>CORES</vcpu>
|
||||
<resource>
|
||||
<partition>/machine</partition>
|
||||
</resource>
|
||||
<os>
|
||||
<type arch='x86_64' machine='pc'>hvm</type>
|
||||
</os>
|
||||
<features>
|
||||
<acpi/>
|
||||
<apic/>
|
||||
<pae/>
|
||||
</features>
|
||||
<cpu match='exact'>
|
||||
<model fallback='forbid'>Nehalem</model>
|
||||
<topology sockets='1' cores='CORES' threads='1'/>
|
||||
<feature policy='optional' name='vmx'/>
|
||||
<feature policy='optional' name='svm'/>
|
||||
</cpu>
|
||||
<clock offset='utc'/>
|
||||
<on_poweroff>destroy</on_poweroff>
|
||||
<on_reboot>restart</on_reboot>
|
||||
<on_crash>destroy</on_crash>
|
||||
<devices>
|
||||
<emulator>/usr/bin/qemu-system-x86_64</emulator>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='qcow2'/>
|
||||
<source file='DISK0'/>
|
||||
<backingStore/>
|
||||
<target dev='sda' bus='sata'/>
|
||||
<boot order='1'/>
|
||||
</disk>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='qcow2'/>
|
||||
<source file='DISK1'/>
|
||||
<backingStore/>
|
||||
<target dev='sdb' bus='sata'/>
|
||||
</disk>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='qemu' type='qcow2'/>
|
||||
<source file='DISK2'/>
|
||||
<backingStore/>
|
||||
<target dev='sdd' bus='sata'/>
|
||||
</disk>
|
||||
<interface type='bridge'>
|
||||
<source bridge='stxbr1'/>
|
||||
<target dev='vnet0'/>
|
||||
<model type='e1000'/>
|
||||
<alias name='net0'/>
|
||||
</interface>
|
||||
<interface type='bridge'>
|
||||
<source bridge='stxbr2'/>
|
||||
<target dev='vnet1'/>
|
||||
<model type='e1000'/>
|
||||
<boot order='2'/>
|
||||
<alias name='net1'/>
|
||||
</interface>
|
||||
<interface type='bridge'>
|
||||
<source bridge='stxbr3'/>
|
||||
<target dev='vnet2'/>
|
||||
<model type='virtio'/>
|
||||
<alias name='net2'/>
|
||||
</interface>
|
||||
<interface type='bridge'>
|
||||
<source bridge='stxbr4'/>
|
||||
<target dev='vnet3'/>
|
||||
<model type='virtio'/>
|
||||
<alias name='net3'/>
|
||||
</interface>
|
||||
<serial type='pty'>
|
||||
<source path='/dev/pts/8'/>
|
||||
<target port='0'/>
|
||||
<alias name='serial0'/>
|
||||
</serial>
|
||||
<console type='pty' tty='/dev/pts/8'>
|
||||
<source path='/dev/pts/8'/>
|
||||
<target type='serial' port='0'/>
|
||||
<alias name='serial0'/>
|
||||
</console>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<input type='keyboard' bus='ps2'/>
|
||||
<graphics type='vnc' port='5900' autoport='yes' listen='127.0.0.1' keymap='en-us'>
|
||||
<listen type='address' address='127.0.0.1'/>
|
||||
</graphics>
|
||||
<video>
|
||||
<model type='cirrus' vram='16384' heads='1'/>
|
||||
<alias name='video0'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
|
||||
</video>
|
||||
<memballoon model='virtio'>
|
||||
<alias name='balloon0'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
|
||||
</memballoon>
|
||||
</devices>
|
||||
</domain>
|
||||
|
|