summaryrefslogtreecommitdiffstats
path: root/fuel/deploy/cloud
diff options
context:
space:
mode:
authorSzilard Cserey <szilard.cserey@ericsson.com>2015-05-04 12:11:29 +0200
committerSzilard Cserey <szilard.cserey@ericsson.com>2015-05-19 20:15:25 +0200
commit945dca48c0b1fd93fec43513afb6680a8d828e33 (patch)
tree2023bf27393a7a1edd5a4b8178b5d20a63814bec /fuel/deploy/cloud
parent2debee7a4f97a6a9d90aa55877264b3c62e3e2df (diff)
Autodeploy inspired on Prototype #2
- setup libvirt environment - setup vfuel environment - patch iso - install Fuel Master - deploy cloud - hardware adapter for libvirt - hardware adapter for ipmi - hardware adapter for hp - README: AutoDeploy instructions JIRA: [BGS-2] Create Fuel deployment script Change-Id: I862d824829baaae7d21115776d13355d575a47c8 Signed-off-by: Szilard Cserey <szilard.cserey@ericsson.com>
Diffstat (limited to 'fuel/deploy/cloud')
-rw-r--r--fuel/deploy/cloud/configure_environment.py73
-rw-r--r--fuel/deploy/cloud/configure_network.py61
-rw-r--r--fuel/deploy/cloud/configure_nodes.py104
-rw-r--r--fuel/deploy/cloud/configure_settings.py47
-rw-r--r--fuel/deploy/cloud/deploy.py206
-rw-r--r--fuel/deploy/cloud/deployment.py113
6 files changed, 604 insertions, 0 deletions
diff --git a/fuel/deploy/cloud/configure_environment.py b/fuel/deploy/cloud/configure_environment.py
new file mode 100644
index 0000000..d0037d7
--- /dev/null
+++ b/fuel/deploy/cloud/configure_environment.py
@@ -0,0 +1,73 @@
+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 = self.dea.get_property('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('Configure environment')
+ if os.path.exists(self.yaml_config_dir):
+ log('Deleting existing config directory %s' % self.yaml_config_dir)
+ shutil.rmtree(self.yaml_config_dir)
+ log('Creating new config directory %s' % self.yaml_config_dir)
+ os.makedirs(self.yaml_config_dir)
+
+ mode = self.dea.get_property('environment_mode')
+ log('Creating environment %s release %s, mode %s, network-mode neutron'
+ ', net-segment-type vlan' % (self.env_name, self.release_id, mode))
+ exec_cmd('fuel env create --name %s --release %s --mode %s '
+ '--network-mode neutron --net-segment-type vlan'
+ % (self.env_name, self.release_id, mode))
+
+ if not self.env_exists(self.env_name):
+ err('Failed to create environment %s' % 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/configure_network.py b/fuel/deploy/cloud/configure_network.py
new file mode 100644
index 0000000..295eb90
--- /dev/null
+++ b/fuel/deploy/cloud/configure_network.py
@@ -0,0 +1,61 @@
+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('Download network config for environment %s' % 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('Upload network config for environment %s' % self.env_id)
+ exec_cmd('fuel network --env %s --upload --dir %s'
+ % (self.env_id, self.yaml_config_dir))
+
+ def config_network(self):
+ log('Configure network')
+ self.download_network_config()
+ self.modify_network_config()
+ self.upload_network_config()
+
+ def modify_network_config(self):
+ log('Modify network config for environment %s' % self.env_id)
+ network_yaml = ('%s/network_%s.yaml'
+ % (self.yaml_config_dir, self.env_id))
+ check_file_exists(network_yaml)
+
+ network_config = self.dea.get_property('network')
+
+ 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/configure_nodes.py b/fuel/deploy/cloud/configure_nodes.py
new file mode 100644
index 0000000..4d1315a
--- /dev/null
+++ b/fuel/deploy/cloud/configure_nodes.py
@@ -0,0 +1,104 @@
+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('Configure nodes')
+ for node_id, roles_blade in self.node_id_roles_dict.iteritems():
+ exec_cmd('fuel node set --node-id %s --role %s --env %s'
+ % (node_id, ','.join(roles_blade[0]), self.env_id))
+
+ self.download_deployment_config()
+ for node_id, roles_blade in self.node_id_roles_dict.iteritems():
+ self.download_interface_config(node_id)
+ self.modify_node_interface(node_id, roles_blade)
+ self.modify_node_network_schemes(node_id, roles_blade)
+ self.upload_interface_config(node_id)
+ self.upload_deployment_config()
+
+ def modify_node_network_schemes(self, node_id, roles_blade):
+ log('Modify node network transformations in environment %s'
+ % self.env_id)
+ type = self.dea.get_node_property(roles_blade[1], 'transformations')
+ transformations = self.dea.get_transformations(type)
+
+ for node_file in glob.glob('%s/deployment_%s/*_%s.yaml'
+ % (self.yaml_config_dir, self.env_id,
+ node_id)):
+ with io.open(node_file) as stream:
+ node = yaml.load(stream)
+
+ node['network_scheme']['transformations'] = transformations
+
+ with io.open(node_file, 'w') as stream:
+ yaml.dump(node, stream, default_flow_style=False)
+
+
+ def download_deployment_config(self):
+ log('Download deployment config for environment %s' % self.env_id)
+ exec_cmd('fuel deployment --env %s --default --dir %s'
+ % (self.env_id, self.yaml_config_dir))
+
+ def upload_deployment_config(self):
+ log('Upload deployment config for environment %s' % self.env_id)
+ exec_cmd('fuel deployment --env %s --upload --dir %s'
+ % (self.env_id, self.yaml_config_dir))
+
+ def download_interface_config(self, node_id):
+ log('Download interface config for node %s' % node_id)
+ 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('Upload interface config for node %s' % node_id)
+ 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, roles_blade):
+ log('Modify interface config for node %s' % node_id)
+ interface_yaml = ('%s/node_%s/interfaces.yaml'
+ % (self.yaml_config_dir, node_id))
+ check_file_exists(interface_yaml)
+
+ 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']
+
+ type = self.dea.get_node_property(roles_blade[1], 'interfaces')
+ interface_config = self.dea.get_interfaces(type)
+
+ for interface in interfaces:
+ interface['assigned_networks'] = []
+ if interface['name'] in interface_config:
+ 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/configure_settings.py b/fuel/deploy/cloud/configure_settings.py
new file mode 100644
index 0000000..ac0afdc
--- /dev/null
+++ b/fuel/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('Download settings for environment %s' % self.env_id)
+ exec_cmd('fuel settings --env %s --download --dir %s'
+ % (self.env_id, self.yaml_config_dir))
+
+ def upload_settings(self):
+ log('Upload settings for environment %s' % self.env_id)
+ exec_cmd('fuel settings --env %s --upload --dir %s'
+ % (self.env_id, self.yaml_config_dir))
+
+ def config_settings(self):
+ log('Configure settings')
+ self.download_settings()
+ self.modify_settings()
+ self.upload_settings()
+
+ def modify_settings(self):
+ log('Modify settings for environment %s' % self.env_id)
+ settings_yaml = ('%s/settings_%s.yaml'
+ % (self.yaml_config_dir, self.env_id))
+ check_file_exists(settings_yaml)
+
+ settings = self.dea.get_property('settings')
+
+ with io.open(settings_yaml, 'w') as stream:
+ yaml.dump(settings, stream, default_flow_style=False)
diff --git a/fuel/deploy/cloud/deploy.py b/fuel/deploy/cloud/deploy.py
new file mode 100644
index 0000000..c8714f8
--- /dev/null
+++ b/fuel/deploy/cloud/deploy.py
@@ -0,0 +1,206 @@
+import time
+import yaml
+import io
+import sys
+
+import common
+from dea import DeploymentEnvironmentAdapter
+from configure_environment import ConfigureEnvironment
+from deployment import Deployment
+
+YAML_CONF_DIR = '/var/lib/opnfv'
+
+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, dea_file, macs_file):
+ self.dea = DeploymentEnvironmentAdapter(dea_file)
+ self.macs_file = macs_file
+ self.macs_per_blade = {}
+ self.blades = self.dea.get_node_ids()
+ self.node_ids_dict = {}
+ self.node_id_roles_dict = {}
+ self.supported_release = None
+ self.env_id = None
+ self.wanted_release = self.dea.get_wanted_release()
+
+ def cleanup_fuel_environments(self, env_list):
+ WAIT_LOOP = 60
+ SLEEP_TIME = 10
+ for env in env_list:
+ log('Deleting environment %s' % 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:
+ 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('Deleting node %s' % node[N['id']])
+ 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):
+ log('Check previous installation')
+ 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):
+ log('Check supported release: %s' % self.wanted_release)
+ release_list = parse(exec_cmd('fuel release -l'))
+ for release in release_list:
+ if release[R['name']] == self.wanted_release:
+ self.supported_release = release
+ break
+ if not self.supported_release:
+ err('This Fuel does not contain the following release: %s'
+ % self.wanted_release)
+
+ def check_prerequisites(self):
+ log('Check prerequisites')
+ self.check_supported_release()
+ self.check_previous_installation()
+
+ def get_mac_addresses(self):
+ with io.open(self.macs_file, 'r') as stream:
+ self.macs_per_blade = yaml.load(stream)
+
+ def find_mac_in_dict(self, mac):
+ for blade, mac_list in self.macs_per_blade.iteritems():
+ if mac in mac_list:
+ return blade
+
+ def all_blades_discovered(self):
+ for blade, node_id in self.node_ids_dict.iteritems():
+ if not node_id:
+ return False
+ return True
+
+ def not_discovered_blades_summary(self):
+ summary = ''
+ for blade, node_id in self.node_ids_dict.iteritems():
+ if not node_id:
+ summary += '\n[blade %s]' % blade
+ return summary
+
+ 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']])
+ blade = self.find_mac_in_dict(node[N['mac']])
+ if blade:
+ log('Blade %s discovered as Node %s with MAC %s'
+ % (blade, node[N['id']], node[N['mac']]))
+ self.node_ids_dict[blade] = 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:
+ 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('Wait for discovered blades')
+ discovered_macs = []
+ for blade in self.blades:
+ self.node_ids_dict[blade] = None
+ all_discovered = self.discovery_waiting_loop(discovered_macs)
+ if not all_discovered:
+ err('Not all blades have been discovered: %s'
+ % self.not_discovered_blades_summary())
+
+ def assign_roles_to_cluster_node_ids(self):
+ self.node_id_roles_dict = {}
+ for blade, node_id in self.node_ids_dict.iteritems():
+ role_list = []
+ role = self.dea.get_node_role(blade)
+ if role == 'controller':
+ role_list.extend(['controller', 'mongo'])
+ elif role == 'compute':
+ role_list.extend(['compute'])
+ self.node_id_roles_dict[node_id] = (role_list, blade)
+
+ def configure_environment(self):
+ config_env = ConfigureEnvironment(self.dea, YAML_CONF_DIR,
+ self.supported_release[R['id']],
+ self.node_id_roles_dict)
+ config_env.configure_environment()
+ self.env_id = config_env.env_id
+
+ def deploy_cloud(self):
+ dep = Deployment(self.dea, YAML_CONF_DIR, self.env_id,
+ self.node_id_roles_dict)
+ dep.deploy()
+
+ def deploy(self):
+ self.get_mac_addresses()
+ self.check_prerequisites()
+ self.wait_for_discovered_blades()
+ self.assign_roles_to_cluster_node_ids()
+ self.configure_environment()
+ self.deploy_cloud()
+
+def usage():
+ print '''
+ Usage:
+ python deploy.py <dea_file> <macs_file>
+
+ Example:
+ python deploy.py dea.yaml macs.yaml
+ '''
+
+def parse_arguments():
+ if len(sys.argv) != 3:
+ log('Incorrect number of arguments')
+ usage()
+ sys.exit(1)
+ dea_file = sys.argv[-2]
+ macs_file = sys.argv[-1]
+ check_file_exists(dea_file)
+ check_file_exists(macs_file)
+ return dea_file, macs_file
+
+def main():
+
+ dea_file, macs_file = parse_arguments()
+
+ deploy = Deploy(dea_file, macs_file)
+ deploy.deploy()
+
+if __name__ == '__main__':
+ main() \ No newline at end of file
diff --git a/fuel/deploy/cloud/deployment.py b/fuel/deploy/cloud/deployment.py
new file mode 100644
index 0000000..cf56c36
--- /dev/null
+++ b/fuel/deploy/cloud/deployment.py
@@ -0,0 +1,113 @@
+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.yaml_config_dir = yaml_config_dir
+ self.env_id = env_id
+ self.node_id_roles_dict = node_id_roles_dict
+
+ def download_deployment_info(self):
+ log('Download deployment info for environment %s' % self.env_id)
+ deployment_dir = '%s/deployment_%s' \
+ % (self.yaml_config_dir, self.env_id)
+ if os.path.exists(deployment_dir):
+ shutil.rmtree(deployment_dir)
+ exec_cmd('fuel --env %s deployment --default --dir %s'
+ % (self.env_id, self.yaml_config_dir))
+
+ def upload_deployment_info(self):
+ log('Upload deployment info for environment %s' % self.env_id)
+ exec_cmd('fuel --env %s deployment --upload --dir %s'
+ % (self.env_id, self.yaml_config_dir))
+
+ def config_opnfv(self):
+ log('Configure OPNFV settings on environment %s' % self.env_id)
+ opnfv_compute = self.dea.get_opnfv('compute')
+ opnfv_controller = self.dea.get_opnfv('controller')
+ self.download_deployment_info()
+ 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 node['role'] == 'compute':
+ node.update(opnfv_compute)
+ else:
+ node.update(opnfv_controller)
+ with io.open(node_file, 'w') as stream:
+ yaml.dump(node, stream, default_flow_style=False)
+ self.upload_deployment_info()
+
+ def run_deploy(self):
+ WAIT_LOOP = 180
+ SLEEP_TIME = 60
+ LOG_FILE = 'cloud.log'
+
+ log('Starting deployment of environment %s' % self.env_id)
+ 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('Environment status: %s' % env[0][E['status']])
+ r, _ = exec_cmd('tail -2 %s | head -1' % LOG_FILE, False)
+ if r:
+ log(r)
+ if env[0][E['status']] == 'operational':
+ ready = True
+ break
+ elif env[0][E['status']] == 'error':
+ break
+ else:
+ time.sleep(SLEEP_TIME)
+ exec_cmd('rm %s' % LOG_FILE)
+
+ if ready:
+ log('Environment %s successfully deployed' % self.env_id)
+ else:
+ err('Deployment failed, environment %s is not operational'
+ % self.env_id)
+
+ def verify_node_status(self):
+ node_list = parse(exec_cmd('fuel node list'))
+ failed_nodes = []
+ for node in node_list:
+ if node[N['status']] != 'ready':
+ failed_nodes.append((node[N['id']], node[N['status']]))
+
+ if failed_nodes:
+ summary = ''
+ for node, status in failed_nodes:
+ summary += '[node %s, status %s]\n' % (node, status)
+ err('Deployment failed: %s' % summary)
+
+ def health_check(self):
+ log('Now running sanity and smoke health checks')
+ exec_cmd('fuel health --env %s --check sanity,smoke --force'
+ % self.env_id)
+ log('Health checks passed !')
+
+ def deploy(self):
+ self.config_opnfv()
+ self.run_deploy()
+ self.verify_node_status()
+ self.health_check() \ No newline at end of file