You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ariatosca.apache.org by av...@apache.org on 2017/04/19 11:21:19 UTC

[01/12] incubator-ariatosca git commit: Requirments-arent-instantiated-properly [Forced Update!]

Repository: incubator-ariatosca
Updated Branches:
  refs/heads/cli-tests 56a4767e3 -> ed07f9f27 (forced update)


Requirments-arent-instantiated-properly


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/8ced0f49
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/8ced0f49
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/8ced0f49

Branch: refs/heads/cli-tests
Commit: 8ced0f49e6439aff434b7c2c09f97e9be5d2b3ea
Parents: cf80675
Author: max-orlov <ma...@gigaspaces.com>
Authored: Tue Apr 18 11:03:13 2017 +0300
Committer: max-orlov <ma...@gigaspaces.com>
Committed: Tue Apr 18 11:03:13 2017 +0300

----------------------------------------------------------------------
 aria/core.py                        | 20 ++++++++++++--------
 aria/parser/consumption/__init__.py |  7 +++++--
 2 files changed, 17 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8ced0f49/aria/core.py
----------------------------------------------------------------------
diff --git a/aria/core.py b/aria/core.py
index 365f39c..f5e2025 100644
--- a/aria/core.py
+++ b/aria/core.py
@@ -75,14 +75,18 @@ class Core(object):
             service = service_template.instantiate(None, self.model_storage, inputs=inputs)
 
         self.model_storage._all_api_kwargs['session'].flush()
-        consumption.ConsumerChain(
-            context,
-            (
-                consumption.FindHosts,
-                consumption.ConfigureOperations
-            )).consume()
-        if context.validation.dump_issues():
-            raise exceptions.InstantiationError('Failed to instantiate service template')
+
+        with self.model_storage._all_api_kwargs['session'].no_autoflush:
+            consumption.ConsumerChain(
+                context,
+                (
+                    consumption.SatisfyRequirements,
+                    consumption.ValidateCapabilities,
+                    consumption.FindHosts,
+                    consumption.ConfigureOperations
+                )).consume()
+            if context.validation.dump_issues():
+                raise exceptions.InstantiationError('Failed to instantiate service template')
 
         # If the user didn't enter a name for this service, we'll want to auto generate it.
         # But how will we ensure a unique but simple name? We'll append the services' unique id

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8ced0f49/aria/parser/consumption/__init__.py
----------------------------------------------------------------------
diff --git a/aria/parser/consumption/__init__.py b/aria/parser/consumption/__init__.py
index ff1b376..8e565eb 100644
--- a/aria/parser/consumption/__init__.py
+++ b/aria/parser/consumption/__init__.py
@@ -20,7 +20,7 @@ from .style import Style
 from .consumer import Consumer, ConsumerChain
 from .presentation import Read
 from .validation import Validate
-from .modeling import ServiceTemplate, Types, ServiceInstance, FindHosts, ConfigureOperations
+from .modeling import ServiceTemplate, Types, ServiceInstance, FindHosts, ConfigureOperations, SatisfyRequirements, ValidateCapabilities
 from .inputs import Inputs
 
 __all__ = (
@@ -34,4 +34,7 @@ __all__ = (
     'ServiceTemplate',
     'Types',
     'ServiceInstance',
-    'Inputs')
+    'Inputs',
+    'SatisfyRequirements',
+    'ValidateCapabilities'
+)
\ No newline at end of file


[08/12] incubator-ariatosca git commit: various review fixes

Posted by av...@apache.org.
various review fixes


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/c1f8eb6a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/c1f8eb6a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/c1f8eb6a

Branch: refs/heads/cli-tests
Commit: c1f8eb6a924f93656dee6d82ded2dc83ed6b4cc9
Parents: 79f5d78
Author: Ran Ziv <ra...@gigaspaces.com>
Authored: Tue Apr 18 18:44:34 2017 +0300
Committer: Ran Ziv <ra...@gigaspaces.com>
Committed: Tue Apr 18 18:44:34 2017 +0300

----------------------------------------------------------------------
 aria/cli/commands/node_templates.py    |  3 ---
 aria/cli/commands/plugins.py           |  4 ++--
 aria/cli/commands/service_templates.py | 21 +++++----------------
 aria/cli/commands/services.py          | 29 ++++++++++++++---------------
 aria/cli/core/aria.py                  |  4 ++--
 aria/cli/inputs.py                     |  2 +-
 aria/cli/utils.py                      | 18 ++++++++++++------
 aria/core.py                           | 19 ++++---------------
 aria/modeling/exceptions.py            | 19 +++++++++++++------
 aria/modeling/service_template.py      |  3 ++-
 aria/orchestrator/workflow_runner.py   | 14 +++++++-------
 tox.ini                                |  2 +-
 12 files changed, 63 insertions(+), 75 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c1f8eb6a/aria/cli/commands/node_templates.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/node_templates.py b/aria/cli/commands/node_templates.py
index b63b630..c79e125 100644
--- a/aria/cli/commands/node_templates.py
+++ b/aria/cli/commands/node_templates.py
@@ -41,10 +41,7 @@ def show(node_template_id, model_storage, logger):
 
     `NODE_TEMPLATE_ID` is the node id to get information on.
     """
-    # logger.info('Showing node template {0} for service template {1}'.format(
-    #     node_template_id, service_template_name))
     logger.info('Showing node template {0}'.format(node_template_id))
-    #TODO get node template of a specific service template instead?
     node_template = model_storage.node_template.get(node_template_id)
 
     print_data(NODE_TEMPLATE_COLUMNS, node_template.to_dict(), 'Node template:', max_width=50)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c1f8eb6a/aria/cli/commands/plugins.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/plugins.py b/aria/cli/commands/plugins.py
index 680284f..41a272e 100644
--- a/aria/cli/commands/plugins.py
+++ b/aria/cli/commands/plugins.py
@@ -15,10 +15,10 @@
 
 import zipfile
 
+from .. import utils
 from ..core import aria
 from ..exceptions import AriaCliError
 from ..table import print_data
-from ..utils import storage_sort_param
 
 
 PLUGIN_COLUMNS = ['id', 'package_name', 'package_version', 'supported_platform',
@@ -129,5 +129,5 @@ def list(sort_by, descending, model_storage, logger):
     """
     logger.info('Listing all plugins...')
     plugins_list = [p.to_dict() for p in model_storage.plugin.list(
-        sort=storage_sort_param(sort_by, descending))]
+        sort=utils.storage_sort_param(sort_by, descending))]
     print_data(PLUGIN_COLUMNS, plugins_list, 'Plugins:')

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c1f8eb6a/aria/cli/commands/service_templates.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/service_templates.py b/aria/cli/commands/service_templates.py
index 93dc188..2ef37c0 100644
--- a/aria/cli/commands/service_templates.py
+++ b/aria/cli/commands/service_templates.py
@@ -16,15 +16,12 @@
 
 import os
 
-from .. import utils
 from .. import csar
 from .. import service_template_utils
+from .. import utils
 from ..core import aria
 from ..table import print_data
-from ..exceptions import AriaCliError
-from ..utils import handle_storage_exception
 from ...core import Core
-from ...exceptions import AriaException
 from ...storage import exceptions as storage_exceptions
 
 
@@ -124,7 +121,8 @@ def store(service_template_path, service_template_name, service_template_filenam
                                      os.path.dirname(service_template_path),
                                      service_template_name)
     except storage_exceptions.StorageError as e:
-        handle_storage_exception(e, 'service template', service_template_name)
+        utils.check_overriding_storage_exceptions(e, 'service template', service_template_name)
+        raise
     logger.info('Service template {0} stored'.format(service_template_name))
 
 
