From 7d4e3541bbe9257ea045ad97220b21dc37982a84 Mon Sep 17 00:00:00 2001 From: Daniel Silverman Date: Fri, 8 Nov 2013 15:44:11 -0500 Subject: [PATCH] Compatibility changes for Cement 2.1, global scope Various changes to accomodate Cement 2.1. Using hooks for registry loading and scope setting. Fixing various scoping corner cases. --- bin/nepho | 5 +- nepho/cli/__init__.py | 3 +- nepho/cli/base.py | 44 +------ nepho/cli/blueprint.py | 50 +++----- nepho/cli/cloudlet.py | 151 +++++++++++------------- nepho/cli/config.py | 25 ++-- nepho/cli/hooks.py | 58 ++++++++++ nepho/cli/parameter.py | 6 +- nepho/cli/scope.py | 53 +++++---- nepho/cli/stack.py | 172 ++++++++-------------------- nepho/core/common.py | 2 +- nepho/core/scenario.py | 2 +- nepho/providers/vagrant_provider.py | 2 +- setup.py | 5 +- 14 files changed, 252 insertions(+), 326 deletions(-) create mode 100644 nepho/cli/hooks.py diff --git a/bin/nepho b/bin/nepho index f228fb2..17810a8 100755 --- a/bin/nepho +++ b/bin/nepho @@ -1,5 +1,5 @@ #!/usr/bin/env python -from cement.core import handler +from cement.core import handler, hook from nepho import cli import sys @@ -16,6 +16,9 @@ def main(): handler.register(cli.parameter.NephoParameterController) handler.register(cli.scope.NephoScopeController) + hook.register('post_argument_parsing', cli.hooks.set_scope) + hook.register('post_setup', cli.hooks.process_config) + try: app.setup() app.run() diff --git a/nepho/cli/__init__.py b/nepho/cli/__init__.py index e817459..6196bc4 100644 --- a/nepho/cli/__init__.py +++ b/nepho/cli/__init__.py @@ -1,9 +1,10 @@ import base import cloudlet import blueprint +import hooks import stack import config import parameter import scope -__all__ = ["base", "config", "parameter", "cloudlet", "blueprint", "stack", "scope"] +__all__ = ["base", "config", "hooks", "parameter", "cloudlet", "blueprint", "stack", "scope"] diff --git a/nepho/cli/base.py b/nepho/cli/base.py index f84fc0d..ccc27c4 100644 --- a/nepho/cli/base.py +++ b/nepho/cli/base.py @@ -4,10 +4,11 @@ import re from cement.core import backend, foundation, controller +from cement.utils.misc import init_defaults import nepho.core.config -defaults = backend.defaults('nepho', 'base') +defaults = init_defaults('nepho', 'internal') defaults['nepho']['archive_dir'] = path.join("~", ".nepho", "archive") defaults['nepho']['tmp_dir'] = path.join("~", ".nepho", "tmp") defaults['nepho']['cache_dir'] = path.join("~", ".nepho", "cache") @@ -15,7 +16,7 @@ defaults['nepho']['local_dir'] = path.join("~", ".nepho", "local") defaults['nepho']['local_config'] = path.join("~", ".nepho", "local/config.yaml") defaults['nepho']['cloudlet_registry_url'] = "http://cloudlets.github.io/registry.yaml" -defaults['base']['processed_config'] = False +defaults['internal']['processed_config'] = False class NephoBaseController(controller.CementBaseController): @@ -27,45 +28,6 @@ class Meta: def _setup(self, app): super(NephoBaseController, self)._setup(app) - # Running this section twice (once for base and once for the subclassed - # controller) causes errors. There is no doubt a better way to avoid - # that behavior than this silly cheat... - if self.config.get('base', 'processed_config') is not True: - self.config.set('base', 'processed_config', True) - - # Multiple cloudlet dirs in a string need to be split into a list and - # excess whitespace removed - cloudlet_dirs = self.config.get('nepho', 'cloudlet_dirs').split(',') - cloudlet_dirs = map(lambda x: x.strip(), cloudlet_dirs) - self.config.set('nepho', 'cloudlet_dirs', cloudlet_dirs) - - # Do some pre-processing on all configuration items - for key in self.config.keys('nepho'): - value = self.config.get('nepho', key) - - if isinstance(value, list): - # Expand user where necessary - value = map(lambda x: path.expanduser(x), value) - self.config.set('nepho', key, value) - - # If items are directories, make sure they exist - if re.search('_dirs$', key): - for one_dir in value: - if not path.exists(one_dir): - makedirs(one_dir) - else: - # Expand user where necessary - value = path.expanduser(value) - self.config.set('nepho', key, value) - - # If item is a directory, make sure it exists - if re.search('_dir$', key) and not path.exists(value): - makedirs(value) - - self.my_shared_obj = dict() - - self.nepho_config = nepho.core.config.ConfigManager(self.config) - @controller.expose(hide=True) def default(self): if self._meta.label == "base": diff --git a/nepho/cli/blueprint.py b/nepho/cli/blueprint.py index f1ce798..b43da47 100644 --- a/nepho/cli/blueprint.py +++ b/nepho/cli/blueprint.py @@ -8,14 +8,16 @@ import nepho.core.config from cement.core import controller -from nepho.cli import base +from nepho.cli import base, scope from nepho.core import cloudlet class NephoBlueprintController(base.NephoBaseController): class Meta: label = 'blueprint' - stacked_on = None + interface = controller.IController + stacked_on = 'base' + stacked_type = 'nested' description = 'list and view individual cloudlet deployment blueprints' usage = "nepho blueprint [blueprint]" arguments = [ @@ -25,20 +27,19 @@ class Meta: def _setup(self, app): super(base.NephoBaseController, self)._setup(app) - self.nepho_config = nepho.core.config.ConfigManager(self.config) + self.nepho_config = nepho.core.config.ConfigManager(self.app.config) self.cloudletManager = cloudlet.CloudletManager(self.nepho_config) @controller.expose(help='List all blueprints in a cloudlet') def list(self): - - cloudlet_name = self._read_cloudlet() - - if cloudlet_name is None: - print "Usage: nepho blueprint list [cloudlet]" + if self.app.cloudlet_name is None: + print "Usage: nepho blueprint list " exit(1) + else: + scope.print_scope(self) try: - cloudlt = self.cloudletManager.find(cloudlet_name) + cloudlt = self.cloudletManager.find(self.app.cloudlet_name) y = cloudlt.defn except IOError: print colored("└──", "yellow"), cloudlt.name, "(", colored("error", "red"), "- missing or malformed cloudlet.yaml )" @@ -64,23 +65,21 @@ def list(self): @controller.expose(help='Describe a blueprint') def describe(self): - - (cloudlet_name, blueprint_name) = self._read_cloudlet_and_blueprint() - - print blueprint_name - if cloudlet_name is None or blueprint_name is None: + if self.app.cloudlet_name is None or self.app.blueprint_name is None: print "Usage: nepho blueprint describe " exit(1) + else: + scope.print_scope(self) try: - cloudlt = self.cloudletManager.find(cloudlet_name) + cloudlt = self.cloudletManager.find(self.app.cloudlet_name) except IOError: print colored("└──", "yellow"), cloudlt.name, "(", colored("error", "red"), "- missing or malformed cloudlet.yaml )" exit(1) else: print colored("└──", "yellow"), cloudlt.name, "(", colored("v%s", "blue") % (cloudlt.defn['version']), ")" - bprint = cloudlt.blueprint(blueprint_name) + bprint = cloudlt.blueprint(self.app.blueprint_name) y = bprint.defn @@ -100,22 +99,3 @@ def describe(self): print "-" * 80 return - - def _read_cloudlet(self): - """Determine the cloudlet name to operate on.""" - - cloudlet_name = self.nepho_config.get("scope_cloudlet") - if self.pargs.cloudlet is not None: - cloudlet_name = self.pargs.cloudlet - - return cloudlet_name - - def _read_cloudlet_and_blueprint(self): - """Determine the cloudlet and blueprint names to operate on.""" - - cloudlet_name = self._read_cloudlet() - blueprint_name = self.nepho_config.get("scope_blueprint") - if self.pargs.blueprint is not None: - blueprint_name = self.pargs.blueprint - - return (cloudlet_name, blueprint_name) diff --git a/nepho/cli/cloudlet.py b/nepho/cli/cloudlet.py index 9f6f4ca..23414de 100644 --- a/nepho/cli/cloudlet.py +++ b/nepho/cli/cloudlet.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # coding: utf-8 from cement.core import controller -from nepho.cli import base +from nepho.cli import base, scope from os import path import argparse from termcolor import colored @@ -22,23 +22,25 @@ class NephoCloudletController(base.NephoBaseController): class Meta: label = 'cloudlet' - stacked_on = None + interface = controller.IController + stacked_on = 'base' + stacked_type = 'nested' description = 'find, download, and manage cloudlets' usage = "nepho cloudlet [options]" arguments = [ (['--force', '-f'], dict(action='store_true', dest='force', help=argparse.SUPPRESS)), (['--location', '-l'], dict(dest='location', help=argparse.SUPPRESS)), - (['string'], dict(help=argparse.SUPPRESS, nargs='*')), + (['cloudlet'], dict(help=argparse.SUPPRESS, nargs='?')), + (['query'], dict(help=argparse.SUPPRESS, nargs='*')), ] def _setup(self, app): super(NephoCloudletController, self)._setup(app) - self.nepho_config = nepho.core.config.ConfigManager(self.config) + self.nepho_config = nepho.core.config.ConfigManager(self.app.config) self.cloudletManager = cloudlet.CloudletManager(self.nepho_config) @controller.expose(help="List all installed cloudlets") def list(self): - cloudlets = self.cloudletManager.list() dir = "" @@ -74,41 +76,45 @@ def list(self): @controller.expose(help="Describe an installed cloudlet") def describe(self): - - cloudlet_name = self._read_cloudlet() - - cloudlt = self.cloudletManager.find(cloudlet_name) - if cloudlt is None: - print colored("No cloudlet named \"%s\" found." % (cloudlet_name), "red") + if self.app.cloudlet_name is None: + print "Usage: nepho cloudlet describe " exit(1) + else: + scope.print_scope(self) - wrapper = TextWrapper(width=80, subsequent_indent=" ") - y = cloudlt.defn - - print "-" * 80 - print "Name: %s" % (y['name']) - print "Version: %s" % (y['version']) - print "Author: %s" % (y['author']) - print "License: %s" % (y['license']) - print wrapper.fill("Summary: %s" % (y['summary'])) - print wrapper.fill("Description: %s" % (y['description'])) - print "-" * 80 + c = self.cloudletManager.find(self.app.cloudlet_name) + if c is None: + print colored("Error:", "red") + "No cloudlet named \"%s\" found." % (self.cloudlet_name) + exit(1) + else: + wrapper = TextWrapper(width=80, subsequent_indent=" ") + d = c.defn + + print "-" * 80 + print "Name: %s" % (d['name']) + print "Version: %s" % (d['version']) + print "Author: %s" % (d['author']) + print "License: %s" % (d['license']) + print wrapper.fill("Summary: %s" % (d['summary'])) + print wrapper.fill("Description: %s" % (d['description'])) + print "-" * 80 return @controller.expose(help="Search the Nepho Cloudlet Registry for cloudlets whose names, summaries, or descriptions match the provided search term") def search(self): - # TODO: Improve registry search. I started looking into fulltext search - # options, and experimented with throwing the registry into a local - # sqlite database, but it seemed like overkill. Really this should be - # calling a web service. + # TODO: Improve search beyond basic string matching - targetString = self.pargs.string[0] if len(self.pargs.string) > 0 else '' + if self.app.pargs.cloudlet is not None: + query = self.app.pargs.cloudlet + ' ' + ' '.join(self.app.pargs.query) + else: + query = "" registry = self.cloudletManager.get_registry() + print "Searching for %s" % query matchList = list() for cloudletRepo in registry.keys(): flattenedText = "%s: %s" % (cloudletRepo, registry[cloudletRepo]) - if (targetString == '') or (targetString in flattenedText): + if (query == '') or (query.trim() in flattenedText): matchList.append(cloudletRepo) if len(matchList) == 0: @@ -124,28 +130,26 @@ def search(self): print "Author: %s" % (cloudletDict['author']) print "License: %s" % (cloudletDict['license']) print wrapper.fill("Summary: %s" % (cloudletDict['summary'])) - print wrapper.fill("Description: %s" % (cloudletDict['description'])) - print "-" * 80 - - #print "Unimplemented action. (input: %s)" % self.pargs.string @controller.expose(help="Install a Nepho cloudlet from the Nepho Cloudlet Registry or from an external Git repository") def install(self): - if self.pargs.string == []: + if self.app.cloudlet_name is None: print "Usage: nepho cloudlet install [--location ]" exit(1) + else: + scope.print_scope(self) - name = self._read_cloudlet() + name = self.app.cloudlet_name registry = self.cloudletManager.get_registry() if name in registry: url = registry[name]['source'] else: - if self.pargs.location is None: + if self.app.pargs.location is None: print "Cloudlet name was not found in master registry. To install a custom cloudlet, specify a location with the --location option." exit(1) else: - url = self.pargs.location + url = self.app.pargs.location cloudlet_dirs = self.cloudletManager.all_cloudlet_dirs() selected_dir = common.select_list(self, cloudlet_dirs, False, "Select an install location:") @@ -159,62 +163,47 @@ def install(self): @controller.expose(help="Upgrade an installed Nepho cloudlet", aliases=["upgrade"]) def update(self): + if self.app.cloudlet_name is None: + print "Usage: nepho cloudlet update " + exit(1) + else: + scope.print_scope(self) - name = self._read_cloudlet() - - cloudlts = self.cloudletManager.find(name) - if cloudlts is None: - print "Cloudlet is not installed." + cl = self.cloudletManager.find(self.app.cloudlet_name) + if cl is None: + print colored("Error: ", "red") + "Cloudlet is not installed." exit(1) - if not isinstance(cloudlts, list): - cloudlts = [cloudlts] - for cloudlt in cloudlts: - cloudlt.update() + if not isinstance(cl, list): + cl = [cl] + for c in cl: + c.update() - @controller.expose(help="Uninstall a Nepho cloudlet") + @controller.expose(help="Uninstall a Nepho cloudlet", aliases=["remove"]) def uninstall(self): - name = self._read_cloudlet() - cloudlt = self.cloudletManager.find(name) + if self.app.cloudlet_name is None: + print "Usage: nepho cloudlet uninstall [--force/-f] " + exit(1) + else: + scope.print_scope(self) - if cloudlt is None: - print "No cloudlet named %s was found.\n" % (name) + cl = self.cloudletManager.find(self.app.cloudlet_name) + if cl is None: + print colored("Error: ", "red") + "Cloudlet is not installed." exit(1) - if not self.pargs.force: - verify = input("Are you sure you want to uninstall %s? [y/N]: " % (name)) + + if not self.app.pargs.force: + verify = input("Are you sure you want to uninstall %s? [y/N]: " % (self.app.cloudlet_name)) if verify != 'y' and verify != 'yes': exit(1) - else: - print "Note: You can hide this message by using the --force option.\n" - cloudlt.archive(name, self.config.get('nepho', 'archive_dir')) - cloudlt.uninstall() + if not isinstance(cl, list): + cl = [cl] + for c in cl: + c.archive(self.app.cloudlet_name, self.nepho_config.get('nepho', 'archive_dir')) + c.uninstall() - @controller.expose(help="Update the local cloudlet registry.", aliases=["registry-update", "update-registry"]) + @controller.expose(help="Update the local cloudlet registry.", aliases=["update-registry"]) def registry_update(self): self.cloudletManager.clear_registry() self.cloudletManager.update_registry() - - def update_registry(self): - cloudlts = self.cloudletManager.find(self.pargs.string[0]) - if cloudlts is None: - print "Cloudlet is not installed." - exit(1) - - if not isinstance(cloudlts, list): - cloudlts = [cloudlts] - for cloudlt in cloudlts: - cloudlt.update() - - def _read_cloudlet(self): - """Determine the cloudlet name to operate on.""" - - cloudlet_name = self.nepho_config.get("scope_cloudlet") - if len(self.pargs.string) > 0 and self.pargs.string[0] is not None: - cloudlet_name = self.pargs.string[0] - - if cloudlet_name is None: - print colored("No cloudlet specified. ", "red") - exit(1) - - return cloudlet_name diff --git a/nepho/cli/config.py b/nepho/cli/config.py index 1500117..0a9d4da 100644 --- a/nepho/cli/config.py +++ b/nepho/cli/config.py @@ -14,7 +14,9 @@ class NephoConfigController(base.NephoBaseController): class Meta: label = 'config' - stacked_on = None + interface = controller.IController + stacked_on = 'base' + stacked_type = 'nested' description = 'list, view and modify config settings' usage = "nepho config [key] [value]" arguments = [ @@ -24,15 +26,12 @@ class Meta: def _setup(self, app): super(base.NephoBaseController, self)._setup(app) - self.nepho_config = nepho.core.config.ConfigManager(self.config) + self.nepho_config = nepho.core.config.ConfigManager(self.app.config) @controller.expose(help='List all config values.') def list(self): - print "-" * 80 - - keys = sorted(self.nepho_config.keys()) - for k in keys: + for k in sorted(self.nepho_config.keys()): v = self.nepho_config.get(k) if isinstance(v, basestring): print colored(" %s: " % (k), "yellow"), colored("\"%s\"" % (v), "blue") @@ -42,21 +41,21 @@ def list(self): @controller.expose(help='Get a config value') def get(self): - if self.pargs.key is None: + if self.app.pargs.key is None: print "Usage: nepho config get " exit(1) - print self.nepho_config.get(self.pargs.key) + print self.nepho_config.get(self.app.pargs.key) @controller.expose(help='Set a config value', aliases=["add"]) def set(self): - if self.pargs.key is None or self.pargs.value is None: + if self.app.pargs.key is None or self.app.pargs.value is None: print "Usage: nepho config set " exit(1) - self.nepho_config.set(self.pargs.key, self.pargs.value) + self.nepho_config.set(self.app.pargs.key, self.app.pargs.value) @controller.expose(help='Unset a config value', aliases=["delete", "remove"]) def unset(self): - if self.pargs.key is None: - print "Usage: nepho config unset " + if self.app.pargs.key is None: + print "Usage: nepho config unset " exit(1) - self.nepho_config.unset(self.pargs.key) + self.nepho_config.unset(self.app.pargs.key) diff --git a/nepho/cli/hooks.py b/nepho/cli/hooks.py new file mode 100644 index 0000000..99e5add --- /dev/null +++ b/nepho/cli/hooks.py @@ -0,0 +1,58 @@ +from os import path, makedirs +from termcolor import colored +from nepho.core.config import ConfigManager +import re + + +def process_config(self): + # Multiple cloudlet dirs in a string need to be split into a list and + # excess whitespace removed + cloudlet_dirs = self.config.get('nepho', 'cloudlet_dirs').split(',') + cloudlet_dirs = map(lambda x: x.strip(), cloudlet_dirs) + self.config.set('nepho', 'cloudlet_dirs', cloudlet_dirs) + + # Do some pre-processing on all configuration items + for key in self.config.keys('nepho'): + value = self.config.get('nepho', key) + + if isinstance(value, list): + # Expand user where necessary + value = map(lambda x: path.expanduser(x), value) + self.config.set('nepho', key, value) + + # If items are directories, make sure they exist + if re.search('_dirs$', key): + for one_dir in value: + if not path.exists(one_dir): + makedirs(one_dir) + else: + # Expand user where necessary + value = path.expanduser(value) + self.config.set('nepho', key, value) + + # If item is a directory, make sure it exists + if re.search('_dir$', key) and not path.exists(value): + makedirs(value) + + self.nepho_config = ConfigManager(self.config) + + +def set_scope(app): + """ + Choose and set correct cloudlet and blueprint names to operate on. + Precedence is configured scope, command line argument, None. If cloudlet is + configured and only the cloudlet argument is passed, assign it to blueprint. + """ + if app.nepho_config.get('scope_cloudlet') is not None: + app.cloudlet_name = app.nepho_config.get('scope_cloudlet') + else: + app.cloudlet_name = app.pargs.cloudlet + + if app.nepho_config.get('scope_blueprint') is not None: + app.blueprint_name = app.nepho_config.get('scope_blueprint') + elif hasattr(app.pargs, 'blueprint') and app.pargs.blueprint is not None: + app.blueprint_name = app.pargs.blueprint + elif app.nepho_config.get('scope_cloudlet') is not None: + app.blueprint_name = app.pargs.cloudlet + else: + app.blueprint_name = None diff --git a/nepho/cli/parameter.py b/nepho/cli/parameter.py index beb8e30..c0e2123 100644 --- a/nepho/cli/parameter.py +++ b/nepho/cli/parameter.py @@ -14,7 +14,9 @@ class NephoParameterController(base.NephoBaseController): class Meta: label = 'parameter' - stacked_on = None + interface = controller.IController + stacked_on = 'base' + stacked_type = 'nested' description = 'list, view and modify parameter settings' usage = "nepho parameter [cloudlet] [blueprint] [key] [value]" arguments = [ @@ -26,7 +28,7 @@ class Meta: def _setup(self, app): super(base.NephoBaseController, self)._setup(app) - self.nepho_config = nepho.core.config.ConfigManager(self.config) + self.nepho_config = nepho.core.config.ConfigManager(self.app.config) @controller.expose(help='List parameters.') def list(self): diff --git a/nepho/cli/scope.py b/nepho/cli/scope.py index 9163e65..f9cadc5 100644 --- a/nepho/cli/scope.py +++ b/nepho/cli/scope.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # coding: utf-8 -from cement.core import controller +from cement.core import controller, hook from termcolor import colored from nepho.cli import base @@ -9,7 +9,9 @@ class NephoScopeController(base.NephoBaseController): class Meta: label = 'scope' - stacked_on = None + interface = controller.IController + stacked_on = 'base' + stacked_type = 'nested' description = 'set a cloudlet (and optionally blueprint) scope for future commands' usage = "nepho config [key] [value]" arguments = [ @@ -19,35 +21,38 @@ class Meta: @controller.expose(aliases=['set'], help="set a scope for future commands or view current scope") def default(self): - self.log.debug('Setting scope to cloudlet: %s, blueprint: %s' % (self.pargs.cloudlet, self.pargs.blueprint)) - if self.pargs.cloudlet: - self.nepho_config.set('scope_cloudlet', self.pargs.cloudlet) - if self.pargs.blueprint: + new_cn = self.app.pargs.cloudlet + new_bp = self.app.pargs.blueprint + old_cn = self.app.nepho_config.get('scope_cloudlet') + old_bp = self.app.nepho_config.get('scope_blueprint') + + self.app.log.debug('Setting scope to cloudlet: %s, blueprint: %s' % (new_cn, new_bp)) + + if new_cn: + self.app.nepho_config.set('scope_cloudlet', new_cn) + if new_bp: # Only delete the blueprint if cloudlet is being explicitly set # (i.e. user isn't just viewing current scope printout) - self.nepho_config.set('scope_blueprint', self.pargs.blueprint) + self.app.nepho_config.set('scope_blueprint', new_bp) else: - self.nepho_config.unset('scope_blueprint') - - cloudlet = self.nepho_config.get('scope_cloudlet') - blueprint = self.nepho_config.get('scope_blueprint') + self.app.nepho_config.unset('scope_blueprint') - if cloudlet is None and blueprint is None: - print "Scope unset. Run nepho scope [blueprint] to set." - else: - print "Scope is currently " + colored(cloudlet, "blue") + " " + colored(blueprint or "", "cyan") + if new_cn != old_cn or new_bp != old_bp: + print "Set default command scope to " + colored(new_cn, "blue") + " " + colored(new_bp or "", "cyan") + elif old_cn is None: + print "Default command scope is unset. Run nepho scope [blueprint] to set." @controller.expose(help="unset current scope") def unset(self): - self.log.debug('Unsetting scope.') - self.nepho_config.unset('scope_cloudlet') - self.nepho_config.unset('scope_blueprint') + self.app.log.debug('Unsetting scope.') + self.app.nepho_config.unset('scope_cloudlet') + self.app.nepho_config.unset('scope_blueprint') - print "Default scope unset. Run nepho scope [blueprint] to set." + print "Default command scope is now unset. Run nepho scope [blueprint] to set." - def display(self): - cloudlet = self.nepho_config.get('scope_cloudlet') - blueprint = self.nepho_config.get('scope_blueprint') - if cloudlet is not None: - print "Default scope is " + colored(cloudlet, "blue") + " " + colored(blueprint or "", "cyan") +def print_scope(app): + if app.nepho_config.get('scope_cloudlet') is not None: + print "Using default command scope " + colored(app.nepho_config.get('scope_cloudlet'), "cyan") + " " + colored(app.nepho_config.get('scope_blueprint') or "", "yellow") + "\n" + else: + pass diff --git a/nepho/cli/stack.py b/nepho/cli/stack.py index 9fcbaba..3154194 100644 --- a/nepho/cli/stack.py +++ b/nepho/cli/stack.py @@ -11,14 +11,16 @@ from cement.core import controller import nepho.core.config -from nepho.cli import base +from nepho.cli import base, scope from nepho.core import common, cloudlet, stack, provider, provider_factory, resource, context, scenario class NephoStackController(base.NephoBaseController): class Meta: label = 'stack' - stacked_on = None + interface = controller.IController + stacked_on = 'base' + stacked_type = 'nested' description = 'create, manage, and destroy stacks built from blueprints' usage = "nepho stack [options]" arguments = [ @@ -30,75 +32,42 @@ class Meta: def _setup(self, app): super(base.NephoBaseController, self)._setup(app) - self.nepho_config = nepho.core.config.ConfigManager(self.config) + self.nepho_config = nepho.core.config.ConfigManager(self.app.config) self.cloudletManager = cloudlet.CloudletManager(self.nepho_config) - @controller.expose(help='Show the context for a stack from a blueprint and configs', aliases=['show-context']) + @controller.expose(help='Show the context for a stack from a blueprint and configs') def show_context(self): - - (cloudlet_name, blueprint_name) = self._read_cloudlet_and_blueprint() - - if cloudlet_name is None or blueprint_name is None: - print dedent("""\ - Usage: nepho stack show-context [--save] [--params Key1=Val1] - - -s, --save - Save command-line (and/or interactive) parameters to an overrides file for - use in all future invocations of this command. - - -p, --params - Override any parameter from the blueprint template. This option can be passed - multiple key=value pairs, and can be called multiple times. If a required - parameter is not passed as a command-line option, nepho will interactively - prompt for it. - - Examples: - nepho stack show-context my-app development --params AwsAvailZone1=us-east-1a - nepho stack show-context my-app development -s -p Foo=True -p Bar=False""") + if self.app.cloudlet_name is None or self.app.blueprint_name is None: + print "Usage: nepho stack show-context " exit(1) + else: + scope.print_scope(self) scene = self._assemble_scenario() ctxt = scene.get_context() - #Use JSON lib to pretty print a sorted version of this ... + # Use JSON lib to pretty print a sorted version of this ... print colored("Context:", "yellow") print colored("-" * 80, "yellow") print yaml.dump(ctxt) # print json.dumps(json.loads(json.dumps(ctxt), object_pairs_hook=collections.OrderedDict), indent=2, separators=(',', ': ')) - @controller.expose(help='Show the template output for a stack from a blueprint', aliases=['show-template']) + @controller.expose(help='Show the template output for a stack from a blueprint') def show_template(self): - - (cloudlet_name, blueprint_name) = self._read_cloudlet_and_blueprint() - if cloudlet_name is None or blueprint_name is None: - print dedent("""\ - Usage: nepho stack show-template [--save] [--params Key1=Val1] - - -s, --save - Save command-line (and/or interactive) parameters to an overrides file for - use in all future invocations of this command. - - -p, --params - Override any parameter from the blueprint template. This option can be passed - multiple key=value pairs, and can be called multiple times. If a required - parameter is not passed as a command-line option, nepho will interactively - prompt for it. - - Examples: - nepho stack show-template my-app development --params AwsAvailZone1=us-east-1a - nepho stack show-template my-app development -s -p Foo=True -p Bar=False""") + if self.app.cloudlet_name is None or self.app.blueprint_name is None: + print "Usage: nepho stack show-template " exit(1) + else: + scope.print_scope(self) scene = self._assemble_scenario() print scene.get_template() - @controller.expose(help='Create a stack from a blueprint', aliases=['deploy']) + @controller.expose(help='Create a stack from a blueprint', aliases=['deploy', 'up']) def create(self): - - (cloudlet_name, blueprint_name) = self._read_cloudlet_and_blueprint() - if cloudlet_name is None or blueprint_name is None: + if self.app.cloudlet_name is None or self.app.blueprint_name is None: print dedent("""\ - Usage: nepho stack create [--save] [--params Key1=Val1] + Usage: nepho stack create [-s/--save] [-p/--params ] -s, --save Save command-line (and/or interactive) parameters to an overrides file for @@ -112,24 +81,21 @@ def create(self): Examples: nepho stack create my-app development --params AwsAvailZone1=us-east-1a - nepho stack create my-app development -s -p Foo=True -p Bar=False""") + nepho stack create my-app development -s -p Foo=True Bar=False -p Test=Passed""") exit(1) + else: + scope.print_scope(self) scene = self._assemble_scenario() scene.provider.deploy() @controller.expose(help='Check on the status of a stack.') def status(self): - - (cloudlet_name, blueprint_name) = self._read_cloudlet_and_blueprint() - if cloudlet_name is None or blueprint_name is None: - print dedent("""\ - Usage: nepho stack status - - Examples: - nepho stack status my-app development - """) + if self.app.cloudlet_name is None or self.app.blueprint_name is None: + print "Usage: nepho stack status " exit(1) + else: + scope.print_scope(self) scene = self._assemble_scenario() @@ -140,7 +106,7 @@ def status(self): # # Report system status # - header_string = "%s/%s" % (cloudlet_name, blueprint_name) + header_string = "%s/%s" % (self.app.cloudlet_name, self.app.blueprint_name) print colored(header_string, "yellow") print colored("-" * len(header_string), "yellow") rep_string = "The stack is currently %s." % (status['default']) @@ -151,18 +117,13 @@ def status(self): color = 'red' print colored(rep_string, color) - @controller.expose(help='Gain access to the stack') + @controller.expose(help='Gain access to the stack', aliases=['ssh']) def access(self): - - (cloudlet_name, blueprint_name) = self._read_cloudlet_and_blueprint() - if cloudlet_name is None or blueprint_name is None: - print dedent("""\ - Usage: nepho stack access - - Examples: - nepho stack access my-app development - """) + if self.app.cloudlet_name is None or self.app.blueprint_name is None: + print "Usage: nepho stack access " exit(1) + else: + scope.print_scope(self) scene = self._assemble_scenario() @@ -170,37 +131,20 @@ def access(self): @controller.expose(help='Destroy a stack from a blueprint', aliases=['delete']) def destroy(self): - - (cloudlet_name, blueprint_name) = self._read_cloudlet_and_blueprint() - if cloudlet_name is None or blueprint_name is None: - print dedent("""\ - Usage: nepho stack destroy - - Examples: - nepho stack destroy my-app development - """) - exit(1) + if self.app.cloudlet_name is None or self.app.blueprint_name is None: + print "Usage: nepho stack destroy " + else: + scope.print_scope(self) scene = self._assemble_scenario() - scene.provider.destroy() - @controller.expose(help='List deployed stacks') + @controller.expose(help='List running stacks') def list(self): - - (cloudlet_name, blueprint_name) = self._read_cloudlet_and_blueprint() - if cloudlet_name is None or blueprint_name is None: - print dedent(""" - Usage: nepho stack list - - Examples: - nepho stack list - nepho stack list my-app - nepho stack list my-app development """) - exit(1) + scope.print_scope(self) try: - cloudlt = self.cloudletManager.find(cloudlet_name) + cloudlt = self.cloudletManager.find(self.app.cloudlet_name) y = cloudlt.defn except IOError: print colored("└──", "yellow"), cloudlt.name, "(", colored("error", "red"), "- missing or malformed cloudlet.yaml )" @@ -208,39 +152,20 @@ def list(self): else: print colored("└──", "yellow"), cloudlt.name, "(", colored("v%s", "blue") % (y['version']), ")" - bprint = cloudlt.blueprint(blueprint_name) + bprint = cloudlt.blueprint(self.app.blueprint_name) # Create an appropriate provider, and set the target pattern. provider_name = bprint.provider_name() - providr = provider.ProviderFactory(provider_name, self.config) + providr = provider.ProviderFactory(provider_name, self.app.config) providr.pattern(bprint.pattern()) - print "Partially implemented action. (input: %s)" % self.pargs.params - - def _read_cloudlet(self): - """Determine the cloudlet name to operate on.""" - - cloudlet_name = self.nepho_config.get("scope_cloudlet") - if self.pargs.cloudlet is not None: - cloudlet_name = self.pargs.cloudlet - - return cloudlet_name - - def _read_cloudlet_and_blueprint(self): - """Determine the cloudlet and blueprint names to operate on.""" - - cloudlet_name = self._read_cloudlet() - blueprint_name = self.nepho_config.get("scope_blueprint") - if self.pargs.blueprint is not None: - blueprint_name = self.pargs.blueprint - - return (cloudlet_name, blueprint_name) + print "Partially implemented action. (input: %s)" % self.app.pargs.params def _parse_params(self): """Helper method to extract params from command line into a dict.""" params = dict() - if self.pargs.params is not None: - paramList = self.pargs.params + if self.app.pargs.params is not None: + paramList = self.app.pargs.params for item in paramList[0]: (k, v) = item.split("=") params[k] = v @@ -249,17 +174,16 @@ def _parse_params(self): def _load_blueprint(self): """Helper method to load blueprint & pattern from args.""" - (cloudlet_name, blueprint_name) = self._read_cloudlet_and_blueprint() try: - cloudlt = self.cloudletManager.find(cloudlet_name) + cloudlt = self.cloudletManager.find(self.app.cloudlet_name) except Exception: - print colored("Error loading cloudlet %s" % (cloudlet_name), "red") + print colored("Error loading cloudlet %s" % (self.app.cloudlet_name), "red") exit(1) - bprint = cloudlt.blueprint(blueprint_name) + bprint = cloudlt.blueprint(self.app.blueprint_name) if bprint is None: - print "Cannot find blueprint %s in cloudlet %s." % (blueprint_name, cloudlet_name) + print "Cannot find blueprint %s in cloudlet %s." % (self.app.blueprint_name, self.app.cloudlet_name) exit(1) return bprint diff --git a/nepho/core/common.py b/nepho/core/common.py index df72f0d..64b8263 100644 --- a/nepho/core/common.py +++ b/nepho/core/common.py @@ -70,7 +70,7 @@ def select_list(self, items_list=[], all=False, desc="Select an item:"): def all_cloudlets(self): - dirs = self.config.get('nepho', 'cloudlet_dirs') + dirs = self.app.config.get('nepho', 'cloudlet_dirs') # Collect the filesystem paths to every cloudlet into one list cloudlet_paths = list() diff --git a/nepho/core/scenario.py b/nepho/core/scenario.py index 0ccd7e5..6f904a5 100644 --- a/nepho/core/scenario.py +++ b/nepho/core/scenario.py @@ -20,7 +20,7 @@ def __init__(self, config, bprint, params): self.provider_name = self.blueprint.provider_name pfac = provider_factory.ProviderFactory() - self.provider = pfac.create(self.provider_name, self.config, self) + self.provider = pfac.create(self.provider_name, config, self) self.remgr = resource.ResourceManager(config) self.context = context.Context(config) diff --git a/nepho/providers/vagrant_provider.py b/nepho/providers/vagrant_provider.py index 9e2330c..8c08ce5 100644 --- a/nepho/providers/vagrant_provider.py +++ b/nepho/providers/vagrant_provider.py @@ -49,7 +49,7 @@ def deploy(self): """Deploy a given pattern.""" self.initialize_vagrant() v = vagrant.Vagrant() - vagrant_provider = self.config.get("vagrant_provider") + vagrant_provider = self.app.config.get("vagrant_provider") #vm_name = self._vm_name() vm_name = None try: diff --git a/setup.py b/setup.py index b4d1194..f17820a 100644 --- a/setup.py +++ b/setup.py @@ -12,13 +12,16 @@ author_email = 'ithelp@harvard.edu', license = 'MIT', scripts = ['bin/nepho'], + dependency_links = [ + 'git+git://github.com/cement/cement.git@2.1.4.dev20131029203905#egg=cement-2.1.4-dev' + ], install_requires = [ 'argparse>=1.2', 'boto>=2.0', 'awscli>=1.2.3', 'Jinja2', 'PyYAML', - 'cement>=2.0', + 'cement>=2.1,==2.1.4-dev', 'termcolor', 'gitpython==0.3.2.RC1', 'requests>=1.2.3',