diff options
author | Sam Thursfield <sam.thursfield@codethink.co.uk> | 2014-03-04 15:16:49 +0000 |
---|---|---|
committer | Sam Thursfield <sam.thursfield@codethink.co.uk> | 2014-03-04 15:16:49 +0000 |
commit | c0c53376133fea500a754560921887b60feee2a2 (patch) | |
tree | 89701f1c63a11da664cebd11185bc00f2ab75d32 /morphlib/plugins/deploy_plugin.py | |
parent | eec2d313ea2381427774b7256120a008565aa448 (diff) | |
parent | 5843afcd9bc657479aca06419d0c0427f73c9ef4 (diff) | |
download | morph-c0c53376133fea500a754560921887b60feee2a2.tar.gz |
Merge branch 'upgrades-v5'
Reviewed-By: Richard Maw <richard.maw@codethink.co.uk>
Diffstat (limited to 'morphlib/plugins/deploy_plugin.py')
-rw-r--r-- | morphlib/plugins/deploy_plugin.py | 79 |
1 files changed, 78 insertions, 1 deletions
diff --git a/morphlib/plugins/deploy_plugin.py b/morphlib/plugins/deploy_plugin.py index e8f1d217..61e1b5a4 100644 --- a/morphlib/plugins/deploy_plugin.py +++ b/morphlib/plugins/deploy_plugin.py @@ -16,6 +16,7 @@ import cliapp import contextlib +import json import os import shutil import stat @@ -33,9 +34,20 @@ import morphlib import morphlib.plugins.branch_and_merge_plugin +class ExtensionNotFoundError(morphlib.Error): + pass + + class DeployPlugin(cliapp.Plugin): def enable(self): + group_deploy = 'Deploy Options' + self.app.settings.boolean(['upgrade'], + 'specify that you want to upgrade an ' + 'existing cluster of systems rather than do ' + 'an initial deployment', + group=group_deploy) + self.app.add_subcommand( 'deploy', self.deploy, arg_synopsis='CLUSTER [SYSTEM.KEY=VALUE]') @@ -250,6 +262,13 @@ class DeployPlugin(cliapp.Plugin): are set as environment variables when either the configuration or the write extension runs (except `type` and `location`). + Deployment configuration is stored in the deployed system as + /baserock/deployment.meta. THIS CONTAINS ALL ENVIRONMENT VARIABLES SET + DURINGR DEPLOYMENT, so make sure you have no sensitive information in + your environment that is being leaked. As a special case, any + environment/deployment variable that contains 'PASSWORD' in its name is + stripped out and not stored in the final system. + ''' if not args: @@ -348,6 +367,9 @@ class DeployPlugin(cliapp.Plugin): deploy_params.items() + user_env.items()) + is_upgrade = 'yes' if self.app.settings['upgrade'] else 'no' + final_env['UPGRADE'] = is_upgrade + deployment_type = final_env.pop('type', None) if not deployment_type: raise morphlib.Error('"type" is undefined ' @@ -364,6 +386,15 @@ class DeployPlugin(cliapp.Plugin): def do_deploy(self, build_command, root_repo_dir, ref, artifact, deployment_type, location, env): + # Run optional write check extension. These are separate from the write + # extension because it may be several minutes before the write + # extension itself has the chance to raise an error. + try: + self._run_extension( + root_repo_dir, ref, deployment_type, '.check', + [location], env) + except ExtensionNotFoundError: + pass # Create a tempdir for this deployment to work in deploy_tempdir = tempfile.mkdtemp( @@ -396,6 +427,14 @@ class DeployPlugin(cliapp.Plugin): msg='System unpacked at %(system_tree)s', system_tree=system_tree) + self.app.status( + msg='Writing deployment metadata file') + metadata = self.create_metadata( + artifact, root_repo_dir, deployment_type, location, env) + metadata_path = os.path.join( + system_tree, 'baserock', 'deployment.meta') + with morphlib.savefile.SaveFile(metadata_path, 'w') as f: + f.write(json.dumps(metadata, indent=4, sort_keys=True)) # Run configuration extensions. self.app.status(msg='Configure system') @@ -445,7 +484,7 @@ class DeployPlugin(cliapp.Plugin): code_dir = os.path.dirname(morphlib.__file__) ext_filename = os.path.join(code_dir, 'exts', name + kind) if not os.path.exists(ext_filename): - raise morphlib.Error( + raise ExtensionNotFoundError( 'Could not find extension %s%s' % (name, kind)) if not self._is_executable(ext_filename): raise morphlib.Error( @@ -473,3 +512,41 @@ class DeployPlugin(cliapp.Plugin): st = os.stat(filename) mask = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH return (stat.S_IMODE(st.st_mode) & mask) != 0 + + def create_metadata(self, system_artifact, root_repo_dir, deployment_type, + location, env): + '''Deployment-specific metadata. + + The `build` and `deploy` operations must be from the same ref, so full + info on the root repo that the system came from is in + /baserock/${system_artifact}.meta and is not duplicated here. We do + store a `git describe` of the definitions.git repo as a convenience for + post-upgrade hooks that we may need to implement at a future date: + the `git describe` output lists the last tag, which will hopefully help + us to identify which release of a system was deployed without having to + keep a list of SHA1s somewhere or query a Trove. + + ''' + + def remove_passwords(env): + def is_password(key): + return 'PASSWORD' in key + return { k:v for k, v in env.iteritems() if not is_password(k) } + + meta = { + 'system-artifact-name': system_artifact.name, + 'configuration': remove_passwords(env), + 'deployment-type': deployment_type, + 'location': location, + 'definitions-version': { + 'describe': root_repo_dir.describe(), + }, + 'morph-version': { + 'ref': morphlib.gitversion.ref, + 'tree': morphlib.gitversion.tree, + 'commit': morphlib.gitversion.commit, + 'version': morphlib.gitversion.version, + }, + } + + return meta |