diff options
Diffstat (limited to 'morphlib/plugins')
-rw-r--r-- | morphlib/plugins/deploy_plugin.py | 85 |
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): |