summaryrefslogtreecommitdiff
path: root/morphlib/plugins/deploy_plugin.py
diff options
context:
space:
mode:
Diffstat (limited to 'morphlib/plugins/deploy_plugin.py')
-rw-r--r--morphlib/plugins/deploy_plugin.py85
1 files changed, 57 insertions, 28 deletions
diff --git a/morphlib/plugins/deploy_plugin.py b/morphlib/plugins/deploy_plugin.py
index 61b8145e..a80079fa 100644
--- a/morphlib/plugins/deploy_plugin.py
+++ b/morphlib/plugins/deploy_plugin.py
@@ -14,36 +14,40 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-import cliapp
-import contextlib
import json
+import logging
import os
import shutil
-import stat
+import sys
import tarfile
import tempfile
import uuid
+import cliapp
import morphlib
+
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',
+ 'existing cluster. Deprecated: use the '
+ '`morph upgrade` command instead',
group=group_deploy)
self.app.add_subcommand(
'deploy', self.deploy,
arg_synopsis='CLUSTER [DEPLOYMENT...] [SYSTEM.KEY=VALUE]')
+ self.app.add_subcommand(
+ 'upgrade', self.upgrade,
+ arg_synopsis='CLUSTER [DEPLOYMENT...] [SYSTEM.KEY=VALUE]')
def disable(self):
pass
def deploy(self, args):
- '''Deploy a built system image.
+ '''Deploy a built system image or a set of images.
Command line arguments:
@@ -300,8 +304,8 @@ class DeployPlugin(cliapp.Plugin):
if cluster_morphology['kind'] != 'cluster':
raise cliapp.AppException(
- "Error: morph deploy is only supported for cluster"
- " morphologies.")
+ "Error: morph deployment commands are only supported for "
+ "cluster morphologies.")
# parse the rest of the args
all_subsystems = set()
@@ -432,6 +436,25 @@ class DeployPlugin(cliapp.Plugin):
finally:
self.app.status_prefix = old_status_prefix
+ def upgrade(self, args):
+ '''Upgrade an existing set of instances using built images.
+
+ See `morph help deploy` for documentation.
+
+ '''
+
+ if not args:
+ raise cliapp.AppException(
+ 'Too few arguments to upgrade command (see `morph help '
+ 'deploy`)')
+
+ if self.app.settings['upgrade']:
+ raise cliapp.AppException(
+ 'Running `morph upgrade --upgrade` does not make sense.')
+
+ self.app.settings['upgrade'] = True
+ self.deploy(args)
+
def check_deploy(self, root_repo_dir, ref, 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
@@ -518,33 +541,39 @@ class DeployPlugin(cliapp.Plugin):
self.app.status(msg='Cleaning up')
shutil.rmtree(deploy_private_tempdir)
+ def _report_extension_stdout(self, line):
+ self.app.status(msg=line.replace('%s', '%%'))
+ def _report_extension_stderr(self, error_list):
+ def cb(line):
+ error_list.append(line)
+ sys.stderr.write('%s\n' % line)
+ return cb
+ def _report_extension_logger(self, name, kind):
+ return lambda line: logging.debug('%s%s: %s', name, kind, line)
def _run_extension(self, gd, name, kind, args, env):
'''Run an extension.
-
+
The ``kind`` should be either ``.configure`` or ``.write``,
depending on the kind of extension that is sought.
-
+
The extension is found either in the git repository of the
system morphology (repo, ref), or with the Morph code.
-
+
'''
- with morphlib.extensions.get_extension_filename(
- name, kind) as ext_filename:
- self.app.status(msg='Running extension %(name)s%(kind)s',
- name=name, kind=kind)
- self.app.runcmd(
- [ext_filename] + args,
- ['sh',
- '-c',
- 'while read l; do echo `date "+%F %T"` "$1$l"; done',
- '-',
- '%s[%s]' % (self.app.status_prefix, name + kind)],
- cwd=gd.dirname, env=env, stdout=None, stderr=None)
-
- def _is_executable(self, filename):
- st = os.stat(filename)
- mask = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
- return (stat.S_IMODE(st.st_mode) & mask) != 0
+ error_list = []
+ with morphlib.extensions.get_extension_filename(name, kind) as fn:
+ ext = morphlib.extensions.ExtensionSubprocess(
+ report_stdout=self._report_extension_stdout,
+ report_stderr=self._report_extension_stderr(error_list),
+ report_logger=self._report_extension_logger(name, kind),
+ )
+ returncode = ext.run(fn, args, env=env, cwd=gd.dirname)
+ if returncode == 0:
+ logging.info('%s%s succeeded', name, kind)
+ else:
+ message = '%s%s failed with code %s: %s' % (
+ name, kind, returncode, '\n'.join(error_list))
+ raise cliapp.AppException(message)
def create_metadata(self, system_artifact, root_repo_dir, deployment_type,
location, env):