aboutsummaryrefslogtreecommitdiffstats
path: root/patches/opnfv-fuel/upstream-backports/0005-CI-deploy-cache-Store-and-reuse-deploy-artifacts.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/opnfv-fuel/upstream-backports/0005-CI-deploy-cache-Store-and-reuse-deploy-artifacts.patch')
-rw-r--r--patches/opnfv-fuel/upstream-backports/0005-CI-deploy-cache-Store-and-reuse-deploy-artifacts.patch786
1 files changed, 0 insertions, 786 deletions
diff --git a/patches/opnfv-fuel/upstream-backports/0005-CI-deploy-cache-Store-and-reuse-deploy-artifacts.patch b/patches/opnfv-fuel/upstream-backports/0005-CI-deploy-cache-Store-and-reuse-deploy-artifacts.patch
deleted file mode 100644
index 9997dedf..00000000
--- a/patches/opnfv-fuel/upstream-backports/0005-CI-deploy-cache-Store-and-reuse-deploy-artifacts.patch
+++ /dev/null
@@ -1,786 +0,0 @@
-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-: Copyright (c) 2017 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
-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-From: Alexandru Avadanii <Alexandru.Avadanii@enea.com>
-Date: Thu, 24 Nov 2016 23:02:04 +0100
-Subject: [PATCH] CI: deploy-cache: Store and reuse deploy artifacts
-
-Add support for caching deploy artifacts, like bootstraps and
-target images, which take a lot of time at each deploy to be built,
-considering it requires a cross-debootstrap via qemu-user-static and
-binfmt.
-
-For OPNFV CI, the cache will piggy back on the <iso_mount> mechanism,
-and be located at:
-/iso_mount/opnfv_ci/<branch>/deploy-cache
-
-TODO: Use dea interface adapter in target images fingerprinting.
-TODO: remote fingerprinting
-TODO: differentiate between bootstraps and targetimages, so we don't
-end up trying to use one cache artifact type as the other.
-TODO: implement sanity checks for bootstrap and target images;
-TODO: switch `exec_cmd('mkdir ...')` to `create_dir_if_not_exists`;
-
-JIRA: ARMBAND-172
-JIRA: ARMBAND-242
-
-Signed-off-by: Alexandru Avadanii <Alexandru.Avadanii@enea.com>
----
- ...p_admin_node.sh-deploy_cache-install-hook.patch | 90 ++++++
- ci/deploy.sh | 14 +-
- deploy/cloud/configure_settings.py | 4 +
- deploy/cloud/deployment.py | 12 +
- deploy/deploy.py | 25 +-
- deploy/deploy_cache.py | 314 +++++++++++++++++++++
- deploy/deploy_env.py | 13 +-
- deploy/install_fuel_master.py | 9 +-
- 8 files changed, 472 insertions(+), 9 deletions(-)
- create mode 100644 build/f_repos/patch/fuel-main/0006-bootstrap_admin_node.sh-deploy_cache-install-hook.patch
- create mode 100644 deploy/deploy_cache.py
-
-diff --git a/build/f_repos/patch/fuel-main/0006-bootstrap_admin_node.sh-deploy_cache-install-hook.patch b/build/f_repos/patch/fuel-main/0006-bootstrap_admin_node.sh-deploy_cache-install-hook.patch
-new file mode 100644
-index 0000000..7acb746
---- /dev/null
-+++ b/build/f_repos/patch/fuel-main/0006-bootstrap_admin_node.sh-deploy_cache-install-hook.patch
-@@ -0,0 +1,90 @@
-+From: Alexandru Avadanii <Alexandru.Avadanii@enea.com>
-+Date: Mon, 28 Nov 2016 14:27:48 +0100
-+Subject: [PATCH] bootstrap_admin_node.sh: deploy_cache install hook
-+
-+Tooling on the automatic deploy side was updated to support deploy
-+caching of artifacts like bootstrap (and id_rsa keypair), target
-+images etc.
-+
-+Add installation hook that calls `fuel-bootstrap import` instead of
-+`build` when a bootstrap tar is available in the agreed location,
-+/var/lib/opnfv/cache/bootstraps/.
-+
-+Temporary until Fuel@Openstack fixes Master key propagation to nodes'
-+authorized_keys, use Mcollective remote shell execute to add it
-+during deployment.
-+This might duplicate the entry in authorized_keys during re-deploys.
-+
-+JIRA: ARMBAND-172
-+JIRA: ARMBAND-242
-+
-+Signed-off-by: Alexandru Avadanii <Alexandru.Avadanii@enea.com>
-+---
-+ iso/bootstrap_admin_node.sh | 35 ++++++++++++++++++++++++++++++++++-
-+ 1 file changed, 34 insertions(+), 1 deletion(-)
-+
-+diff --git a/iso/bootstrap_admin_node.sh b/iso/bootstrap_admin_node.sh
-+index 4f5ce4e..4c79552 100755
-+--- a/iso/bootstrap_admin_node.sh
-++++ b/iso/bootstrap_admin_node.sh
-+@@ -64,6 +64,8 @@ wget \
-+ ASTUTE_YAML='/etc/fuel/astute.yaml'
-+ BOOTSTRAP_NODE_CONFIG="/etc/fuel/bootstrap_admin_node.conf"
-+ CUSTOM_REPOS="/root/default_deb_repos.yaml"
-++OPNFV_CACHE_PATH="/var/cache/opnfv/bootstraps"
-++OPNFV_CACHE_TAR="opnfv-bootstraps-cache.tar"
-+ bs_build_log='/var/log/fuel-bootstrap-image-build.log'
-+ bs_status=0
-+ # Backup network configs to this folder. Folder will be created only if
-+@@ -97,6 +99,7 @@ image becomes available, reboot nodes that failed to be discovered."
-+ bs_done_message="Default bootstrap image building done. Now you can boot new \
-+ nodes over PXE, they will be discovered and become available for installing \
-+ OpenStack on them"
-++bs_cache_message="OPNFV deploy cache: bootstrap image injected."
-+ # Update issues messages
-+ update_warn_message="There is an issue connecting to update repository of \
-+ your distributions of OpenStack. \
-+@@ -509,12 +512,42 @@ set_ui_bootstrap_error () {
-+ EOF
-+ }
-+
-++function inject_cached_ssh_key () {
-++ # FIXME(armband): Propagate master ssh key to nodes'
-++ # authorized_keys, until upstream fixes this for image build.
-++ local moddir="/etc/puppet/${OPENSTACK_VERSION}/modules/osnailyfacter/modular"
-++ cat >> "${moddir}/astute/generate_keys.sh" <<-EOF
-++ mco rpc execute_shell_command execute \\
-++ cmd="echo $(cat /root/.ssh/id_rsa.pub) >> /root/.ssh/authorized_keys"
-++ EOF
-++}
-++
-++function inject_cached_ubuntu_bootstrap () {
-++ if [ -f "${OPNFV_CACHE_PATH}/${OPNFV_CACHE_TAR}" -a \
-++ -f "${OPNFV_CACHE_PATH}/id_rsa.pub" -a \
-++ -f "${OPNFV_CACHE_PATH}/id_rsa" ]; then
-++ if cp "${OPNFV_CACHE_PATH}/id_rsa"* "/root/.ssh/" && \
-++ cp "/root/.ssh/id_rsa.pub" "/root/.ssh/authorized_keys" && \
-++ cp "/root/.ssh/id_rsa.pub" "/etc/cobbler/authorized_keys" && \
-++ sed -i -e "s|\"ssh-rsa .*\"|\"$(cat /root/.ssh/id_rsa.pub)\"|g" \
-++ /etc/nailgun/settings.yaml && \
-++ fuel-bootstrap -v --debug import --activate \
-++ "${OPNFV_CACHE_PATH}/${OPNFV_CACHE_TAR}" >>"$bs_build_log" 2>&1; then
-++ inject_cached_ssh_key
-++ fuel notify --topic "done" --send "${bs_cache_message}"
-++ return 0
-++ fi
-++ fi
-++ return 1
-++}
-++
-+ # Actually build the bootstrap image
-+ build_ubuntu_bootstrap () {
-+ local ret=1
-+ echo ${bs_progress_message} >&2
-+ set_ui_bootstrap_error "${bs_progress_message}" >&2
-+- if fuel-bootstrap -v --debug build --target_arch arm64 --activate >>"$bs_build_log" 2>&1; then
-++ if inject_cached_ubuntu_bootstrap || fuel-bootstrap -v --debug \
-++ build --activate --target_arch arm64 >>"$bs_build_log" 2>&1; then
-+ ret=0
-+ fuel notify --topic "done" --send "${bs_done_message}"
-+ else
-diff --git a/ci/deploy.sh b/ci/deploy.sh
-index 081806c..4b1ae0e 100755
---- a/ci/deploy.sh
-+++ b/ci/deploy.sh
-@@ -29,7 +29,7 @@ cat << EOF
- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- `basename $0`: Deploys the Fuel@OPNFV stack
-
--usage: `basename $0` -b base-uri [-B PXE Bridge] [-f] [-F] [-H] -l lab-name -p pod-name -s deploy-scenario [-S image-dir] [-T timeout] -i iso
-+usage: `basename $0` -b base-uri [-B PXE Bridge] [-f] [-F] [-H] -l lab-name -p pod-name -s deploy-scenario [-S image-dir] [-C deploy-cache-dir] [-T timeout] -i iso
- -s deployment-scenario [-S optional Deploy-scenario path URI]
- [-R optional local relen repo (containing deployment Scenarios]
-
-@@ -47,6 +47,7 @@ OPTIONS:
- -p Pod-name
- -s Deploy-scenario short-name/base-file-name
- -S Storage dir for VM images
-+ -C Deploy cache dir for storing image artifacts
- -T Timeout, in minutes, for the deploy.
- -i iso url
-
-@@ -79,6 +80,7 @@ Input parameters to the build script is:
- or a deployment short-name as defined by scenario.yaml in the deployment
- scenario path.
- -S Storage dir for VM images, default is fuel/deploy/images
-+-C Deploy cache dir for bootstrap and target image artifacts, optional
- -T Timeout, in minutes, for the deploy. It defaults to using the DEPLOY_TIMEOUT
- environment variable when defined, or to the default in deploy.py otherwise
- -i .iso image to be deployed (needs to be provided in a URI
-@@ -116,6 +118,7 @@ FUEL_CREATION_ONLY=''
- NO_DEPLOY_ENVIRONMENT=''
- STORAGE_DIR=''
- DRY_RUN=0
-+DEPLOY_CACHE_DIR=''
- if ! [ -z $DEPLOY_TIMEOUT ]; then
- DEPLOY_TIMEOUT="-dt $DEPLOY_TIMEOUT"
- else
-@@ -128,7 +131,7 @@ fi
- ############################################################################
- # BEGIN of main
- #
--while getopts "b:B:dfFHl:L:p:s:S:T:i:he" OPTION
-+while getopts "b:B:dfFHl:L:p:s:S:C:T:i:he" OPTION
- do
- case $OPTION in
- b)
-@@ -179,6 +182,9 @@ do
- STORAGE_DIR="-s ${OPTARG}"
- fi
- ;;
-+ C)
-+ DEPLOY_CACHE_DIR="-dc ${OPTARG}"
-+ ;;
- T)
- DEPLOY_TIMEOUT="-dt ${OPTARG}"
- ;;
-@@ -243,8 +249,8 @@ if [ $DRY_RUN -eq 0 ]; then
- ISO=${SCRIPT_PATH}/ISO/image.iso
- fi
- # Start deployment
-- echo "python deploy.py $DEPLOY_LOG $STORAGE_DIR $PXE_BRIDGE $USE_EXISTING_FUEL $FUEL_CREATION_ONLY $NO_HEALTH_CHECK $NO_DEPLOY_ENVIRONMENT -dea ${SCRIPT_PATH}/config/dea.yaml -dha ${SCRIPT_PATH}/config/dha.yaml -iso $ISO $DEPLOY_TIMEOUT"
-- python deploy.py $DEPLOY_LOG $STORAGE_DIR $PXE_BRIDGE $USE_EXISTING_FUEL $FUEL_CREATION_ONLY $NO_HEALTH_CHECK $NO_DEPLOY_ENVIRONMENT -dea ${SCRIPT_PATH}/config/dea.yaml -dha ${SCRIPT_PATH}/config/dha.yaml -iso $ISO $DEPLOY_TIMEOUT
-+ echo "python deploy.py $DEPLOY_LOG $STORAGE_DIR $PXE_BRIDGE $USE_EXISTING_FUEL $FUEL_CREATION_ONLY $NO_HEALTH_CHECK $NO_DEPLOY_ENVIRONMENT -dea ${SCRIPT_PATH}/config/dea.yaml -dha ${SCRIPT_PATH}/config/dha.yaml -iso $ISO $DEPLOY_TIMEOUT $DEPLOY_CACHE_DIR"
-+ python deploy.py $DEPLOY_LOG $STORAGE_DIR $PXE_BRIDGE $USE_EXISTING_FUEL $FUEL_CREATION_ONLY $NO_HEALTH_CHECK $NO_DEPLOY_ENVIRONMENT -dea ${SCRIPT_PATH}/config/dea.yaml -dha ${SCRIPT_PATH}/config/dha.yaml -iso $ISO $DEPLOY_TIMEOUT $DEPLOY_CACHE_DIR
- fi
- popd > /dev/null
-
-diff --git a/deploy/cloud/configure_settings.py b/deploy/cloud/configure_settings.py
-index b60a60f..4e007e1 100644
---- a/deploy/cloud/configure_settings.py
-+++ b/deploy/cloud/configure_settings.py
-@@ -71,5 +71,9 @@ class ConfigureSettings(object):
- settings['editable'][plugin]['metadata']['chosen_id'] = orig_dea['editable'][plugin]['metadata']['chosen_id']
- settings['editable'][plugin]['metadata']['versions'][0]['metadata']['plugin_id'] = orig_dea['editable'][plugin]['metadata']['versions'][0]['metadata']['plugin_id']
-
-+ # deploy-cache req: pass master id_rsa.pub as authorized key
-+ with io.open('/root/.ssh/id_rsa.pub', 'r') as pkey:
-+ settings['editable']['operator_user']['authkeys']['value'] = pkey.read()
-+
- with io.open(settings_yaml, 'w') as stream:
- yaml.dump(settings, stream, default_flow_style=False)
-diff --git a/deploy/cloud/deployment.py b/deploy/cloud/deployment.py
-index 4329a4c..a84d46c 100644
---- a/deploy/cloud/deployment.py
-+++ b/deploy/cloud/deployment.py
-@@ -19,6 +19,8 @@ from common import (
- log,
- )
-
-+from deploy_cache import DeployCache
-+
- SEARCH_TEXT = '(err)'
- LOG_FILE = '/var/log/puppet.log'
- GREP_LINES_OF_LEADING_CONTEXT = 100
-@@ -51,6 +53,14 @@ class Deployment(object):
- self.pattern = re.compile(
- '\d\d\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d')
-
-+ def deploy_cache_install_targetimages(self):
-+ log('Using target images from deploy cache')
-+ DeployCache.install_targetimages_for_env(self.env_id)
-+
-+ def deploy_cache_extract_targetimages(self):
-+ log('Collecting Fuel target image files for deploy cache')
-+ DeployCache.extract_targetimages_from_env(self.env_id)
-+
- def collect_error_logs(self):
- for node_id, roles_blade in self.node_id_roles_dict.iteritems():
- log_list = []
-@@ -112,6 +122,7 @@ class Deployment(object):
- start = time.time()
-
- log('Starting deployment of environment %s' % self.env_id)
-+ self.deploy_cache_install_targetimages()
- deploy_id = None
- ready = False
- timeout = False
-@@ -144,6 +155,7 @@ class Deployment(object):
- err('Deployment timed out, environment %s is not operational, '
- 'snapshot will not be performed'
- % self.env_id)
-+ self.deploy_cache_extract_targetimages()
- if ready:
- log('Environment %s successfully deployed'
- % self.env_id)
-diff --git a/deploy/deploy.py b/deploy/deploy.py
-index 7648baf..ee3cb7a 100755
---- a/deploy/deploy.py
-+++ b/deploy/deploy.py
-@@ -22,6 +22,7 @@ from dea import DeploymentEnvironmentAdapter
- from dha import DeploymentHardwareAdapter
- from install_fuel_master import InstallFuelMaster
- from deploy_env import CloudDeploy
-+from deploy_cache import DeployCache
- from execution_environment import ExecutionEnvironment
-
- from common import (
-@@ -61,7 +62,8 @@ class AutoDeploy(object):
- def __init__(self, no_fuel, fuel_only, no_health_check, cleanup_only,
- cleanup, storage_dir, pxe_bridge, iso_file, dea_file,
- dha_file, fuel_plugins_dir, fuel_plugins_conf_dir,
-- no_plugins, deploy_timeout, no_deploy_environment, deploy_log):
-+ no_plugins, deploy_cache_dir, deploy_timeout,
-+ no_deploy_environment, deploy_log):
- self.no_fuel = no_fuel
- self.fuel_only = fuel_only
- self.no_health_check = no_health_check
-@@ -75,6 +77,7 @@ class AutoDeploy(object):
- self.fuel_plugins_dir = fuel_plugins_dir
- self.fuel_plugins_conf_dir = fuel_plugins_conf_dir
- self.no_plugins = no_plugins
-+ self.deploy_cache_dir = deploy_cache_dir
- self.deploy_timeout = deploy_timeout
- self.no_deploy_environment = no_deploy_environment
- self.deploy_log = deploy_log
-@@ -116,7 +119,7 @@ class AutoDeploy(object):
- self.fuel_username, self.fuel_password,
- self.dea_file, self.fuel_plugins_conf_dir,
- WORK_DIR, self.no_health_check,
-- self.deploy_timeout,
-+ self.deploy_cache_dir, self.deploy_timeout,
- self.no_deploy_environment, self.deploy_log)
- with old_dep.ssh:
- old_dep.check_previous_installation()
-@@ -128,6 +131,7 @@ class AutoDeploy(object):
- self.fuel_conf['ip'], self.fuel_username,
- self.fuel_password, self.fuel_node_id,
- self.iso_file, WORK_DIR,
-+ self.deploy_cache_dir,
- self.fuel_plugins_dir, self.no_plugins)
- fuel.install()
-
-@@ -136,6 +140,7 @@ class AutoDeploy(object):
- tmp_new_dir = '%s/newiso' % self.tmp_dir
- try:
- self.copy(tmp_orig_dir, tmp_new_dir)
-+ self.deploy_cache_fingerprints(tmp_new_dir)
- self.patch(tmp_new_dir, new_iso)
- except Exception as e:
- exec_cmd('fusermount -u %s' % tmp_orig_dir, False)
-@@ -156,6 +161,12 @@ class AutoDeploy(object):
- delete(tmp_orig_dir)
- exec_cmd('chmod -R 755 %s' % tmp_new_dir)
-
-+ def deploy_cache_fingerprints(self, tmp_new_dir):
-+ if self.deploy_cache_dir:
-+ log('Deploy cache: Collecting fingerprints...')
-+ deploy_cache = DeployCache(self.deploy_cache_dir)
-+ deploy_cache.do_fingerprints(tmp_new_dir, self.dea_file)
-+
- def patch(self, tmp_new_dir, new_iso):
- log('Patching...')
- patch_dir = '%s/%s' % (CWD, PATCH_DIR)
-@@ -218,7 +229,8 @@ class AutoDeploy(object):
- dep = CloudDeploy(self.dea, self.dha, self.fuel_conf['ip'],
- self.fuel_username, self.fuel_password,
- self.dea_file, self.fuel_plugins_conf_dir,
-- WORK_DIR, self.no_health_check, self.deploy_timeout,
-+ WORK_DIR, self.no_health_check,
-+ self.deploy_cache_dir, self.deploy_timeout,
- self.no_deploy_environment, self.deploy_log)
- return dep.deploy()
-
-@@ -343,6 +355,8 @@ def parse_arguments():
- help='Fuel Plugins Configuration directory')
- parser.add_argument('-np', dest='no_plugins', action='store_true',
- default=False, help='Do not install Fuel Plugins')
-+ parser.add_argument('-dc', dest='deploy_cache_dir', action='store',
-+ help='Deploy Cache Directory')
- parser.add_argument('-dt', dest='deploy_timeout', action='store',
- default=240, help='Deployment timeout (in minutes) '
- '[default: 240]')
-@@ -376,6 +390,10 @@ def parse_arguments():
- for bridge in args.pxe_bridge:
- check_bridge(bridge, args.dha_file)
-
-+ if args.deploy_cache_dir:
-+ log('Using deploy cache directory: %s' % args.deploy_cache_dir)
-+ create_dir_if_not_exists(args.deploy_cache_dir)
-+
-
- kwargs = {'no_fuel': args.no_fuel, 'fuel_only': args.fuel_only,
- 'no_health_check': args.no_health_check,
-@@ -386,6 +404,7 @@ def parse_arguments():
- 'fuel_plugins_dir': args.fuel_plugins_dir,
- 'fuel_plugins_conf_dir': args.fuel_plugins_conf_dir,
- 'no_plugins': args.no_plugins,
-+ 'deploy_cache_dir': args.deploy_cache_dir,
- 'deploy_timeout': args.deploy_timeout,
- 'no_deploy_environment': args.no_deploy_environment,
- 'deploy_log': args.deploy_log}
-diff --git a/deploy/deploy_cache.py b/deploy/deploy_cache.py
-new file mode 100644
-index 0000000..30bfe30
---- /dev/null
-+++ b/deploy/deploy_cache.py
-@@ -0,0 +1,314 @@
-+###############################################################################
-+# Copyright (c) 2016 Enea AB and others.
-+# Alexandru.Avadanii@enea.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
-+###############################################################################
-+
-+import glob
-+import hashlib
-+import io
-+import json
-+import os
-+import shutil
-+import yaml
-+
-+from common import (
-+ exec_cmd,
-+ log,
-+)
-+
-+###############################################################################
-+# Deploy Cache Flow Overview
-+###############################################################################
-+# 1. do_fingerprints
-+# Can be called as soon as a Fuel Master ISO chroot is available.
-+# This will gather all required information for uniquely identifying the
-+# objects in cache (bootstraps, targetimages).
-+# 2. inject_cache
-+# Can be called as soon as we have a steady SSH connection to the Fuel
-+# Master node. It will inject cached artifacts over SSH, for later install.
-+# 3. (external, async) install cached bootstrap instead of building a new one
-+# /sbin/bootstrap_admin_node.sh will check for cached bootstrap images
-+# (with id_rsa, id_rsa.pub attached) and will install those via
-+# $ fuel-bootstrap import opfnv-bootstraps-cache.tar
-+# 4. install_targetimages_for_env
-+# Should be called before cloud deploy is started, to install env-generic
-+# 'env_X_...' cached images for the current environment ID.
-+# Static method, to be used on the remote Fuel Master node; does not require
-+# access to the deploy cache, it only moves around some local files.
-+# 5. extract_targetimages_from_env
-+# Should be called at env deploy finish, to prepare artifacts for caching.
-+# Static method, same observations as above apply.
-+# 6. collect_artifacts
-+# Call last, to collect all artifacts.
-+###############################################################################
-+
-+###############################################################################
-+# Deploy cache artifacts:
-+# - id_rsa
-+# - bootstrap image (Ubuntu)
-+# - environment target image (Ubuntu)
-+###############################################################################
-+# Cache fingerprint covers:
-+# - bootstrap:
-+# - local mirror contents
-+# - FIXME(armband): [disabled] package list (old fuel_bootstrap_cli.yaml)
-+# - target image:
-+# - local mirror contents
-+# - package list (determined from DEA)
-+###############################################################################
-+# WARN: Cache fingerprint does NOT yet cover:
-+# - image_data (always assume the default /boot, /);
-+# - output_dir (always assume the default /var/www/nailgun/targetimages;
-+# - codename (always assume the default, currently 'trusty');
-+# - extra_dirs: /usr/share/fuel_bootstrap_cli/files/trusty
-+# - root_ssh_authorized_file, inluding the contents of /root/.ssh/id_rsa.pub
-+# - Auxiliary repo .../mitaka-9.0/ubuntu/auxiliary
-+# If the above change without triggering a cache miss, try clearing the cache.
-+###############################################################################
-+# WARN: Bootstrap caching implies RSA keypair to be reused!
-+###############################################################################
-+
-+# Local mirrros will be used on Fuel Master for both bootstrap and target image
-+# build, from `http://127.0.0.1:8080/...` or `http://10.20.0.2:8080/...`:
-+# - MOS .../mitaka-9.0/ubuntu/x86_64
-+# - Ubuntu .../mirrors/ubuntu/
-+# All these reside on Fuel Master at local path:
-+NAILGUN_PATH = '/var/www/nailgun/'
-+
-+# Artifact names (corresponding to nailgun subdirs)
-+MIRRORS = 'mirrors'
-+BOOTSTRAPS = 'bootstraps'
-+TARGETIMAGES = 'targetimages'
-+
-+# Info for collecting RSA keypair
-+RSA_KEYPAIR_PATH = '/root/.ssh'
-+RSA_KEYPAIR_FILES = ['id_rsa', 'id_rsa.pub']
-+
-+# Relative path for collecting the active bootstrap image(s) after env deploy
-+NAILGUN_ACT_BOOTSTRAP_SUBDIR = '%s/active_bootstrap' % BOOTSTRAPS
-+
-+# Relative path for collecting target image(s) for deployed enviroment
-+NAILGUN_TIMAGES_SUBDIR = TARGETIMAGES
-+
-+# FIXME(armband): re-include package list (old fuel_bootstrap_cli.yaml)
-+# ISO_BOOTSTRAP_CLI_YAML = '/opnfv/fuel_bootstrap_cli.yaml'
-+
-+# OPNFV Deploy Cache path on Fuel Master, where artifacts will be injected
-+REMOTE_CACHE_PATH = '/var/cache/opnfv'
-+
-+# OPNFV Bootstrap Cache tar archive name, to be used by bootstrap_admin_node.sh
-+BOOTSTRAP_ARCHIVE = 'opnfv-bootstraps-cache.tar'
-+
-+# Env-ID indep prefix
-+ENVX = 'env_X_'
-+
-+class DeployCache(object):
-+ """OPNFV Deploy Cache - managed storage for cacheable artifacts"""
-+
-+ def __init__(self, cache_dir,
-+ fingerprints_yaml='deploy_cache_fingerprints.yaml'):
-+ self.cache_dir = cache_dir
-+ self.fingerprints_yaml = fingerprints_yaml
-+ self.fingerprints = {BOOTSTRAPS: None,
-+ MIRRORS: None,
-+ TARGETIMAGES: None}
-+
-+ def __load_fingerprints(self):
-+ """Load deploy cache yaml config holding fingerprints"""
-+ if os.path.isfile(self.fingerprints_yaml):
-+ cache_fingerprints = open(self.fingerprints_yaml).read()
-+ self.fingerprints = yaml.load(cache_fingerprints)
-+
-+ def __save_fingerprints(self):
-+ """Update deploy cache yaml config holding fingerprints"""
-+ with open(self.fingerprints_yaml, 'w') as outfile:
-+ outfile.write(yaml.safe_dump(self.fingerprints,
-+ default_flow_style=False))
-+
-+ def __fingerprint_mirrors(self, chroot_path):
-+ """Collect repo mirror fingerprints"""
-+ deb_packages = list()
-+ # Scan ISO for deb files (MOS mirror + Ubuntu mirror, no plugins)
-+ for repo_dir in ['ubuntu', 'opnfv/nailgun/mirrors/ubuntu']:
-+ for _, _, files in os.walk(os.path.join(chroot_path, repo_dir)):
-+ for fdeb in files:
-+ if fdeb.endswith(".deb"):
-+ deb_packages.append(fdeb)
-+ sorted_debs = json.dumps(deb_packages, sort_keys=True)
-+ self.fingerprints[MIRRORS] = hashlib.sha1(sorted_debs).hexdigest()
-+
-+ def __fingerprint_bootstrap(self, chroot_path):
-+ """Collect bootstrap image metadata fingerprints"""
-+ # FIXME(armband): include 'extra_dirs' contents
-+ sorted_data = ''
-+ # FIXME(armband): re-include package list (old fuel_bootstrap_cli.yaml)
-+ # cli_yaml_path = os.path.join(chroot_path, ISO_BOOTSTRAP_CLI_YAML[1:])
-+ # bootstrap_cli_yaml = open(cli_yaml_path).read()
-+ # bootstrap_data = yaml.load(bootstrap_cli_yaml)
-+ # sorted_data = json.dumps(bootstrap_data, sort_keys=True)
-+ self.fingerprints[BOOTSTRAPS] = hashlib.sha1(sorted_data).hexdigest()
-+
-+ def __fingerprint_target(self, dea_file):
-+ """Collect target image metadata fingerprints"""
-+ # FIXME(armband): include 'image_data', 'codename', 'output'
-+ with io.open(dea_file) as stream:
-+ dea = yaml.load(stream)
-+ editable = dea['settings']['editable']
-+ target_data = {'packages': editable['provision']['packages'],
-+ 'repos': editable['repo_setup']['repos']}
-+ s_data = json.dumps(target_data, sort_keys=True)
-+ self.fingerprints[TARGETIMAGES] = hashlib.sha1(s_data).hexdigest()
-+
-+ def do_fingerprints(self, chroot_path, dea_file):
-+ """Collect SHA1 fingerprints based on chroot contents, DEA settings"""
-+ try:
-+ self.__load_fingerprints()
-+ self.__fingerprint_mirrors(chroot_path)
-+ self.__fingerprint_bootstrap(chroot_path)
-+ self.__fingerprint_target(dea_file)
-+ self.__save_fingerprints()
-+ except Exception as ex:
-+ log('Failed to get cache fingerprint: %s' % str(ex))
-+
-+ def __lookup_cache(self, sha):
-+ """Search for object in cache based on SHA fingerprint"""
-+ cache_sha_dir = os.path.join(self.cache_dir, sha)
-+ if not os.path.isdir(cache_sha_dir) or not os.listdir(cache_sha_dir):
-+ return None
-+ return cache_sha_dir
-+
-+ def __inject_cache_dir(self, ssh, sha, artifact):
-+ """Stage cached object (dir) in Fuel Master OPNFV local cache"""
-+ local_path = self.__lookup_cache(sha)
-+ if local_path:
-+ remote_path = os.path.join(REMOTE_CACHE_PATH, artifact)
-+ with ssh:
-+ ssh.exec_cmd('mkdir -p %s' % remote_path)
-+ for cachedfile in glob.glob('%s/*' % local_path):
-+ ssh.scp_put(cachedfile, remote_path)
-+ return local_path
-+
-+ def __mix_fingerprints(self, f1, f2):
-+ """Compute composite fingerprint"""
-+ if self.fingerprints[f1] is None or self.fingerprints[f2] is None:
-+ return None
-+ return hashlib.sha1('%s%s' %
-+ (self.fingerprints[f1], self.fingerprints[f2])).hexdigest()
-+
-+ def inject_cache(self, ssh):
-+ """Lookup artifacts in cache and inject them over SSH/SCP into Fuel"""
-+ try:
-+ self.__load_fingerprints()
-+ for artifact in [BOOTSTRAPS, TARGETIMAGES]:
-+ sha = self.__mix_fingerprints(MIRRORS, artifact)
-+ if sha is None:
-+ log('Missing fingerprint for: %s' % artifact)
-+ continue
-+ if not self.__inject_cache_dir(ssh, sha, artifact):
-+ log('SHA1 not in cache: %s (%s)' % (str(sha), artifact))
-+ else:
-+ log('SHA1 injected: %s (%s)' % (str(sha), artifact))
-+ except Exception as ex:
-+ log('Failed to inject cached artifacts into Fuel: %s' % str(ex))
-+
-+ def __extract_bootstraps(self, ssh, cache_sha_dir):
-+ """Collect bootstrap artifacts from Fuel over SSH/SCP"""
-+ remote_tar = os.path.join(REMOTE_CACHE_PATH, BOOTSTRAP_ARCHIVE)
-+ local_tar = os.path.join(cache_sha_dir, BOOTSTRAP_ARCHIVE)
-+ with ssh:
-+ for k in RSA_KEYPAIR_FILES:
-+ ssh.scp_get(os.path.join(RSA_KEYPAIR_PATH, k),
-+ local=os.path.join(cache_sha_dir, k))
-+ ssh.exec_cmd('mkdir -p %s && cd %s && tar cf %s *' %
-+ (REMOTE_CACHE_PATH,
-+ os.path.join(NAILGUN_PATH, NAILGUN_ACT_BOOTSTRAP_SUBDIR),
-+ remote_tar))
-+ ssh.scp_get(remote_tar, local=local_tar)
-+ ssh.exec_cmd('rm -f %s' % remote_tar)
-+
-+ def __extract_targetimages(self, ssh, cache_sha_dir):
-+ """Collect target image artifacts from Fuel over SSH/SCP"""
-+ cti_path = os.path.join(REMOTE_CACHE_PATH, TARGETIMAGES)
-+ with ssh:
-+ ssh.scp_get('%s/%s*' % (cti_path, ENVX), local=cache_sha_dir)
-+
-+ def collect_artifacts(self, ssh):
-+ """Collect artifacts from Fuel over SSH/SCP and add them to cache"""
-+ try:
-+ self.__load_fingerprints()
-+ for artifact, func in {
-+ BOOTSTRAPS: self.__extract_bootstraps,
-+ TARGETIMAGES: self.__extract_targetimages
-+ }.iteritems():
-+ sha = self.__mix_fingerprints(MIRRORS, artifact)
-+ if sha is None:
-+ log('WARN: Skip caching, NO fingerprint: %s' % artifact)
-+ continue
-+ local_path = self.__lookup_cache(sha)
-+ if local_path:
-+ log('SHA1 already in cache: %s (%s)' % (str(sha), artifact))
-+ else:
-+ log('New cache SHA1: %s (%s)' % (str(sha), artifact))
-+ cache_sha_dir = os.path.join(self.cache_dir, sha)
-+ exec_cmd('mkdir -p %s' % cache_sha_dir)
-+ func(ssh, cache_sha_dir)
-+ except Exception as ex:
-+ log('Failed to extract artifacts from Fuel: %s' % str(ex))
-+
-+ @staticmethod
-+ def extract_targetimages_from_env(env_id):
-+ """Prepare targetimages from env ID for storage in deploy cache
-+
-+ NOTE: This method should be executed locally ON the Fuel Master node.
-+ WARN: This method overwrites targetimages cache on Fuel Master node.
-+ """
-+ env_n = 'env_%s_' % str(env_id)
-+ cti_path = os.path.join(REMOTE_CACHE_PATH, TARGETIMAGES)
-+ ti_path = os.path.join(NAILGUN_PATH, NAILGUN_TIMAGES_SUBDIR)
-+ try:
-+ exec_cmd('rm -rf %s && mkdir -p %s' % (cti_path, cti_path))
-+ for root, _, files in os.walk(ti_path):
-+ for tif in files:
-+ if tif.startswith(env_n):
-+ src = os.path.join(root, tif)
-+ dest = os.path.join(cti_path, tif.replace(env_n, ENVX))
-+ if tif.endswith('.yaml'):
-+ shutil.copy(src, dest)
-+ exec_cmd('sed -i "s|%s|%s|g" %s' %
-+ (env_n, ENVX, dest))
-+ else:
-+ os.link(src, dest)
-+ except Exception as ex:
-+ log('Failed to extract targetimages artifacts from env %s: %s' %
-+ (str(env_id), str(ex)))
-+
-+ @staticmethod
-+ def install_targetimages_for_env(env_id):
-+ """Install targetimages artifacts for a specific env ID
-+
-+ NOTE: This method should be executed locally ON the Fuel Master node.
-+ """
-+ env_n = 'env_%s_' % str(env_id)
-+ cti_path = os.path.join(REMOTE_CACHE_PATH, TARGETIMAGES)
-+ ti_path = os.path.join(NAILGUN_PATH, NAILGUN_TIMAGES_SUBDIR)
-+ if not os.path.isdir(cti_path):
-+ log('%s cache dir not found: %s' % (TARGETIMAGES, cti_path))
-+ else:
-+ try:
-+ for root, _, files in os.walk(cti_path):
-+ for tif in files:
-+ src = os.path.join(root, tif)
-+ dest = os.path.join(ti_path, tif.replace(ENVX, env_n))
-+ if tif.endswith('.yaml'):
-+ shutil.copy(src, dest)
-+ exec_cmd('sed -i "s|%s|%s|g" %s' %
-+ (ENVX, env_n, dest))
-+ else:
-+ os.link(src, dest)
-+ except Exception as ex:
-+ log('Failed to install targetimages for env %s: %s' %
-+ (str(env_id), str(ex)))
-diff --git a/deploy/deploy_env.py b/deploy/deploy_env.py
-index d374cce..445070a 100644
---- a/deploy/deploy_env.py
-+++ b/deploy/deploy_env.py
-@@ -15,6 +15,7 @@ import glob
- import time
- import shutil
-
-+from deploy_cache import DeployCache
- from ssh_client import SSHClient
-
- from common import (
-@@ -35,7 +36,8 @@ class CloudDeploy(object):
-
- def __init__(self, dea, dha, fuel_ip, fuel_username, fuel_password,
- dea_file, fuel_plugins_conf_dir, work_dir, no_health_check,
-- deploy_timeout, no_deploy_environment, deploy_log):
-+ deploy_cache_dir, deploy_timeout,
-+ no_deploy_environment, deploy_log):
- self.dea = dea
- self.dha = dha
- self.fuel_ip = fuel_ip
-@@ -49,6 +51,8 @@ class CloudDeploy(object):
- self.fuel_plugins_conf_dir = fuel_plugins_conf_dir
- self.work_dir = work_dir
- self.no_health_check = no_health_check
-+ self.deploy_cache = ( DeployCache(deploy_cache_dir)
-+ if deploy_cache_dir else None )
- self.deploy_timeout = deploy_timeout
- self.no_deploy_environment = no_deploy_environment
- self.deploy_log = deploy_log
-@@ -82,9 +86,14 @@ class CloudDeploy(object):
- self.work_dir, os.path.basename(self.dea_file)))
- s.scp_put('%s/common.py' % self.file_dir, self.work_dir)
- s.scp_put('%s/dea.py' % self.file_dir, self.work_dir)
-+ s.scp_put('%s/deploy_cache.py' % self.file_dir, self.work_dir)
- for f in glob.glob('%s/cloud/*' % self.file_dir):
- s.scp_put(f, self.work_dir)
-
-+ def deploy_cache_collect_artifacts(self):
-+ if self.deploy_cache:
-+ self.deploy_cache.collect_artifacts(self.ssh)
-+
- def power_off_nodes(self):
- for node_id in self.node_ids:
- self.dha.node_power_off(node_id)
-@@ -281,4 +290,6 @@ class CloudDeploy(object):
-
- self.get_put_deploy_log()
-
-+ self.deploy_cache_collect_artifacts()
-+
- return rc
-diff --git a/deploy/install_fuel_master.py b/deploy/install_fuel_master.py
-index b731c6b..83d31fb 100644
---- a/deploy/install_fuel_master.py
-+++ b/deploy/install_fuel_master.py
-@@ -10,6 +10,7 @@
- import time
- import os
- import glob
-+from deploy_cache import DeployCache
- from ssh_client import SSHClient
- from dha_adapters.libvirt_adapter import LibvirtAdapter
-
-@@ -32,7 +33,7 @@ class InstallFuelMaster(object):
-
- def __init__(self, dea_file, dha_file, fuel_ip, fuel_username,
- fuel_password, fuel_node_id, iso_file, work_dir,
-- fuel_plugins_dir, no_plugins):
-+ deploy_cache_dir, fuel_plugins_dir, no_plugins):
- self.dea_file = dea_file
- self.dha = LibvirtAdapter(dha_file)
- self.fuel_ip = fuel_ip
-@@ -42,6 +43,8 @@ class InstallFuelMaster(object):
- self.iso_file = iso_file
- self.iso_dir = os.path.dirname(self.iso_file)
- self.work_dir = work_dir
-+ self.deploy_cache = ( DeployCache(deploy_cache_dir)
-+ if deploy_cache_dir else None )
- self.fuel_plugins_dir = fuel_plugins_dir
- self.no_plugins = no_plugins
- self.file_dir = os.path.dirname(os.path.realpath(__file__))
-@@ -83,6 +86,10 @@ class InstallFuelMaster(object):
- log('Wait until Fuel menu is up')
- fuel_menu_pid = self.wait_until_fuel_menu_up()
-
-+ if self.deploy_cache:
-+ log('Deploy cache: Injecting bootstraps and targetimages')
-+ self.deploy_cache.inject_cache(self.ssh)
-+
- log('Inject our own astute.yaml and fuel_bootstrap_cli.yaml settings')
- self.inject_own_astute_and_bootstrap_yaml()
-