summaryrefslogtreecommitdiff
path: root/morphlib/plugins/deploy_plugin.py
diff options
context:
space:
mode:
authorSam Thursfield <sam.thursfield@codethink.co.uk>2014-03-04 15:16:49 +0000
committerSam Thursfield <sam.thursfield@codethink.co.uk>2014-03-04 15:16:49 +0000
commitc0c53376133fea500a754560921887b60feee2a2 (patch)
tree89701f1c63a11da664cebd11185bc00f2ab75d32 /morphlib/plugins/deploy_plugin.py
parenteec2d313ea2381427774b7256120a008565aa448 (diff)
parent5843afcd9bc657479aca06419d0c0427f73c9ef4 (diff)
downloadmorph-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.py79
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