@@ -143,10 +141,7 @@ def delete(service_template_name, model_storage, resource_storage, plugin_manage
     logger.info('Deleting service template {0}...'.format(service_template_name))
     service_template = model_storage.service_template.get_by_name(service_template_name)
     core = Core(model_storage, resource_storage, plugin_manager)
-    try:
-        core.delete_service_template(service_template.id)
-    except storage_exceptions.NotFoundError:
-        raise AriaCliError()
+    core.delete_service_template(service_template.id)
     logger.info('Service template {0} deleted'.format(service_template_name))
 
 
@@ -183,13 +178,7 @@ def validate(service_template, service_template_filename,
     logger.info('Validating service template: {0}'.format(service_template))
     service_template_path = service_template_utils.get(service_template, service_template_filename)
     core = Core(model_storage, resource_storage, plugin_manager)
-
-    try:
-        core.validate_service_template(service_template_path)
-    except AriaException as e:
-        # TODO: gather errors from parser and dump them via CLI?
-        raise AriaCliError(str(e))
-
+    core.validate_service_template(service_template_path)
     logger.info('Service template validated successfully')
 
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c1f8eb6a/aria/cli/commands/services.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/services.py b/aria/cli/commands/services.py
index 4728509..afa5e42 100644
--- a/aria/cli/commands/services.py
+++ b/aria/cli/commands/services.py
@@ -19,12 +19,11 @@ from StringIO import StringIO
 
 from . import service_templates
 from .. import helptexts
+from .. import utils
 from ..core import aria
-from ..exceptions import AriaCliError
 from ..table import print_data
-from ..utils import storage_sort_param, handle_storage_exception
 from ...core import Core
-from ...exceptions import AriaException
+from ...modeling import exceptions as modeling_exceptions
 from ...storage import exceptions as storage_exceptions
 
 
@@ -66,7 +65,7 @@ def list(service_template_name,
         filters = {}
 
     services_list = [d.to_dict() for d in model_storage.service.list(
-        sort=storage_sort_param(sort_by=sort_by, descending=descending),
+        sort=utils.storage_sort_param(sort_by=sort_by, descending=descending),
         filters=filters)]
     print_data(SERVICE_COLUMNS, services_list, 'Services:')
 
@@ -95,18 +94,18 @@ def create(service_template_name,
     """
     logger.info('Creating new service from service template {0}...'.format(
         service_template_name))
+    core = Core(model_storage, resource_storage, plugin_manager)
+    service_template = model_storage.service_template.get_by_name(service_template_name)
 
     try:
-        core = Core(model_storage, resource_storage, plugin_manager)
-        service_template = model_storage.service_template.get_by_name(service_template_name)
         service = core.create_service(service_template.id, inputs, service_name)
     except storage_exceptions.StorageError as e:
-        handle_storage_exception(e, 'service', service_name)
-    except AriaException as e:
-        logger.info(str(e))
+        utils.check_overriding_storage_exceptions(e, 'service', service_name)
+        raise
+    except modeling_exceptions.InputsException:
         service_templates.print_service_template_inputs(model_storage, service_template_name,
                                                         logger)
-        raise AriaCliError(str(e))
+        raise
     logger.info("Service created. The service's name is {0}".format(service.name))
 
 
@@ -171,11 +170,11 @@ def inputs(service_name, model_storage, logger):
     logger.info('Showing inputs for service {0}...'.format(service_name))
     service = model_storage.service.get_by_name(service_name)
     if service.inputs:
-        inputs_ = StringIO()
-        for input_name, input in service.inputs.iteritems():
-            inputs_.write(' - "{0}":{1}'.format(input_name, os.linesep))
-            inputs_.write('     Value: {0}{1}'.format(input.value, os.linesep))
-        logger.info(inputs_.getvalue())
+        inputs_string = StringIO()
+        for input_name, input_ in service.inputs.iteritems():
+            inputs_string.write(' - "{0}":{1}'.format(input_name, os.linesep))
+            inputs_string.write('     Value: {0}{1}'.format(input_.value, os.linesep))
+        logger.info(inputs_string.getvalue())
     else:
         logger.info('\tNo inputs')
     logger.info('')

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c1f8eb6a/aria/cli/core/aria.py
----------------------------------------------------------------------
diff --git a/aria/cli/core/aria.py b/aria/cli/core/aria.py
index cd1036e..fb5a81b 100644
--- a/aria/cli/core/aria.py
+++ b/aria/cli/core/aria.py
@@ -354,7 +354,7 @@ class Options(object):
             help=help)
 
     @staticmethod
-    def task_max_attempts(default=1):
+    def task_max_attempts(default=30):
         return click.option(
             '--task-max-attempts',
             type=int,
@@ -370,7 +370,7 @@ class Options(object):
             help=helptexts.SORT_BY)
 
     @staticmethod
-    def task_retry_interval(default=1):
+    def task_retry_interval(default=30):
         return click.option(
             '--task-retry-interval',
             type=int,

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c1f8eb6a/aria/cli/inputs.py
----------------------------------------------------------------------
diff --git a/aria/cli/inputs.py b/aria/cli/inputs.py
index 78db846..0ff48dc 100644
--- a/aria/cli/inputs.py
+++ b/aria/cli/inputs.py
@@ -18,7 +18,7 @@ import glob
 import yaml
 
 from .env import logger
-from.exceptions import AriaCliError
+from .exceptions import AriaCliError
 
 
 def inputs_to_dict(resources):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c1f8eb6a/aria/cli/utils.py
----------------------------------------------------------------------
diff --git a/aria/cli/utils.py b/aria/cli/utils.py
index fad1b07..3cc68c9 100644
--- a/aria/cli/utils.py
+++ b/aria/cli/utils.py
@@ -152,10 +152,16 @@ def generate_progress_handler(file_path, action='', max_bar_length=80):
     return print_progress
 
 
-def handle_storage_exception(e, model_class, name):
+def check_overriding_storage_exceptions(e, model_class, name):
+    """
+    This method checks whether the storage exception is a known type where we'd like to override
+     the exception message; If so, it raises a new error. Otherwise it simply returns.
+    """
+    assert isinstance(e, BaseException)
     if 'UNIQUE constraint failed' in e.message:
-        msg = 'Could not store {model_class} `{name}`{linesep}' \
-              'There already a exists a {model_class} with the same name' \
-              .format(model_class=model_class, name=name, linesep=os.linesep)
-        raise AriaCliError(msg)
-    raise AriaCliError()
+        new_message = \
+            'Could not store {model_class} `{name}`{linesep}' \
+            'There already a exists a {model_class} with the same name' \
+            .format(model_class=model_class, name=name, linesep=os.linesep)
+        trace = sys.exc_info()[2]
+        raise type(e), type(e)(new_message), trace  # pylint: disable=raising-non-exception

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c1f8eb6a/aria/core.py
----------------------------------------------------------------------
diff --git a/aria/core.py b/aria/core.py
index f5e2025..af1984a 100644
--- a/aria/core.py
+++ b/aria/core.py
@@ -16,7 +16,6 @@
 from . import exceptions
 from .parser import consumption
 from .parser.loading.location import UriLocation
-from .storage import exceptions as storage_exceptions
 
 
 class Core(object):
@@ -69,14 +68,12 @@ class Core(object):
         # creating an empty ConsumptionContext, initiating a threadlocal context
         context = consumption.ConsumptionContext()
 
+        storage_session = self.model_storage._all_api_kwargs['session']
         # setting no autoflush for the duration of instantiation - this helps avoid dependency
         # constraints as they're being set up
-        with self.model_storage._all_api_kwargs['session'].no_autoflush:
+        with storage_session.no_autoflush:
             service = service_template.instantiate(None, self.model_storage, inputs=inputs)
 
-        self.model_storage._all_api_kwargs['session'].flush()
-
-        with self.model_storage._all_api_kwargs['session'].no_autoflush:
             consumption.ConsumerChain(
                 context,
                 (
@@ -88,17 +85,9 @@ class Core(object):
             if context.validation.dump_issues():
                 raise exceptions.InstantiationError('Failed to instantiate service template')
 
-        # If the user didn't enter a name for this service, we'll want to auto generate it.
-        # But how will we ensure a unique but simple name? We'll append the services' unique id
-        # to the service_templates name. Since this service is not in the storage yet, we'll put it
-        # there, and pull out its id.
-        self.model_storage.service.put(service)
+        storage_session.flush()  # flushing so service.id would auto-populate
         service.name = service_name or '{0}_{1}'.format(service_template.name, service.id)
-        try:
-            self.model_storage.service.update(service)
-        except storage_exceptions.StorageError:
-            self.model_storage.service.delete(service)
-            raise
+        self.model_storage.service.put(service)
         return service
 
     def delete_service(self, service_id, force=False):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c1f8eb6a/aria/modeling/exceptions.py
----------------------------------------------------------------------
diff --git a/aria/modeling/exceptions.py b/aria/modeling/exceptions.py
index 8225f37..19fd942 100644
--- a/aria/modeling/exceptions.py
+++ b/aria/modeling/exceptions.py
@@ -22,6 +22,13 @@ class ModelingException(AriaException):
     """
 
 
+class InputsException(ModelingException):
+    """
+    ARIA inputs exception.
+    """
+    pass
+
+
 class ValueFormatException(ModelingException):
     """
     ARIA modeling exception: the value is in the wrong format.
@@ -34,19 +41,19 @@ class CannotEvaluateFunctionException(ModelingException):
     """
 
 
-class MissingRequiredInputsException(ModelingException):
+class MissingRequiredInputsException(InputsException):
     """
-    ARIA modeling exception: Required inputs have been omitted
+    ARIA modeling exception: Required inputs have been omitted.
     """
 
 
-class InputsOfWrongTypeException(ModelingException):
+class InputsOfWrongTypeException(InputsException):
     """
-    ARIA modeling exception: Inputs of the wrong types have been provided
+    ARIA modeling exception: Inputs of the wrong types have been provided.
     """
 
 
-class UndeclaredInputsException(ModelingException):
+class UndeclaredInputsException(InputsException):
     """
-    ARIA modeling exception: Undeclared inputs have been provided
+    ARIA modeling exception: Undeclared inputs have been provided.
     """

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c1f8eb6a/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py
index 9a07b53..f1c2bcb 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -1237,7 +1237,8 @@ class RequirementTemplateBase(TemplateModelMixin):
 
         # Find first node that matches the type
         elif self.target_node_type is not None:
-            for target_node_template in context.modeling.template.node_templates.itervalues():
+            for target_node_template in \
+                    self.node_template.service_template.node_templates.values():
                 if self.target_node_type.get_descendant(target_node_template.type.name) is None:
                     continue
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c1f8eb6a/aria/orchestrator/workflow_runner.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflow_runner.py b/aria/orchestrator/workflow_runner.py
index 7b043c5..0051e8e 100644
--- a/aria/orchestrator/workflow_runner.py
+++ b/aria/orchestrator/workflow_runner.py
@@ -23,7 +23,7 @@ from datetime import datetime
 
 from . import exceptions
 from .context.workflow import WorkflowContext
-from .workflows.builtin import BUILTIN_WORKFLOWS, BUILTIN_WORKFLOWS_PATH_PREFIX
+from .workflows import builtin
 from .workflows.core.engine import Engine
 from .workflows.executor.process import ProcessExecutor
 from ..modeling import models
@@ -31,8 +31,8 @@ from ..modeling import utils as modeling_utils
 from ..utils.imports import import_fullname
 
 
-DEFAULT_TASK_MAX_ATTEMPTS = 1
-DEFAULT_TASK_RETRY_INTERVAL = 1
+DEFAULT_TASK_MAX_ATTEMPTS = 30
+DEFAULT_TASK_RETRY_INTERVAL = 30
 
 
 class WorkflowRunner(object):
@@ -110,7 +110,7 @@ class WorkflowRunner(object):
             workflow_name=self._workflow_name,
             inputs={})
 
-        if self._workflow_name in BUILTIN_WORKFLOWS:
+        if self._workflow_name in builtin.BUILTIN_WORKFLOWS:
             workflow_inputs = dict()  # built-in workflows don't have any inputs
         else:
             workflow_inputs = self.service.workflows[self._workflow_name].inputs
@@ -123,7 +123,7 @@ class WorkflowRunner(object):
 
     def _validate_workflow_exists_for_service(self):
         if self._workflow_name not in self.service.workflows and \
-                        self._workflow_name not in BUILTIN_WORKFLOWS:
+                        self._workflow_name not in builtin.BUILTIN_WORKFLOWS:
             raise exceptions.UndeclaredWorkflowError(
                 'No workflow policy {0} declared in service {1}'
                 .format(self._workflow_name, self.service.name))
@@ -137,8 +137,8 @@ class WorkflowRunner(object):
                 .format(self.service.name, active_executions[0].id))
 
     def _get_workflow_fn(self):
-        if self._workflow_name in BUILTIN_WORKFLOWS:
-            return import_fullname('{0}.{1}'.format(BUILTIN_WORKFLOWS_PATH_PREFIX,
+        if self._workflow_name in builtin.BUILTIN_WORKFLOWS:
+            return import_fullname('{0}.{1}'.format(builtin.BUILTIN_WORKFLOWS_PATH_PREFIX,
                                                     self._workflow_name))
 
         workflow = self.service.workflows[self._workflow_name]

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c1f8eb6a/tox.ini
----------------------------------------------------------------------
diff --git a/tox.ini b/tox.ini
index fa4bd5c..6ad048f 100644
--- a/tox.ini
+++ b/tox.ini
@@ -41,7 +41,7 @@ commands=pytest tests --cov-report term-missing --cov aria
 commands=pytest tests --cov-report term-missing --cov aria
 
 [testenv:pylint_code]
-commands=pylint --rcfile=aria/.pylintrc --disable=fixme,missing-docstring --ignore=commands.py aria
+commands=pylint --rcfile=aria/.pylintrc --disable=fixme,missing-docstring aria
 
 [testenv:pylint_tests]
 commands=pylint --rcfile=tests/.pylintrc --disable=fixme,missing-docstring tests


[06/12] incubator-ariatosca git commit: added aria reset cli command

Posted by av...@apache.org.
added aria reset cli command


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/3bff159e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/3bff159e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/3bff159e

Branch: refs/heads/cli-tests
Commit: 3bff159e6c3db3d855281c478c6ceab52fee6ad5
Parents: 8b0e451
Author: Ran Ziv <ra...@gigaspaces.com>
Authored: Tue Apr 18 16:39:51 2017 +0300
Committer: Ran Ziv <ra...@gigaspaces.com>
Committed: Tue Apr 18 16:39:51 2017 +0300

----------------------------------------------------------------------
 aria/cli/cli/aria.py          | 12 +++---------
 aria/cli/cli/helptexts.py     |  6 +++---
 aria/cli/commands/__init__.py |  1 +
 aria/cli/commands/reset.py    | 40 ++++++++++++++++++++++++++++++++++++++
 aria/cli/commands/services.py |  2 +-
 aria/cli/config/config.py     |  5 ++++-
 aria/cli/env.py               | 13 +++++++++++++
 aria/cli/main.py              |  1 +
 8 files changed, 66 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/3bff159e/aria/cli/cli/aria.py
----------------------------------------------------------------------
diff --git a/aria/cli/cli/aria.py b/aria/cli/cli/aria.py
index 31d6c9b..548be23 100644
--- a/aria/cli/cli/aria.py
+++ b/aria/cli/cli/aria.py
@@ -314,16 +314,10 @@ class Options(object):
             is_flag=True,
             help=helptexts.DRY_EXECUTION)
 
-        self.init_hard_reset = click.option(
-            '--hard',
+        self.reset_config = click.option(
+            '--reset-config',
             is_flag=True,
-            help=helptexts.HARD_RESET)
-
-        self.reset_context = click.option(
-            '-r',
-            '--reset-context',
-            is_flag=True,
-            help=helptexts.RESET_CONTEXT)
+            help=helptexts.RESET_CONFIG)
 
         self.enable_colors = click.option(
             '--enable-colors',

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/3bff159e/aria/cli/cli/helptexts.py
----------------------------------------------------------------------
diff --git a/aria/cli/cli/helptexts.py b/aria/cli/cli/helptexts.py
index c50a172..f8b315c 100644
--- a/aria/cli/cli/helptexts.py
+++ b/aria/cli/cli/helptexts.py
@@ -26,8 +26,8 @@ INPUTS_PARAMS_USAGE = (
 SERVICE_TEMPLATE_PATH = "The path to the application's service template file"
 SERVICE_TEMPLATE_ID = "The unique identifier for the service template"
 
-RESET_CONTEXT = "Reset the working environment"
-HARD_RESET = "Hard reset the configuration, including coloring and loggers"
+FORCE_RESET = "Confirmation for resetting ARIA's working directory"
+RESET_CONFIG = "Reset ARIA's user configuration"
 ENABLE_COLORS = "Enable colors in logger (use --hard when working with" \
                 " an initialized environment) [default: False]"
 
@@ -47,7 +47,7 @@ JSON_OUTPUT = "Output events in a consumable JSON format"
 
 SERVICE_ID = "The unique identifier for the service"
 EXECUTION_ID = "The unique identifier for the execution"
-IGNORE_RUNNING_NODES = "Delete the service even if it has running nodes"
+IGNORE_AVAILABLE_NODES = "Delete the service even if it has available nodes"
 
 NODE_NAME = "The node's name"
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/3bff159e/aria/cli/commands/__init__.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/__init__.py b/aria/cli/commands/__init__.py
index 7777791..a01a029 100644
--- a/aria/cli/commands/__init__.py
+++ b/aria/cli/commands/__init__.py
@@ -19,6 +19,7 @@ from . import (
     node_templates,
     nodes,
     plugins,
+    reset,
     service_templates,
     services,
     workflows

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/3bff159e/aria/cli/commands/reset.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/reset.py b/aria/cli/commands/reset.py
new file mode 100644
index 0000000..775f555
--- /dev/null
+++ b/aria/cli/commands/reset.py
@@ -0,0 +1,40 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from ..cli import aria
+from ..cli import helptexts
+from ..env import env
+from ..exceptions import AriaCliError
+
+
+@aria.command(name='reset',
+              short_help="Reset ARIA's working directory")
+@aria.options.force(help=helptexts.FORCE_RESET)
+@aria.options.reset_config
+@aria.pass_logger
+@aria.options.verbose()
+def reset(force, reset_config, logger):
+    """
+    Reset ARIA working directory
+    Resetting the working directory will result in the deletion of all state in ARIA; The user
+     configuration will remain intact, unless the `reset_config` flag has been set as well, in
+     which case the entire ARIA working directory shall be removed.
+    """
+    if not force:
+        raise AriaCliError("To reset the ARIA's working directory, you must also provide the force"
+                           " flag ('-f'/'--force').")
+
+    env.reset(reset_config=reset_config)
+    logger.info("ARIA's working directory has been reset")

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/3bff159e/aria/cli/commands/services.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/services.py b/aria/cli/commands/services.py
index b785006..78899c5 100644
--- a/aria/cli/commands/services.py
+++ b/aria/cli/commands/services.py
@@ -112,7 +112,7 @@ def create(service_template_name,
 @services.command(name='delete',
                   short_help='Delete a service')
 @aria.argument('service-name')
-@aria.options.force(help=helptexts.IGNORE_RUNNING_NODES)
+@aria.options.force(help=helptexts.IGNORE_AVAILABLE_NODES)
 @aria.options.verbose()
 @aria.pass_model_storage
 @aria.pass_resource_storage

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/3bff159e/aria/cli/config/config.py
----------------------------------------------------------------------
diff --git a/aria/cli/config/config.py b/aria/cli/config/config.py
index 7d76830..99f46ca 100644
--- a/aria/cli/config/config.py
+++ b/aria/cli/config/config.py
@@ -21,6 +21,9 @@ import pkg_resources
 from jinja2.environment import Template
 
 
+CONFIG_FILE_NAME = 'config.yaml'
+
+
 class CliConfig(object):
 
     def __init__(self, config_path):
@@ -29,7 +32,7 @@ class CliConfig(object):
 
     @classmethod
     def create_config(cls, workdir):
-        config_path = os.path.join(workdir, 'config.yaml')
+        config_path = os.path.join(workdir, CONFIG_FILE_NAME)
         if not os.path.isfile(config_path):
             config_template = pkg_resources.resource_string(
                 __package__,

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/3bff159e/aria/cli/env.py
----------------------------------------------------------------------
diff --git a/aria/cli/env.py b/aria/cli/env.py
index 71cf69a..52a4ec6 100644
--- a/aria/cli/env.py
+++ b/aria/cli/env.py
@@ -15,6 +15,7 @@
 
 
 import os
+import shutil
 
 from .config import config
 from .logger import Logging
@@ -76,6 +77,18 @@ class _Environment(object):
             self._plugin_manager = self._init_plugin_manager()
         return self._plugin_manager
 
+    def reset(self, reset_config):
+        if reset_config:
+            shutil.rmtree(self._workdir)
+        else:
+            _, dirs, files = next(os.walk(self._workdir))
+            files.remove(config.CONFIG_FILE_NAME)
+
+            for dir_ in dirs:
+                shutil.rmtree(os.path.join(self._workdir, dir_))
+            for file_ in files:
+                os.remove(os.path.join(self._workdir, file_))
+
     def _init_workdir(self):
         if not os.path.exists(self._workdir):
             os.makedirs(self._workdir)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/3bff159e/aria/cli/main.py
----------------------------------------------------------------------
diff --git a/aria/cli/main.py b/aria/cli/main.py
index 9ae41bf..01d224c 100644
--- a/aria/cli/main.py
+++ b/aria/cli/main.py
@@ -45,6 +45,7 @@ def _register_commands():
     _aria.add_command(commands.executions.executions)
     _aria.add_command(commands.plugins.plugins)
     _aria.add_command(commands.logs.logs)
+    _aria.add_command(commands.reset.reset)
 
 
 def main():


[05/12] incubator-ariatosca git commit: fixed ssh tests

Posted by av...@apache.org.
fixed ssh tests


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/8b0e451a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/8b0e451a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/8b0e451a

Branch: refs/heads/cli-tests
Commit: 8b0e451ab3cb5dbb7dbab3c53aac6730c3ea3d64
Parents: 1bfefd1
Author: Ran Ziv <ra...@gigaspaces.com>
Authored: Tue Apr 18 16:05:24 2017 +0300
Committer: Ran Ziv <ra...@gigaspaces.com>
Committed: Tue Apr 18 16:05:24 2017 +0300

----------------------------------------------------------------------
 tests/orchestrator/execution_plugin/test_ssh.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8b0e451a/tests/orchestrator/execution_plugin/test_ssh.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/execution_plugin/test_ssh.py b/tests/orchestrator/execution_plugin/test_ssh.py
index dcfd88e..a75d59a 100644
--- a/tests/orchestrator/execution_plugin/test_ssh.py
+++ b/tests/orchestrator/execution_plugin/test_ssh.py
@@ -222,11 +222,13 @@ class TestWithActualSSHServer(object):
                 'fabric_env': _FABRIC_ENV,
                 'process': process,
                 'use_sudo': use_sudo,
-                'hide_output': hide_output,
                 'custom_env_var': custom_input,
                 'test_operation': '',
-                'commands': commands
             }
+            if hide_output:
+                inputs['hide_output'] = hide_output
+            if commands:
+                inputs['commands'] = commands
             interface = mock.models.create_interface(
                 node.service,
                 'test',


[09/12] incubator-ariatosca git commit: more review fixes

Posted by av...@apache.org.
more review fixes


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/1cbd81b3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/1cbd81b3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/1cbd81b3

Branch: refs/heads/cli-tests
Commit: 1cbd81b3bb950dd589435af4bce6f0c1c1fc6411
Parents: c1f8eb6
Author: Ran Ziv <ra...@gigaspaces.com>
Authored: Wed Apr 19 13:19:26 2017 +0300
Committer: Ran Ziv <ra...@gigaspaces.com>
Committed: Wed Apr 19 13:19:26 2017 +0300

----------------------------------------------------------------------
 aria/cli/commands/executions.py                 |  7 +-
 aria/cli/commands/node_templates.py             |  6 +-
 aria/cli/commands/nodes.py                      |  7 +-
 aria/cli/commands/plugins.py                    | 50 ++---------
 aria/cli/commands/service_templates.py          | 38 ++++-----
 aria/cli/commands/services.py                   |  5 +-
 aria/cli/commands/workflows.py                  |  6 +-
 aria/cli/constants.py                           | 18 ----
 aria/cli/core/aria.py                           | 10 +--
 aria/cli/defaults.py                            | 20 +++++
 aria/cli/helptexts.py                           |  2 +-
 aria/cli/logger.py                              | 16 ++--
 aria/cli/service_template_utils.py              | 39 +++------
 aria/cli/table.py                               | 90 +++++++++++++-------
 aria/cli/utils.py                               | 88 ++++---------------
 aria/modeling/service_common.py                 | 10 +--
 aria/orchestrator/exceptions.py                 |  7 ++
 aria/orchestrator/plugin.py                     | 23 +++++
 aria/orchestrator/workflow_runner.py            |  2 +-
 aria/orchestrator/workflows/executor/celery.py  |  4 +-
 aria/orchestrator/workflows/executor/dry.py     |  3 +-
 aria/orchestrator/workflows/executor/process.py |  3 +-
 aria/orchestrator/workflows/executor/thread.py  |  3 +-
 aria/utils/http.py                              | 62 ++++++++++++++
 24 files changed, 258 insertions(+), 261 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/cli/commands/executions.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/executions.py b/aria/cli/commands/executions.py
index cd12ead..adec56b 100644
--- a/aria/cli/commands/executions.py
+++ b/aria/cli/commands/executions.py
@@ -51,7 +51,7 @@ def show(execution_id, model_storage, logger):
     logger.info('Showing execution {0}'.format(execution_id))
     execution = model_storage.execution.get(execution_id)
 
-    print_data(EXECUTION_COLUMNS, execution.to_dict(), 'Execution:', max_width=50)
+    print_data(EXECUTION_COLUMNS, execution, 'Execution:', col_max_width=50)
 
     # print execution parameters
     logger.info('Execution Inputs:')
@@ -63,7 +63,6 @@ def show(execution_id, model_storage, logger):
             logger.info('\t{0}: \t{1}'.format(input_name, input_value))
     else:
         logger.info('\tNo inputs')
-    logger.info('')
 
 
 @executions.command(name='list',
@@ -93,9 +92,9 @@ def list(service_name,
         logger.info('Listing all executions...')
         filters = {}
 
-    executions_list = [e.to_dict() for e in model_storage.execution.list(
+    executions_list = model_storage.execution.list(
         filters=filters,
-        sort=utils.storage_sort_param(sort_by, descending))]
+        sort=utils.storage_sort_param(sort_by, descending)).items
 
     print_data(EXECUTION_COLUMNS, executions_list, 'Executions:')
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/cli/commands/node_templates.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/node_templates.py b/aria/cli/commands/node_templates.py
index c79e125..f0ca2c1 100644
--- a/aria/cli/commands/node_templates.py
+++ b/aria/cli/commands/node_templates.py
@@ -44,7 +44,7 @@ def show(node_template_id, model_storage, logger):
     logger.info('Showing node template {0}'.format(node_template_id))
     node_template = model_storage.node_template.get(node_template_id)
 
-    print_data(NODE_TEMPLATE_COLUMNS, node_template.to_dict(), 'Node template:', max_width=50)
+    print_data(NODE_TEMPLATE_COLUMNS, node_template, 'Node template:', col_max_width=50)
 
     # print node template properties
     logger.info('Node template properties:')
@@ -86,8 +86,8 @@ def list(service_template_name, sort_by, descending, model_storage, logger):
         logger.info('Listing all node templates...')
         filters = {}
 
-    node_templates_list = [nt.to_dict() for nt in model_storage.node_template.list(
+    node_templates_list = model_storage.node_template.list(
         filters=filters,
-        sort=utils.storage_sort_param(sort_by, descending))]
+        sort=utils.storage_sort_param(sort_by, descending)).items
 
     print_data(NODE_TEMPLATE_COLUMNS, node_templates_list, 'Node templates:')

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/cli/commands/nodes.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/nodes.py b/aria/cli/commands/nodes.py
index b1f2acc..0a00478 100644
--- a/aria/cli/commands/nodes.py
+++ b/aria/cli/commands/nodes.py
@@ -43,7 +43,7 @@ def show(node_id, model_storage, logger):
     logger.info('Showing node {0}'.format(node_id))
     node = model_storage.node.get(node_id)
 
-    print_data(NODE_COLUMNS, node.to_dict(), 'Node:', 50)
+    print_data(NODE_COLUMNS, node, 'Node:', 50)
 
     # print node attributes
     logger.info('Node attributes:')
@@ -52,7 +52,6 @@ def show(node_id, model_storage, logger):
             logger.info('\t{0}: {1}'.format(prop_name, prop_value))
     else:
         logger.info('\tNo attributes')
-    logger.info('')
 
 
 @nodes.command(name='list',
@@ -81,8 +80,8 @@ def list(service_name,
         logger.info('Listing all nodes...')
         filters = {}
 
-    nodes_list = [node.to_dict() for node in model_storage.node.list(
+    nodes_list = model_storage.node.list(
         filters=filters,
-        sort=utils.storage_sort_param(sort_by, descending))]
+        sort=utils.storage_sort_param(sort_by, descending)).items
 
     print_data(NODE_COLUMNS, nodes_list, 'Nodes:')

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/cli/commands/plugins.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/plugins.py b/aria/cli/commands/plugins.py
index 41a272e..22552d6 100644
--- a/aria/cli/commands/plugins.py
+++ b/aria/cli/commands/plugins.py
@@ -13,11 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import zipfile
-
 from .. import utils
 from ..core import aria
-from ..exceptions import AriaCliError
 from ..table import print_data
 
 
@@ -37,52 +34,21 @@ def plugins():
                  short_help='Validate a plugin')
 @aria.argument('plugin-path')
 @aria.options.verbose()
+@aria.pass_plugin_manager
 @aria.pass_logger
-def validate(plugin_path, logger):
-    """Validate a plugin
+def validate(plugin_path, plugin_manager, logger):
+    """Validate a plugin archive
 
-    This will try to validate the plugin's archive is not corrupted.
-    A valid plugin is a wagon (http://github.com/cloudify-cosomo/wagon)
+    A valid plugin is a wagon (http://github.com/cloudify-cosmo/wagon)
     in the zip format (suffix may also be .wgn).
 
     `PLUGIN_PATH` is the path to wagon archive to validate.
     """
     logger.info('Validating plugin {0}...'.format(plugin_path))
-
-    if not zipfile.is_zipfile(plugin_path):
-        raise AriaCliError(
-            'Archive {0} is of an unsupported type. Only '
-            'zip/wgn is allowed'.format(plugin_path))
-    with zipfile.ZipFile(plugin_path, 'r') as zip_file:
-        infos = zip_file.infolist()
-        try:
-            package_name = infos[0].filename[:infos[0].filename.index('/')]
-            package_json_path = "{0}/{1}".format(package_name, 'package.json')
-            zip_file.getinfo(package_json_path)
-        except (KeyError, ValueError, IndexError):
-            raise AriaCliError(
-                'Failed to validate plugin {0} '
-                '(package.json was not found in archive)'.format(plugin_path))
-
+    plugin_manager.validate_plugin(plugin_path)
     logger.info('Plugin validated successfully')
 
 
-# @plugins.command(name='delete',
-#                  short_help='Delete a plugin')
-# @aria.argument('plugin-id')
-# @aria.options.verbose()
-# @aria.pass_model_storage
-# @aria.pass_logger
-# def delete(plugin_id, model_storage, logger):
-#     """Delete a plugin
-#
-#     `PLUGIN_ID` is the id of the plugin to delete.
-#     """
-#     logger.info('Deleting plugin {0}...'.format(plugin_id))
-#     model_storage.plugin.delete(plugin_id=plugin_id)
-#     logger.info('Plugin deleted')
-
-
 @plugins.command(name='install',
                  short_help='Install a plugin')
 @aria.argument('plugin-path')
@@ -114,7 +80,7 @@ def show(plugin_id, model_storage, logger):
     """
     logger.info('Showing plugin {0}...'.format(plugin_id))
     plugin = model_storage.plugin.get(plugin_id)
-    print_data(PLUGIN_COLUMNS, plugin.to_dict(), 'Plugin:')
+    print_data(PLUGIN_COLUMNS, plugin, 'Plugin:')
 
 
 @plugins.command(name='list',
@@ -128,6 +94,6 @@ def list(sort_by, descending, model_storage, logger):
     """List all plugins on the manager
     """
     logger.info('Listing all plugins...')
-    plugins_list = [p.to_dict() for p in model_storage.plugin.list(
-        sort=utils.storage_sort_param(sort_by, descending))]
+    plugins_list = model_storage.plugin.list(
+        sort=utils.storage_sort_param(sort_by, descending)).items
     print_data(PLUGIN_COLUMNS, plugins_list, 'Plugins:')

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/cli/commands/service_templates.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/service_templates.py b/aria/cli/commands/service_templates.py
index 2ef37c0..189ba51 100644
--- a/aria/cli/commands/service_templates.py
+++ b/aria/cli/commands/service_templates.py
@@ -18,16 +18,16 @@ import os
 
 from .. import csar
 from .. import service_template_utils
+from .. import table
 from .. import utils
 from ..core import aria
-from ..table import print_data
 from ...core import Core
 from ...storage import exceptions as storage_exceptions
 
 
-DESCRIPTION_LIMIT = 20
+DESCRIPTION_FIELD_LENGTH_LIMIT = 20
 SERVICE_TEMPLATE_COLUMNS = \
-    ['id', 'name', 'main_file_name', 'created_at', 'updated_at']
+    ['id', 'name', 'description', 'main_file_name', 'created_at', 'updated_at']
 
 
 @aria.group(name='service-templates')
@@ -51,11 +51,14 @@ def show(service_template_name, model_storage, logger):
     """
     logger.info('Showing service template {0}...'.format(service_template_name))
     service_template = model_storage.service_template.get_by_name(service_template_name)
-    services = [d.to_dict() for d in service_template.services]
     service_template_dict = service_template.to_dict()
-    service_template_dict['#services'] = len(services)
+    service_template_dict['#services'] = len(service_template.services)
+
+    column_formatters = \
+        dict(description=table.trim_formatter_generator(DESCRIPTION_FIELD_LENGTH_LIMIT))
     columns = SERVICE_TEMPLATE_COLUMNS + ['#services']
-    print_data(columns, service_template_dict, 'Service-template:', max_width=50)
+    table.print_data(columns, service_template_dict, 'Service-template:',
+                     column_formatters=column_formatters, col_max_width=50)
 
     if service_template_dict['description'] is not None:
         logger.info('Description:')
@@ -63,8 +66,8 @@ def show(service_template_name, model_storage, logger):
                                     os.linesep))
 
     logger.info('Existing services:')
-    logger.info('{0}{1}'.format([s['name'] for s in services],
-                                os.linesep))
+    for service in service_template.services:
+        logger.info('\t{0}'.format(service.name))
 
 
 @service_templates.command(name='list',
@@ -77,20 +80,15 @@ def show(service_template_name, model_storage, logger):
 def list(sort_by, descending, model_storage, logger):
     """List all service templates
     """
-    def trim_description(service_template):
-        if service_template['description'] is not None:
-            if len(service_template['description']) >= DESCRIPTION_LIMIT:
-                service_template['description'] = '{0}..'.format(
-                    service_template['description'][:DESCRIPTION_LIMIT - 2])
-        else:
-            service_template['description'] = ''
-        return service_template
 
     logger.info('Listing all service templates...')
-    service_templates_list = [trim_description(b.to_dict()) for b in
-                              model_storage.service_template.list(
-                                  sort=utils.storage_sort_param(sort_by, descending))]
-    print_data(SERVICE_TEMPLATE_COLUMNS, service_templates_list, 'Service templates:')
+    service_templates_list = model_storage.service_template.list(
+        sort=utils.storage_sort_param(sort_by, descending)).items
+
+    column_formatters = \
+        dict(description=table.trim_formatter_generator(DESCRIPTION_FIELD_LENGTH_LIMIT))
+    table.print_data(SERVICE_TEMPLATE_COLUMNS, service_templates_list, 'Service templates:',
+                     column_formatters=column_formatters)
 
 
 @service_templates.command(name='store',

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/cli/commands/services.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/services.py b/aria/cli/commands/services.py
index afa5e42..e1569a6 100644
--- a/aria/cli/commands/services.py
+++ b/aria/cli/commands/services.py
@@ -64,9 +64,9 @@ def list(service_template_name,
         logger.info('Listing all services...')
         filters = {}
 
-    services_list = [d.to_dict() for d in model_storage.service.list(
+    services_list = model_storage.service.list(
         sort=utils.storage_sort_param(sort_by=sort_by, descending=descending),
-        filters=filters)]
+        filters=filters).items
     print_data(SERVICE_COLUMNS, services_list, 'Services:')
 
 
@@ -177,4 +177,3 @@ def inputs(service_name, model_storage, logger):
         logger.info(inputs_string.getvalue())
     else:
         logger.info('\tNo inputs')
-    logger.info('')

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/cli/commands/workflows.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/workflows.py b/aria/cli/commands/workflows.py
index d380fac..5bd23b7 100644
--- a/aria/cli/commands/workflows.py
+++ b/aria/cli/commands/workflows.py
@@ -52,7 +52,7 @@ def show(workflow_name, service_name, model_storage, logger):
         'service_template_name': service.service_template_name,
         'service_name': service.name
     }
-    print_data(WORKFLOW_COLUMNS, workflow.to_dict(), 'Workflows:', defaults=defaults)
+    print_data(WORKFLOW_COLUMNS, workflow, 'Workflows:', defaults=defaults)
 
     # print workflow inputs
     required_inputs = dict()
@@ -78,7 +78,6 @@ def show(workflow_name, service_name, model_storage, logger):
         else:
             logger.info('\t\t{0}: \t{1}'.format(input_name,
                                                 input.value))
-    logger.info('')
 
 
 @workflows.command(name='list',
@@ -92,8 +91,7 @@ def list(service_name, model_storage, logger):
     """
     logger.info('Listing workflows for service {0}...'.format(service_name))
     service = model_storage.service.get_by_name(service_name)
-    workflows_list = [wf.to_dict() for wf in
-                      sorted(service.workflows.values(), key=lambda w: w.name)]
+    workflows_list = sorted(service.workflows.values(), key=lambda w: w.name)
 
     defaults = {
         'service_template_name': service.service_template_name,

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/cli/constants.py
----------------------------------------------------------------------
diff --git a/aria/cli/constants.py b/aria/cli/constants.py
deleted file mode 100644
index c68fb5e..0000000
--- a/aria/cli/constants.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-DEFAULT_SERVICE_TEMPLATE_FILENAME = 'service_template.yaml'
-HELP_TEXT_COLUMN_BUFFER = 5

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/cli/core/aria.py
----------------------------------------------------------------------
diff --git a/aria/cli/core/aria.py b/aria/cli/core/aria.py
index fb5a81b..fe6dc4b 100644
--- a/aria/cli/core/aria.py
+++ b/aria/cli/core/aria.py
@@ -27,9 +27,9 @@ from ..env import (
     env,
     logger
 )
+from .. import defaults
 from .. import helptexts
 from ..inputs import inputs_to_dict
-from ..constants import DEFAULT_SERVICE_TEMPLATE_FILENAME
 from ...utils.exceptions import get_exception_as_string
 from ... import __version__
 
@@ -316,13 +316,13 @@ class Options(object):
             '--descending',
             required=False,
             is_flag=True,
-            default=False,
+            default=defaults.SORT_DESCENDING_DEFAULT,
             help=helptexts.DESCENDING)
 
         self.service_template_filename = click.option(
             '-n',
             '--service-template-filename',
-            default=DEFAULT_SERVICE_TEMPLATE_FILENAME,
+            default=defaults.SERVICE_TEMPLATE_FILENAME_DEFAULT,
             help=helptexts.SERVICE_TEMPLATE_FILENAME)
 
     @staticmethod
@@ -354,7 +354,7 @@ class Options(object):
             help=help)
 
     @staticmethod
-    def task_max_attempts(default=30):
+    def task_max_attempts(default=defaults.TASK_MAX_ATTEMPTS_DEFAULT):
         return click.option(
             '--task-max-attempts',
             type=int,
@@ -370,7 +370,7 @@ class Options(object):
             help=helptexts.SORT_BY)
 
     @staticmethod
-    def task_retry_interval(default=30):
+    def task_retry_interval(default=defaults.TASK_RETRY_INTERVAL_DEFAULT):
         return click.option(
             '--task-retry-interval',
             type=int,

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/cli/defaults.py
----------------------------------------------------------------------
diff --git a/aria/cli/defaults.py b/aria/cli/defaults.py
new file mode 100644
index 0000000..6befd25
--- /dev/null
+++ b/aria/cli/defaults.py
@@ -0,0 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+SERVICE_TEMPLATE_FILENAME_DEFAULT = 'service_template.yaml'
+TASK_MAX_ATTEMPTS_DEFAULT = 30
+TASK_RETRY_INTERVAL_DEFAULT = 30
+SORT_DESCENDING_DEFAULT = False

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/cli/helptexts.py
----------------------------------------------------------------------
diff --git a/aria/cli/helptexts.py b/aria/cli/helptexts.py
index 6e31f47..1a3f6c0 100644
--- a/aria/cli/helptexts.py
+++ b/aria/cli/helptexts.py
@@ -29,7 +29,7 @@ EXECUTION_ID = "The unique identifier for the execution"
 SERVICE_TEMPLATE_PATH = "The path to the application's service template file"
 SERVICE_TEMPLATE_FILENAME = (
     "The name of the archive's main service template file. "
-    "This is only relevant if uploading a non-csar archive")
+    "This is only relevant if uploading a (non-csar) archive")
 INPUTS_PARAMS_USAGE = (
     '(Can be provided as wildcard based paths '
     '(*.yaml, /my_inputs/, etc..) to YAML files, a JSON string or as '

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/cli/logger.py
----------------------------------------------------------------------
diff --git a/aria/cli/logger.py b/aria/cli/logger.py
index 2f012d9..1ffa918 100644
--- a/aria/cli/logger.py
+++ b/aria/cli/logger.py
@@ -25,7 +25,7 @@ MEDIUM_VERBOSE = 2
 LOW_VERBOSE = 1
 NO_VERBOSE = 0
 
-DEFAULT_LOGGER_CONFIG = {
+LOGGER_CONFIG_TEMPLATE = {
     "version": 1,
     "formatters": {
         "file": {
@@ -57,7 +57,7 @@ class Logging(object):
     def __init__(self, config):
         self._log_file = None
         self._verbosity_level = NO_VERBOSE
-        self._all_loggers = []
+        self._all_loggers_names = []
         self._configure_loggers(config)
         self._lgr = logging.getLogger('aria.cli.main')
 
@@ -73,21 +73,21 @@ class Logging(object):
     def verbosity_level(self):
         return self._verbosity_level
 
-    def is_high_verbose_level(self):
-        return self.verbosity_level == HIGH_VERBOSE
-
     @verbosity_level.setter
     def verbosity_level(self, level):
         self._verbosity_level = level
         if self.is_high_verbose_level():
-            for logger_name in self._all_loggers:
+            for logger_name in self._all_loggers_names:
                 logging.getLogger(logger_name).setLevel(logging.DEBUG)
 
+    def is_high_verbose_level(self):
+        return self.verbosity_level == HIGH_VERBOSE
+
     def _configure_loggers(self, config):
         loggers_config = config.logging.loggers
         logfile = config.logging.filename
 
-        logger_dict = copy.deepcopy(DEFAULT_LOGGER_CONFIG)
+        logger_dict = copy.deepcopy(LOGGER_CONFIG_TEMPLATE)
         if logfile:
             # set filename on file handler
             logger_dict['handlers']['file']['filename'] = logfile
@@ -102,6 +102,7 @@ class Logging(object):
         loggers = {}
         for logger_name in loggers_config:
             loggers[logger_name] = dict(handlers=list(logger_dict['handlers'].keys()))
+            self._all_loggers_names.append(logger_name)
         logger_dict['loggers'] = loggers
 
         # set level for all loggers
@@ -109,6 +110,5 @@ class Logging(object):
             log = logging.getLogger(logger_name)
             level = logging._levelNames[logging_level.upper()]
             log.setLevel(level)
-            self._all_loggers.append(logger_name)
 
         dictconfig.dictConfig(logger_dict)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/cli/service_template_utils.py
----------------------------------------------------------------------
diff --git a/aria/cli/service_template_utils.py b/aria/cli/service_template_utils.py
index 0300449..382cce1 100644
--- a/aria/cli/service_template_utils.py
+++ b/aria/cli/service_template_utils.py
@@ -26,28 +26,23 @@ def get(source, service_template_filename):
     """Get a source and return a path to the main service template file
 
     The behavior based on then source argument content is:
-        -
+        - local yaml file: return the file
         - local archive:
             extract it locally and return path service template file
-        - local yaml file: return the file
         - URL:
-            - return it (download=False)
-            - download and get service template from downloaded file (download=True)
+            - download and get service template from downloaded archive
         - github repo:
-            - map it to a URL and return it (download=False)
-            - download and get service template from downloaded file (download=True)
+            - download and get service template from downloaded archive
 
     Supported archive types are: csar, zip, tar, tar.gz and tar.bz2
 
     :param source: Path/URL/github repo to archive/service-template file
     :type source: str
-    :param service_template_filename: Path to service template (if source is an archive file)
+    :param service_template_filename: Path to service template (if source is an archive [but
+     not a csar archive - with csars archives, this is read from the metadata file])
     :type service_template_filename: str
-    :param download: Download service template file if source is URL/github repo
-    :type download: bool
-    :return: Path to file (if archive/service-template file passed) or url
+    :return: Path to main service template file
     :rtype: str
-
     """
     if urlparse(source).scheme:
         downloaded_file = utils.download_file(source)
@@ -115,26 +110,12 @@ def _map_to_github_url(source):
     return url
 
 
-# def generate_id(service_template_path,
-#                 service_template_filename=DEFAULT_SERVICE_TEMPLATE_FILENAME):
-#     """The name of the service template will be the name of the folder.
-#     If service_template_filename is provided, it will be appended to the folder.
-#     """
-#     service_template_id = os.path.split(os.path.dirname(os.path.abspath(
-#         service_template_path)))[-1]
-#     if service_template_filename != DEFAULT_SERVICE_TEMPLATE_FILENAME:
-#         filename, _ = os.path.splitext(os.path.basename(service_template_filename))
-#         service_template_id = (service_template_id + '.' + filename)
-#     return service_template_id.replace('_', '-')
-
-
 def _is_archive(source):
     return archive_utils.is_archive(source) or csar.is_csar_archive(source)
 
 
 def _extract_csar_archive(archive):
-    if csar.is_csar_archive(archive):
-        reader = csar.read(source=archive)
-        main_service_template_file_name = os.path.basename(reader.entry_definitions)
-        return os.path.join(reader.destination,
-                            main_service_template_file_name)
+    reader = csar.read(source=archive)
+    main_service_template_file_name = os.path.basename(reader.entry_definitions)
+    return os.path.join(reader.destination,
+                        main_service_template_file_name)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/cli/table.py
----------------------------------------------------------------------
diff --git a/aria/cli/table.py b/aria/cli/table.py
index 36dcbea..11d791e 100644
--- a/aria/cli/table.py
+++ b/aria/cli/table.py
@@ -21,7 +21,25 @@ from prettytable import PrettyTable
 from .env import logger
 
 
-def generate(cols, data, defaults=None):
+def print_data(columns, items, header_text,
+               column_formatters=None, col_max_width=None, defaults=None):
+    if items is None:
+        items = []
+    elif not isinstance(items, list):
+        items = [items]
+
+    pretty_table = _generate(columns, data=items, column_formatters=column_formatters,
+                             defaults=defaults)
+    if col_max_width:
+        pretty_table.max_width = col_max_width
+    _log(header_text, pretty_table)
+
+
+def _log(title, table):
+    logger.info('{0}{1}{0}{2}{0}'.format(os.linesep, title, table))
+
+
+def _generate(cols, data, column_formatters=None, defaults=None):
     """
     Return a new PrettyTable instance representing the list.
 
@@ -32,10 +50,16 @@ def generate(cols, data, defaults=None):
 
                for example: ['id','name']
 
-        data - An iterable of dictionaries, each dictionary must
-               have key's corresponding to the cols items.
+        data - An iterable of dictionaries or objects, each element must
+               have keys or attributes corresponding to the cols items.
+
+               for example: [{'id':'123', 'name':'Pete'}]
 
-               for example: [{'id':'123', 'name':'Pete']
+        column_formatters - A dictionary from a column name to a function that may manipulate
+                            the values printed for this column.
+                            (See below for a few built-in formatter examples)
+
+                            for example: {'created_at': timestamp_formatter}
 
         defaults - A dictionary specifying default values for
                    key's that don't exist in the data itself.
@@ -45,25 +69,26 @@ def generate(cols, data, defaults=None):
 
     """
     def get_values_per_column(column, row_data):
-        if column in row_data:
-            if row_data[column] and isinstance(row_data[column], basestring):
-                try:
-                    datetime.strptime(row_data[column][:10], '%Y-%m-%d')
-                    row_data[column] = \
-                        row_data[column].replace('T', ' ').replace('Z', ' ')
-                except ValueError:
-                    # not a timestamp
-                    pass
-            elif row_data[column] and isinstance(row_data[column], list):
-                row_data[column] = ','.join(row_data[column])
-            elif not row_data[column]:
-                # if it's empty list, don't print []
-                row_data[column] = ''
-            return row_data[column]
+        if hasattr(row_data, column) or (isinstance(row_data, dict) and column in row_data):
+            val = row_data[column] if isinstance(row_data, dict) else getattr(row_data, column)
+
+            if val and isinstance(val, list):
+                val = [str(element) for element in val]
+                val = ','.join(val)
+            elif val is None or isinstance(val, list):
+                # don't print `[]` or `None` (but do print `0`, `False`, etc.)
+                val = ''
+
+            if column in column_formatters:
+                # calling the user's column formatter to manipulate the value
+                val = column_formatters[column](val)
+
+            return val
         else:
             return defaults[column]
 
-    pretty_table = PrettyTable([col for col in cols])
+    column_formatters = column_formatters or dict()
+    pretty_table = PrettyTable(list(cols))
 
     for datum in data:
         values_row = []
@@ -74,17 +99,18 @@ def generate(cols, data, defaults=None):
     return pretty_table
 
 
-def log(title, table):
-    logger.info('{0}{1}{0}{2}{0}'.format(os.linesep, title, table))
-
+def timestamp_formatter(value):
+    try:
+        datetime.strptime(value[:10], '%Y-%m-%d')
+        return value.replace('T', ' ').replace('Z', ' ')
+    except ValueError:
+        # not a timestamp
+        return value
 
-def print_data(columns, items, header_text, max_width=None, defaults=None):
-    if items is None:
-        items = []
-    elif not isinstance(items, list):
-        items = [items]
 
-    pretty_table = generate(columns, data=items, defaults=defaults)
-    if max_width:
-        pretty_table.max_width = max_width
-    log(header_text, pretty_table)
+def trim_formatter_generator(max_length):
+    def trim_formatter(value):
+        if len(value) >= max_length:
+            value = '{0}..'.format(value[:max_length - 2])
+        return value
+    return trim_formatter

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/cli/utils.py
----------------------------------------------------------------------
diff --git a/aria/cli/utils.py b/aria/cli/utils.py
index 3cc68c9..852f24d 100644
--- a/aria/cli/utils.py
+++ b/aria/cli/utils.py
@@ -15,41 +15,19 @@
 
 import os
 import sys
-import string
-import random
-import tempfile
 from StringIO import StringIO
 
 from backports.shutil_get_terminal_size import get_terminal_size
-import requests
 
 from .env import logger
 from .exceptions import AriaCliError
-
-
-def dump_to_file(collection, file_path):
-    with open(file_path, 'a') as f:
-        f.write(os.linesep.join(collection))
-        f.write(os.linesep)
-
-
-def is_virtual_env():
-    return hasattr(sys, 'real_prefix')
+from ..utils import http
 
 
 def storage_sort_param(sort_by, descending):
     return {sort_by: 'desc' if descending else 'asc'}
 
 
-def generate_random_string(size=6,
-                           chars=string.ascii_uppercase + string.digits):
-    return ''.join(random.choice(chars) for _ in range(size))
-
-
-def generate_suffixed_id(id):
-    return '{0}_{1}'.format(id, generate_random_string())
-
-
 def get_parameter_templates_as_string(parameter_templates):
     params_string = StringIO()
 
@@ -64,43 +42,28 @@ def get_parameter_templates_as_string(parameter_templates):
     return params_string.getvalue()
 
 
-def download_file(url, destination=None):
-    """Download file.
-
-    :param url: Location of the file to download
-    :type url: str
-    :param destination:
-        Location where the file should be saved (autogenerated by default)
-    :type destination: str | None
-    :returns: Location where the file was saved
-    :rtype: str
-
+def check_overriding_storage_exceptions(e, model_class, name):
     """
-    chunk_size = 1024
-
-    if not destination:
-        file_descriptor, destination = tempfile.mkstemp()
-        os.close(file_descriptor)
-    logger.info('Downloading {0} to {1}...'.format(url, destination))
-
-    try:
-        response = requests.get(url, stream=True)
-    except requests.exceptions.RequestException as ex:
-        raise AriaCliError(
-            'Failed to download {0}. ({1})'.format(url, str(ex)))
+    This method checks whether the storage exception is a known type where we'd like to override
+     the exception message; If so, it raises a new error. Otherwise it simply returns.
+    """
+    assert isinstance(e, BaseException)
+    if 'UNIQUE constraint failed' in e.message:
+        new_message = \
+            'Could not store {model_class} `{name}`{linesep}' \
+            'There already a exists a {model_class} with the same name' \
+                .format(model_class=model_class, name=name, linesep=os.linesep)
+        trace = sys.exc_info()[2]
+        raise type(e), type(e)(new_message), trace  # pylint: disable=raising-non-exception
 
-    final_url = response.url
-    if final_url != url:
-        logger.debug('Redirected to {0}'.format(final_url))
 
+def download_file(url):
+    progress_bar = generate_progress_handler(url, 'Downloading')
     try:
-        with open(destination, 'wb') as destination_file:
-            for chunk in response.iter_content(chunk_size):
-                destination_file.write(chunk)
-    except IOError as ex:
+        destination = http.download_file(url, logger=logger, progress_handler=progress_bar)
+    except Exception as e:
         raise AriaCliError(
-            'Failed to download {0}. ({1})'.format(url, str(ex)))
-
+            'Failed to download {0}. ({1})'.format(url, str(e)))
     return destination
 
 
@@ -150,18 +113,3 @@ def generate_progress_handler(file_path, action='', max_bar_length=80):
             sys.stdout.write(os.linesep)
 
     return print_progress
-
-
-def check_overriding_storage_exceptions(e, model_class, name):
-    """
-    This method checks whether the storage exception is a known type where we'd like to override
-     the exception message; If so, it raises a new error. Otherwise it simply returns.
-    """
-    assert isinstance(e, BaseException)
-    if 'UNIQUE constraint failed' in e.message:
-        new_message = \
-            'Could not store {model_class} `{name}`{linesep}' \
-            'There already a exists a {model_class} with the same name' \
-            .format(model_class=model_class, name=name, linesep=os.linesep)
-        trace = sys.exc_info()[2]
-        raise type(e), type(e)(new_message), trace  # pylint: disable=raising-non-exception

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/modeling/service_common.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py
index e7fda29..1188f34 100644
--- a/aria/modeling/service_common.py
+++ b/aria/modeling/service_common.py
@@ -87,14 +87,8 @@ class ParameterBase(TemplateModelMixin):
         if self.description:
             console.puts(context.style.meta(self.description))
 
-    @staticmethod
-    def unwrap_dict(parameters_dict):
-        """
-        Takes a parameters dict and simplifies it into key-value dict
-        :param parameters_dict: a parameter-name to parameter dict
-        :return: a parameter-name to parameter value dict
-        """
-        return dict((k, v.value) for k, v in parameters_dict.iteritems())
+    def unwrap(self):
+        return self.name, self.value
 
     @classmethod
     def wrap(cls, name, value, description=None):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/orchestrator/exceptions.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/exceptions.py b/aria/orchestrator/exceptions.py
index fd3b66d..8d3dcc6 100644
--- a/aria/orchestrator/exceptions.py
+++ b/aria/orchestrator/exceptions.py
@@ -25,6 +25,13 @@ class OrchestratorError(AriaError):
     pass
 
 
+class InvalidPluginError(AriaError):
+    """
+    Raised when an invalid plugin is validated unsuccessfully
+    """
+    pass
+
+
 class PluginAlreadyExistsError(AriaError):
     """
     Raised when a plugin with the same package name and package version already exists

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/orchestrator/plugin.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/plugin.py b/aria/orchestrator/plugin.py
index d526e9c..b79d7fc 100644
--- a/aria/orchestrator/plugin.py
+++ b/aria/orchestrator/plugin.py
@@ -17,6 +17,7 @@ import os
 import tempfile
 import subprocess
 import sys
+import zipfile
 from datetime import datetime
 
 import wagon
@@ -69,6 +70,28 @@ class PluginManager(object):
             self._plugins_dir,
             '{0}-{1}'.format(plugin.package_name, plugin.package_version))
 
+    @staticmethod
+    def validate_plugin(source):
+        """
+        validate a plugin archive.
+        A valid plugin is a wagon (http://github.com/cloudify-cosmo/wagon)
+        in the zip format (suffix may also be .wgn).
+        """
+        if not zipfile.is_zipfile(source):
+            raise exceptions.InvalidPluginError(
+                'Archive {0} is of an unsupported type. Only '
+                'zip/wgn is allowed'.format(source))
+        with zipfile.ZipFile(source, 'r') as zip_file:
+            infos = zip_file.infolist()
+            try:
+                package_name = infos[0].filename[:infos[0].filename.index('/')]
+                package_json_path = "{0}/{1}".format(package_name, 'package.json')
+                zip_file.getinfo(package_json_path)
+            except (KeyError, ValueError, IndexError):
+                raise exceptions.InvalidPluginError(
+                    'Failed to validate plugin {0} '
+                    '(package.json was not found in archive)'.format(source))
+
     def _install_wagon(self, source, prefix):
         pip_freeze_output = self._pip_freeze()
         file_descriptor, constraint_path = tempfile.mkstemp(prefix='constraint-', suffix='.txt')

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/orchestrator/workflow_runner.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflow_runner.py b/aria/orchestrator/workflow_runner.py
index 0051e8e..8779f06 100644
--- a/aria/orchestrator/workflow_runner.py
+++ b/aria/orchestrator/workflow_runner.py
@@ -80,7 +80,7 @@ class WorkflowRunner(object):
             task_retry_interval=task_retry_interval)
 
         # transforming the execution inputs to dict, to pass them to the workflow function
-        execution_inputs_dict = models.Parameter.unwrap_dict(self.execution.inputs)
+        execution_inputs_dict = dict(inp.unwrap() for inp in self.execution.inputs.values())
         self._tasks_graph = workflow_fn(ctx=workflow_context, **execution_inputs_dict)
 
         executor = executor or ProcessExecutor(plugin_manager=plugin_manager)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/orchestrator/workflows/executor/celery.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/executor/celery.py b/aria/orchestrator/workflows/executor/celery.py
index 3c98197..7bd9b7c 100644
--- a/aria/orchestrator/workflows/executor/celery.py
+++ b/aria/orchestrator/workflows/executor/celery.py
@@ -22,8 +22,6 @@ import Queue
 
 from aria.orchestrator.workflows.executor import BaseExecutor
 
-from ....modeling.models import Parameter
-
 
 class CeleryExecutor(BaseExecutor):
     """
@@ -46,7 +44,7 @@ class CeleryExecutor(BaseExecutor):
 
     def execute(self, task):
         self._tasks[task.id] = task
-        inputs = Parameter.unwrap_dict(task.inputs.iteritems())
+        inputs = dict(inp.unwrap() for inp in task.inputs.values())
         inputs['ctx'] = task.context
         self._results[task.id] = self._app.send_task(
             task.operation_mapping,

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/orchestrator/workflows/executor/dry.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/executor/dry.py b/aria/orchestrator/workflows/executor/dry.py
index b14f5d7..d894b25 100644
--- a/aria/orchestrator/workflows/executor/dry.py
+++ b/aria/orchestrator/workflows/executor/dry.py
@@ -20,7 +20,6 @@ Dry executor
 from datetime import datetime
 
 from .base import BaseExecutor
-from ....modeling.models import Parameter
 
 
 class DryExecutor(BaseExecutor):
@@ -38,7 +37,7 @@ class DryExecutor(BaseExecutor):
         actor_type = type(task.actor).__name__.lower()
         implementation = '{0} > '.format(task.plugin) if task.plugin else ''
         implementation += task.implementation
-        inputs = Parameter.unwrap_dict(task.inputs)
+        inputs = dict(inp.unwrap() for inp in task.inputs.values())
 
         task.context.logger.info(
             'Executing {actor_type} {task.actor.name} operation {task.interface_name} '

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/orchestrator/workflows/executor/process.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/executor/process.py b/aria/orchestrator/workflows/executor/process.py
index 3c2b5fe..851d78e 100644
--- a/aria/orchestrator/workflows/executor/process.py
+++ b/aria/orchestrator/workflows/executor/process.py
@@ -48,7 +48,6 @@ from aria.utils import exceptions
 from aria.orchestrator.workflows.executor import base
 from aria.storage import instrumentation
 from aria.modeling import types as modeling_types
-from aria.modeling.models import Parameter
 
 _IS_WIN = os.name == 'nt'
 
@@ -149,7 +148,7 @@ class ProcessExecutor(base.BaseExecutor):
         return {
             'task_id': task.id,
             'implementation': task.implementation,
-            'operation_inputs': Parameter.unwrap_dict(task.inputs),
+            'operation_inputs': dict(inp.unwrap() for inp in task.inputs.values()),
             'port': self._server_port,
             'context': task.context.serialization_dict,
         }

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/orchestrator/workflows/executor/thread.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/executor/thread.py b/aria/orchestrator/workflows/executor/thread.py
index 8b443cc..f422592 100644
--- a/aria/orchestrator/workflows/executor/thread.py
+++ b/aria/orchestrator/workflows/executor/thread.py
@@ -23,7 +23,6 @@ import threading
 from aria.utils import imports
 
 from .base import BaseExecutor
-from ....modeling.models import Parameter
 
 
 class ThreadExecutor(BaseExecutor):
@@ -60,7 +59,7 @@ class ThreadExecutor(BaseExecutor):
                 self._task_started(task)
                 try:
                     task_func = imports.load_attribute(task.implementation)
-                    inputs = Parameter.unwrap_dict(task.inputs)
+                    inputs = dict(inp.unwrap() for inp in task.inputs.values())
                     task_func(ctx=task.context, **inputs)
                     self._task_succeeded(task)
                 except BaseException as e:

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1cbd81b3/aria/utils/http.py
----------------------------------------------------------------------
diff --git a/aria/utils/http.py b/aria/utils/http.py
new file mode 100644
index 0000000..7bdfd79
--- /dev/null
+++ b/aria/utils/http.py
@@ -0,0 +1,62 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import tempfile
+
+import requests
+
+
+def download_file(url, destination=None, logger=None, progress_handler=None):
+    """Download file.
+
+    May raise IOError as well as requests.exceptions.RequestException
+    :param url: Location of the file to download
+    :type url: str
+    :param destination:
+        Location where the file should be saved (autogenerated by default)
+    :type destination: str | None
+    :returns: Location where the file was saved
+    :rtype: str
+
+    """
+    chunk_size = 1024
+
+    if not destination:
+        file_descriptor, destination = tempfile.mkstemp()
+        os.close(file_descriptor)
+    if logger:
+        logger.info('Downloading {0} to {1}...'.format(url, destination))
+
+    response = requests.get(url, stream=True)
+    final_url = response.url
+    if final_url != url and logger:
+        logger.debug('Redirected to {0}'.format(final_url))
+
+    read_bytes = 0
+    total_size = int(response.headers['Content-Length']) \
+        if 'Content-Length' in response.headers else None
+    try:
+        with open(destination, 'wb') as destination_file:
+            for chunk in response.iter_content(chunk_size):
+                destination_file.write(chunk)
+                if total_size and progress_handler:
+                    # Only showing progress bar if we have the total content length
+                    read_bytes += chunk_size
+                    progress_handler(read_bytes, total_size)
+    finally:
+        response.close()
+
+    return destination



[04/12] incubator-ariatosca git commit: fix failing ssh tests

Posted by av...@apache.org.
fix failing ssh tests


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/1bfefd17
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/1bfefd17
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/1bfefd17

Branch: refs/heads/cli-tests
Commit: 1bfefd17890c7c65c12f0a943e60dc714ac95adf
Parents: 38f9aba
Author: Ran Ziv <ra...@gigaspaces.com>
Authored: Tue Apr 18 15:38:41 2017 +0300
Committer: Ran Ziv <ra...@gigaspaces.com>
Committed: Tue Apr 18 15:38:41 2017 +0300

----------------------------------------------------------------------
 tests/mock/models.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1bfefd17/tests/mock/models.py
----------------------------------------------------------------------
diff --git a/tests/mock/models.py b/tests/mock/models.py
index 38c2b28..8a9273b 100644
--- a/tests/mock/models.py
+++ b/tests/mock/models.py
@@ -190,7 +190,8 @@ def create_interface(service, interface_name, operation_name, operation_kwargs=N
     if operation_kwargs and operation_kwargs.get('inputs'):
         operation_kwargs['inputs'] = dict(
             (input_name, models.Parameter.wrap(input_name, input_value))
-            for input_name, input_value in operation_kwargs['inputs'].iteritems())
+            for input_name, input_value in operation_kwargs['inputs'].iteritems()
+            if input_value is not None)
 
     operation = models.Operation(
         name=operation_name,


[10/12] incubator-ariatosca git commit: final review fixes

Posted by av...@apache.org.
final review fixes


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/a39e7d13
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/a39e7d13
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/a39e7d13

Branch: refs/heads/cli-tests
Commit: a39e7d134989b5df753a50c9bcdf9c7a34e9a03f
Parents: 1cbd81b
Author: Ran Ziv <ra...@gigaspaces.com>
Authored: Wed Apr 19 14:01:41 2017 +0300
Committer: Ran Ziv <ra...@gigaspaces.com>
Committed: Wed Apr 19 14:01:41 2017 +0300

----------------------------------------------------------------------
 aria/cli/table.py                    | 4 ++--
 aria/modeling/orchestration.py       | 2 +-
 aria/orchestrator/workflow_runner.py | 3 +--
 3 files changed, 4 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/a39e7d13/aria/cli/table.py
----------------------------------------------------------------------
diff --git a/aria/cli/table.py b/aria/cli/table.py
index 11d791e..408f81e 100644
--- a/aria/cli/table.py
+++ b/aria/cli/table.py
@@ -55,8 +55,8 @@ def _generate(cols, data, column_formatters=None, defaults=None):
 
                for example: [{'id':'123', 'name':'Pete'}]
 
-        column_formatters - A dictionary from a column name to a function that may manipulate
-                            the values printed for this column.
+        column_formatters - A dictionary from a column name to a formatter - a function that
+                            may manipulate the string values printed for this column.
                             (See below for a few built-in formatter examples)
 
                             for example: {'created_at': timestamp_formatter}

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/a39e7d13/aria/modeling/orchestration.py
----------------------------------------------------------------------
diff --git a/aria/modeling/orchestration.py b/aria/modeling/orchestration.py
index a2f041b..01ab2e8 100644
--- a/aria/modeling/orchestration.py
+++ b/aria/modeling/orchestration.py
@@ -101,7 +101,7 @@ class ExecutionBase(ModelMixin):
         return self.status in self.END_STATES
 
     def is_active(self):
-        return not self.has_ended()
+        return not self.has_ended() and self.status != self.PENDING
 
     @declared_attr
     def logs(cls):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/a39e7d13/aria/orchestrator/workflow_runner.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflow_runner.py b/aria/orchestrator/workflow_runner.py
index 8779f06..1ea60a1 100644
--- a/aria/orchestrator/workflow_runner.py
+++ b/aria/orchestrator/workflow_runner.py
@@ -129,8 +129,7 @@ class WorkflowRunner(object):
                 .format(self._workflow_name, self.service.name))
 
     def _validate_no_active_executions(self, execution):
-        active_executions = [e for e in self.service.executions
-                             if e.id != execution.id and e.is_active()]
+        active_executions = [e for e in self.service.executions if e.is_active()]
         if active_executions:
             raise exceptions.ActiveExecutionsError(
                 "Can't start execution; Service {0} has an active execution with id {1}"


[07/12] incubator-ariatosca git commit: reviewed helptexts module; renamed cli.cli package to cli.core

Posted by av...@apache.org.
reviewed helptexts module; renamed cli.cli package to cli.core


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/79f5d78e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/79f5d78e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/79f5d78e

Branch: refs/heads/cli-tests
Commit: 79f5d78ebe31327e7635ae75551ba636ac5fd1dc
Parents: 3bff159
Author: Ran Ziv <ra...@gigaspaces.com>
Authored: Tue Apr 18 16:55:52 2017 +0300
Committer: Ran Ziv <ra...@gigaspaces.com>
Committed: Tue Apr 18 16:55:52 2017 +0300

----------------------------------------------------------------------
 aria/cli/cli/__init__.py               |  14 -
 aria/cli/cli/aria.py                   | 439 ----------------------------
 aria/cli/cli/helptexts.py              |  57 ----
 aria/cli/commands/executions.py        |   5 +-
 aria/cli/commands/logs.py              |   2 +-
 aria/cli/commands/node_templates.py    |   4 +-
 aria/cli/commands/nodes.py             |   2 +-
 aria/cli/commands/plugins.py           |   4 +-
 aria/cli/commands/reset.py             |   4 +-
 aria/cli/commands/service_templates.py |   2 +-
 aria/cli/commands/services.py          |   5 +-
 aria/cli/commands/workflows.py         |   2 +-
 aria/cli/core/__init__.py              |  14 +
 aria/cli/core/aria.py                  | 429 +++++++++++++++++++++++++++
 aria/cli/helptexts.py                  |  49 ++++
 aria/cli/main.py                       |   2 +-
 16 files changed, 509 insertions(+), 525 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/79f5d78e/aria/cli/cli/__init__.py
----------------------------------------------------------------------
diff --git a/aria/cli/cli/__init__.py b/aria/cli/cli/__init__.py
deleted file mode 100644
index ae1e83e..0000000
--- a/aria/cli/cli/__init__.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/79f5d78e/aria/cli/cli/aria.py
----------------------------------------------------------------------
diff --git a/aria/cli/cli/aria.py b/aria/cli/cli/aria.py
deleted file mode 100644
index 548be23..0000000
--- a/aria/cli/cli/aria.py
+++ /dev/null
@@ -1,439 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-import os
-import sys
-import difflib
-import StringIO
-import traceback
-from functools import wraps
-
-import click
-
-from ..env import (
-    env,
-    logger
-)
-from ..cli import helptexts
-from ..inputs import inputs_to_dict
-from ..constants import DEFAULT_SERVICE_TEMPLATE_FILENAME
-from ...utils.exceptions import get_exception_as_string
-from ... import __version__
-
-
-CLICK_CONTEXT_SETTINGS = dict(
-    help_option_names=['-h', '--help'],
-    token_normalize_func=lambda param: param.lower())
-
-
-class MutuallyExclusiveOption(click.Option):
-    """Makes options mutually exclusive. The option must pass a `cls` argument
-    with this class name and a `mutually_exclusive` argument with a list of
-    argument names it is mutually exclusive with.
-
-    NOTE: All mutually exclusive options must use this. It's not enough to
-    use it in just one of the options.
-    """
-
-    def __init__(self, *args, **kwargs):
-        self.mutually_exclusive = set(kwargs.pop('mutually_exclusive', []))
-        self.mutuality_error_message = \
-            kwargs.pop('mutuality_error_message',
-                       helptexts.DEFAULT_MUTUALITY_MESSAGE)
-        self.mutuality_string = ', '.join(self.mutually_exclusive)
-        if self.mutually_exclusive:
-            help = kwargs.get('help', '')
-            kwargs['help'] = (
-                '{0}. This argument is mutually exclusive with '
-                'arguments: [{1}] ({2})'.format(
-                    help,
-                    self.mutuality_string,
-                    self.mutuality_error_message))
-        super(MutuallyExclusiveOption, self).__init__(*args, **kwargs)
-
-    def handle_parse_result(self, ctx, opts, args):
-        if self.mutually_exclusive.intersection(opts) and self.name in opts:
-            raise click.UsageError(
-                'Illegal usage: `{0}` is mutually exclusive with '
-                'arguments: [{1}] ({2}).'.format(
-                    self.name,
-                    self.mutuality_string,
-                    self.mutuality_error_message))
-        return super(MutuallyExclusiveOption, self).handle_parse_result(
-            ctx, opts, args)
-
-
-def _format_version_data(version,
-                         prefix=None,
-                         suffix=None,
-                         infix=None):
-    all_data = dict(version=version)
-    all_data['prefix'] = prefix or ''
-    all_data['suffix'] = suffix or ''
-    all_data['infix'] = infix or ''
-    output = StringIO.StringIO()
-    output.write('{prefix}{version}'.format(**all_data))
-    output.write('{suffix}'.format(**all_data))
-    return output.getvalue()
-
-
-def show_version(ctx, param, value):
-    if not value:
-        return
-
-    cli_version = _format_version_data(
-        __version__,
-        prefix='ARIA CLI ',
-        infix=' ' * 5,
-        suffix='')
-
-    logger.info(cli_version)
-    ctx.exit()
-
-
-def inputs_callback(ctx, param, value):
-    """Allow to pass any inputs we provide to a command as
-    processed inputs instead of having to call `inputs_to_dict`
-    inside the command.
-
-    `@aria.options.inputs` already calls this callback so that
-    every time you use the option it returns the inputs as a
-    dictionary.
-    """
-    if not value:
-        return {}
-
-    return inputs_to_dict(value)
-
-
-def set_verbosity_level(ctx, param, value):
-    if not value:
-        return
-
-    env.logging.verbosity_level = value
-
-
-def set_cli_except_hook():
-
-    def recommend(possible_solutions):
-        logger.info('Possible solutions:')
-        for solution in possible_solutions:
-            logger.info('  - {0}'.format(solution))
-
-    def new_excepthook(tpe, value, trace):
-        if env.logging.is_high_verbose_level():
-            # log error including traceback
-            logger.error(get_exception_as_string(tpe, value, trace))
-        else:
-            # write the full error to the log file
-            with open(env.logging.log_file, 'a') as log_file:
-                traceback.print_exception(
-                    etype=tpe,
-                    value=value,
-                    tb=trace,
-                    file=log_file)
-            # print only the error message
-            print value
-
-        if hasattr(value, 'possible_solutions'):
-            recommend(getattr(value, 'possible_solutions'))
-
-    sys.excepthook = new_excepthook
-
-
-def pass_logger(func):
-    """Simply passes the logger to a command.
-    """
-    # Wraps here makes sure the original docstring propagates to click
-    @wraps(func)
-    def wrapper(*args, **kwargs):
-        return func(logger=logger, *args, **kwargs)
-
-    return wrapper
-
-
-def pass_plugin_manager(func):
-    """Simply passes the plugin manager to a command.
-    """
-    # Wraps here makes sure the original docstring propagates to click
-    @wraps(func)
-    def wrapper(*args, **kwargs):
-        return func(plugin_manager=env.plugin_manager, *args, **kwargs)
-
-    return wrapper
-
-
-def pass_model_storage(func):
-    """Simply passes the model storage to a command.
-    """
-    # Wraps here makes sure the original docstring propagates to click
-    @wraps(func)
-    def wrapper(*args, **kwargs):
-        return func(model_storage=env.model_storage, *args, **kwargs)
-
-    return wrapper
-
-
-def pass_resource_storage(func):
-    """Simply passes the resource storage to a command.
-    """
-    # Wraps here makes sure the original docstring propagates to click
-    @wraps(func)
-    def wrapper(*args, **kwargs):
-        return func(resource_storage=env.resource_storage, *args, **kwargs)
-
-    return wrapper
-
-
-def pass_context(func):
-    """Make click context ARIA specific
-
-    This exists purely for aesthetic reasons, otherwise
-    Some decorators are called `@click.something` instead of
-    `@aria.something`
-    """
-    return click.pass_context(func)
-
-
-class AliasedGroup(click.Group):
-    def __init__(self, *args, **kwargs):
-        self.max_suggestions = kwargs.pop("max_suggestions", 3)
-        self.cutoff = kwargs.pop("cutoff", 0.5)
-        super(AliasedGroup, self).__init__(*args, **kwargs)
-
-    def get_command(self, ctx, cmd_name):
-        cmd = click.Group.get_command(self, ctx, cmd_name)
-        if cmd is not None:
-            return cmd
-        matches = \
-            [x for x in self.list_commands(ctx) if x.startswith(cmd_name)]
-        if not matches:
-            return None
-        elif len(matches) == 1:
-            return click.Group.get_command(self, ctx, matches[0])
-        ctx.fail('Too many matches: {0}'.format(', '.join(sorted(matches))))
-
-    def resolve_command(self, ctx, args):
-        """Override clicks ``resolve_command`` method
-        and appends *Did you mean ...* suggestions
-        to the raised exception message.
-        """
-        try:
-            return super(AliasedGroup, self).resolve_command(ctx, args)
-        except click.exceptions.UsageError as error:
-            error_msg = str(error)
-            original_cmd_name = click.utils.make_str(args[0])
-            matches = difflib.get_close_matches(
-                original_cmd_name,
-                self.list_commands(ctx),
-                self.max_suggestions,
-                self.cutoff)
-            if matches:
-                error_msg += '{0}{0}Did you mean one of these?{0}    {1}'.format(
-                    os.linesep,
-                    '{0}    '.format(os.linesep).join(matches, ))
-            raise click.exceptions.UsageError(error_msg, error.ctx)
-
-
-def group(name):
-    """Allow to create a group with a default click context
-    and a cls for click's `didyoueamn` without having to repeat
-    it for every group.
-    """
-    return click.group(
-        name=name,
-        context_settings=CLICK_CONTEXT_SETTINGS,
-        cls=AliasedGroup)
-
-
-def command(*args, **kwargs):
-    """Make Click commands ARIA specific
-
-    This exists purely for aesthetical reasons, otherwise
-    Some decorators are called `@click.something` instead of
-    `@aria.something`
-    """
-    return click.command(*args, **kwargs)
-
-
-def argument(*args, **kwargs):
-    """Make Click arguments ARIA specific
-
-    This exists purely for aesthetic reasons, otherwise
-    Some decorators are called `@click.something` instead of
-    `@aria.something`
-    """
-    return click.argument(*args, **kwargs)
-
-
-class Options(object):
-    def __init__(self):
-        """The options api is nicer when you use each option by calling
-        `@aria.options.some_option` instead of `@aria.some_option`.
-
-        Note that some options are attributes and some are static methods.
-        The reason for that is that we want to be explicit regarding how
-        a developer sees an option. It it can receive arguments, it's a
-        method - if not, it's an attribute.
-        """
-        self.version = click.option(
-            '--version',
-            is_flag=True,
-            callback=show_version,
-            expose_value=False,
-            is_eager=True,
-            help=helptexts.VERSION)
-
-        self.inputs = click.option(
-            '-i',
-            '--inputs',
-            multiple=True,
-            callback=inputs_callback,
-            help=helptexts.INPUTS)
-
-        self.json_output = click.option(
-            '--json-output',
-            is_flag=True,
-            help=helptexts.JSON_OUTPUT)
-
-        self.dry_execution = click.option(
-            '--dry',
-            is_flag=True,
-            help=helptexts.DRY_EXECUTION)
-
-        self.reset_config = click.option(
-            '--reset-config',
-            is_flag=True,
-            help=helptexts.RESET_CONFIG)
-
-        self.enable_colors = click.option(
-            '--enable-colors',
-            is_flag=True,
-            default=False,
-            help=helptexts.ENABLE_COLORS)
-
-        self.node_name = click.option(
-            '-n',
-            '--node-name',
-            required=False,
-            help=helptexts.NODE_NAME)
-
-        self.descending = click.option(
-            '--descending',
-            required=False,
-            is_flag=True,
-            default=False,
-            help=helptexts.DESCENDING)
-
-        self.service_template_filename = click.option(
-            '-n',
-            '--service-template-filename',
-            default=DEFAULT_SERVICE_TEMPLATE_FILENAME,
-            help=helptexts.SERVICE_TEMPLATE_FILENAME)
-
-    @staticmethod
-    def verbose(expose_value=False):
-        return click.option(
-            '-v',
-            '--verbose',
-            count=True,
-            callback=set_verbosity_level,
-            expose_value=expose_value,
-            is_eager=True,
-            help=helptexts.VERBOSE)
-
-    @staticmethod
-    def force(help):
-        return click.option(
-            '-f',
-            '--force',
-            is_flag=True,
-            help=help)
-
-    @staticmethod
-    def task_max_attempts(default=1):
-        return click.option(
-            '--task-max-attempts',
-            type=int,
-            default=default,
-            help=helptexts.TASK_MAX_ATTEMPTS.format(default))
-
-    @staticmethod
-    def sort_by(default='created_at'):
-        return click.option(
-            '--sort-by',
-            required=False,
-            default=default,
-            help=helptexts.SORT_BY)
-
-    @staticmethod
-    def task_retry_interval(default=1):
-        return click.option(
-            '--task-retry-interval',
-            type=int,
-            default=default,
-            help=helptexts.TASK_RETRY_INTERVAL.format(default))
-
-    @staticmethod
-    def service_id(required=False):
-        return click.option(
-            '-s',
-            '--service-id',
-            required=required,
-            help=helptexts.SERVICE_ID)
-
-    @staticmethod
-    def execution_id(required=False):
-        return click.option(
-            '-e',
-            '--execution-id',
-            required=required,
-            help=helptexts.EXECUTION_ID)
-
-    @staticmethod
-    def service_template_id(required=False):
-        return click.option(
-            '-t',
-            '--service-template-id',
-            required=required,
-            help=helptexts.SERVICE_TEMPLATE_ID)
-
-    @staticmethod
-    def service_template_path(required=False):
-        return click.option(
-            '-p',
-            '--service-template-path',
-            required=required,
-            type=click.Path(exists=True))
-
-    @staticmethod
-    def service_name(required=False):
-        return click.option(
-            '-s',
-            '--service-name',
-            required=required,
-            help=helptexts.SERVICE_ID)
-
-    @staticmethod
-    def service_template_name(required=False):
-        return click.option(
-            '-t',
-            '--service-template-name',
-            required=required,
-            help=helptexts.SERVICE_ID)
-
-
-options = Options()

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/79f5d78e/aria/cli/cli/helptexts.py
----------------------------------------------------------------------
diff --git a/aria/cli/cli/helptexts.py b/aria/cli/cli/helptexts.py
deleted file mode 100644
index f8b315c..0000000
--- a/aria/cli/cli/helptexts.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-VERBOSE = \
-    "Show verbose output. You can supply this up to three times (i.e. -vvv)"
-VERSION = "Display the version and exit"
-
-INPUTS_PARAMS_USAGE = (
-    '(Can be provided as wildcard based paths '
-    '(*.yaml, /my_inputs/, etc..) to YAML files, a JSON string or as '
-    'key1=value1;key2=value2). This argument can be used multiple times'
-)
-
-SERVICE_TEMPLATE_PATH = "The path to the application's service template file"
-SERVICE_TEMPLATE_ID = "The unique identifier for the service template"
-
-FORCE_RESET = "Confirmation for resetting ARIA's working directory"
-RESET_CONFIG = "Reset ARIA's user configuration"
-ENABLE_COLORS = "Enable colors in logger (use --hard when working with" \
-                " an initialized environment) [default: False]"
-
-DRY_EXECUTION = "Execute a workflow dry run (prints operations information without causing side " \
-                "effects)"
-SERVICE_TEMPLATE_FILENAME = (
-    "The name of the archive's main service template file. "
-    "This is only relevant if uploading an archive")
-INPUTS = "Inputs for the service {0}".format(INPUTS_PARAMS_USAGE)
-PARAMETERS = "Parameters for the workflow {0}".format(INPUTS_PARAMS_USAGE)
-TASK_RETRY_INTERVAL = \
-    "How long of a minimal interval should occur between task retry attempts [default: {0}]"
-TASK_MAX_ATTEMPTS = \
-    "How many times should a task be attempted in case of failures [default: {0}]"
-
-JSON_OUTPUT = "Output events in a consumable JSON format"
-
-SERVICE_ID = "The unique identifier for the service"
-EXECUTION_ID = "The unique identifier for the execution"
-IGNORE_AVAILABLE_NODES = "Delete the service even if it has available nodes"
-
-NODE_NAME = "The node's name"
-
-DEFAULT_MUTUALITY_MESSAGE = 'Cannot be used simultaneously'
-
-SORT_BY = "Key for sorting the list"
-DESCENDING = "Sort list in descending order [default: False]"

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/79f5d78e/aria/cli/commands/executions.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/executions.py b/aria/cli/commands/executions.py
index 730fd29..cd12ead 100644
--- a/aria/cli/commands/executions.py
+++ b/aria/cli/commands/executions.py
@@ -15,9 +15,10 @@
 
 import os
 
+from .. import helptexts
 from .. import utils
+from ..core import aria
 from ..table import print_data
-from ..cli import aria
 from ...modeling.models import Execution
 from ...orchestrator.workflow_runner import WorkflowRunner
 from ...orchestrator.workflows.executor.dry import DryExecutor
@@ -103,7 +104,7 @@ def list(service_name,
                     short_help='Execute a workflow')
 @aria.argument('workflow-name')
 @aria.options.service_name(required=True)
-@aria.options.inputs
+@aria.options.inputs(help=helptexts.EXECUTION_INPUTS)
 @aria.options.dry_execution
 @aria.options.task_max_attempts()
 @aria.options.task_retry_interval()

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/79f5d78e/aria/cli/commands/logs.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/logs.py b/aria/cli/commands/logs.py
index f8873cd..8888fef 100644
--- a/aria/cli/commands/logs.py
+++ b/aria/cli/commands/logs.py
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 from .. import utils
-from ..cli import aria
+from ..core import aria
 
 
 @aria.group(name='logs')

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/79f5d78e/aria/cli/commands/node_templates.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/node_templates.py b/aria/cli/commands/node_templates.py
index cf50ceb..b63b630 100644
--- a/aria/cli/commands/node_templates.py
+++ b/aria/cli/commands/node_templates.py
@@ -13,9 +13,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from ..table import print_data
 from .. import utils
-from ..cli import aria
+from ..core import aria
+from ..table import print_data
 
 
 NODE_TEMPLATE_COLUMNS = ['id', 'name', 'description', 'service_template_name', 'type_name']

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/79f5d78e/aria/cli/commands/nodes.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/nodes.py b/aria/cli/commands/nodes.py
index fd65e24..b1f2acc 100644
--- a/aria/cli/commands/nodes.py
+++ b/aria/cli/commands/nodes.py
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 from .. import utils
-from ..cli import aria
+from ..core import aria
 from ..table import print_data
 
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/79f5d78e/aria/cli/commands/plugins.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/plugins.py b/aria/cli/commands/plugins.py
index 9e7d449..680284f 100644
--- a/aria/cli/commands/plugins.py
+++ b/aria/cli/commands/plugins.py
@@ -15,9 +15,9 @@
 
 import zipfile
 
-from ..table import print_data
-from ..cli import aria
+from ..core import aria
 from ..exceptions import AriaCliError
+from ..table import print_data
 from ..utils import storage_sort_param
 
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/79f5d78e/aria/cli/commands/reset.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/reset.py b/aria/cli/commands/reset.py
index 775f555..1fe0714 100644
--- a/aria/cli/commands/reset.py
+++ b/aria/cli/commands/reset.py
@@ -13,8 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from ..cli import aria
-from ..cli import helptexts
+from .. import helptexts
+from ..core import aria
 from ..env import env
 from ..exceptions import AriaCliError
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/79f5d78e/aria/cli/commands/service_templates.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/service_templates.py b/aria/cli/commands/service_templates.py
index 8e0e91c..93dc188 100644
--- a/aria/cli/commands/service_templates.py
+++ b/aria/cli/commands/service_templates.py
@@ -19,7 +19,7 @@ import os
 from .. import utils
 from .. import csar
 from .. import service_template_utils
-from ..cli import aria
+from ..core import aria
 from ..table import print_data
 from ..exceptions import AriaCliError
 from ..utils import handle_storage_exception

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/79f5d78e/aria/cli/commands/services.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/services.py b/aria/cli/commands/services.py
index 78899c5..4728509 100644
--- a/aria/cli/commands/services.py
+++ b/aria/cli/commands/services.py
@@ -18,7 +18,8 @@ import os
 from StringIO import StringIO
 
 from . import service_templates
-from ..cli import aria, helptexts
+from .. import helptexts
+from ..core import aria
 from ..exceptions import AriaCliError
 from ..table import print_data
 from ..utils import storage_sort_param, handle_storage_exception
@@ -74,7 +75,7 @@ def list(service_template_name,
                   short_help='Create a services')
 @aria.argument('service-name', required=False)
 @aria.options.service_template_name(required=True)
-@aria.options.inputs
+@aria.options.inputs(help=helptexts.SERVICE_INPUTS)
 @aria.options.verbose()
 @aria.pass_model_storage
 @aria.pass_resource_storage

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/79f5d78e/aria/cli/commands/workflows.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/workflows.py b/aria/cli/commands/workflows.py
index 72dea5b..d380fac 100644
--- a/aria/cli/commands/workflows.py
+++ b/aria/cli/commands/workflows.py
@@ -13,8 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from ..core import aria
 from ..table import print_data
-from ..cli import aria
 from ..exceptions import AriaCliError
 
 WORKFLOW_COLUMNS = ['name', 'service_template_name', 'service_name']

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/79f5d78e/aria/cli/core/__init__.py
----------------------------------------------------------------------
diff --git a/aria/cli/core/__init__.py b/aria/cli/core/__init__.py
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/aria/cli/core/__init__.py
@@ -0,0 +1,14 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/79f5d78e/aria/cli/core/aria.py
----------------------------------------------------------------------
diff --git a/aria/cli/core/aria.py b/aria/cli/core/aria.py
new file mode 100644
index 0000000..cd1036e
--- /dev/null
+++ b/aria/cli/core/aria.py
@@ -0,0 +1,429 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+import os
+import sys
+import difflib
+import StringIO
+import traceback
+from functools import wraps
+
+import click
+
+from ..env import (
+    env,
+    logger
+)
+from .. import helptexts
+from ..inputs import inputs_to_dict
+from ..constants import DEFAULT_SERVICE_TEMPLATE_FILENAME
+from ...utils.exceptions import get_exception_as_string
+from ... import __version__
+
+
+CLICK_CONTEXT_SETTINGS = dict(
+    help_option_names=['-h', '--help'],
+    token_normalize_func=lambda param: param.lower())
+
+
+class MutuallyExclusiveOption(click.Option):
+    """Makes options mutually exclusive. The option must pass a `cls` argument
+    with this class name and a `mutually_exclusive` argument with a list of
+    argument names it is mutually exclusive with.
+
+    NOTE: All mutually exclusive options must use this. It's not enough to
+    use it in just one of the options.
+    """
+
+    def __init__(self, *args, **kwargs):
+        self.mutually_exclusive = set(kwargs.pop('mutually_exclusive', []))
+        self.mutuality_error_message = \
+            kwargs.pop('mutuality_error_message',
+                       helptexts.DEFAULT_MUTUALITY_MESSAGE)
+        self.mutuality_string = ', '.join(self.mutually_exclusive)
+        if self.mutually_exclusive:
+            help = kwargs.get('help', '')
+            kwargs['help'] = (
+                '{0}. This argument is mutually exclusive with '
+                'arguments: [{1}] ({2})'.format(
+                    help,
+                    self.mutuality_string,
+                    self.mutuality_error_message))
+        super(MutuallyExclusiveOption, self).__init__(*args, **kwargs)
+
+    def handle_parse_result(self, ctx, opts, args):
+        if self.mutually_exclusive.intersection(opts) and self.name in opts:
+            raise click.UsageError(
+                'Illegal usage: `{0}` is mutually exclusive with '
+                'arguments: [{1}] ({2}).'.format(
+                    self.name,
+                    self.mutuality_string,
+                    self.mutuality_error_message))
+        return super(MutuallyExclusiveOption, self).handle_parse_result(
+            ctx, opts, args)
+
+
+def _format_version_data(version,
+                         prefix=None,
+                         suffix=None,
+                         infix=None):
+    all_data = dict(version=version)
+    all_data['prefix'] = prefix or ''
+    all_data['suffix'] = suffix or ''
+    all_data['infix'] = infix or ''
+    output = StringIO.StringIO()
+    output.write('{prefix}{version}'.format(**all_data))
+    output.write('{suffix}'.format(**all_data))
+    return output.getvalue()
+
+
+def show_version(ctx, param, value):
+    if not value:
+        return
+
+    cli_version = _format_version_data(
+        __version__,
+        prefix='ARIA CLI ',
+        infix=' ' * 5,
+        suffix='')
+
+    logger.info(cli_version)
+    ctx.exit()
+
+
+def inputs_callback(ctx, param, value):
+    """Allow to pass any inputs we provide to a command as
+    processed inputs instead of having to call `inputs_to_dict`
+    inside the command.
+
+    `@aria.options.inputs` already calls this callback so that
+    every time you use the option it returns the inputs as a
+    dictionary.
+    """
+    if not value:
+        return {}
+
+    return inputs_to_dict(value)
+
+
+def set_verbosity_level(ctx, param, value):
+    if not value:
+        return
+
+    env.logging.verbosity_level = value
+
+
+def set_cli_except_hook():
+
+    def recommend(possible_solutions):
+        logger.info('Possible solutions:')
+        for solution in possible_solutions:
+            logger.info('  - {0}'.format(solution))
+
+    def new_excepthook(tpe, value, trace):
+        if env.logging.is_high_verbose_level():
+            # log error including traceback
+            logger.error(get_exception_as_string(tpe, value, trace))
+        else:
+            # write the full error to the log file
+            with open(env.logging.log_file, 'a') as log_file:
+                traceback.print_exception(
+                    etype=tpe,
+                    value=value,
+                    tb=trace,
+                    file=log_file)
+            # print only the error message
+            print value
+
+        if hasattr(value, 'possible_solutions'):
+            recommend(getattr(value, 'possible_solutions'))
+
+    sys.excepthook = new_excepthook
+
+
+def pass_logger(func):
+    """Simply passes the logger to a command.
+    """
+    # Wraps here makes sure the original docstring propagates to click
+    @wraps(func)
+    def wrapper(*args, **kwargs):
+        return func(logger=logger, *args, **kwargs)
+
+    return wrapper
+
+
+def pass_plugin_manager(func):
+    """Simply passes the plugin manager to a command.
+    """
+    # Wraps here makes sure the original docstring propagates to click
+    @wraps(func)
+    def wrapper(*args, **kwargs):
+        return func(plugin_manager=env.plugin_manager, *args, **kwargs)
+
+    return wrapper
+
+
+def pass_model_storage(func):
+    """Simply passes the model storage to a command.
+    """
+    # Wraps here makes sure the original docstring propagates to click
+    @wraps(func)
+    def wrapper(*args, **kwargs):
+        return func(model_storage=env.model_storage, *args, **kwargs)
+
+    return wrapper
+
+
+def pass_resource_storage(func):
+    """Simply passes the resource storage to a command.
+    """
+    # Wraps here makes sure the original docstring propagates to click
+    @wraps(func)
+    def wrapper(*args, **kwargs):
+        return func(resource_storage=env.resource_storage, *args, **kwargs)
+
+    return wrapper
+
+
+def pass_context(func):
+    """Make click context ARIA specific
+
+    This exists purely for aesthetic reasons, otherwise
+    Some decorators are called `@click.something` instead of
+    `@aria.something`
+    """
+    return click.pass_context(func)
+
+
+class AliasedGroup(click.Group):
+    def __init__(self, *args, **kwargs):
+        self.max_suggestions = kwargs.pop("max_suggestions", 3)
+        self.cutoff = kwargs.pop("cutoff", 0.5)
+        super(AliasedGroup, self).__init__(*args, **kwargs)
+
+    def get_command(self, ctx, cmd_name):
+        cmd = click.Group.get_command(self, ctx, cmd_name)
+        if cmd is not None:
+            return cmd
+        matches = \
+            [x for x in self.list_commands(ctx) if x.startswith(cmd_name)]
+        if not matches:
+            return None
+        elif len(matches) == 1:
+            return click.Group.get_command(self, ctx, matches[0])
+        ctx.fail('Too many matches: {0}'.format(', '.join(sorted(matches))))
+
+    def resolve_command(self, ctx, args):
+        """Override clicks ``resolve_command`` method
+        and appends *Did you mean ...* suggestions
+        to the raised exception message.
+        """
+        try:
+            return super(AliasedGroup, self).resolve_command(ctx, args)
+        except click.exceptions.UsageError as error:
+            error_msg = str(error)
+            original_cmd_name = click.utils.make_str(args[0])
+            matches = difflib.get_close_matches(
+                original_cmd_name,
+                self.list_commands(ctx),
+                self.max_suggestions,
+                self.cutoff)
+            if matches:
+                error_msg += '{0}{0}Did you mean one of these?{0}    {1}'.format(
+                    os.linesep,
+                    '{0}    '.format(os.linesep).join(matches, ))
+            raise click.exceptions.UsageError(error_msg, error.ctx)
+
+
+def group(name):
+    """Allow to create a group with a default click context
+    and a cls for click's `didyoueamn` without having to repeat
+    it for every group.
+    """
+    return click.group(
+        name=name,
+        context_settings=CLICK_CONTEXT_SETTINGS,
+        cls=AliasedGroup)
+
+
+def command(*args, **kwargs):
+    """Make Click commands ARIA specific
+
+    This exists purely for aesthetical reasons, otherwise
+    Some decorators are called `@click.something` instead of
+    `@aria.something`
+    """
+    return click.command(*args, **kwargs)
+
+
+def argument(*args, **kwargs):
+    """Make Click arguments ARIA specific
+
+    This exists purely for aesthetic reasons, otherwise
+    Some decorators are called `@click.something` instead of
+    `@aria.something`
+    """
+    return click.argument(*args, **kwargs)
+
+
+class Options(object):
+    def __init__(self):
+        """The options api is nicer when you use each option by calling
+        `@aria.options.some_option` instead of `@aria.some_option`.
+
+        Note that some options are attributes and some are static methods.
+        The reason for that is that we want to be explicit regarding how
+        a developer sees an option. It it can receive arguments, it's a
+        method - if not, it's an attribute.
+        """
+        self.version = click.option(
+            '--version',
+            is_flag=True,
+            callback=show_version,
+            expose_value=False,
+            is_eager=True,
+            help=helptexts.VERSION)
+
+        self.json_output = click.option(
+            '--json-output',
+            is_flag=True,
+            help=helptexts.JSON_OUTPUT)
+
+        self.dry_execution = click.option(
+            '--dry',
+            is_flag=True,
+            help=helptexts.DRY_EXECUTION)
+
+        self.reset_config = click.option(
+            '--reset-config',
+            is_flag=True,
+            help=helptexts.RESET_CONFIG)
+
+        self.descending = click.option(
+            '--descending',
+            required=False,
+            is_flag=True,
+            default=False,
+            help=helptexts.DESCENDING)
+
+        self.service_template_filename = click.option(
+            '-n',
+            '--service-template-filename',
+            default=DEFAULT_SERVICE_TEMPLATE_FILENAME,
+            help=helptexts.SERVICE_TEMPLATE_FILENAME)
+
+    @staticmethod
+    def verbose(expose_value=False):
+        return click.option(
+            '-v',
+            '--verbose',
+            count=True,
+            callback=set_verbosity_level,
+            expose_value=expose_value,
+            is_eager=True,
+            help=helptexts.VERBOSE)
+
+    @staticmethod
+    def inputs(help):
+        return click.option(
+            '-i',
+            '--inputs',
+            multiple=True,
+            callback=inputs_callback,
+            help=help)
+
+    @staticmethod
+    def force(help):
+        return click.option(
+            '-f',
+            '--force',
+            is_flag=True,
+            help=help)
+
+    @staticmethod
+    def task_max_attempts(default=1):
+        return click.option(
+            '--task-max-attempts',
+            type=int,
+            default=default,
+            help=helptexts.TASK_MAX_ATTEMPTS.format(default))
+
+    @staticmethod
+    def sort_by(default='created_at'):
+        return click.option(
+            '--sort-by',
+            required=False,
+            default=default,
+            help=helptexts.SORT_BY)
+
+    @staticmethod
+    def task_retry_interval(default=1):
+        return click.option(
+            '--task-retry-interval',
+            type=int,
+            default=default,
+            help=helptexts.TASK_RETRY_INTERVAL.format(default))
+
+    @staticmethod
+    def service_id(required=False):
+        return click.option(
+            '-s',
+            '--service-id',
+            required=required,
+            help=helptexts.SERVICE_ID)
+
+    @staticmethod
+    def execution_id(required=False):
+        return click.option(
+            '-e',
+            '--execution-id',
+            required=required,
+            help=helptexts.EXECUTION_ID)
+
+    @staticmethod
+    def service_template_id(required=False):
+        return click.option(
+            '-t',
+            '--service-template-id',
+            required=required,
+            help=helptexts.SERVICE_TEMPLATE_ID)
+
+    @staticmethod
+    def service_template_path(required=False):
+        return click.option(
+            '-p',
+            '--service-template-path',
+            required=required,
+            type=click.Path(exists=True))
+
+    @staticmethod
+    def service_name(required=False):
+        return click.option(
+            '-s',
+            '--service-name',
+            required=required,
+            help=helptexts.SERVICE_ID)
+
+    @staticmethod
+    def service_template_name(required=False):
+        return click.option(
+            '-t',
+            '--service-template-name',
+            required=required,
+            help=helptexts.SERVICE_ID)
+
+
+options = Options()

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/79f5d78e/aria/cli/helptexts.py
----------------------------------------------------------------------
diff --git a/aria/cli/helptexts.py b/aria/cli/helptexts.py
new file mode 100644
index 0000000..6e31f47
--- /dev/null
+++ b/aria/cli/helptexts.py
@@ -0,0 +1,49 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+DEFAULT_MUTUALITY_MESSAGE = 'Cannot be used simultaneously'
+VERBOSE = \
+    "Show verbose output. You can supply this up to three times (i.e. -vvv)"
+
+VERSION = "Display the version and exit"
+FORCE_RESET = "Confirmation for resetting ARIA's working directory"
+RESET_CONFIG = "Reset ARIA's user configuration"
+
+SERVICE_TEMPLATE_ID = "The unique identifier for the service template"
+SERVICE_ID = "The unique identifier for the service"
+EXECUTION_ID = "The unique identifier for the execution"
+
+SERVICE_TEMPLATE_PATH = "The path to the application's service template file"
+SERVICE_TEMPLATE_FILENAME = (
+    "The name of the archive's main service template file. "
+    "This is only relevant if uploading a non-csar archive")
+INPUTS_PARAMS_USAGE = (
+    '(Can be provided as wildcard based paths '
+    '(*.yaml, /my_inputs/, etc..) to YAML files, a JSON string or as '
+    'key1=value1;key2=value2). This argument can be used multiple times')
+SERVICE_INPUTS = "Inputs for the service {0}".format(INPUTS_PARAMS_USAGE)
+EXECUTION_INPUTS = "Inputs for the execution {0}".format(INPUTS_PARAMS_USAGE)
+
+TASK_RETRY_INTERVAL = \
+    "How long of a minimal interval should occur between task retry attempts [default: {0}]"
+TASK_MAX_ATTEMPTS = \
+    "How many times should a task be attempted in case of failures [default: {0}]"
+DRY_EXECUTION = "Execute a workflow dry run (prints operations information without causing side " \
+                "effects)"
+IGNORE_AVAILABLE_NODES = "Delete the service even if it has available nodes"
+SORT_BY = "Key for sorting the list"
+DESCENDING = "Sort list in descending order [default: False]"
+JSON_OUTPUT = "Output logs in a consumable JSON format"

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/79f5d78e/aria/cli/main.py
----------------------------------------------------------------------
diff --git a/aria/cli/main.py b/aria/cli/main.py
index 01d224c..02cf095 100644
--- a/aria/cli/main.py
+++ b/aria/cli/main.py
@@ -15,7 +15,7 @@
 
 from aria import install_aria_extensions
 from aria.cli import commands
-from aria.cli.cli import aria
+from aria.cli.core import aria
 
 
 @aria.group(name='aria')



[12/12] incubator-ariatosca git commit: Refactor cli tests framework

Posted by av...@apache.org.
Refactor cli tests framework


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/ed07f9f2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/ed07f9f2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/ed07f9f2

Branch: refs/heads/cli-tests
Commit: ed07f9f278c4752641aceac71c5988fc2e1a06d2
Parents: 9169cb3
Author: Avia Efrat <av...@gigaspaces.com>
Authored: Wed Apr 19 14:17:27 2017 +0300
Committer: Avia Efrat <av...@gigaspaces.com>
Committed: Wed Apr 19 14:20:57 2017 +0300

----------------------------------------------------------------------
 tests/cli/test_logs.py              |  23 ------
 tests/cli/test_node_templates.py    |  56 ++++++++------
 tests/cli/test_nodes.py             |  21 +++--
 tests/cli/test_service_templates.py | 124 +++++++++++++++++++++---------
 tests/cli/test_services.py          |  93 +++++++++++-----------
 tests/cli/utils.py                  | 128 ++++---------------------------
 tests/mock/models.py                |  69 +++++++++++++----
 tests/mock/topology.py              |   8 +-
 tests/modeling/test_models.py       |   5 +-
 9 files changed, 258 insertions(+), 269 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ed07f9f2/tests/cli/test_logs.py
----------------------------------------------------------------------
diff --git a/tests/cli/test_logs.py b/tests/cli/test_logs.py
deleted file mode 100644
index ad0c4f1..0000000
--- a/tests/cli/test_logs.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from aria.cli.env import _Environment
-from tests.cli.base_test import TestCliBase, mock_storage
-
-
-class TestLogsList(TestCliBase):
-
-    def test_existing_logs(self, monkeypatch, mock_storage):
-        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
-        self.invoke('logs list exec_id')
-
-        assert 'Listing logs for execution id exec_id' in self.logger_output_string
-        assert 'log_msg' in self.logger_output_string
-        assert 'No logs' not in self.logger_output_string
-
-    def test_no_logs(self, monkeypatch, mock_object):
-        m = mock_object
-        m.log.list.return_value = []
-        monkeypatch.setattr(_Environment, 'model_storage', m)
-        self.invoke('logs list exec_id')
-
-        assert 'Listing logs for execution id exec_id' in self.logger_output_string
-        assert 'log_msg' not in self.logger_output_string
-        assert 'No logs' in self.logger_output_string

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ed07f9f2/tests/cli/test_node_templates.py
----------------------------------------------------------------------
diff --git a/tests/cli/test_node_templates.py b/tests/cli/test_node_templates.py
index f0ad539..931c0a4 100644
--- a/tests/cli/test_node_templates.py
+++ b/tests/cli/test_node_templates.py
@@ -1,57 +1,66 @@
-from mock import ANY
+from mock import ANY, MagicMock
 import pytest
 
 from aria.cli.env import _Environment
 from tests.cli.base_test import TestCliBase, mock_storage  # pylint: disable=unused-import
+from tests.mock.models import create_node_template_with_dependencies, NODE_NAME, \
+    SERVICE_TEMPLATE_NAME, NODE_TEMPLATE_NAME
 
 
 class TestNodeTemplatesShow(TestCliBase):
 
-    def test_no_properties_no_nodes(self, monkeypatch, mock_storage):
-
+    def test_header_strings(self, monkeypatch, mock_storage):
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
         self.invoke('node_templates show 1')
         assert 'Showing node template 1' in self.logger_output_string
         assert 'Node template properties:' in self.logger_output_string
+        assert 'Nodes:' in self.logger_output_string
+
+    def test_no_properties_no_nodes(self, monkeypatch, mock_storage):
+
+        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        self.invoke('node_templates show 1')
+
         assert 'No properties' in self.logger_output_string
         assert 'prop1' not in self.logger_output_string
         assert 'value1' not in self.logger_output_string
         assert 'No nodes' in self.logger_output_string
-        assert 'node1' not in self.logger_output_string
+        assert NODE_NAME not in self.logger_output_string
 
     def test_one_property_no_nodes(self, monkeypatch, mock_storage):
 
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        m = MagicMock(return_value=create_node_template_with_dependencies(include_property=True))
+        monkeypatch.setattr(mock_storage.node_template, 'get', m)
         self.invoke('node_templates show 2')
-        assert 'Showing node template 2' in self.logger_output_string
-        assert 'Node template properties:' in self.logger_output_string
         assert 'No properties' not in self.logger_output_string
         assert 'prop1' in self.logger_output_string and 'value1' in self.logger_output_string
         assert 'No nodes' in self.logger_output_string
-        assert 'node1' not in self.logger_output_string
+        assert NODE_NAME not in self.logger_output_string
 
     def test_no_properties_one_node(self, monkeypatch, mock_storage):
 
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        m = MagicMock(return_value=create_node_template_with_dependencies(include_node=True))
+        monkeypatch.setattr(mock_storage.node_template, 'get', m)
         self.invoke('node_templates show 3')
-        assert 'Showing node template 3' in self.logger_output_string
-        assert 'Node template properties:' in self.logger_output_string
         assert 'No properties' in self.logger_output_string
         assert 'prop1' not in self.logger_output_string
         assert 'value1' not in self.logger_output_string
         assert 'No nodes' not in self.logger_output_string
-        assert 'node1' in self.logger_output_string
+        assert NODE_NAME in self.logger_output_string
 
     def test_one_property_one_node(self, monkeypatch, mock_storage):
 
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        m = MagicMock(return_value=create_node_template_with_dependencies(include_node=True,
+                                                                          include_property=True))
+        monkeypatch.setattr(mock_storage.node_template, 'get', m)
         self.invoke('node_templates show 4')
-        assert 'Showing node template 4' in self.logger_output_string
-        assert 'Node template properties:' in self.logger_output_string
         assert 'No properties' not in self.logger_output_string
         assert 'prop1' in self.logger_output_string and 'value1' in self.logger_output_string
         assert 'No nodes' not in self.logger_output_string
-        assert 'node1' in self.logger_output_string
+        assert NODE_NAME in self.logger_output_string
 
 
 class TestNodeTemplatesList(TestCliBase):
@@ -66,17 +75,20 @@ class TestNodeTemplatesList(TestCliBase):
                                              sort_by_in_output, order_in_output):
 
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
-        self.invoke('node_templates list -t test_st{sort_by}{order}'.format(sort_by=sort_by,
-                                                                            order=order))
-        assert 'Listing node templates for service template test_st...' in self.logger_output_string
+        self.invoke('node_templates list -t {service_template_name}{sort_by}{order}'
+                    .format(service_template_name=SERVICE_TEMPLATE_NAME,
+                            sort_by=sort_by,
+                            order=order))
+        assert 'Listing node templates for service template ' \
+               '{name}...'.format(name=SERVICE_TEMPLATE_NAME) in self.logger_output_string
         assert 'Listing all node templates...' not in self.logger_output_string
 
         node_templates_list = mock_storage.node_template.list
         node_templates_list.assert_called_once_with(sort={sort_by_in_output: order_in_output},
                                                     filters={'service_template': ANY})
         assert 'Node templates:' in self.logger_output_string
-        assert 'test_st' in self.logger_output_string
-        assert 'test_nt' in self.logger_output_string
+        assert SERVICE_TEMPLATE_NAME in self.logger_output_string
+        assert NODE_TEMPLATE_NAME in self.logger_output_string
 
     @pytest.mark.parametrize('sort_by, order, sort_by_in_output, order_in_output', [
         ('', '', 'service_template_name', 'asc'),
@@ -90,12 +102,12 @@ class TestNodeTemplatesList(TestCliBase):
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
         self.invoke('node_templates list{sort_by}{order}'.format(sort_by=sort_by, order=order))
         assert 'Listing all node templates...' in self.logger_output_string
-        assert 'Listing node templates for service template test_st...' not in \
-               self.logger_output_string
+        assert 'Listing node templates for service template ' \
+               '{name}...'.format(name=SERVICE_TEMPLATE_NAME) not in self.logger_output_string
 
         node_templates_list = mock_storage.node_template.list
         node_templates_list.assert_called_once_with(sort={sort_by_in_output: order_in_output},
                                                     filters={})
         assert 'Node templates:' in self.logger_output_string
-        assert 'test_st' in self.logger_output_string
-        assert 'test_nt' in self.logger_output_string
+        assert SERVICE_TEMPLATE_NAME in self.logger_output_string
+        assert NODE_TEMPLATE_NAME in self.logger_output_string

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ed07f9f2/tests/cli/test_nodes.py
----------------------------------------------------------------------
diff --git a/tests/cli/test_nodes.py b/tests/cli/test_nodes.py
index 9be97ca..e5a081c 100644
--- a/tests/cli/test_nodes.py
+++ b/tests/cli/test_nodes.py
@@ -1,19 +1,24 @@
 import pytest
-from mock import ANY
+from mock import ANY, MagicMock
 
 from aria.cli.env import _Environment
 from tests.cli.base_test import TestCliBase, mock_storage  # pylint: disable=unused-import
+from tests.mock.models import create_node_with_dependencies
 
 
 class TestNodesShow(TestCliBase):
 
-    def test_no_attributes(self, monkeypatch, mock_storage):
-
+    def test_header_strings(self, monkeypatch, mock_storage):
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
         self.invoke('nodes show 1')
         assert 'Showing node 1' in self.logger_output_string
         assert 'Node:' in self.logger_output_string
         assert 'Node attributes:' in self.logger_output_string
+
+    def test_no_attributes(self, monkeypatch, mock_storage):
+
+        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        self.invoke('nodes show 2')
         assert 'No attributes' in self.logger_output_string
         assert 'attribute1' not in self.logger_output_string
         assert 'value1' not in self.logger_output_string
@@ -21,12 +26,12 @@ class TestNodesShow(TestCliBase):
     def test_one_attribute(self, monkeypatch, mock_storage):
 
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
-        self.invoke('nodes show 2')
-        assert 'Showing node 2' in self.logger_output_string
-        assert 'Node:' in self.logger_output_string
-        assert 'Node attributes:' in self.logger_output_string
+        m = MagicMock(return_value=create_node_with_dependencies(include_attribute=True))
+        monkeypatch.setattr(mock_storage.node, 'get', m)
+        self.invoke('nodes show 3')
         assert 'No attributes' not in self.logger_output_string
-        assert 'attribute1' in self.logger_output_string and 'value1' in self.logger_output_string
+        assert 'attribute1' in self.logger_output_string
+        assert 'value1' in self.logger_output_string
 
 
 class TestNodesList(TestCliBase):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ed07f9f2/tests/cli/test_service_templates.py
----------------------------------------------------------------------
diff --git a/tests/cli/test_service_templates.py b/tests/cli/test_service_templates.py
index ef70c37..67ba567 100644
--- a/tests/cli/test_service_templates.py
+++ b/tests/cli/test_service_templates.py
@@ -1,4 +1,5 @@
 import pytest
+from mock import MagicMock
 
 from aria.cli import service_template_utils, csar
 from aria.cli.env import _Environment
@@ -7,51 +8,76 @@ from aria.core import Core
 from aria.exceptions import AriaException
 from aria.storage import exceptions as storage_exceptions
 from tests.cli.base_test import TestCliBase, assert_exception_raised, raise_exception, mock_storage  # pylint: disable=unused-import
+from tests.mock.models import create_service_template, create_service, create_parameter, \
+    SERVICE_TEMPLATE_NAME, SERVICE_NAME
 
 
 class TestServiceTemplatesShow(TestCliBase):
 
-    def test_show_no_services_no_description(self, monkeypatch, mock_storage):
+    def test_header_string(self, monkeypatch, mock_storage):
 
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
-        self.invoke('service_templates show no_services_no_description')
+        self.invoke('service_templates show test_st')
+        assert 'Showing service template test_st...' in self.logger_output_string
+
+    def test_no_services_no_description(self, monkeypatch, mock_storage):
+
+        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        self.invoke('service_templates show test_st')
 
-        assert 'Showing service template no_services_no_description...' in self.logger_output_string
         assert 'Description:' not in self.logger_output_string
-        assert 'Existing services:\n[]' in self.logger_output_string
+        assert 'Existing services:' not in self.logger_output_string
 
-    def test_show_no_services_yes_description(self, monkeypatch, mock_storage):
+    def test_no_services_yes_description(self, monkeypatch, mock_storage):
 
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
-        self.invoke('service_templates show no_services_yes_description')
+        st = create_service_template(description='test_description')
+        monkeypatch.setattr(mock_storage.service_template, 'get_by_name',
+                            MagicMock(return_value=st))
 
-        assert 'Showing service template no_services_yes_description...' in \
-               self.logger_output_string
-        assert 'Description:\ntest_description' in self.logger_output_string
-        assert 'Existing services:\n[]' in self.logger_output_string
+        self.invoke('service_templates show test_st')
+        assert 'Description:' in self.logger_output_string
+        assert 'test_description' in self.logger_output_string
+        assert 'Existing services:' not in self.logger_output_string
 
-    def test_show_one_service_no_description(self, monkeypatch, mock_storage):
+    def test_one_service_no_description(self, monkeypatch, mock_storage):
 
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
-        self.invoke('service_templates show one_service_no_description')
+        st = create_service_template()
+        st.services = [create_service(st)]
+        monkeypatch.setattr(mock_storage.service_template, 'get_by_name',
+                            MagicMock(return_value=st))
+
+        self.invoke('service_templates show test_st')
 
-        assert 'Showing service template one_service_no_description...' in self.logger_output_string
         assert 'Description:' not in self.logger_output_string
-        assert "Existing services:\n['test_s']" in self.logger_output_string
+        assert 'Existing services:' in self.logger_output_string
+        assert SERVICE_NAME in self.logger_output_string
 
-    def test_show_one_service_yes_description(self, monkeypatch, mock_storage):
+    def test_one_service_yes_description(self, monkeypatch, mock_storage):
 
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
-        self.invoke('service_templates show one_service_yes_description')
+        st = create_service_template(description='test_description')
+        st.services = [create_service(st)]
+        monkeypatch.setattr(mock_storage.service_template, 'get_by_name',
+                            MagicMock(return_value=st))
+
+        self.invoke('service_templates show test_st')
 
-        assert 'Showing service template one_service_yes_description...' in \
-               self.logger_output_string
-        assert 'Description:\ntest_description' in self.logger_output_string
-        assert "Existing services:\n['test_s']" in self.logger_output_string
+        assert 'Description:' in self.logger_output_string
+        assert 'test_description' in self.logger_output_string
+        assert 'Existing services:' in self.logger_output_string
+        assert 'test_s' in self.logger_output_string
 
 
 class TestServiceTemplatesList(TestCliBase):
 
+    def test_header_string(self, monkeypatch, mock_storage):
+
+        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        self.invoke('service_templates list')
+        assert 'Listing all service templates...' in self.logger_output_string
+
     @pytest.mark.parametrize('sort_by, order, sort_by_in_output, order_in_output', [
         ('', '', 'created_at', 'asc'),
         ('', ' --descending', 'created_at', 'desc'),
@@ -66,19 +92,24 @@ class TestServiceTemplatesList(TestCliBase):
 
         mock_storage.service_template.list.assert_called_with(
             sort={sort_by_in_output: order_in_output})
-        assert 'Listing all service templates...' in self.logger_output_string
-        assert 'test_st' in self.logger_output_string
+        assert SERVICE_TEMPLATE_NAME in self.logger_output_string
 
 
 class TestServiceTemplatesStore(TestCliBase):
 
+    def test_header_string(self, monkeypatch, mock_storage):
+
+        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        self.invoke('service_templates store stubpath test_st')
+        assert 'Storing service template test_st...' in self.logger_output_string
+
     def test_store_no_exception(self, monkeypatch, mock_object):
 
         monkeypatch.setattr(Core, 'create_service_template', mock_object)
         monkeypatch.setattr(service_template_utils, 'get', mock_object)
-        self.invoke('service_templates store stubpath test_st')
-        assert 'Storing service template test_st...' in self.logger_output_string
-        assert 'Service template test_st stored' in self.logger_output_string
+        self.invoke('service_templates store stubpath {name}'.format(name=SERVICE_TEMPLATE_NAME))
+        assert 'Service template {name} stored'.format(name=SERVICE_TEMPLATE_NAME) \
+               in self.logger_output_string
 
     def test_store_raises_exception_resulting_from_name_uniqueness(self, monkeypatch, mock_object):
 
@@ -93,7 +124,6 @@ class TestServiceTemplatesStore(TestCliBase):
             expected_exception=AriaCliError,
             expected_msg='Could not store service template `test_st`\n'
                          'There already a exists a service template with the same name')
-        assert 'Storing service template test_st...' in self.logger_output_string
 
     def test_store_raises_exception(self, monkeypatch, mock_object):
 
@@ -105,18 +135,23 @@ class TestServiceTemplatesStore(TestCliBase):
         assert_exception_raised(
             self.invoke('service_templates store stubpath test_st'),
             expected_exception=AriaCliError)
-        assert 'Storing service template test_st...' in self.logger_output_string
 
 
 class TestServiceTemplatesDelete(TestCliBase):
 
+    def test_header_string(self, monkeypatch, mock_storage):
+
+        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        self.invoke('service_templates delete test_st')
+        assert 'Deleting service template test_st...' in self.logger_output_string
+
     def test_delete_no_exception(self, monkeypatch, mock_object):
 
         monkeypatch.setattr(_Environment, 'model_storage', mock_object)
         monkeypatch.setattr(Core, 'delete_service_template', mock_object)
-        self.invoke('service_templates delete test_st')
-        assert 'Deleting service template test_st...' in self.logger_output_string
-        assert 'Service template test_st deleted' in self.logger_output_string
+        self.invoke('service_templates delete {name}'.format(name=SERVICE_TEMPLATE_NAME))
+        assert 'Service template {name} deleted'.format(name=SERVICE_TEMPLATE_NAME) \
+               in self.logger_output_string
 
     def test_delete_raises_exception(self, monkeypatch, mock_object):
 
@@ -129,31 +164,44 @@ class TestServiceTemplatesDelete(TestCliBase):
             self.invoke('service_templates delete test_st'),
             expected_exception=AriaCliError,
             expected_msg='')
-        assert 'Deleting service template test_st...' in self.logger_output_string
 
 
 class TestServiceTemplatesInputs(TestCliBase):
 
+    def test_header_string(self, monkeypatch, mock_storage):
+
+        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        self.invoke('service_templates inputs test_st')
+        assert 'Showing inputs for service template test_st...' in self.logger_output_string
+
     def test_inputs_existing_inputs(self, monkeypatch, mock_storage):
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        input = create_parameter(name='input1', value='value1')
+        st = create_service_template(inputs={'input1': input})
+        monkeypatch.setattr(mock_storage.service_template, 'get_by_name',
+                            MagicMock(return_value=st))
+
         self.invoke('service_templates inputs with_inputs')
-        assert 'Showing inputs for service template with_inputs...' in self.logger_output_string
         assert 'input1' in self.logger_output_string and 'value1' in self.logger_output_string
 
     def test_inputs_no_inputs(self, monkeypatch, mock_storage):
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
         self.invoke('service_templates inputs without_inputs')
-        assert 'Showing inputs for service template without_inputs...' in self.logger_output_string
         assert 'No inputs' in self.logger_output_string
 
 
 class TestServiceTemplatesValidate(TestCliBase):
 
+    def test_header_string(self, monkeypatch, mock_storage):
+
+        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        self.invoke('service_templates validate stubpath')
+        assert 'Validating service template: stubpath' in self.logger_output_string
+
     def test_validate_no_exception(self, monkeypatch, mock_object):
         monkeypatch.setattr(Core, 'validate_service_template', mock_object)
         monkeypatch.setattr(service_template_utils, 'get', mock_object)
         self.invoke('service_templates validate stubpath')
-        assert 'Validating service template: stubpath' in self.logger_output_string
         assert 'Service template validated successfully' in self.logger_output_string
 
     def test_validate_raises_exception(self, monkeypatch, mock_object):
@@ -162,13 +210,17 @@ class TestServiceTemplatesValidate(TestCliBase):
         assert_exception_raised(
             self.invoke('service_templates validate stubpath'),
             expected_exception=AriaCliError)
-        assert 'Validating service template: stubpath' in self.logger_output_string
 
 
 class TestServiceTemplatesCreateArchive(TestCliBase):
 
+    def test_header_string(self, monkeypatch, mock_storage):
+
+        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        self.invoke('service_templates create_archive stubpath stubdest')
+        assert 'Creating a csar archive' in self.logger_output_string
+
     def test_create_archive_successful(self, monkeypatch, mock_object):
         monkeypatch.setattr(csar, 'write', mock_object)
         self.invoke('service_templates create_archive stubpath stubdest')
-        assert 'Creating a csar archive' in self.logger_output_string
         assert 'Csar archive created at stubdest' in self.logger_output_string

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ed07f9f2/tests/cli/test_services.py
----------------------------------------------------------------------
diff --git a/tests/cli/test_services.py b/tests/cli/test_services.py
index 116e449..7e48593 100644
--- a/tests/cli/test_services.py
+++ b/tests/cli/test_services.py
@@ -1,5 +1,5 @@
 import pytest
-from mock import ANY
+from mock import ANY, MagicMock
 from aria.cli.exceptions import AriaCliError
 from aria.cli.env import _Environment
 from aria.core import Core
@@ -7,7 +7,7 @@ from aria.exceptions import (AriaException, DependentActiveExecutionsError,
                              DependentAvailableNodesError)
 from aria.storage import exceptions as storage_exceptions
 from tests.cli.base_test import TestCliBase, raise_exception, assert_exception_raised, mock_storage  #pylint: disable=unused-import
-from tests.mock.models import create_service, create_service_template
+from tests.mock.models import create_service_with_dependencies, SERVICE_TEMPLATE_NAME, SERVICE_NAME
 
 
 class TestServicesList(TestCliBase):
@@ -18,8 +18,8 @@ class TestServicesList(TestCliBase):
         (' --sort-by name', '', 'name', 'asc'),
         (' --sort-by name', ' --descending', 'name', 'desc')
     ])
-    def test_list_no_specified_service_template(self, monkeypatch, mock_storage, sort_by, order,
-                                                sort_by_in_output, order_in_output):
+    def test_no_specified_service_template(self, monkeypatch, mock_storage, sort_by, order,
+                                           sort_by_in_output, order_in_output):
 
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
         self.invoke('services list{sort_by}{order}'.format(sort_by=sort_by, order=order))
@@ -29,8 +29,8 @@ class TestServicesList(TestCliBase):
         mock_storage.service.list.assert_called_once_with(sort={sort_by_in_output: order_in_output},
                                                           filters={})
         assert 'Services:' in self.logger_output_string
-        assert 'test_st' in self.logger_output_string
-        assert 'test_s' in self.logger_output_string
+        assert SERVICE_TEMPLATE_NAME in self.logger_output_string
+        assert SERVICE_NAME in self.logger_output_string
 
     @pytest.mark.parametrize('sort_by, order, sort_by_in_output, order_in_output', [
         ('', '', 'created_at', 'asc'),
@@ -38,8 +38,8 @@ class TestServicesList(TestCliBase):
         (' --sort-by name', '', 'name', 'asc'),
         (' --sort-by name', ' --descending', 'name', 'desc')
     ])
-    def test_list_specified_service_template(self, monkeypatch, mock_storage, sort_by, order,
-                                             sort_by_in_output, order_in_output):
+    def test_specified_service_template(self, monkeypatch, mock_storage, sort_by, order,
+                                        sort_by_in_output, order_in_output):
 
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
         self.invoke('services list -t test_st{sort_by}{order}'.format(sort_by=sort_by, order=order))
@@ -49,27 +49,29 @@ class TestServicesList(TestCliBase):
         mock_storage.service.list.assert_called_once_with(sort={sort_by_in_output: order_in_output},
                                                           filters={'service_template': ANY})
         assert 'Services:' in self.logger_output_string
-        assert 'test_st' in self.logger_output_string
-        assert 'test_s' in self.logger_output_string
+        assert SERVICE_TEMPLATE_NAME in self.logger_output_string
+        assert SERVICE_NAME in self.logger_output_string
 
 
 class TestServicesCreate(TestCliBase):
 
-    def test_create_no_exception(self, monkeypatch, mock_object):
+    def test_header_string(self, monkeypatch, mock_storage):
+        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        self.invoke('services create -t test_st test_s')
+        assert 'Creating new service from service template test_st...' in self.logger_output_string
 
-        monkeypatch.setattr(_Environment, 'model_storage', mock_object)
+    def test_no_exception(self, monkeypatch, mock_storage):
 
-        test_st = create_service_template('test_st')
-        mock_object.return_value = create_service(test_st, 'test_s')
-        monkeypatch.setattr(Core, 'create_service', mock_object)
-        self.invoke('services create -t test_st test_s')
+        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
 
-        assert 'Creating new service from service template test_st...' in self.logger_output_string
+        m = MagicMock(return_value=create_service_with_dependencies())
+        monkeypatch.setattr(Core, 'create_service', m)
+        self.invoke('services create -t test_st test_s')
         assert "Service created. The service's name is test_s" in self.logger_output_string
 
-    def test_store_raises_storage_error_resulting_from_name_uniqueness(self, monkeypatch,
-                                                                       mock_object):
-        monkeypatch.setattr(_Environment, 'model_storage', mock_object)
+    def test_raises_storage_error_resulting_from_name_uniqueness(self, monkeypatch,
+                                                                 mock_storage):
+        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
         monkeypatch.setattr(Core,
                             'create_service',
                             raise_exception(storage_exceptions.NotFoundError,
@@ -80,10 +82,9 @@ class TestServicesCreate(TestCliBase):
             expected_msg='Could not store service `test_s`\n'
                          'There already a exists a service with the same name')
 
-        assert 'Creating new service from service template test_st...' in self.logger_output_string
         assert "Service created. The service's name is test_s" not in self.logger_output_string
 
-    def test_store_raises_other_storage_error(self, monkeypatch, mock_object):
+    def test_raises_other_storage_error(self, monkeypatch, mock_object):
         monkeypatch.setattr(_Environment, 'model_storage', mock_object)
         monkeypatch.setattr(Core,
                             'create_service',
@@ -93,10 +94,9 @@ class TestServicesCreate(TestCliBase):
             self.invoke('services create -t test_st test_s'),
             expected_exception=AriaCliError)
 
-        assert 'Creating new service from service template test_st...' in self.logger_output_string
         assert "Service created. The service's name is test_s" not in self.logger_output_string
 
-    def test_store_raises_aria_exception(self, monkeypatch, mock_storage):
+    def test_raises_aria_exception(self, monkeypatch, mock_storage):
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
         monkeypatch.setattr(Core,
                             'create_service',
@@ -107,62 +107,67 @@ class TestServicesCreate(TestCliBase):
             expected_exception=AriaCliError,
             expected_msg='error creating service `test_s`')
 
-        assert 'Creating new service from service template with_inputs...' in \
-               self.logger_output_string
         assert 'error creating service `test_s`' in self.logger_output_string
-        assert 'input1' in self.logger_output_string and 'value1' in self.logger_output_string
         assert "Service created. The service's name is test_s" not in self.logger_output_string
 
 
 class TestServicesDelete(TestCliBase):
 
-    def test_delete_no_exception(self, monkeypatch, mock_object):
+    def test_header_string(self, monkeypatch, mock_storage):
+        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        self.invoke('services delete test_s')
+        assert 'Deleting service test_s...' in self.logger_output_string
 
-        monkeypatch.setattr(_Environment, 'model_storage', mock_object)
+    def test_delete_no_exception(self, monkeypatch, mock_storage, mock_object):
+
+        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
         monkeypatch.setattr(Core, 'delete_service', mock_object)
         self.invoke('services delete test_s')
-        assert 'Deleting service test_s...' in self.logger_output_string
         assert 'Service test_s deleted' in self.logger_output_string
 
     def test_delete_active_execution_error(self, monkeypatch, mock_storage):
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        mock_service_with_execution = \
+            MagicMock(return_value=create_service_with_dependencies(include_execution=True))
+        monkeypatch.setattr(mock_storage.service, 'get', mock_service_with_execution)
         assert_exception_raised(
-            self.invoke('services delete service_with_active_executions'),
+            self.invoke('services delete test_s'),
             expected_exception=DependentActiveExecutionsError,
-            expected_msg="Can't delete service test_s - there is an active "
-                         "execution for this service. Active execution id: 1"
-        )
-        assert 'Deleting service service_with_active_executions...' in self.logger_output_string
+            expected_msg="Can't delete service {name} - there is an active execution "
+                         "for this service. Active execution id: 1".format(name=SERVICE_NAME))
 
     def test_delete_available_nodes_error(self, monkeypatch, mock_storage):
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
         assert_exception_raised(
-            self.invoke('services delete service_with_available_nodes'),
+            self.invoke('services delete test_s'),
             expected_exception=DependentAvailableNodesError,
-            expected_msg="Can't delete service test_s - "
-                         "there are available nodes for this service. Available node ids: 1"
+            expected_msg="Can't delete service {name} - there are available nodes "
+                         "for this service. Available node ids: 1".format(name=SERVICE_NAME)
         )
-        assert 'Deleting service service_with_available_nodes...' in self.logger_output_string
 
     def test_delete_available_nodes_error_with_force(self, monkeypatch, mock_storage):
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
         self.invoke('services delete service_with_available_nodes --force')
 
         assert mock_storage.service.delete.call_count == 1
-        assert 'Deleting service service_with_available_nodes...' in self.logger_output_string
         assert 'Service service_with_available_nodes deleted' in self.logger_output_string
 
+
 class TestServicesOutputs(TestCliBase):
     pass
 
 
 class TestServicesInputs(TestCliBase):
 
+    def test_header_string(self, monkeypatch, mock_storage):
+        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        self.invoke('services inputs test_s')
+        assert 'Showing inputs for service test_s...' in self.logger_output_string
+
     def test_inputs_no_inputs(self, monkeypatch, mock_storage):
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
         self.invoke('services inputs service_with_no_inputs')
 
-        assert 'Showing inputs for service service_with_no_inputs...' in self.logger_output_string
         assert 'No inputs' in self.logger_output_string
         assert 'input1' not in self.logger_output_string
         assert 'value1' not in self.logger_output_string
@@ -170,9 +175,11 @@ class TestServicesInputs(TestCliBase):
     def test_inputs_one_input(self, monkeypatch, mock_storage):
 
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
-        self.invoke('services inputs service_with_one_input')
+        s = create_service_with_dependencies(include_input=True)
+        monkeypatch.setattr(mock_storage.service, 'get_by_name', MagicMock(return_value=s))
+
+        self.invoke('services inputs test_s')
 
-        assert 'Showing inputs for service service_with_one_input...' in self.logger_output_string
         assert 'input1' in self.logger_output_string
         assert 'value1' in self.logger_output_string
         assert 'No inputs' not in self.logger_output_string

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ed07f9f2/tests/cli/utils.py
----------------------------------------------------------------------
diff --git a/tests/cli/utils.py b/tests/cli/utils.py
index b1537c5..e33203e 100644
--- a/tests/cli/utils.py
+++ b/tests/cli/utils.py
@@ -1,5 +1,4 @@
 import logging
-from aria.modeling import models
 from mock import MagicMock
 
 from tests.mock import models as mock_models
@@ -51,135 +50,36 @@ class MockStorage(object):
         self.service = MockServiceStorage()
         self.node_template = MockNodeTemplateStorage()
         self.node = MockNodeStorage()
-        self.log = MockLogStorage()
 
 
 class MockServiceTemplateStorage(object):
 
     def __init__(self):
-        self.list = MagicMock(return_value=[mock_models.create_service_template('test_st')])
-
-    @staticmethod
-    def get_by_name(name):
-        st = mock_models.create_service_template('test_st')
-        if name == 'no_services_no_description':
-            pass
-        elif name == 'no_services_yes_description':
-            st.description = 'test_description'
-        elif name == 'one_service_no_description':
-            service = mock_models.create_service(st, 'test_s')
-            st.services = [service]
-        elif name == 'one_service_yes_description':
-            service = mock_models.create_service(st, 'test_s')
-            st.description = 'test_description'
-            st.services = [service]
-        elif name == 'with_inputs':
-            input = mock_models.create_parameter(name='input1', value='value1')
-            st.inputs = {'input1': input}
-        elif name == 'without_inputs':
-            st.inputs = {}
-        elif name == 'one_service':
-            service = mock_models.create_service(st, 'test_s')
-            st.services = [service]
-        return st
+        self.list = MagicMock(return_value=[mock_models.create_service_template()])
+        self.get_by_name = MagicMock(return_value=mock_models.create_service_template())
 
 
 class MockServiceStorage(object):
 
     def __init__(self):
-        self.st = mock_models.create_service_template('test_st')
-        self.list = MagicMock(return_value=[mock_models.create_service(self.st, 'test_s')])
-        self.delete = MagicMock()
 
-    @staticmethod
-    def get(id):
-        test_st = mock_models.create_service_template('test_st')
-        test_s = mock_models.create_service(test_st, 'test_s')
-        if id == '1':
-            execution = mock_models.create_execution(test_s, status=models.Execution.STARTED)
-            execution.id = '1'
-            test_s.executions = [execution]
-        elif id == '2':
-            node_template = mock_models.create_node_template(service_template=test_st)
-            node = mock_models.create_node(name='test_node',
-                                           dependency_node_template=node_template,
-                                           service=test_s,
-                                           state=models.Node.STARTED)
-            node.id = '1'
-        return test_s
-
-    @staticmethod
-    def get_by_name(name):
-        test_st = mock_models.create_service_template('test_st')
-        test_s = mock_models.create_service(test_st, 'test_s')
-        if name == 'service_with_active_executions':
-            m = MagicMock()
-            m.id = '1'
-            return m
-        elif name == 'service_with_available_nodes':
-            m = MagicMock()
-            m.id = '2'
-            return m
-        elif name == 'service_with_no_inputs':
-            pass
-        elif name == 'service_with_one_input':
-            input = mock_models.create_parameter(name='input1', value='value1')
-            test_s.inputs = {'input1': input}
-
-        return test_s
+        self.s = mock_models.create_service_with_dependencies()
+
+        self.list = MagicMock(return_value=[self.s])
+        self.create = MagicMock(return_value=self.s)
+        self.get = MagicMock(
+            return_value=mock_models.create_service_with_dependencies(include_node=True))
+        self.get_by_name = MagicMock(return_value=self.s)
+        self.delete = MagicMock()
 
 
 class MockNodeTemplateStorage(object):
-
     def __init__(self):
-        self.st = mock_models.create_service_template('test_st')
-        self.list = MagicMock(return_value=[mock_models.create_node_template(self.st, 'test_nt')])
-
-
-    @staticmethod
-    def get(id):
-        st = mock_models.create_service_template('test_st')
-        s = mock_models.create_service(st, 'test_s')
-        nt = mock_models.create_node_template(service_template=st, name='test_nt')
-        if id == '1':
-            pass
-        elif id == '2':
-            prop1 = mock_models.create_parameter('prop1', 'value1')
-            nt.properties = {'prop1': prop1}
-        elif id == '3':
-            mock_models.create_node('node1', nt, s)
-        elif id == '4':
-            prop1 = mock_models.create_parameter('prop1', 'value1')
-            nt.properties = {'prop1': prop1}
-            mock_models.create_node('node1', nt, s)
-        return nt
+        self.get = MagicMock(return_value=mock_models.create_node_template_with_dependencies())
+        self.list = MagicMock(return_value=[mock_models.create_node_template_with_dependencies()])
 
 
 class MockNodeStorage(object):
-
-    def __init__(self):
-        self.st = mock_models.create_service_template('test_st')
-        self.s = mock_models.create_service(self.st, 'test_s')
-        self.nt = mock_models.create_node_template(service_template=self.st, name='test_nt')
-        self.list = MagicMock(return_value=[mock_models.create_node('test_n', self.nt, self.s)])
-
-    @staticmethod
-    def get(id):
-        st = mock_models.create_service_template('test_st')
-        s = mock_models.create_service(st, 'test_s')
-        nt = mock_models.create_node_template(service_template=st, name='test_nt')
-        n = mock_models.create_node('test_n', nt, s)
-        if id == '1':
-            pass
-        elif id == '2':
-            n.runtime_properties = {'attribute1': 'value1'}
-        return n
-
-
-class MockLogStorage(object):
-
     def __init__(self):
-        st = mock_models.create_service_template('test_st')
-        s = mock_models.create_service(st, 'test_s')
-        execution = mock_models.create_execution(s)
-        self.list = MagicMock(return_value=[mock_models.create_log(execution)])
+        self.get = MagicMock(return_value=mock_models.create_node_with_dependencies())
+        self.list = MagicMock(return_value=[mock_models.create_node_with_dependencies()])

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ed07f9f2/tests/mock/models.py
----------------------------------------------------------------------
diff --git a/tests/mock/models.py b/tests/mock/models.py
index 328453a..cdedea9 100644
--- a/tests/mock/models.py
+++ b/tests/mock/models.py
@@ -37,10 +37,11 @@ from aria.orchestrator.workflows.builtin.workflows import (
     NORMATIVE_REMOVE_SOURCE
 )
 
-SERVICE_NAME = 'test_service_name'
-SERVICE_TEMPLATE_NAME = 'test_service_template_name'
+SERVICE_TEMPLATE_NAME = 'test_service_template'
+SERVICE_NAME = 'test_service1'
 NODE_TEMPLATE_NAME = 'test_node_template'
-WORKFLOW_NAME = 'test_workflow_name'
+NODE_NAME = 'test_node1'
+WORKFLOW_NAME = 'test_workflow'
 TASK_RETRY_INTERVAL = 1
 TASK_MAX_ATTEMPTS = 1
 
@@ -50,11 +51,13 @@ DEPENDENT_NODE_TEMPLATE_NAME = 'dependent_node_template'
 DEPENDENT_NODE_NAME = 'dependent_node'
 
 
-def create_service_template(name=SERVICE_TEMPLATE_NAME):
+def create_service_template(name=SERVICE_TEMPLATE_NAME, description=None, inputs=None):
     now = datetime.now()
+    inputs = inputs or {}
     return models.ServiceTemplate(
         name=name,
-        description=None,
+        description=description,
+        inputs=inputs,
         created_at=now,
         updated_at=now,
         main_file_name='main_file_name',
@@ -68,10 +71,12 @@ def create_service_template(name=SERVICE_TEMPLATE_NAME):
     )
 
 
-def create_service(service_template, name=SERVICE_NAME):
+def create_service(service_template, name=SERVICE_NAME, inputs=None):
     now = datetime.utcnow()
+    inputs = inputs or {}
     return models.Service(
         name=name,
+        inputs=inputs,
         service_template=service_template,
         description='',
         created_at=now,
@@ -81,6 +86,46 @@ def create_service(service_template, name=SERVICE_NAME):
     )
 
 
+def create_service_with_dependencies(include_execution=False,
+                                     include_input=False,
+                                     include_node=False):
+    service_template = create_service_template()
+    service = create_service(service_template=service_template)
+    if include_execution:
+        execution = create_execution(service=service, status=models.Execution.STARTED)
+        service.executions = [execution]
+        execution.id = '1'
+    if include_input:
+        input = create_parameter(name='input1', value='value1')
+        service.inputs = {'input1': input}
+    if include_node:
+        node_template = create_node_template(service_template=service_template)
+        node = create_node(node_template, service, state=models.Node.STARTED)
+        node.id = '1'
+    return service
+
+
+def create_node_template_with_dependencies(include_node=False, include_property=False):
+    service_template = create_service_template()
+    node_template = create_node_template(service_template=service_template)
+    if include_node:
+        service = create_service(service_template=service_template)
+        create_node(dependency_node_template=node_template, service=service)
+    if include_property:
+        node_template.properties = {'prop1': create_parameter(name='prop1', value='value1')}
+    return node_template
+
+
+def create_node_with_dependencies(include_attribute=False):
+
+    node_template = create_node_template_with_dependencies()
+    node_template.service_template.services[0] = create_service(node_template.service_template)
+    node = create_node(node_template, node_template.service_template.services[0])
+    if include_attribute:
+        node.runtime_properties = {'attribute1': 'value1'}
+    return node
+
+
 def create_node_template(service_template,
                          name=NODE_TEMPLATE_NAME,
                          type=models.Type(variant='node', name='test_node_type'),
@@ -141,10 +186,9 @@ def create_dependent_node_template(
     )
 
 
-def create_node(name, dependency_node_template, service, state=models.Node.INITIAL,
+def create_node(dependency_node_template, service, name=NODE_NAME, state=models.Node.INITIAL,
                 runtime_properties=None):
     runtime_properties = runtime_properties or {}
-    # tmp_runtime_properties = {'ip': '1.1.1.1'}
     node = models.Node(
         name=name,
         type=dependency_node_template.type,
@@ -245,15 +289,6 @@ def create_parameter(name, value):
     return p.wrap(name, value)
 
 
-def create_log(execution, msg='log_msg', level=0, created_at=datetime.utcnow()):
-
-    return models.Log(
-        execution=execution,
-        msg=msg,
-        level=level,
-        created_at=created_at)
-
-
 def _dictify(item):
     return dict(((item.name, item),))
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ed07f9f2/tests/mock/topology.py
----------------------------------------------------------------------
diff --git a/tests/mock/topology.py b/tests/mock/topology.py
index e5b4e01..bfb7b4e 100644
--- a/tests/mock/topology.py
+++ b/tests/mock/topology.py
@@ -33,7 +33,7 @@ def create_simple_topology_single_node(model_storage, create_operation):
     )
     node_template.interface_templates[interface_template.name] = interface_template                 # pylint: disable=unsubscriptable-object
 
-    node = models.create_node(models.DEPENDENCY_NODE_NAME, node_template, service)
+    node = models.create_node(node_template, service, name=models.DEPENDENCY_NODE_NAME)
     interface = models.create_interface(
         service,
         'Standard', 'create',
@@ -59,9 +59,9 @@ def create_simple_topology_two_nodes(model_storage):
                                                                     dependency_node_template)
 
     dependency_node = models.create_node(
-        models.DEPENDENCY_NODE_NAME, dependency_node_template, service)
+        dependency_node_template, service, models.DEPENDENCY_NODE_NAME)
     dependent_node = models.create_node(
-        models.DEPENDENT_NODE_NAME, dependent_node_template, service)
+        dependent_node_template, service, models.DEPENDENT_NODE_NAME)
 
     dependent_node.outbound_relationships.append(models.create_relationship(                        # pylint: disable=no-member
         source=dependent_node,
@@ -86,7 +86,7 @@ def create_simple_topology_three_nodes(model_storage):
     service = model_storage.service.get(service_id)
     third_node_template = models.create_dependency_node_template(
         service.service_template, name='another_dependency_node_template')
-    third_node = models.create_node('another_dependency_node', third_node_template, service)
+    third_node = models.create_node(third_node_template, service, 'another_dependency_node')
     new_relationship = models.create_relationship(
         source=model_storage.node.get_by_name(models.DEPENDENT_NODE_NAME),
         target=third_node,

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ed07f9f2/tests/modeling/test_models.py
----------------------------------------------------------------------
diff --git a/tests/modeling/test_models.py b/tests/modeling/test_models.py
index d91249a..d64cdba 100644
--- a/tests/modeling/test_models.py
+++ b/tests/modeling/test_models.py
@@ -100,12 +100,13 @@ def _nodes_storage():
     service = storage.service.get_by_name(mock.models.SERVICE_NAME)
     dependency_node_template = storage.node_template.get_by_name(
         mock.models.DEPENDENCY_NODE_TEMPLATE_NAME)
-    mock.models.create_node(mock.models.DEPENDENCY_NODE_NAME, dependency_node_template, service)
+    mock.models.create_node(dependency_node_template, service,
+                            name=mock.models.DEPENDENCY_NODE_NAME)
 
     dependent_node_template = mock.models.create_dependent_node_template(service.service_template,
                                                                          dependency_node_template)
 
-    mock.models.create_node(mock.models.DEPENDENT_NODE_NAME, dependent_node_template, service)
+    mock.models.create_node(dependent_node_template, service, name=mock.models.DEPENDENT_NODE_NAME)
     storage.service.update(service)
     return storage
 


[03/12] incubator-ariatosca git commit: fixed pylint issues

Posted by av...@apache.org.
fixed pylint issues


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/38f9abad
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/38f9abad
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/38f9abad

Branch: refs/heads/cli-tests
Commit: 38f9abada5f850729c46c269ee063add58d15ec0
Parents: 9f9dc3e
Author: Ran Ziv <ra...@gigaspaces.com>
Authored: Tue Apr 18 14:40:14 2017 +0300
Committer: Ran Ziv <ra...@gigaspaces.com>
Committed: Tue Apr 18 14:40:14 2017 +0300

----------------------------------------------------------------------
 aria/parser/consumption/__init__.py | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/38f9abad/aria/parser/consumption/__init__.py
----------------------------------------------------------------------
diff --git a/aria/parser/consumption/__init__.py b/aria/parser/consumption/__init__.py
index 8e565eb..8f6d2b6 100644
--- a/aria/parser/consumption/__init__.py
+++ b/aria/parser/consumption/__init__.py
@@ -17,10 +17,21 @@
 from .exceptions import ConsumerException
 from .context import ConsumptionContext
 from .style import Style
-from .consumer import Consumer, ConsumerChain
+from .consumer import (
+    Consumer,
+    ConsumerChain
+)
 from .presentation import Read
 from .validation import Validate
-from .modeling import ServiceTemplate, Types, ServiceInstance, FindHosts, ConfigureOperations, SatisfyRequirements, ValidateCapabilities
+from .modeling import (
+    ServiceTemplate,
+    Types,
+    ServiceInstance,
+    FindHosts,
+    ConfigureOperations,
+    SatisfyRequirements,
+    ValidateCapabilities
+)
 from .inputs import Inputs
 
 __all__ = (
@@ -37,4 +48,4 @@ __all__ = (
     'Inputs',
     'SatisfyRequirements',
     'ValidateCapabilities'
-)
\ No newline at end of file
+)


[11/12] incubator-ariatosca git commit: Add tests for logs list

Posted by av...@apache.org.
Add tests for logs list


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/9169cb35
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/9169cb35
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/9169cb35

Branch: refs/heads/cli-tests
Commit: 9169cb357adb12948f6a7ce5c97f833addd7dae8
Parents: a39e7d1
Author: Avia Efrat <av...@gigaspaces.com>
Authored: Tue Apr 18 12:28:37 2017 +0300
Committer: Avia Efrat <av...@gigaspaces.com>
Committed: Wed Apr 19 14:18:19 2017 +0300

----------------------------------------------------------------------
 aria/cli/commands/logs.py |  2 +-
 tests/cli/test_logs.py    | 23 +++++++++++++++++++++++
 tests/cli/utils.py        | 10 ++++++++++
 tests/mock/models.py      |  9 +++++++++
 4 files changed, 43 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9169cb35/aria/cli/commands/logs.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/logs.py b/aria/cli/commands/logs.py
index 8888fef..6c83347 100644
--- a/aria/cli/commands/logs.py
+++ b/aria/cli/commands/logs.py
@@ -42,7 +42,7 @@ def list(execution_id,
     # TODO: print logs nicely
     if logs_list:
         for log in logs_list:
-            print log
+            logger.info(log)
     else:
         logger.info('\tNo logs')
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9169cb35/tests/cli/test_logs.py
----------------------------------------------------------------------
diff --git a/tests/cli/test_logs.py b/tests/cli/test_logs.py
new file mode 100644
index 0000000..ad0c4f1
--- /dev/null
+++ b/tests/cli/test_logs.py
@@ -0,0 +1,23 @@
+from aria.cli.env import _Environment
+from tests.cli.base_test import TestCliBase, mock_storage
+
+
+class TestLogsList(TestCliBase):
+
+    def test_existing_logs(self, monkeypatch, mock_storage):
+        monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
+        self.invoke('logs list exec_id')
+
+        assert 'Listing logs for execution id exec_id' in self.logger_output_string
+        assert 'log_msg' in self.logger_output_string
+        assert 'No logs' not in self.logger_output_string
+
+    def test_no_logs(self, monkeypatch, mock_object):
+        m = mock_object
+        m.log.list.return_value = []
+        monkeypatch.setattr(_Environment, 'model_storage', m)
+        self.invoke('logs list exec_id')
+
+        assert 'Listing logs for execution id exec_id' in self.logger_output_string
+        assert 'log_msg' not in self.logger_output_string
+        assert 'No logs' in self.logger_output_string

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9169cb35/tests/cli/utils.py
----------------------------------------------------------------------
diff --git a/tests/cli/utils.py b/tests/cli/utils.py
index 20fdb90..b1537c5 100644
--- a/tests/cli/utils.py
+++ b/tests/cli/utils.py
@@ -51,6 +51,7 @@ class MockStorage(object):
         self.service = MockServiceStorage()
         self.node_template = MockNodeTemplateStorage()
         self.node = MockNodeStorage()
+        self.log = MockLogStorage()
 
 
 class MockServiceTemplateStorage(object):
@@ -173,3 +174,12 @@ class MockNodeStorage(object):
         elif id == '2':
             n.runtime_properties = {'attribute1': 'value1'}
         return n
+
+
+class MockLogStorage(object):
+
+    def __init__(self):
+        st = mock_models.create_service_template('test_st')
+        s = mock_models.create_service(st, 'test_s')
+        execution = mock_models.create_execution(s)
+        self.list = MagicMock(return_value=[mock_models.create_log(execution)])

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9169cb35/tests/mock/models.py
----------------------------------------------------------------------
diff --git a/tests/mock/models.py b/tests/mock/models.py
index 8a9273b..328453a 100644
--- a/tests/mock/models.py
+++ b/tests/mock/models.py
@@ -245,6 +245,15 @@ def create_parameter(name, value):
     return p.wrap(name, value)
 
 
+def create_log(execution, msg='log_msg', level=0, created_at=datetime.utcnow()):
+
+    return models.Log(
+        execution=execution,
+        msg=msg,
+        level=level,
+        created_at=created_at)
+
+
 def _dictify(item):
     return dict(((item.name, item),))
 


[02/12] incubator-ariatosca git commit: Implementation-less-relationship-tasks-are-being-created

Posted by av...@apache.org.
Implementation-less-relationship-tasks-are-being-created


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/9f9dc3ec
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/9f9dc3ec
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/9f9dc3ec

Branch: refs/heads/cli-tests
Commit: 9f9dc3ec9f2980e296a293bf7793263eca01c308
Parents: 8ced0f4
Author: max-orlov <ma...@gigaspaces.com>
Authored: Tue Apr 18 10:56:34 2017 +0300
Committer: max-orlov <ma...@gigaspaces.com>
Committed: Tue Apr 18 11:16:34 2017 +0300

----------------------------------------------------------------------
 aria/orchestrator/workflows/builtin/utils.py | 28 +++++++++++------------
 1 file changed, 14 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9f9dc3ec/aria/orchestrator/workflows/builtin/utils.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/builtin/utils.py b/aria/orchestrator/workflows/builtin/utils.py
index 722c618..2254d13 100644
--- a/aria/orchestrator/workflows/builtin/utils.py
+++ b/aria/orchestrator/workflows/builtin/utils.py
@@ -73,13 +73,13 @@ def relationship_tasks(relationship, interface_name, source_operation_name=None,
         try:
             if _is_empty_task(relationship, interface_name, source_operation_name):
                 operations.append(StubTask())
-
-            operations.append(
-                OperationTask.for_relationship(relationship=relationship,
-                                               interface_name=interface_name,
-                                               operation_name=source_operation_name,
-                                               **kwargs)
-            )
+            else:
+                operations.append(
+                    OperationTask.for_relationship(relationship=relationship,
+                                                   interface_name=interface_name,
+                                                   operation_name=source_operation_name,
+                                                   **kwargs)
+                )
         except exceptions.OperationNotFoundException:
             # We will skip relationships which do not have the operation
             pass
@@ -87,13 +87,13 @@ def relationship_tasks(relationship, interface_name, source_operation_name=None,
         try:
             if _is_empty_task(relationship, interface_name, target_operation_name):
                 operations.append(StubTask())
-
-            operations.append(
-                OperationTask.for_relationship(relationship=relationship,
-                                               interface_name=interface_name,
-                                               operation_name=target_operation_name,
-                                               **kwargs)
-            )
+            else:
+                operations.append(
+                    OperationTask.for_relationship(relationship=relationship,
+                                                   interface_name=interface_name,
+                                                   operation_name=target_operation_name,
+                                                   **kwargs)
+                )
         except exceptions.OperationNotFoundException:
             # We will skip relationships which do not have the operation
             pass