diff options
Diffstat (limited to 'patches')
23 files changed, 1344 insertions, 71 deletions
diff --git a/patches/fuel-plugin-qemu/0001-Fix-apt-cache-and-qemu-version-handling.patch b/patches/fuel-plugin-qemu/0001-Fix-apt-cache-and-qemu-version-handling.patch deleted file mode 100644 index 9a77c3a3..00000000 --- a/patches/fuel-plugin-qemu/0001-Fix-apt-cache-and-qemu-version-handling.patch +++ /dev/null @@ -1,28 +0,0 @@ -From: Stanislaw Kardach <stanislaw.kardach@caviumnetworks.com> -Date: Fri, 4 Mar 2016 14:26:43 +0100 -Subject: [PATCH] Fix apt cache and qemu version handling - ---- - qemu/build-qemu.sh | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/qemu/build-qemu.sh b/qemu/build-qemu.sh -index 652939e..f54f486 100755 ---- a/qemu/build-qemu.sh -+++ b/qemu/build-qemu.sh -@@ -1,11 +1,12 @@ - #!/bin/bash - wget http://wiki.qemu-project.org/download/qemu-2.2.1.tar.bz2 -+sudo apt-get update -y - sudo apt-get build-dep qemu -y - sudo apt-get install devscripts -y - sudo apt-get install dpkg-dev -y --apt-get source qemu -y --dpkg-source -x qemu_2.0.0+dfsg-2ubuntu1.21.dsc --cd qemu-2.0.0+dfsg; uupdate -v 2.2.1 ../qemu-2.2.1.tar.bz2 -+apt-get source qemu=2.0.0 -y -+dpkg-source -x qemu_2.0.0*.dsc -+cd qemu-2.0.0*; uupdate -v 2.2.1 ../qemu-2.2.1.tar.bz2 - cd ../qemu-2.2.1;echo "">> debian/patches/series - sed -i 's/seccomp="yes"/seccomp="no"/' configure - debian/rules build diff --git a/patches/opnfv-fuel/0009-Allow-customizing-fuel-plugin-opendaylight.patch b/patches/opnfv-fuel/0007-Allow-customizing-fuel-plugin-opendaylight.patch index c47b166c..c47b166c 100644 --- a/patches/opnfv-fuel/0009-Allow-customizing-fuel-plugin-opendaylight.patch +++ b/patches/opnfv-fuel/0007-Allow-customizing-fuel-plugin-opendaylight.patch diff --git a/patches/opnfv-fuel/0007-Allow-customizing-fuel-plugin-qemu.patch b/patches/opnfv-fuel/0007-Allow-customizing-fuel-plugin-qemu.patch deleted file mode 100644 index 4ce6d83e..00000000 --- a/patches/opnfv-fuel/0007-Allow-customizing-fuel-plugin-qemu.patch +++ /dev/null @@ -1,21 +0,0 @@ -From: Stanislaw Kardach <stanislaw.kardach@caviumnetworks.com> -Date: Fri, 4 Mar 2016 14:27:48 +0100 -Subject: [PATCH] Allow customizing fuel-plugin-qemu - ---- - build/f_isoroot/f_qemupluginbuild/config.mk | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/build/f_isoroot/f_qemupluginbuild/config.mk b/build/f_isoroot/f_qemupluginbuild/config.mk -index 0b84654..e7fb65a 100644 ---- a/build/f_isoroot/f_qemupluginbuild/config.mk -+++ b/build/f_isoroot/f_qemupluginbuild/config.mk -@@ -7,6 +7,6 @@ - # http://www.apache.org/licenses/LICENSE-2.0 - ############################################################################## - --QEMU_BRANCH=c35ce3377bcf382a4e36f1df49758100cd2910b1 --QEMU_REPO=https://review.openstack.org/openstack/fuel-plugin-qemu -+QEMU_BRANCH:=c35ce3377bcf382a4e36f1df49758100cd2910b1 -+QEMU_REPO:=https://review.openstack.org/openstack/fuel-plugin-qemu - QEMU_CHANGE= diff --git a/patches/opnfv-fuel/0008-Allow-customizing-fuel-plugin-ovsnfv.patch b/patches/opnfv-fuel/0008-Allow-customizing-fuel-plugin-ovsnfv.patch deleted file mode 100644 index c427394f..00000000 --- a/patches/opnfv-fuel/0008-Allow-customizing-fuel-plugin-ovsnfv.patch +++ /dev/null @@ -1,22 +0,0 @@ -From: Stanislaw Kardach <stanislaw.kardach@caviumnetworks.com> -Date: Sat, 5 Mar 2016 15:08:10 +0100 -Subject: [PATCH] Allow customizing fuel-plugin-ovsnfv - ---- - build/f_isoroot/f_ovsnfv-dpdk-pluginbuild/config.mk | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/build/f_isoroot/f_ovsnfv-dpdk-pluginbuild/config.mk b/build/f_isoroot/f_ovsnfv-dpdk-pluginbuild/config.mk -index 1893fce..f29dab5 100644 ---- a/build/f_isoroot/f_ovsnfv-dpdk-pluginbuild/config.mk -+++ b/build/f_isoroot/f_ovsnfv-dpdk-pluginbuild/config.mk -@@ -7,7 +7,7 @@ - # http://www.apache.org/licenses/LICENSE-2.0 - ############################################################################## - --OVSNFV_DPDK_BRANCH=stable/brahmaputra --OVSNFV_DPDK_REPO=https://gerrit.opnfv.org/gerrit/p/ovsnfv.git -+OVSNFV_DPDK_BRANCH:=stable/brahmaputra -+OVSNFV_DPDK_REPO:=https://gerrit.opnfv.org/gerrit/p/ovsnfv.git - OVSNFV_DPDK_DIR=fuel-plugin-ovsnfv - OVSNFV_DPDK_CHANGE= diff --git a/patches/opnfv-fuel/0010-Separate-armband-repo-comp-from-upstream-RPM-repos.patch b/patches/opnfv-fuel/0008-Separate-armband-repo-comp-from-upstream-RPM-repos.patch index 670e8728..670e8728 100644 --- a/patches/opnfv-fuel/0010-Separate-armband-repo-comp-from-upstream-RPM-repos.patch +++ b/patches/opnfv-fuel/0008-Separate-armband-repo-comp-from-upstream-RPM-repos.patch diff --git a/patches/opnfv-fuel/0011-f_repobuild-Makefile-Use-python-debian-from-pip.patch b/patches/opnfv-fuel/0009-f_repobuild-Makefile-Use-python-debian-from-pip.patch index f84b4c0c..f84b4c0c 100644 --- a/patches/opnfv-fuel/0011-f_repobuild-Makefile-Use-python-debian-from-pip.patch +++ b/patches/opnfv-fuel/0009-f_repobuild-Makefile-Use-python-debian-from-pip.patch diff --git a/patches/opnfv-fuel/0010-deployment.py-stdout-not-consumed-when-deploying-cha.patch b/patches/opnfv-fuel/0010-deployment.py-stdout-not-consumed-when-deploying-cha.patch new file mode 100644 index 00000000..584413ec --- /dev/null +++ b/patches/opnfv-fuel/0010-deployment.py-stdout-not-consumed-when-deploying-cha.patch @@ -0,0 +1,66 @@ +From: Josep Puigdemont <josep.puigdemont@enea.com> +Date: Wed, 4 May 2016 14:27:23 +0200 +Subject: [PATCH] deployment.py: stdout not consumed when deploying changes + +During the automatic deployment, when the environment is ready to be +deployed, the deploy.py script will spawn a shell process that will +perform the command "fuel deploy-changes". The standard output of this +process is then piped to a "tee" process, which redirects the output +to the standard output of the shell process, and to a file named +cloud.log. The file is monitored by the deploy script to find out the +status of the deployment, and print it to the log file of the automatic +deployment script, including percentages for each node being +provisioned. However, the deploy script never consumes the standard +output of the shell process. If the shell process produces enough +output, its standard output buffer will fill up, thus making the tee +process block trying to write to its standard output, and the cloud.log +file will not be updated. At this point, the deploy process, which is +monitoring cloud.log, will not detect any progress in the deployment, +and eventually it will time out and assume the deployment failed, +although it might have finished fine after that. + +The solution here is to remove the "tee" process from the shell command, +and instead redirect standard output to the cloud.log file. +Another solution would be to actually parse the standard output of the +shell command from the deploy script itself, but that would require a +bit more work, as reading a line at a time might block the script. + +Finally, with this patch the cloud.log file won't be deleted unless the +shell process has already finished. + +Change-Id: I03a77be42d220b1606e48fc4ca35e22d73a6e583 +Signed-off-by: Josep Puigdemont <josep.puigdemont@enea.com> +--- + deploy/cloud/deployment.py | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/deploy/cloud/deployment.py b/deploy/cloud/deployment.py +index 306abf0..0127d2a 100644 +--- a/deploy/cloud/deployment.py ++++ b/deploy/cloud/deployment.py +@@ -101,8 +101,8 @@ class Deployment(object): + 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)) ++ p = run_proc('fuel --env %s deploy-changes | strings > %s' ++ % (self.env_id, LOG_FILE)) + + ready = False + for i in range(int(self.deploy_timeout)): +@@ -119,7 +119,13 @@ class Deployment(object): + break + else: + time.sleep(SLEEP_TIME) +- delete(LOG_FILE) ++ ++ p.poll() ++ if p.returncode == None: ++ log('The process deploying the changes has not yet finished.') ++ log('''The file %s won't be deleted''' % LOG_FILE) ++ else: ++ delete(LOG_FILE) + + if ready: + log('Environment %s successfully deployed' % self.env_id) diff --git a/patches/opnfv-fuel/0011-common.py-catch-stderr-in-exec_cmd.patch b/patches/opnfv-fuel/0011-common.py-catch-stderr-in-exec_cmd.patch new file mode 100644 index 00000000..918a1192 --- /dev/null +++ b/patches/opnfv-fuel/0011-common.py-catch-stderr-in-exec_cmd.patch @@ -0,0 +1,40 @@ +From: Josep Puigdemont <josep.puigdemont@enea.com> +Date: Wed, 4 May 2016 14:27:23 +0200 +Subject: [PATCH] common.py: catch stderr in exec_cmd + +Signed-off-by: Josep Puigdemont <josep.puigdemont@enea.com> +--- + deploy/common.py | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/deploy/common.py b/deploy/common.py +index 787a21a..41b4e27 100644 +--- a/deploy/common.py ++++ b/deploy/common.py +@@ -38,20 +38,20 @@ LOG.addHandler(out_handler) + os.chmod(LOGFILE, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) + + def exec_cmd(cmd, check=True): +- nul_f = open(os.devnull, 'w') + process = subprocess.Popen(cmd, + stdout=subprocess.PIPE, +- stderr=nul_f, ++ stderr=subprocess.PIPE, + shell=True) +- nul_f.close() +- response = process.communicate()[0].strip() ++ (response, stderr) = process.communicate() + return_code = process.returncode ++ response = response.strip() + if check: + if return_code > 0: ++ stderr = stderr.strip() + print "Failed command: " + str(cmd) +- print "Command returned response: " + str(response) ++ print "Command returned response: " + str(stderr) + print "Command return code: " + str(return_code) +- raise Exception(response) ++ raise Exception(stderr) + else: + print "Command: " + str(cmd) + print str(response) diff --git a/patches/opnfv-fuel/0012-deploy.sh-do-not-expect-a-parameter-for-h.patch b/patches/opnfv-fuel/0012-deploy.sh-do-not-expect-a-parameter-for-h.patch new file mode 100644 index 00000000..f515aab6 --- /dev/null +++ b/patches/opnfv-fuel/0012-deploy.sh-do-not-expect-a-parameter-for-h.patch @@ -0,0 +1,47 @@ +From: Josep Puigdemont <josep.puigdemont@enea.com> +Date: Wed, 4 May 2016 14:27:23 +0200 +Subject: [PATCH] deploy.sh: do not expect a parameter for -h + +If -h was given as a parameter to the script, it would report an error +as it expected a parameter, and if it was called as the only parameter, +it would run deploy.py as if "old style" parameters had been given, thus +showing the usage for the python script, instead of the expected usage +message for this script. + +Update the usage message to include -h. + +Change-Id: I0930936962c1cb479ec4409ff114cd60a386b276 +Signed-off-by: Josep Puigdemont <josep.puigdemont@enea.com> +--- + ci/deploy.sh | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/ci/deploy.sh b/ci/deploy.sh +index d83bba2..dc13f1c 100755 +--- a/ci/deploy.sh ++++ b/ci/deploy.sh +@@ -40,6 +40,7 @@ OPTIONS: + -f Deploy on existing Fuel master + -e Do not launch environment deployment + -F Do only create a Fuel master ++ -h Print this message and exit + -H No health check + -l Lab-name + -p Pod-name +@@ -62,6 +63,7 @@ Input parameters to the build script is: + -f Deploy on existing Fuel master + -e Do not launch environment deployment + -F Do only create a Fuel master ++-h Print this message and exit + -H Do not run fuel built in health-check after successfull deployment + -l Lab name as defined in the configuration directory, e.g. lf + -p POD name as defined in the configuration directory, e.g. pod-1 +@@ -116,7 +118,7 @@ DRY_RUN=0 + ############################################################################ + # BEGIN of main + # +-while getopts "b:B:dfFHl:p:s:S:i:h:e" OPTION ++while getopts "b:B:dfFHl:p:s:S:i:he" OPTION + do + case $OPTION in + b) diff --git a/patches/opnfv-fuel/0013-VirtualFuel-Add-temp_dir-and-vm_name-attributes.patch b/patches/opnfv-fuel/0013-VirtualFuel-Add-temp_dir-and-vm_name-attributes.patch new file mode 100644 index 00000000..83d6e292 --- /dev/null +++ b/patches/opnfv-fuel/0013-VirtualFuel-Add-temp_dir-and-vm_name-attributes.patch @@ -0,0 +1,57 @@ +From: Josep Puigdemont <josep.puigdemont@enea.com> +Date: Wed, 4 May 2016 14:27:23 +0200 +Subject: [PATCH] VirtualFuel: Add temp_dir and vm_name attributes + +These two variables are defined in one of the methods right now. They +will be useful to other methods too, so we add them as attributes to the +object here. + +Signed-off-by: Josep Puigdemont <josep.puigdemont@enea.com> +--- + deploy/environments/virtual_fuel.py | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/deploy/environments/virtual_fuel.py b/deploy/environments/virtual_fuel.py +index cb3bc6c..966bb91 100644 +--- a/deploy/environments/virtual_fuel.py ++++ b/deploy/environments/virtual_fuel.py +@@ -25,6 +25,12 @@ class VirtualFuel(ExecutionEnvironment): + def __init__(self, storage_dir, pxe_bridge, dha_file, root_dir): + super(VirtualFuel, self).__init__(storage_dir, dha_file, root_dir) + self.pxe_bridge = pxe_bridge ++ self.temp_dir = tempfile.mkdtemp() ++ self.vm_name = self.dha.get_node_property(self.fuel_node_id, ++ 'libvirtName') ++ ++ def __del__(self): ++ delete(self.temp_dir) + + def set_vm_nic(self, temp_vm_file): + with open(temp_vm_file) as f: +@@ -46,23 +52,20 @@ class VirtualFuel(ExecutionEnvironment): + vm_xml.write(f, pretty_print=True, xml_declaration=True) + + def create_vm(self): +- temp_dir = tempfile.mkdtemp() +- vm_name = self.dha.get_node_property(self.fuel_node_id, 'libvirtName') + vm_template = '%s/%s' % (self.root_dir, + self.dha.get_node_property( + self.fuel_node_id, 'libvirtTemplate')) + check_file_exists(vm_template) +- disk_path = '%s/%s.raw' % (self.storage_dir, vm_name) ++ disk_path = '%s/%s.raw' % (self.storage_dir, self.vm_name) + disk_sizes = self.dha.get_disks() + disk_size = disk_sizes['fuel'] + exec_cmd('qemu-img create -f qcow2 %s %s' % (disk_path, disk_size)) +- temp_vm_file = '%s/%s' % (temp_dir, vm_name) ++ temp_vm_file = '%s/%s' % (self.temp_dir, self.vm_name) + exec_cmd('cp %s %s' % (vm_template, temp_vm_file)) + self.set_vm_nic(temp_vm_file) + vm_definition_overwrite = self.dha.get_vm_definition('fuel') +- self.define_vm(vm_name, temp_vm_file, disk_path, ++ self.define_vm(self.vm_name, temp_vm_file, disk_path, + vm_definition_overwrite) +- delete(temp_dir) + + def setup_environment(self): + check_if_root() diff --git a/patches/opnfv-fuel/0014-virtual_fuel-factor-out-image-creation-into-a-method.patch b/patches/opnfv-fuel/0014-virtual_fuel-factor-out-image-creation-into-a-method.patch new file mode 100644 index 00000000..4e1f583b --- /dev/null +++ b/patches/opnfv-fuel/0014-virtual_fuel-factor-out-image-creation-into-a-method.patch @@ -0,0 +1,35 @@ +From: Josep Puigdemont <josep.puigdemont@enea.com> +Date: Wed, 4 May 2016 14:27:23 +0200 +Subject: [PATCH] virtual_fuel: factor out image creation into a method + +Signed-off-by: Josep Puigdemont <josep.puigdemont@enea.com> +--- + deploy/environments/virtual_fuel.py | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/deploy/environments/virtual_fuel.py b/deploy/environments/virtual_fuel.py +index 966bb91..82c4e47 100644 +--- a/deploy/environments/virtual_fuel.py ++++ b/deploy/environments/virtual_fuel.py +@@ -51,15 +51,20 @@ class VirtualFuel(ExecutionEnvironment): + with open(temp_vm_file, 'w') as f: + vm_xml.write(f, pretty_print=True, xml_declaration=True) + ++ def create_image(self, disk_path, disk_size): ++ exec_cmd('qemu-img create -f qcow2 %s %s' % (disk_path, disk_size)) ++ + def create_vm(self): + vm_template = '%s/%s' % (self.root_dir, + self.dha.get_node_property( + self.fuel_node_id, 'libvirtTemplate')) + check_file_exists(vm_template) ++ + disk_path = '%s/%s.raw' % (self.storage_dir, self.vm_name) + disk_sizes = self.dha.get_disks() + disk_size = disk_sizes['fuel'] +- exec_cmd('qemu-img create -f qcow2 %s %s' % (disk_path, disk_size)) ++ self.create_image(disk_path, disk_size) ++ + temp_vm_file = '%s/%s' % (self.temp_dir, self.vm_name) + exec_cmd('cp %s %s' % (vm_template, temp_vm_file)) + self.set_vm_nic(temp_vm_file) diff --git a/patches/opnfv-fuel/0015-virtual_fuel-initial-support-for-libvirt-volumes.patch b/patches/opnfv-fuel/0015-virtual_fuel-initial-support-for-libvirt-volumes.patch new file mode 100644 index 00000000..87266ef8 --- /dev/null +++ b/patches/opnfv-fuel/0015-virtual_fuel-initial-support-for-libvirt-volumes.patch @@ -0,0 +1,209 @@ +From: Josep Puigdemont <josep.puigdemont@enea.com> +Date: Wed, 4 May 2016 14:27:23 +0200 +Subject: [PATCH] virtual_fuel: initial support for libvirt volumes + +This patch introduces the ability to create volumes on the libvirt host +where the Fuel VM is being deployed. For now a default pool is used, +but the idea is to allow this to be configured. + +Since all virsh commands honor LIBVIRT_DEFAULT_URI, we use this +environment variable to detect wheter we should create a volume or not. +The rationale being that this environment variable will only be set if +the user wants to do the VM deployment on a remote libvirt host. + +All this could also be done using scp and a user directory on the host +machine, but using pools allows us to take advantage of libvirt's +policies and file permissions. + +CHANGE: before this patch, the file system image was named like the VM: +vm_name.raw. This patch introduces a change and adds a timestamp suffix +to the image: vm_name-timestamp.raw. This is so to avoid collisions with +an image with the same name on the remote pool. It may also be useful to +keep around old images for later testing, while the VM definition can +likely be the same. + +FIXME: This patch will use a pool called "jenkins" in the libvirt +server, and it will fail if it is not present. This is a requirement +that should be amended in the future, and properly documented. + +Signed-off-by: Josep Puigdemont <josep.puigdemont@enea.com> +--- + deploy/deploy.py | 5 +++ + deploy/dha_adapters/libvirt_adapter.py | 28 +++++++++++++++++ + deploy/environments/virtual_fuel.py | 57 +++++++++++++++++++++++++++++----- + deploy/install_fuel_master.py | 8 +++-- + 4 files changed, 88 insertions(+), 10 deletions(-) + +diff --git a/deploy/deploy.py b/deploy/deploy.py +index f86f2be..265e888 100755 +--- a/deploy/deploy.py ++++ b/deploy/deploy.py +@@ -243,6 +243,11 @@ class AutoDeploy(object): + + + def check_bridge(pxe_bridge, dha_path): ++ # Assume that bridges on remote nodes exists, we could ssh but ++ # the remote user might not have a login shell. ++ if os.environ.get('LIBVIRT_DEFAULT_URI'): ++ return ++ + with io.open(dha_path) as yaml_file: + dha_struct = yaml.load(yaml_file) + if dha_struct['adapter'] != 'libvirt': +diff --git a/deploy/dha_adapters/libvirt_adapter.py b/deploy/dha_adapters/libvirt_adapter.py +index 85913ac..8f3042c 100644 +--- a/deploy/dha_adapters/libvirt_adapter.py ++++ b/deploy/dha_adapters/libvirt_adapter.py +@@ -11,6 +11,7 @@ + from lxml import etree + from hardware_adapter import HardwareAdapter + import tempfile ++import os + + from common import ( + log, +@@ -23,6 +24,13 @@ DEV = {'pxe': 'network', + 'disk': 'hd', + 'iso': 'cdrom'} + ++vol_xml_template = '''<volume type='file'> ++ <name>%s</name> ++ <capacity unit='%s'>%s</capacity> ++ <target> ++ <format type='%s'/> ++ </target> ++</volume>''' + + class LibvirtAdapter(HardwareAdapter): + +@@ -140,3 +148,23 @@ class LibvirtAdapter(HardwareAdapter): + + def get_virt_net_conf_dir(self): + return self.dha_struct['virtNetConfDir'] ++ ++ def upload_iso(self, iso_file): ++ size = os.path.getsize(iso_file) ++ vol_name = os.path.basename(iso_file) ++ vol_xml = vol_xml_template % (vol_name, 'bytes', str(size), 'raw') ++ fd, fname = tempfile.mkstemp(text=True, suffix='deploy') ++ os.write(fd, vol_xml) ++ os.close(fd) ++ ++ log(vol_xml) ++ pool = 'jenkins' # FIXME ++ exec_cmd('virsh vol-create --pool %s %s' % (pool, fname)) ++ vol_path = exec_cmd('virsh vol-path --pool %s %s' % (pool, vol_name)) ++ ++ exec_cmd('virsh vol-upload %s %s' % (vol_path, iso_file), ++ attempts=5, delay=10, verbose=True) ++ ++ delete(fname) ++ ++ return vol_path +diff --git a/deploy/environments/virtual_fuel.py b/deploy/environments/virtual_fuel.py +index 82c4e47..56d6f98 100644 +--- a/deploy/environments/virtual_fuel.py ++++ b/deploy/environments/virtual_fuel.py +@@ -11,14 +11,33 @@ + from lxml import etree + from execution_environment import ExecutionEnvironment + import tempfile ++import os ++import re + + from common import ( + exec_cmd, + check_file_exists, + check_if_root, + delete, ++ log, + ) + ++vol_xml_template = '''<volume type='file'> ++ <name>%s</name> ++ <capacity unit='%s'>%s</capacity> ++ <target> ++ <format type='%s'/> ++ </target> ++</volume>''' ++ ++def get_size_and_unit(s): ++ p = re.compile('^(\d+)\s*(\D+)') ++ m = p.match(s) ++ if m == None: ++ return None, None ++ size = m.groups()[0] ++ unit = m.groups()[1] ++ return size, unit + + class VirtualFuel(ExecutionEnvironment): + +@@ -51,19 +70,41 @@ class VirtualFuel(ExecutionEnvironment): + with open(temp_vm_file, 'w') as f: + vm_xml.write(f, pretty_print=True, xml_declaration=True) + ++ def create_volume(self, pool, name, su, img_type='qcow2'): ++ log('Creating image using Libvirt volumes in pool %s, name: %s' % ++ (pool, name)) ++ size, unit = get_size_and_unit(su) ++ if size == None: ++ err('Could not determine size and unit of %s' % s) ++ ++ vol_xml = vol_xml_template % (name, unit, str(size), img_type) ++ fname = os.path.join(self.temp_dir, '%s_vol.xml' % name) ++ with file(fname, 'w') as f: ++ f.write(vol_xml) ++ ++ exec_cmd('virsh vol-create --pool %s %s' % (pool, fname)) ++ vol_path = exec_cmd('virsh vol-path --pool %s %s' % (pool, name)) ++ ++ delete(fname) ++ ++ return vol_path ++ + def create_image(self, disk_path, disk_size): +- exec_cmd('qemu-img create -f qcow2 %s %s' % (disk_path, disk_size)) ++ if os.environ.get('LIBVIRT_DEFAULT_URI') == None: ++ exec_cmd('qemu-img create -f qcow2 %s %s' % (disk_path, disk_size)) ++ else: ++ pool = 'jenkins' # FIXME ++ name = os.path.basename(disk_path) ++ disk_path = self.create_volume(pool, name, disk_size) + +- def create_vm(self): +- vm_template = '%s/%s' % (self.root_dir, +- self.dha.get_node_property( +- self.fuel_node_id, 'libvirtTemplate')) +- check_file_exists(vm_template) ++ return disk_path + +- disk_path = '%s/%s.raw' % (self.storage_dir, self.vm_name) ++ def create_vm(self): ++ stamp = time.strftime("%Y%m%d%H%M%S") ++ disk_path = '%s/%s-%s.raw' % (self.storage_dir, self.vm_name, stamp) + disk_sizes = self.dha.get_disks() + disk_size = disk_sizes['fuel'] +- self.create_image(disk_path, disk_size) ++ disk_path = self.create_image(disk_path, disk_size) + + temp_vm_file = '%s/%s' % (self.temp_dir, self.vm_name) + exec_cmd('cp %s %s' % (vm_template, temp_vm_file)) +diff --git a/deploy/install_fuel_master.py b/deploy/install_fuel_master.py +index 4f6a052..1c1bf05 100644 +--- a/deploy/install_fuel_master.py ++++ b/deploy/install_fuel_master.py +@@ -54,8 +54,12 @@ class InstallFuelMaster(object): + + self.dha.node_power_off(self.fuel_node_id) + +- log('Zero the MBR') +- self.dha.node_zero_mbr(self.fuel_node_id) ++ if os.environ.get('LIBVIRT_DEFAULT_URI'): ++ log('Upload ISO to pool') ++ self.iso_file = self.dha.upload_iso(self.iso_file) ++ else: ++ log('Zero the MBR') ++ self.dha.node_zero_mbr(self.fuel_node_id) + + self.dha.node_set_boot_order(self.fuel_node_id, ['disk', 'iso']) + diff --git a/patches/opnfv-fuel/0016-Remove-check-for-root.patch b/patches/opnfv-fuel/0016-Remove-check-for-root.patch new file mode 100644 index 00000000..4c24bb0e --- /dev/null +++ b/patches/opnfv-fuel/0016-Remove-check-for-root.patch @@ -0,0 +1,79 @@ +From: Josep Puigdemont <josep.puigdemont@enea.com> +Date: Wed, 4 May 2016 14:27:23 +0200 +Subject: [PATCH] Remove check for root + +--- + ci/deploy.sh | 5 ----- + deploy/deploy-config.py | 1 - + deploy/deploy.py | 2 -- + deploy/environments/virtual_fuel.py | 2 -- + 4 files changed, 10 deletions(-) + +diff --git a/ci/deploy.sh b/ci/deploy.sh +index dc13f1c..343d499 100755 +--- a/ci/deploy.sh ++++ b/ci/deploy.sh +@@ -193,11 +193,6 @@ do + esac + done + +-if [[ $EUID -ne 0 ]]; then +- echo "This script must be run as root" 1>&2 +- exit 1 +-fi +- + if [ -z $BASE_CONFIG_URI ] || [ -z $TARGET_LAB ] || \ + [ -z $TARGET_POD ] || [ -z $DEPLOY_SCENARIO ] || \ + [ -z $ISO ]; then +diff --git a/deploy/deploy-config.py b/deploy/deploy-config.py +index 65d51b2..88a1111 100644 +--- a/deploy/deploy-config.py ++++ b/deploy/deploy-config.py +@@ -40,7 +40,6 @@ from common import ( + check_file_exists, + create_dir_if_not_exists, + delete, +- check_if_root, + ArgParser, + ) + +diff --git a/deploy/deploy.py b/deploy/deploy.py +index 265e888..ff4582a 100755 +--- a/deploy/deploy.py ++++ b/deploy/deploy.py +@@ -32,7 +32,6 @@ from common import ( + check_file_exists, + create_dir_if_not_exists, + delete, +- check_if_root, + ArgParser, + ) + +@@ -230,7 +229,6 @@ class AutoDeploy(object): + return 0 + + def run(self): +- check_if_root() + if self.cleanup_only: + self.cleanup_execution_environment() + else: +diff --git a/deploy/environments/virtual_fuel.py b/deploy/environments/virtual_fuel.py +index 56d6f98..f07207f 100644 +--- a/deploy/environments/virtual_fuel.py ++++ b/deploy/environments/virtual_fuel.py +@@ -17,7 +17,6 @@ import re + from common import ( + exec_cmd, + check_file_exists, +- check_if_root, + delete, + log, + ) +@@ -114,7 +113,6 @@ class VirtualFuel(ExecutionEnvironment): + vm_definition_overwrite) + + def setup_environment(self): +- check_if_root() + self.cleanup_environment() + self.create_vm() + diff --git a/patches/opnfv-fuel/0017-virtual_fuel-make-vm_template-an-attibute.patch b/patches/opnfv-fuel/0017-virtual_fuel-make-vm_template-an-attibute.patch new file mode 100644 index 00000000..db602029 --- /dev/null +++ b/patches/opnfv-fuel/0017-virtual_fuel-make-vm_template-an-attibute.patch @@ -0,0 +1,33 @@ +From: Josep Puigdemont <josep.puigdemont@enea.com> +Date: Wed, 4 May 2016 14:27:23 +0200 +Subject: [PATCH] virtual_fuel: make vm_template an attibute + +Signed-off-by: Josep Puigdemont <josep.puigdemont@enea.com> +--- + deploy/environments/virtual_fuel.py | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/deploy/environments/virtual_fuel.py b/deploy/environments/virtual_fuel.py +index f07207f..92a234c 100644 +--- a/deploy/environments/virtual_fuel.py ++++ b/deploy/environments/virtual_fuel.py +@@ -46,6 +46,10 @@ class VirtualFuel(ExecutionEnvironment): + self.temp_dir = tempfile.mkdtemp() + self.vm_name = self.dha.get_node_property(self.fuel_node_id, + 'libvirtName') ++ self.vm_template = '%s/%s' % (self.root_dir, ++ self.dha.get_node_property( ++ self.fuel_node_id, 'libvirtTemplate')) ++ check_file_exists(self.vm_template) + + def __del__(self): + delete(self.temp_dir) +@@ -106,7 +110,7 @@ class VirtualFuel(ExecutionEnvironment): + disk_path = self.create_image(disk_path, disk_size) + + temp_vm_file = '%s/%s' % (self.temp_dir, self.vm_name) +- exec_cmd('cp %s %s' % (vm_template, temp_vm_file)) ++ exec_cmd('cp %s %s' % (self.vm_template, temp_vm_file)) + self.set_vm_nic(temp_vm_file) + vm_definition_overwrite = self.dha.get_vm_definition('fuel') + self.define_vm(self.vm_name, temp_vm_file, disk_path, diff --git a/patches/opnfv-fuel/0018-virtual_fuel-add-XML-tree-as-attribute-of-VirtualFue.patch b/patches/opnfv-fuel/0018-virtual_fuel-add-XML-tree-as-attribute-of-VirtualFue.patch new file mode 100644 index 00000000..ebaad984 --- /dev/null +++ b/patches/opnfv-fuel/0018-virtual_fuel-add-XML-tree-as-attribute-of-VirtualFue.patch @@ -0,0 +1,102 @@ +From: Josep Puigdemont <josep.puigdemont@enea.com> +Date: Wed, 4 May 2016 14:27:23 +0200 +Subject: [PATCH] virtual_fuel: add XML tree as attribute of VirtualFuel + +Now the VM XML definition tree is an attribute of the object, this way +it can be used by all methods without having to re-read the file from +the file. + +Methods added: +update_vm_template_file: Flushes the contents of the in-memory XML + representation of the VM to the backing file. + +del_vm_nics: Deletes all interfaces from the VM + +add_vm_nic: Adds a new NIC to the VM, it now takes the name of the + bridge as a parameter. + +Add a function to flush the contents of the in-memory XML representation +to the file update_vm_template_file + +Signed-off-by: Josep Puigdemont <josep.puigdemont@enea.com> +--- + deploy/environments/virtual_fuel.py | 37 +++++++++++++++++++++++++------------ + 1 file changed, 25 insertions(+), 12 deletions(-) + +diff --git a/deploy/environments/virtual_fuel.py b/deploy/environments/virtual_fuel.py +index 92a234c..b68577e 100644 +--- a/deploy/environments/virtual_fuel.py ++++ b/deploy/environments/virtual_fuel.py +@@ -13,6 +13,7 @@ from execution_environment import ExecutionEnvironment + import tempfile + import os + import re ++import time + + from common import ( + exec_cmd, +@@ -50,28 +51,38 @@ class VirtualFuel(ExecutionEnvironment): + self.dha.get_node_property( + self.fuel_node_id, 'libvirtTemplate')) + check_file_exists(self.vm_template) ++ with open(self.vm_template) as f: ++ self.vm_xml = etree.parse(f) ++ ++ self.temp_vm_file = '%s/%s' % (self.temp_dir, self.vm_name) ++ self.update_vm_template_file() + + def __del__(self): + delete(self.temp_dir) + +- def set_vm_nic(self, temp_vm_file): +- with open(temp_vm_file) as f: +- vm_xml = etree.parse(f) +- interfaces = vm_xml.xpath('/domain/devices/interface') ++ def update_vm_template_file(self): ++ with open(self.temp_vm_file, "wc") as f: ++ self.vm_xml.write(f, pretty_print=True, xml_declaration=True) ++ ++ def del_vm_nics(self): ++ interfaces = self.vm_xml.xpath('/domain/devices/interface') + for interface in interfaces: + interface.getparent().remove(interface) ++ ++ def add_vm_nic(self, bridge): + interface = etree.Element('interface') + interface.set('type', 'bridge') + source = etree.SubElement(interface, 'source') +- source.set('bridge', self.pxe_bridge) ++ source.set('bridge', bridge) + model = etree.SubElement(interface, 'model') + model.set('type', 'virtio') +- devices = vm_xml.xpath('/domain/devices') ++ ++ devices = self.vm_xml.xpath('/domain/devices') + if devices: + device = devices[0] + device.append(interface) +- with open(temp_vm_file, 'w') as f: +- vm_xml.write(f, pretty_print=True, xml_declaration=True) ++ else: ++ err('No devices!') + + def create_volume(self, pool, name, su, img_type='qcow2'): + log('Creating image using Libvirt volumes in pool %s, name: %s' % +@@ -109,11 +120,13 @@ class VirtualFuel(ExecutionEnvironment): + disk_size = disk_sizes['fuel'] + disk_path = self.create_image(disk_path, disk_size) + +- temp_vm_file = '%s/%s' % (self.temp_dir, self.vm_name) +- exec_cmd('cp %s %s' % (self.vm_template, temp_vm_file)) +- self.set_vm_nic(temp_vm_file) ++ self.del_vm_nics() ++ self.add_vm_nic(self.pxe_bridge) ++ self.update_vm_template_file() ++ + vm_definition_overwrite = self.dha.get_vm_definition('fuel') +- self.define_vm(self.vm_name, temp_vm_file, disk_path, ++ ++ self.define_vm(self.vm_name, self.temp_vm_file, disk_path, + vm_definition_overwrite) + + def setup_environment(self): diff --git a/patches/opnfv-fuel/0019-transplant-Generate-extra-interfaces-config-file.patch b/patches/opnfv-fuel/0019-transplant-Generate-extra-interfaces-config-file.patch new file mode 100644 index 00000000..b6a351e4 --- /dev/null +++ b/patches/opnfv-fuel/0019-transplant-Generate-extra-interfaces-config-file.patch @@ -0,0 +1,107 @@ +From: Josep Puigdemont <josep.puigdemont@enea.com> +Date: Wed, 4 May 2016 17:58:56 +0200 +Subject: [PATCH] transplant: Generate extra interfaces config file + +The DEA override may contain a IFCGF_<interface> section in its 'fuel:' +section, containing the necessary keys to produce a ifcfg-<interface> +file, like in this example: + +fuel: + IFCFG_ETH1: + device: eth1 + ipaddress: 10.0.1.10 + netmask: 255.255.255.0 + gateway: 10.0.1.254 + +FIXME: In order for Network Manager to use the newly added interfaces +for outgoing traffic and honor their GATEWAY setting (e.g. if we just +added one public interface), the default route on admin iface (most of +the time called eth0) should be disabled. For now, we assume the admin +interface is always "eth0". + +Signed-off-by: Josep Puigdemont <josep.puigdemont@enea.com> +Signed-off-by: Alexandu Avadanii <alexandru.avadanii@enea.com> +--- + deploy/transplant_fuel_settings.py | 37 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 37 insertions(+) + +diff --git a/deploy/transplant_fuel_settings.py b/deploy/transplant_fuel_settings.py +index e57a4fb..9a65cf6 100644 +--- a/deploy/transplant_fuel_settings.py ++++ b/deploy/transplant_fuel_settings.py +@@ -11,10 +11,14 @@ + import sys + import io + import yaml ++import re ++import os + from dea import DeploymentEnvironmentAdapter + + from common import ( + check_file_exists, ++ exec_cmd, ++ log, + ) + + ASTUTE_YAML = '/etc/fuel/astute.yaml' +@@ -35,15 +39,45 @@ def parse_arguments(): + check_file_exists(dea_file) + return dea_file + ++def write_ifcfg_file(key, fuel_conf): ++ config = ('BOOTPROTO=none\n' ++ 'ONBOOT=yes\n' ++ 'TYPE=Ethernet\n' ++ 'NM_CONTROLLED=yes\n') ++ for skey in ('ipaddress', 'device', 'netmask', 'gateway'): ++ if not fuel_conf[key].get(skey): ++ log('Warning: missing key %s for %s' % (skey, key)) ++ config += '%s=\n' % skey.upper() ++ elif skey == 'ipaddress': ++ config += 'IPADDR=%s\n' % fuel_conf[key][skey] ++ else: ++ config += '%s=%s\n' % (skey.upper(), fuel_conf[key][skey]) ++ ++ fname = os.path.join('/etc/sysconfig/network-scripts/', ++ key.lower().replace('_','-')) ++ with open(fname, 'wc') as f: ++ f.write(config) + + def transplant(dea, astute): + fuel_conf = dea.get_fuel_config() ++ require_network_restart = False + for key in fuel_conf.iterkeys(): + if key == 'ADMIN_NETWORK': + for skey in fuel_conf[key].iterkeys(): + astute[key][skey] = fuel_conf[key][skey] ++ elif re.match('^IFCFG', key): ++ log('Adding interface configuration for: %s' % key.lower()) ++ require_network_restart = True ++ write_ifcfg_file(key, fuel_conf) ++ if astute.has_key(key): ++ astute.pop(key, None) + else: + astute[key] = fuel_conf[key] ++ if require_network_restart: ++ admin_ifcfg = '/etc/sysconfig/network-scripts/ifcfg-eth0' ++ exec_cmd('echo "DEFROUTE=no" >> %s' % admin_ifcfg) ++ log('At least one interface was reconfigured, restart network manager') ++ exec_cmd('systemctl restart network') + return astute + + +@@ -51,11 +85,14 @@ def main(): + dea_file = parse_arguments() + check_file_exists(ASTUTE_YAML) + dea = DeploymentEnvironmentAdapter(dea_file) ++ log('Reading astute file %s' % ASTUTE_YAML) + with io.open(ASTUTE_YAML) as stream: + astute = yaml.load(stream) ++ log('Initiating transplant') + transplant(dea, astute) + with io.open(ASTUTE_YAML, 'w') as stream: + yaml.dump(astute, stream, default_flow_style=False) ++ log('Transplant done') + + + if __name__ == '__main__': diff --git a/patches/opnfv-fuel/0020-deploy.sh-no-need-to-set-umask-0000.patch b/patches/opnfv-fuel/0020-deploy.sh-no-need-to-set-umask-0000.patch new file mode 100644 index 00000000..241f3078 --- /dev/null +++ b/patches/opnfv-fuel/0020-deploy.sh-no-need-to-set-umask-0000.patch @@ -0,0 +1,33 @@ +From: Josep Puigdemont <josep.puigdemont@enea.com> +Date: Fri, 6 May 2016 03:07:40 +0200 +Subject: [PATCH] deploy.sh: no need to set umask 0000 + +Signed-off-by: Josep Puigdemont <josep.puigdemont@enea.com> +--- + ci/deploy.sh | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/ci/deploy.sh b/ci/deploy.sh +index 343d499..34ecc57 100755 +--- a/ci/deploy.sh ++++ b/ci/deploy.sh +@@ -76,9 +76,6 @@ Input parameters to the build script is: + -i .iso image to be deployed (needs to be provided in a URI + style, it can be a local resource: file:// or a remote resource http(s)://) + +-NOTE: Root priviledges are needed for this script to run +- +- + Examples: + sudo `basename $0` -b file:///home/jenkins/lab-config -l lf -p pod1 -s ha_odl-l3_heat_ceilometer -i file:///home/jenkins/myiso.iso + EOF +@@ -207,9 +204,6 @@ fi + # Enable the automatic exit trap + trap do_exit SIGINT SIGTERM EXIT + +-# Set no restrictive umask so that Jenkins can removeeee any residuals +-umask 0000 +- + clean + + pushd ${DEPLOY_DIR} > /dev/null diff --git a/patches/opnfv-fuel/0021-common.py-allow-specifying-number-of-attempts-in-exe.patch b/patches/opnfv-fuel/0021-common.py-allow-specifying-number-of-attempts-in-exe.patch new file mode 100644 index 00000000..d799723e --- /dev/null +++ b/patches/opnfv-fuel/0021-common.py-allow-specifying-number-of-attempts-in-exe.patch @@ -0,0 +1,70 @@ +From: Josep Puigdemont <josep.puigdemont@enea.com> +Date: Fri, 6 May 2016 03:28:26 +0200 +Subject: [PATCH] common.py: allow specifying number of attempts in exec_cmd + +Some commands executed by exec_cmd may fail because of a temporary +cause, and it may be desirable to retry the same command several times +until it succeeds. One example of this are the ipmitool commands, which +may fail temorarily on some targets if they get too many requests +simultaneously. + +In this patch two new optional parameters are introduced to the function +signature, which do not break backward compatibility: + attempts: which indicates how many times the command should be run if + it returns a non-zero value*, and defaults to 1 (as today). + delay: which indicates the delay in seconds between attempts, and + defaults to 5 seconds. + verbose: It will print the remaining attempts left for the current + command if set to True. + +* It may be desirable to add yet another parameter to indicate what + return value should be considered an error, but zero for now seems a + reasonable default + +Signed-off-by: Josep Puigdemont <josep.puigdemont@enea.com> +--- + deploy/common.py | 24 +++++++++++++++++------- + 1 file changed, 17 insertions(+), 7 deletions(-) + +diff --git a/deploy/common.py b/deploy/common.py +index 41b4e27..3cd3e0e 100644 +--- a/deploy/common.py ++++ b/deploy/common.py +@@ -16,6 +16,7 @@ import argparse + import shutil + import stat + import errno ++import time + + N = {'id': 0, 'status': 1, 'name': 2, 'cluster': 3, 'ip': 4, 'mac': 5, + 'roles': 6, 'pending_roles': 7, 'online': 8, 'group_id': 9} +@@ -37,13 +38,22 @@ out_handler.setFormatter(formatter) + LOG.addHandler(out_handler) + os.chmod(LOGFILE, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) + +-def exec_cmd(cmd, check=True): +- process = subprocess.Popen(cmd, +- stdout=subprocess.PIPE, +- stderr=subprocess.PIPE, +- shell=True) +- (response, stderr) = process.communicate() +- return_code = process.returncode ++def exec_cmd(cmd, check=True, attempts=1, delay=5, verbose=False): ++ # a negative value means forever ++ while attempts != 0: ++ attempts = attempts - 1 ++ process = subprocess.Popen(cmd, ++ stdout=subprocess.PIPE, ++ stderr=subprocess.PIPE, ++ shell=True) ++ (response, stderr) = process.communicate() ++ return_code = process.returncode ++ if return_code == 0 or attempts == 0: ++ break ++ time.sleep(delay) ++ if verbose: ++ log('%d attempts left: %s' % (attempts, cmd)) ++ + response = response.strip() + if check: + if return_code > 0: diff --git a/patches/opnfv-fuel/0022-ipmi_adapter-simplify-retry-if-command-fails.patch b/patches/opnfv-fuel/0022-ipmi_adapter-simplify-retry-if-command-fails.patch new file mode 100644 index 00000000..c1617f04 --- /dev/null +++ b/patches/opnfv-fuel/0022-ipmi_adapter-simplify-retry-if-command-fails.patch @@ -0,0 +1,171 @@ +From: Josep Puigdemont <josep.puigdemont@enea.com> +Date: Fri, 6 May 2016 12:09:58 +0200 +Subject: [PATCH] ipmi_adapter: simplify, retry if command fails + +The method get_node_state has been added to the The IpmiAdapter class. + +In addition, now the power on/off methods will try several times to +perform their IPMI command before giving up, instead of bailing out at +the first error. + +After the power on/off command is completed, the method will wait until +the node is in the desired state. + +FIXME: a command could potentially take several minutes if the defaults +are used; each IPMI command can take 1 minutes, and there can be three +commands issued per operation, one of them may be retried 20 times with +the current defaults. Ideally we would use eventlet or something alike +to allow each command a limited time to execute: + with eventlet.timeout.Timeout(seconds) as t: + power_on/off_command + +FIXME: There is a potential dead-lock situation by issuing the command +and then checking the status, as someone could have intervened in +between the two commands. + +Signed-off-by: Josep Puigdemont <josep.puigdemont@enea.com> +--- + deploy/dha_adapters/ipmi_adapter.py | 101 +++++++++++++++--------------------- + 1 file changed, 42 insertions(+), 59 deletions(-) + +diff --git a/deploy/dha_adapters/ipmi_adapter.py b/deploy/dha_adapters/ipmi_adapter.py +index 8fda4f9..283bd57 100644 +--- a/deploy/dha_adapters/ipmi_adapter.py ++++ b/deploy/dha_adapters/ipmi_adapter.py +@@ -1,5 +1,6 @@ + ############################################################################### + # Copyright (c) 2015 Ericsson AB and others. ++# (c) 2016 Enea Software AB + # szilard.cserey@ericsson.com + # All rights reserved. This program and the accompanying materials + # are made available under the terms of the Apache License, Version 2.0 +@@ -20,8 +21,10 @@ from common import ( + + class IpmiAdapter(HardwareAdapter): + +- def __init__(self, yaml_path): ++ def __init__(self, yaml_path, attempts=20, delay=3): + super(IpmiAdapter, self).__init__(yaml_path) ++ self.attempts = attempts ++ self.delay = delay + + def get_access_info(self, node_id): + ip = self.get_node_property(node_id, 'ipmiIp') +@@ -40,69 +43,46 @@ class IpmiAdapter(HardwareAdapter): + mac_list.append(self.get_node_property(node_id, 'pxeMac').lower()) + return mac_list + ++ def node_get_state(self, node_id): ++ state = exec_cmd('%s chassis power status' % self.ipmi_cmd(node_id), ++ attempts=self.attempts, delay=self.delay, ++ verbose=True) ++ return state ++ ++ def __node_power_cmd__(self, node_id, cmd): ++ expected = 'Chassis Power is %s' % cmd ++ if self.node_get_state(node_id) == expected: ++ return ++ ++ pow_cmd = '%s chassis power %s' % (self.ipmi_cmd(node_id), cmd) ++ exec_cmd(pow_cmd, attempts=self.attempts, delay=self.delay, ++ verbose=True) ++ ++ attempts = self.attempts ++ while attempts: ++ state = self.node_get_state(node_id) ++ attempts -= 1 ++ if state == expected: ++ return ++ elif attempts != 0: ++ # reinforce our will, but allow the command to fail, ++ # we know our message got across once already... ++ exec_cmd(pow_cmd, check=False) ++ ++ err('Could not set chassis %s for node %s' % (cmd, node_id)) ++ + def node_power_on(self, node_id): +- WAIT_LOOP = 200 +- SLEEP_TIME = 3 + log('Power ON Node %s' % node_id) +- cmd_prefix = self.ipmi_cmd(node_id) +- state = exec_cmd('%s chassis power status' % cmd_prefix) +- if state == 'Chassis Power is off': +- exec_cmd('%s chassis power on' % cmd_prefix) +- done = False +- for i in range(WAIT_LOOP): +- state, _ = exec_cmd('%s chassis power status' % cmd_prefix, +- False) +- if state == 'Chassis Power is on': +- done = True +- break +- else: +- time.sleep(SLEEP_TIME) +- if not done: +- err('Could Not Power ON Node %s' % node_id) ++ self.__node_power_cmd__(node_id, 'on') + + def node_power_off(self, node_id): +- WAIT_LOOP = 200 +- SLEEP_TIME = 3 + log('Power OFF Node %s' % node_id) +- cmd_prefix = self.ipmi_cmd(node_id) +- state = exec_cmd('%s chassis power status' % cmd_prefix) +- if state == 'Chassis Power is on': +- done = False +- exec_cmd('%s chassis power off' % cmd_prefix) +- for i in range(WAIT_LOOP): +- state, _ = exec_cmd('%s chassis power status' % cmd_prefix, +- False) +- if state == 'Chassis Power is off': +- done = True +- break +- else: +- time.sleep(SLEEP_TIME) +- if not done: +- err('Could Not Power OFF Node %s' % node_id) ++ self.__node_power_cmd__(node_id, 'off') + + def node_reset(self, node_id): +- WAIT_LOOP = 600 + log('RESET Node %s' % node_id) +- cmd_prefix = self.ipmi_cmd(node_id) +- state = exec_cmd('%s chassis power status' % cmd_prefix) +- if state == 'Chassis Power is on': +- was_shut_off = False +- done = False +- exec_cmd('%s chassis power reset' % cmd_prefix) +- for i in range(WAIT_LOOP): +- state, _ = exec_cmd('%s chassis power status' % cmd_prefix, +- False) +- if state == 'Chassis Power is off': +- was_shut_off = True +- elif state == 'Chassis Power is on' and was_shut_off: +- done = True +- break +- time.sleep(1) +- if not done: +- err('Could Not RESET Node %s' % node_id) +- else: +- err('Cannot RESET Node %s because it\'s not Active, state: %s' +- % (node_id, state)) ++ cmd = '%s chassis power reset' % self.ipmi_cmd(node_id) ++ exec_cmd(cmd, attempts=self.attempts, delay=self.delay, verbose=True) + + def node_set_boot_order(self, node_id, boot_order_list): + log('Set boot order %s on Node %s' % (boot_order_list, node_id)) +@@ -111,9 +91,12 @@ class IpmiAdapter(HardwareAdapter): + for dev in boot_order_list: + if dev == 'pxe': + exec_cmd('%s chassis bootdev pxe options=persistent' +- % cmd_prefix) ++ % cmd_prefix, attempts=self.attempts, delay=self.delay, ++ verbose=True) + elif dev == 'iso': +- exec_cmd('%s chassis bootdev cdrom' % cmd_prefix) ++ exec_cmd('%s chassis bootdev cdrom' % cmd_prefix, ++ attempts=self.attempts, delay=self.delay, verbose=True) + elif dev == 'disk': + exec_cmd('%s chassis bootdev disk options=persistent' +- % cmd_prefix) ++ % cmd_prefix, attempts=self.attempts, delay=self.delay, ++ verbose=True) diff --git a/patches/opnfv-fuel/0023-deploy.py-add-multiple-bridges-support.patch b/patches/opnfv-fuel/0023-deploy.py-add-multiple-bridges-support.patch new file mode 100644 index 00000000..376a7221 --- /dev/null +++ b/patches/opnfv-fuel/0023-deploy.py-add-multiple-bridges-support.patch @@ -0,0 +1,69 @@ +From: Josep Puigdemont <josep.puigdemont@enea.com> +Date: Fri, 6 May 2016 04:32:06 +0200 +Subject: [PATCH] deploy.py: add multiple bridges support + +Some Fuel VMs may need more than one network interface. To be able to do +that, we now allow the user to specify the "-b" paramter (bridge) +multiple times, creating a new NIC for each one of them. + +The NICs are created in the same order as they are given in the command +line. + +There is no change in behavior from earlier versions, pxebr will still +be the default bridge if none is specified. + +Signed-off-by: Josep Puigdemont <josep.puigdemont@enea.com> +--- + deploy/deploy.py | 10 +++++++--- + deploy/environments/virtual_fuel.py | 3 ++- + 2 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/deploy/deploy.py b/deploy/deploy.py +index ff4582a..041ba2f 100755 +--- a/deploy/deploy.py ++++ b/deploy/deploy.py +@@ -312,8 +312,8 @@ def parse_arguments(): + parser.add_argument('-s', dest='storage_dir', action='store', + default='%s/images' % CWD, + help='Storage Directory [default: images]') +- parser.add_argument('-b', dest='pxe_bridge', action='store', +- default='pxebr', ++ parser.add_argument('-b', dest='pxe_bridge', action='append', ++ default=[], + help='Linux Bridge for booting up the Fuel Master VM ' + '[default: pxebr]') + parser.add_argument('-p', dest='fuel_plugins_dir', action='store', +@@ -332,6 +332,9 @@ def parse_arguments(): + args = parser.parse_args() + log(args) + ++ if not args.pxe_bridge: ++ args.pxe_bridge = ['pxebr'] ++ + check_file_exists(args.dha_file) + + if not args.cleanup_only: +@@ -343,7 +346,8 @@ def parse_arguments(): + check_file_exists(args.iso_file) + log('Using image directory: %s' % args.storage_dir) + create_dir_if_not_exists(args.storage_dir) +- check_bridge(args.pxe_bridge, args.dha_file) ++ for bridge in args.pxe_bridge: ++ check_bridge(bridge, args.dha_file) + + kwargs = {'no_fuel': args.no_fuel, 'fuel_only': args.fuel_only, + 'no_health_check': args.no_health_check, +diff --git a/deploy/environments/virtual_fuel.py b/deploy/environments/virtual_fuel.py +index b68577e..6b673d0 100644 +--- a/deploy/environments/virtual_fuel.py ++++ b/deploy/environments/virtual_fuel.py +@@ -121,7 +121,8 @@ class VirtualFuel(ExecutionEnvironment): + disk_path = self.create_image(disk_path, disk_size) + + self.del_vm_nics() +- self.add_vm_nic(self.pxe_bridge) ++ for bridge in self.pxe_bridge: ++ self.add_vm_nic(bridge) + self.update_vm_template_file() + + vm_definition_overwrite = self.dha.get_vm_definition('fuel') diff --git a/patches/opnfv-fuel/0024-deploy.sh-allow-specifying-several-bridges.patch b/patches/opnfv-fuel/0024-deploy.sh-allow-specifying-several-bridges.patch new file mode 100644 index 00000000..b10effee --- /dev/null +++ b/patches/opnfv-fuel/0024-deploy.sh-allow-specifying-several-bridges.patch @@ -0,0 +1,47 @@ +From: Josep Puigdemont <josep.puigdemont@enea.com> +Date: Fri, 6 May 2016 04:39:44 +0200 +Subject: [PATCH] deploy.sh: allow specifying several bridges + +It might be desirable to add several bridges to the fuel VM, so we let +the user specify -B more than once, and honor that when calling +deploy.py. We also make it possible to specify a comma separated list of +bridges, as in: -B br1,br2, for convenience for the Jenkins jobs. + +There is a change in behavior from the previous version, and that is +that it may call the deploy.py python script with more than one instance +of the "-b" parameter. + +Signed-off-by: Josep Puigdemont <josep.puigdemont@enea.com> +--- + ci/deploy.sh | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/ci/deploy.sh b/ci/deploy.sh +index 34ecc57..c9b836b 100755 +--- a/ci/deploy.sh ++++ b/ci/deploy.sh +@@ -57,7 +57,10 @@ and provides a fairly simple mechanism to execute a deployment. + Input parameters to the build script is: + -b Base URI to the configuration directory (needs to be provided in a URI + style, it can be a local resource: file:// or a remote resource http(s)://) +--B PXE Bridge for booting of Fuel master, default is pxebr ++-B PXE Bridge for booting of Fuel master. It can be specified several times, ++ or as a comma separated list of bridges, or both: -B br1 -B br2,br3 ++ One NIC connected to each specified bridge will be created in the Fuel VM, ++ in the same order as provided in the command line. The default is pxebr. + -d Dry-run - Produces deploy config files (config/dea.yaml and + config/dha.yaml), but does not execute deploy + -f Deploy on existing Fuel master +@@ -130,9 +133,9 @@ do + fi + ;; + B) +- if [[ ${OPTARG} ]]; then +- PXE_BRIDGE="-b ${OPTARG}" +- fi ++ for bridge in ${OPTARG//,/ }; do ++ PXE_BRIDGE+=" -b $bridge" ++ done + ;; + d) + DRY_RUN=1 diff --git a/patches/opnfv-fuel/0025-Fuel-VM-for-the-Enea-Armband-lab.patch b/patches/opnfv-fuel/0025-Fuel-VM-for-the-Enea-Armband-lab.patch new file mode 100644 index 00000000..fbcd11d1 --- /dev/null +++ b/patches/opnfv-fuel/0025-Fuel-VM-for-the-Enea-Armband-lab.patch @@ -0,0 +1,106 @@ +From: Josep Puigdemont <josep.puigdemont@enea.com> +Date: Wed, 4 May 2016 14:27:23 +0200 +Subject: [PATCH] Fuel VM for the Enea Armband lab + +This is the initial VM description fit for Enea's Armband lab. + +Signed-off-by: Josep Puigdemont <josep.puigdemont@enea.com> +--- + .../hardware_environment/vms/enea_lab/fuel.xml | 88 ++++++++++++++++++++++ + 1 file changed, 88 insertions(+) + create mode 100644 deploy/templates/hardware_environment/vms/enea_lab/fuel.xml + +diff --git a/deploy/templates/hardware_environment/vms/enea_lab/fuel.xml b/deploy/templates/hardware_environment/vms/enea_lab/fuel.xml +new file mode 100644 +index 0000000..8773ed4 +--- /dev/null ++++ b/deploy/templates/hardware_environment/vms/enea_lab/fuel.xml +@@ -0,0 +1,88 @@ ++<domain type='kvm' id='1'> ++ <name>fuel</name> ++ <memory unit='KiB'>8290304</memory> ++ <currentMemory unit='KiB'>8290304</currentMemory> ++ <vcpu placement='static'>8</vcpu> ++ <resource> ++ <partition>/machine</partition> ++ </resource> ++ <os> ++ <type arch='x86_64' machine='pc-i440fx-rhel7.0.0'>hvm</type> ++ <boot dev='cdrom'/> ++ <boot dev='hd'/> ++ <bootmenu enable='no'/> ++ </os> ++ <features> ++ <acpi/> ++ <apic/> ++ <pae/> ++ </features> ++ <cpu mode='host-model'> ++ <model fallback='allow'/> ++ </cpu> ++ <clock offset='utc'> ++ <timer name='rtc' tickpolicy='catchup'/> ++ <timer name='pit' tickpolicy='delay'/> ++ <timer name='hpet' present='no'/> ++ </clock> ++ <on_poweroff>destroy</on_poweroff> ++ <on_reboot>restart</on_reboot> ++ <on_crash>restart</on_crash> ++ <pm> ++ <suspend-to-mem enabled='no'/> ++ <suspend-to-disk enabled='no'/> ++ </pm> ++ <devices> ++ <emulator>/usr/libexec/qemu-kvm</emulator> ++ <disk type='file' device='disk'> ++ <driver name='qemu' type='qcow2'/> ++ <target dev='vda' bus='virtio'/> ++ </disk> ++ <disk type='block' device='cdrom'> ++ <driver name='qemu' type='raw'/> ++ <target dev='hdb' bus='ide'/> ++ <readonly/> ++ </disk> ++ <controller type='usb' index='0' model='ich9-ehci1'> ++ </controller> ++ <controller type='usb' index='0' model='ich9-uhci1'> ++ <master startport='0'/> ++ </controller> ++ <controller type='usb' index='0' model='ich9-uhci2'> ++ <master startport='2'/> ++ </controller> ++ <controller type='usb' index='0' model='ich9-uhci3'> ++ <master startport='4'/> ++ </controller> ++ <controller type='pci' index='0' model='pci-root'> ++ </controller> ++ <controller type='ide' index='0'> ++ </controller> ++ <controller type='virtio-serial' index='0'> ++ </controller> ++ <interface type='bridge'> ++ <model type='virtio'/> ++ </interface> ++ <interface type='bridge'> ++ <model type='virtio'/> ++ </interface> ++ <serial type='pty'> ++ <source path='/dev/pts/0'/> ++ <target port='0'/> ++ </serial> ++ <console type='pty' tty='/dev/pts/0'> ++ <source path='/dev/pts/0'/> ++ <target type='serial' port='0'/> ++ </console> ++ <input type='mouse' bus='ps2'/> ++ <input type='keyboard' bus='ps2'/> ++ <graphics type='vnc' port='5906' autoport='yes' listen='127.0.0.1'> ++ <listen type='address' address='127.0.0.1'/> ++ </graphics> ++ <video> ++ <model type='vga' vram='16384' heads='1'/> ++ </video> ++ <memballoon model='virtio'> ++ </memballoon> ++ </devices> ++</domain> diff --git a/patches/opnfv-fuel/0026-f_repobuild-Repeat-mirror-build-up-to-ten-times.patch b/patches/opnfv-fuel/0026-f_repobuild-Repeat-mirror-build-up-to-ten-times.patch new file mode 100644 index 00000000..0b1f92f1 --- /dev/null +++ b/patches/opnfv-fuel/0026-f_repobuild-Repeat-mirror-build-up-to-ten-times.patch @@ -0,0 +1,73 @@ +From: Alexandru Avadanii <Alexandru.Avadanii@enea.com> +Date: Sun, 8 May 2016 22:37:43 +0200 +Subject: [PATCH] f_repobuild: Repeat mirror build up to ten times. + +OPNFV ISO build uses fuel-mirror to create a local Ubuntu +partial mirror in nailgun. + +Work around temporary mirror issue (e.g. during rsync) by +retrying mirror build up to 10 times. + +Signed-off-by: Alexandru Avadanii <Alexandru.Avadanii@enea.com> +--- + build/f_isoroot/f_repobuild/Makefile | 6 +++++- + build/f_isoroot/f_repobuild/fuel_mirror_loop | 26 ++++++++++++++++++++++++++ + 2 files changed, 31 insertions(+), 1 deletion(-) + create mode 100755 build/f_isoroot/f_repobuild/fuel_mirror_loop + +diff --git a/build/f_isoroot/f_repobuild/Makefile b/build/f_isoroot/f_repobuild/Makefile +index 5e7157b..9abe9bb 100644 +--- a/build/f_isoroot/f_repobuild/Makefile ++++ b/build/f_isoroot/f_repobuild/Makefile +@@ -23,6 +23,9 @@ export OPENSTACK_VERSION + .PHONY: all + all: nailgun + ++nailgun_mirror: ++ sudo fuel-mirror --debug --config ./opnfv-config.yaml create --group ubuntu --pattern=ubuntu ++ + nailgun: + sudo apt-get install -y git libxml2-dev libxslt-dev python-dev python-pip libz-dev libyaml-dev createrepo python-yaml + # python-debian from Ubuntu can't parse foreign arch relationships, use pip +@@ -35,7 +38,8 @@ nailgun: + sudo pip install ./fuel-mirror + sudo pip install ./fuel-mirror/contrib/fuel_mirror + ./opnfv_mirror_conf.py +- sudo fuel-mirror --debug --config ./opnfv-config.yaml create --group ubuntu --pattern=ubuntu ++ # Repeat mirror build up to ten times ++ sudo -E ./fuel_mirror_loop + sudo chmod -R 755 /var/www/nailgun + cp -Rp /var/www/nailgun . + # On the end we want to have ubuntu repository in mirrors/ubuntu directory +diff --git a/build/f_isoroot/f_repobuild/fuel_mirror_loop b/build/f_isoroot/f_repobuild/fuel_mirror_loop +new file mode 100755 +index 0000000..f123cf2 +--- /dev/null ++++ b/build/f_isoroot/f_repobuild/fuel_mirror_loop +@@ -0,0 +1,26 @@ ++#!/bin/bash ++############################################################################## ++# Copyright (c) 2016 Ericsson AB and others. ++# Copyright (c) 2016 Enea AB and others. ++# 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 ++############################################################################## ++ ++maxcount=10 ++cnt=0 ++rc=1 ++while [ $cnt -lt $maxcount ] && [ $rc -ne 0 ] ++do ++ cnt=$[cnt + 1] ++ echo -e "\n\n\n*** Starting mirror build attempt # $cnt" ++ make nailgun_mirror ++ rc=$? ++ if [ $rc -ne 0 ]; then ++ echo "### Mirror build failed with rc $rc ###" ++ else ++ echo "### Mirror build successful at attempt # $cnt" ++ fi ++done ++exit $rc |