summaryrefslogtreecommitdiffstats
path: root/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands
diff options
context:
space:
mode:
Diffstat (limited to 'azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands')
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/__init__.py30
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/executions.py246
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/logs.py72
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/node_templates.py100
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/nodes.py94
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/plugins.py111
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/reset.py45
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/service_templates.py244
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/services.py238
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/workflows.py111
10 files changed, 1291 insertions, 0 deletions
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/__init__.py b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/__init__.py
new file mode 100644
index 0000000..ba34a43
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/__init__.py
@@ -0,0 +1,30 @@
+# 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.
+
+"""
+CLI commands package.
+"""
+
+from . import (
+ executions,
+ logs,
+ node_templates,
+ nodes,
+ plugins,
+ reset,
+ service_templates,
+ services,
+ workflows
+)
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/executions.py b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/executions.py
new file mode 100644
index 0000000..cecbbc5
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/executions.py
@@ -0,0 +1,246 @@
+# 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.
+
+"""
+CLI ``executions`` sub-commands.
+"""
+
+import os
+
+from .. import helptexts
+from .. import table
+from .. import utils
+from .. import logger as cli_logger
+from .. import execution_logging
+from ..core import aria
+from ...modeling.models import Execution
+from ...orchestrator.workflow_runner import WorkflowRunner
+from ...orchestrator.workflows.executor.dry import DryExecutor
+from ...utils import formatting
+from ...utils import threading
+
+EXECUTION_COLUMNS = ('id', 'workflow_name', 'status', 'service_name',
+ 'created_at', 'error')
+
+
+@aria.group(name='executions')
+@aria.options.verbose()
+def executions():
+ """
+ Manage executions
+ """
+ pass
+
+
+@executions.command(name='show',
+ short_help='Show information for an execution')
+@aria.argument('execution-id')
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_logger
+def show(execution_id, model_storage, logger):
+ """
+ Show information for an execution
+
+ EXECUTION_ID is the unique ID of the execution.
+ """
+ logger.info('Showing execution {0}'.format(execution_id))
+ execution = model_storage.execution.get(execution_id)
+
+ table.print_data(EXECUTION_COLUMNS, execution, 'Execution:', col_max_width=50)
+
+ # print execution parameters
+ logger.info('Execution Inputs:')
+ if execution.inputs:
+ #TODO check this section, havent tested it
+ execution_inputs = [ei.to_dict() for ei in execution.inputs]
+ for input_name, input_value in formatting.decode_dict(
+ execution_inputs).iteritems():
+ logger.info('\t{0}: \t{1}'.format(input_name, input_value))
+ else:
+ logger.info('\tNo inputs')
+
+
+@executions.command(name='list',
+ short_help='List executions')
+@aria.options.service_name(required=False)
+@aria.options.sort_by()
+@aria.options.descending
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_logger
+def list(service_name,
+ sort_by,
+ descending,
+ model_storage,
+ logger):
+ """
+ List executions
+
+ If SERVICE_NAME is provided, list executions on that service. Otherwise, list executions on all
+ services.
+ """
+ if service_name:
+ logger.info('Listing executions for service {0}...'.format(
+ service_name))
+ service = model_storage.service.get_by_name(service_name)
+ filters = dict(service=service)
+ else:
+ logger.info('Listing all executions...')
+ filters = {}
+
+ executions_list = model_storage.execution.list(
+ filters=filters,
+ sort=utils.storage_sort_param(sort_by, descending)).items
+
+ table.print_data(EXECUTION_COLUMNS, executions_list, 'Executions:')
+
+
+@executions.command(name='start',
+ short_help='Start a workflow on a service')
+@aria.argument('workflow-name')
+@aria.options.service_name(required=True)
+@aria.options.inputs(help=helptexts.EXECUTION_INPUTS)
+@aria.options.dry_execution
+@aria.options.task_max_attempts()
+@aria.options.task_retry_interval()
+@aria.options.mark_pattern()
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_resource_storage
+@aria.pass_plugin_manager
+@aria.pass_logger
+def start(workflow_name,
+ service_name,
+ inputs,
+ dry,
+ task_max_attempts,
+ task_retry_interval,
+ mark_pattern,
+ model_storage,
+ resource_storage,
+ plugin_manager,
+ logger):
+ """
+ Start a workflow on a service
+
+ SERVICE_NAME is the unique name of the service.
+
+ WORKFLOW_NAME is the unique name of the workflow within the service (e.g. "uninstall").
+ """
+ service = model_storage.service.get_by_name(service_name)
+ executor = DryExecutor() if dry else None # use WorkflowRunner's default executor
+
+ workflow_runner = \
+ WorkflowRunner(
+ model_storage, resource_storage, plugin_manager,
+ service_id=service.id, workflow_name=workflow_name, inputs=inputs, executor=executor,
+ task_max_attempts=task_max_attempts, task_retry_interval=task_retry_interval
+ )
+ logger.info('Starting {0}execution. Press Ctrl+C cancel'.format('dry ' if dry else ''))
+
+ _run_execution(workflow_runner, logger, model_storage, dry, mark_pattern)
+
+
+@executions.command(name='resume',
+ short_help='Resume a stopped execution')
+@aria.argument('execution-id')
+@aria.options.dry_execution
+@aria.options.retry_failed_tasks
+@aria.options.mark_pattern()
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_resource_storage
+@aria.pass_plugin_manager
+@aria.pass_logger
+def resume(execution_id,
+ retry_failed_tasks,
+ dry,
+ mark_pattern,
+ model_storage,
+ resource_storage,
+ plugin_manager,
+ logger):
+ """
+ Resume a stopped execution
+
+ EXECUTION_ID is the unique ID of the execution.
+ """
+ executor = DryExecutor() if dry else None # use WorkflowRunner's default executor
+
+ execution = model_storage.execution.get(execution_id)
+ if execution.status != execution.CANCELLED:
+ logger.info("Can't resume execution {execution.id} - "
+ "execution is in status {execution.status}. "
+ "Can only resume executions in status {valid_status}"
+ .format(execution=execution, valid_status=execution.CANCELLED))
+ return
+
+ workflow_runner = \
+ WorkflowRunner(
+ model_storage, resource_storage, plugin_manager,
+ execution_id=execution_id, retry_failed_tasks=retry_failed_tasks, executor=executor,
+ )
+
+ logger.info('Resuming {0}execution. Press Ctrl+C cancel'.format('dry ' if dry else ''))
+ _run_execution(workflow_runner, logger, model_storage, dry, mark_pattern)
+
+
+def _run_execution(workflow_runner, logger, model_storage, dry, mark_pattern):
+ execution_thread_name = '{0}_{1}'.format(workflow_runner.service.name,
+ workflow_runner.execution.workflow_name)
+ execution_thread = threading.ExceptionThread(target=workflow_runner.execute,
+ name=execution_thread_name)
+
+ execution_thread.start()
+
+ last_task_id = workflow_runner.execution.logs[-1].id if workflow_runner.execution.logs else 0
+ log_iterator = cli_logger.ModelLogIterator(model_storage,
+ workflow_runner.execution_id,
+ offset=last_task_id)
+ try:
+ while execution_thread.is_alive():
+ execution_logging.log_list(log_iterator, mark_pattern=mark_pattern)
+ execution_thread.join(1)
+
+ except KeyboardInterrupt:
+ _cancel_execution(workflow_runner, execution_thread, logger, log_iterator)
+
+ # It might be the case where some logs were written and the execution was terminated, thus we
+ # need to drain the remaining logs.
+ execution_logging.log_list(log_iterator, mark_pattern=mark_pattern)
+
+ # raise any errors from the execution thread (note these are not workflow execution errors)
+ execution_thread.raise_error_if_exists()
+
+ execution = workflow_runner.execution
+ logger.info('Execution has ended with "{0}" status'.format(execution.status))
+ if execution.status == Execution.FAILED and execution.error:
+ logger.info('Execution error:{0}{1}'.format(os.linesep, execution.error))
+
+ if dry:
+ # remove traces of the dry execution (including tasks, logs, inputs..)
+ model_storage.execution.delete(execution)
+
+
+def _cancel_execution(workflow_runner, execution_thread, logger, log_iterator):
+ logger.info('Cancelling execution. Press Ctrl+C again to force-cancel.')
+ workflow_runner.cancel()
+ while execution_thread.is_alive():
+ try:
+ execution_logging.log_list(log_iterator)
+ execution_thread.join(1)
+ except KeyboardInterrupt:
+ pass
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/logs.py b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/logs.py
new file mode 100644
index 0000000..b751b97
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/logs.py
@@ -0,0 +1,72 @@
+# 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.
+
+"""
+CLI ``logs`` sub-commands.
+"""
+
+from .. import execution_logging
+from ..logger import ModelLogIterator
+from ..core import aria
+
+
+@aria.group(name='logs')
+@aria.options.verbose()
+def logs():
+ """
+ Manage logs of workflow executions
+ """
+ pass
+
+
+@logs.command(name='list',
+ short_help='List logs for an execution')
+@aria.argument('execution-id')
+@aria.options.verbose()
+@aria.options.mark_pattern()
+@aria.pass_model_storage
+@aria.pass_logger
+def list(execution_id, mark_pattern, model_storage, logger):
+ """
+ List logs for an execution
+
+ EXECUTION_ID is the unique ID of the execution.
+ """
+ logger.info('Listing logs for execution id {0}'.format(execution_id))
+ log_iterator = ModelLogIterator(model_storage, execution_id)
+
+ any_logs = execution_logging.log_list(log_iterator, mark_pattern=mark_pattern)
+
+ if not any_logs:
+ logger.info('\tNo logs')
+
+
+@logs.command(name='delete',
+ short_help='Delete logs of an execution')
+@aria.argument('execution-id')
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_logger
+def delete(execution_id, model_storage, logger):
+ """
+ Delete logs of an execution
+
+ EXECUTION_ID is the unique ID of the execution.
+ """
+ logger.info('Deleting logs for execution id {0}'.format(execution_id))
+ logs_list = model_storage.log.list(filters=dict(execution_fk=execution_id))
+ for log in logs_list:
+ model_storage.log.delete(log)
+ logger.info('Deleted logs for execution id {0}'.format(execution_id))
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/node_templates.py b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/node_templates.py
new file mode 100644
index 0000000..ec160d2
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/node_templates.py
@@ -0,0 +1,100 @@
+# 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.
+
+"""
+CLI ``node-templates`` sub-commands.
+"""
+
+from .. import table
+from .. import utils
+from ..core import aria
+
+
+NODE_TEMPLATE_COLUMNS = ['id', 'name', 'description', 'service_template_name', 'type_name']
+
+
+@aria.group(name='node-templates')
+@aria.options.verbose()
+def node_templates():
+ """
+ Manages stored service templates' node templates
+ """
+ pass
+
+
+@node_templates.command(name='show',
+ short_help='Show information for a stored node template')
+@aria.argument('node-template-id')
+# @aria.options.service_template_name(required=True)
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_logger
+def show(node_template_id, model_storage, logger):
+ """
+ Show information for a stored node template
+
+ NODE_TEMPLATE_ID is the unique node template ID.
+ """
+ logger.info('Showing node template {0}'.format(node_template_id))
+ node_template = model_storage.node_template.get(node_template_id)
+
+ table.print_data(NODE_TEMPLATE_COLUMNS, node_template, 'Node template:', col_max_width=50)
+
+ # print node template properties
+ logger.info('Node template properties:')
+ if node_template.properties:
+ logger.info(utils.get_parameter_templates_as_string(node_template.properties))
+ else:
+ logger.info('\tNo properties')
+
+ # print node IDs
+ nodes = node_template.nodes
+ logger.info('Nodes:')
+ if nodes:
+ for node in nodes:
+ logger.info('\t{0}'.format(node.name))
+ else:
+ logger.info('\tNo nodes')
+
+
+@node_templates.command(name='list',
+ short_help='List stored node templates')
+@aria.options.service_template_name()
+@aria.options.sort_by('service_template_name')
+@aria.options.descending
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_logger
+def list(service_template_name, sort_by, descending, model_storage, logger):
+ """
+ List stored node templates
+
+ If SERVICE_TEMPLATE_NAME is provided, list node templates for that stored service template.
+ Otherwise, list node templates for all service templates.
+ """
+ if service_template_name:
+ logger.info('Listing node templates for service template {0}...'.format(
+ service_template_name))
+ service_template = model_storage.service_template.get_by_name(service_template_name)
+ filters = dict(service_template=service_template)
+ else:
+ logger.info('Listing all node templates...')
+ filters = {}
+
+ node_templates_list = model_storage.node_template.list(
+ filters=filters,
+ sort=utils.storage_sort_param(sort_by, descending))
+
+ table.print_data(NODE_TEMPLATE_COLUMNS, node_templates_list, 'Node templates:')
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/nodes.py b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/nodes.py
new file mode 100644
index 0000000..30f1dd4
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/nodes.py
@@ -0,0 +1,94 @@
+# 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.
+
+"""
+CLI ``nodes`` sub-commands.
+"""
+
+from .. import table
+from .. import utils
+from ..core import aria
+
+
+NODE_COLUMNS = ['id', 'name', 'service_name', 'node_template_name', 'state']
+
+
+@aria.group(name='nodes')
+@aria.options.verbose()
+def nodes():
+ """
+ Manage services' nodes
+ """
+ pass
+
+
+@nodes.command(name='show',
+ short_help='Show information for a node')
+@aria.argument('node_id')
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_logger
+def show(node_id, model_storage, logger):
+ """
+ Show information for a node
+
+ NODE_ID is the unique node ID.
+ """
+ logger.info('Showing node {0}'.format(node_id))
+ node = model_storage.node.get(node_id)
+
+ table.print_data(NODE_COLUMNS, node, 'Node:', col_max_width=50)
+
+ # print node attributes
+ logger.info('Node attributes:')
+ if node.attributes:
+ for param_name, param in node.attributes.iteritems():
+ logger.info('\t{0}: {1}'.format(param_name, param.value))
+ else:
+ logger.info('\tNo attributes')
+
+
+@nodes.command(name='list',
+ short_help='List node')
+@aria.options.service_name(required=False)
+@aria.options.sort_by('service_name')
+@aria.options.descending
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_logger
+def list(service_name,
+ sort_by,
+ descending,
+ model_storage,
+ logger):
+ """
+ List nodes
+
+ If SERVICE_NAME is provided, list nodes for that service. Otherwise, list nodes for all
+ services.
+ """
+ if service_name:
+ logger.info('Listing nodes for service {0}...'.format(service_name))
+ service = model_storage.service.get_by_name(service_name)
+ filters = dict(service=service)
+ else:
+ logger.info('Listing all nodes...')
+ filters = {}
+
+ nodes_list = model_storage.node.list(
+ filters=filters,
+ sort=utils.storage_sort_param(sort_by, descending))
+
+ table.print_data(NODE_COLUMNS, nodes_list, 'Nodes:')
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/plugins.py b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/plugins.py
new file mode 100644
index 0000000..b5d68a2
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/plugins.py
@@ -0,0 +1,111 @@
+# 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.
+
+"""
+CLI ``plugins`` sub-commands.
+"""
+
+from .. import table
+from .. import utils
+from ..core import aria
+
+
+PLUGIN_COLUMNS = ['id', 'package_name', 'package_version', 'supported_platform',
+ 'distribution', 'distribution_release', 'uploaded_at']
+
+
+@aria.group(name='plugins')
+@aria.options.verbose()
+def plugins():
+ """
+ Manage plugins
+ """
+ pass
+
+
+@plugins.command(name='validate',
+ short_help='Validate a plugin archive')
+@aria.argument('plugin-path')
+@aria.options.verbose()
+@aria.pass_plugin_manager
+@aria.pass_logger
+def validate(plugin_path, plugin_manager, logger):
+ """
+ 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`).
+
+ PLUGIN_PATH is the path to the wagon archive.
+ """
+ logger.info('Validating plugin {0}...'.format(plugin_path))
+ plugin_manager.validate_plugin(plugin_path)
+ logger.info('Plugin validated successfully')
+
+
+@plugins.command(name='install',
+ short_help='Install a plugin')
+@aria.argument('plugin-path')
+@aria.options.verbose()
+@aria.pass_context
+@aria.pass_plugin_manager
+@aria.pass_logger
+def install(ctx, plugin_path, plugin_manager, logger):
+ """
+ Install a plugin
+
+ 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 the wagon archive.
+ """
+ ctx.invoke(validate, plugin_path=plugin_path)
+ logger.info('Installing plugin {0}...'.format(plugin_path))
+ plugin = plugin_manager.install(plugin_path)
+ logger.info("Plugin installed. The plugin's id is {0}".format(plugin.id))
+
+
+@plugins.command(name='show',
+ short_help='Show information for an installed plugin')
+@aria.argument('plugin-id')
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_logger
+def show(plugin_id, model_storage, logger):
+ """
+ Show information for an installed plugin
+
+ PLUGIN_ID is the unique installed plugin ID in this ARIA instance.
+ """
+ logger.info('Showing plugin {0}...'.format(plugin_id))
+ plugin = model_storage.plugin.get(plugin_id)
+ table.print_data(PLUGIN_COLUMNS, plugin, 'Plugin:')
+
+
+@plugins.command(name='list',
+ short_help='List all installed plugins')
+@aria.options.sort_by('uploaded_at')
+@aria.options.descending
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_logger
+def list(sort_by, descending, model_storage, logger):
+ """
+ List all installed plugins
+ """
+ logger.info('Listing all plugins...')
+ plugins_list = model_storage.plugin.list(
+ sort=utils.storage_sort_param(sort_by, descending)).items
+ table.print_data(PLUGIN_COLUMNS, plugins_list, 'Plugins:')
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/reset.py b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/reset.py
new file mode 100644
index 0000000..c82c707
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/reset.py
@@ -0,0 +1,45 @@
+# 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.
+
+"""
+CLI ``reset`` command.
+"""
+
+from .. import helptexts
+from ..core import aria
+from ..env import env
+from ..exceptions import AriaCliError
+
+
+@aria.command(name='reset',
+ short_help="Reset ARIA 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
+
+ Deletes installed plugins, service templates, services, executions, and logs. 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")
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/service_templates.py b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/service_templates.py
new file mode 100644
index 0000000..5a7039c
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/service_templates.py
@@ -0,0 +1,244 @@
+# 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.
+
+"""
+CLI ``service-templates`` sub-commands.
+"""
+
+import os
+
+from .. import csar
+from .. import service_template_utils
+from .. import table
+from .. import utils
+from ..core import aria
+from ...core import Core
+from ...storage import exceptions as storage_exceptions
+from ...parser import consumption
+from ...utils import (formatting, collections, console)
+from ... orchestrator import topology
+
+DESCRIPTION_FIELD_LENGTH_LIMIT = 20
+SERVICE_TEMPLATE_COLUMNS = \
+ ('id', 'name', 'description', 'main_file_name', 'created_at', 'updated_at')
+
+
+@aria.group(name='service-templates')
+@aria.options.verbose()
+def service_templates():
+ """
+ Manage service templates
+ """
+ pass
+
+
+@service_templates.command(name='show',
+ short_help='Show information for a stored service template')
+@aria.argument('service-template-name')
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.options.service_template_mode_full
+@aria.options.mode_types
+@aria.options.format_json
+@aria.options.format_yaml
+@aria.pass_logger
+def show(service_template_name, model_storage, mode_full, mode_types, format_json, format_yaml,
+ logger):
+ """
+ Show information for a stored service template
+
+ SERVICE_TEMPLATE_NAME is the unique name of the stored service template.
+ """
+ service_template = model_storage.service_template.get_by_name(service_template_name)
+
+ if format_json or format_yaml:
+ mode_full = True
+
+ if mode_full:
+ consumption.ConsumptionContext()
+ if format_json:
+ console.puts(formatting.json_dumps(collections.prune(service_template.as_raw)))
+ elif format_yaml:
+ console.puts(formatting.yaml_dumps(collections.prune(service_template.as_raw)))
+ else:
+ console.puts(topology.Topology().dump(service_template))
+ elif mode_types:
+ console.puts(topology.Topology().dump_types(service_template=service_template))
+ else:
+ logger.info('Showing service template {0}...'.format(service_template_name))
+ service_template_dict = service_template.to_dict()
+ service_template_dict['#services'] = len(service_template.services)
+ columns = SERVICE_TEMPLATE_COLUMNS + ('#services',)
+ column_formatters = \
+ dict(description=table.trim_formatter_generator(DESCRIPTION_FIELD_LENGTH_LIMIT))
+ 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:')
+ logger.info('{0}{1}'.format(service_template_dict['description'].encode('UTF-8') or '',
+ os.linesep))
+
+ if service_template.services:
+ logger.info('Existing services:')
+ for service_name in service_template.services:
+ logger.info('\t{0}'.format(service_name))
+
+
+@service_templates.command(name='list',
+ short_help='List all stored service templates')
+@aria.options.sort_by()
+@aria.options.descending
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_logger
+def list(sort_by, descending, model_storage, logger):
+ """
+ List all stored service templates
+ """
+
+ logger.info('Listing all service templates...')
+ service_templates_list = model_storage.service_template.list(
+ sort=utils.storage_sort_param(sort_by, descending))
+
+ 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',
+ short_help='Parse and store a service template archive')
+@aria.argument('service-template-path')
+@aria.argument('service-template-name')
+@aria.options.service_template_filename
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_resource_storage
+@aria.pass_plugin_manager
+@aria.pass_logger
+def store(service_template_path, service_template_name, service_template_filename,
+ model_storage, resource_storage, plugin_manager, logger):
+ """
+ Parse and store a service template archive
+
+ SERVICE_TEMPLATE_PATH is the path to the service template archive.
+
+ SERVICE_TEMPLATE_NAME is the unique name to give to the service template in storage.
+ """
+ logger.info('Storing service template {0}...'.format(service_template_name))
+
+ service_template_path = service_template_utils.get(service_template_path,
+ service_template_filename)
+ core = Core(model_storage, resource_storage, plugin_manager)
+ try:
+ core.create_service_template(service_template_path,
+ os.path.dirname(service_template_path),
+ service_template_name)
+ except storage_exceptions.StorageError as e:
+ utils.check_overriding_storage_exceptions(e, 'service template', service_template_name)
+ raise
+ logger.info('Service template {0} stored'.format(service_template_name))
+
+
+@service_templates.command(name='delete',
+ short_help='Delete a stored service template')
+@aria.argument('service-template-name')
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_resource_storage
+@aria.pass_plugin_manager
+@aria.pass_logger
+def delete(service_template_name, model_storage, resource_storage, plugin_manager, logger):
+ """
+ Delete a stored service template
+
+ SERVICE_TEMPLATE_NAME is the unique name of the stored service template.
+ """
+ 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)
+ core.delete_service_template(service_template.id)
+ logger.info('Service template {0} deleted'.format(service_template_name))
+
+
+@service_templates.command(name='inputs',
+ short_help='Show stored service template inputs')
+@aria.argument('service-template-name')
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_logger
+def inputs(service_template_name, model_storage, logger):
+ """
+ Show stored service template inputs
+
+ SERVICE_TEMPLATE_NAME is the unique name of the stored service template.
+ """
+ logger.info('Showing inputs for service template {0}...'.format(service_template_name))
+ print_service_template_inputs(model_storage, service_template_name, logger)
+
+
+@service_templates.command(name='validate',
+ short_help='Validate a service template archive')
+@aria.argument('service-template')
+@aria.options.service_template_filename
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_resource_storage
+@aria.pass_plugin_manager
+@aria.pass_logger
+def validate(service_template, service_template_filename,
+ model_storage, resource_storage, plugin_manager, logger):
+ """
+ Validate a service template archive
+
+ SERVICE_TEMPLATE_PATH is the path to the service template archive.
+ """
+ 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)
+ core.validate_service_template(service_template_path)
+ logger.info('Service template validated successfully')
+
+
+@service_templates.command(name='create-archive',
+ short_help='Create a CSAR archive from a service template source')
+@aria.argument('service-template-path')
+@aria.argument('destination')
+@aria.options.verbose()
+@aria.pass_logger
+def create_archive(service_template_path, destination, logger):
+ """
+ Create a CSAR archive from a service template source
+
+ SERVICE_TEMPLATE_PATH is the path to the service template source.
+
+ DESTINATION is the path to the created CSAR archive.
+ """
+ logger.info('Creating a CSAR archive')
+ if not destination.endswith(csar.CSAR_FILE_EXTENSION):
+ destination += csar.CSAR_FILE_EXTENSION
+ csar.write(service_template_path, destination, logger)
+ logger.info('CSAR archive created at {0}'.format(destination))
+
+
+def print_service_template_inputs(model_storage, service_template_name, logger):
+ service_template = model_storage.service_template.get_by_name(service_template_name)
+
+ logger.info('Service template inputs:')
+ if service_template.inputs:
+ logger.info(utils.get_parameter_templates_as_string(service_template.inputs))
+ else:
+ logger.info('\tNo inputs')
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/services.py b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/services.py
new file mode 100644
index 0000000..6752899
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/services.py
@@ -0,0 +1,238 @@
+# 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.
+
+"""
+CLI ``services`` sub-commands.
+"""
+
+import os
+from StringIO import StringIO
+
+from . import service_templates
+from .. import helptexts
+from .. import table
+from .. import utils
+from ..core import aria
+from ...core import Core
+from ...modeling import exceptions as modeling_exceptions
+from ...storage import exceptions as storage_exceptions
+from ...parser import consumption
+from ...utils import (formatting, collections, console)
+from ...orchestrator import topology
+
+
+DESCRIPTION_FIELD_LENGTH_LIMIT = 20
+SERVICE_COLUMNS = ('id', 'name', 'description', 'service_template_name', 'created_at', 'updated_at')
+
+
+@aria.group(name='services')
+@aria.options.verbose()
+def services():
+ """
+ Manage services
+ """
+ pass
+
+
+@services.command(name='show',
+ short_help='Show information for a service')
+@aria.argument('service-name')
+@aria.options.verbose()
+@aria.options.service_mode_full
+@aria.options.mode_graph
+@aria.options.format_json
+@aria.options.format_yaml
+@aria.pass_model_storage
+@aria.pass_logger
+def show(service_name, model_storage, mode_full, mode_graph, format_json, format_yaml, logger):
+ """
+ Show information for a service
+
+ SERVICE_NAME is the unique name of the service.
+ """
+ service = model_storage.service.get_by_name(service_name)
+
+ if format_json or format_yaml:
+ mode_full = True
+
+ if mode_full:
+ consumption.ConsumptionContext()
+ if format_json:
+ console.puts(formatting.json_dumps(collections.prune(service.as_raw)))
+ elif format_yaml:
+ console.puts(formatting.yaml_dumps(collections.prune(service.as_raw)))
+ else:
+ console.puts(topology.Topology().dump(service))
+ elif mode_graph:
+ console.puts(topology.Topology().dump_graph(service))
+ else:
+ logger.info('Showing service {0}...'.format(service_name))
+ service_dict = service.to_dict()
+ columns = SERVICE_COLUMNS
+ column_formatters = \
+ dict(description=table.trim_formatter_generator(DESCRIPTION_FIELD_LENGTH_LIMIT))
+ table.print_data(columns, service_dict, 'Service:',
+ column_formatters=column_formatters, col_max_width=50)
+
+ if service_dict['description'] is not None:
+ logger.info('Description:')
+ logger.info('{0}{1}'.format(service_dict['description'].encode('UTF-8') or '',
+ os.linesep))
+
+
+@services.command(name='list', short_help='List services')
+@aria.options.service_template_name()
+@aria.options.sort_by()
+@aria.options.descending
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_logger
+def list(service_template_name,
+ sort_by,
+ descending,
+ model_storage,
+ logger):
+ """
+ List services
+
+ If `--service-template-name` is provided, list services based on that service template.
+ Otherwise, list all services.
+ """
+ if service_template_name:
+ logger.info('Listing services for service template {0}...'.format(
+ service_template_name))
+ service_template = model_storage.service_template.get_by_name(service_template_name)
+ filters = dict(service_template=service_template)
+ else:
+ logger.info('Listing all services...')
+ filters = {}
+
+ services_list = model_storage.service.list(
+ sort=utils.storage_sort_param(sort_by=sort_by, descending=descending),
+ filters=filters)
+ table.print_data(SERVICE_COLUMNS, services_list, 'Services:')
+
+
+@services.command(name='create',
+ short_help='Create a service')
+@aria.argument('service-name', required=False)
+@aria.options.service_template_name(required=True)
+@aria.options.inputs(help=helptexts.SERVICE_INPUTS)
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_resource_storage
+@aria.pass_plugin_manager
+@aria.pass_logger
+def create(service_template_name,
+ service_name,
+ inputs, # pylint: disable=redefined-outer-name
+ model_storage,
+ resource_storage,
+ plugin_manager,
+ logger):
+ """
+ Create a service
+
+ SERVICE_NAME is the unique name to give to the service.
+ """
+ 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:
+ service = core.create_service(service_template.id, inputs, service_name)
+ except storage_exceptions.StorageError as e:
+ utils.check_overriding_storage_exceptions(e, 'service', service_name)
+ raise
+ except modeling_exceptions.ParameterException:
+ service_templates.print_service_template_inputs(model_storage, service_template_name,
+ logger)
+ raise
+ logger.info("Service created. The service's name is {0}".format(service.name))
+
+
+@services.command(name='delete',
+ short_help='Delete a service')
+@aria.argument('service-name')
+@aria.options.force(help=helptexts.IGNORE_AVAILABLE_NODES)
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_resource_storage
+@aria.pass_plugin_manager
+@aria.pass_logger
+def delete(service_name, force, model_storage, resource_storage, plugin_manager, logger):
+ """
+ Delete a service
+
+ SERVICE_NAME is the unique name of the service.
+ """
+ logger.info('Deleting service {0}...'.format(service_name))
+ service = model_storage.service.get_by_name(service_name)
+ core = Core(model_storage, resource_storage, plugin_manager)
+ core.delete_service(service.id, force=force)
+ logger.info('Service {0} deleted'.format(service_name))
+
+
+@services.command(name='outputs',
+ short_help='Show service outputs')
+@aria.argument('service-name')
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_logger
+def outputs(service_name, model_storage, logger):
+ """
+ Show service outputs
+
+ SERVICE_NAME is the unique name of the service.
+ """
+ logger.info('Showing outputs for service {0}...'.format(service_name))
+ service = model_storage.service.get_by_name(service_name)
+
+ if service.outputs:
+ outputs_string = StringIO()
+ for output_name, output in service.outputs.iteritems():
+ outputs_string.write(' - "{0}":{1}'.format(output_name, os.linesep))
+ outputs_string.write(' Description: {0}{1}'.format(output.description, os.linesep))
+ outputs_string.write(' Value: {0}{1}'.format(output.value, os.linesep))
+ logger.info(outputs_string.getvalue())
+ else:
+ logger.info('\tNo outputs')
+
+
+@services.command(name='inputs',
+ short_help='Show service inputs')
+@aria.argument('service-name')
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_logger
+def inputs(service_name, model_storage, logger):
+ """
+ Show service inputs
+
+ SERVICE_NAME is the unique name of the service.
+ """
+ logger.info('Showing inputs for service {0}...'.format(service_name))
+ service = model_storage.service.get_by_name(service_name)
+
+ if service.inputs:
+ inputs_string = StringIO()
+ for input_name, input_ in service.inputs.iteritems():
+ inputs_string.write(' - "{0}":{1}'.format(input_name, os.linesep))
+ inputs_string.write(' Description: {0}{1}'.format(input_.description, os.linesep))
+ inputs_string.write(' Value: {0}{1}'.format(input_.value, os.linesep))
+ logger.info(inputs_string.getvalue())
+ else:
+ logger.info('\tNo inputs')
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/workflows.py b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/workflows.py
new file mode 100644
index 0000000..ca191aa
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/commands/workflows.py
@@ -0,0 +1,111 @@
+# 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.
+
+"""
+CLI ``worfklows`` sub-commands.
+"""
+
+from .. import table
+from ..core import aria
+from ..exceptions import AriaCliError
+
+WORKFLOW_COLUMNS = ['name', 'service_template_name', 'service_name']
+
+
+@aria.group(name='workflows')
+def workflows():
+ """
+ Manage service workflows
+ """
+ pass
+
+
+@workflows.command(name='show',
+ short_help='Show information for a service workflow')
+@aria.argument('workflow-name')
+@aria.options.service_name(required=True)
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_logger
+def show(workflow_name, service_name, model_storage, logger):
+ """
+ Show information for a service workflow
+
+ SERVICE_NAME is the unique name of the service.
+
+ WORKFLOW_NAME is the unique name of the workflow within the service (e.g. "uninstall").
+ """
+ logger.info('Retrieving workflow {0} for service {1}'.format(
+ workflow_name, service_name))
+ service = model_storage.service.get_by_name(service_name)
+ workflow = next((wf for wf in service.workflows.itervalues() if
+ wf.name == workflow_name), None)
+ if not workflow:
+ raise AriaCliError(
+ 'Workflow {0} not found for service {1}'.format(workflow_name, service_name))
+
+ defaults = {
+ 'service_template_name': service.service_template_name,
+ 'service_name': service.name
+ }
+ table.print_data(WORKFLOW_COLUMNS, workflow, 'Workflows:', defaults=defaults)
+
+ # print workflow inputs
+ required_inputs = dict()
+ optional_inputs = dict()
+ for input_name, input in workflow.inputs.iteritems():
+ inputs_group = optional_inputs if input.value is not None else required_inputs
+ inputs_group[input_name] = input
+
+ logger.info('Workflow Inputs:')
+ logger.info('\tMandatory Inputs:')
+ for input_name, input in required_inputs.iteritems():
+ if input.description is not None:
+ logger.info('\t\t{0}\t({1})'.format(input_name,
+ input.description))
+ else:
+ logger.info('\t\t{0}'.format(input_name))
+
+ logger.info('\tOptional Inputs:')
+ for input_name, input in optional_inputs.iteritems():
+ if input.description is not None:
+ logger.info('\t\t{0}: \t{1}\t({2})'.format(
+ input_name, input.value, input.description))
+ else:
+ logger.info('\t\t{0}: \t{1}'.format(input_name,
+ input.value))
+
+
+@workflows.command(name='list',
+ short_help='List service workflows')
+@aria.options.service_name(required=True)
+@aria.options.verbose()
+@aria.pass_model_storage
+@aria.pass_logger
+def list(service_name, model_storage, logger):
+ """
+ List service workflows
+
+ SERVICE_NAME is the unique name of the service.
+ """
+ logger.info('Listing workflows for service {0}...'.format(service_name))
+ service = model_storage.service.get_by_name(service_name)
+ workflows_list = sorted(service.workflows.itervalues(), key=lambda w: w.name)
+
+ defaults = {
+ 'service_template_name': service.service_template_name,
+ 'service_name': service.name
+ }
+ table.print_data(WORKFLOW_COLUMNS, workflows_list, 'Workflows:', defaults=defaults)