summaryrefslogtreecommitdiffstats
path: root/fuel/deploy
diff options
context:
space:
mode:
authorSzilard Cserey <szilard.cserey@ericsson.com>2015-04-14 15:47:45 +0200
committerSzilard Cserey <szilard.cserey@ericsson.com>2015-04-28 10:01:04 +0200
commit9c2b6848566a0b80bb44f27cca155a240d69f061 (patch)
tree5081686f09c3c4662f6b807a196a28cb4acab67a /fuel/deploy
parente2b2d46756213fde3bca42a49b04e6a1e8792498 (diff)
Automatic Deployment
- node discovery - refactoring to support multiple shelves - configure nodes and interfaces - provisioning - deployment - extending with autodeployment scripts from libvirt prototype JIRA: [BGS-2] Create Fuel deployment scrip Signed-off-by: Szilard Cserey <szilard.cserey@ericsson.com> Change-Id: Ic48f93594914d5bef6c9de34d87434c7cd567198
Diffstat (limited to 'fuel/deploy')
-rw-r--r--fuel/deploy/README.rst47
-rw-r--r--fuel/deploy/cloud_deploy/__init__.py1
-rw-r--r--fuel/deploy/cloud_deploy/cloud/__init__.py1
-rw-r--r--fuel/deploy/cloud_deploy/cloud/common.py51
-rw-r--r--fuel/deploy/cloud_deploy/cloud/configure_environment.py74
-rw-r--r--fuel/deploy/cloud_deploy/cloud/configure_network.py62
-rw-r--r--fuel/deploy/cloud_deploy/cloud/configure_nodes.py108
-rw-r--r--fuel/deploy/cloud_deploy/cloud/configure_settings.py47
-rw-r--r--fuel/deploy/cloud_deploy/cloud/dea.py (renamed from fuel/deploy/dea.py)56
-rw-r--r--fuel/deploy/cloud_deploy/cloud/deploy.py208
-rw-r--r--fuel/deploy/cloud_deploy/cloud/deployment.py100
-rw-r--r--fuel/deploy/cloud_deploy/cloud_deploy.py117
-rw-r--r--fuel/deploy/cloud_deploy/hardware_adapters/__init__.py1
-rw-r--r--fuel/deploy/cloud_deploy/hardware_adapters/dha.py (renamed from fuel/deploy/dha.py)5
-rw-r--r--fuel/deploy/cloud_deploy/hardware_adapters/hp/__init__.py1
-rw-r--r--fuel/deploy/cloud_deploy/hardware_adapters/hp/hp_adapter.py (renamed from fuel/deploy/hardware_adapters/hp/hp_adapter.py)54
-rw-r--r--fuel/deploy/cloud_deploy/hardware_adapters/hp/run_oa_command.py (renamed from fuel/deploy/hardware_adapters/hp/run_oa_command.py)9
-rw-r--r--fuel/deploy/cloud_deploy/hardware_adapters/libvirt/__init__.py1
-rw-r--r--fuel/deploy/cloud_deploy/hardware_adapters/libvirt/libvirt_adapter.py153
-rw-r--r--fuel/deploy/cloud_deploy/ssh_client.py56
-rw-r--r--fuel/deploy/common.py29
-rw-r--r--fuel/deploy/configure_environment.py70
-rw-r--r--fuel/deploy/configure_network.py91
-rw-r--r--fuel/deploy/configure_settings.py88
-rw-r--r--fuel/deploy/dea.yaml958
-rw-r--r--fuel/deploy/deploy.py212
-rwxr-xr-xfuel/deploy/deploy.sh107
-rwxr-xr-xfuel/deploy/deploy_fuel.sh106
-rwxr-xr-xfuel/deploy/functions/common.sh109
-rwxr-xr-xfuel/deploy/functions/install_iso.sh62
-rw-r--r--fuel/deploy/functions/isolinux.cfg.patch14
-rw-r--r--fuel/deploy/functions/ks.cfg.patch19
-rwxr-xr-xfuel/deploy/functions/patch-iso.sh69
-rw-r--r--fuel/deploy/libvirt/networks/fuel112
-rw-r--r--fuel/deploy/libvirt/networks/fuel25
-rw-r--r--fuel/deploy/libvirt/networks/fuel35
-rw-r--r--fuel/deploy/libvirt/networks/fuel412
-rw-r--r--fuel/deploy/libvirt/vms/fuel-master95
-rw-r--r--fuel/deploy/libvirt/vms/s1_b1100
-rw-r--r--fuel/deploy/libvirt/vms/s1_b2100
-rw-r--r--fuel/deploy/libvirt/vms/s1_b3100
-rw-r--r--fuel/deploy/libvirt/vms/s1_b4101
-rw-r--r--fuel/deploy/libvirt/vms/s1_b5100
-rw-r--r--fuel/deploy/libvirt/vms/s1_b6100
-rwxr-xr-xfuel/deploy/setup_vms/apply_setup.sh61
-rwxr-xr-xfuel/deploy/setup_vms/setup-vm-host.sh17
46 files changed, 3228 insertions, 666 deletions
diff --git a/fuel/deploy/README.rst b/fuel/deploy/README.rst
new file mode 100644
index 0000000..f7b5711
--- /dev/null
+++ b/fuel/deploy/README.rst
@@ -0,0 +1,47 @@
+**DEA libvirt deployment prototype**
+
+This is an example of how to deploy a libvirt KVM setup with a DEA
+YAML file.
+
+The file is created from an already deployed Fuel installation using
+the create_dea script and helper files which are to be present on the
+Fuel master and run from there.
+
+The install is kicked off from the host by running deploy.sh and
+providing the ISO file to deploy and (optionally) an DEA file name as
+an argument. If the DEA file is omitted the example one will be used
+instead.
+
+Pre-condition 1: The host needs to be Ubuntu 14.x
+
+Pre-condition 2: Necessary packages installed by running
+sudo genesis/fuel/prototypes/libvirt/setup_vms/setup-vm-host.sh
+
+Pre-condition 3: Example VM configuration deployed by running
+genesis/fuel/prototypes/libvirt/setup_vms/apply_setup.sh The VMs and
+networks to be setup are in genesis/fuel/prototypes/libvirt/examples:
+"vms" and "networks"
+sudo mkdir /mnt/images
+cd setup-vms
+sudo ./apply_setup.sh /mnt/images 50
+
+In order to run the automated install, it's just a matter of running
+genesis/fuel/prototypes/libvirt/deploy.sh <isofile> [<deafile>] The
+deafile will be optional, if not specified the example one in
+genesis/fuel/prototypes/libvirt/examples/libvirt_dea.yaml will be
+used.
+sudo ./deploy.sh ~/ISO/opnfv-P0000.iso ~/DEPLOY/deploy/dea.yaml
+
+Now either this will succeed (return code 0) or fail. I'll have a
+three hours safety catch to kill off things if something is hanging,
+may need to be adjusted for slow environments (see deploy.sh).
+
+All the steps above should be run with sudo.
+
+In principle the deploy.sh is assuming the example vm setup (one fuel,
+three controllers, two computes) and will always deploy with full HA
+and Ceilometer.
+
+TODO: Copy also the deployment mode in my dea.yaml creation script
+genesis/fuel/prototypes/libvirt/create_dea/create_dea.sh so it's a
+real xerox of the running deploy.
diff --git a/fuel/deploy/cloud_deploy/__init__.py b/fuel/deploy/cloud_deploy/__init__.py
new file mode 100644
index 0000000..c274feb
--- /dev/null
+++ b/fuel/deploy/cloud_deploy/__init__.py
@@ -0,0 +1 @@
+__author__ = 'eszicse'
diff --git a/fuel/deploy/cloud_deploy/cloud/__init__.py b/fuel/deploy/cloud_deploy/cloud/__init__.py
new file mode 100644
index 0000000..c274feb
--- /dev/null
+++ b/fuel/deploy/cloud_deploy/cloud/__init__.py
@@ -0,0 +1 @@
+__author__ = 'eszicse'
diff --git a/fuel/deploy/cloud_deploy/cloud/common.py b/fuel/deploy/cloud_deploy/cloud/common.py
new file mode 100644
index 0000000..365f6fb
--- /dev/null
+++ b/fuel/deploy/cloud_deploy/cloud/common.py
@@ -0,0 +1,51 @@
+import subprocess
+import sys
+import os
+import logging
+
+N = {'id': 0, 'status': 1, 'name': 2, 'cluster': 3, 'ip': 4, 'mac': 5,
+ 'roles': 6, 'pending_roles': 7, 'online': 8}
+E = {'id': 0, 'status': 1, 'name': 2, 'mode': 3, 'release_id': 4,
+ 'changes': 5, 'pending_release_id': 6}
+R = {'id': 0, 'name': 1, 'state': 2, 'operating_system': 3, 'version': 4}
+RO = {'name': 0, 'conflicts': 1}
+
+LOG = logging.getLogger(__name__)
+LOG.setLevel(logging.DEBUG)
+formatter = logging.Formatter('%(message)s')
+out_handler = logging.StreamHandler(sys.stdout)
+out_handler.setFormatter(formatter)
+LOG.addHandler(out_handler)
+out_handler = logging.FileHandler('autodeploy.log', mode='w')
+out_handler.setFormatter(formatter)
+LOG.addHandler(out_handler)
+
+def exec_cmd(cmd):
+ process = subprocess.Popen(cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ shell=True)
+ return process.communicate()[0], process.returncode
+
+def run_proc(cmd):
+ process = subprocess.Popen(cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ shell=True)
+ return process
+
+def parse(printout, *args):
+ parsed_list = []
+ lines = printout[0].splitlines()
+ for l in lines[2:]:
+ parsed = [e.strip() for e in l.split('|')]
+ parsed_list.append(parsed)
+ return parsed_list
+
+def err(error_message):
+ LOG.error(error_message)
+ sys.exit(1)
+
+def check_file_exists(file_path):
+ if not os.path.isfile(file_path):
+ err('ERROR: File %s not found\n' % file_path)
diff --git a/fuel/deploy/cloud_deploy/cloud/configure_environment.py b/fuel/deploy/cloud_deploy/cloud/configure_environment.py
new file mode 100644
index 0000000..426bbd1
--- /dev/null
+++ b/fuel/deploy/cloud_deploy/cloud/configure_environment.py
@@ -0,0 +1,74 @@
+import common
+import os
+import shutil
+
+from configure_settings import ConfigureSettings
+from configure_network import ConfigureNetwork
+from configure_nodes import ConfigureNodes
+
+N = common.N
+E = common.E
+R = common.R
+RO = common.RO
+exec_cmd = common.exec_cmd
+parse = common.parse
+err = common.err
+LOG = common.LOG
+
+class ConfigureEnvironment(object):
+
+ def __init__(self, dea, yaml_config_dir, release_id, node_id_roles_dict):
+ self.env_id = None
+ self.dea = dea
+ self.yaml_config_dir = yaml_config_dir
+ self.env_name = dea.get_environment_name()
+ self.release_id = release_id
+ self.node_id_roles_dict = node_id_roles_dict
+ self.required_networks = []
+
+ def env_exists(self, env_name):
+ env_list = parse(exec_cmd('fuel env --list'))
+ for env in env_list:
+ if env[E['name']] == env_name and env[E['status']] == 'new':
+ self.env_id = env[E['id']]
+ return True
+ return False
+
+ def configure_environment(self):
+ LOG.debug('Configure environment\n')
+ if os.path.exists(self.yaml_config_dir):
+ LOG.debug('Deleting existing config directory %s\n'
+ % self.yaml_config_dir)
+ shutil.rmtree(self.yaml_config_dir)
+ LOG.debug('Creating new config directory %s\n' % self.yaml_config_dir)
+ os.makedirs(self.yaml_config_dir)
+
+ LOG.debug('Creating environment %s release %s, mode ha, network-mode '
+ 'neutron, net-segment-type vlan\n'
+ % (self.env_name, self.release_id))
+ exec_cmd('fuel env create --name %s --release %s --mode ha '
+ '--network-mode neutron --net-segment-type vlan'
+ % (self.env_name, self.release_id))
+
+ if not self.env_exists(self.env_name):
+ err("Failed to create environment %s\n" % self.env_name)
+ self.config_settings()
+ self.config_network()
+ self.config_nodes()
+
+ def config_settings(self):
+ settings = ConfigureSettings(self.yaml_config_dir, self.env_id,
+ self.dea)
+ settings.config_settings()
+
+ def config_network(self):
+ network = ConfigureNetwork(self.yaml_config_dir, self.env_id, self.dea)
+ network.config_network()
+
+ def config_nodes(self):
+ nodes = ConfigureNodes(self.yaml_config_dir, self.env_id,
+ self.node_id_roles_dict, self.dea)
+ nodes.config_nodes()
+
+
+
diff --git a/fuel/deploy/cloud_deploy/cloud/configure_network.py b/fuel/deploy/cloud_deploy/cloud/configure_network.py
new file mode 100644
index 0000000..f4d6f87
--- /dev/null
+++ b/fuel/deploy/cloud_deploy/cloud/configure_network.py
@@ -0,0 +1,62 @@
+import common
+import yaml
+import io
+
+N = common.N
+E = common.E
+R = common.R
+RO = common.RO
+exec_cmd = common.exec_cmd
+parse = common.parse
+err = common.err
+check_file_exists = common.check_file_exists
+LOG = common.LOG
+
+class ConfigureNetwork(object):
+
+ def __init__(self, yaml_config_dir, env_id, dea):
+ self.yaml_config_dir = yaml_config_dir
+ self.env_id = env_id
+ self.dea = dea
+ self.required_networks = []
+
+ def download_network_config(self):
+ LOG.debug('Download network config for environment %s\n' % self.env_id)
+ exec_cmd('fuel network --env %s --download --dir %s'
+ % (self.env_id, self.yaml_config_dir))
+
+ def upload_network_config(self):
+ LOG.debug('Upload network config for environment %s\n' % self.env_id)
+ exec_cmd('fuel network --env %s --upload --dir %s'
+ % (self.env_id, self.yaml_config_dir))
+
+ def config_network(self):
+ LOG.debug('Configure network\n')
+ self.download_network_config()
+ self.modify_network_config()
+ self.upload_network_config()
+
+ def modify_network_config(self):
+ LOG.debug('Modify network config for environment %s\n' % self.env_id)
+ network_yaml = (self.yaml_config_dir + '/network_%s.yaml'
+ % self.env_id)
+ check_file_exists(network_yaml)
+
+ network_config = self.dea.get_networks()
+
+
+ with io.open(network_yaml) as stream:
+ network = yaml.load(stream)
+
+ net_names = self.dea.get_network_names()
+ net_id = {}
+ for net in network['networks']:
+ if net['name'] in net_names:
+ net_id[net['name']] = {'id': net['id'],
+ 'group_id': net['group_id']}
+
+ for network in network_config['networks']:
+ network.update(net_id[network['name']])
+
+ with io.open(network_yaml, 'w') as stream:
+ yaml.dump(network_config, stream, default_flow_style=False) \ No newline at end of file
diff --git a/fuel/deploy/cloud_deploy/cloud/configure_nodes.py b/fuel/deploy/cloud_deploy/cloud/configure_nodes.py
new file mode 100644
index 0000000..a5e24a8
--- /dev/null
+++ b/fuel/deploy/cloud_deploy/cloud/configure_nodes.py
@@ -0,0 +1,108 @@
+import common
+import yaml
+import io
+import glob
+
+N = common.N
+E = common.E
+R = common.R
+RO = common.RO
+exec_cmd = common.exec_cmd
+parse = common.parse
+err = common.err
+check_file_exists = common.check_file_exists
+LOG = common.LOG
+
+
+class ConfigureNodes(object):
+
+ def __init__(self, yaml_config_dir, env_id, node_id_roles_dict, dea):
+ self.yaml_config_dir = yaml_config_dir
+ self.env_id = env_id
+ self.node_id_roles_dict = node_id_roles_dict
+ self.dea = dea
+
+ def config_nodes(self):
+ LOG.debug('Configure nodes\n')
+ for node_id, roles_shelf_blade in self.node_id_roles_dict.iteritems():
+ exec_cmd('fuel node set --node-id %s --role %s --env %s'
+ % (node_id, ','.join(roles_shelf_blade[0]), self.env_id))
+
+ self.download_deployment_config()
+ self.modify_node_network_schemes()
+ self.upload_deployment_config()
+
+ for node_id, roles_shelf_blade in self.node_id_roles_dict.iteritems():
+ self.download_interface_config(node_id)
+ self.modify_node_interface(node_id)
+ self.upload_interface_config(node_id)
+
+ def modify_node_network_schemes(self):
+ LOG.debug('Modify node network schemes in environment %s\n' % self.env_id)
+ for node_file in glob.glob('%s/deployment_%s/*.yaml'
+ % (self.yaml_config_dir, self.env_id)):
+ check_file_exists(node_file)
+
+ if 'compute' in node_file:
+ node_type = 'compute'
+ else:
+ node_type = 'controller'
+
+ network_scheme = self.dea.get_network_scheme(node_type)
+
+ with io.open(node_file) as stream:
+ node = yaml.load(stream)
+
+ node['network_scheme']['transformations'] = network_scheme
+
+ with io.open(node_file, 'w') as stream:
+ yaml.dump(node, stream, default_flow_style=False)
+
+
+ def download_deployment_config(self):
+ LOG.debug('Download deployment config for environment %s\n' % self.env_id)
+ r, c = exec_cmd('fuel deployment --env %s --default --dir %s'
+ % (self.env_id, self.yaml_config_dir))
+
+ def upload_deployment_config(self):
+ LOG.debug('Upload deployment config for environment %s\n' % self.env_id)
+ r, c = exec_cmd('fuel deployment --env %s --upload --dir %s'
+ % (self.env_id, self.yaml_config_dir))
+
+ def download_interface_config(self, node_id):
+ LOG.debug('Download interface config for node %s\n' % node_id)
+ r, c = exec_cmd('fuel node --env %s --node %s --network --download '
+ '--dir %s' % (self.env_id, node_id,
+ self.yaml_config_dir))
+
+ def upload_interface_config(self, node_id):
+ LOG.debug('Upload interface config for node %s\n' % node_id)
+ r, c = exec_cmd('fuel node --env %s --node %s --network --upload '
+ '--dir %s' % (self.env_id, node_id,
+ self.yaml_config_dir))
+
+ def modify_node_interface(self, node_id):
+ LOG.debug('Modify interface config for node %s\n' % node_id)
+ interface_yaml = (self.yaml_config_dir + '/node_%s/interfaces.yaml'
+ % node_id)
+
+ with io.open(interface_yaml) as stream:
+ interfaces = yaml.load(stream)
+
+ net_name_id = {}
+ for interface in interfaces:
+ for network in interface['assigned_networks']:
+ net_name_id[network['name']] = network['id']
+
+ interface_config = self.dea.get_interfaces()
+
+ for interface in interfaces:
+ interface['assigned_networks'] = []
+ for net_name in interface_config[interface['name']]:
+ net = {}
+ net['id'] = net_name_id[net_name]
+ net['name'] = net_name
+ interface['assigned_networks'].append(net)
+
+ with io.open(interface_yaml, 'w') as stream:
+ yaml.dump(interfaces, stream, default_flow_style=False) \ No newline at end of file
diff --git a/fuel/deploy/cloud_deploy/cloud/configure_settings.py b/fuel/deploy/cloud_deploy/cloud/configure_settings.py
new file mode 100644
index 0000000..3a3e4d5
--- /dev/null
+++ b/fuel/deploy/cloud_deploy/cloud/configure_settings.py
@@ -0,0 +1,47 @@
+import common
+import yaml
+import io
+
+N = common.N
+E = common.E
+R = common.R
+RO = common.RO
+exec_cmd = common.exec_cmd
+parse = common.parse
+err = common.err
+check_file_exists = common.check_file_exists
+LOG = common.LOG
+
+class ConfigureSettings(object):
+
+ def __init__(self, yaml_config_dir, env_id, dea):
+ self.yaml_config_dir = yaml_config_dir
+ self.env_id = env_id
+ self.dea = dea
+
+ def download_settings(self):
+ LOG.debug('Download settings for environment %s\n' % self.env_id)
+ r, c = exec_cmd('fuel settings --env %s --download --dir %s'
+ % (self.env_id, self.yaml_config_dir))
+
+ def upload_settings(self):
+ LOG.debug('Upload settings for environment %s\n' % self.env_id)
+ r, c = exec_cmd('fuel settings --env %s --upload --dir %s'
+ % (self.env_id, self.yaml_config_dir))
+
+ def config_settings(self):
+ LOG.debug('Configure settings\n')
+ self.download_settings()
+ self.modify_settings()
+ self.upload_settings()
+
+ def modify_settings(self):
+ LOG.debug('Modify settings for environment %s\n' % self.env_id)
+ settings_yaml = (self.yaml_config_dir + '/settings_%s.yaml'
+ % self.env_id)
+ check_file_exists(settings_yaml)
+
+ settings = self.dea.get_settings()
+
+ with io.open(settings_yaml, 'w') as stream:
+ yaml.dump(settings, stream, default_flow_style=False)
diff --git a/fuel/deploy/dea.py b/fuel/deploy/cloud_deploy/cloud/dea.py
index 5f306a2..295636a 100644
--- a/fuel/deploy/dea.py
+++ b/fuel/deploy/cloud_deploy/cloud/dea.py
@@ -7,13 +7,15 @@ class DeploymentEnvironmentAdapter(object):
self.blade_ids_per_shelves = {}
self.blades_per_shelves = {}
self.shelf_ids = []
- self.networks = {}
+ self.info_per_shelves = {}
+ self.network_names = []
def parse_yaml(self, yaml_path):
with io.open(yaml_path) as yaml_file:
self.dea_struct = yaml.load(yaml_file)
self.collect_shelf_and_blade_info()
- self.collect_network_info()
+ self.collect_shelf_info()
+ self.collect_network_names()
def get_no_of_blades(self):
no_of_blades = 0
@@ -21,14 +23,16 @@ class DeploymentEnvironmentAdapter(object):
no_of_blades += len(shelf['blade'])
return no_of_blades
- def get_server_type(self):
- return self.dea_struct['server']['type']
+ def collect_shelf_info(self):
+ self.info_per_shelves = {}
+ for shelf in self.dea_struct['shelf']:
+ self.info_per_shelves[shelf['id']] = shelf
- def get_server_info(self):
- return (self.dea_struct['server']['type'],
- self.dea_struct['server']['mgmt_ip'],
- self.dea_struct['server']['username'],
- self.dea_struct['server']['password'])
+ def get_shelf_info(self, shelf):
+ return (self.info_per_shelves[shelf]['type'],
+ self.info_per_shelves[shelf]['mgmt_ip'],
+ self.info_per_shelves[shelf]['username'],
+ self.info_per_shelves[shelf]['password'])
def get_environment_name(self):
return self.dea_struct['name']
@@ -54,19 +58,29 @@ class DeploymentEnvironmentAdapter(object):
blade_ids.append(blade['id'])
blades[blade['id']] = blade
- def is_controller(self, shelf_id, blade_id):
- blade = self.blades[shelf_id][blade_id]
- return (True if 'role' in blade and blade['role'] == 'controller'
+ def has_role(self, role, shelf, blade):
+ blade = self.blades_per_shelves[shelf][blade]
+ if role == 'compute':
+ return True if 'roles' not in blade else False
+ return (True if 'roles' in blade and role in blade['roles']
else False)
- def is_compute_host(self, shelf_id, blade_id):
- blade = self.blades[shelf_id][blade_id]
- return True if 'role' not in blade else False
-
- def collect_network_info(self):
- self.networks = {}
- for network in self.dea_struct['network']:
- self.networks[network['name']] = network
+ def collect_network_names(self):
+ self.network_names = []
+ for network in self.dea_struct['networks']['networks']:
+ self.network_names.append(network['name'])
def get_networks(self):
- return self.networks \ No newline at end of file
+ return self.dea_struct['networks']
+
+ def get_network_names(self):
+ return self.network_names
+
+ def get_settings(self):
+ return self.dea_struct['settings']
+
+ def get_network_scheme(self, node_type):
+ return self.dea_struct[node_type]
+
+ def get_interfaces(self):
+ return self.dea_struct['interfaces'] \ No newline at end of file
diff --git a/fuel/deploy/cloud_deploy/cloud/deploy.py b/fuel/deploy/cloud_deploy/cloud/deploy.py
new file mode 100644
index 0000000..ea33f8b
--- /dev/null
+++ b/fuel/deploy/cloud_deploy/cloud/deploy.py
@@ -0,0 +1,208 @@
+import time
+import yaml
+import io
+import os
+
+import common
+from dea import DeploymentEnvironmentAdapter
+from configure_environment import ConfigureEnvironment
+from deployment import Deployment
+
+SUPPORTED_RELEASE = 'Juno on CentOS 6.5'
+
+N = common.N
+E = common.E
+R = common.R
+RO = common.RO
+exec_cmd = common.exec_cmd
+parse = common.parse
+err = common.err
+check_file_exists = common.check_file_exists
+LOG = common.LOG
+
+class Deploy(object):
+
+ def __init__(self, yaml_config_dir):
+ self.supported_release = None
+ self.yaml_config_dir = yaml_config_dir
+ self.macs_per_shelf_dict = {}
+ self.node_ids_dict = {}
+ self.node_id_roles_dict = {}
+ self.env_id = None
+ self.shelf_blades_dict = {}
+
+ def cleanup_fuel_environments(self, env_list):
+ WAIT_LOOP = 60
+ SLEEP_TIME = 10
+ for env in env_list:
+ LOG.debug('Deleting environment %s\n' % env[E['id']])
+ exec_cmd('fuel env --env %s --delete' % env[E['id']])
+ all_env_erased = False
+ for i in range(WAIT_LOOP):
+ env_list = parse(exec_cmd('fuel env list'))
+ if env_list[0][0]:
+ time.sleep(SLEEP_TIME)
+ else:
+ all_env_erased = True
+ break
+ if not all_env_erased:
+ err('Could not erase these environments %s'
+ % [(env[E['id']], env[E['status']]) for env in env_list])
+
+ def cleanup_fuel_nodes(self, node_list):
+ for node in node_list:
+ if node[N['status']] == 'discover':
+ LOG.debug('Deleting node %s\n' % node[N['id']])
+ exec_cmd('fuel node --node-id %s --delete-from-db'
+ % node[N['id']])
+ exec_cmd('cobbler system remove --name node-%s'
+ % node[N['id']])
+
+ def check_previous_installation(self):
+ LOG.debug('Check previous installation\n')
+ env_list = parse(exec_cmd('fuel env list'))
+ if env_list[0][0]:
+ self.cleanup_fuel_environments(env_list)
+ node_list = parse(exec_cmd('fuel node list'))
+ if node_list[0][0]:
+ self.cleanup_fuel_nodes(node_list)
+
+ def check_supported_release(self):
+ LOG.debug('Check supported release: %s\n' % SUPPORTED_RELEASE)
+ release_list = parse(exec_cmd('fuel release -l'))
+ for release in release_list:
+ if release[R['name']] == SUPPORTED_RELEASE:
+ self.supported_release = release
+ break
+ if not self.supported_release:
+ err('This Fuel does not contain the following '
+ 'release: %s\n' % SUPPORTED_RELEASE)
+
+ def check_prerequisites(self):
+ LOG.debug('Check prerequisites\n')
+ self.check_supported_release()
+ self.check_previous_installation()
+
+ def find_mac_in_dict(self, mac):
+ for shelf, blade_dict in self.macs_per_shelf_dict.iteritems():
+ for blade, mac_list in blade_dict.iteritems():
+ if mac in mac_list:
+ return shelf, blade
+
+ def all_blades_discovered(self):
+ for shelf, blade_dict in self.node_ids_dict.iteritems():
+ for blade, node_id in blade_dict.iteritems():
+ if not node_id:
+ return False
+ return True
+
+ def not_discovered_blades_summary(self):
+ summary = ''
+ for shelf, blade_dict in self.node_ids_dict.iteritems():
+ for blade, node_id in blade_dict.iteritems():
+ if not node_id:
+ summary += '[shelf %s, blade %s]\n' % (shelf, blade)
+ return summary
+
+ def collect_blade_ids_per_shelves(self, dea):
+ self.shelf_blades_dict = dea.get_blade_ids_per_shelves()
+
+ def node_discovery(self, node_list, discovered_macs):
+ for node in node_list:
+ if (node[N['status']] == 'discover' and
+ node[N['online']] == 'True' and
+ node[N['mac']] not in discovered_macs):
+ discovered_macs.append(node[N['mac']])
+ shelf_blade = self.find_mac_in_dict(node[N['mac']])
+ if shelf_blade:
+ self.node_ids_dict[shelf_blade[0]][shelf_blade[1]] = \
+ node[N['id']]
+
+ def discovery_waiting_loop(self, discovered_macs):
+ WAIT_LOOP = 180
+ SLEEP_TIME = 10
+ all_discovered = False
+ for i in range(WAIT_LOOP):
+ node_list = parse(exec_cmd('fuel node list'))
+ if node_list[0][0]:
+ self.node_discovery(node_list, discovered_macs)
+ if self.all_blades_discovered():
+ all_discovered = True
+ break
+ else:
+ time.sleep(SLEEP_TIME)
+ return all_discovered
+
+ def wait_for_discovered_blades(self):
+ LOG.debug('Wait for discovered blades\n')
+ discovered_macs = []
+ for shelf, blade_list in self.shelf_blades_dict.iteritems():
+ self.node_ids_dict[shelf] = {}
+ for blade in blade_list:
+ self.node_ids_dict[shelf][blade] = None
+ all_discovered = self.discovery_waiting_loop(discovered_macs)
+ if not all_discovered:
+ err('Not all blades have been discovered: %s\n'
+ % self.not_discovered_blades_summary())
+
+ def get_mac_addresses(self, macs_yaml):
+ with io.open(macs_yaml, 'r') as stream:
+ self.macs_per_shelf_dict = yaml.load(stream)
+
+ def assign_roles_to_cluster_node_ids(self, dea):
+ self.node_id_roles_dict = {}
+ for shelf, blades_dict in self.node_ids_dict.iteritems():
+ for blade, node_id in blades_dict.iteritems():
+ role_list = []
+ if dea.has_role('controller', shelf, blade):
+ role_list.extend(['controller', 'mongo'])
+ if dea.has_role('cinder', shelf, blade):
+ role_list.extend(['cinder'])
+ elif dea.has_role('compute', shelf, blade):
+ role_list.extend(['compute'])
+ self.node_id_roles_dict[node_id] = (role_list, shelf, blade)
+
+ def configure_environment(self, dea):
+ config_env = ConfigureEnvironment(dea, self.yaml_config_dir,
+ self.supported_release[R['id']],
+ self.node_id_roles_dict)
+ config_env.configure_environment()
+ self.env_id = config_env.env_id
+
+ def deploy(self, dea):
+ dep = Deployment(dea, self.yaml_config_dir, self.env_id,
+ self.node_id_roles_dict)
+ dep.deploy()
+
+
+def main():
+
+ base_dir = os.path.dirname(os.path.realpath(__file__))
+ dea_yaml = base_dir + '/dea.yaml'
+ check_file_exists(dea_yaml)
+ macs_yaml = base_dir + '/macs.yaml'
+ check_file_exists(macs_yaml)
+
+ yaml_config_dir = '/var/lib/opnfv/pre_deploy'
+
+ deploy = Deploy(yaml_config_dir)
+ dea = DeploymentEnvironmentAdapter()
+ dea.parse_yaml(dea_yaml)
+
+ deploy.get_mac_addresses(macs_yaml)
+
+ deploy.collect_blade_ids_per_shelves(dea)
+
+ deploy.check_prerequisites()
+
+ deploy.wait_for_discovered_blades()
+
+ deploy.assign_roles_to_cluster_node_ids(dea)
+
+ deploy.configure_environment(dea)
+
+ deploy.deploy(dea)
+
+
+if __name__ == '__main__':
+ main() \ No newline at end of file
diff --git a/fuel/deploy/cloud_deploy/cloud/deployment.py b/fuel/deploy/cloud_deploy/cloud/deployment.py
new file mode 100644
index 0000000..831059b
--- /dev/null
+++ b/fuel/deploy/cloud_deploy/cloud/deployment.py
@@ -0,0 +1,100 @@
+import common
+import os
+import shutil
+import glob
+import yaml
+import io
+import time
+
+N = common.N
+E = common.E
+R = common.R
+RO = common.RO
+exec_cmd = common.exec_cmd
+run_proc = common.run_proc
+parse = common.parse
+err = common.err
+LOG = common.LOG
+
+
+class Deployment(object):
+
+ def __init__(self, dea, yaml_config_dir, env_id, node_id_roles_dict):
+ self.dea = dea
+ self.env_name = dea.get_environment_name()
+ self.yaml_config_dir = yaml_config_dir
+ self.env_id = env_id
+ self.node_id_roles_dict = node_id_roles_dict
+ self.node_id_list = []
+ for node_id in self.node_id_roles_dict.iterkeys():
+ self.node_id_list.append(node_id)
+ self.node_id_list.sort()
+
+ def download_deployment_info(self):
+ LOG.debug('Download deployment info for environment %s\n' % self.env_id)
+ deployment_dir = self.yaml_config_dir + '/deployment_%s' % self.env_id
+ if os.path.exists(deployment_dir):
+ shutil.rmtree(deployment_dir)
+ r, c = exec_cmd('fuel --env %s deployment --default --dir %s'
+ % (self.env_id, self.yaml_config_dir))
+ if c > 0:
+ err('Error: Could not download deployment info for env %s,'
+ ' reason: %s\n' % (self.env_id, r))
+
+ def upload_deployment_info(self):
+ LOG.debug('Upload deployment info for environment %s\n' % self.env_id)
+ r, c = exec_cmd('fuel --env %s deployment --upload --dir %s'
+ % (self.env_id, self.yaml_config_dir))
+ if c > 0:
+ err('Error: Could not upload deployment info for env %s,'
+ ' reason: %s\n' % (self.env_id, r))
+
+ def pre_deploy(self):
+ LOG.debug('Running pre-deploy on environment %s\n' % self.env_name)
+ self.download_deployment_info()
+ opnfv = {'opnfv': {}}
+
+ for node_file in glob.glob('%s/deployment_%s/*.yaml'
+ % (self.yaml_config_dir, self.env_id)):
+ with io.open(node_file) as stream:
+ node = yaml.load(stream)
+
+ if 'opnfv' not in node:
+ node.update(opnfv)
+
+ with io.open(node_file, 'w') as stream:
+ yaml.dump(node, stream, default_flow_style=False)
+ self.upload_deployment_info()
+
+
+ def deploy(self):
+ WAIT_LOOP = 180
+ SLEEP_TIME = 60
+
+ self.pre_deploy()
+
+ log_file = 'cloud.log'
+
+ LOG.debug('Starting deployment of environment %s\n' % self.env_name)
+ run_proc('fuel --env %s deploy-changes | strings | tee %s'
+ % (self.env_id, log_file))
+
+ ready = False
+ for i in range(WAIT_LOOP):
+ env = parse(exec_cmd('fuel env --env %s' % self.env_id))
+ LOG.debug('Environment status: %s\n' % env[0][E['status']])
+ r, _ = exec_cmd('tail -2 %s | head -1' % log_file)
+ if r:
+ LOG.debug('%s\n' % r)
+ if env[0][E['status']] == 'operational':
+ ready = True
+ break
+ else:
+ time.sleep(SLEEP_TIME)
+ exec_cmd('rm %s' % log_file)
+
+ if ready:
+ LOG.debug('Environment %s successfully deployed\n' % self.env_name)
+ else:
+ err('Deployment failed, environment %s is not operational\n'
+ % self.env_name)
diff --git a/fuel/deploy/cloud_deploy/cloud_deploy.py b/fuel/deploy/cloud_deploy/cloud_deploy.py
new file mode 100644
index 0000000..4197519
--- /dev/null
+++ b/fuel/deploy/cloud_deploy/cloud_deploy.py
@@ -0,0 +1,117 @@
+import os
+import io
+import yaml
+
+from cloud import common
+from cloud.dea import DeploymentEnvironmentAdapter
+from hardware_adapters.dha import DeploymentHardwareAdapter
+from ssh_client import SSHClient
+
+exec_cmd = common.exec_cmd
+err = common.err
+check_file_exists = common.check_file_exists
+LOG = common.LOG
+
+class CloudDeploy(object):
+
+ def __init__(self, fuel_ip, fuel_username, fuel_password):
+ self.fuel_ip = fuel_ip
+ self.fuel_username = fuel_username
+ self.fuel_password = fuel_password
+ self.shelf_blades_dict = {}
+ self.macs_per_shelf_dict = {}
+
+ def copy_to_fuel_master(self, dir_path=None, file_path=None, target='~'):
+ if dir_path:
+ path = '-r ' + dir_path
+ elif file_path:
+ path = file_path
+ LOG.debug('Copying %s to Fuel Master %s' % (path, target))
+ if path:
+ exec_cmd('sshpass -p %s scp -o UserKnownHostsFile=/dev/null'
+ ' -o StrictHostKeyChecking=no -o ConnectTimeout=15'
+ ' %s %s@%s:%s'
+ % (self.fuel_password, path, self.fuel_username,
+ self.fuel_ip, target))
+
+ def run_cloud_deploy(self, deploy_dir, deploy_app):
+ LOG.debug('START CLOUD DEPLOYMENT')
+ ssh = SSHClient(self.fuel_ip, self.fuel_username, self.fuel_password)
+ ssh.open()
+ ssh.run('python %s/%s' % (deploy_dir, deploy_app))
+ ssh.close()
+
+ def power_off_blades(self, dea):
+ for shelf, blade_list in self.shelf_blades_dict.iteritems():
+ type, mgmt_ip, username, password = dea.get_shelf_info(shelf)
+ dha = DeploymentHardwareAdapter(type, mgmt_ip, username, password)
+ dha.power_off_blades(shelf, blade_list)
+
+ def power_on_blades(self, dea):
+ for shelf, blade_list in self.shelf_blades_dict.iteritems():
+ type, mgmt_ip, username, password = dea.get_shelf_info(shelf)
+ dha = DeploymentHardwareAdapter(type, mgmt_ip, username, password)
+ dha.power_on_blades(shelf, blade_list)
+
+ def set_boot_order(self, dea):
+ for shelf, blade_list in self.shelf_blades_dict.iteritems():
+ type, mgmt_ip, username, password = dea.get_shelf_info(shelf)
+ dha = DeploymentHardwareAdapter(type, mgmt_ip, username, password)
+ dha.set_boot_order_blades(shelf, blade_list)
+
+ def get_mac_addresses(self, dea, macs_yaml):
+ self.macs_per_shelf_dict = {}
+ for shelf, blade_list in self.shelf_blades_dict.iteritems():
+ type, mgmt_ip, username, password = dea.get_shelf_info(shelf)
+ dha = DeploymentHardwareAdapter(type, mgmt_ip, username, password)
+ self.macs_per_shelf_dict[shelf] = dha.get_blades_mac_addresses(
+ shelf, blade_list)
+
+ with io.open(macs_yaml, 'w') as stream:
+ yaml.dump(self.macs_per_shelf_dict, stream,
+ default_flow_style=False)
+
+ def collect_blade_ids_per_shelves(self, dea):
+ self.shelf_blades_dict = dea.get_blade_ids_per_shelves()
+
+
+
+def main():
+
+ fuel_ip = '10.20.0.2'
+ fuel_username = 'root'
+ fuel_password = 'r00tme'
+ deploy_dir = '~/cloud'
+
+ cloud = CloudDeploy(fuel_ip, fuel_username, fuel_password)
+
+ base_dir = os.path.dirname(os.path.realpath(__file__))
+ deployment_dir = base_dir + '/cloud'
+ macs_yaml = base_dir + '/macs.yaml'
+ dea_yaml = base_dir + '/dea.yaml'
+ check_file_exists(dea_yaml)
+
+ cloud.copy_to_fuel_master(dir_path=deployment_dir)
+ cloud.copy_to_fuel_master(file_path=dea_yaml, target=deploy_dir)
+
+ dea = DeploymentEnvironmentAdapter()
+ dea.parse_yaml(dea_yaml)
+
+ cloud.collect_blade_ids_per_shelves(dea)
+
+ cloud.power_off_blades(dea)
+
+ cloud.set_boot_order(dea)
+
+ cloud.power_on_blades(dea)
+
+ cloud.get_mac_addresses(dea, macs_yaml)
+ check_file_exists(dea_yaml)
+
+ cloud.copy_to_fuel_master(file_path=macs_yaml, target=deploy_dir)
+
+ cloud.run_cloud_deploy(deploy_dir, 'deploy.py')
+
+
+if __name__ == '__main__':
+ main() \ No newline at end of file
diff --git a/fuel/deploy/cloud_deploy/hardware_adapters/__init__.py b/fuel/deploy/cloud_deploy/hardware_adapters/__init__.py
new file mode 100644
index 0000000..c274feb
--- /dev/null
+++ b/fuel/deploy/cloud_deploy/hardware_adapters/__init__.py
@@ -0,0 +1 @@
+__author__ = 'eszicse'
diff --git a/fuel/deploy/dha.py b/fuel/deploy/cloud_deploy/hardware_adapters/dha.py
index 87ac6e2..2764aeb 100644
--- a/fuel/deploy/dha.py
+++ b/fuel/deploy/cloud_deploy/hardware_adapters/dha.py
@@ -1,4 +1,5 @@
-from hardware_adapters.hp.hp_adapter import HpAdapter
+from hp.hp_adapter import HpAdapter
+from libvirt.libvirt_adapter import LibvirtAdapter
class DeploymentHardwareAdapter(object):
def __new__(cls, server_type, *args):
@@ -55,8 +56,6 @@ class EsxiAdapter(HardwareAdapter):
def get_blade_mac_addresses(self, shelf, blade):
return self.environment[shelf][blade]['mac']
-class LibvirtAdapter(HardwareAdapter):
- pass
class DellAdapter(HardwareAdapter):
pass
diff --git a/fuel/deploy/cloud_deploy/hardware_adapters/hp/__init__.py b/fuel/deploy/cloud_deploy/hardware_adapters/hp/__init__.py
new file mode 100644
index 0000000..c274feb
--- /dev/null
+++ b/fuel/deploy/cloud_deploy/hardware_adapters/hp/__init__.py
@@ -0,0 +1 @@
+__author__ = 'eszicse'
diff --git a/fuel/deploy/hardware_adapters/hp/hp_adapter.py b/fuel/deploy/cloud_deploy/hardware_adapters/hp/hp_adapter.py
index 7ce0dc9..916d4dc 100644
--- a/fuel/deploy/hardware_adapters/hp/hp_adapter.py
+++ b/fuel/deploy/cloud_deploy/hardware_adapters/hp/hp_adapter.py
@@ -1,16 +1,11 @@
import re
import time
from netaddr import EUI, mac_unix
-import logging
+from cloud import common
from run_oa_command import RunOACommand
-
-LOG = logging.getLogger(__name__)
-out_hdlr = logging.FileHandler(__file__.split('.')[0] + '.log', mode='w')
-out_hdlr.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
-LOG.addHandler(out_hdlr)
-LOG.setLevel(logging.DEBUG)
+LOG = common.LOG
class HpAdapter(object):
@@ -66,8 +61,38 @@ class HpAdapter(object):
right = EUI(right, dialect=self.mac_dhcp)
return [str(left), str(right)]
- def get_blade_hardware_info(self, shelf, blade=None):
+ def get_blades_mac_addresses(self, shelf, blade_list):
+ macs_per_blade_dict = {}
+ LOG.debug("Getting MAC addresses for shelf %s, blades %s"
+ % (shelf, blade_list))
+ self.oa_error_message = ''
+ oa = RunOACommand(self.mgmt_ip, self.username, self.password)
+ LOG.debug("Connect to active OA for shelf %d" % shelf)
+ try:
+ res = oa.connect_to_active()
+ except:
+ raise self.InternalConnectError(oa.error_message)
+ if res is None:
+ raise self.InternalConnectError(oa.error_message)
+ if not oa.connected():
+ raise self.NoInfoFoundError(oa.error_message)
+ try:
+ for blade in blade_list:
+ LOG.debug("Send command to OA: %s" % cmd)
+ cmd = ("show server info %s" % blade)
+ printout = oa.send_command(cmd)
+ left, right = self.find_mac(printout, shelf, blade)
+ left = EUI(left, dialect=self.mac_dhcp)
+ right = EUI(right, dialect=self.mac_dhcp)
+ macs_per_blade_dict[blade] = [str(left), str(right)]
+ except:
+ raise self.NoInfoFoundError(oa.error_message)
+ finally:
+ oa.close()
+ return macs_per_blade_dict
+
+ def get_blade_hardware_info(self, shelf, blade=None):
if blade:
LOG.debug("Entering: get_hp_info(%d,%d)" % (shelf, blade))
else:
@@ -118,6 +143,9 @@ class HpAdapter(object):
def power_on_blades(self, shelf, blade_list):
return self.set_state(shelf, 'unlocked', blade_list=blade_list)
+ def set_boot_order_blades(self, shelf, blade_list):
+ return self.set_boot_order(shelf, blade_list=blade_list)
+
def power_off_blade(self, shelf, blade):
return self.set_state(shelf, 'locked', one_blade=blade)
@@ -127,16 +155,11 @@ class HpAdapter(object):
def set_boot_order_blade(self, shelf, blade):
return self.set_boot_order(shelf, one_blade=blade)
- def set_boot_order_blades(self, shelf, blade_list):
- return self.set_boot_order(shelf, blade_list=blade_list)
-
-
-
# Search HP's OA server info for MAC for left and right control
- def find_mac(self, serverinfo, shelf, blade):
+ def find_mac(self, printout, shelf, blade):
left = False
right = False
- for line in serverinfo:
+ for line in printout:
if ("No Server Blade Installed" in line or
"Invalid Arguments" in line):
raise self.NoInfoFoundError("Blade %d in shelf %d "
@@ -160,7 +183,6 @@ class HpAdapter(object):
# Return True to indicate that power state succesfully updated
# state: locked, unlocked
def set_state(self, shelf, state, one_blade=None, blade_list=None):
-
if state not in ['locked', 'unlocked']:
return None
diff --git a/fuel/deploy/hardware_adapters/hp/run_oa_command.py b/fuel/deploy/cloud_deploy/hardware_adapters/hp/run_oa_command.py
index 32135c3..36fac77 100644
--- a/fuel/deploy/hardware_adapters/hp/run_oa_command.py
+++ b/fuel/deploy/cloud_deploy/hardware_adapters/hp/run_oa_command.py
@@ -1,12 +1,9 @@
import socket
import paramiko
-import logging
-LOG = logging.getLogger(__name__)
-out_hdlr = logging.FileHandler(__file__.split('.')[0] + '.log', mode='w')
-out_hdlr.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
-LOG.addHandler(out_hdlr)
-LOG.setLevel(logging.DEBUG)
+from cloud import common
+
+LOG = common.LOG
class RunOACommand:
diff --git a/fuel/deploy/cloud_deploy/hardware_adapters/libvirt/__init__.py b/fuel/deploy/cloud_deploy/hardware_adapters/libvirt/__init__.py
new file mode 100644
index 0000000..c274feb
--- /dev/null
+++ b/fuel/deploy/cloud_deploy/hardware_adapters/libvirt/__init__.py
@@ -0,0 +1 @@
+__author__ = 'eszicse'
diff --git a/fuel/deploy/cloud_deploy/hardware_adapters/libvirt/libvirt_adapter.py b/fuel/deploy/cloud_deploy/hardware_adapters/libvirt/libvirt_adapter.py
new file mode 100644
index 0000000..d332e59
--- /dev/null
+++ b/fuel/deploy/cloud_deploy/hardware_adapters/libvirt/libvirt_adapter.py
@@ -0,0 +1,153 @@
+from lxml import etree
+from cloud import common
+from ssh_client import SSHClient
+
+exec_cmd = common.exec_cmd
+err = common.err
+LOG = common.LOG
+
+
+class LibvirtAdapter(object):
+
+ def __init__(self, mgmt_ip, username, password):
+ self.mgmt_ip = mgmt_ip
+ self.username = username
+ self.password = password
+ self.parser = etree.XMLParser(remove_blank_text=True)
+
+ def power_off_blades(self, shelf, blade_list):
+ ssh = SSHClient(self.mgmt_ip, self.username, self.password)
+ ssh.open()
+ for blade in blade_list:
+ LOG.debug('Power off blade %s in shelf %s' % (blade, shelf))
+ vm_name = 's%s_b%s' % (shelf, blade)
+ resp = ssh.execute('virsh destroy %s' % vm_name)
+ LOG.debug('response: %s' % resp)
+ ssh.close()
+
+ def power_on_blades(self, shelf, blade_list):
+ ssh = SSHClient(self.mgmt_ip, self.username, self.password)
+ ssh.open()
+ for blade in blade_list:
+ LOG.debug('Power on blade %s in shelf %s' % (blade, shelf))
+ vm_name = 's%s_b%s' % (shelf, blade)
+ resp = ssh.execute('virsh start %s' % vm_name)
+ LOG.debug('response: %s' % resp)
+ ssh.close()
+
+ def set_boot_order_blades(self, shelf, blade_list, boot_dev_list=None):
+ if not boot_dev_list:
+ boot_dev_list = ['network', 'hd']
+ ssh = SSHClient(self.mgmt_ip, self.username, self.password)
+ ssh.open()
+ temp_dir= ssh.execute('mktemp -d').strip()
+ for blade in blade_list:
+ LOG.debug('Set boot order %s on blade %s in shelf %s'
+ % (boot_dev_list, blade, shelf))
+ vm_name = 's%s_b%s' % (shelf, blade)
+ resp = ssh.execute('virsh dumpxml %s' % vm_name)
+ xml_dump = etree.fromstring(resp, self.parser)
+ os = xml_dump.xpath('/domain/os')
+ for o in os:
+ for bootelem in ['boot', 'bootmenu']:
+ boot = o.xpath(bootelem)
+ for b in boot:
+ b.getparent().remove(b)
+ for dev in boot_dev_list:
+ b = etree.Element('boot')
+ b.set('dev', dev)
+ o.append(b)
+ bmenu = etree.Element('bootmenu')
+ bmenu.set('enable', 'no')
+ o.append(bmenu)
+ tree = etree.ElementTree(xml_dump)
+ xml_file = temp_dir + '/%s.xml' % vm_name
+ with open(xml_file, 'w') as f:
+ tree.write(f, pretty_print=True, xml_declaration=True)
+ ssh.execute('virsh define %s' % xml_file)
+ ssh.execute('rm -fr %s' % temp_dir)
+ ssh.close()
+
+ def get_blades_mac_addresses(self, shelf, blade_list):
+ LOG.debug('Get the MAC addresses of blades %s in shelf %s'
+ % (blade_list, shelf))
+ macs_per_blade_dict = {}
+ ssh = SSHClient(self.mgmt_ip, self.username, self.password)
+ ssh.open()
+ for blade in blade_list:
+ vm_name = 's%s_b%s' % (shelf, blade)
+ mac_list = macs_per_blade_dict[blade] = []
+ resp = ssh.execute('virsh dumpxml %s' % vm_name)
+ xml_dump = etree.fromstring(resp)
+ interfaces = xml_dump.xpath('/domain/devices/interface')
+ for interface in interfaces:
+ macs = interface.xpath('mac')
+ for mac in macs:
+ mac_list.append(mac.get('address'))
+ ssh.close()
+ return macs_per_blade_dict
+
+ def load_image_file(self, shelf=None, blade=None, vm=None,
+ image_path=None):
+ if shelf and blade:
+ vm_name = 's%s_b%s' % (shelf, blade)
+ else:
+ vm_name = vm
+
+ LOG.debug('Load media file %s into %s '
+ % (image_path, 'vm %s' % vm if vm else 'blade %s in shelf %s'
+ % (shelf, blade)))
+
+ ssh = SSHClient(self.mgmt_ip, self.username, self.password)
+ ssh.open()
+ temp_dir= ssh.execute('mktemp -d').strip()
+ resp = ssh.execute('virsh dumpxml %s' % vm_name)
+ xml_dump = etree.fromstring(resp)
+
+ disks = xml_dump.xpath('/domain/devices/disk')
+ for disk in disks:
+ if disk.get('device') == 'cdrom':
+ disk.set('type', 'file')
+ sources = disk.xpath('source')
+ for source in sources:
+ disk.remove(source)
+ source = etree.SubElement(disk, 'source')
+ source.set('file', image_path)
+ tree = etree.ElementTree(xml_dump)
+ xml_file = temp_dir + '/%s.xml' % vm_name
+ with open(xml_file, 'w') as f:
+ tree.write(f, pretty_print=True, xml_declaration=True)
+ ssh.execute('virsh define %s' % xml_file)
+ ssh.execute('rm -fr %s' % temp_dir)
+ ssh.close()
+
+ def eject_image_file(self, shelf=None, blade=None, vm=None):
+ if shelf and blade:
+ vm_name = 's%s_b%s' % (shelf, blade)
+ else:
+ vm_name = vm
+
+ LOG.debug('Eject media file from %s '
+ % 'vm %s' % vm if vm else 'blade %s in shelf %s'
+ % (shelf, blade))
+
+ ssh = SSHClient(self.mgmt_ip, self.username, self.password)
+ ssh.open()
+ temp_dir= ssh.execute('mktemp -d').strip()
+ resp = ssh.execute('virsh dumpxml %s' % vm_name)
+ xml_dump = etree.fromstring(resp)
+
+ disks = xml_dump.xpath('/domain/devices/disk')
+ for disk in disks:
+ if disk.get('device') == 'cdrom':
+ disk.set('type', 'block')
+ sources = disk.xpath('source')
+ for source in sources:
+ disk.remove(source)
+ tree = etree.ElementTree(xml_dump)
+ xml_file = temp_dir + '/%s.xml' % vm_name
+ with open(xml_file, 'w') as f:
+ tree.write(f, pretty_print=True, xml_declaration=True)
+ ssh.execute('virsh define %s' % xml_file)
+ ssh.execute('rm -fr %s' % temp_dir)
+ ssh.close()
diff --git a/fuel/deploy/cloud_deploy/ssh_client.py b/fuel/deploy/cloud_deploy/ssh_client.py
new file mode 100644
index 0000000..b9aad6c
--- /dev/null
+++ b/fuel/deploy/cloud_deploy/ssh_client.py
@@ -0,0 +1,56 @@
+import paramiko
+from cloud import common
+
+TIMEOUT = 600
+LOG = common.LOG
+
+class SSHClient(object):
+
+ def __init__(self, host, username, password):
+ self.host = host
+ self.username = username
+ self.password = password
+ self.client = None
+
+ def open(self, timeout=TIMEOUT):
+ self.client = paramiko.SSHClient()
+ self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+ self.client.connect(self.host, username=self.username,
+ password=self.password, timeout=timeout)
+
+ def close(self):
+ if self.client is not None:
+ self.client.close()
+ self.client = None
+
+ def execute(self, command, sudo=False, timeout=TIMEOUT):
+ if sudo and self.username != 'root':
+ command = "sudo -S -p '' %s" % command
+ stdin, stdout, stderr = self.client.exec_command(command,
+ timeout=timeout)
+ if sudo:
+ stdin.write(self.password + '\n')
+ stdin.flush()
+ return ''.join(''.join(stderr.readlines()) +
+ ''.join(stdout.readlines()))
+
+ def run(self, command):
+ transport = self.client.get_transport()
+ transport.set_keepalive(1)
+ chan = transport.open_session()
+ chan.exec_command(command)
+
+ while not chan.exit_status_ready():
+ if chan.recv_ready():
+ data = chan.recv(1024)
+ while data:
+ print data
+ data = chan.recv(1024)
+
+ if chan.recv_stderr_ready():
+ error_buff = chan.recv_stderr(1024)
+ while error_buff:
+ print error_buff
+ error_buff = chan.recv_stderr(1024)
+ exit_status = chan.recv_exit_status()
+ LOG.debug('Exit status %s' % exit_status) \ No newline at end of file
diff --git a/fuel/deploy/common.py b/fuel/deploy/common.py
deleted file mode 100644
index cd5085c..0000000
--- a/fuel/deploy/common.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import subprocess
-import sys
-
-
-N = {'id': 0, 'status': 1, 'name': 2, 'cluster': 3, 'ip': 4, 'mac': 5,
- 'roles': 6, 'pending_roles': 7, 'online': 8}
-E = {'id': 0, 'status': 1, 'name': 2, 'mode': 3, 'release_id': 4,
- 'changes': 5, 'pending_release_id': 6}
-R = {'id': 0, 'name': 1, 'state': 2, 'operating_system': 3, 'version': 4}
-RO = {'name': 0, 'conflicts': 1}
-
-def exec_cmd(cmd):
- process = subprocess.Popen(cmd,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- shell=True)
- return process.communicate()[0]
-
-def parse(printout):
- parsed_list = []
- lines = printout.splitlines()
- for l in lines[2:]:
- parsed = [e.strip() for e in l.split('|')]
- parsed_list.append(parsed)
- return parsed_list
-
-def err(error_message):
- sys.stderr.write(error_message)
- sys.exit(1)
diff --git a/fuel/deploy/configure_environment.py b/fuel/deploy/configure_environment.py
deleted file mode 100644
index 9aca904..0000000
--- a/fuel/deploy/configure_environment.py
+++ /dev/null
@@ -1,70 +0,0 @@
-import common
-import os
-import shutil
-import yaml
-
-
-from configure_settings import ConfigureSettings
-from configure_network import ConfigureNetwork
-
-N = common.N
-E = common.E
-R = common.R
-RO = common.RO
-exec_cmd = common.exec_cmd
-parse = common.parse
-err = common.err
-
-class ConfigureEnvironment(object):
-
- def __init__(self, dea, yaml_config_dir):
- self.env_id = None
- self.dea = dea
- self.yaml_config_dir = yaml_config_dir
- self.env_name = dea.get_environment_name()
-
- def env_exists(self, env_name):
- env_list = parse(exec_cmd('fuel env --list'))
- for env in env_list:
- if env[E['name']] == env_name and env[E['status']] == 'new':
- return True
- return False
-
- def get_env_id(self, env_name):
- env_list = parse(exec_cmd('fuel env --list'))
- for env in env_list:
- if env[E['name']] == env_name:
- return env[E['id']]
-
- def configure_environment(self, dea):
- exec_cmd('fuel env -c --name %s --release %s --mode ha --net neutron '
- '--nst vlan' % (self.env_name,
- self.supported_release[R['id']]))
-
- self.env_id = self.get_env_id(self.env_name)
- if not self.env_exists(self.env_name):
- err("Failed to create environment %s" % self.env_name)
-
- self.config_settings()
- self.config_network()
-
- def config_settings(self):
- if os.path.exists(self.yaml_config_dir):
- shutil.rmtree(self.yaml_config_dir)
- os.makedirs(self.yaml_config_dir)
-
- settings = ConfigureSettings(self.yaml_config_dir, self.env_id)
- settings.config_settings()
-
-
- def config_network(self):
- network_yaml=self.yaml_config_dir + '/network_%s.yaml' % self.env_id
- os.remove(network_yaml)
-
- network = ConfigureNetwork(self.yaml_config_dir, network_yaml,
- self.env_id, self.dea)
- network.config_network()
-
-
-
-
diff --git a/fuel/deploy/configure_network.py b/fuel/deploy/configure_network.py
deleted file mode 100644
index 0b298e5..0000000
--- a/fuel/deploy/configure_network.py
+++ /dev/null
@@ -1,91 +0,0 @@
-import common
-import os
-import yaml
-import io
-import re
-
-N = common.N
-E = common.E
-R = common.R
-RO = common.RO
-exec_cmd = common.exec_cmd
-parse = common.parse
-err = common.err
-
-P1 = re.compile('!\s.*')
-
-class ConfigureNetwork(object):
-
- def __init__(self, yaml_config_dir, network_yaml, env_id, dea):
- self.yaml_config_dir = yaml_config_dir
- self.network_yaml = network_yaml
- self.env_id = env_id
- self.dea = dea
-
- def download_settings(self):
- exec_cmd('fuel network --env %s --download --dir %s'
- % (self.env_id, self.yaml_config_dir))
-
- def upload_settings(self):
- exec_cmd('fuel network --env %s --upload --dir %s'
- % (self.env_id, self.yaml_config_dir))
-
- def config_network(self):
-
- self.download_settings()
-
- self.apply_network_config()
-
- self.upload_settings()
-
- self.verify()
-
- def apply_network_config(self):
-
- with io.open(self.network_yaml) as stream:
- network_config = yaml.load(stream)
- networks = network_config['networks']
-
- net = self.dea.get_networks()
- net['fuelweb_admin'] = net['management']
- if 'vlan' in net['fuelweb_admin']:
- del net['fuelweb_admin']['vlan']
- del net['management']
- net_names = [n for n in net.iterkeys()]
-
- for i in range(len(networks)):
- if networks[i]['name'] == 'management':
- networks = networks[:i] + networks[i+1:]
- network_config['networks'] = networks
- break
-
- for network in networks:
- name = network['name']
- if name in net_names:
- if ('vlan' in net[name] and net[name]['vlan'] is not None):
- network['vlan_start'] = net[name]['vlan']
- network['cidr'] = net[name]['cidr']
- network['ip_ranges'][0][0] = net[name]['start']
- network['ip_ranges'][0][1] = net[name]['end']
-
- with io.open(self.network_yaml, 'w') as stream:
- yaml.dump(network_config, stream, default_flow_style=False)
-
- def verify(self):
- ret = exec_cmd('mktemp -d')
- temp_dir = ret.splitlines()[0]
-
- exec_cmd('fuel network --env %s --download --dir %s'
- % (self.env_id, temp_dir))
-
- ret = exec_cmd('diff -C0 %s %s'
- % (self.network_yaml,
- temp_dir + '/network_%s.yaml' % self.env_id))
- diff_list = []
- for l in ret.splitlines():
- m = P1.match(l)
- if m and '_vip' not in l:
- diff_list.append(l)
- if diff_list:
- err('Uploaded network yaml rejected by Fuel\n')
- \ No newline at end of file
diff --git a/fuel/deploy/configure_settings.py b/fuel/deploy/configure_settings.py
deleted file mode 100644
index cdeea49..0000000
--- a/fuel/deploy/configure_settings.py
+++ /dev/null
@@ -1,88 +0,0 @@
-import common
-import os
-import yaml
-import io
-import re
-
-N = common.N
-E = common.E
-R = common.R
-RO = common.RO
-exec_cmd = common.exec_cmd
-parse = common.parse
-err = common.err
-
-class ConfigureSettings(object):
-
- def __init__(self, yaml_config_dir, env_id):
- self.yaml_config_dir = yaml_config_dir
- self.env_id = env_id
-
- def download_settings(self):
- exec_cmd('fuel --env %s settings --download' % self.env_id)
-
- def upload_settings(self):
- exec_cmd('fuel --env %s settings --upload' % self.env_id)
-
-
- def config_settings(self):
- self.download_settings()
- self.modify_settings()
- self.upload_settings()
-
- # Fix console speed
- def fix_console_speed(data):
- # First remove all console= from the kernel cmdline
- cmdline = data["editable"]["kernel_params"]["kernel"]["value"]
- pat = re.compile(r"console=[\w,]+\s+")
- repl = 1
- while repl != 0:
- cmdline, repl = pat.subn("", cmdline)
-
- # Then add the console info we want
- cmdline = re.sub(r"^", "console=tty0 console=ttyS0,115200 ", cmdline)
- data["editable"]["kernel_params"]["kernel"]["value"] = cmdline
-
- # Initialize kernel audit
- def initialize_kernel_audit(data):
- cmdline = data["editable"]["kernel_params"]["kernel"]["value"]
- cmdline = "audit=1 " + cmdline
- data["editable"]["kernel_params"]["kernel"]["value"] = cmdline
-
- # Add crashkernel parameter to boot parameters. W/o this we can't
- # make crash dumps after initial deploy. Standard grub setup will add
- # crashkernel= options - with bad values but that is another issue - but
- # that only enables crash dumps after first reboot
- def add_crashkernel_support(data):
- cmdline = data["editable"]["kernel_params"]["kernel"]["value"]
- cmdline += " crashkernel=256M"
- data["editable"]["kernel_params"]["kernel"]["value"] = cmdline
-
-
- def modify_settings(self):
-
- filename = "%s/settings_%d.yaml" % (self.yaml_config_dir, self.env_id)
- if not os.path.isfile(filename):
- err("Failed to find %s\n" % filename)
-
- with io.open(filename) as stream:
- data = yaml.load(stream)
-
- self.fix_console_speed(data)
-
- self.initialize_kernel_audit(data)
-
- self.add_crashkernel_support(data)
-
- # Make sure we have the correct libvirt type
- data["editable"]["common"]["libvirt_type"]["value"] = "kvm"
-
-
- # Save the settings into the file from which we loaded them
- with io.open(filename, "w") as stream:
- yaml.dump(data, stream, default_flow_style=False)
-
-
-
-
-
diff --git a/fuel/deploy/dea.yaml b/fuel/deploy/dea.yaml
index 420dae7..b83ddea 100644
--- a/fuel/deploy/dea.yaml
+++ b/fuel/deploy/dea.yaml
@@ -1,37 +1,947 @@
---
name: ENV-1
-server:
- type: hp
- mgmt_ip: 10.118.32.197
- username: opnfv
- password: E///@work
shelf:
- id: 1
+ type: libvirt
+ mgmt_ip: 10.20.0.1
+ username: user
+ password: systemabc
blade:
- id: 1
- role: controller
+ roles:
+ - controller
- id: 2
+ roles:
+ - controller
- id: 3
- role: controller
+ roles:
+ - controller
- id: 4
- id: 5
- id: 6
-network:
- - name: management
- cidr: 192.168.0.0/24
- start: 192.168.0.1
- end: 192.168.0.253
- - name: private
- vlan:
- cidr: 192.168.11.0/24
- start: 192.168.11.1
- end: 192.168.11.253
- - name: storage
- vlan:
- cidr: 192.168.12.0/24
- start: 192.168.12.1
- end: 192.168.12.253
- - name: public
- vlan:
+networks:
+ management_vip: 192.168.0.2
+ networking_parameters:
+ base_mac: fa:16:3e:00:00:00
+ dns_nameservers:
+ - 8.8.4.4
+ - 8.8.8.8
+ floating_ranges:
+ - - 172.16.0.130
+ - 172.16.0.254
+ gre_id_range:
+ - 2
+ - 65535
+ internal_cidr: 192.168.111.0/24
+ internal_gateway: 192.168.111.1
+ net_l23_provider: ovs
+ segmentation_type: vlan
+ vlan_range:
+ - 1000
+ - 1200
+ networks:
+ - cidr: 172.16.0.0/24
+ gateway: 172.16.0.1
+ ip_ranges:
+ - - 172.16.0.2
+ - 172.16.0.126
+ meta:
+ assign_vip: true
+ cidr: 172.16.0.0/24
+ configurable: true
+ floating_range_var: floating_ranges
+ ip_range:
+ - 172.16.0.2
+ - 172.16.0.126
+ map_priority: 1
+ name: public
+ notation: ip_ranges
+ render_addr_mask: public
+ render_type: null
+ use_gateway: true
+ vlan_start: null
+ name: public
+ vlan_start: null
+ - cidr: null
+ gateway: null
+ ip_ranges: []
+ meta:
+ assign_vip: false
+ configurable: false
+ map_priority: 2
+ name: private
+ neutron_vlan_range: true
+ notation: null
+ render_addr_mask: null
+ render_type: null
+ seg_type: vlan
+ use_gateway: false
+ vlan_start: null
+ name: private
+ vlan_start: null
+ - cidr: 192.168.0.0/24
+ gateway: null
+ ip_ranges:
+ - - 192.168.0.2
+ - 192.168.0.254
+ meta:
+ assign_vip: true
+ cidr: 192.168.0.0/24
+ configurable: true
+ map_priority: 2
+ name: management
+ notation: cidr
+ render_addr_mask: internal
+ render_type: cidr
+ use_gateway: false
+ vlan_start: 101
+ name: management
+ vlan_start: 101
+ - cidr: 192.168.1.0/24
+ gateway: null
+ ip_ranges:
+ - - 192.168.1.2
+ - 192.168.1.254
+ meta:
+ assign_vip: false
+ cidr: 192.168.1.0/24
+ configurable: true
+ map_priority: 2
+ name: storage
+ notation: cidr
+ render_addr_mask: storage
+ render_type: cidr
+ use_gateway: false
+ vlan_start: 102
+ name: storage
+ vlan_start: 102
+ - cidr: 10.20.0.0/24
+ gateway: null
+ ip_ranges:
+ - - 10.20.0.3
+ - 10.20.0.254
+ meta:
+ assign_vip: false
+ configurable: false
+ map_priority: 0
+ notation: ip_ranges
+ render_addr_mask: null
+ render_type: null
+ unmovable: true
+ use_gateway: true
+ name: fuelweb_admin
+ vlan_start: null
+ public_vip: 172.16.0.2
+controller:
+- action: add-br
+ name: br-eth0
+- action: add-port
+ bridge: br-eth0
+ name: eth0
+- action: add-br
+ name: br-eth1
+- action: add-port
+ bridge: br-eth1
+ name: eth1
+- action: add-br
+ name: br-eth2
+- action: add-port
+ bridge: br-eth2
+ name: eth2
+- action: add-br
+ name: br-eth3
+- action: add-port
+ bridge: br-eth3
+ name: eth3
+- action: add-br
+ name: br-ex
+- action: add-br
+ name: br-mgmt
+- action: add-br
+ name: br-storage
+- action: add-br
+ name: br-fw-admin
+- action: add-patch
+ bridges:
+ - br-eth1
+ - br-storage
+ tags:
+ - 102
+ - 0
+ vlan_ids:
+ - 102
+ - 0
+- action: add-patch
+ bridges:
+ - br-eth0
+ - br-mgmt
+ tags:
+ - 101
+ - 0
+ vlan_ids:
+ - 101
+ - 0
+- action: add-patch
+ bridges:
+ - br-eth0
+ - br-fw-admin
+ trunks:
+ - 0
+- action: add-patch
+ bridges:
+ - br-eth3
+ - br-ex
+ trunks:
+ - 0
+- action: add-br
+ name: br-prv
+- action: add-patch
+ bridges:
+ - br-eth2
+ - br-prv
+compute:
+- action: add-br
+ name: br-eth0
+- action: add-port
+ bridge: br-eth0
+ name: eth0
+- action: add-br
+ name: br-eth1
+- action: add-port
+ bridge: br-eth1
+ name: eth1
+- action: add-br
+ name: br-eth2
+- action: add-port
+ bridge: br-eth2
+ name: eth2
+- action: add-br
+ name: br-eth3
+- action: add-port
+ bridge: br-eth3
+ name: eth3
+- action: add-br
+ name: br-mgmt
+- action: add-br
+ name: br-storage
+- action: add-br
+ name: br-fw-admin
+- action: add-patch
+ bridges:
+ - br-eth1
+ - br-storage
+ tags:
+ - 102
+ - 0
+ vlan_ids:
+ - 102
+ - 0
+- action: add-patch
+ bridges:
+ - br-eth0
+ - br-mgmt
+ tags:
+ - 101
+ - 0
+ vlan_ids:
+ - 101
+ - 0
+- action: add-patch
+ bridges:
+ - br-eth0
+ - br-fw-admin
+ trunks:
+ - 0
+- action: add-br
+ name: br-prv
+- action: add-patch
+ bridges:
+ - br-eth2
+ - br-prv
+interfaces:
+ eth0:
+ - fuelweb_admin
+ - management
+ eth1:
+ - storage
+ eth2:
+ - private
+ eth3:
+ - public
+settings:
+ editable:
+ access:
+ email:
+ description: Email address for Administrator
+ label: email
+ type: text
+ value: admin@localhost
+ weight: 40
+ metadata:
+ label: Access
+ weight: 10
+ password:
+ description: Password for Administrator
+ label: password
+ type: password
+ value: admin
+ weight: 20
+ tenant:
+ description: Tenant (project) name for Administrator
+ label: tenant
+ regex:
+ error: Invalid tenant name
+ source: ^(?!services$)(?!nova$)(?!glance$)(?!keystone$)(?!neutron$)(?!cinder$)(?!swift$)(?!ceph$)(?![Gg]uest$).*
+ type: text
+ value: admin
+ weight: 30
+ user:
+ description: Username for Administrator
+ label: username
+ regex:
+ error: Invalid username
+ source: ^(?!services$)(?!nova$)(?!glance$)(?!keystone$)(?!neutron$)(?!cinder$)(?!swift$)(?!ceph$)(?![Gg]uest$).*
+ type: text
+ value: admin
+ weight: 10
+ additional_components:
+ ceilometer:
+ description: If selected, Ceilometer component will be installed
+ label: Install Ceilometer
+ type: checkbox
+ value: true
+ weight: 40
+ heat:
+ description: ''
+ label: ''
+ type: hidden
+ value: true
+ weight: 30
+ metadata:
+ label: Additional Components
+ weight: 20
+ murano:
+ description: If selected, Murano component will be installed
+ label: Install Murano
+ restrictions:
+ - cluster:net_provider != 'neutron'
+ type: checkbox
+ value: false
+ weight: 20
+ sahara:
+ description: If selected, Sahara component will be installed
+ label: Install Sahara
+ type: checkbox
+ value: false
+ weight: 10
+ common:
+ auth_key:
+ description: Public key(s) to include in authorized_keys on deployed nodes
+ label: Public Key
+ type: text
+ value: ''
+ weight: 70
+ auto_assign_floating_ip:
+ description: If selected, OpenStack will automatically assign a floating IP
+ to a new instance
+ label: Auto assign floating IP
+ restrictions:
+ - cluster:net_provider == 'neutron'
+ type: checkbox
+ value: false
+ weight: 40
+ compute_scheduler_driver:
+ label: Scheduler driver
+ type: radio
+ value: nova.scheduler.filter_scheduler.FilterScheduler
+ values:
+ - data: nova.scheduler.filter_scheduler.FilterScheduler
+ description: Currently the most advanced OpenStack scheduler. See the OpenStack
+ documentation for details.
+ label: Filter scheduler
+ - data: nova.scheduler.simple.SimpleScheduler
+ description: This is 'naive' scheduler which tries to find the least loaded
+ host
+ label: Simple scheduler
+ weight: 40
+ debug:
+ description: Debug logging mode provides more information, but requires more
+ disk space.
+ label: OpenStack debug logging
+ type: checkbox
+ value: false
+ weight: 20
+ disable_offload:
+ description: If set, generic segmentation offload (gso) and generic receive
+ offload (gro) on physical nics will be disabled. See ethtool man.
+ label: Disable generic offload on physical nics
+ restrictions:
+ - action: hide
+ condition: cluster:net_provider == 'neutron' and networking_parameters:segmentation_type
+ == 'gre'
+ type: checkbox
+ value: true
+ weight: 80
+ libvirt_type:
+ label: Hypervisor type
+ type: radio
+ value: kvm
+ values:
+ - data: kvm
+ description: Choose this type of hypervisor if you run OpenStack on hardware
+ label: KVM
+ restrictions:
+ - settings:common.libvirt_type.value == 'vcenter'
+ - data: qemu
+ description: Choose this type of hypervisor if you run OpenStack on virtual
+ hosts.
+ label: QEMU
+ restrictions:
+ - settings:common.libvirt_type.value == 'vcenter'
+ - data: vcenter
+ description: Choose this type of hypervisor if you run OpenStack in a vCenter
+ environment.
+ label: vCenter
+ restrictions:
+ - settings:common.libvirt_type.value != 'vcenter' or cluster:net_provider
+ == 'neutron'
+ weight: 30
+ metadata:
+ label: Common
+ weight: 30
+ nova_quota:
+ description: Quotas are used to limit CPU and memory usage for tenants. Enabling
+ quotas will increase load on the Nova database.
+ label: Nova quotas
+ type: checkbox
+ value: false
+ weight: 25
+ resume_guests_state_on_host_boot:
+ description: Whether to resume previous guests state when the host reboots.
+ If enabled, this option causes guests assigned to the host to resume their
+ previous state. If the guest was running a restart will be attempted when
+ nova-compute starts. If the guest was not running previously, a restart
+ will not be attempted.
+ label: Resume guests state on host boot
+ type: checkbox
+ value: false
+ weight: 60
+ use_cow_images:
+ description: For most cases you will want qcow format. If it's disabled, raw
+ image format will be used to run VMs. OpenStack with raw format currently
+ does not support snapshotting.
+ label: Use qcow format for images
+ type: checkbox
+ value: true
+ weight: 50
+ corosync:
+ group:
+ description: ''
+ label: Group
+ type: text
+ value: 226.94.1.1
+ weight: 10
+ metadata:
+ label: Corosync
+ restrictions:
+ - action: hide
+ condition: 'true'
+ weight: 50
+ port:
+ description: ''
+ label: Port
+ type: text
+ value: '12000'
+ weight: 20
+ verified:
+ description: Set True only if multicast is configured correctly on router.
+ label: Need to pass network verification.
+ type: checkbox
+ value: false
+ weight: 10
+ external_dns:
+ dns_list:
+ description: List of upstream DNS servers, separated by comma
+ label: DNS list
+ type: text
+ value: 8.8.8.8, 8.8.4.4
+ weight: 10
+ metadata:
+ label: Upstream DNS
+ weight: 90
+ external_ntp:
+ metadata:
+ label: Upstream NTP
+ weight: 100
+ ntp_list:
+ description: List of upstream NTP servers, separated by comma
+ label: NTP servers list
+ type: text
+ value: 0.pool.ntp.org, 1.pool.ntp.org
+ weight: 10
+ kernel_params:
+ kernel:
+ description: Default kernel parameters
+ label: Initial parameters
+ type: text
+ value: console=ttyS0,9600 console=tty0 rootdelay=90 nomodeset
+ weight: 45
+ metadata:
+ label: Kernel parameters
+ weight: 40
+ neutron_mellanox:
+ metadata:
+ enabled: true
+ label: Mellanox Neutron components
+ toggleable: false
+ weight: 50
+ plugin:
+ label: Mellanox drivers and SR-IOV plugin
+ type: radio
+ value: disabled
+ values:
+ - data: disabled
+ description: If selected, Mellanox drivers, Neutron and Cinder plugin will
+ not be installed.
+ label: Mellanox drivers and plugins disabled
+ restrictions:
+ - settings:storage.iser.value == true
+ - data: drivers_only
+ description: If selected, Mellanox Ethernet drivers will be installed to
+ support networking over Mellanox NIC. Mellanox Neutron plugin will not
+ be installed.
+ label: Install only Mellanox drivers
+ restrictions:
+ - settings:common.libvirt_type.value != 'kvm'
+ - data: ethernet
+ description: If selected, both Mellanox Ethernet drivers and Mellanox network
+ acceleration (Neutron) plugin will be installed.
+ label: Install Mellanox drivers and SR-IOV plugin
+ restrictions:
+ - settings:common.libvirt_type.value != 'kvm' or not (cluster:net_provider
+ == 'neutron' and networking_parameters:segmentation_type == 'vlan')
+ weight: 60
+ vf_num:
+ description: Note that one virtual function will be reserved to the storage
+ network, in case of choosing iSER.
+ label: Number of virtual NICs
+ restrictions:
+ - settings:neutron_mellanox.plugin.value != 'ethernet'
+ type: text
+ value: '16'
+ weight: 70
+ nsx_plugin:
+ connector_type:
+ description: Default network transport type to use
+ label: NSX connector type
+ type: select
+ value: stt
+ values:
+ - data: gre
+ label: GRE
+ - data: ipsec_gre
+ label: GRE over IPSec
+ - data: stt
+ label: STT
+ - data: ipsec_stt
+ label: STT over IPSec
+ - data: bridge
+ label: Bridge
+ weight: 80
+ l3_gw_service_uuid:
+ description: UUID for the default L3 gateway service to use with this cluster
+ label: L3 service UUID
+ regex:
+ error: Invalid L3 gateway service UUID
+ source: '[a-f\d]{8}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{12}'
+ type: text
+ value: ''
+ weight: 50
+ metadata:
+ enabled: false
+ label: VMware NSX
+ restrictions:
+ - action: hide
+ condition: cluster:net_provider != 'neutron' or networking_parameters:net_l23_provider
+ != 'nsx'
+ weight: 20
+ nsx_controllers:
+ description: One or more IPv4[:port] addresses of NSX controller node, separated
+ by comma (e.g. 10.30.30.2,192.168.110.254:443)
+ label: NSX controller endpoint
+ regex:
+ error: Invalid controller endpoints, specify valid IPv4[:port] pair
+ source: ^(([\d]|[1-9][\d]|1[\d]{2}|2[0-4][\d]|25[0-5])\.){3}([\d]|[1-9][\d]|1[\d]{2}|2[0-4][\d]|25[0-5])(:(6553[0-5]|655[0-2][\d]|65[0-4][\d]{2}|6[0-4][\d]{3}|5[\d]{4}|[\d][\d]{0,3}))?(,(([\d]|[1-9][\d]|1[\d]{2}|2[0-4][\d]|25[0-5])\.){3}([\d]|[1-9][\d]|1[\d]{2}|2[0-4][\d]|25[0-5])(:(6553[0-5]|655[0-2][\d]|65[0-4][\d]{2}|6[0-4][\d]{3}|5[\d]{4}|[\d][\d]{0,3}))?)*$
+ type: text
+ value: ''
+ weight: 60
+ nsx_password:
+ description: Password for Administrator
+ label: NSX password
+ regex:
+ error: Empty password
+ source: \S
+ type: password
+ value: ''
+ weight: 30
+ nsx_username:
+ description: NSX administrator's username
+ label: NSX username
+ regex:
+ error: Empty username
+ source: \S
+ type: text
+ value: admin
+ weight: 20
+ packages_url:
+ description: URL to NSX specific packages
+ label: URL to NSX bits
+ regex:
+ error: Invalid URL, specify valid HTTP/HTTPS URL with IPv4 address (e.g.
+ http://10.20.0.2/nsx)
+ source: ^https?://(([\d]|[1-9][\d]|1[\d]{2}|2[0-4][\d]|25[0-5])\.){3}([\d]|[1-9][\d]|1[\d]{2}|2[0-4][\d]|25[0-5])(:(6553[0-5]|655[0-2][\d]|65[0-4][\d]{2}|6[0-4][\d]{3}|5[\d]{4}|[\d][\d]{0,3}))?(/.*)?$
+ type: text
+ value: ''
+ weight: 70
+ replication_mode:
+ description: ''
+ label: NSX cluster has Service nodes
+ type: checkbox
+ value: true
+ weight: 90
+ transport_zone_uuid:
+ description: UUID of the pre-existing default NSX Transport zone
+ label: Transport zone UUID
+ regex:
+ error: Invalid transport zone UUID
+ source: '[a-f\d]{8}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{12}'
+ type: text
+ value: ''
+ weight: 40
+ provision:
+ metadata:
+ label: Provision
+ restrictions:
+ - action: hide
+ condition: not ('experimental' in version:feature_groups)
+ weight: 80
+ method:
+ description: Which provision method to use for this cluster.
+ label: Provision method
+ type: radio
+ value: cobbler
+ values:
+ - data: image
+ description: Copying pre-built images on a disk.
+ label: Image
+ - data: cobbler
+ description: Install from scratch using anaconda or debian-installer.
+ label: Classic (use anaconda or debian-installer)
+ public_network_assignment:
+ assign_to_all_nodes:
+ description: When disabled, public network will be assigned to controllers
+ and zabbix-server only
+ label: Assign public network to all nodes
+ type: checkbox
+ value: false
+ weight: 10
+ metadata:
+ label: Public network assignment
+ restrictions:
+ - action: hide
+ condition: cluster:net_provider != 'neutron'
+ weight: 50
+ storage:
+ ephemeral_ceph:
+ description: Configures Nova to store ephemeral volumes in RBD. This works
+ best if Ceph is enabled for volumes and images, too. Enables live migration
+ of all types of Ceph backed VMs (without this option, live migration will
+ only work with VMs launched from Cinder volumes).
+ label: Ceph RBD for ephemeral volumes (Nova)
+ restrictions:
+ - settings:common.libvirt_type.value == 'vcenter'
+ type: checkbox
+ value: false
+ weight: 75
+ images_ceph:
+ description: Configures Glance to use the Ceph RBD backend to store images.
+ If enabled, this option will prevent Swift from installing.
+ label: Ceph RBD for images (Glance)
+ type: checkbox
+ value: false
+ weight: 30
+ images_vcenter:
+ description: Configures Glance to use the vCenter/ESXi backend to store images.
+ If enabled, this option will prevent Swift from installing.
+ label: VMWare vCenter/ESXi datastore for images (Glance)
+ restrictions:
+ - settings:common.libvirt_type.value != 'vcenter'
+ type: checkbox
+ value: false
+ weight: 35
+ iser:
+ description: 'High performance block storage: Cinder volumes over iSER protocol
+ (iSCSI over RDMA). This feature requires SR-IOV capabilities in the NIC,
+ and will use a dedicated virtual function for the storage network.'
+ label: iSER protocol for volumes (Cinder)
+ restrictions:
+ - settings:storage.volumes_lvm.value != true or settings:common.libvirt_type.value
+ != 'kvm'
+ type: checkbox
+ value: false
+ weight: 11
+ metadata:
+ label: Storage
+ weight: 60
+ objects_ceph:
+ description: Configures RadosGW front end for Ceph RBD. This exposes S3 and
+ Swift API Interfaces. If enabled, this option will prevent Swift from installing.
+ label: Ceph RadosGW for objects (Swift API)
+ restrictions:
+ - settings:storage.images_ceph.value == false
+ type: checkbox
+ value: false
+ weight: 80
+ osd_pool_size:
+ description: Configures the default number of object replicas in Ceph. This
+ number must be equal to or lower than the number of deployed 'Storage -
+ Ceph OSD' nodes.
+ label: Ceph object replication factor
+ regex:
+ error: Invalid number
+ source: ^[1-9]\d*$
+ restrictions:
+ - settings:common.libvirt_type.value == 'vcenter'
+ type: text
+ value: '2'
+ weight: 85
+ vc_datacenter:
+ description: Inventory path to a datacenter. If you want to use ESXi host
+ as datastore, it should be "ha-datacenter".
+ label: Datacenter name
+ regex:
+ error: Empty datacenter
+ source: \S
+ restrictions:
+ - action: hide
+ condition: settings:storage.images_vcenter.value == false or settings:common.libvirt_type.value
+ != 'vcenter'
+ type: text
+ value: ''
+ weight: 65
+ vc_datastore:
+ description: Datastore associated with the datacenter.
+ label: Datastore name
+ regex:
+ error: Empty datastore
+ source: \S
+ restrictions:
+ - action: hide
+ condition: settings:storage.images_vcenter.value == false or settings:common.libvirt_type.value
+ != 'vcenter'
+ type: text
+ value: ''
+ weight: 60
+ vc_host:
+ description: IP Address of vCenter/ESXi
+ label: vCenter/ESXi IP
+ regex:
+ error: Specify valid IPv4 address
+ source: ^(([\d]|[1-9][\d]|1[\d]{2}|2[0-4][\d]|25[0-5])\.){3}([\d]|[1-9][\d]|1[\d]{2}|2[0-4][\d]|25[0-5])$
+ restrictions:
+ - action: hide
+ condition: settings:storage.images_vcenter.value == false or settings:common.libvirt_type.value
+ != 'vcenter'
+ type: text
+ value: ''
+ weight: 45
+ vc_image_dir:
+ description: The name of the directory where the glance images will be stored
+ in the VMware datastore.
+ label: Datastore Images directory
+ regex:
+ error: Empty images directory
+ source: \S
+ restrictions:
+ - action: hide
+ condition: settings:storage.images_vcenter.value == false or settings:common.libvirt_type.value
+ != 'vcenter'
+ type: text
+ value: /openstack_glance
+ weight: 70
+ vc_password:
+ description: vCenter/ESXi admin password
+ label: Password
+ regex:
+ error: Empty password
+ source: \S
+ restrictions:
+ - action: hide
+ condition: settings:storage.images_vcenter.value == false or settings:common.libvirt_type.value
+ != 'vcenter'
+ type: password
+ value: ''
+ weight: 55
+ vc_user:
+ description: vCenter/ESXi admin username
+ label: Username
+ regex:
+ error: Empty username
+ source: \S
+ restrictions:
+ - action: hide
+ condition: settings:storage.images_vcenter.value == false or settings:common.libvirt_type.value
+ != 'vcenter'
+ type: text
+ value: ''
+ weight: 50
+ volumes_ceph:
+ description: Configures Cinder to store volumes in Ceph RBD images.
+ label: Ceph RBD for volumes (Cinder)
+ restrictions:
+ - settings:storage.volumes_lvm.value == true or settings:common.libvirt_type.value
+ == 'vcenter'
+ type: checkbox
+ value: false
+ weight: 20
+ volumes_lvm:
+ description: Requires at least one Storage - Cinder LVM node.
+ label: Cinder LVM over iSCSI for volumes
+ restrictions:
+ - settings:storage.volumes_ceph.value == true
+ type: checkbox
+ value: false
+ weight: 10
+ volumes_vmdk:
+ description: Configures Cinder to store volumes via VMware vCenter.
+ label: VMware vCenter for volumes (Cinder)
+ restrictions:
+ - settings:common.libvirt_type.value != 'vcenter' or settings:storage.volumes_lvm.value
+ == true
+ type: checkbox
+ value: false
+ weight: 15
+ syslog:
+ metadata:
+ label: Syslog
+ weight: 50
+ syslog_port:
+ description: Remote syslog port
+ label: Port
+ regex:
+ error: Invalid Syslog port
+ source: ^([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$
+ type: text
+ value: '514'
+ weight: 20
+ syslog_server:
+ description: Remote syslog hostname
+ label: Hostname
+ type: text
+ value: ''
+ weight: 10
+ syslog_transport:
+ label: Syslog transport protocol
+ type: radio
+ value: tcp
+ values:
+ - data: udp
+ description: ''
+ label: UDP
+ - data: tcp
+ description: ''
+ label: TCP
+ weight: 30
+ vcenter:
+ cluster:
+ description: vCenter cluster name. If you have multiple clusters, use comma
+ to separate names
+ label: Cluster
+ regex:
+ error: Invalid cluster list
+ source: ^([^,\ ]+([\ ]*[^,\ ])*)(,[^,\ ]+([\ ]*[^,\ ])*)*$
+ type: text
+ value: ''
+ weight: 40
+ datastore_regex:
+ description: The Datastore regexp setting specifies the data stores to use
+ with Compute. For example, "nas.*". If you want to use all available datastores,
+ leave this field blank
+ label: Datastore regexp
+ regex:
+ error: Invalid datastore regexp
+ source: ^(\S.*\S|\S|)$
+ type: text
+ value: ''
+ weight: 50
+ host_ip:
+ description: IP Address of vCenter
+ label: vCenter IP
+ regex:
+ error: Specify valid IPv4 address
+ source: ^(([\d]|[1-9][\d]|1[\d]{2}|2[0-4][\d]|25[0-5])\.){3}([\d]|[1-9][\d]|1[\d]{2}|2[0-4][\d]|25[0-5])$
+ type: text
+ value: ''
+ weight: 10
+ metadata:
+ label: vCenter
+ restrictions:
+ - action: hide
+ condition: settings:common.libvirt_type.value != 'vcenter'
+ weight: 20
+ use_vcenter:
+ description: ''
+ label: ''
+ type: hidden
+ value: true
+ weight: 5
+ vc_password:
+ description: vCenter admin password
+ label: Password
+ regex:
+ error: Empty password
+ source: \S
+ type: password
+ value: ''
+ weight: 30
+ vc_user:
+ description: vCenter admin username
+ label: Username
+ regex:
+ error: Empty username
+ source: \S
+ type: text
+ value: ''
+ weight: 20
+ vlan_interface:
+ description: Physical ESXi host ethernet adapter for VLAN networking (e.g.
+ vmnic1). If empty "vmnic0" is used by default
+ label: ESXi VLAN interface
+ restrictions:
+ - action: hide
+ condition: cluster:net_provider != 'nova_network' or networking_parameters:net_manager
+ != 'VlanManager'
+ type: text
+ value: ''
+ weight: 60
+ zabbix:
+ metadata:
+ label: Zabbix Access
+ restrictions:
+ - action: hide
+ condition: not ('experimental' in version:feature_groups)
+ weight: 70
+ password:
+ description: Password for Zabbix Administrator
+ label: password
+ type: password
+ value: zabbix
+ weight: 20
+ username:
+ description: Username for Zabbix Administrator
+ label: username
+ type: text
+ value: admin
+ weight: 10
...
diff --git a/fuel/deploy/deploy.py b/fuel/deploy/deploy.py
deleted file mode 100644
index 4037c1d..0000000
--- a/fuel/deploy/deploy.py
+++ /dev/null
@@ -1,212 +0,0 @@
-import time
-import os
-import sys
-
-import common
-from dha import DeploymentHardwareAdapter
-from dea import DeploymentEnvironmentAdapter
-from configure_environment import ConfigureEnvironment
-
-
-SUPPORTED_RELEASE = 'Juno on CentOS 6.5'
-
-N = common.N
-E = common.E
-R = common.R
-RO = common.RO
-exec_cmd = common.exec_cmd
-parse = common.parse
-err = common.err
-
-class Deploy(object):
-
- def __init__(self, yaml_config_dir):
- self.supported_release = None
- self.yaml_config_dir = yaml_config_dir
-
- def get_id_list(self, list):
- return [l[0] for l in list]
-
- def cleanup_fuel_environments(self, env_list):
- WAIT_LOOP = 10
- SLEEP_TIME = 2
- id_list = self.get_id_list(env_list)
- for id in id_list:
- exec_cmd('fuel env --env %s --delete' % id)
- for i in range(WAIT_LOOP):
- if id in self.get_id_list(parse(exec_cmd('fuel env list'))):
- time.sleep(SLEEP_TIME)
- else:
- continue
-
- def cleanup_fuel_nodes(self, node_list):
- for node in node_list:
- if node[N['status']] == 'discover':
- exec_cmd('fuel node --node-id %s --delete-from-db'
- % node[N['id']])
- exec_cmd('dockerctl shell cobbler cobbler system remove '
- '--name node-%s' % node[N['id']])
-
- def check_previous_installation(self):
- env_list = parse(exec_cmd('fuel env list'))
- if env_list:
- self.cleanup_fuel_environments(env_list)
- node_list = parse(exec_cmd('fuel node list'))
- if node_list:
- self.cleanup_fuel_nodes(node_list)
-
- def check_supported_release(self):
- release_list= parse(exec_cmd('fuel release -l'))
- for release in release_list:
- if release[R['name']] == SUPPORTED_RELEASE:
- self.supported_release = release
- break
- if not self.supported_release:
- err("This Fuel doesn't contain the following "
- "release: %s\n" % SUPPORTED_RELEASE)
-
- def check_role_definitions(self):
- role_list= parse(exec_cmd('fuel role --release %s'
- % self.supported_release[R['id']]))
- roles = [role[RO['name']] for role in role_list]
- if 'compute' not in roles:
- err("Role compute does not exist in release %"
- % self.supported_release[R['name']])
- if 'controller' not in roles:
- err("Role controller does not exist in release %"
- % self.supported_release[R['name']])
-
- def check_prerequisites(self):
- self.check_supported_release()
- self.check_role_definitions()
- self.check_previous_installation()
-
- def power_off_blades(self, dha, shelf_blades_dict):
- for shelf, blade_list in shelf_blades_dict.iteritems():
- dha.power_off_blades(shelf, blade_list)
-
- def power_on_blades(self, dha, shelf_blades_dict):
- for shelf, blade_list in shelf_blades_dict.iteritems():
- dha.power_on_blades(shelf, blade_list)
-
- def set_boot_order(self, dha, shelf_blades_dict):
- for shelf, blade_list in shelf_blades_dict.iteritems():
- dha.set_boot_order_blades(shelf, blade_list)
-
- def count_discovered_nodes(self, node_list):
- discovered_nodes = 0
- for node in node_list:
- if node[N['status']] == 'discover':
- discovered_nodes += 1
- return discovered_nodes
-
- def wait_for_discovered_blades(self, no_of_blades):
- WAIT_LOOP = 10
- SLEEP_TIME = 2
- all_discovered = False
- node_list = parse(exec_cmd('fuel node list'))
- for i in range(WAIT_LOOP):
- if (self.count_discovered_nodes(node_list) < no_of_blades):
- time.sleep(SLEEP_TIME)
- node_list = parse(exec_cmd('fuel node list'))
- else:
- all_discovered = True
- break
- if not all_discovered:
- err("There are %s blades defined, but not all of "
- "them have been discovered\n" % no_of_blades)
-
- def assign_cluster_node_ids(self, dha, dea, controllers, compute_hosts):
- node_list= parse(exec_cmd('fuel node list'))
- for shelf_id in dea.get_shelf_ids():
- for blade_id in dea.get_blade_ids_per_shelf(shelf_id):
- blade_mac_list = dha.get_blade_mac_addresses(
- shelf_id, blade_id)
-
- found = False
- for node in node_list:
- if (node[N['mac']] in blade_mac_list and
- node[N['status']] == 'discover'):
- found = True
- break
- if found:
- if dea.is_controller(shelf_id, blade_id):
- controllers.append(node[N['id']])
- if dea.is_compute_host(shelf_id, blade_id):
- compute_hosts.append(node[N['id']])
- else:
- err("Could not find the Node ID for blade "
- "with MACs %s or blade is not in "
- "discover status\n" % blade_mac_list)
-
-
- def configure_environment(self, dea):
- config_env = ConfigureEnvironment(dea, self.yaml_config_dir)
-
-
-
- def provision(self):
-
-
-
- def fix_power_address(self):
-
-
-
-
- def deploy(self):
-
- if id in self.get_id_list(parse(exec_cmd('fuel env list'))):
-
- self.fix_power_address()
-
-
-
-
-def main():
-
- yaml_path = exec_cmd('pwd').strip() + '/dea.yaml'
- yaml_config_dir = '/var/lib/opnfv/pre_deploy'
-
- deploy = Deploy(yaml_config_dir)
-
- dea = DeploymentEnvironmentAdapter()
-
- if not os.path.isfile(yaml_path):
- sys.stderr.write("ERROR: File %s not found\n" % yaml_path)
- sys.exit(1)
-
- dea.parse_yaml(yaml_path)
-
- server_type, mgmt_ip, username, password = dea.get_server_info()
- shelf_blades_dict = dea.get_blade_ids_per_shelves()
-
- dha = DeploymentHardwareAdapter(server_type, mgmt_ip, username, password)
-
- deploy.check_prerequisites()
-
- deploy.power_off_blades(dha, shelf_blades_dict)
-
- deploy.set_boot_order(dha, shelf_blades_dict)
-
- deploy.power_on_blades(dha, shelf_blades_dict)
-
- macs = dha.get_blade_mac_addresses()
-
- deploy.wait_for_discovered_blades(dea.get_no_of_blades())
-
-
- controllers = []
- compute_hosts = []
- deploy.assign_cluster_node_ids(dha, dea, controllers, compute_hosts)
-
-
-
- deploy.configure_environment(dea)
-
- deploy.deploy(dea)
-
-
-
-if __name__ == '__main__':
- main() \ No newline at end of file
diff --git a/fuel/deploy/deploy.sh b/fuel/deploy/deploy.sh
new file mode 100755
index 0000000..916125e
--- /dev/null
+++ b/fuel/deploy/deploy.sh
@@ -0,0 +1,107 @@
+#!/bin/bash
+##############################################################################
+# Copyright (c) 2015 Ericsson AB and others.
+# stefan.k.berg@ericsson.com
+# jonas.bjurel@ericsson.com
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+# Setup locations
+topdir=$(cd `dirname $0`; pwd)
+functions=${topdir}/functions
+tmpdir=$HOME/fueltmp
+deployiso=${tmpdir}/deploy.iso
+cloud_deploy=$(cd ${topdir}/cloud_deploy; pwd)
+
+# Define common functions
+. ${functions}/common.sh
+
+exit_handler() {
+ # Remove safety catch
+ kill -9 `ps -p $killpid -o pid --no-headers` \
+ `ps --ppid $killpid -o pid --no-headers`\
+ > /dev/null 2>&1
+}
+
+# Set maximum allowed deploy time (default three hours)
+MAXDEPLOYTIME=${MAXDEPLOYTIME-3h}
+
+####### MAIN ########
+
+if [ "`whoami`" != "root" ]; then
+ error_exit "You need be root to run this script"
+fi
+
+if [ $# -eq 0 -o $# -gt 2 ]; then
+ error_exit "Argument error"
+fi
+
+# Setup tmpdir
+if [ -d $tmpdir ]; then
+ rm -Rf $tmpdir || error_exit "Could not remove tmpdir $tmpdir"
+fi
+
+mkdir $tmpdir || error_exit "Could not create tmpdir $tmpdir"
+
+if [ ! -f $1 ]; then
+ error_exit "Could not find ISO file $1"
+else
+ isofile=$(cd `dirname $1`; echo `pwd`/`basename $1`)
+fi
+
+# If no DEA specified, use the example one
+if [ $# -eq 1 ]; then
+ deafile=${topdir}/dea.yaml
+else
+ deafile=$(cd `dirname $2`; echo `pwd`/`basename $2`)
+fi
+cp ${deafile} ${cloud_deploy}/
+
+if [ ! -f $deafile ]; then
+ error-exit "Could not find DEA file $deafile"
+fi
+
+# Enable safety catch
+echo "Enabling auto-kill if deployment exceeds $MAXDEPLOYTIME"
+(sleep $MAXDEPLOYTIME; echo "Auto-kill of deploy after a timeout of $MAXDEPLOYTIME"; kill $$) &
+killpid=$!
+
+# Enable exit handler
+trap exit_handler exit
+
+# Stop all VMs
+for node in `ls libvirt/vms`
+do
+ virsh destroy $node >/dev/null 2>&1
+done
+
+
+# Install the Fuel master
+# (Convert to functions at later stage)
+echo "Patching iso file"
+${functions}/patch-iso.sh $isofile $deployiso $tmpdir || error_exit "Failed to patch ISO"
+# Swap isofiles from now on
+isofile=$deployiso
+. ${functions}/install_iso.sh
+
+python ${cloud_deploy}/cloud_deploy.py
+
+echo "Waiting for five minutes for deploy to stabilize"
+sleep 5m
+
+echo "Verifying node status after deployment"
+# Any node with non-ready status?
+ssh root@10.20.0.2 fuel node 2>/dev/null | tail -n +3 | cut -d "|" -f 2 | \
+ sed 's/ //g' | grep -v ready | wc -l | grep -q "^0$"
+if [ $? -ne 0 ]; then
+ echo "Deploy failed to verify"
+ ssh root@10.20.0.2 fuel node 2>/dev/null
+ error_exit "Exiting with error status"
+else
+ ssh root@10.20.0.2 fuel node 2>/dev/null
+ echo "Deployment verified"
+fi
+
diff --git a/fuel/deploy/deploy_fuel.sh b/fuel/deploy/deploy_fuel.sh
deleted file mode 100755
index 8cb72b7..0000000
--- a/fuel/deploy/deploy_fuel.sh
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/bin/bash
-# Deploy in deployFuel has the "configure host-network,
-# install fuel, configure vm and start it" meaning
-set -o xtrace
-set -o errexit
-set -o nounset
-set -o pipefail
-
-if [ $# -ne 2 ]; then
- echo "Usage: $0 <iso-file> <interface>"
- exit 1
-fi
-
-readonly iso_file=$1
-readonly interface=$2
-readonly vm_name="fuel_opnfv"
-readonly ssh_fuel_vm="sshpass -p r00tme
- ssh -o UserKnownHostsFile=/dev/null
- -o StrictHostKeyChecking=no
- -q
- root@192.168.0.11"
-readonly RUN_INSTALL="${RUN_INSTALL:-false}"
-readonly DEV="${DEV:-false}"
-
-# poll is not real timeout, commands can take some undefined time to execute
-# it is a count of how many times to try while sleeping shortly
-# in between checks
-readonly poll_virtinstall=1800
-readonly poll_fuel_startup=1200
-readonly poll_deployment=2150
-readonly fuel_logfile="/var/log/puppet/bootstrap_admin_node.log"
-
-cat >$interface.xml <<EOF
-<network>
- <name>$interface</name>
- <forward dev='$interface' mode='bridge'>
- <interface dev='$interface'/>
- </forward>
-</network>
-EOF
-
-cleanup_previous_run() {
- echo "Cleaning up previous run"
- set +eu
- virsh net-destroy $interface > /dev/null 2>&1
- virsh net-undefine $interface > /dev/null 2>&1
- virsh destroy $vm_name > /dev/null 2>&1
- virsh undefine $vm_name > /dev/null 2>&1
- set -eu
-}
-
-create_disk_and_install() {
- rm -rf $vm_name.qcow2
- qemu-img create -f qcow2 -o preallocation=metadata $vm_name.qcow2 60G
- virt-install --connect=qemu:///system \
- --name=$vm_name \
- --network=network:$interface \
- --ram 2048 --vcpus=4,cores=2 --check-cpu --hvm \
- --disk path=$vm_name.qcow2,format=qcow2,device=disk,bus=virtio \
- --noautoconsole --vnc \
- --cdrom $iso_file
-}
-
-wait_for_virtinstall() {
- # Workaround for virt-install --wait which restarts vm
- # too fast too attach disk
- echo "Waiting for virt-install to finish..."
- set +eu
- stopped=false
- for i in $(seq 0 $poll_virtinstall); do
- virsh_out=`virsh list | grep "$vm_name"`
- if [ -z "$virsh_out" ]; then
- stopped=true
- break
- fi
- sleep 2
- done
- set -eu
-}
-
-wait_for_fuel_startup() {
- echo "Wait for fuel to start up..."
- for i in $(seq 0 $poll_fuel_startup); do
- sleep 2 && echo -n "$i "
- $ssh_fuel_vm grep complete $fuel_logfile &&
- echo "Fuel bootstrap is done, deployment should have started now" &&
- return 0
- done
- return 1
-}
-
-
-cleanup_previous_run
-virsh net-define $interface.xml
-virsh net-start $interface
-create_disk_and_install
-wait_for_virtinstall
-
-echo "Starting $vm_name after installation in 6s..." && sleep 6s
-set +eu
-
-virsh start $vm_name
-if ! wait_for_fuel_startup; then
- echo "Fuel failed to start up"
- exit 1
-fi
diff --git a/fuel/deploy/functions/common.sh b/fuel/deploy/functions/common.sh
new file mode 100755
index 0000000..f6cceb4
--- /dev/null
+++ b/fuel/deploy/functions/common.sh
@@ -0,0 +1,109 @@
+##############################################################################
+# Copyright (c) 2015 Ericsson AB and others.
+# stefan.k.berg@ericsson.com
+# jonas.bjurel@ericsson.com
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+# Common functions
+
+error_exit () {
+ echo "Error: $@" >&2
+ exit 1
+}
+
+ssh() {
+ SSHPASS="r00tme" sshpass -e ssh -o UserKnownHostsFile=/dev/null \
+ -o StrictHostKeyChecking=no -o ConnectTimeout=15 "$@"
+}
+
+scp() {
+ SSHPASS="r00tme" sshpass -e scp -o UserKnownHostsFile=/dev/null \
+ -o StrictHostKeyChecking=no -o ConnectTimeout=15 "$@"
+}
+
+noNodesUp () {
+ fuel node | grep True | wc -l
+}
+
+fuel () {
+ ssh root@10.20.0.2 "fuel $@"
+}
+
+# Return MAC id for virsh node
+getNodeId() {
+ virsh dumpxml $1 | grep "mac address" | head -1 | sed "s/.*'..:..:..:..:\(.*\)'.*/\1/"
+}
+
+# Wait for node with virtid name to come up
+waitForHost() {
+ mac=`getNodeId $1`
+
+ while true
+ do
+ fuel node --node-id $mac 2>/dev/null | grep -q True && break
+ sleep 3
+ echo -n "."
+ done
+ echo -e "\n"
+}
+
+# Currently not used!
+# Wait for node count to increase
+waitForNode() {
+ local cnt
+ local initCnt
+ local expectCnt
+
+ initCnt=`noNodesUp`
+ expectCnt=$[initCnt+1]
+ while true
+ do
+ cnt=`noNodesUp`
+ if [ $cnt -eq $expectCnt ]; then
+ break
+ elif [ $cnt -lt $initCnt ]; then
+ error_exit "Node count decreased while waiting, $initCnt -> $cnt"
+ elif [ $cnt -gt $expectCnt ]; then
+ error_exit "Node count exceeded expect count, $cnt > $expectCnt"
+ fi
+ sleep 3
+ echo -n "."
+ done
+ echo -e "\n"
+}
+
+bootorder_dvdhd() {
+ virsh dumpxml $1 | grep -v "<boot.*>" | \
+ sed "/<\/os>/i\
+ <boot dev='cdrom'/\>\n\
+ <boot dev='hd'/\>\n\
+ <bootmenu enable='no'/\>" > $tmpdir/vm.xml || error_exit "Could not set bootorder"
+ virsh define $tmpdir/vm.xml || error_exit "Could not set bootorder"
+}
+
+bootorder_hddvd() {
+ virsh dumpxml $1 | grep -v "<boot.*>" | \
+ sed "/<\/os>/i\
+ <boot dev='hd'/\>\n\
+ <boot dev='cdrom'/\>\n\
+ <bootmenu enable='no'/\>" > $tmpdir/vm.xml || error_exit "Could not set bootorder"
+ virsh define $tmpdir/vm.xml || error_exit "Could not set bootorder"
+}
+
+addisofile() {
+ virsh dumpxml $1 | grep -v '\.iso' | sed "s/<.*device='cdrom'.*/<disk type='file' device='cdrom'>/" | \
+ sed "/<.*device='cdrom'.*/a <source file='$2'/>" > $tmpdir/vm.xml \
+ || error_exit "Could not add isofile"
+ virsh define $tmpdir/vm.xml || error_exit "Could not add isofile"
+}
+
+removeisofile() {
+ virsh dumpxml $1 | grep -v '\.iso' | sed "s/<.*device='cdrom'.*/<disk type='block' device='cdrom'>/" \
+ > $tmpdir/vm.xml \
+ || error_exit "Could not remove isofile"
+ virsh define $tmpdir/vm.xml || error_exit "Could not remove isofile"
+}
diff --git a/fuel/deploy/functions/install_iso.sh b/fuel/deploy/functions/install_iso.sh
new file mode 100755
index 0000000..0a92cd5
--- /dev/null
+++ b/fuel/deploy/functions/install_iso.sh
@@ -0,0 +1,62 @@
+##############################################################################
+# Copyright (c) 2015 Ericsson AB and others.
+# stefan.k.berg@ericsson.com
+# jonas.bjurel@ericsson.com
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+# Recreate disk - needed for the reboot to work
+fueldisk=`virsh dumpxml fuel-master | \
+ grep fuel-master.raw | sed "s/.*'\(.*\)'.*/\1/"`
+disksize=`ls -l $fueldisk | awk '{ print $5 }'`
+rm -f $fueldisk
+fallocate -l $disksize $fueldisk
+
+bootorder_hddvd fuel-master
+sleep 3
+addisofile fuel-master $isofile
+sleep 3
+virsh start fuel-master
+
+# wait for node up
+echo "Waiting for Fuel master to accept SSH"
+while true
+do
+ ssh root@10.20.0.2 date 2>/dev/null
+ if [ $? -eq 0 ]; then
+ break
+ fi
+ sleep 10
+done
+
+# Wait until fuelmenu is up
+echo "Waiting for fuelmenu to come up"
+menuPid=""
+while [ -z "$menuPid" ]
+do
+ menuPid=`ssh root@10.20.0.2 "ps -ef" 2>&1 | grep fuelmenu | grep -v grep | awk '{ print $2 }'`
+ sleep 10
+done
+
+# This is where we would inject our own astute.yaml
+
+echo "Found menu as PID $menuPid, now killing it"
+ssh root@10.20.0.2 "kill $menuPid" 2>/dev/null
+
+# Wait until installation complete
+echo "Waiting for bootstrap of Fuel node to complete"
+while true
+do
+ ssh root@10.20.0.2 "ps -ef" 2>/dev/null \
+ | grep -q /usr/local/sbin/bootstrap_admin_node
+ if [ $? -ne 0 ]; then
+ break
+ fi
+ sleep 10
+done
+
+echo "Waiting two minutes for Fuel to stabilize"
+sleep 2m
diff --git a/fuel/deploy/functions/isolinux.cfg.patch b/fuel/deploy/functions/isolinux.cfg.patch
new file mode 100644
index 0000000..298a057
--- /dev/null
+++ b/fuel/deploy/functions/isolinux.cfg.patch
@@ -0,0 +1,14 @@
+*** isolinux/isolinux.cfg.orig 2015-04-15 08:29:52.026868322 -0400
+--- isolinux/isolinux.cfg 2015-04-15 08:30:34.350868343 -0400
+***************
+*** 19,22 ****
+ menu label Fuel Install (^Static IP)
+ menu default
+ kernel vmlinuz
+! append initrd=initrd.img biosdevname=0 ks=cdrom:/ks.cfg ip=10.20.0.2 gw=10.20.0.1 dns1=10.20.0.1 netmask=255.255.255.0 hostname=fuel.domain.tld showmenu=no
+--- 19,22 ----
+ menu label Fuel Install (^Static IP)
+ menu default
+ kernel vmlinuz
+! append initrd=initrd.img biosdevname=0 ks=cdrom:/ks.cfg ip=10.20.0.2 gw=10.20.0.1 dns1=10.20.0.1 netmask=255.255.255.0 hostname=fuel.domain.tld showmenu=yes
+
diff --git a/fuel/deploy/functions/ks.cfg.patch b/fuel/deploy/functions/ks.cfg.patch
new file mode 100644
index 0000000..1896957
--- /dev/null
+++ b/fuel/deploy/functions/ks.cfg.patch
@@ -0,0 +1,19 @@
+*** ks.cfg.orig Wed Apr 15 21:47:09 2015
+--- ks.cfg Wed Apr 15 21:47:24 2015
+***************
+*** 35,41 ****
+ default_drive=`echo ${drives} ${removable_drives} | awk '{print $1}'`
+
+ installdrive="undefined"
+! forceformat="no"
+ for I in `cat /proc/cmdline`; do case "$I" in *=*) eval $I;; esac ; done
+
+ set ${drives} ${removable_drives}
+--- 35,41 ----
+ default_drive=`echo ${drives} ${removable_drives} | awk '{print $1}'`
+
+ installdrive="undefined"
+! forceformat="yes"
+ for I in `cat /proc/cmdline`; do case "$I" in *=*) eval $I;; esac ; done
+
+ set ${drives} ${removable_drives}
diff --git a/fuel/deploy/functions/patch-iso.sh b/fuel/deploy/functions/patch-iso.sh
new file mode 100755
index 0000000..782737e
--- /dev/null
+++ b/fuel/deploy/functions/patch-iso.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+##############################################################################
+# Copyright (c) 2015 Ericsson AB and others.
+# stefan.k.berg@ericsson.com
+# jonas.bjurel@ericsson.com
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+# This is a temporary script - this should be rolled into a separate
+# build target "make ci-iso" instead!
+
+exit_handler() {
+ rm -Rf $tmpnewdir
+ fusermount -u $tmporigdir 2>/dev/null
+ test -d $tmporigdir && mdir $tmporigdir
+}
+
+trap exit_handler exit
+
+error_exit() {
+ echo "$@"
+ exit 1
+}
+
+
+top=$(cd `dirname $0`; pwd)
+origiso=$(cd `dirname $1`; echo `pwd`/`basename $1`)
+newiso=$(cd `dirname $2`; echo `pwd`/`basename $2`)
+tmpdir=$3
+tmporigdir=/${tmpdir}/origiso
+tmpnewdir=/${tmpdir}/newiso
+
+test -f $origiso || error_exit "Could not find origiso $origiso"
+test -d $tmpdir || error_exit "Could not find tmpdir $tmpdir"
+
+
+if [ "`whoami`" != "root" ]; then
+ error_exit "You need be root to run this script"
+fi
+
+echo "Copying..."
+rm -Rf $tmporigdir $tmpnewdir
+mkdir -p $tmporigdir $tmpnewdir
+fuseiso $origiso $tmporigdir || error_exit "Failed fuseiso"
+cd $tmporigdir
+find . | cpio -pd $tmpnewdir
+cd $tmpnewdir
+fusermount -u $tmporigdir
+rmdir $tmporigdir
+chmod -R 755 $tmpnewdir
+
+echo "Patching..."
+cd $tmpnewdir
+# Patch ISO to make it suitable for automatic deployment
+cat $top/ks.cfg.patch | patch -p0 || error_exit "Failed patch 1"
+cat $top/isolinux.cfg.patch | patch -p0 || error_exit "Failed patch 2"
+rm -rf .rr_moved
+
+echo "Creating iso $newiso"
+mkisofs -quiet -r \
+ -J -R -b isolinux/isolinux.bin \
+ -no-emul-boot \
+ -boot-load-size 4 -boot-info-table \
+ --hide-rr-moved \
+ -x "lost+found" -o $newiso . || error_exit "Failed making iso"
+
diff --git a/fuel/deploy/libvirt/networks/fuel1 b/fuel/deploy/libvirt/networks/fuel1
new file mode 100644
index 0000000..7b2b154
--- /dev/null
+++ b/fuel/deploy/libvirt/networks/fuel1
@@ -0,0 +1,12 @@
+<network>
+ <name>fuel1</name>
+ <forward mode='nat'>
+ <nat>
+ <port start='1024' end='65535'/>
+ </nat>
+ </forward>
+ <bridge name='fuel1' stp='on' delay='0'/>
+ <ip address='10.20.0.1' netmask='255.255.255.0'>
+ </ip>
+</network>
+
diff --git a/fuel/deploy/libvirt/networks/fuel2 b/fuel/deploy/libvirt/networks/fuel2
new file mode 100644
index 0000000..615c920
--- /dev/null
+++ b/fuel/deploy/libvirt/networks/fuel2
@@ -0,0 +1,5 @@
+<network>
+ <name>fuel2</name>
+ <bridge name='fuel2' stp='on' delay='0'/>
+</network>
+
diff --git a/fuel/deploy/libvirt/networks/fuel3 b/fuel/deploy/libvirt/networks/fuel3
new file mode 100644
index 0000000..2383e6c
--- /dev/null
+++ b/fuel/deploy/libvirt/networks/fuel3
@@ -0,0 +1,5 @@
+<network>
+ <name>fuel3</name>
+ <bridge name='fuel3' stp='on' delay='0'/>
+</network>
+
diff --git a/fuel/deploy/libvirt/networks/fuel4 b/fuel/deploy/libvirt/networks/fuel4
new file mode 100644
index 0000000..5b69f91
--- /dev/null
+++ b/fuel/deploy/libvirt/networks/fuel4
@@ -0,0 +1,12 @@
+<network>
+ <name>fuel4</name>
+ <forward mode='nat'>
+ <nat>
+ <port start='1024' end='65535'/>
+ </nat>
+ </forward>
+ <bridge name='fuel4' stp='on' delay='0'/>
+ <ip address='172.16.0.1' netmask='255.255.255.0'>
+ </ip>
+</network>
+
diff --git a/fuel/deploy/libvirt/vms/fuel-master b/fuel/deploy/libvirt/vms/fuel-master
new file mode 100644
index 0000000..1b2d86f
--- /dev/null
+++ b/fuel/deploy/libvirt/vms/fuel-master
@@ -0,0 +1,95 @@
+<domain type='kvm'>
+ <name>fuel-master</name>
+ <memory unit='KiB'>2097152</memory>
+ <currentMemory unit='KiB'>2097152</currentMemory>
+ <vcpu placement='static'>2</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc-1.0'>hvm</type>
+ <boot dev='hd'/>
+ <boot dev='cdrom'/>
+ <bootmenu enable='yes'/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <pae/>
+ </features>
+ <cpu mode='custom' match='exact'>
+ <model fallback='allow'>SandyBridge</model>
+ <vendor>Intel</vendor>
+ <feature policy='require' name='vme'/>
+ <feature policy='require' name='dtes64'/>
+ <feature policy='require' name='vmx'/>
+ <feature policy='require' name='erms'/>
+ <feature policy='require' name='xtpr'/>
+ <feature policy='require' name='smep'/>
+ <feature policy='require' name='pcid'/>
+ <feature policy='require' name='est'/>
+ <feature policy='require' name='monitor'/>
+ <feature policy='require' name='smx'/>
+ <feature policy='require' name='tm'/>
+ <feature policy='require' name='acpi'/>
+ <feature policy='require' name='osxsave'/>
+ <feature policy='require' name='ht'/>
+ <feature policy='require' name='pdcm'/>
+ <feature policy='require' name='fsgsbase'/>
+ <feature policy='require' name='f16c'/>
+ <feature policy='require' name='ds'/>
+ <feature policy='require' name='tm2'/>
+ <feature policy='require' name='ss'/>
+ <feature policy='require' name='pbe'/>
+ <feature policy='require' name='ds_cpl'/>
+ <feature policy='require' name='rdrand'/>
+ </cpu>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <emulator>/usr/bin/kvm</emulator>
+ <disk type='file' device='cdrom'>
+ <driver name='qemu' type='raw'/>
+ <target dev='hdc' bus='ide'/>
+ <readonly/>
+ <address type='drive' controller='0' bus='1' target='0' unit='0'/>
+ </disk>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <source file='disk.raw'/>
+ <target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
+ </disk>
+ <controller type='ide' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+ </controller>
+ <controller type='usb' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'/>
+ <interface type='network'>
+ <source network='fuel1'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </interface>
+ <serial type='pty'>
+ <target port='0'/>
+ </serial>
+ <console type='pty'>
+ <target type='serial' port='0'/>
+ </console>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <graphics type='vnc' port='-1' autoport='yes' keymap='sv'/>
+ <sound model='ich6'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+ </sound>
+ <video>
+ <model type='cirrus' vram='9216' heads='1'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </video>
+ <memballoon model='virtio'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
+ </memballoon>
+ </devices>
+</domain>
+
diff --git a/fuel/deploy/libvirt/vms/s1_b1 b/fuel/deploy/libvirt/vms/s1_b1
new file mode 100644
index 0000000..a879163
--- /dev/null
+++ b/fuel/deploy/libvirt/vms/s1_b1
@@ -0,0 +1,100 @@
+<domain type='kvm'>
+ <name>s1_b1</name>
+ <memory unit='KiB'>2097152</memory>
+ <currentMemory unit='KiB'>2097152</currentMemory>
+ <vcpu placement='static'>2</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc-1.0'>hvm</type>
+ <boot dev='network'/>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <pae/>
+ </features>
+ <cpu mode='custom' match='exact'>
+ <model fallback='allow'>SandyBridge</model>
+ <vendor>Intel</vendor>
+ <feature policy='require' name='vme'/>
+ <feature policy='require' name='dtes64'/>
+ <feature policy='require' name='vmx'/>
+ <feature policy='require' name='erms'/>
+ <feature policy='require' name='xtpr'/>
+ <feature policy='require' name='smep'/>
+ <feature policy='require' name='pcid'/>
+ <feature policy='require' name='est'/>
+ <feature policy='require' name='monitor'/>
+ <feature policy='require' name='smx'/>
+ <feature policy='require' name='tm'/>
+ <feature policy='require' name='acpi'/>
+ <feature policy='require' name='osxsave'/>
+ <feature policy='require' name='ht'/>
+ <feature policy='require' name='pdcm'/>
+ <feature policy='require' name='fsgsbase'/>
+ <feature policy='require' name='f16c'/>
+ <feature policy='require' name='ds'/>
+ <feature policy='require' name='tm2'/>
+ <feature policy='require' name='ss'/>
+ <feature policy='require' name='pbe'/>
+ <feature policy='require' name='ds_cpl'/>
+ <feature policy='require' name='rdrand'/>
+ </cpu>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <emulator>/usr/bin/kvm</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <source file='disk.raw'/>
+ <target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
+ </disk>
+ <controller type='usb' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'/>
+ <interface type='network'>
+ <source network='fuel1'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel2'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel3'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel4'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>
+ </interface>
+ <serial type='pty'>
+ <target port='0'/>
+ </serial>
+ <console type='pty'>
+ <target type='serial' port='0'/>
+ </console>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <graphics type='vnc' port='-1' autoport='yes' keymap='sv'/>
+ <sound model='ich6'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+ </sound>
+ <video>
+ <model type='cirrus' vram='9216' heads='1'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </video>
+ <memballoon model='virtio'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
+ </memballoon>
+ </devices>
+</domain>
+
diff --git a/fuel/deploy/libvirt/vms/s1_b2 b/fuel/deploy/libvirt/vms/s1_b2
new file mode 100644
index 0000000..27eebcf
--- /dev/null
+++ b/fuel/deploy/libvirt/vms/s1_b2
@@ -0,0 +1,100 @@
+<domain type='kvm'>
+ <name>s1_b2</name>
+ <memory unit='KiB'>2097152</memory>
+ <currentMemory unit='KiB'>2097152</currentMemory>
+ <vcpu placement='static'>2</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc-1.0'>hvm</type>
+ <boot dev='network'/>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <pae/>
+ </features>
+ <cpu mode='custom' match='exact'>
+ <model fallback='allow'>SandyBridge</model>
+ <vendor>Intel</vendor>
+ <feature policy='require' name='vme'/>
+ <feature policy='require' name='dtes64'/>
+ <feature policy='require' name='vmx'/>
+ <feature policy='require' name='erms'/>
+ <feature policy='require' name='xtpr'/>
+ <feature policy='require' name='smep'/>
+ <feature policy='require' name='pcid'/>
+ <feature policy='require' name='est'/>
+ <feature policy='require' name='monitor'/>
+ <feature policy='require' name='smx'/>
+ <feature policy='require' name='tm'/>
+ <feature policy='require' name='acpi'/>
+ <feature policy='require' name='osxsave'/>
+ <feature policy='require' name='ht'/>
+ <feature policy='require' name='pdcm'/>
+ <feature policy='require' name='fsgsbase'/>
+ <feature policy='require' name='f16c'/>
+ <feature policy='require' name='ds'/>
+ <feature policy='require' name='tm2'/>
+ <feature policy='require' name='ss'/>
+ <feature policy='require' name='pbe'/>
+ <feature policy='require' name='ds_cpl'/>
+ <feature policy='require' name='rdrand'/>
+ </cpu>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <emulator>/usr/bin/kvm</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <source file='disk.raw'/>
+ <target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
+ </disk>
+ <controller type='usb' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'/>
+ <interface type='network'>
+ <source network='fuel1'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel2'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel3'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel4'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>
+ </interface>
+ <serial type='pty'>
+ <target port='0'/>
+ </serial>
+ <console type='pty'>
+ <target type='serial' port='0'/>
+ </console>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <graphics type='vnc' port='-1' autoport='yes' keymap='sv'/>
+ <sound model='ich6'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+ </sound>
+ <video>
+ <model type='cirrus' vram='9216' heads='1'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </video>
+ <memballoon model='virtio'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
+ </memballoon>
+ </devices>
+</domain>
+
diff --git a/fuel/deploy/libvirt/vms/s1_b3 b/fuel/deploy/libvirt/vms/s1_b3
new file mode 100644
index 0000000..37a4d2f
--- /dev/null
+++ b/fuel/deploy/libvirt/vms/s1_b3
@@ -0,0 +1,100 @@
+<domain type='kvm'>
+ <name>s1_b3</name>
+ <memory unit='KiB'>2097152</memory>
+ <currentMemory unit='KiB'>2097152</currentMemory>
+ <vcpu placement='static'>2</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc-1.0'>hvm</type>
+ <boot dev='network'/>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <pae/>
+ </features>
+ <cpu mode='custom' match='exact'>
+ <model fallback='allow'>SandyBridge</model>
+ <vendor>Intel</vendor>
+ <feature policy='require' name='vme'/>
+ <feature policy='require' name='dtes64'/>
+ <feature policy='require' name='vmx'/>
+ <feature policy='require' name='erms'/>
+ <feature policy='require' name='xtpr'/>
+ <feature policy='require' name='smep'/>
+ <feature policy='require' name='pcid'/>
+ <feature policy='require' name='est'/>
+ <feature policy='require' name='monitor'/>
+ <feature policy='require' name='smx'/>
+ <feature policy='require' name='tm'/>
+ <feature policy='require' name='acpi'/>
+ <feature policy='require' name='osxsave'/>
+ <feature policy='require' name='ht'/>
+ <feature policy='require' name='pdcm'/>
+ <feature policy='require' name='fsgsbase'/>
+ <feature policy='require' name='f16c'/>
+ <feature policy='require' name='ds'/>
+ <feature policy='require' name='tm2'/>
+ <feature policy='require' name='ss'/>
+ <feature policy='require' name='pbe'/>
+ <feature policy='require' name='ds_cpl'/>
+ <feature policy='require' name='rdrand'/>
+ </cpu>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <emulator>/usr/bin/kvm</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <source file='disk.raw'/>
+ <target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
+ </disk>
+ <controller type='usb' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'/>
+ <interface type='network'>
+ <source network='fuel1'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel2'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel3'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel4'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>
+ </interface>
+ <serial type='pty'>
+ <target port='0'/>
+ </serial>
+ <console type='pty'>
+ <target type='serial' port='0'/>
+ </console>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <graphics type='vnc' port='-1' autoport='yes' keymap='sv'/>
+ <sound model='ich6'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+ </sound>
+ <video>
+ <model type='cirrus' vram='9216' heads='1'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </video>
+ <memballoon model='virtio'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
+ </memballoon>
+ </devices>
+</domain>
+
diff --git a/fuel/deploy/libvirt/vms/s1_b4 b/fuel/deploy/libvirt/vms/s1_b4
new file mode 100644
index 0000000..97384ba
--- /dev/null
+++ b/fuel/deploy/libvirt/vms/s1_b4
@@ -0,0 +1,101 @@
+<domain type='kvm'>
+ <name>s1_b4</name>
+ <memory unit='KiB'>8388608</memory>
+ <currentMemory unit='KiB'>8388608</currentMemory>
+ <vcpu placement='static'>2</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc-1.0'>hvm</type>
+ <boot dev='network'/>
+ <boot dev='hd'/>
+ <bootmenu enable='yes'/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <pae/>
+ </features>
+ <cpu mode='custom' match='exact'>
+ <model fallback='allow'>SandyBridge</model>
+ <vendor>Intel</vendor>
+ <feature policy='require' name='vme'/>
+ <feature policy='require' name='dtes64'/>
+ <feature policy='require' name='vmx'/>
+ <feature policy='require' name='erms'/>
+ <feature policy='require' name='xtpr'/>
+ <feature policy='require' name='smep'/>
+ <feature policy='require' name='pcid'/>
+ <feature policy='require' name='est'/>
+ <feature policy='require' name='monitor'/>
+ <feature policy='require' name='smx'/>
+ <feature policy='require' name='tm'/>
+ <feature policy='require' name='acpi'/>
+ <feature policy='require' name='osxsave'/>
+ <feature policy='require' name='ht'/>
+ <feature policy='require' name='pdcm'/>
+ <feature policy='require' name='fsgsbase'/>
+ <feature policy='require' name='f16c'/>
+ <feature policy='require' name='ds'/>
+ <feature policy='require' name='tm2'/>
+ <feature policy='require' name='ss'/>
+ <feature policy='require' name='pbe'/>
+ <feature policy='require' name='ds_cpl'/>
+ <feature policy='require' name='rdrand'/>
+ </cpu>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <emulator>/usr/bin/kvm</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <source file='disk.raw'/>
+ <target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
+ </disk>
+ <controller type='usb' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'/>
+ <interface type='network'>
+ <source network='fuel1'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel2'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel3'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel4'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>
+ </interface>
+ <serial type='pty'>
+ <target port='0'/>
+ </serial>
+ <console type='pty'>
+ <target type='serial' port='0'/>
+ </console>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <graphics type='vnc' port='-1' autoport='yes' keymap='sv'/>
+ <sound model='ich6'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+ </sound>
+ <video>
+ <model type='cirrus' vram='9216' heads='1'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </video>
+ <memballoon model='virtio'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
+ </memballoon>
+ </devices>
+</domain>
+
diff --git a/fuel/deploy/libvirt/vms/s1_b5 b/fuel/deploy/libvirt/vms/s1_b5
new file mode 100644
index 0000000..97218c3
--- /dev/null
+++ b/fuel/deploy/libvirt/vms/s1_b5
@@ -0,0 +1,100 @@
+<domain type='kvm'>
+ <name>s1_b5</name>
+ <memory unit='KiB'>8388608</memory>
+ <currentMemory unit='KiB'>8388608</currentMemory>
+ <vcpu placement='static'>2</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc-1.0'>hvm</type>
+ <boot dev='network'/>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <pae/>
+ </features>
+ <cpu mode='custom' match='exact'>
+ <model fallback='allow'>SandyBridge</model>
+ <vendor>Intel</vendor>
+ <feature policy='require' name='vme'/>
+ <feature policy='require' name='dtes64'/>
+ <feature policy='require' name='vmx'/>
+ <feature policy='require' name='erms'/>
+ <feature policy='require' name='xtpr'/>
+ <feature policy='require' name='smep'/>
+ <feature policy='require' name='pcid'/>
+ <feature policy='require' name='est'/>
+ <feature policy='require' name='monitor'/>
+ <feature policy='require' name='smx'/>
+ <feature policy='require' name='tm'/>
+ <feature policy='require' name='acpi'/>
+ <feature policy='require' name='osxsave'/>
+ <feature policy='require' name='ht'/>
+ <feature policy='require' name='pdcm'/>
+ <feature policy='require' name='fsgsbase'/>
+ <feature policy='require' name='f16c'/>
+ <feature policy='require' name='ds'/>
+ <feature policy='require' name='tm2'/>
+ <feature policy='require' name='ss'/>
+ <feature policy='require' name='pbe'/>
+ <feature policy='require' name='ds_cpl'/>
+ <feature policy='require' name='rdrand'/>
+ </cpu>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <emulator>/usr/bin/kvm</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <source file='disk.raw'/>
+ <target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
+ </disk>
+ <controller type='usb' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'/>
+ <interface type='network'>
+ <source network='fuel1'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel2'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel3'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel4'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>
+ </interface>
+ <serial type='pty'>
+ <target port='0'/>
+ </serial>
+ <console type='pty'>
+ <target type='serial' port='0'/>
+ </console>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <graphics type='vnc' port='-1' autoport='yes' keymap='sv'/>
+ <sound model='ich6'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+ </sound>
+ <video>
+ <model type='cirrus' vram='9216' heads='1'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </video>
+ <memballoon model='virtio'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
+ </memballoon>
+ </devices>
+</domain>
+
diff --git a/fuel/deploy/libvirt/vms/s1_b6 b/fuel/deploy/libvirt/vms/s1_b6
new file mode 100644
index 0000000..0cd3028
--- /dev/null
+++ b/fuel/deploy/libvirt/vms/s1_b6
@@ -0,0 +1,100 @@
+<domain type='kvm'>
+ <name>s1_b6</name>
+ <memory unit='KiB'>8388608</memory>
+ <currentMemory unit='KiB'>8388608</currentMemory>
+ <vcpu placement='static'>2</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc-1.0'>hvm</type>
+ <boot dev='network'/>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <pae/>
+ </features>
+ <cpu mode='custom' match='exact'>
+ <model fallback='allow'>SandyBridge</model>
+ <vendor>Intel</vendor>
+ <feature policy='require' name='vme'/>
+ <feature policy='require' name='dtes64'/>
+ <feature policy='require' name='vmx'/>
+ <feature policy='require' name='erms'/>
+ <feature policy='require' name='xtpr'/>
+ <feature policy='require' name='smep'/>
+ <feature policy='require' name='pcid'/>
+ <feature policy='require' name='est'/>
+ <feature policy='require' name='monitor'/>
+ <feature policy='require' name='smx'/>
+ <feature policy='require' name='tm'/>
+ <feature policy='require' name='acpi'/>
+ <feature policy='require' name='osxsave'/>
+ <feature policy='require' name='ht'/>
+ <feature policy='require' name='pdcm'/>
+ <feature policy='require' name='fsgsbase'/>
+ <feature policy='require' name='f16c'/>
+ <feature policy='require' name='ds'/>
+ <feature policy='require' name='tm2'/>
+ <feature policy='require' name='ss'/>
+ <feature policy='require' name='pbe'/>
+ <feature policy='require' name='ds_cpl'/>
+ <feature policy='require' name='rdrand'/>
+ </cpu>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <emulator>/usr/bin/kvm</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <source file='disk.raw'/>
+ <target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
+ </disk>
+ <controller type='usb' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'/>
+ <interface type='network'>
+ <source network='fuel1'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel2'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel3'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+ </interface>
+ <interface type='network'>
+ <source network='fuel4'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>
+ </interface>
+ <serial type='pty'>
+ <target port='0'/>
+ </serial>
+ <console type='pty'>
+ <target type='serial' port='0'/>
+ </console>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <graphics type='vnc' port='-1' autoport='yes' keymap='sv'/>
+ <sound model='ich6'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+ </sound>
+ <video>
+ <model type='cirrus' vram='9216' heads='1'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </video>
+ <memballoon model='virtio'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
+ </memballoon>
+ </devices>
+</domain>
+
diff --git a/fuel/deploy/setup_vms/apply_setup.sh b/fuel/deploy/setup_vms/apply_setup.sh
new file mode 100755
index 0000000..b38cf5d
--- /dev/null
+++ b/fuel/deploy/setup_vms/apply_setup.sh
@@ -0,0 +1,61 @@
+#!/bin/bash
+##############################################################################
+# Copyright (c) 2015 Ericsson AB and others.
+# stefan.k.berg@ericsson.com
+# jonas.bjurel@ericsson.com
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+error_exit () {
+ echo "$@"
+ exit 1
+}
+
+netdir='../libvirt/networks'
+vmdir='../libvirt/vms'
+tmpfile=/tmp/foo
+
+if [ ! -d $netdir ]; then
+ error_exit "No net directory $netdir"
+ exit 1
+elif [ ! -d $vmdir ]; then
+ error_exit "No VM directory $vmdir"
+ exit 1
+fi
+
+if [ $# -ne 2 ]; then
+ echo "Argument error."
+ echo "`basename $0` <path to storage dir> <size in GB of disk per VM>"
+ exit 1
+fi
+
+storagedir=$1
+size=$2
+
+if [ ! -d $storagedir ]; then
+ error_exit "Could not find storagedir directory $storagedir"
+fi
+
+# Create storage space and patch it in
+for vm in $vmdir/*
+do
+ storage=${storagedir}/`basename ${vm}`.raw
+ if [ -f ${storage} ]; then
+ error_exit "Storage already present: ${storage}"
+ fi
+ echo "Creating ${size} GB of storage in ${storage}"
+ fallocate -l ${size}G ${storage} || \
+ error_exit "Could not create storage"
+ sed "s:<source file='disk.raw':<source file='${storage}':" $vm >$tmpfile
+ virsh define $tmpfile
+done
+
+for net in $netdir/*
+do
+ virsh net-define $net
+ virsh net-autostart `basename $net`
+ virsh net-start `basename $net`
+done
diff --git a/fuel/deploy/setup_vms/setup-vm-host.sh b/fuel/deploy/setup_vms/setup-vm-host.sh
new file mode 100755
index 0000000..fd469e6
--- /dev/null
+++ b/fuel/deploy/setup_vms/setup-vm-host.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+##############################################################################
+# Copyright (c) 2015 Ericsson AB and others.
+# stefan.k.berg@ericsson.com
+# jonas.bjurel@ericsson.com
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+# Tools for installation on the libvirt server/base host
+#
+apt-get install -y libvirt-bin qemu-kvm tightvncserver virt-manager \
+ sshpass fuseiso genisoimage blackbox xterm python-yaml python-netaddr \
+ python-paramiko python-lxml
+restart libvirt-bin