diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 3687842..0000000 --- a/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -*.pyc -*.sqlite - -*.gem - -# vim swap files -.*.swp - -# services' runtime files -*.log -*.pid - -# Vagrant housekeeping file -.vagrant - -build -dist -lock - -*.egg -.testrepository -.tox -.venv -.idea -.DS_Store -test_run/* - -*.egg-info - -fuelclient-*.xml -.coverage diff --git a/.gitreview b/.gitreview deleted file mode 100644 index ab64fce..0000000 --- a/.gitreview +++ /dev/null @@ -1,4 +0,0 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=openstack/python-fuelclient.git diff --git a/.testr.conf b/.testr.conf deleted file mode 100644 index 00e20ad..0000000 --- a/.testr.conf +++ /dev/null @@ -1,5 +0,0 @@ -[DEFAULT] -test_command=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_LOG_CAPTURE=1 ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./fuelclient/tests/unit} $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list -test_run_concurrency=echo 1 diff --git a/MAINTAINERS b/MAINTAINERS deleted file mode 100644 index c8b884f..0000000 --- a/MAINTAINERS +++ /dev/null @@ -1,69 +0,0 @@ ---- -description: - For Fuel team structure and contribution policy, see [1]. - - This is repository level MAINTAINERS file. All contributions to this - repository must be approved by one or more Core Reviewers [2]. - If you are contributing to files (or create new directories) in - root folder of this repository, please contact Core Reviewers for - review and merge requests. - - If you are contributing to subfolders of this repository, please - check 'maintainers' section of this file in order to find maintainers - for those specific modules. - - It is mandatory to get +1 from one or more maintainers before asking - Core Reviewers for review/merge in order to decrease a load on Core Reviewers [3]. - Exceptions are when maintainers are actually cores, or when maintainers - are not available for some reason (e.g. on vacation). - - [1] http://specs.openstack.org/openstack/fuel-specs/policy/team-structure.html - [2] https://review.openstack.org/#/admin/groups/551,members - [3] http://lists.openstack.org/pipermail/openstack-dev/2015-August/072406.html - - Please keep this file in YAML format in order to allow helper scripts - to read this as a configuration data. - -maintainers: - -- ./: - - name: Alexander Saprykin - email: asaprykin@mirantis.com - IRC: asaprykin - - - name: Bulat Gaifullin - email: bgaifullin@mirantis.com - IRC: bgaifullin - - - name: Maciej Kwiek - email: mkwiek@mirantis.com - IRC: mkwiek - - - name: Sylwester Brzeczkowski - email: sbrzeczkowski@mirantis.com - IRC: sylwesterB - -- specs/: - - name: Mikhail Ivanov - email: mivanov@mirantis.com - IRC: mivanov - - - name: Artem Silenkov - email: asilenkov@mirantis.com - IRC: asilenkov - - - name: Alexander Tsamutali - email: atsamutali@mirantis.com - IRC: astsmtl - - - name: Daniil Trishkin - email: dtrishkin@mirantis.com - IRC: dtrishkin - - - name: Ivan Udovichenko - email: iudovichenko@mirantis.com - IRC: tlbr - - - name: Igor Yozhikov - email: iyozhikov@mirantis.com - IRC: IgorYozhikov diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 30fa462..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -include fuelclient/fuel_client.yaml diff --git a/README b/README new file mode 100644 index 0000000..8fcd2b2 --- /dev/null +++ b/README @@ -0,0 +1,14 @@ +This project is no longer maintained. + +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". + +For ongoing work on maintaining OpenStack packages in the Debian +distribution, please see the Debian OpenStack packaging team at +https://wiki.debian.org/OpenStack/. + +For any further questions, please email +openstack-dev@lists.openstack.org or join #openstack-dev on +Freenode. diff --git a/README.rst b/README.rst deleted file mode 100644 index 5969382..0000000 --- a/README.rst +++ /dev/null @@ -1,38 +0,0 @@ -======================== -Team and repository tags -======================== - -.. image:: http://governance.openstack.org/badges/python-fuelclient.svg - :target: http://governance.openstack.org/reference/tags/index.html - -.. Change things from this point on - -python-fuelclient -================= - -python-fuelclient provides a CLI tool and a Python API wrapper for interacting -with `Fuel `_. - - ------------------ -Project resources ------------------ - -Project status, bugs, and blueprints are tracked on Launchpad: - https://launchpad.net/fuel - -Development documentation is hosted here: - https://docs.fuel-infra.org/fuel-dev - -User guide can be found here: - http://docs.mirantis.com - -Any additional information can be found on the Fuel's project wiki - https://wiki.openstack.org/wiki/Fuel - -Anyone wishing to contribute to python-fuelclient should follow the general -OpenStack process. A good reference for it can be found here: - https://wiki.openstack.org/wiki/How_To_Contribute - - http://docs.openstack.org/infra/manual/developers.html - diff --git a/fuelclient/__init__.py b/fuelclient/__init__.py deleted file mode 100644 index d9c92b8..0000000 --- a/fuelclient/__init__.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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. - -# DO NOT PUT ANY IMPORTS HERE BECAUSE THIS FILE IS USED -# DURING THE INSTALLATION. - -try: - import pkg_resources - try: - __version__ = pkg_resources.get_distribution( - "python-fuelclient").version - except pkg_resources.DistributionNotFound: - __version__ = "" -except ImportError: - __version__ = "" - - -def connect(host, port, http_proxy=None, os_username=None, os_password=None, - os_tenant_name=None, debug=False): - """Creates API connection.""" - from fuelclient import client - - return client.APIClient( - host, port, http_proxy=http_proxy, os_username=os_username, - os_password=os_password, os_tenant_name=os_tenant_name, debug=debug) - - -def get_client(resource, version='v1', connection=None): - """Gets an API client for a resource - - python-fuelclient provides access to Fuel's API - through a set of per-resource facades. In order to - get a proper facade it's necessary to specify the name - of the API resource and the version of Fuel's API. - - :param resource: Name of the resource to get a facade for. - :type resource: str - Valid values are environment, node and task - :param version: Version of the Fuel's API - :type version: str, - Available: v1. Default: v1. - :param connection: API connection - :type connection: fuelclient.client.APIClient - :return: Facade to the specified resource that wraps - calls to the specified version of the API. - - """ - from fuelclient import v1 - - version_map = { - 'v1': { - 'cluster-settings': v1.cluster_settings, - 'deployment_history': v1.deployment_history, - 'deployment-info': v1.deployment_info, - 'environment': v1.environment, - 'extension': v1.extension, - 'fuel-version': v1.fuelversion, - 'graph': v1.graph, - 'health': v1.health, - 'network-configuration': v1.network_configuration, - 'network-group': v1.network_group, - 'node': v1.node, - 'openstack-config': v1.openstack_config, - 'plugins': v1.plugins, - 'release': v1.release, - 'role': v1.role, - 'sequence': v1.sequence, - 'snapshot': v1.snapshot, - 'task': v1.task, - 'tag': v1.tag, - 'vip': v1.vip - } - } - - try: - return version_map[version][resource].get_client(connection) - except KeyError: - msg = 'Cannot load API client for "{r}" in the API version "{v}".' - raise ValueError(msg.format(r=resource, v=version)) diff --git a/fuelclient/cli/__init__.py b/fuelclient/cli/__init__.py deleted file mode 100644 index 9aa9881..0000000 --- a/fuelclient/cli/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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. - -"""fuelclient.cli sub-module contains functionality of -fuelclient command line interface - - -""" diff --git a/fuelclient/cli/actions/__init__.py b/fuelclient/cli/actions/__init__.py deleted file mode 100644 index 3d82f2c..0000000 --- a/fuelclient/cli/actions/__init__.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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. -"""fuelclient.cli.actions sub-module contains files with action classes -which implement command line interface logic - -All action classes must be added to action_tuple to be used by parser -""" -from fuelclient.cli.actions.deploy import DeployChangesAction -from fuelclient.cli.actions.deploy import RedeployChangesAction -from fuelclient.cli.actions.deployment_tasks import DeploymentTasksAction -from fuelclient.cli.actions.environment import EnvironmentAction -from fuelclient.cli.actions.fact import DeploymentAction -from fuelclient.cli.actions.fact import ProvisioningAction -from fuelclient.cli.actions.graph import GraphAction -from fuelclient.cli.actions.token import TokenAction -from fuelclient.cli.actions.health import HealthCheckAction -from fuelclient.cli.actions.interrupt import ResetAction -from fuelclient.cli.actions.interrupt import StopAction -from fuelclient.cli.actions.network import NetworkAction -from fuelclient.cli.actions.network import NetworkTemplateAction -from fuelclient.cli.actions.network_group import NetworkGroupAction -from fuelclient.cli.actions.node import NodeAction -from fuelclient.cli.actions.nodegroup import NodeGroupAction -from fuelclient.cli.actions.notifications import NotificationsAction -from fuelclient.cli.actions.notifications import NotifyAction -from fuelclient.cli.actions.openstack_config import OpenstackConfigAction -from fuelclient.cli.actions.release import ReleaseAction -from fuelclient.cli.actions.role import RoleAction -from fuelclient.cli.actions.settings import SettingsAction -from fuelclient.cli.actions.snapshot import SnapshotAction -from fuelclient.cli.actions.user import UserAction -from fuelclient.cli.actions.plugins import PluginAction -from fuelclient.cli.actions.fuelversion import FuelVersionAction -from fuelclient.cli.actions.vip import VIPAction - -actions_tuple = ( - DeployChangesAction, - DeploymentAction, - DeploymentTasksAction, - EnvironmentAction, - FuelVersionAction, - GraphAction, - HealthCheckAction, - NetworkAction, - NetworkGroupAction, - NetworkTemplateAction, - NodeAction, - NodeGroupAction, - NotificationsAction, - NotifyAction, - OpenstackConfigAction, - PluginAction, - ProvisioningAction, - RedeployChangesAction, - ReleaseAction, - ResetAction, - RoleAction, - SettingsAction, - SnapshotAction, - StopAction, - TokenAction, - UserAction, - VIPAction, -) - -actions = dict( - (action.action_name, action()) - for action in actions_tuple -) diff --git a/fuelclient/cli/actions/base.py b/fuelclient/cli/actions/base.py deleted file mode 100644 index 284e978..0000000 --- a/fuelclient/cli/actions/base.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 functools import partial -from functools import wraps -import os - -import six - -from fuelclient.cli import error -from fuelclient.cli.formatting import quote_and_join -from fuelclient.cli.serializers import Serializer -from fuelclient.client import DefaultAPIClient - - -class Action(object): - """Action class generalizes logic of action execution - method action_func - entry point of parser with parsed arguments - - flag_func_map - is tuple of pairs ("flag", self.some_method) where - "flag" is name of argument which causes "some_method" to be called. - None is used as "flag" when method will be called without any flag. - - serializer - is Serializer class instance which supposed to be the - only way to read and write to output or file system. - - args - tuple of function calls of functions from arguments module, - is a manifest of all arguments used in action, and is used to initialize - argparse subparser of that action. - """ - def __init__(self): - # Mapping of flags to methods - self.flag_func_map = None - self.serializer = Serializer() - - def action_func(self, params): - """Entry point for all actions subclasses - """ - DefaultAPIClient.debug_mode(debug=params.debug) - - self.serializer = Serializer.from_params(params) - if self.flag_func_map is not None: - for flag, method in self.flag_func_map: - if flag is None or getattr(params, flag): - method(params) - break - - @property - def examples(self): - """examples property is concatenation of __doc__ strings from - methods in child action classes, and is added as epilog of help - output - """ - methods_with_docs = set( - method - for _, method in self.flag_func_map - ) - return "Examples:\n\n" + \ - "\n".join( - six.moves.map( - lambda method: ( - "\t" + method.__doc__.replace("\n ", "\n") - ), - methods_with_docs - ) - ).format( - action_name=self.action_name - ) - - def full_path_directory(self, directory, base_name): - full_path = os.path.join(directory, base_name) - if not os.path.exists(full_path): - try: - os.mkdir(full_path) - except OSError as e: - raise error.ActionException(six.text_type(e)) - return full_path - - def default_directory(self, directory=None): - return os.path.abspath(os.curdir if directory is None else directory) - - -def wrap(method, args, f): - """wrap - is second order function, purpose of which is to - generalize argument checking for methods in actions in form - of decorator with arguments. - - 'check_all' and 'check_any' are partial function of wrap. - """ - @wraps(f) - def wrapped_f(self, params): - if method(getattr(params, _arg) for _arg in args): - return f(self, params) - else: - raise error.ArgumentException( - "{0} required!".format( - quote_and_join( - "--" + arg for arg in args - ) - ) - ) - return wrapped_f - - -def check_all(*args): - """check_all - decorator with arguments, which checks that - all arguments are given before running action method, if - not all arguments are given, it raises an ArgumentException. - """ - return partial(wrap, all, args) - - -def check_any(*args): - """check_any - decorator with arguments, which checks that - at least one arguments is given before running action method, - if no arguments were given, it raises an ArgumentException. - """ - return partial(wrap, any, args) diff --git a/fuelclient/cli/actions/deploy.py b/fuelclient/cli/actions/deploy.py deleted file mode 100644 index f33585d..0000000 --- a/fuelclient/cli/actions/deploy.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 six - -from fuelclient.cli.actions.base import Action -import fuelclient.cli.arguments as Args -from fuelclient.objects.environment import Environment - - -class ChangesAction(Action): - - action_name = None - actions_func_map = {} - - def __init__(self): - super(ChangesAction, self).__init__() - self.args = ( - Args.get_env_arg(required=True), - Args.get_dry_run_deployment_arg(), - ) - self.flag_func_map = ( - (None, self.deploy_changes), - ) - - def print_deploy_info(self, deploy_task): - six.print_("Deployment task with id {t} for the environment {e} " - "has been started.".format(t=deploy_task.id, - e=deploy_task.env.id) - ) - - def deploy_changes(self, params): - """To apply all changes to some environment: - fuel --env 1 {action_name} - """ - env = Environment(params.env) - - deploy_task = getattr( - env, self.actions_func_map[self.action_name])( - dry_run=params.dry_run) - self.serializer.print_to_output( - deploy_task.data, - deploy_task, - print_method=self.print_deploy_info) - - -class DeployChangesAction(ChangesAction): - """Deploy changes to environments - """ - action_name = "deploy-changes" - - def __init__(self): - super(DeployChangesAction, self).__init__() - self.actions_func_map[self.action_name] = 'deploy_changes' - - -class RedeployChangesAction(ChangesAction): - """Redeploy changes to environment which is in the operational state - """ - action_name = "redeploy-changes" - - def __init__(self): - super(RedeployChangesAction, self).__init__() - self.actions_func_map[self.action_name] = 'redeploy_changes' diff --git a/fuelclient/cli/actions/deployment_tasks.py b/fuelclient/cli/actions/deployment_tasks.py deleted file mode 100644 index 9dabb66..0000000 --- a/fuelclient/cli/actions/deployment_tasks.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli.actions.base import Action -import fuelclient.cli.arguments as Args -from fuelclient.cli.arguments import group -from fuelclient.cli.formatting import format_table - -from fuelclient.v1.deployment_history import DeploymentHistoryClient - - -class DeploymentTasksAction(Action): - """Show deployment tasks - """ - action_name = "deployment-tasks" - - def __init__(self): - super(DeploymentTasksAction, self).__init__() - self.args = [ - group( - Args.get_list_arg("List all deployment tasks"), - ), - Args.get_single_task_arg(required=True), - Args.get_deployment_node_arg( - "Node ids." - ), - Args.get_status_arg( - "Statuses: pending, error, ready, running, skipped" - ), - Args.get_tasks_names_arg( - "Show deployment history for specific deployment tasks names " - "and group output by task" - ), - Args.get_show_parameters_arg( - "Show deployment tasks parameters" - ), - Args.get_include_summary_arg( - "Show deployment tasks summary" - ), - ] - self.flag_func_map = ( - (None, self.list), - ) - - def list(self, params): - """To display all deployment tasks for task: - fuel deployment-tasks --task-id 5 - - To display deployment tasks for some nodes: - fuel deployment-tasks --task-id 5 --node 1,2 - - To display deployment tasks for some statuses(pending, error, - ready, running): - fuel deployment-tasks --task-id 5 --status pending,running - - To display deployment tasks for some statuses(pending, error, - ready, running) on some nodes: - fuel deployment-tasks --task-id 5 --status error --node 1,2 - - To display certain deployment tasks results only: - fuel deployment-tasks --task-id 5 - --task-name task-name1,task-name2 - - To display tasks parameters use: - fuel deployment-tasks --task-id 5 --show-parameters - - """ - client = DeploymentHistoryClient() - tasks_names = getattr(params, 'task-name', None) - show_parameters = getattr(params, 'show-parameters') - statuses = params.status.split(',') if params.status else [] - nodes = params.node.split(',') if params.node else [] - tasks_names = tasks_names.split(',') if tasks_names else [] - include_summary = getattr(params, 'include-summary') - - data = client.get_all( - transaction_id=params.task, - nodes=nodes, - statuses=statuses, - tasks_names=tasks_names, - show_parameters=show_parameters, - include_summary=include_summary - ) - - if show_parameters: - table_keys = client.tasks_records_keys - else: - table_keys = client.history_records_keys - if include_summary: - table_keys += ('summary',) - self.serializer.print_to_output( - data, - format_table( - data, - acceptable_keys=table_keys - ) - ) diff --git a/fuelclient/cli/actions/environment.py b/fuelclient/cli/actions/environment.py deleted file mode 100644 index 549b591..0000000 --- a/fuelclient/cli/actions/environment.py +++ /dev/null @@ -1,228 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 sys - -import six - -from fuelclient.cli.actions.base import Action -from fuelclient.cli.actions.base import check_all -from fuelclient.cli.actions.base import check_any -import fuelclient.cli.arguments as Args -from fuelclient.cli.arguments import group -from fuelclient.cli.formatting import format_table -from fuelclient.objects.environment import Environment - - -class EnvironmentAction(Action): - """Create, list and modify currently existing environments(clusters) - """ - action_name = "environment" - - def __init__(self): - super(EnvironmentAction, self).__init__() - self.args = [ - Args.get_env_arg(), - group( - Args.get_list_arg( - "List all available environments" - ), - Args.get_set_arg( - "Set environment parameters e.g., its name" - ), - Args.get_delete_arg( - "Delete environment with a specific id or name" - ), - Args.get_create_arg( - "Create a new environment with " - "specific release id and name" - ), - ), - Args.get_release_arg( - "Release id" - ), - Args.get_force_arg( - "Do it anyway" - ), - Args.get_name_arg( - "Environment name" - ), - Args.get_nst_arg( - "Set network segment type" - ), - Args.get_deployment_tasks_arg("Environment tasks configuration"), - Args.get_attributes_arg("Environment attributes"), - group( - Args.get_download_arg( - "Download configuration of specific cluster"), - Args.get_upload_arg( - "Upload configuration to specific cluster") - ), - Args.get_dir_arg( - "Select directory to which download release attributes"), - ] - self.flag_func_map = ( - ("deployment-tasks", self.deployment_tasks), - ("attributes", self.attributes), - ("create", self.create), - ("set", self.set), - ("delete", self.delete), - (None, self.list) - ) - - @check_all("name", "release") - def create(self, params): - """To create an environment with name MyEnv and release id=1 run: - fuel env create --name MyEnv --rel 1 - - By default, it creates environment setting neutron with VLAN - network segmentation as network provider - To specify other modes add optional arguments: - fuel env create --name MyEnv --rel 1 --net-segment-type vlan - """ - - if params.nst == 'gre': - six.print_( - "WARNING: GRE network segmentation type is deprecated " - "since 7.0 release.", file=sys.stderr) - - env = Environment.create( - params.name, - params.release, - params.nst, - ) - - data = env.get_fresh_data() - - self.serializer.print_to_output( - data, - u"Environment '{name}' with id={id} was created!" - .format(**data) - ) - - @check_all("env") - def set(self, params): - """To change environment name: - fuel --env 1 env set --name NewEnvName - """ - acceptable_params = ('name', ) - - env = Environment(params.env, params=params) - - # forming message for output and data structure for request body - # TODO(aroma): make it less ugly - msg_template = ("Following attributes are changed for " - "the environment: {env_attributes}") - - env_attributes = [] - update_kwargs = dict() - for param_name in acceptable_params: - attr_value = getattr(params, param_name, None) - if attr_value: - update_kwargs[param_name] = attr_value - env_attributes.append( - ''.join([param_name, '=', str(attr_value)]) - ) - - data = env.set(update_kwargs) - env_attributes = ', '.join(env_attributes) - self.serializer.print_to_output( - data, - msg_template.format(env_attributes=env_attributes) - ) - - @check_all("env") - def delete(self, params): - """To delete the environment: - fuel --env 1 env --force delete - """ - env = Environment(params.env, params=params) - - if env.status == "operational" and not params.force: - self.serializer.print_to_output(env.data, - "Deleting an operational" - "environment is a dangerous " - "operation. Please use --force to " - "bypass this message.") - return - - data = env.delete() - self.serializer.print_to_output( - data, - "Environment with id={0} was deleted" - .format(env.id) - ) - - def list(self, params): - """Print all available environments: - fuel env - """ - acceptable_keys = ("id", "status", "name", "release_id", ) - data = Environment.get_all_data() - if params.env: - data = filter( - lambda x: x[u"id"] == int(params.env), - data - ) - self.serializer.print_to_output( - data, - format_table( - data, - acceptable_keys=acceptable_keys - ) - ) - - @check_all("env") - @check_any("download", "upload") - def deployment_tasks(self, params): - """Modify deployment_tasks for environment: - fuel env --env 1 --deployment-tasks --download - fuel env --env 1 --deployment-tasks --upload - """ - cluster = Environment(params.env) - dir_path = self.full_path_directory( - params.dir, 'cluster_{0}'.format(params.env)) - full_path = '{0}/deployment_tasks'.format(dir_path) - if params.download: - tasks = cluster.get_deployment_tasks() - self.serializer.write_to_path(full_path, tasks) - print("Deployment tasks for cluster {0} " - "downloaded into {1}.yaml.".format(cluster.id, full_path)) - elif params.upload: - tasks = self.serializer.read_from_file(full_path) - cluster.update_deployment_tasks(tasks) - print("Deployment tasks for cluster {0} " - "uploaded from {1}.yaml".format(cluster.id, full_path)) - - @check_all("env") - @check_any("download", "upload") - def attributes(self, params): - """Modify attributes of the environment: - fuel env --env 1 --attributes --download - fuel env --env 1 --attributes --upload - """ - cluster = Environment(params.env) - dir_path = self.full_path_directory( - params.dir, 'cluster_{0}'.format(params.env)) - full_path = '{0}/attributes'.format(dir_path) - - if params.download: - attributes = cluster.get_attributes() - self.serializer.write_to_path(full_path, attributes) - print("Attributes of cluster {0} " - "downloaded into {1}.yaml.".format(cluster.id, full_path)) - elif params.upload: - attributes = self.serializer.read_from_file(full_path) - cluster.update_attributes(attributes, params.force) - print("Attributes of cluster {0} " - "uploaded from {1}.yaml".format(cluster.id, full_path)) diff --git a/fuelclient/cli/actions/fact.py b/fuelclient/cli/actions/fact.py deleted file mode 100644 index 22ea41e..0000000 --- a/fuelclient/cli/actions/fact.py +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli.actions.base import Action -import fuelclient.cli.arguments as Args -from fuelclient.cli.arguments import group -from fuelclient.objects.environment import Environment - - -class FactAction(Action): - - action_name = None - - def __init__(self): - super(FactAction, self).__init__() - self.args = [ - Args.get_env_arg(required=True), - group( - Args.get_delete_arg( - "Delete current {0} data.".format(self.action_name) - ), - Args.get_download_arg( - "Download current {0} data.".format(self.action_name) - ), - Args.get_upload_arg( - "Upload current {0} data.".format(self.action_name) - ), - Args.get_default_arg( - "Download default {0} data.".format(self.action_name) - ), - required=True - ), - Args.get_dir_arg( - "Directory with {0} data.".format(self.action_name) - ), - Args.get_node_arg( - "Node ids." - ), - Args.get_not_split_facts_args(), - ] - self.flag_func_map = ( - ("default", self.default), - ("upload", self.upload), - ("delete", self.delete), - ("download", self.download) - ) - - def default(self, params): - """To get default {action_name} information for some environment: - fuel --env 1 {action_name} --default - - It's possible to get default {action_name} information - just for some nodes: - fuel --env 1 {action_name} --default --node 1,2,3 - """ - env = Environment(params.env) - dir_name = env.write_facts_to_dir( - self.action_name, - env.get_default_facts( - self.action_name, nodes=params.node, split=params.split - ), - directory=params.dir, - serializer=self.serializer - ) - print( - "Default {0} info was downloaded to {1}".format( - self.action_name, - dir_name - ) - ) - - def upload(self, params): - """To upload {action_name} information for some environment: - fuel --env 1 {action_name} --upload - """ - env = Environment(params.env) - facts = env.read_fact_info( - self.action_name, - directory=params.dir, - serializer=self.serializer - ) - env.upload_facts(self.action_name, facts) - print("{0} facts were uploaded.".format(self.action_name)) - - def delete(self, params): - """Also {action_name} information can be left or - taken from specific directory: - fuel --env 1 {action_name} --upload \\ - --dir path/to/some/directory - """ - env = Environment(params.env) - env.delete_facts(self.action_name) - print("{0} facts deleted.".format(self.action_name)) - - def download(self, params): - """To download {action_name} information for some environment: - fuel --env 1 {action_name} --download - """ - env = Environment(params.env) - dir_name = env.write_facts_to_dir( - self.action_name, - env.get_facts( - self.action_name, nodes=params.node, split=params.split - ), - directory=params.dir, - serializer=self.serializer - ) - print( - "Current {0} info was downloaded to {1}".format( - self.action_name, - dir_name - ) - ) - - -class DeploymentAction(FactAction): - """Show computed deployment facts for orchestrator - """ - action_name = "deployment" - - -class ProvisioningAction(FactAction): - """Show computed provisioning facts for orchestrator - """ - action_name = "provisioning" diff --git a/fuelclient/cli/actions/fuelversion.py b/fuelclient/cli/actions/fuelversion.py deleted file mode 100644 index bc9d051..0000000 --- a/fuelclient/cli/actions/fuelversion.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli.arguments as Args - -from fuelclient.cli.actions.base import Action -from fuelclient.objects.fuelversion import FuelVersion - - -class FuelVersionAction(Action): - """Show Fuel server's version - """ - - action_name = "fuel-version" - - def __init__(self): - super(FuelVersionAction, self).__init__() - - self.args = [ - Args.get_list_arg("Show fuel version"), - ] - self.flag_func_map = ( - (None, self.version), - ) - - def version(self, params): - """To show fuel version data: - fuel fuel-version - """ - version = FuelVersion.get_all_data() - print(self.serializer.serialize(version)) diff --git a/fuelclient/cli/actions/graph.py b/fuelclient/cli/actions/graph.py deleted file mode 100644 index 3197144..0000000 --- a/fuelclient/cli/actions/graph.py +++ /dev/null @@ -1,163 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 six - -from fuelclient.cli.actions import base -import fuelclient.cli.arguments as Args -from fuelclient.cli import error -from fuelclient.objects import environment - - -class GraphAction(base.Action): - """Manipulate deployment graph's representation.""" - - action_name = 'graph' - - task_types = ('skipped', 'group', 'stage') - - def __init__(self): - super(GraphAction, self).__init__() - self.args = ( - Args.get_env_arg(), - Args.get_render_arg( - "Render graph from DOT to PNG" - ), - Args.get_download_arg( - "Download graph of specific cluster" - ), - Args.get_dir_arg( - "Select target dir to render graph." - ), - Args.group( - Args.get_skip_tasks(), - Args.get_tasks() - ), - Args.get_graph_endpoint(), - Args.get_graph_startpoint(), - Args.get_remove_type_arg(self.task_types), - Args.get_parents_arg(), - Args.get_tred_arg("Apply transitive reduction filter for graph."), - ) - self.flag_func_map = ( - ('render', self.render), - ('download', self.download), - ) - - @base.check_all("env") - def download(self, params): - """Download deployment graph to stdout - - fuel graph --env 1 --download - fuel graph --env 1 --download --tasks A B C - fuel graph --env 1 --download --skip X Y --end pre_deployment - fuel graph --env 1 --download --skip X Y --start post_deployment - - Specify output: - fuel graph --env 1 --download > output/dir/file.gv - - Get parents only for task A: - - fuel graph --env 1 --download --parents-for A - """ - env = environment.Environment(params.env) - - parents_for = getattr(params, 'parents-for') - - used_params = "# params:\n" - for param in ('start', 'end', 'skip', 'tasks', 'parents-for', - 'remove'): - used_params += "# - {0}: {1}\n".format(param, - getattr(params, param)) - - tasks = params.tasks - - if not tasks or (params.skip or params.end or params.start): - tasks = env.get_tasks( - skip=params.skip, end=params.end, - start=params.start, include=params.tasks) - - dotraph = env.get_deployment_tasks_graph(tasks, - parents_for=parents_for, - remove=params.remove) - sys.stdout.write(six.text_type(used_params)) - sys.stdout.write(six.text_type(dotraph)) - - @base.check_all("render") - def render(self, params): - """Render graph in PNG format - - fuel graph --render graph.gv - fuel graph --render graph.gv --dir ./output/dir/ - - To apply transitive reduction filter on rendered graph: - - fuel graph --render graph.gv --tred - fuel graph --render graph.gv --dir ./output/dir/ --tred - - Read graph from stdin - some_process | fuel graph --render - - """ - if params.render == '-': - dot_data = sys.stdin.read() - out_filename = 'graph.gv' - elif not os.path.exists(params.render): - raise error.ArgumentException( - "Input file does not exist" - ) - else: - out_filename = os.path.basename(params.render) - with open(params.render, 'r') as f: - dot_data = f.read() - - target_dir = self.full_path_directory( - self.default_directory(params.dir), - '' - ) - target_file = os.path.join( - target_dir, - '{0}.png'.format(out_filename), - ) - - if not os.access(os.path.dirname(target_file), os.W_OK): - raise error.ActionException( - 'Path {0} is not writable'.format(target_file)) - render_graph(dot_data, target_file, params.tred) - print('Graph saved in "{0}"'.format(target_file)) - - -def render_graph(input_data, output_path, tred=False): - """Renders DOT graph using pygraphviz. - - :param input_data: DOT graph representation - :param output_path: path to the rendered graph - :param tred: applies transitive reduction of graph - """ - try: - import pygraphviz - except ImportError: - raise error.WrongEnvironmentError( - "This action requires Graphviz installed " - "together with 'pygraphviz' Python library") - - graph = pygraphviz.AGraph(string=input_data) - if tred: - graph = graph.tred() - - graph.draw(output_path, prog='dot', format='png') diff --git a/fuelclient/cli/actions/health.py b/fuelclient/cli/actions/health.py deleted file mode 100644 index 8ceddad..0000000 --- a/fuelclient/cli/actions/health.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 sys - -from fuelclient.cli.actions.base import Action -import fuelclient.cli.arguments as Args -from fuelclient.cli.error import EnvironmentException -from fuelclient.cli.formatting import format_table -from fuelclient.cli.formatting import print_health_check -from fuelclient.objects.environment import Environment -import six - - -class HealthCheckAction(Action): - """Run health check on environment - """ - action_name = "health" - - _allowed_statuses = ( - 'error', - 'operational', - 'update_error', - ) - - def __init__(self): - super(HealthCheckAction, self).__init__() - self.args = ( - Args.get_env_arg(required=True), - Args.get_list_arg("List all available checks"), - Args.get_force_arg("Forced test run"), - Args.get_check_arg("Run check for some testset."), - Args.get_ostf_username_arg(), - Args.get_ostf_password_arg(), - Args.get_ostf_tenant_name_arg() - ) - - self.flag_func_map = ( - ("check", self.check), - (None, self.list) - ) - - def check(self, params): - """To run some health checks: - fuel --env 1 health --check smoke,sanity - """ - env = Environment(params.env) - - if env.status not in self._allowed_statuses and not params.force: - raise EnvironmentException( - "Environment is not ready to run health check " - "because it is in {0} state. " - "Health check is likely to fail because of " - "this. Use --force flag to proceed anyway.". format(env.status) - ) - - if env.is_customized and not params.force: - raise EnvironmentException( - "Environment deployment facts were updated. " - "Health check is likely to fail because of " - "that. Use --force flag to proceed anyway." - ) - test_sets_to_check = params.check or set( - ts["id"] for ts in env.get_testsets()) - ostf_credentials = {} - if params.ostf_tenant_name is not None: - ostf_credentials['tenant'] = params.ostf_tenant_name - if params.ostf_username is not None: - ostf_credentials['username'] = params.ostf_username - if params.ostf_password is not None: - ostf_credentials['password'] = params.ostf_password - if not ostf_credentials: - six.print_("WARNING: ostf credentials are going to be", - "mandatory in the next release.", file=sys.stderr) - env.run_test_sets(test_sets_to_check, ostf_credentials) - tests_state = env.get_state_of_tests() - self.serializer.print_to_output( - tests_state, - env, - print_method=print_health_check - ) - - def list(self, params): - """To list all health check test sets: - fuel --env 1 health - or: - fuel --env 1 health --list - """ - env = Environment(params.env) - test_sets = env.get_testsets() - self.serializer.print_to_output( - test_sets, - format_table(test_sets) - ) diff --git a/fuelclient/cli/actions/interrupt.py b/fuelclient/cli/actions/interrupt.py deleted file mode 100644 index 91ad9f5..0000000 --- a/fuelclient/cli/actions/interrupt.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli.actions.base import Action -import fuelclient.cli.arguments as Args -from fuelclient.objects.environment import Environment - - -class InterruptAction(Action): - - def __init__(self): - super(InterruptAction, self).__init__() - self.args = [ - Args.get_env_arg(required=True) - ] - self.flag_func_map = ( - (None, self.interrupt), - ) - - def interrupt(self, params): - """To {action_name} some environment: - fuel --env 1 {action_name} - """ - env = Environment(params.env) - intercept_task = getattr(env, self.action_name)() - self.serializer.print_to_output( - intercept_task.data, - "{0} task of environment with id={1} started. " - "To check task status run 'fuel task --tid {2}'.".format( - self.action_name.title(), - params.env, - intercept_task.data["id"] - ) - ) - - -class StopAction(InterruptAction): - """Stop deployment process for specific environment - """ - action_name = "stop" - - -class ResetAction(InterruptAction): - """Reset deployed process for specific environment - """ - action_name = "reset" diff --git a/fuelclient/cli/actions/network.py b/fuelclient/cli/actions/network.py deleted file mode 100644 index ce45431..0000000 --- a/fuelclient/cli/actions/network.py +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli.actions.base import Action -import fuelclient.cli.arguments as Args -from fuelclient.cli.arguments import group -from fuelclient.objects.environment import Environment - - -class NetworkAction(Action): - """Show or modify network settings of specific environments - """ - action_name = "network" - - def __init__(self): - super(NetworkAction, self).__init__() - self.args = ( - Args.get_env_arg(required=True), - Args.get_dir_arg("Directory with network data."), - group( - Args.get_download_arg( - "Download current network configuration."), - Args.get_verify_arg( - "Verify current network configuration."), - Args.get_upload_arg( - "Upload changed network configuration."), - required=True - ) - ) - self.flag_func_map = ( - ("upload", self.upload), - ("verify", self.verify), - ("download", self.download) - ) - - def upload(self, params): - """To upload network configuration from some - directory for some environment: - fuel --env 1 network --upload --dir path/to/directory - """ - env = Environment(params.env) - network_data = env.read_network_data( - directory=params.dir, - serializer=self.serializer - ) - env.set_network_data(network_data) - print("Network configuration uploaded.") - - def verify(self, params): - """To verify network configuration from some directory - for some environment: - fuel --env 1 network --verify --dir path/to/directory - """ - env = Environment(params.env) - response = env.verify_network() - print( - "Verification status is '{status}'. message: {message}" - .format(**response) - ) - - def download(self, params): - """To download network configuration in this - directory for some environment: - fuel --env 1 network --download - """ - env = Environment(params.env) - network_data = env.get_network_data() - network_file_path = env.write_network_data( - network_data, - directory=params.dir, - serializer=self.serializer) - print( - "Network configuration for environment with id={0}" - " downloaded to {1}" - .format(env.id, network_file_path) - ) - - -class NetworkTemplateAction(Action): - """Manipulate network templates for a specific environment - """ - action_name = 'network-template' - - def __init__(self): - super(NetworkTemplateAction, self).__init__() - self.args = ( - Args.get_env_arg(required=True), - Args.get_dir_arg("Directory with network templates."), - group( - Args.get_download_arg( - "Download current network template configuration."), - Args.get_upload_arg( - "Upload changed network template configuration."), - Args.get_delete_arg( - "Delete network template configuration."), - required=True)) - - self.flag_func_map = ( - ("upload", self.upload), - ("download", self.download), - ("delete", self.delete)) - - def upload(self, params): - """Uploads network template from filesystem path - for specified environment: - fuel --env 1 network-template --upload --dir path/to/directory - """ - env = Environment(params.env) - network_template_data = env.read_network_template_data( - directory=params.dir, - serializer=self.serializer) - env.set_network_template_data(network_template_data) - full_path = self.serializer.prepare_path( - env.get_network_template_data_path(directory=params.dir)) - print("Network template {0} has been uploaded.".format(full_path)) - - def download(self, params): - """Downloads network template in current - directory for specified environment: - fuel --env 1 network-template --download - """ - env = Environment(params.env) - template_data = env.get_network_template_data() - network_template_file_path = env.write_network_template_data( - template_data, - directory=params.dir, - serializer=self.serializer) - - print("Network template configuration for environment with id={0}" - " downloaded to {1}".format(env.id, network_template_file_path)) - - def delete(self, params): - """Deletes network template for specified environment: - fuel --env 1 --network-template --delete - """ - env = Environment(params.env) - env.delete_network_template_data() - - print("Network template configuration for environment id={0}" - " has been deleted.".format(env.id)) diff --git a/fuelclient/cli/actions/network_group.py b/fuelclient/cli/actions/network_group.py deleted file mode 100644 index 524c865..0000000 --- a/fuelclient/cli/actions/network_group.py +++ /dev/null @@ -1,147 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 sys - -import six - -from fuelclient.cli.actions.base import Action -from fuelclient.cli.actions.base import check_all -import fuelclient.cli.arguments as Args -from fuelclient.cli.arguments import group -from fuelclient.cli.formatting import format_table -from fuelclient.commands.network_group import get_args_for_update -from fuelclient.objects.network_group import NetworkGroup -from fuelclient.objects.network_group import NetworkGroupCollection - - -class NetworkGroupAction(Action): - """Show or modify network groups - """ - action_name = "network-group" - acceptable_keys = ("id", "name", "vlan_start", "cidr", - "gateway", "group_id") - - def __init__(self): - super(NetworkGroupAction, self).__init__() - self.args = ( - Args.get_env_arg(), - Args.get_name_arg("Name of new network group."), - Args.get_node_group_arg("ID of node group."), - Args.get_release_arg("Release ID this network group belongs to."), - Args.get_vlan_arg("VLAN of network."), - Args.get_cidr_arg("CIDR of network."), - Args.get_gateway_arg("Gateway of network."), - Args.get_network_group_arg("ID of network group."), - Args.get_meta_arg("Metadata in JSON format to override default " - "network metadata."), - group( - Args.get_create_network_arg( - "Create a new network group for the specified " - " node group." - ), - Args.get_delete_arg("Delete specified network groups."), - Args.get_list_arg("List all network groups."), - Args.get_set_arg("Set network group parameters.") - ) - ) - self.flag_func_map = ( - ("create", self.create), - ("delete", self.delete), - ("set", self.set), - (None, self.list), - ) - - @check_all('nodegroup', 'name', 'cidr') - def create(self, params): - """Create a new network group - fuel network-group --create --node-group 1 --name "new network" - --release 2 --vlan 100 --cidr 10.0.0.0/24 - - fuel network-group --create --node-group 2 --name "new network" - --release 2 --vlan 100 --cidr 10.0.0.0/24 --gateway 10.0.0.1 - --meta 'meta information in JSON format' - """ - meta = self.serializer.deserialize(params.meta) if params.meta else {} - - NetworkGroup.create( - params.name, - params.release, - params.vlan, - params.cidr, - params.gateway, - int(params.nodegroup.pop()), - meta - ) - self.serializer.print_to_output( - {}, - "Network group {0} has been created".format(params.name) - ) - - @check_all('network') - def delete(self, params): - """Delete the specified network groups - fuel network-group --delete --network 1 - fuel network-group --delete --network 2,3,4 - """ - ngs = NetworkGroup.get_by_ids(params.network) - for network_group in ngs: - network_group.delete() - - self.serializer.print_to_output( - {}, - "Network groups with IDS {0} have been deleted.".format( - ','.join(params.network)) - ) - - @check_all('network') - def set(self, params): - """Set parameters for the specified network group: - fuel network-group --set --network 1 --name new_name - """ - # Since network has set type and we cannot update multiple network - # groups at once, we pick first network group id from set. - ng_id = next(iter(params.network)) - - if len(params.network) > 1: - msg = ("Warning: Only first network with id={0}" - " will be updated.".format(ng_id)) - six.print_(msg, file=sys.stderr) - - ng = NetworkGroup(ng_id) - - update_params = get_args_for_update(params, self.serializer) - data = ng.set(update_params) - - self.serializer.print_to_output( - data, - "Network group id={0} has been updated".format(ng_id)) - - def list(self, params): - """To list all available network groups: - fuel network-group list - - To filter them by node group: - fuel network-group --node-group 1 - """ - group_collection = NetworkGroupCollection.get_all() - if params.nodegroup: - group_collection.filter_by_group_id(int(params.nodegroup.pop())) - self.serializer.print_to_output( - group_collection.data, - format_table( - group_collection.data, - acceptable_keys=self.acceptable_keys, - ) - ) diff --git a/fuelclient/cli/actions/node.py b/fuelclient/cli/actions/node.py deleted file mode 100644 index c3dd0b7..0000000 --- a/fuelclient/cli/actions/node.py +++ /dev/null @@ -1,418 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 itertools import groupby -from operator import attrgetter - -from fuelclient.cli.actions.base import Action -from fuelclient.cli.actions.base import check_all -from fuelclient.cli.actions.base import check_any -import fuelclient.cli.arguments as Args -from fuelclient.cli.arguments import group -from fuelclient.cli import error -from fuelclient.cli.formatting import format_table -from fuelclient.objects.environment import Environment -from fuelclient.objects.node import Node -from fuelclient.objects.node import NodeCollection - - -class NodeAction(Action): - """List and assign available nodes to environments - """ - action_name = "node" - acceptable_keys = ("id", "status", "name", "cluster", "ip", - "mac", "roles", "pending_roles", "online", "group_id") - - def __init__(self): - super(NodeAction, self).__init__() - self.args = [ - Args.get_env_arg(), - group( - Args.get_list_arg("List all nodes."), - Args.get_set_arg("Set role for specific node."), - Args.get_delete_arg("Delete specific node from environment."), - Args.get_attributes_arg("Node attributes."), - Args.get_network_arg("Node network configuration."), - Args.get_disk_arg("Node disk configuration."), - Args.get_deploy_arg("Deploy specific nodes."), - Args.get_hostname_arg("Set node hostname."), - Args.get_node_name_arg("Set node name."), - Args.get_delete_from_db_arg( - "Delete specific nodes only from fuel db.\n" - "User should still delete node from cobbler"), - Args.get_provision_arg("Provision specific nodes."), - ), - group( - Args.get_default_arg( - "Get default configuration of some node"), - Args.get_download_arg( - "Download configuration of specific node"), - Args.get_upload_arg( - "Upload configuration to specific node") - ), - Args.get_dir_arg( - "Select directory to which download node attributes"), - Args.get_node_arg("Node id."), - Args.get_force_arg("Bypassing parameter validation."), - Args.get_noop_run_deployment_arg(), - Args.get_all_arg("Select all nodes."), - Args.get_role_arg("Role to assign for node."), - group( - Args.get_skip_tasks(), - Args.get_tasks() - ), - Args.get_graph_endpoint(), - Args.get_graph_startpoint(), - ] - - self.flag_func_map = ( - ("set", self.set), - ("delete", self.delete), - ("network", self.attributes), - ("disk", self.attributes), - ("deploy", self.start), - ("provision", self.start), - ("hostname", self.set_hostname), - ("name", self.set_name), - ("delete-from-db", self.delete_from_db), - ("tasks", self.execute_tasks), - ("skip", self.execute_tasks), - ("end", self.execute_tasks), - ("start", self.execute_tasks), - ("attributes", self.node_attributes), - (None, self.list) - ) - - @check_all("node", "role", "env") - def set(self, params): - """Assign some nodes to environment with with specific roles: - fuel --env 1 node set --node 1 --role controller - fuel --env 1 node set --node 2,3,4 --role compute,cinder - """ - env = Environment(params.env) - nodes = Node.get_by_ids(params.node) - roles = map(str.lower, params.role) - env.assign(nodes, roles) - self.serializer.print_to_output( - {}, - "Nodes {0} with roles {1} " - "were added to environment {2}" - .format(params.node, roles, params.env) - ) - - @check_any("node", "env") - def delete(self, params): - """Remove some nodes from environment: - fuel --env 1 node remove --node 2,3 - - Remove nodes no matter to which environment they were assigned: - fuel node remove --node 2,3,6,7 - - Remove all nodes from some environment: - fuel --env 1 node remove --all - """ - if params.env: - env = Environment(params.env) - if params.node: - env.unassign(params.node) - self.serializer.print_to_output( - {}, - "Nodes with ids {0} were removed " - "from environment with id {1}." - .format(params.node, params.env)) - else: - if params.all: - env.unassign_all() - else: - raise error.ArgumentException( - "You have to select which nodes to remove " - "with --node-id. Try --all for removing all nodes." - ) - self.serializer.print_to_output( - {}, - "All nodes from environment with id {0} were removed." - .format(params.env)) - else: - nodes = map(Node, params.node) - for env_id, _nodes in groupby(nodes, attrgetter("env_id")): - list_of_nodes = [n.id for n in _nodes] - if env_id: - Environment(env_id).unassign(list_of_nodes) - self.serializer.print_to_output( - {}, - "Nodes with ids {0} were removed " - "from environment with id {1}." - .format(list_of_nodes, env_id) - ) - else: - self.serializer.print_to_output( - {}, - "Nodes with ids {0} aren't added to " - "any environment.".format(list_of_nodes) - ) - - @check_all("node") - @check_any("default", "download", "upload") - def attributes(self, params): - """Download current or default disk, network, - configuration for some node: - fuel node --node-id 2 --disk --default - fuel node --node-id 2 --network --download \\ - --dir path/to/directory - - Upload disk, network, configuration for some node: - fuel node --node-id 2 --network --upload - fuel node --node-id 2 --disk --upload --dir path/to/directory - """ - nodes = Node.get_by_ids(params.node) - attribute_type = "interfaces" if params.network else "disks" - attributes = [] - files = [] - if params.default: - for node in nodes: - default_attribute = node.get_default_attribute(attribute_type) - file_path = node.write_attribute( - attribute_type, - default_attribute, - params.dir, - serializer=self.serializer - ) - files.append(file_path) - attributes.append(default_attribute) - message = "Default node attributes for {0} were written" \ - " to:\n{1}".format(attribute_type, "\n".join(files)) - elif params.upload: - for node in nodes: - attribute = node.read_attribute( - attribute_type, - params.dir, - serializer=self.serializer - ) - node.upload_node_attribute( - attribute_type, - attribute - ) - attributes.append(attribute) - message = "Node attributes for {0} were uploaded" \ - " from {1}".format(attribute_type, params.dir) - else: - for node in nodes: - downloaded_attribute = node.get_attribute(attribute_type) - file_path = node.write_attribute( - attribute_type, - downloaded_attribute, - params.dir, - serializer=self.serializer - ) - attributes.append(downloaded_attribute) - files.append(file_path) - message = "Node attributes for {0} were written" \ - " to:\n{1}".format(attribute_type, "\n".join(files)) - print(message) - - def get_env_id(self, node_collection): - env_ids = set(n.env_id for n in node_collection) - if len(env_ids) != 1: - raise error.ActionException( - "Inputed nodes assigned to multiple environments!") - else: - return env_ids.pop() - - @check_all("node") - def start(self, params): - """Deploy/Provision some node: - fuel node --node-id 2 --provision - fuel node --node-id 2 --deploy - """ - node_collection = NodeCollection.init_with_ids(params.node) - method_type = "deploy" if params.deploy else "provision" - env_id_to_start = self.get_env_id(node_collection) - - if not env_id_to_start: - raise error.ActionException( - "Input nodes are not assigned to any environment!") - - task = Environment(env_id_to_start).install_selected_nodes( - method_type, node_collection.collection) - - self.serializer.print_to_output( - task.data, - "Started {0}ing {1}." - .format(method_type, node_collection)) - - @check_all("node") - def execute_tasks(self, params): - """Execute deployment tasks - fuel node --node 2 --tasks hiera netconfig - fuel node --node 2 --tasks netconfig --force - fuel node --node 2 --skip hiera netconfig - fuel node --node 2 --skip rsync --end pre_deployment_end - fuel node --node 2 --end netconfig - fuel node --node 2 --start hiera --end neutron - fuel node --node 2 --start post_deployment_start - """ - node_collection = NodeCollection.init_with_ids(params.node) - env_id_to_start = self.get_env_id(node_collection) - - env = Environment(env_id_to_start) - - tasks = params.tasks or None - force = params.force or None - noop_run = params.noop_run or None - - if params.skip or params.end or params.start: - tasks = env.get_tasks( - skip=params.skip, - end=params.end, - start=params.start, - include=tasks) - - if not tasks: - self.serializer.print_to_output({}, "Nothing to run.") - return - - task = env.execute_tasks( - node_collection.collection, tasks=tasks, force=force, - noop_run=noop_run) - - self.serializer.print_to_output( - task.data, - "Started tasks {0} for nodes {1}.".format(tasks, node_collection)) - - def list(self, params): - """To list all available nodes: - fuel node - - To filter them by environment: - fuel --env-id 1 node - - It's Possible to manipulate nodes with their short mac addresses: - fuel node --node-id 80:ac - fuel node remove --node-id 80:ac,5d:a2 - """ - if params.node: - node_collection = NodeCollection.init_with_ids(params.node) - else: - node_collection = NodeCollection.get_all() - if params.env: - node_collection.filter_by_env_id(int(params.env)) - self.serializer.print_to_output( - node_collection.data, - format_table( - node_collection.data, - acceptable_keys=self.acceptable_keys, - column_to_join=("roles", "pending_roles") - ) - ) - - @check_all("node") - def delete_from_db(self, params): - """To delete nodes from fuel db: - fuel node --node-id 1 --delete-from-db - fuel node --node-id 1 2 --delete-from-db - (this works only for offline nodes) - fuel node --node-id 1 --delete-from-db --force - (this forces deletion of nodes regardless of their state) - """ - if not params.force: - node_collection = NodeCollection.init_with_ids(params.node) - - online_nodes = [node for node in node_collection.data - if node['online']] - - if online_nodes: - raise error.ActionException( - "Nodes with ids {0} cannot be deleted from cluster " - "because they are online. You might want to use the " - "--force option.".format( - [node['id'] for node in online_nodes])) - - NodeCollection.delete_by_ids(params.node) - - self.serializer.print_to_output( - {}, - "Nodes with ids {0} have been deleted from Fuel db.".format( - params.node) - ) - - @staticmethod - def _get_one_node(params): - """Ensures that only one node was passed in the command and returns it. - - :raises ArgumentException: When more than 1 node provided. - """ - if len(params.node) > 1: - raise error.ArgumentException( - "You should select only one node to change.") - - return Node(params.node[0]) - - @check_all("node", "name") - def set_name(self, params): - """To set node name: - fuel node --node-id 1 --name NewName - """ - node = self._get_one_node(params) - node.set({"name": params.name}) - self.serializer.print_to_output( - {}, - u"Name for node with id {0} has been changed to {1}." - .format(node.id, params.name) - ) - - @check_all("node", "hostname") - def set_hostname(self, params): - """To set node hostname: - fuel node --node-id 1 --hostname ctrl-01 - """ - node = self._get_one_node(params) - node.set({"hostname": params.hostname}) - self.serializer.print_to_output( - {}, - "Hostname for node with id {0} has been changed to {1}." - .format(node.id, params.hostname) - ) - - @check_all("node") - @check_any("upload", "download") - def node_attributes(self, params): - """Download node attributes for specified node: - fuel node --node-id 1 --attributes --download [--dir download-dir] - - Upload node attributes for specified node - fuel node --node-id 1 --attributes --upload [--dir upload-dir] - - """ - node = self._get_one_node(params) - if params.upload: - data = node.read_attribute( - 'attributes', params.dir, serializer=self.serializer) - node.update_node_attributes(data) - self.serializer.print_to_output( - {}, - "Attributes for node {0} were uploaded." - .format(node.id)) - elif params.download: - attributes = node.get_node_attributes() - file_path = node.write_attribute( - 'attributes', attributes, - params.dir, serializer=self.serializer) - self.serializer.print_to_output( - {}, - "Attributes for node {0} were written to {1}" - .format(node.id, file_path)) - - else: - raise error.ArgumentException( - "--upload or --download action should be specified.") diff --git a/fuelclient/cli/actions/nodegroup.py b/fuelclient/cli/actions/nodegroup.py deleted file mode 100644 index d30f6d4..0000000 --- a/fuelclient/cli/actions/nodegroup.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 sys - -import six - -from fuelclient.cli.actions.base import Action -from fuelclient.cli.actions.base import check_all -import fuelclient.cli.arguments as Args -from fuelclient.cli.arguments import group -from fuelclient.cli.error import ActionException -from fuelclient.cli.formatting import format_table -from fuelclient.objects import Environment -from fuelclient.objects.nodegroup import NodeGroup -from fuelclient.objects.nodegroup import NodeGroupCollection - - -class NodeGroupAction(Action): - """Show or modify node groups - """ - action_name = "nodegroup" - acceptable_keys = ("id", "cluster_id", "name") - - def __init__(self): - super(NodeGroupAction, self).__init__() - self.args = ( - Args.get_env_arg(), - Args.get_list_arg("List all node groups."), - Args.get_name_arg("Name of new node group."), - Args.get_group_arg("ID of node group."), - Args.get_node_arg("List of nodes to assign specified group to."), - group( - Args.get_create_arg( - "Create a new node group in the specified environment." - ), - Args.get_assign_arg( - "Assign nodes to the specified node group."), - Args.get_delete_arg( - "Delete specified node groups."), - ) - ) - self.flag_func_map = ( - ("create", self.create), - ("delete", self.delete), - ("assign", self.assign), - (None, self.list) - ) - - @check_all("env", "name") - def create(self, params): - """Create a new node group - fuel --env 1 nodegroup --create --name "group 1" - """ - env_id = int(params.env) - data = NodeGroup.create(params.name, env_id) - env = Environment(env_id) - network_data = env.get_network_data() - seg_type = network_data['networking_parameters'].get( - 'segmentation_type' - ) - if seg_type == 'vlan': - six.print_("WARNING: In VLAN segmentation type, there will be no " - "connectivity over private network between instances " - "running on hypervisors in different segments and that " - "it's a user's responsibility to handle this " - "situation.", - file=sys.stderr) - - self.serializer.print_to_output( - data, - u"Node group '{name}' with id={id} " - u"in environment {env} was created!" - .format(env=env_id, **data) - ) - - @check_all("group") - def delete(self, params): - """Delete the specified node groups - fuel nodegroup --delete --group 1 - fuel nodegroup --delete --group 2,3,4 - """ - ngs = NodeGroup.get_by_ids(params.group) - for n in ngs: - if n.name == "default": - raise ActionException( - "Default node groups cannot be deleted." - ) - data = NodeGroup.delete(n.id) - self.serializer.print_to_output( - data, - u"Node group with id={id} was deleted!" - .format(id=n.id) - ) - - @check_all("node", "group") - def assign(self, params): - """Assign nodes to specified node group: - fuel nodegroup --assign --node 1 --group 1 - fuel nodegroup --assign --node 2,3,4 --group 1 - """ - if len(params.group) > 1: - raise ActionException( - "Nodes can only be assigned to one node group." - ) - - group = NodeGroup(params.group.pop()) - group.assign(params.node) - - def list(self, params): - """To list all available node groups: - fuel nodegroup - - To filter them by environment: - fuel --env-id 1 nodegroup - """ - group_collection = NodeGroupCollection.get_all() - if params.env: - group_collection.filter_by_env_id(int(params.env)) - self.serializer.print_to_output( - group_collection.data, - format_table( - group_collection.data, - acceptable_keys=self.acceptable_keys, - ) - ) diff --git a/fuelclient/cli/actions/notifications.py b/fuelclient/cli/actions/notifications.py deleted file mode 100644 index 0acaee7..0000000 --- a/fuelclient/cli/actions/notifications.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli.actions.base import Action -import fuelclient.cli.arguments as Args -from fuelclient.cli.formatting import format_table -from fuelclient.objects.notifications import Notifications - - -class NotificationsAction(Action): - """List and create notifications - """ - action_name = "notifications" - - acceptable_keys = ( - "id", - "message", - "status", - "topic", - ) - - def __init__(self): - super(NotificationsAction, self).__init__() - self.args = [ - Args.group( - Args.get_list_arg("List all available notifications."), - Args.get_notify_send_arg("Send notification"), - Args.get_notify_mark_as_read_arg( - "Mark notification(s) as read ('*' to mark all as read)."), - ), - Args.group( - Args.get_notify_topic_arg("Notification topic (severity)"), - ), - Args.get_notify_all_messages_arg( - "Select all messages (only unread by default)."), - ] - self.flag_func_map = ( - ("send", self.send), - ("mark-as-read", self.mark_as_read), - (None, self.list), - ) - - def list(self, params): - """Print all available notifications: - fuel notifications - fuel notifications --list - """ - notifications = Notifications.get_all_data() - - if not params.all: - notifications = [notification for notification in notifications - if notification['status'] == 'unread'] - - self.serializer.print_to_output( - notifications, - format_table( - notifications, - acceptable_keys=self.acceptable_keys - ) - ) - - def mark_as_read(self, params): - """Mark given notifications as read. - fuel notifications --mark-as-read 1 2 - fuel notifications -r 1 2 - """ - result = Notifications.mark_as_read( - ids=getattr(params, 'mark-as-read')) - - self.serializer.print_to_output( - result, - 'Notification(s) marked as read' - ) - - def send(self, params): - """Send notification: - fuel notifications --send "message" --topic done - """ - message = params.send - if isinstance(message, list): - message = ' '.join(message) - result = Notifications.send(message, topic=params.topic) - self.serializer.print_to_output( - result, - "Notification sent") - - -class NotifyAction(NotificationsAction): - """Shortcut for quickly sending a notification. - """ - - action_name = "notify" - - def __init__(self): - super(NotifyAction, self).__init__() - self.args = [ - Args.get_notify_message_arg("Notification message"), - Args.get_notify_topic_arg("Notification topic (severity)"), - ] - self.flag_func_map = ( - (None, self.send), - ) diff --git a/fuelclient/cli/actions/openstack_config.py b/fuelclient/cli/actions/openstack_config.py deleted file mode 100644 index ab85a87..0000000 --- a/fuelclient/cli/actions/openstack_config.py +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli.actions.base import Action -from fuelclient.cli.actions.base import check_all -import fuelclient.cli.arguments as Args -from fuelclient.cli.arguments import group -from fuelclient.cli.formatting import format_table -from fuelclient.objects.openstack_config import OpenstackConfig - - -class OpenstackConfigAction(Action): - """Manage openstack configuration""" - - action_name = 'openstack-config' - acceptable_keys = ('id', 'is_active', 'config_type', - 'cluster_id', 'node_id', 'node_role') - - def __init__(self): - super(OpenstackConfigAction, self).__init__() - self.args = ( - Args.get_env_arg(), - Args.get_file_arg("Openstack configuration file"), - Args.get_node_arg("Node IDs list"), - Args.get_single_role_arg("Node role"), - Args.get_config_id_arg("Openstack config ID"), - Args.get_deleted_arg("Get deleted configurations"), - Args.get_force_arg("Force configuration update"), - group( - Args.get_list_arg("List openstack configurations"), - Args.get_download_arg( - "Download current openstack configuration"), - Args.get_upload_arg("Upload new openstack configuration"), - Args.get_delete_arg("Delete openstack configuration"), - Args.get_execute_arg("Apply openstack configuration"), - required=True, - ) - ) - - self.flag_func_map = ( - ('list', self.list), - ('download', self.download), - ('upload', self.upload), - ('delete', self.delete), - ('execute', self.execute) - ) - - @check_all('env') - def list(self, params): - """List all available configurations: - fuel openstack-config --list --env 1 - fuel openstack-config --list --env 1 --node 1[,2,3,...] - fuel openstack-config --list --env 1 --deleted - """ - filters = {'cluster_id': params.env} - - if 'deleted' in params: - filters['is_active'] = int(not params.deleted) - - if 'node' in params: - filters['node_ids'] = params.node - - if 'role' in params: - filters['node_role'] = params.role - - configs = OpenstackConfig.get_filtered_data(**filters) - - self.serializer.print_to_output( - configs, - format_table( - configs, - acceptable_keys=self.acceptable_keys - ) - ) - - @check_all('config-id', 'file') - def download(self, params): - """Download an existing configuration to file: - fuel openstack-config --download --config-id 1 --file config.yaml - """ - config_id = getattr(params, 'config-id') - config = OpenstackConfig(config_id) - data = config.data - OpenstackConfig.write_file(params.file, { - 'configuration': data['configuration']}) - - @check_all('env', 'file') - def upload(self, params): - """Upload new configuration from file: - fuel openstack-config --upload --env 1 --file config.yaml - fuel openstack-config --upload --env 1 --node 1[,2,3,...] - --file config.yaml - fuel openstack-config --upload --env 1 - --role controller --file config.yaml - """ - node_ids = getattr(params, 'node', None) - node_role = getattr(params, 'role', None) - data = OpenstackConfig.read_file(params.file) - - configs = OpenstackConfig.create( - cluster_id=params.env, - configuration=data['configuration'], - node_ids=node_ids, node_role=node_role) - configs = [c.data for c in configs] - self.serializer.print_to_output( - configs, - format_table( - configs, - acceptable_keys=self.acceptable_keys - ) - ) - - @check_all('config-id') - def delete(self, params): - """Delete an existing configuration: - fuel openstack-config --delete --config 1 - """ - config_id = getattr(params, 'config-id') - config = OpenstackConfig(config_id) - config.delete() - print("Openstack configuration '{0}' " - "has been deleted.".format(config_id)) - - @check_all('env') - def execute(self, params): - """Deploy configuration: - fuel openstack-config --execute --env 1 - fuel openstack-config --execute --env 1 --node 1[,2,3,...] - fuel openstack-config --execute --env 1 --role controller - fuel openstack-config --execute --env 1 --force - """ - node_ids = getattr(params, 'node', None) - node_role = getattr(params, 'role', None) - force = getattr(params, 'force', False) - task_result = OpenstackConfig.execute( - cluster_id=params.env, node_ids=node_ids, - node_role=node_role, force=force) - if task_result['status'] == 'error': - print( - 'Error applying openstack configuration: {0}.'.format( - task_result['message']) - ) - else: - print('Openstack configuration update is started.') diff --git a/fuelclient/cli/actions/plugins.py b/fuelclient/cli/actions/plugins.py deleted file mode 100644 index ab9620e..0000000 --- a/fuelclient/cli/actions/plugins.py +++ /dev/null @@ -1,209 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 collections -import six - -import fuelclient.cli.arguments as Args - -from fuelclient.cli.actions.base import Action -from fuelclient.cli import error -from fuelclient.cli.formatting import format_table -from fuelclient.objects.plugins import Plugins -from fuelclient import utils - - -class PluginAction(Action): - """List and modify currently available releases - """ - action_name = "plugins" - - acceptable_keys = ( - "id", - "name", - "version", - "package_version", - "releases" - ) - - def __init__(self): - super(PluginAction, self).__init__() - self.args = [ - Args.group( - Args.get_list_arg( - "List of all registered plugins."), - Args.get_plugin_install_arg( - "Install and register plugin package"), - Args.get_plugin_remove_arg( - "Remove and unregister plugin"), - Args.get_plugin_register_arg( - "Register installed plugin"), - Args.get_plugin_unregister_arg( - "Unregister plugin"), - Args.get_plugin_update_arg( - "Update installed plugin"), - Args.get_plugin_downgrade_arg( - "Downgrade installed plugin"), - Args.get_plugin_sync_arg( - "Synchronise plugins with API service")), - Args.get_plugin_arg("Plugin id."), - Args.get_force_arg("Force action") - ] - self.flag_func_map = ( - ("install", self.install), - ("remove", self.remove), - ("update", self.update), - ("downgrade", self.downgrade), - ("sync", self.sync), - ("register", self.register), - ("unregister", self.unregister), - (None, self.list), - ) - - def list(self, params): - """Print all available plugins - - fuel plugins - fuel plugins --list - """ - plugins = Plugins.get_all_data() - # Replace original nested 'release' dictionary (from plugins meta - # dictionary) to flat one with necessary release info (os, version) - for plugin in plugins: - releases = collections.defaultdict(list) - for key in plugin['releases']: - releases[key['os']].append(key['version']) - plugin['releases'] = ', '.join('{} ({})'.format(k, ', '.join(v)) - for k, v in six.iteritems(releases)) - self.serializer.print_to_output( - plugins, - format_table(plugins, acceptable_keys=self.acceptable_keys)) - - def install(self, params): - """Install plugin archive and register in API service - - fuel plugins --install plugin-name-2.0-2.0.1-0.noarch.rpm - """ - file_path = params.install - self.check_file(file_path) - results = Plugins.install(file_path, force=params.force) - self.serializer.print_to_output( - results, - "Plugin {0} was successfully installed.".format( - params.install)) - - def remove(self, params): - """Remove plugin from file system and from API service - - fuel plugins --remove plugin-name==1.0.1 - """ - name, version = self.parse_name_version(params.remove) - results = Plugins.remove(name, version) - - self.serializer.print_to_output( - results, - "Plugin {0} was successfully removed.".format(params.remove)) - - def update(self, params): - """Update plugin from one minor version to another. - For example if there is a plugin with version 2.0.0, - plugin with version 2.0.1 can be used as update. But - plugin with version 2.1.0, cannot be used to update - plugin. Note that update is supported for plugins - beginning from package_version 2.0.0 - - fuel plugins --update plugin-name-2.0-2.0.1-0.noarch.rpm - """ - plugin_path = params.update - self.check_file(plugin_path) - result = Plugins.update(plugin_path) - self.serializer.print_to_output( - result, - "Plugin {0} was successfully updated.".format(plugin_path)) - - def downgrade(self, params): - """Downgrade plugin from one minor version to another. - For example if there is a plugin with version 2.0.1, - plugin with version 2.0.0 can be used to perform downgrade. - Plugin with version 1.0.0, cannot be used to perform downgrade - plugin. Note that downgrade is supported for plugins - beginning from package_version 2.0.0 - - fuel plugins --downgrade plugin-name-2.0-2.0.1-0.noarch.rpm - """ - plugin_path = params.downgrade - self.check_file(plugin_path) - result = Plugins.downgrade(plugin_path) - self.serializer.print_to_output( - result, - "Plugin {0} was successfully downgraded.".format(plugin_path)) - - def sync(self, params): - """Synchronise plugins on file system with plugins in - API service, creates plugin if it is not exists, - updates existent plugins - - fuel plugins --sync - fuel plugins --sync --plugin-id=1,2 - """ - Plugins.sync(plugin_ids=params.plugin) - self.serializer.print_to_output( - None, "Plugins were successfully synchronized.") - - def register(self, params): - """Register plugin in API service - - fuel plugins --register plugin-name==1.0.1 - """ - name, version = self.parse_name_version(params.register) - result = Plugins.register(name, version, force=params.force) - self.serializer.print_to_output( - result, - "Plugin {0} was successfully registered.".format(params.register)) - - def unregister(self, params): - """Deletes plugin from API service - - fuel plugins --unregister plugin-name==1.0.1 - """ - name, version = self.parse_name_version(params.unregister) - result = Plugins.unregister(name, version) - self.serializer.print_to_output( - result, - "Plugin {0} was successfully unregistered." - "".format(params.unregister)) - - def parse_name_version(self, param): - """Takes the string and returns name and version - - :param str param: string with name and version - :raises: error.ArgumentException if version is not specified - """ - attrs = param.split('==') - - if len(attrs) != 2: - raise error.ArgumentException( - 'Syntax: fuel plugins fuel_plugin==1.0.0') - - return attrs - - def check_file(self, file_path): - """Checks if file exists - - :param str file_path: path to the file - :raises: error.ArgumentException if file does not exist - """ - if not utils.file_exists(file_path): - raise error.ArgumentException( - 'File "{0}" does not exists'.format(file_path)) diff --git a/fuelclient/cli/actions/release.py b/fuelclient/cli/actions/release.py deleted file mode 100644 index f43ca10..0000000 --- a/fuelclient/cli/actions/release.py +++ /dev/null @@ -1,172 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 collections import defaultdict -import os - -from fuelclient.cli.actions.base import Action -from fuelclient.cli.actions.base import check_all -from fuelclient.cli.actions.base import check_any -import fuelclient.cli.arguments as Args -from fuelclient.cli.arguments import group -from fuelclient.cli.formatting import format_table -from fuelclient.objects.release import Release -from fuelclient import utils - - -class ReleaseAction(Action): - """List and modify currently available releases - """ - action_name = "release" - - def __init__(self): - super(ReleaseAction, self).__init__() - self.args = [ - Args.get_release_arg('Specify particular release id'), - Args.get_list_arg("List all available releases."), - Args.get_network_arg("Release network configuration."), - Args.get_deployment_tasks_arg("Release tasks configuration."), - Args.get_sync_deployment_tasks_arg(), - Args.get_file_pattern_arg(), - Args.get_dir_arg( - "Select directory to which download release attributes"), - group( - Args.get_download_arg( - "Download configuration of specific release"), - Args.get_upload_arg( - "Upload configuration to specific release") - ) - ] - self.flag_func_map = ( - ('sync-deployment-tasks', self.sync_deployment_tasks), - ('deployment-tasks', self.deployment_tasks), - ('network', self.network), - (None, self.list), - ) - - def list(self, params): - """Print all available releases: - fuel release --list - - Print release with specific id=1: - fuel release --rel 1 - """ - acceptable_keys = ( - "id", - "name", - "state", - "operating_system", - "version" - ) - if params.release: - release = Release(params.release) - data = [release.get_fresh_data()] - else: - data = Release.get_all_data() - self.serializer.print_to_output( - data, - format_table( - data, - acceptable_keys=acceptable_keys - ) - ) - - @check_all("release") - @check_any("download", "upload") - def network(self, params): - """Modify release networks configuration. - fuel rel --rel 1 --network --download - fuel rel --rel 2 --network --upload - """ - release = Release(params.release) - dir_path = self.full_path_directory( - params.dir, 'release_{0}'.format(params.release)) - full_path = '{0}/networks'.format(dir_path) - if params.download: - networks = release.get_networks() - self.serializer.write_to_path(full_path, networks) - print("Networks for release {0} " - "downloaded into {1}.yaml".format(release.id, full_path)) - elif params.upload: - networks = self.serializer.read_from_file(full_path) - release.update_networks(networks) - print("Networks for release {0} uploaded from {1}.yaml".format( - release.id, full_path)) - - @check_all("release") - @check_any("download", "upload") - def deployment_tasks(self, params): - """Modify deployment_tasks for release. - fuel rel --rel 1 --deployment-tasks --download - fuel rel --rel 1 --deployment-tasks --upload - """ - release = Release(params.release) - dir_path = self.full_path_directory( - params.dir, 'release_{0}'.format(params.release)) - full_path = '{0}/deployment_tasks'.format(dir_path) - if params.download: - tasks = release.get_deployment_tasks() - self.serializer.write_to_path(full_path, tasks) - print("Deployment tasks for release {0} " - "downloaded into {1}.yaml.".format(release.id, full_path)) - elif params.upload: - tasks = self.serializer.read_from_file(full_path) - release.update_deployment_tasks(tasks) - print("Deployment tasks for release {0}" - " uploaded from {1}.yaml".format(release.id, dir_path)) - - @check_all("dir") - def sync_deployment_tasks(self, params): - """Upload tasks for different releases based on directories. - The string identifier for the release(s) to update is expected to be - found in the path (see `fuel release`), like: - - /etc/puppet// - /etc/puppet/liberty-9.0 - - fuel rel --sync-deployment-tasks --dir /etc/puppet/liberty-9.0/ - fuel rel --sync-deployment-tasks --fp '*tasks.yaml' - - In case no directory was provided: - - fuel rel --sync-deployment-tasks - - The current directory will be used - """ - all_rels = Release.get_all_data() - real_path = os.path.realpath(params.dir) - serialized_tasks = defaultdict(list) - versions = set([r['version'] for r in all_rels]) - - for file_name in utils.iterfiles(real_path, params.filepattern): - for version in versions: - if version in file_name: - serialized_tasks[version].extend( - self.serializer.read_from_full_path(file_name)) - - for rel in all_rels: - release = Release(rel['id']) - data = serialized_tasks.get(rel['version']) - if data: - release.update_deployment_tasks(data) - print("Deployment tasks synchronized for release" - " {0} of version {1}".format(rel['name'], - rel['version'])) - else: - print("No tasks were synchronized for release {0} " - "of version {1}.(Hint: nothing matched " - "{2}/{1}/{3})".format(rel['name'], - rel['version'], - real_path, - params.filepattern)) diff --git a/fuelclient/cli/actions/role.py b/fuelclient/cli/actions/role.py deleted file mode 100644 index a8fd644..0000000 --- a/fuelclient/cli/actions/role.py +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli.actions.base import Action -from fuelclient.cli.actions.base import check_all -from fuelclient.cli.actions.base import check_any -import fuelclient.cli.arguments as Args -from fuelclient.cli.arguments import group -from fuelclient.cli.formatting import format_table -from fuelclient.cli.serializers import FileFormatBasedSerializer -from fuelclient.objects.role import Role - - -class RoleAction(Action): - """List all roles for specific release or cluster - """ - action_name = "role" - - fields_mapper = ( - ('env', 'clusters'), - ('release', 'releases') - ) - - def __init__(self): - # NOTE(dshulyak) this serializers are really messed up - # it gets overwritten in several places - self.file_serializer = FileFormatBasedSerializer() - self.args = [ - Args.get_list_arg("List all roles"), - group( - Args.get_env_arg(), - Args.get_release_arg("Release id"), - required=True - ), - Args.get_str_arg("role", help="Name of the role"), - Args.get_file_arg("File with role description"), - - group( - Args.get_create_arg("Create role from file"), - Args.get_boolean_arg("update", help="Update role from file"), - Args.get_delete_arg("Delete role from fuel") - ) - ] - self.flag_func_map = ( - ("delete", self.delete), - ("create", self.create), - ("update", self.update), - ("role", self.item), - (None, self.list), - ) - - def parse_model(self, args): - for param, role_class in self.fields_mapper: - model_id = getattr(args, param) - if model_id: - return role_class, model_id - - @check_any('release', 'env') - def list(self, params): - """Print all available roles for release or cluster - - fuel role --rel 1 - fuel role --env 1 - """ - model, model_id = self.parse_model(params) - roles = Role(owner_type=model, owner_id=model_id).get_all() - - acceptable_keys = ("name", ) - - self.serializer.print_to_output( - roles, - format_table( - roles, - acceptable_keys=acceptable_keys - ) - ) - - @check_all('role', 'file') - @check_any('release', 'env') - def item(self, params): - """Save full role description to file - fuel role --rel 1 --role controller --file some.yaml - fuel role --env 1 --role controller --file some.yaml - """ - model, model_id = self.parse_model(params) - role = Role(owner_type=model, owner_id=model_id).get_role(params.role) - self.file_serializer.write_to_file(params.file, role) - self.file_serializer.print_to_output( - role, - "Role {0} for {1} successfully saved to {2}.".format( - params.role, - model, - params.file)) - - @check_all('file') - @check_any('release', 'env') - def create(self, params): - """Create a role from file description - fuel role --rel 1 --create --file some.yaml - fuel role --env 1 --create --file some.yaml - """ - model, model_id = self.parse_model(params) - role = self.file_serializer.read_from_file(params.file) - role = Role(owner_type=model, owner_id=model_id).create_role(role) - self.file_serializer.print_to_output( - role, - "Role {0} for {1} successfully created from {2}.".format( - role['name'], model, params.file)) - - @check_all('file') - @check_any('release', 'env') - def update(self, params): - """Update a role from file description - fuel role --rel 1 --create --file some.yaml - fuel role --env 1 --create --file some.yaml - """ - model, model_id = self.parse_model(params) - role = self.file_serializer.read_from_file(params.file) - role = Role(owner_type=model, owner_id=model_id).update_role( - role['name'], - role) - self.file_serializer.print_to_output( - role, - "Role {0} for {1} successfully updated from {2}.".format( - params.role, - model, - params.file)) - - @check_all('role') - @check_any('release', 'env') - def delete(self, params): - """Delete role from fuel - fuel role --delete --role controller --rel 1 - fuel role --delete --role controller --env 1 - """ - model, model_id = self.parse_model(params) - Role(owner_type=model, owner_id=model_id).delete_role(params.role) - self.file_serializer.print_to_output( - {}, - "Role {0} for {1} with id {2} successfully deleted.".format( - params.role, - model, - model_id)) diff --git a/fuelclient/cli/actions/settings.py b/fuelclient/cli/actions/settings.py deleted file mode 100644 index 1422768..0000000 --- a/fuelclient/cli/actions/settings.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli.actions.base import Action -import fuelclient.cli.arguments as Args -from fuelclient.cli.arguments import group -from fuelclient.objects.environment import Environment - - -class SettingsAction(Action): - """Show or modify environment settings - """ - action_name = "settings" - - def __init__(self): - super(SettingsAction, self).__init__() - self.args = ( - Args.get_env_arg(required=True), - group( - Args.get_download_arg("Modify current configuration."), - Args.get_default_arg("Open default configuration."), - Args.get_upload_arg("Save current changes in configuration."), - required=True - ), - Args.get_dir_arg("Directory with configuration data."), - Args.get_force_arg("Force settings upload.") - ) - self.flag_func_map = ( - ("upload", self.upload), - ("default", self.default), - ("download", self.download) - ) - - def upload(self, params): - """To upload settings for some environment from some directory: - fuel --env 1 settings --upload --dir path/to/directory - """ - env = Environment(params.env) - settings_data = env.read_settings_data( - directory=params.dir, - serializer=self.serializer - ) - env.set_settings_data(settings_data, params.force) - print("Settings configuration uploaded.") - - def default(self, params): - """To download default settings for some environment in some directory: - fuel --env 1 settings --default --dir path/to/directory - """ - env = Environment(params.env) - default_data = env.get_default_settings_data() - settings_file_path = env.write_settings_data( - default_data, - directory=params.dir, - serializer=self.serializer) - print( - "Default settings configuration downloaded to {0}." - .format(settings_file_path) - ) - - def download(self, params): - """To download settings for some environment in this directory: - fuel --env 1 settings --download - """ - env = Environment(params.env) - settings_data = env.get_settings_data() - settings_file_path = env.write_settings_data( - settings_data, - directory=params.dir, - serializer=self.serializer) - print( - "Settings configuration for environment with id={0}" - " downloaded to {1}" - .format(env.id, settings_file_path) - ) diff --git a/fuelclient/cli/actions/snapshot.py b/fuelclient/cli/actions/snapshot.py deleted file mode 100644 index 68eda19..0000000 --- a/fuelclient/cli/actions/snapshot.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 sys - -import six -import yaml - -from fuelclient.cli.actions.base import Action -import fuelclient.cli.arguments as Args -from fuelclient.objects.task import SnapshotTask - - -class SnapshotAction(Action): - """Generate and download snapshot. - """ - action_name = "snapshot" - - def __init__(self): - super(SnapshotAction, self).__init__() - self.args = ( - Args.get_boolean_arg("conf", - help_="Provide this flag to generate conf"), - ) - self.flag_func_map = ( - ('conf', self.get_snapshot_config), - (None, self.create_snapshot), - ) - - def create_snapshot(self, params): - """To create diagnostic snapshot: - fuel snapshot - - To specify config for snapshotting: - fuel snapshot < conf.yaml - - """ - if sys.stdin.isatty(): - conf = {} - else: - conf = yaml.load(sys.stdin.read()) - - snapshot_task = SnapshotTask.start_snapshot_task(conf) - self.serializer.print_to_output( - snapshot_task.data, - "Generating diagnostic snapshot..." - ) - snapshot_task.wait() - - if snapshot_task.status == 'ready': - self.serializer.print_to_output( - snapshot_task.data, - "...Completed...\n" - "Diagnostic snapshot can be downloaded from " + - snapshot_task.connection.root + - snapshot_task.data["message"] - ) - elif snapshot_task.status == 'error': - six.print_( - "Snapshot generating task ended with error. Task message: {0}" - .format(snapshot_task.data["message"]), - file=sys.stderr - ) - - def get_snapshot_config(self, params): - """Download default config for snapshot: - fuel snapshot --conf > dump_conf.yaml - - To use json formatter: - fuel snapshot --conf --json - """ - conf = SnapshotTask.get_default_config() - self.serializer.write_to_file(sys.stdout, conf) diff --git a/fuelclient/cli/actions/token.py b/fuelclient/cli/actions/token.py deleted file mode 100644 index 22b9e96..0000000 --- a/fuelclient/cli/actions/token.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 sys - -from fuelclient.cli.actions.base import Action -from fuelclient.client import DefaultAPIClient - - -class TokenAction(Action): - """Return a valid keystone auth token - """ - action_name = "token" - - def __init__(self): - super(TokenAction, self).__init__() - - self.args = [] - self.flag_func_map = ( - (None, self.get_token), - ) - - def get_token(self, params): - """Print out a valid Keystone auth token - """ - sys.stdout.write(DefaultAPIClient.auth_token) diff --git a/fuelclient/cli/actions/user.py b/fuelclient/cli/actions/user.py deleted file mode 100644 index 79eae26..0000000 --- a/fuelclient/cli/actions/user.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 getpass import getpass - -from fuelclient.cli.actions.base import Action -import fuelclient.cli.arguments as Args -from fuelclient.cli.error import ArgumentException -from fuelclient.client import DefaultAPIClient -from fuelclient import fuelclient_settings - - -class UserAction(Action): - """Change password for user - """ - action_name = "user" - - def __init__(self): - super(UserAction, self).__init__() - self.args = ( - Args.get_new_password_arg( - "WARNING: This method of changing the " - "password is dangerous - it may be saved in bash history."), - Args.get_change_password_arg( - "Change user password using interactive prompt") - ) - - self.flag_func_map = ( - ("change-password", self.change_password), - ) - - def _get_password_from_prompt(self): - password1 = getpass("Changing password for Fuel User.\nNew Password:") - password2 = getpass("Retype new Password:") - if password1 != password2: - raise ArgumentException("Passwords are not the same.") - return password1 - - def change_password(self, params): - """To change user password: - fuel user change-password - """ - if params.newpass: - password = params.newpass - else: - password = self._get_password_from_prompt() - - DefaultAPIClient.update_own_password(password) - settings = fuelclient_settings.get_settings() - self.serializer.print_to_output( - None, "\nPassword changed.\nPlease note that configuration " - "is not automatically updated.\nYou may want to update " - "{0}.".format( - settings.user_settings)) diff --git a/fuelclient/cli/actions/vip.py b/fuelclient/cli/actions/vip.py deleted file mode 100644 index bbd419a..0000000 --- a/fuelclient/cli/actions/vip.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli.actions.base import Action -import fuelclient.cli.arguments as Args -from fuelclient.cli import serializers -from fuelclient.objects.environment import Environment - - -class VIPAction(Action): - """Download or upload VIP settings of specific environments. - """ - action_name = "vip" - acceptable_keys = ("id", "upload", "download", "network", "network-role",) - - def __init__(self): - super(VIPAction, self).__init__() - # NOTE(aroma): 'serializer' attribute for action objects is - # overwritten while building parser object - # (fuelclient.cli.parser.Parser) - self.file_serializer = serializers.FileFormatBasedSerializer() - self.args = ( - Args.get_env_arg(required=True), - Args.get_create_arg("Create VIP"), - Args.get_upload_file_arg("Upload changed VIP configuration " - "from given file"), - Args.get_download_arg("Download VIP configuration"), - Args.get_file_arg("Target file with vip data."), - Args.get_ip_id_arg("IP address entity identifier"), - Args.get_ip_address_arg("IP address string"), - Args.get_network_id_arg("Network identifier"), - Args.get_network_role_arg("Network role string"), - Args.get_vip_name_arg("VIP name string"), - Args.get_vip_namespace_arg("VIP namespace string"), - ) - self.flag_func_map = ( - ("create", self.create), - ("upload", self.upload), - ("download", self.download) - ) - - def create(self, params): - """To create VIP for environment: - fuel --env 1 vip create --address 172.16.0.10 --network 1 \\ - --name public_vip --namespace haproxy - """ - env = Environment(params.env) - vip_kwargs = { - "ip_addr": getattr(params, 'ip-address'), - "network": getattr(params, 'network'), - "vip_name": getattr(params, 'vip-name'), - } - - vip_namespace = getattr(params, 'vip-namespace', None) - if vip_namespace is not None: - vip_kwargs['vip_namespace'] = vip_namespace - - env.create_vip(**vip_kwargs) - print("VIP has been created") - - def upload(self, params): - """To upload VIP configuration from some - file for some environment: - fuel --env 1 vip --upload vip.yaml - """ - env = Environment(params.env) - vips_data = env.read_vips_data_from_file( - file_path=params.upload, - serializer=self.file_serializer - ) - env.set_vips_data(vips_data) - print("VIP configuration uploaded.") - - def download(self, params): - """To download VIP configuration in this - file for some environment: - fuel --env 1 vip --download --file vip.yaml - where --file param is optional - """ - - env = Environment(params.env) - vips_data = env.get_vips_data( - ip_address_id=getattr(params, 'ip-address-id'), - network=getattr(params, 'network'), - network_role=getattr(params, 'network-role') - ) - vips_data_file_path = env.write_vips_data_to_file( - vips_data, - file_path=params.file, - serializer=self.serializer - ) - print( - "VIP configuration for environment with id={0}" - " downloaded to {1}".format(env.id, vips_data_file_path) - ) diff --git a/fuelclient/cli/arguments.py b/fuelclient/cli/arguments.py deleted file mode 100644 index e76e109..0000000 --- a/fuelclient/cli/arguments.py +++ /dev/null @@ -1,787 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 argparse -from itertools import chain -import os - -from fuelclient import __version__ -from fuelclient.cli.error import ArgumentException -from fuelclient.client import DefaultAPIClient - -substitutions = { - # replace from: to - "env": "environment", - "nodes": "node", - "statuses": "status", - "net": "network", - "rel": "release", - "list": "--list", - "set": "--set", - "delete": "--delete", - "download": "--download", - "upload": "--upload", - "default": "--default", - "create": "--create", - "remove": "--delete", - "config": "--config", - "--roles": "--role", - "help": "--help", - "change-password": "--change-password", - "hostname": "--hostname", -} - - -def group(*args, **kwargs): - required = kwargs.get("required", False) - return (required,) + args - - -class ArrayAction(argparse.Action): - """Custom argparse.Action subclass to store ids - - :returns: list of ids - """ - def __call__(self, parser, namespace, values, option_string=None): - list_ids = [int(value) for value in chain(*values)] - setattr(namespace, self.dest, list_ids) - - -class NodeAction(argparse.Action): - """Custom argparse.Action subclass to store node identity - - :returns: list of ids - """ - def __call__(self, parser, namespace, values, option_string=None): - if values: - node_identities = set(chain(*values)) - input_macs = set(n for n in node_identities if ":" in n) - only_ids = set() - for _id in (node_identities - input_macs): - try: - only_ids.add(int(_id)) - except ValueError: - raise ArgumentException( - "'{0}' is not valid node id.".format(_id)) - if input_macs: - nodes_mac_to_id_map = dict( - (n["mac"], n["id"]) - for n in DefaultAPIClient.get_request("nodes/") - ) - for short_mac in input_macs: - target_node = None - for mac in nodes_mac_to_id_map: - if mac.endswith(short_mac): - target_node = mac - break - if target_node: - only_ids.add(nodes_mac_to_id_map[target_node]) - else: - raise ArgumentException( - 'Node with mac endfix "{0}" was not found.' - .format(short_mac) - ) - node_ids = [int(node_id) for node_id in only_ids] - setattr(namespace, self.dest, node_ids) - - -class SetAction(argparse.Action): - """Custom argparse.Action subclass to store distinct values - - :returns: Set of arguments - """ - def __call__(self, _parser, namespace, values, option_string=None): - try: - getattr(namespace, self.dest).update(values) - except AttributeError: - setattr(namespace, self.dest, set(values)) - - -def get_debug_arg(): - return { - "args": ["--debug"], - "params": { - "dest": "debug", - "action": "store_true", - "help": "prints details of all HTTP request", - "default": False - } - } - - -def get_version_arg(): - return { - "args": ["-v", "--version"], - "params": { - "action": "version", - "version": __version__ - } - } - - -def get_arg(name, flags=None, aliases=None, help_=None, **kwargs): - name = name.replace("_", "-") - args = ["--" + name, ] - if flags is not None: - args.extend(flags) - if aliases is not None: - substitutions.update( - dict((alias, args[0]) for alias in aliases) - ) - all_args = { - "args": args, - "params": { - "dest": name, - "help": help_ or name - } - } - all_args["params"].update(kwargs) - return all_args - - -def get_boolean_arg(name, **kwargs): - kwargs.update({ - "action": "store_true", - "default": False - }) - return get_arg(name, **kwargs) - - -def get_env_arg(required=False): - return get_int_arg( - "env", - flags=("--env-id",), - help="environment id", - required=required - ) - - -def get_single_task_arg(required=False): - return get_int_arg( - "task", - flags=("--task-id", "--tid"), - help="task id", - required=required - ) - - -def get_new_password_arg(help_msg): - return get_str_arg( - "newpass", - flags=("--new-pass",), - help=help_msg, - required=False - ) - - -def get_str_arg(name, **kwargs): - default_kwargs = { - "action": "store", - "type": str, - "default": None - } - default_kwargs.update(kwargs) - return get_arg(name, **default_kwargs) - - -def get_int_arg(name, **kwargs): - default_kwargs = { - "action": "store", - "type": int, - "default": None - } - default_kwargs.update(kwargs) - return get_arg(name, **default_kwargs) - - -def get_array_arg(name, **kwargs): - default_kwargs = { - "action": ArrayAction, - "nargs": '+', - "type": lambda v: v.split(","), - "default": None - } - default_kwargs.update(kwargs) - return get_arg(name, **default_kwargs) - - -def get_set_type_arg(name, **kwargs): - default_kwargs = { - "type": lambda v: v.split(','), - "action": SetAction, - "default": None - } - default_kwargs.update(kwargs) - return get_arg(name, **default_kwargs) - - -def get_delete_from_db_arg(help_msg): - return get_boolean_arg("delete-from-db", help=help_msg) - - -def get_deployment_tasks_arg(help_msg): - return get_boolean_arg( - "deployment-tasks", help=help_msg) - - -def get_attributes_arg(help_msg): - return get_boolean_arg("attributes", help=help_msg) - - -def get_sync_deployment_tasks_arg(): - return get_boolean_arg( - "sync-deployment-tasks", - help="Update tasks for each release.") - - -def get_dry_run_deployment_arg(): - return get_boolean_arg( - "dry-run", - dest='dry_run', - help="Specifies to dry-run a deployment by configuring task executor" - "to dump the deployment graph to a dot file.") - - -def get_noop_run_deployment_arg(): - return get_boolean_arg( - "noop", - dest='noop_run', - help="Specifies noop-run deployment configuring tasks executor to run " - "puppet and shell tasks in noop mode and skip all other. " - "Stores noop-run result summary in nailgun database") - - -def get_file_pattern_arg(): - return get_str_arg( - "filepattern", - flags=("--fp", "--file-pattern"), - default="*tasks.yaml", - help="Provide unix file pattern to filter tasks with files.") - - -def get_node_name_arg(help_msg): - return get_str_arg("name", help=help_msg) - - -def get_hostname_arg(help_msg): - return get_str_arg("hostname", help=help_msg) - - -def get_network_arg(help_msg): - return get_boolean_arg("network", flags=("--net",), help=help_msg) - - -def get_force_arg(help_msg): - return get_boolean_arg("force", flags=("-f",), help=help_msg) - - -def get_disk_arg(help_msg): - return get_boolean_arg("disk", help=help_msg) - - -def get_deploy_arg(help_msg): - return get_boolean_arg("deploy", help=help_msg) - - -def get_provision_arg(help_msg): - return get_boolean_arg("provision", help=help_msg) - - -def get_role_arg(help_msg): - return get_set_type_arg("role", flags=("-r",), help=help_msg) - - -def get_single_role_arg(help_msg): - return get_str_arg("role", flags=('--role', ), help=help_msg) - - -def get_check_arg(help_msg): - return get_set_type_arg("check", help=help_msg) - - -def get_ostf_username_arg(): - return get_str_arg( - "ostf_username", - dest="ostf_username", - help="OSTF username", - required=False - ) - - -def get_ostf_password_arg(): - return get_str_arg( - "ostf_password", - dest="ostf_password", - help="OSTF password", - required=False - ) - - -def get_ostf_tenant_name_arg(): - return get_str_arg( - "ostf_tenant_name", - dest="ostf_tenant_name", - help="OSTF tenant name", - required=False - ) - - -def get_change_password_arg(help_msg): - return get_boolean_arg("change-password", help=help_msg) - - -def get_name_arg(help_msg): - return get_str_arg("name", flags=("--env-name",), help=help_msg) - - -def get_graph_endpoint(): - return get_arg( - 'end', - action="store", - default=None, - help="Specify endpoint for the graph traversal.", - metavar='TASK', - ) - - -def get_graph_startpoint(): - return get_arg( - 'start', - action="store", - default=None, - help="Specify start point for the graph traversal.", - metavar='TASK', - ) - - -def get_skip_tasks(): - return get_arg( - 'skip', - nargs='+', - default=[], - help="Get list of tasks to be skipped.", - metavar='TASK', - ) - - -def get_tasks(): - return get_arg( - 'tasks', - nargs='+', - default=[], - help="Get list of tasks to be executed.", - metavar='TASK', - ) - - -def get_parents_arg(): - return get_arg( - 'parents-for', - help="Get parent for given task", - metavar='TASK', - ) - - -def get_remove_type_arg(types): - return get_arg( - 'remove', - nargs='+', - default=[], - choices=types, - help="Select task types to remove from graph.", - ) - - -def get_nst_arg(help_msg): - return get_arg("nst", - flags=("--net-segment-type",), - action="store", - choices=("gre", "vlan", "tun"), - help_=help_msg, - default="vlan") - - -def get_all_arg(help_msg): - return get_boolean_arg("all", help=help_msg) - - -def get_create_arg(help_msg): - return get_boolean_arg( - "create", - flags=("-c", "--env-create"), - help=help_msg) - - -def get_download_arg(help_msg): - return get_boolean_arg("download", flags=("-d",), help=help_msg) - - -def get_list_arg(help_msg): - return get_boolean_arg("list", flags=("-l",), help=help_msg) - - -def get_dir_arg(help_msg): - return get_str_arg("dir", default=os.curdir, help=help_msg) - - -def get_file_arg(help_msg): - return get_str_arg("file", help=help_msg) - - -def get_verify_arg(help_msg): - return get_boolean_arg("verify", flags=("-v",), help=help_msg) - - -def get_upload_arg(help_msg): - return get_boolean_arg("upload", flags=("-u",), help=help_msg) - - -def get_default_arg(help_msg): - return get_boolean_arg("default", help=help_msg) - - -def get_set_arg(help_msg): - return get_boolean_arg("set", flags=("-s",), help=help_msg) - - -def get_delete_arg(help_msg): - return get_boolean_arg("delete", help=help_msg) - - -def get_execute_arg(help_msg): - return get_boolean_arg("execute", help=help_msg) - - -def get_assign_arg(help_msg): - return get_boolean_arg("assign", help=help_msg) - - -def get_group_arg(help_msg): - return get_set_type_arg("group", help=help_msg) - - -def get_node_group_arg(help_msg): - return get_set_type_arg("nodegroup", flags=("--node-group",), - help=help_msg) - - -def get_vlan_arg(help_msg): - return get_int_arg("vlan", help=help_msg) - - -def get_cidr_arg(help_msg): - return get_str_arg("cidr", help=help_msg) - - -def get_gateway_arg(help_msg): - return get_str_arg("gateway", help=help_msg) - - -def get_meta_arg(help_msg): - return get_str_arg("meta", help=help_msg) - - -def get_create_network_arg(help_msg): - return get_boolean_arg( - "create", - flags=("-c", "--create"), - help=help_msg) - - -def get_network_group_arg(help_msg): - return get_set_type_arg("network", help=help_msg) - - -def get_release_arg(help_msg, required=False): - return get_int_arg( - "release", - flags=("--rel",), - required=required, - help=help_msg) - - -def get_render_arg(help_msg): - return get_str_arg( - "render", - metavar='INPUT', - help=help_msg) - - -def get_tred_arg(help_msg): - return get_boolean_arg("tred", help=help_msg) - - -def get_node_arg(help_msg): - default_kwargs = { - "action": NodeAction, - "flags": ("--node-id",), - "nargs": '+', - "type": lambda v: v.split(","), - "default": None, - "help": help_msg - } - return get_arg("node", **default_kwargs) - - -def get_single_node_arg(help_msg): - return get_int_arg('node', flags=('--node-id',), help=help_msg) - - -def get_task_arg(help_msg): - return get_array_arg( - 'task', - flags=("--task-id", "--tid"), - help=help_msg - ) - - -def get_config_id_arg(help_msg): - return get_int_arg( - 'config-id', - help=help_msg) - - -def get_deleted_arg(help_msg): - return get_boolean_arg( - 'deleted', help=help_msg) - - -def get_plugin_install_arg(help_msg): - return get_str_arg( - "install", - metavar='PLUGIN_FILE', - help=help_msg - ) - - -def get_plugin_remove_arg(help_msg): - return get_str_arg( - "remove", - metavar='PLUGIN_NAME==VERSION', - help=help_msg - ) - - -def get_plugin_register_arg(help_msg): - return get_str_arg( - "register", - metavar='PLUGIN_NAME==VERSION', - help=help_msg - ) - - -def get_plugin_unregister_arg(help_msg): - return get_str_arg( - "unregister", - metavar='PLUGIN_NAME==VERSION', - help=help_msg - ) - - -def get_plugin_update_arg(help_msg): - return get_str_arg( - "update", - metavar='PLUGIN_FILE', - help=help_msg - ) - - -def get_plugin_downgrade_arg(help_msg): - return get_str_arg( - "downgrade", - metavar='PLUGIN_FILE', - help=help_msg - ) - - -def get_plugin_sync_arg(help_msg): - return get_boolean_arg( - "sync", - help=help_msg - ) - - -def get_plugin_arg(help_msg): - return get_array_arg( - 'plugin', - flags=('--plugin-id',), - help=help_msg - ) - - -def get_notify_all_messages_arg(help_msg): - return get_boolean_arg( - 'all', - flags=('-a',), - help=help_msg - ) - - -def get_notify_mark_as_read_arg(help_msg): - return get_str_arg( - "mark-as-read", - flags=('-r',), - nargs='+', - help=help_msg, - ) - - -def get_notify_message_arg(help_msg): - return get_str_arg( - "send", - nargs='+', - flags=('-m',), - help=help_msg, - ) - - -def get_notify_send_arg(help_msg): - return get_str_arg( - "send", - flags=("--send",), - help=help_msg - ) - - -def get_notify_topic_arg(help_msg): - return get_str_arg( - "topic", - flags=("--topic",), - choices=( - 'discover', - 'done', - 'error', - 'warning', - 'release' - ), - help=help_msg - ) - - -def get_vip_arg(help_msg): - return get_boolean_arg( - "vip", - flags=("--vip",), - help=help_msg - ) - - -def get_vip_name_arg(help_msg): - return get_str_arg( - "vip-name", - flags=("--name",), - help=help_msg - ) - - -def get_vip_namespace_arg(help_msg, required=False): - return get_str_arg( - "vip-namespace", - flags=("--namespace",), - required=required, - help=help_msg - ) - - -def get_ip_address_arg(help_msg): - return get_str_arg( - "ip-address", - flags=("--address", "--ip-addr"), - help=help_msg - ) - - -def get_ip_id_arg(help_msg): - return get_int_arg( - "ip-address-id", - flags=("--ip-address-id",), - help=help_msg - ) - - -def get_network_id_arg(help_msg): - return get_int_arg( - "network", - flags=("--network",), - help=help_msg - ) - - -def get_network_role_arg(help_msg): - return get_str_arg( - "network-role", - flags=("--network-role",), - help=help_msg - ) - - -def get_upload_file_arg(help_msg): - return get_str_arg( - "upload", - flags=("-u", "--upload",), - help=help_msg - ) - - -def get_status_arg(help_msg): - default_kwargs = { - "flags": ("--status",), - "default": None, - "help": help_msg - } - return get_arg("status", **default_kwargs) - - -def get_deployment_node_arg(help_msg): - default_kwargs = { - "flags": ("--node-id",), - "default": None, - "help": help_msg - } - return get_arg("node", **default_kwargs) - - -def get_tasks_names_arg(help_msg): - default_kwargs = { - "flags": ("-d", "--task-name",), - "default": None, - "help": help_msg - } - return get_arg("task-name", **default_kwargs) - - -def get_show_parameters_arg(help_msg): - default_kwargs = { - "flags": ("-p", "--show-parameters",), - "help": help_msg - } - return get_boolean_arg("show-parameters", **default_kwargs) - - -def get_include_summary_arg(help_msg): - default_kwargs = { - "flags": ("--include-summary",), - "help": help_msg - } - return get_boolean_arg("include-summary", **default_kwargs) - - -def get_not_split_facts_args(): - kwargs = { - "action": "store_false", - "default": True, - "dest": "split", - "help": "Do not split deployment info for node and cluster parts." - } - return get_arg('no-split', **kwargs) diff --git a/fuelclient/cli/error.py b/fuelclient/cli/error.py deleted file mode 100644 index f069b84..0000000 --- a/fuelclient/cli/error.py +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 functools import wraps -import json -import os -import sys - -from keystoneclient.exceptions import Unauthorized -import requests -import textwrap - - -def exit_with_error(message): - """exit_with_error - writes message to stderr and exits with exit code 1. - """ - sys.stderr.write("{}{}".format(message, os.linesep)) - exit(1) - - -class FuelClientException(Exception): - """Base Exception for Fuel-Client - - All child classes must be instantiated before raising. - """ - def __init__(self, *args, **kwargs): - super(FuelClientException, self).__init__(*args, **kwargs) - self.message = args[0] - - -class BadDataException(FuelClientException): - """Should be raised when user provides corrupted data.""" - - -class WrongEnvironmentError(FuelClientException): - """Raised when particular action is not supported on environment.""" - - -class ServerDataException(FuelClientException): - """ServerDataException - must be raised when - data returned from server cannot be processed by Fuel-Client methods. - """ - - -class DeployProgressError(FuelClientException): - """DeployProgressError - must be raised when - deployment process interrupted on server. - """ - - -class ArgumentException(FuelClientException): - """ArgumentException - must be raised when - incorrect arguments inputted through argparse or some function. - """ - - -class ActionException(FuelClientException): - """ActionException - must be raised when - though arguments inputted to action are correct but they contradict - to logic in action. - """ - - -class ParserException(FuelClientException): - """ParserException - must be raised when - some problem occurred in process of argument parsing, - in argparse extension or in Fuel-Client Parser submodule. - """ - - -class ProfilingError(FuelClientException): - """Indicates errors and other issues related to performance profiling.""" - - -class SettingsException(FuelClientException): - """Indicates errors or unexpected behaviour in processing settings.""" - - -class ExecutedErrorNonZeroExitCode(FuelClientException): - """Subshell command returned non-zero exit code.""" - - -class LabelEmptyKeyError(BadDataException): - """Should be raised when user provides labels with empty key.""" - - -class InvalidDirectoryException(FuelClientException): - pass - - -class InvalidFileException(FuelClientException): - pass - - -class HTTPError(FuelClientException): - pass - - -class EnvironmentException(Exception): - pass - - -def exceptions_decorator(func): - """Handles HTTP errors and expected exceptions that may occur - in methods of DefaultAPIClient class - """ - @wraps(func) - def wrapper(*args, **kwargs): - try: - return func(*args, **kwargs) - - # when server returns to us bad request check that - # and print meaningful reason - except HTTPError as exc: - exit_with_error(exc) - except requests.ConnectionError: - message = """ - Can't connect to Nailgun server! - Please check connection settings in your configuration file.""" - exit_with_error(textwrap.dedent(message).strip()) - except Unauthorized: - message = """ - Unauthorized: need authentication! - Please provide user and password via client - fuel --os-username=user --os-password=pass [action] - or modify your credentials in your configuration file.""" - exit_with_error(textwrap.dedent(message).strip()) - except FuelClientException as exc: - exit_with_error(exc.message) - - return wrapper - - -def get_error_body(error): - try: - error_body = json.loads(error.response.text)['message'] - except (ValueError, TypeError, KeyError): - error_body = error.response.text - - return error_body - - -def get_full_error_message(error): - return "{} ({})".format(error, get_error_body(error)) diff --git a/fuelclient/cli/formatting.py b/fuelclient/cli/formatting.py deleted file mode 100644 index 7788b97..0000000 --- a/fuelclient/cli/formatting.py +++ /dev/null @@ -1,161 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 itertools import chain -from operator import itemgetter -from time import sleep - -import six - - -def format_table(data, acceptable_keys=None, column_to_join=None): - """Format list of dicts to table in a string form - - :acceptable_keys list(str): list of keys for which to create table - also specifies their order - """ - - # prepare columns - if column_to_join is not None: - for data_dict in data: - for column_name in column_to_join: - data_dict[column_name] = u", ".join( - sorted(data_dict[column_name]) - ) - if acceptable_keys is not None: - rows = [tuple(value.get(key, "") for key in acceptable_keys) - for value in data] - header = tuple(acceptable_keys) - else: - rows = [tuple(x.values()) for x in data] - header = tuple(data[0].keys()) - number_of_columns = len(header) - - # split multi-lines cells if there is no automatic columns merge - if column_to_join: - def format_cell(cell): - return [cell or ""] - else: - def format_cell(cell): - return six.text_type(cell).split('\n') - rows = [ - [format_cell(cell) if cell is not None else [''] for cell in row] - for row in rows - ] - - # calculate columns widths - column_widths = dict( - zip( - range(number_of_columns), - (len(str(x)) for x in header) - ) - ) - for row in rows: - column_widths.update( - ( - index, - max( - column_widths[index], - max(len(six.text_type(line)) for line in cell) - ) - ) - for index, cell in enumerate(row) - ) - - # make output - hor_delimeter = u'-+-'.join(column_widths[column_index] * u'-' - for column_index in range(number_of_columns)) - - row_template = u' | '.join( - u"{{{0}:{1}}}".format(idx, width) - for idx, width in column_widths.items() - ) - - output_lines = [ - row_template.format(*header), - hor_delimeter - ] - - for row in rows: - max_cell_lines = max(len(cell) for cell in row) - for cell_line_no in range(max_cell_lines): - output_lines.append( - row_template.format( - *( - cell[cell_line_no] if len(cell) > cell_line_no else u"" - for cell in row - ) - ) - ) - return u'\n'.join(output_lines) - - -def quote_and_join(words): - """quote_and_join - performs listing of objects and returns string. - """ - words = list(words) - if len(words) > 1: - return '{0} and "{1}"'.format( - ", ".join( - ['"{0}"'.format(x) for x in words][:-1] - ), - words[-1] - ) - else: - return '"{0}"'.format(words[0]) - - -# TODO(vkulanov): remove when deprecate old cli -def print_health_check(env): - tests_states = [{"status": "not finished"}] - finished_tests = set() - test_counter, total_tests_count = 1, None - while not all(map( - lambda t: t["status"] == "finished", - tests_states - )): - tests_states = env.get_state_of_tests() - all_tests = list(chain(*map( - itemgetter("tests"), - filter( - env.is_in_running_test_sets, - tests_states - )))) - if total_tests_count is None: - total_tests_count = len(all_tests) - all_finished_tests = filter( - lambda t: "running" not in t["status"], - all_tests - ) - new_finished_tests = filter( - lambda t: t["name"] not in finished_tests, - all_finished_tests - ) - finished_tests.update( - map( - itemgetter("name"), - new_finished_tests - ) - ) - for test in new_finished_tests: - print( - u"[{0:2} of {1}] [{status}] '{name}' " - u"({taken:.4} s) {message}".format( - test_counter, - total_tests_count, - **test - ) - ) - test_counter += 1 - sleep(1) diff --git a/fuelclient/cli/parser.py b/fuelclient/cli/parser.py deleted file mode 100644 index 2e9cf79..0000000 --- a/fuelclient/cli/parser.py +++ /dev/null @@ -1,246 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 argparse -import sys - -from fuelclient.cli.actions import actions -from fuelclient.cli.arguments import get_version_arg -from fuelclient.cli.arguments import substitutions -from fuelclient.cli.error import exceptions_decorator -from fuelclient.cli.error import ParserException -from fuelclient.cli.serializers import Serializer -from fuelclient import consts -from fuelclient import fuelclient_settings -from fuelclient import profiler -from fuelclient import utils - - -class Parser(object): - """Parser class - encapsulates argparse's ArgumentParser - and based on available actions, serializers and additional flags - populates it. - """ - def __init__(self, argv): - self.args = argv - self.parser = argparse.ArgumentParser( - usage=""" - fuel [optional args] [action] [flags] - - DEPRECATION WARNING: - - In an upcoming release of Fuel Client, the syntax will - be changed to the following: - - fuel [general flags] [action flags] - - where both [general flags] and [action flags] are derivatives - from [optional args] and [flags]; is a derivative from - . Keep in mind that specifying will be - mandatory. - - Some of the [optional args] are going to specific to a - particular and context in the upcoming - release of Fuel Client, so specifying them - before either or will not be possible. - - Example: - Correct: fuel node list --env 1 - Wrong: fuel --env 1 node list - - The table below describes the upcoming changes to commands - which will be removed or changed significantly. - - +--------------------------------------------------------+ - | Old command | New command | - +------------------------+-------------------------------+ - | fuel deploy-changes | fuel env deploy | - +------------------------+-------------------------------+ - | fuel node --set --env | fuel env add nodes | - +------------------------+-------------------------------+ - | fuel network <> --env | fuel env network <> | - +------------------------+-------------------------------+ - | fuel settings <> --env | fuel env settings <> | - +------------------------+-------------------------------+ - | fuel stop | fuel env stop-deploy | - +------------------------+-------------------------------+ - - Further information will be located in Fuel Documentation and - on our Wiki page: https://wiki.openstack.org/wiki/Fuel_CLI - - You can check out an experimental version of the new - Fuel Client by using the following command: - - fuel2 --help - - """ - ) - self.universal_flags = [] - self.credential_flags = [] - self.subparsers = self.parser.add_subparsers( - title="Namespaces", - metavar="", - dest="action", - help='actions' - ) - self.generate_actions() - self.add_version_args() - self.add_debug_arg() - self.add_serializers_args() - utils.add_os_cli_parameters(self.parser) - - def generate_actions(self): - for action, action_object in actions.items(): - action_parser = self.subparsers.add_parser( - action, - prog="fuel {0}".format(action), - help=action_object.__doc__, - formatter_class=argparse.RawTextHelpFormatter, - epilog=action_object.examples - ) - for argument in action_object.args: - if isinstance(argument, dict): - action_parser.add_argument( - *argument["args"], - **argument["params"] - ) - elif isinstance(argument, tuple): - required = argument[0] - group = action_parser.add_mutually_exclusive_group( - required=required) - for argument_in_group in argument[1:]: - group.add_argument( - *argument_in_group["args"], - **argument_in_group["params"] - ) - - def parse(self): - self.prepare_args() - if len(self.args) < 2: - self.parser.print_help() - sys.exit(0) - - parsed_params = self.parser.parse_args(self.args[1:]) - - settings = fuelclient_settings.get_settings() - settings.update_from_command_line_options(parsed_params) - - if parsed_params.action not in actions: - self.parser.print_help() - sys.exit(0) - - if profiler.profiling_enabled(): - handler_name = parsed_params.action - method_name = ''.join([method for method in parsed_params.__dict__ - if getattr(parsed_params, method) is True]) - prof = profiler.Profiler(method_name, handler_name) - - actions[parsed_params.action].action_func(parsed_params) - - if profiler.profiling_enabled(): - prof.save_data() - - def add_serializers_args(self): - serializers = self.parser.add_mutually_exclusive_group() - for format_name in Serializer.serializers.keys(): - serialization_flag = "--{0}".format(format_name) - self.universal_flags.append(serialization_flag) - serializers.add_argument( - serialization_flag, - dest=consts.SERIALIZATION_FORMAT_FLAG, - action="store_const", - const=format_name, - help="prints only {0} to stdout".format(format_name), - default=False - ) - - def add_debug_arg(self): - self.universal_flags.append("--debug") - self.parser.add_argument( - "--debug", - dest="debug", - action="store_true", - help="prints details of all HTTP request", - default=False - ) - - def add_version_args(self): - arg = get_version_arg() - self.parser.add_argument(*arg["args"], **arg["params"]) - - def prepare_args(self): - # replace some args from dict substitutions - self.args = [substitutions.get(arg, arg) for arg in self.args] - - # move general used flags before actions, otherwise they will be used - # as a part of action by action_generator - for flag in self.credential_flags: - self.move_argument_before_action(flag) - - for flag in self.universal_flags: - self.move_argument_before_action(flag, has_value=False) - - self.move_argument_after_action("--env",) - - def move_argument_before_action(self, flag, has_value=True): - """We need to move general argument before action, we use them - not directly in action but in DefaultAPIClient. - """ - for arg in self.args: - if flag in arg: - if "=" in arg or not has_value: - index_of_flag = self.args.index(arg) - flag = self.args.pop(index_of_flag) - self.args.insert(1, flag) - else: - try: - index_of_flag = self.args.index(arg) - flag = self.args.pop(index_of_flag) - value = self.args.pop(index_of_flag) - self.args.insert(1, value) - self.args.insert(1, flag) - except IndexError: - raise ParserException( - 'Corresponding value must follow "{0}" flag' - .format(arg) - ) - break - - def move_argument_after_action(self, flag): - for arg in self.args: - if flag in arg: - # if declaration with '=' sign (e.g. --env-id=1) - if "=" in arg: - index_of_flag = self.args.index(arg) - flag = self.args.pop(index_of_flag) - self.args.append(flag) - else: - try: - index_of_flag = self.args.index(arg) - self.args.pop(index_of_flag) - flag = self.args.pop(index_of_flag) - self.args.append(arg) - self.args.append(flag) - except IndexError: - raise ParserException( - 'Corresponding value must follow "{0}" flag' - .format(arg) - ) - break - - -@exceptions_decorator -def main(args=sys.argv): - parser = Parser(args) - parser.parse() diff --git a/fuelclient/cli/serializers.py b/fuelclient/cli/serializers.py deleted file mode 100644 index 9678b40..0000000 --- a/fuelclient/cli/serializers.py +++ /dev/null @@ -1,152 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 __future__ import print_function - -import json -import os - -import six -import yaml - -from fuelclient.cli import error -from fuelclient import consts -from fuelclient import utils - - -class Serializer(object): - """Serializer class - contains all logic responsible for - printing to stdout, reading and writing files to file system. - """ - serializers = { - "json": { - "w": lambda d: json.dumps(d, indent=4), - "r": utils.safe_deserialize(json.loads) - }, - "yaml": { - "w": lambda d: yaml.safe_dump(d, default_flow_style=False), - "r": utils.safe_deserialize(yaml.load) - } - } - - format_flags = False - default_format = "yaml" - format = default_format - - def __init__(self, format=None): - if format and format in self.serializers: - self.format = format - self.format_flags = True - - @property - def serializer(self): - """Returns dicts with methods for loadin/dumping current fromat. - - Returned dict's keys: - * 'w' - from 'writing', method for serializing/dumping data - * 'r' - from 'reading', method for deserializing/loading data - """ - return self.serializers[self.format] - - def serialize(self, data): - """Shortcut for serializing data with current format.""" - return self.serializer['w'](data) - - def deserialize(self, data): - """Shortcut for deserializing data with current format.""" - return self.serializer['r'](data) - - @classmethod - def from_params(cls, params): - return cls(format=getattr(params, - consts.SERIALIZATION_FORMAT_FLAG, None)) - - def print_formatted(self, data): - print(self.serializer["w"](data)) - - def print_to_output(self, formatted_data, arg, print_method=print): - if self.format_flags: - self.print_formatted(formatted_data) - else: - if six.PY2 and isinstance(arg, six.text_type): - arg = arg.encode('utf-8') - print_method(arg) - - def prepare_path(self, path): - return "{0}.{1}".format( - path, self.format - ) - - def write_to_path(self, path, data): - full_path = self.prepare_path(path) - return self.write_to_full_path(full_path, data) - - def write_to_full_path(self, path, data): - try: - with open(path, "w") as file_to_write: - self.write_to_file(file_to_write, data) - except IOError as e: - raise error.InvalidFileException( - "Can't write to file '{0}': {1}.".format( - path, e.strerror)) - return path - - def read_from_file(self, path): - return self.read_from_full_path(self.prepare_path(path)) - - def read_from_full_path(self, full_path): - try: - with open(full_path, "r") as file_to_read: - return self.serializer["r"](file_to_read.read()) - except IOError as e: - raise error.InvalidFileException( - "Can't open file '{0}': {1}.".format(full_path, e.strerror)) - - def write_to_file(self, file_obj, data): - """Writes to opened file or file like object - :param file_obj: opened file - :param data: any serializable object - """ - serialized = self.serializer["w"](data) - file_obj.write(serialized) - - -class FileFormatBasedSerializer(Serializer): - - def get_serializer(self, path): - extension = os.path.splitext(path)[1][1:] - if extension not in self.serializers: - raise error.BadDataException( - 'No serializer for provided file {0}'.format(path)) - return self.serializers[extension] - - def write_to_file(self, full_path, data): - serializer = self.get_serializer(full_path) - with open(full_path, "w+") as f: - f.write(serializer["w"](data)) - return full_path - - def read_from_file(self, full_path): - serializer = self.get_serializer(full_path) - with open(full_path, "r") as f: - return serializer["r"](f.read()) - - -def listdir_without_extensions(dir_path): - return six.moves.filter( - lambda f: f != "", - six.moves.map( - lambda f: f.split(".")[0], - os.listdir(dir_path) - ) - ) diff --git a/fuelclient/client.py b/fuelclient/client.py deleted file mode 100644 index 36a7772..0000000 --- a/fuelclient/client.py +++ /dev/null @@ -1,248 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 json -import requests - -from keystoneclient.v2_0 import client as auth_client -from six.moves.urllib import parse as urlparse - -from fuelclient.cli import error -from fuelclient import fuelclient_settings - - -class APIClient(object): - """This class handles API requests - """ - - def __init__(self, host, port, http_proxy=None, http_timeout=None, - os_username=None, os_password=None, - os_tenant_name=None, debug=False): - self.debug = debug - - self._http_proxy = http_proxy - self._http_timeout = http_timeout - self._os_username = os_username - self._os_password = os_password - self._os_tenant_name = os_tenant_name - - self.root = "http://{host}:{port}".format(host=host, port=port) - - self.keystone_base = urlparse.urljoin(self.root, "/keystone/v2.0") - self.api_root = urlparse.urljoin(self.root, "/api/v1/") - self.ostf_root = urlparse.urljoin(self.root, "/ostf/") - - self._keystone_client = None - self._auth_required = None - self._session = None - - @classmethod - def default_client(cls): - conf = fuelclient_settings.get_settings() - return cls( - host=conf.SERVER_ADDRESS, - port=conf.SERVER_PORT, - http_proxy=conf.HTTP_PROXY, - http_timeout=conf.HTTP_TIMEOUT, - os_username=conf.OS_USERNAME, - os_password=conf.OS_PASSWORD, - os_tenant_name=conf.OS_TENANT_NAME - ) - - def _make_common_headers(self): - """Returns a dict of HTTP headers common for all requests.""" - - return {'Content-Type': 'application/json', - 'Accept': 'application/json', - 'X-Auth-Token': self.auth_token} - - def _make_proxies(self): - """Provides HTTP proxy configuration for requests module.""" - if self._http_proxy is None: - return None - - return {'http': self._http_proxy, - 'https': self._http_proxy} - - def _make_session(self): - """Initializes a HTTP session.""" - session = requests.Session() - session.headers.update(self._make_common_headers()) - session.timeout = self._http_timeout - session.proxies = self._make_proxies() - - return session - - @property - def session(self): - """Lazy initialization of a session - - Since HTTP client is a singleton test runners cannot - collect tests due to keystone authentication issues. - - TODO(romcheg): remove lazy initialization for session - when HTTP client is not a singleton. - - """ - if self._session is None: - self._session = self._make_session() - - return self._session - - @property - def auth_token(self): - if self.auth_required: - if not self.keystone_client.auth_token: - self.keystone_client.authenticate() - return self.keystone_client.auth_token - return '' - - @property - def auth_required(self): - if self._auth_required is None: - url = self.api_root + 'version' - resp = requests.get(url) - if resp.status_code == 401: - self._auth_required = True - else: - self._raise_for_status_with_info(resp) - self._auth_required = resp.json().get('auth_required', False) - - return self._auth_required - - @property - def keystone_client(self): - if not self._keystone_client: - self.initialize_keystone_client() - return self._keystone_client - - def update_own_password(self, new_pass): - if self.auth_token: - self.keystone_client.users.update_own_password( - self._os_password, new_pass) - - def initialize_keystone_client(self): - if self.auth_required: - self._keystone_client = auth_client.Client( - auth_url=self.keystone_base, - username=self._os_username, - password=self._os_password, - tenant_name=self._os_tenant_name) - - self._keystone_client.session.auth = self._keystone_client - self._keystone_client.authenticate() - - def debug_mode(self, debug=False): - self.debug = debug - return self - - def print_debug(self, message): - if self.debug: - print(message) - - def delete_request(self, api): - """Make DELETE request to specific API with some data.""" - - url = self.api_root + api - self.print_debug('DELETE {0}'.format(url)) - - resp = self.session.delete(url) - self._raise_for_status_with_info(resp) - - return self._decode_content(resp) - - def put_request(self, api, data, ostf=False, **params): - """Make PUT request to specific API with some data. - - :param api: API endpoint (path) - :param data: Data send in request, will be serialized to JSON - :param ostf: is this a call to OSTF API - :param params: Params of query string - """ - url = (self.ostf_root if ostf else self.api_root) + api - data_json = json.dumps(data) - resp = self.session.put(url, data=data_json, params=params) - - self.print_debug('PUT {0} data={1}'.format(resp.url, data_json)) - self._raise_for_status_with_info(resp) - return self._decode_content(resp) - - def get_request_raw(self, api, ostf=False, params=None): - """Make a GET request to specific API and return raw response - - :param api: API endpoint (path) - :param ostf: is this a call to OSTF API - :param params: params passed to GET request - - """ - url = (self.ostf_root if ostf else self.api_root) + api - self.print_debug('GET {0}'.format(url)) - - return self.session.get(url, params=params) - - def get_request(self, api, ostf=False, params=None): - """Make GET request to specific API.""" - - params = params or {} - - resp = self.get_request_raw(api, ostf, params) - self._raise_for_status_with_info(resp) - - return resp.json() - - def post_request_raw(self, api, data=None, ostf=False): - """Make a POST request to specific API and return raw response. - - :param api: API endpoint (path) - :param data: data send in request, will be serialzied to JSON - :param ostf: is this a call to OSTF API - - """ - url = (self.ostf_root if ostf else self.api_root) + api - data_json = None if data is None else json.dumps(data) - - self.print_debug('POST {0} data={1}'.format(url, data_json)) - - return self.session.post(url, data=data_json) - - def post_request(self, api, data=None, ostf=False): - """Make POST request to specific API with some data - """ - resp = self.post_request_raw(api, data, ostf=ostf) - self._raise_for_status_with_info(resp) - return self._decode_content(resp) - - def get_fuel_version(self): - return self.get_request("version") - - def _raise_for_status_with_info(self, response): - try: - response.raise_for_status() - except requests.exceptions.HTTPError as e: - raise error.HTTPError(error.get_full_error_message(e)) - - def _decode_content(self, response): - if response.status_code == 204: - return {} - - self.print_debug(response.text) - return response.json() - - -# This line is single point of instantiation for 'APIClient' class, -# which intended to implement Singleton design pattern. -DefaultAPIClient = APIClient.default_client() -""" -.. deprecated:: Use fuelclient.client.APIClient instead -""" diff --git a/fuelclient/commands/__init__.py b/fuelclient/commands/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fuelclient/commands/base.py b/fuelclient/commands/base.py deleted file mode 100644 index 234f08c..0000000 --- a/fuelclient/commands/base.py +++ /dev/null @@ -1,253 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 abc -import os - -from cliff import command -from cliff import lister -from cliff import show -import six - -import fuelclient -from fuelclient.cli.serializers import Serializer -from fuelclient.common import data_utils - -VERSION = 'v1' - - -@six.add_metaclass(abc.ABCMeta) -class BaseCommand(command.Command): - """Base Fuel Client command.""" - - def get_attributes_path(self, attr_type, file_format, ent_id, directory): - """Returnes a path for attributes of an entity - - :param attr_type: Type of the attribute, e. g., disks, networks. - :param file_format: The format of the file that contains or will - contain the attributes, e. g., json or yaml. - :param ent_id: Id of an entity - :param directory: Directory that is used to store attributes. - - """ - if attr_type not in self.allowed_attr_types: - raise ValueError('attr_type must be ' - 'one of {}'.format(self.allowed_attr_types)) - - if file_format not in self.supported_file_formats: - raise ValueError('file_format must be ' - 'one of {}'.format(self.supported_file_formats)) - - return os.path.join(os.path.abspath(directory), - '{ent}_{id}'.format(ent=self.entity_name, - id=ent_id), - '{}.{}'.format(attr_type, file_format)) - - def __init__(self, *args, **kwargs): - super(BaseCommand, self).__init__(*args, **kwargs) - self.client = fuelclient.get_client(self.entity_name, VERSION) - - @abc.abstractproperty - def entity_name(self): - """Name of the Fuel entity.""" - pass - - @property - def supported_file_formats(self): - raise NotImplementedError() - - @property - def allowed_attr_types(self): - raise NotImplementedError() - - -@six.add_metaclass(abc.ABCMeta) -class BaseListCommand(lister.Lister, BaseCommand): - """Lists all entities showing some information.""" - - filters = {} - - @property - def default_sorting_by(self): - return ['id'] - - @abc.abstractproperty - def columns(self): - """Names of columns in the resulting table.""" - pass - - def get_parser(self, prog_name): - parser = super(BaseListCommand, self).get_parser(prog_name) - - # Add sorting key argument to the output formatters group - # if it exists. If not -- add is to the general group. - matching_groups = (gr - for gr in parser._action_groups - if gr.title == 'output formatters') - - group = next(matching_groups, None) or parser - - group.add_argument('-s', - '--sort-columns', - type=str, - nargs='+', - choices=self.columns, - metavar='SORT_COLUMN', - default=self.default_sorting_by, - help='Space separated list of keys for sorting ' - 'the data. Defaults to {}. Wrong values ' - 'are ignored.'.format( - ', '.join(self.default_sorting_by))) - - return parser - - def _sort_data(self, parsed_args, data): - scolumn_ids = [self.columns.index(col) - for col in parsed_args.sort_columns] - data.sort(key=lambda x: [x[scolumn_id] for scolumn_id in scolumn_ids]) - return data - - def take_action(self, parsed_args): - filters = {} - for name, prop in self.filters.items(): - value = getattr(parsed_args, prop, None) - if value is not None: - filters[name] = value - - data = self.client.get_all(**filters) - data = data_utils.get_display_data_multi(self.columns, data) - data = self._sort_data(parsed_args, data) - - return self.columns, data - - -@six.add_metaclass(abc.ABCMeta) -class BaseShowCommand(show.ShowOne, BaseCommand): - """Shows detailed information about the entity.""" - - @abc.abstractproperty - def columns(self): - """Names of columns in the resulting table.""" - pass - - def get_parser(self, prog_name): - parser = super(BaseShowCommand, self).get_parser(prog_name) - - parser.add_argument('id', type=int, - help='Id of the {0}.'.format(self.entity_name)) - - return parser - - def take_action(self, parsed_args): - data = self.client.get_by_id(parsed_args.id) - data = data_utils.get_display_data_single(self.columns, data) - - return (self.columns, data) - - -@six.add_metaclass(abc.ABCMeta) -class BaseDeleteCommand(BaseCommand): - """Deletes entity with the specified id.""" - - def get_parser(self, prog_name): - parser = super(BaseDeleteCommand, self).get_parser(prog_name) - - parser.add_argument( - 'id', - type=int, - help='Id of the {0} to delete.'.format(self.entity_name)) - - return parser - - def take_action(self, parsed_args): - self.client.delete_by_id(parsed_args.id) - - msg = '{ent} with id {ent_id} was deleted\n' - - self.app.stdout.write( - msg.format( - ent=self.entity_name.capitalize(), - ent_id=parsed_args.id)) - - -@six.add_metaclass(abc.ABCMeta) -class BaseTasksExecuteCommand(BaseCommand): - - def get_parser(self, prog_name): - parser = super(BaseTasksExecuteCommand, self).get_parser(prog_name) - - parser.add_argument( - '-e', '--env', - type=int, - required=True, - help='Id of the environment' - ) - parser.add_argument( - '--force', - action="store_true", - default=False, - help='Force run all deployment tasks without skipping.') - - parser.add_argument( - '--trace', - action="store_true", - default=False, - help='Enable debugging mode in tasks executor.' - ) - parser.add_argument( - '--format', - choices=['json', 'yaml'], - help='Select output format, by default text message will produce.' - ) - - mode_group = parser.add_mutually_exclusive_group() - mode_group.add_argument( - '--dry-run', - action="store_true", - default=False, - help='Specifies to dry-run a deployment by configuring ' - 'task executor to dump the deployment graph to a dot file.' - ) - mode_group.add_argument( - '--noop', - action="store_true", - default=False, - help='Specifies noop-run deployment configuring tasks executor ' - 'to run all tasks in noop mode. ' - 'Execution result summary can be got via history of tasks.') - - return parser - - def take_action(self, parsed_args): - task = self.client.execute( - env_id=parsed_args.env, - dry_run=parsed_args.dry_run, - noop_run=parsed_args.noop, - force=parsed_args.force, - debug=parsed_args.trace, - **self.get_options(parsed_args) - ) - if parsed_args.format: - msg = Serializer(parsed_args.format).serialize(task.data) + '\n' - else: - msg = ( - 'Deployment task with id {0} for the environment {1} ' - 'has been started.\n' - .format(task.data['id'], task.data['cluster']) - ) - self.app.stdout.write(msg) - - def get_options(self, parsed_args): - """Produce additional options from cmdline arguments.""" - raise NotImplementedError diff --git a/fuelclient/commands/environment.py b/fuelclient/commands/environment.py deleted file mode 100644 index aa80625..0000000 --- a/fuelclient/commands/environment.py +++ /dev/null @@ -1,933 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 abc -import argparse -import functools -import os -import shutil - -import six - -from cliff import show -from oslo_utils import fileutils - -from fuelclient.cli import error -from fuelclient.commands import base -from fuelclient.common import data_utils - - -class EnvMixIn(object): - entity_name = 'environment' - - supported_file_formats = ('json', 'yaml') - allowed_attr_types = ('network', 'settings') - - @staticmethod - def source_dir(directory): - """Check that the source directory exists and is readable. - - :param directory: Path to source directory - :type directory: str - :return: Absolute path to source directory - :rtype: str - """ - path = os.path.abspath(directory) - if not os.path.isdir(path): - raise argparse.ArgumentTypeError( - '"{0}" is not a directory.'.format(path)) - if not os.access(path, os.R_OK): - raise argparse.ArgumentTypeError( - 'directory "{0}" is not readable'.format(path)) - return path - - @staticmethod - def destination_dir(directory): - """Check that the destination directory exists and is writable. - - :param directory: Path to destination directory - :type directory: str - :return: Absolute path to destination directory - :rtype: str - """ - path = os.path.abspath(directory) - if not os.path.isdir(path): - raise argparse.ArgumentTypeError( - '"{0}" is not a directory.'.format(path)) - if not os.access(path, os.W_OK): - raise argparse.ArgumentTypeError( - 'directory "{0}" is not writable'.format(path)) - return path - - -@six.add_metaclass(abc.ABCMeta) -class BaseUploadCommand(EnvMixIn, base.BaseCommand): - - @abc.abstractproperty - def uploader(self): - pass - - @abc.abstractproperty - def attribute(self): - pass - - def get_parser(self, prog_name): - parser = super(BaseUploadCommand, self).get_parser(prog_name) - parser.add_argument('id', - type=int, - help='Id of environment.') - parser.add_argument('-f', - '--format', - required=True, - choices=self.supported_file_formats, - help='Format of serialized ' - '{}.'.format(self.attribute)) - parser.add_argument('-d', - '--directory', - required=False, - default=os.curdir, - help='Source directory. Defaults to the ' - 'current directory.') - - return parser - - def take_action(self, parsed_args): - directory = parsed_args.directory - file_path = self.get_attributes_path(self.attribute, - parsed_args.format, - parsed_args.id, - directory) - try: - with open(file_path, 'r') as stream: - attribute = data_utils.safe_load(parsed_args.format, stream) - except (IOError, OSError): - msg = 'Could not read configuration of {} at {}.' - raise error.InvalidFileException(msg.format(self.attribute, - file_path)) - - self.uploader(parsed_args.id, attribute) - - msg = ('Configuration of {t} for the environment with id ' - '{env} was loaded from {path}\n') - - self.app.stdout.write(msg.format(t=self.attribute, - env=parsed_args.id, - path=file_path)) - - -@six.add_metaclass(abc.ABCMeta) -class BaseDownloadCommand(EnvMixIn, base.BaseCommand): - - @abc.abstractproperty - def downloader(self): - pass - - @abc.abstractproperty - def attribute(self): - pass - - def get_parser(self, prog_name): - parser = super(BaseDownloadCommand, self).get_parser(prog_name) - parser.add_argument('id', - type=int, - help='Id of an environment.') - parser.add_argument('-f', - '--format', - required=True, - choices=self.supported_file_formats, - help='Format of serialized ' - '{}.'.format(self.attribute)) - parser.add_argument('-d', - '--directory', - required=False, - default=os.curdir, - help='Destination directory. Defaults to the ' - 'current directory.') - - return parser - - def take_action(self, parsed_args): - directory = parsed_args.directory or os.curdir - attributes = self.downloader(parsed_args.id) - - file_path = self.get_attributes_path(self.attribute, - parsed_args.format, - parsed_args.id, - directory) - - try: - fileutils.ensure_tree(os.path.dirname(file_path)) - fileutils.delete_if_exists(file_path) - - with open(file_path, 'w') as stream: - data_utils.safe_dump(parsed_args.format, stream, attributes) - except (IOError, OSError): - msg = 'Could not store configuration of {} at {}.' - raise error.InvalidFileException(msg.format(self.attribute, - file_path)) - - msg = ('Configuration of {t} for the environment with id ' - '{env} was stored in {path}\n') - self.app.stdout.write(msg.format(t=self.attribute, - env=parsed_args.id, - path=file_path)) - - -class EnvList(EnvMixIn, base.BaseListCommand): - """Show list of all available environments.""" - - columns = ("id", - "status", - "name", - "release_id") - - -class EnvShow(EnvMixIn, base.BaseShowCommand): - """Show info about environment with given id.""" - columns = ("id", - "status", - "fuel_version", - "name", - "release_id", - "is_customized", - "changes") - - -class EnvCreate(EnvMixIn, base.BaseShowCommand): - """Creates environment with given attributes.""" - - columns = EnvShow.columns - - def get_parser(self, prog_name): - # Avoid adding id argument by BaseShowCommand - parser = show.ShowOne.get_parser(self, prog_name) - - parser.add_argument( - 'name', - type=str, - help='Name of the new environment' - ) - - parser.add_argument('-r', - '--release', - type=int, - required=True, - help='Id of the release for which will ' - 'be deployed') - - parser.add_argument('-nst', - '--net-segmentation-type', - type=str, - choices=['vlan', 'gre', 'tun'], - dest='nst', - default='vlan', - help='Network segmentation type.\n' - 'WARNING: GRE network segmentation type ' - 'is deprecated since 7.0 release.') - - return parser - - def take_action(self, parsed_args): - if parsed_args.nst == 'gre': - self.app.stderr.write('WARNING: GRE network segmentation type is ' - 'deprecated since 7.0 release') - - new_env = self.client.create(name=parsed_args.name, - release_id=parsed_args.release, - net_segment_type=parsed_args.nst) - - new_env = data_utils.get_display_data_single(self.columns, new_env) - - return (self.columns, new_env) - - -class EnvDelete(EnvMixIn, base.BaseDeleteCommand): - """Delete environment with given id.""" - - def get_parser(self, prog_name): - parser = super(EnvDelete, self).get_parser(prog_name) - - parser.add_argument('-f', - '--force', - action='store_true', - help='Force-delete the environment.') - - return parser - - def take_action(self, parsed_args): - env = self.client.get_by_id(parsed_args.id) - - if env['status'] == 'operational' and not parsed_args.force: - self.app.stdout.write("Deleting an operational environment is a " - "dangerous operation.\n" - "Please use --force to bypass this message.") - return - - return super(EnvDelete, self).take_action(parsed_args) - - -class EnvUpdate(EnvMixIn, base.BaseShowCommand): - """Change given attributes for an environment.""" - - columns = EnvShow.columns - - def get_parser(self, prog_name): - # Avoid adding id argument by BaseShowCommand - parser = show.ShowOne.get_parser(self, prog_name) - - parser.add_argument('id', - type=int, - help='Id of the nailgun entity to be processed.') - - parser.add_argument('-n', - '--name', - type=str, - dest='name', - default=None, - help='New name for environment') - - return parser - - def take_action(self, parsed_args): - updates = {} - for attr in self.client._updatable_attributes: - if getattr(parsed_args, attr, None): - updates[attr] = getattr(parsed_args, attr) - - updated_env = self.client.update(environment_id=parsed_args.id, - **updates) - updated_env = data_utils.get_display_data_single(self.columns, - updated_env) - - return (self.columns, updated_env) - - -class EnvReset(EnvMixIn, base.BaseCommand): - """Reset deployed environment.""" - - def get_parser(self, prog_name): - parser = super(EnvReset, self).get_parser(prog_name) - - parser.add_argument('id', - type=int, - help='Id of the environment to reset.') - parser.add_argument('-f', - '--force', - action='store_true', - help='Force reset environment.') - - return parser - - def take_action(self, parsed_args): - result = self.client.reset(parsed_args.id, force=parsed_args.force) - - msg = ('Reset task with id {t} for the environment {e} ' - 'has been started.\n'.format(t=result.data['id'], - e=result.data['cluster'])) - - self.app.stdout.write(msg) - - -class EnvStopDeploy(EnvMixIn, base.BaseCommand): - """Stop deployment process for specific environment.""" - - def get_parser(self, prog_name): - parser = super(EnvStopDeploy, self).get_parser(prog_name) - - parser.add_argument('id', - type=int, - help='Id of the environment to stop deployment.') - - return parser - - def take_action(self, parsed_args): - result = self.client.stop(parsed_args.id) - - msg = ('Stop deployment task with id {t} for the environment ' - '{e} has been started.\n'.format(t=result.data['id'], - e=result.data['cluster'])) - self.app.stdout.write(msg) - - -class EnvAddNodes(EnvMixIn, base.BaseCommand): - """Adds nodes to an environment with the specified roles.""" - - def get_parser(self, prog_name): - - parser = super(EnvAddNodes, self).get_parser(prog_name) - - parser.add_argument('-e', - '--env', - type=int, - required=True, - help='Id of the environment to add nodes to') - - parser.add_argument('-n', - '--nodes', - type=int, - nargs='+', - required=True, - help='Ids of the nodes to add.') - - parser.add_argument('-r', - '--roles', - type=str, - nargs='+', - required=True, - help='Target roles of the nodes.') - - return parser - - def take_action(self, parsed_args): - env_id = parsed_args.env - - self.client.add_nodes(environment_id=env_id, - nodes=parsed_args.nodes, - roles=parsed_args.roles) - - msg = 'Nodes {n} were added to the environment {e} with roles {r}\n' - self.app.stdout.write(msg.format(n=parsed_args.nodes, - e=parsed_args.env, - r=parsed_args.roles)) - - -class EnvRemoveNodes(EnvMixIn, base.BaseCommand): - """Removes nodes from an environment.""" - - def get_parser(self, prog_name): - - parser = super(EnvRemoveNodes, self).get_parser(prog_name) - - parser.add_argument('-e', - '--env', - type=int, - required=True, - help='Id of the environment to remove nodes from') - - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-n', - '--nodes', - type=int, - nargs='+', - help='Ids of the nodes to remove.') - - group.add_argument('--nodes-all', - action='store_true', - help='Remove all nodes from environment') - - return parser - - def take_action(self, parsed_args): - nodes = None if parsed_args.nodes_all else parsed_args.nodes - self.client.remove_nodes(environment_id=parsed_args.env, - nodes=nodes) - - msg = 'Nodes were removed from the environment with id={e}\n'.format( - e=parsed_args.env) - - self.app.stdout.write(msg) - - -class EnvDeploy(EnvMixIn, base.BaseCommand): - """Deploys changes on the specified environment.""" - - def get_parser(self, prog_name): - parser = super(EnvDeploy, self).get_parser(prog_name) - - parser.add_argument('id', - type=int, - help='Id of the environment to be deployed.') - - dry_run_help_string = 'Specifies to dry-run a deployment by' \ - 'configuring task executor to dump the' \ - 'deployment graph to a dot file.' \ - 'Store cluster settings and serialized ' \ - 'data in the db and ask the task executor ' \ - 'to dump the resulting graph into a dot file' - noop_run_help_string = 'Specifies noop-run deployment ' \ - 'configuring tasks executor to run ' \ - 'puppet and shell tasks in noop mode and ' \ - 'skip all other. Stores noop-run result ' \ - 'summary in nailgun database' - parser.add_argument( - '-d', '--dry-run', dest="dry_run", - action='store_true', help=dry_run_help_string) - parser.add_argument( - '--noop', dest="noop_run", - action='store_true', help=noop_run_help_string) - - return parser - - def take_action(self, parsed_args): - task_id = self.client.deploy_changes(parsed_args.id, - dry_run=parsed_args.dry_run, - noop_run=parsed_args.noop_run) - - msg = 'Deployment task with id {t} for the environment {e} '\ - 'has been started.\n'.format(t=task_id, e=parsed_args.id) - - self.app.stdout.write(msg) - - -class EnvRedeploy(EnvDeploy): - """Redeploys changes on the specified environment.""" - - def take_action(self, parsed_args): - task_id = self.client.redeploy_changes(parsed_args.id, - dry_run=parsed_args.dry_run, - noop_run=parsed_args.noop_run) - - msg = 'Deployment task with id {t} for the environment {e} '\ - 'has been started.\n'.format(t=task_id, e=parsed_args.id) - - self.app.stdout.write(msg) - - -class EnvProvisionNodes(EnvMixIn, base.BaseCommand): - """Provision specified nodes for a specified environment.""" - - def get_parser(self, prog_name): - parser = super(EnvProvisionNodes, self).get_parser(prog_name) - - parser.add_argument('-e', - '--env', - required=True, - type=int, - help='Id of the environment.') - parser.add_argument('-n', - '--nodes', - required=True, - type=int, - nargs='+', - help='Ids of nodes to provision.') - - return parser - - def take_action(self, parsed_args): - node_ids = parsed_args.nodes - task = self.client.provision_nodes(parsed_args.env, node_ids) - - msg = ('Provisioning task with id {t} for the nodes {n} ' - 'within the environment {e} has been ' - 'started.\n').format(t=task['id'], - e=parsed_args.env, - n=', '.join(str(i) for i in node_ids)) - - self.app.stdout.write(msg) - - -class EnvDeployNodes(EnvMixIn, base.BaseCommand): - """Deploy specified nodes for a specified environment.""" - - def get_parser(self, prog_name): - parser = super(EnvDeployNodes, self).get_parser(prog_name) - - parser.add_argument('-e', - '--env', - required=True, - type=int, - help='Id of the environment.') - parser.add_argument('-n', - '--nodes', - required=True, - type=int, - nargs='+', - help='Ids of nodes to deploy.') - parser.add_argument('-f', - '--force', - action='store_true', - help='Force deploy nodes.') - - noop_run_help_string = 'Specifies noop-run deployment ' \ - 'configuring tasks executor to run ' \ - 'puppet and shell tasks in noop mode and ' \ - 'skip all other. Stores noop-run result ' \ - 'summary in nailgun database' - parser.add_argument('--noop', dest="noop_run", action='store_true', - help=noop_run_help_string) - return parser - - def take_action(self, parsed_args): - node_ids = parsed_args.nodes - task = self.client.deploy_nodes(parsed_args.env, node_ids, - force=parsed_args.force, - noop_run=parsed_args.noop_run) - - msg = ('Deployment task with id {t} for the nodes {n} within ' - 'the environment {e} has been ' - 'started.\n').format(t=task['id'], - e=parsed_args.env, - n=', '.join(str(i) for i in node_ids)) - - self.app.stdout.write(msg) - - -class EnvSpawnVms(EnvMixIn, base.BaseCommand): - """Provision specified environment.""" - - def get_parser(self, prog_name): - parser = super(EnvSpawnVms, self).get_parser(prog_name) - - parser.add_argument('id', - type=int, - help='Id of the environment to be provision.') - - return parser - - def take_action(self, parsed_args): - return self.client.spawn_vms(parsed_args.id) - - -class EnvNetworkVerify(EnvMixIn, base.BaseCommand): - """Run network verification for specified environment.""" - - def get_parser(self, prog_name): - parser = super(EnvNetworkVerify, self).get_parser(prog_name) - - parser.add_argument('id', - type=int, - help='Id of the environment to verify network.') - - return parser - - def take_action(self, parsed_args): - task = self.client.verify_network(parsed_args.id) - msg = 'Network verification task with id {t} for the environment {e} '\ - 'has been started.\n'.format(t=task['id'], e=parsed_args.id) - - self.app.stdout.write(msg) - - -class EnvNetworkUpload(BaseUploadCommand): - """Upload network configuration and apply it to an environment.""" - - attribute = 'network' - - @property - def uploader(self): - return self.client.set_network_configuration - - -class EnvNetworkDownload(BaseDownloadCommand): - """Download and store network configuration of an environment.""" - - attribute = 'network' - - @property - def downloader(self): - return self.client.get_network_configuration - - -class EnvSettingsUpload(BaseUploadCommand): - """Upload and apply environment settings.""" - - attribute = 'settings' - - @property - def uploader(self): - return functools.partial(self.client.set_settings, - force=self.force_flag) - - def get_parser(self, prog_name): - parser = super(EnvSettingsUpload, self).get_parser(prog_name) - parser.add_argument('--force', - action='store_true', - help='Force applying the settings.') - - return parser - - def take_action(self, parsed_args): - self.force_flag = parsed_args.force - - super(EnvSettingsUpload, self).take_action(parsed_args) - - -class EnvSettingsDownload(BaseDownloadCommand): - """Download and store environment settings.""" - - attribute = 'settings' - - @property - def downloader(self): - return self.client.get_settings - - -class FactsMixIn(object): - - @staticmethod - def _get_fact_dir(env_id, fact_type, directory): - return os.path.join(directory, "{0}_{1}".format(fact_type, env_id)) - - @staticmethod - def _read_deployment_facts_from_file(directory, file_format): - return list(six.moves.map( - lambda f: data_utils.read_from_file(f), - [os.path.join(directory, file_name) - for file_name in os.listdir(directory) - if file_format == os.path.splitext(file_name)[1].lstrip('.')] - )) - - @staticmethod - def _read_provisioning_facts_from_file(directory, file_format): - node_facts = list(six.moves.map( - lambda f: data_utils.read_from_file(f), - [os.path.join(directory, file_name) - for file_name in os.listdir(directory) - if file_format == os.path.splitext(file_name)[1].lstrip('.') - and 'engine' != os.path.splitext(file_name)[0]] - )) - - engine_facts = None - engine_file = os.path.join(directory, - "{}.{}".format('engine', file_format)) - if os.path.lexists(engine_file): - engine_facts = data_utils.read_from_file(engine_file) - - return {'engine': engine_facts, 'nodes': node_facts} - - @staticmethod - def _write_deployment_facts_to_file(facts, directory, file_format): - # from 9.0 the deployment info is serialized only per node - for _fact in facts: - file_name = "{role}_{uid}." if 'role' in _fact else "{uid}." - file_name += file_format - data_utils.write_to_file( - os.path.join(directory, file_name.format(**_fact)), - _fact) - - @staticmethod - def _write_provisioning_facts_to_file(facts, directory, file_format): - file_name = "{uid}." - file_name += file_format - data_utils.write_to_file( - os.path.join(directory, file_name.format(uid='engine')), - facts['engine']) - - for _fact in facts['nodes']: - data_utils.write_to_file( - os.path.join(directory, file_name.format(**_fact)), - _fact) - - def download(self, env_id, fact_type, destination_dir, file_format, - nodes=None, default=False, split=None): - facts = self.client.download_facts( - env_id, fact_type, nodes=nodes, default=default, split=split) - - facts_dir = self._get_fact_dir(env_id, fact_type, destination_dir) - if os.path.exists(facts_dir): - shutil.rmtree(facts_dir) - os.makedirs(facts_dir) - - getattr(self, "_write_{0}_facts_to_file".format(fact_type))( - facts, facts_dir, file_format) - - return facts_dir - - def upload(self, env_id, fact_type, source_dir, file_format): - facts_dir = self._get_fact_dir(env_id, fact_type, source_dir) - facts = getattr(self, "_read_{0}_facts_from_file".format(fact_type))( - facts_dir, file_format) - - if not facts \ - or isinstance(facts, dict) and not six.moves.reduce( - lambda a, b: a or b, facts.values()): - raise error.ServerDataException( - "There are no {} facts for this environment!".format( - fact_type)) - - return self.client.upload_facts(env_id, fact_type, facts) - - -class BaseEnvFactsDelete(EnvMixIn, base.BaseCommand): - """Delete current various facts for orchestrator.""" - - fact_type = '' - - def get_parser(self, prog_name): - parser = super(BaseEnvFactsDelete, self).get_parser(prog_name) - - parser.add_argument( - 'id', - type=int, - help='ID of the environment') - - return parser - - def take_action(self, parsed_args): - self.client.delete_facts(parsed_args.id, self.fact_type) - self.app.stdout.write( - "{0} facts for the environment {1} were deleted " - "successfully.\n".format(self.fact_type.capitalize(), - parsed_args.id) - ) - - -class EnvDeploymentFactsDelete(BaseEnvFactsDelete): - """Delete current deployment facts.""" - - fact_type = 'deployment' - - -class EnvProvisioningFactsDelete(BaseEnvFactsDelete): - """Delete current provisioning facts.""" - - fact_type = 'provisioning' - - -class BaseEnvFactsDownload(FactsMixIn, EnvMixIn, base.BaseCommand): - """Download various facts for orchestrator.""" - - fact_type = '' - fact_default = False - - def get_parser(self, prog_name): - parser = super(BaseEnvFactsDownload, self).get_parser(prog_name) - - parser.add_argument( - '-e', '--env', - type=int, - required=True, - help='ID of the environment') - - parser.add_argument( - '-d', '--directory', - type=self.destination_dir, - default=os.path.curdir, - help='Path to directory to save {} facts. ' - 'Defaults to the current directory'.format(self.fact_type)) - - parser.add_argument( - '-n', '--nodes', - type=int, - nargs='+', - help='Get {} facts for nodes with given IDs'.format( - self.fact_type)) - - parser.add_argument( - '-f', '--format', - choices=self.supported_file_formats, - required=True, - help='Format of serialized {} facts'.format(self.fact_type)) - - parser.add_argument( - '--no-split', - action='store_false', - dest='split', - default=True, - help='Do not split deployment info for node and cluster parts.' - ) - - return parser - - def take_action(self, parsed_args): - facts_dir = self.download( - parsed_args.env, - self.fact_type, - parsed_args.directory, - parsed_args.format, - nodes=parsed_args.nodes, - default=self.fact_default, - split=parsed_args.split - ) - self.app.stdout.write( - "{0} {1} facts for the environment {2} " - "were downloaded to {3}\n".format( - 'Default' if self.fact_default else 'User-defined', - self.fact_type, - parsed_args.env, - facts_dir) - ) - - -class EnvDeploymentFactsDownload(BaseEnvFactsDownload): - """Download the user-defined deployment facts.""" - - fact_type = 'deployment' - fact_default = False - - -class EnvDeploymentFactsGetDefault(BaseEnvFactsDownload): - """Download the default deployment facts.""" - - fact_type = 'deployment' - fact_default = True - - -class EnvProvisioningFactsDownload(BaseEnvFactsDownload): - """Download the user-defined provisioning facts.""" - - fact_type = 'provisioning' - fact_default = False - - -class EnvProvisioningFactsGetDefault(BaseEnvFactsDownload): - """Download the default provisioning facts.""" - - fact_type = 'provisioning' - fact_default = True - - -class BaseEnvFactsUpload(FactsMixIn, EnvMixIn, base.BaseCommand): - """Upload various facts for orchestrator.""" - - fact_type = '' - - def get_parser(self, prog_name): - parser = super(BaseEnvFactsUpload, self).get_parser(prog_name) - - parser.add_argument( - '-e', '--env', - type=int, - required=True, - help='ID of the environment') - - parser.add_argument( - '-d', '--directory', - type=self.source_dir, - default=os.path.curdir, - help='Path to directory to read {} facts. ' - 'Defaults to the current directory'.format(self.fact_type)) - - parser.add_argument( - '-f', '--format', - choices=self.supported_file_formats, - required=True, - help='Format of serialized {} facts'.format(self.fact_type)) - - return parser - - def take_action(self, parsed_args): - self.upload( - parsed_args.env, - self.fact_type, - parsed_args.directory, - parsed_args.format - ) - self.app.stdout.write( - "{0} facts for the environment {1} were uploaded " - "successfully.\n".format(self.fact_type.capitalize(), - parsed_args.env) - ) - - -class EnvDeploymentFactsUpload(BaseEnvFactsUpload): - """Upload deployment facts.""" - - fact_type = 'deployment' - - -class EnvProvisioningFactsUpload(BaseEnvFactsUpload): - """Upload provisioning facts.""" - - fact_type = 'provisioning' diff --git a/fuelclient/commands/extension.py b/fuelclient/commands/extension.py deleted file mode 100644 index 9a59afa..0000000 --- a/fuelclient/commands/extension.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 cliff import show - -from fuelclient.commands import base - - -class ExtensionMixIn(object): - entity_name = 'extension' - - -class ExtensionList(ExtensionMixIn, base.BaseListCommand): - """Show list of all available extensions.""" - - columns = ("name", - "version", - "description", - "provides") - default_sorting_by = ["name"] - - -class EnvExtensionShow(ExtensionMixIn, base.BaseShowCommand): - """Show list of enabled extensions for environment with given id.""" - - columns = ("extensions", ) - - def get_parser(self, prog_name): - # Avoid adding id argument by BaseShowCommand - # Because it adds 'id' with wrong help message for this class - parser = show.ShowOne.get_parser(self, prog_name) - - parser.add_argument('id', type=int, help='Id of the environment.') - - return parser - - -class EnvExtensionEnable(ExtensionMixIn, base.BaseCommand): - """Enable specified extensions for environment with given id.""" - - def get_parser(self, prog_name): - parser = super(EnvExtensionEnable, self).get_parser(prog_name) - - parser.add_argument('id', type=int, help='Id of the environment.') - parser.add_argument('-E', - '--extensions', - required=True, - nargs='+', - help='Names of extensions to enable.') - - return parser - - def take_action(self, parsed_args): - self.client.enable_extensions(parsed_args.id, parsed_args.extensions) - - msg = ('The following extensions: {e} have been enabled for ' - 'the environment with id {id}.\n'.format( - e=', '.join(parsed_args.extensions), id=parsed_args.id)) - - self.app.stdout.write(msg) - - -class EnvExtensionDisable(ExtensionMixIn, base.BaseCommand): - """Disable specified extensions for environment with given id.""" - - def get_parser(self, prog_name): - parser = super(EnvExtensionDisable, self).get_parser(prog_name) - - parser.add_argument('id', type=int, help='Id of the environment.') - parser.add_argument('-E', - '--extensions', - required=True, - nargs='+', - help='Names of extensions to disable.') - - return parser - - def take_action(self, parsed_args): - self.client.disable_extensions(parsed_args.id, parsed_args.extensions) - - msg = ('The following extensions: {e} have been disabled for ' - 'the environment with id {id}.\n'.format( - e=', '.join(parsed_args.extensions), id=parsed_args.id)) - - self.app.stdout.write(msg) diff --git a/fuelclient/commands/fuelversion.py b/fuelclient/commands/fuelversion.py deleted file mode 100644 index 2ae0c8b..0000000 --- a/fuelclient/commands/fuelversion.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 cliff import show - -from fuelclient.commands import base -from fuelclient.common import data_utils - - -class FuelVersion(show.ShowOne, base.BaseCommand): - """Show the version of Fuel.""" - - entity_name = 'fuel-version' - columns = ('api', - 'auth_required', - 'feature_groups', - 'openstack_version', - 'release') - - def take_action(self, parsed_args): - data = self.client.get_all() - data = data_utils.get_display_data_single(self.columns, data) - - return (self.columns, data) diff --git a/fuelclient/commands/graph.py b/fuelclient/commands/graph.py deleted file mode 100644 index 986e2f1..0000000 --- a/fuelclient/commands/graph.py +++ /dev/null @@ -1,414 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 - -from fuelclient.cli import error -from fuelclient.cli.serializers import Serializer -from fuelclient.commands import base -from fuelclient.common import data_utils -from fuelclient.utils import iterfiles - - -class FileMethodsMixin(object): - @classmethod - def check_file_path(cls, file_path): - if not os.path.exists(file_path): - raise error.InvalidFileException( - "File '{0}' doesn't exist.".format(file_path)) - - @classmethod - def check_dir(cls, directory): - if not os.path.exists(directory): - raise error.InvalidDirectoryException( - "Directory '{0}' doesn't exist.".format(directory)) - if not os.path.isdir(directory): - raise error.InvalidDirectoryException( - "Error: '{0}' is not a directory.".format(directory)) - - -class GraphUpload(base.BaseCommand, FileMethodsMixin): - """Upload deployment graph configuration.""" - entity_name = 'graph' - - @classmethod - def read_data_from_file(cls, file_path=None, serializer=None): - """Read graph data from given path. - - :param file_path: path - :type file_path: str - :param serializer: serializer object - :type serializer: object - :return: data - :rtype: list|object - """ - cls.check_file_path(file_path) - return (serializer or Serializer()).read_from_full_path(file_path) - - @classmethod - def read_data_from_dir(cls, dir_path=None, serializer=None): - """Read graph data from directory. - - :param dir_path: path - :type dir_path: str - :param serializer: serializer object - :type serializer: object - :return: data - :rtype: list|object - """ - cls.check_dir(dir_path) - serializer = serializer or Serializer() - - metadata_filepath = os.path.join(dir_path, 'metadata.yaml') - if os.path.exists(metadata_filepath): - data = serializer.read_from_full_path(metadata_filepath) - else: - data = {} - - tasks = [] - for file_name in iterfiles(dir_path, 'tasks.yaml'): - task_data = serializer.read_from_full_path(file_name) - if task_data: - tasks.extend(task_data) - - if tasks: - data['tasks'] = tasks - - if not data: - msg = ("Nothing to upload. Check if at least one 'tasks.yaml' " - "file is not empty and exists in '{path}' directory " - "path".format(path=dir_path)) - raise error.ActionException(msg) - return data - - def get_parser(self, prog_name): - parser = super(GraphUpload, self).get_parser(prog_name) - graph_class = parser.add_mutually_exclusive_group(required=True) - - graph_class.add_argument('-e', - '--env', - type=int, - required=False, - help='Id of the environment') - graph_class.add_argument('-r', - '--release', - type=int, - required=False, - help='Id of the release') - graph_class.add_argument('-p', - '--plugin', - type=int, - required=False, - help='Id of the plugin') - - parser.add_argument('-t', - '--graph-type', - required=True, - help='Type of the deployment graph') - - graph_source = parser.add_mutually_exclusive_group(required=True) - graph_source.add_argument( - '-f', - '--file', - default=None, - help='YAML file that contains deployment graph data.' - ) - graph_source.add_argument( - '-d', - '--dir', - default=None, - help='The directory that includes tasks.yaml and metadata.yaml.' - ) - return parser - - def take_action(self, args): - parameters_to_graph_class = ( - ('env', 'clusters'), - ('release', 'releases'), - ('plugin', 'plugins'), - ) - - if args.file: - data = self.read_data_from_file(args.file) - else: - data = self.read_data_from_dir(args.dir) - - for parameter, graph_class in parameters_to_graph_class: - model_id = getattr(args, parameter) - if model_id: - self.client.upload( - data=data, - related_model=graph_class, - related_id=model_id, - graph_type=args.graph_type - ) - break - - self.app.stdout.write("Deployment graph was successfully uploaded.\n") - - -class GraphExecute(base.BaseTasksExecuteCommand): - """Start deployment with given graph type.""" - entity_name = 'graph' - - def get_parser(self, prog_name): - parser = super(GraphExecute, self).get_parser(prog_name) - parser.add_argument( - '-t', - '--graph-types', - nargs='+', - required=True, - help='Types of the deployment graph in order of execution' - ) - parser.add_argument( - '-n', - '--nodes', - type=int, - nargs='+', - help='Ids of the nodes to use for deployment.' - ) - parser.add_argument( - '-T', - '--task-names', - nargs='+', - help='List of deployment tasks to run.' - ) - parser.add_argument('-S', - '--subgraphs', - type=str, - nargs='+', - required=False, - help='List of subgraphs to execute' - 'Format is: ' - '[[/]]\ - [:/[]]') - return parser - - def get_options(self, parsed_args): - return { - 'graph_types': parsed_args.graph_types, - 'nodes': parsed_args.nodes, - 'task_names': parsed_args.task_names, - 'subgraphs': parsed_args.subgraphs - } - - -class GraphDownload(base.BaseCommand): - """Download deployment graph configuration.""" - entity_name = 'graph' - supported_file_formats = ('json', 'yaml') - - def get_parser(self, prog_name): - parser = super(GraphDownload, self).get_parser(prog_name) - tasks_level = parser.add_mutually_exclusive_group(required=True) - parser.add_argument('-e', - '--env', - type=int, - required=True, - help='Id of the environment') - - tasks_level.add_argument('-a', - '--all', - action="store_true", - required=False, - default=False, - help='Download merged graph for the ' - 'environment') - tasks_level.add_argument('-c', - '--cluster', - action="store_true", - required=False, - default=False, - help='Download cluster-specific tasks') - tasks_level.add_argument('-p', - '--plugins', - action="store_true", - required=False, - default=False, - help='Download plugins-specific tasks') - tasks_level.add_argument('-r', - '--release', - action="store_true", - required=False, - default=False, - help='Download release-specific tasks') - - parser.add_argument('-t', - '--graph-type', - type=str, - default=None, - required=False, - help='Graph type string') - parser.add_argument('-f', - '--file', - type=str, - required=False, - default=None, - help='File in {} format that contains tasks ' - 'data.'.format(self.supported_file_formats)) - parser.add_argument('--format', - required=False, - choices=self.supported_file_formats, - default='yaml', - help='Format of serialized tasks data. ' - 'Defaults to YAML.') - return parser - - @classmethod - def get_default_tasks_data_path(cls, env_id, task_level_name, file_format): - return os.path.join( - os.path.abspath(os.curdir), - '{}_graph_{}.{}'.format(task_level_name, env_id, file_format) - ) - - @classmethod - def write_tasks_to_file(cls, tasks_data, serializer, file_path): - return serializer.write_to_full_path(file_path, tasks_data) - - def take_action(self, args): - tasks_data = [] - tasks_level_name = '' - for tasks_level_name in ('all', 'cluster', 'release', 'plugins'): - if getattr(args, tasks_level_name): - tasks_data = self.client.download( - env_id=args.env, - level=tasks_level_name, - graph_type=args.graph_type - ) - break - - # write to file - file_path = args.file or self.get_default_tasks_data_path( - args.env, tasks_level_name, args.format) - graph_data_file_path = self.write_tasks_to_file( - tasks_data=tasks_data, - serializer=Serializer(format=args.format), - file_path=file_path) - - self.app.stdout.write( - "Tasks were downloaded to {0}\n".format(graph_data_file_path) - ) - - -class GraphList(base.BaseListCommand): - """List deployment graphs.""" - entity_name = 'graph' - columns = ("id", - "name", - "tasks", - "relations") - - def get_parser(self, prog_name): - parser = super(GraphList, self).get_parser(prog_name) - parser.add_argument( - '-e', - '--env', - type=int, - help='Id of the environment' - ) - parser.add_argument( - '--cluster', - dest='filters', - action='append_const', - const='cluster', - help='Include cluster-specific graphs' - ) - parser.add_argument( - '--plugins', - dest='filters', - action='append_const', - const='plugin', - help='Include plugins-specific graphs' - ) - parser.add_argument( - '--release', - dest='filters', - action='append_const', - const='release', - help='Include release-specific graphs' - ) - return parser - - def take_action(self, args): - data = self.client.list(env_id=args.env, filters=args.filters) - - # make table context applying special formatting to data copy - display_data = [] - for d in data: - d = d.copy() - d.update({ - 'relations': "\n".join( - 'as "{type}" to {model}(ID={model_id})'.format(**r) - for r in d['relations'] - ), - 'tasks': ', '.join(sorted(t['id'] for t in d['tasks'])) - }) - display_data.append(d) - - data = data_utils.get_display_data_multi(self.columns, display_data) - scolumn_ids = [self.columns.index(col) for col in args.sort_columns] - data.sort(key=lambda x: [x[scolumn_id] for scolumn_id in scolumn_ids]) - return self.columns, data - - -class GraphDelete(base.BaseCommand): - """Delete deployment graph.""" - entity_name = 'graph' - - def get_parser(self, prog_name): - parser = super(GraphDelete, self).get_parser(prog_name) - graph_class = parser.add_mutually_exclusive_group(required=True) - graph_class.add_argument('-e', - '--environment', - type=int, - help='Id of the environment') - graph_class.add_argument('-r', - '--release', - type=int, - help='Id of the release') - graph_class.add_argument('-p', - '--plugin', - type=int, - help='Id of the plugin') - parser.add_argument('-t', - '--graph-type', - required=True, - help='Type of the deployment graph') - return parser - - def take_action(self, parsed_args): - parameters_to_graph_class = ( - ('environment', 'clusters'), - ('release', 'releases'), - ('plugin', 'plugins'), - ) - - msg = '' - for parameter, graph_class in parameters_to_graph_class: - model_id = getattr(parsed_args, parameter) - if model_id: - self.client.delete( - related_model=graph_class, - related_id=model_id, - graph_type=parsed_args.graph_type - ) - msg = ("Deployment graph '{0}' for {1} with id {2} was " - "deleted.\n".format(parsed_args.graph_type, - parameter, - model_id)) - break - - self.app.stdout.write(msg) diff --git a/fuelclient/commands/health.py b/fuelclient/commands/health.py deleted file mode 100644 index 64c0b1d..0000000 --- a/fuelclient/commands/health.py +++ /dev/null @@ -1,177 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Vitalii Kulanov -# -# Licensed 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 abc -import six - -from fuelclient.commands import base -from fuelclient.common import data_utils - - -class HealthMixIn(object): - - entity_name = 'health' - - -class HealthTestSetsList(HealthMixIn, base.BaseListCommand): - """List of all available test sets for a given environment.""" - - columns = ("id", - "name") - - filters = {'environment_id': 'env'} - - def get_parser(self, prog_name): - parser = super(HealthTestSetsList, self).get_parser(prog_name) - parser.add_argument('-e', - '--env', - type=int, - required=True, - help='Id of the environment.') - return parser - - -class HealthCheckStart(HealthMixIn, base.BaseListCommand): - """Run specified test sets for a given environment.""" - - columns = ("id", - "testset", - "cluster_id") - - def get_parser(self, prog_name): - parser = super(HealthCheckStart, self).get_parser(prog_name) - parser.add_argument('-e', - '--env', - type=int, - required=True, - help='Id of the environment.') - parser.add_argument('--force', - action='store_true', - help='Force run health test sets.') - parser.add_argument('-t', - '--tests', - nargs='+', - help='Name of the test sets to run.') - parser.add_argument('--ostf-username', - default=None, - help='OSTF username.') - parser.add_argument('--ostf-password', - default=None, - help='OSTF password.') - parser.add_argument('--ostf-tenant-name', - default=None, - help='OSTF tenant name.') - return parser - - def take_action(self, parsed_args): - ostf_credentials = {} - if parsed_args.ostf_tenant_name is not None: - ostf_credentials['tenant'] = parsed_args.ostf_tenant_name - if parsed_args.ostf_username is not None: - ostf_credentials['username'] = parsed_args.ostf_username - if parsed_args.ostf_password is not None: - ostf_credentials['password'] = parsed_args.ostf_password - - if not ostf_credentials: - self.app.stdout.write("WARNING: ostf credentials are going to be " - "mandatory in the next release.\n") - - data = self.client.start(parsed_args.env, - ostf_credentials=ostf_credentials, - test_sets=parsed_args.tests, - force=parsed_args.force) - - msg = ("\nHealth check tests for environment with id {0} has been " - "started:\n".format(parsed_args.env)) - self.app.stdout.write(msg) - data = data_utils.get_display_data_multi(self.columns, data) - return self.columns, data - - -@six.add_metaclass(abc.ABCMeta) -class HealthCheckBaseAction(HealthMixIn, base.BaseShowCommand): - """Base class for implementing action over a given test set.""" - - columns = ("id", - "testset", - "cluster_id", - "status") - - @abc.abstractproperty - def action_status(self): - """String with the name of the action.""" - pass - - def take_action(self, parsed_args): - data = self.client.action(parsed_args.id, self.action_status) - - data = data_utils.get_display_data_single(self.columns, data) - return self.columns, data - - -class HealthCheckStop(HealthCheckBaseAction): - """Stop test set with given id.""" - - action_status = "stopped" - - -class HealthCheckRestart(HealthCheckBaseAction): - """Restart test set with given id.""" - - action_status = "restarted" - - -class HealthTestSetsStatusList(HealthMixIn, base.BaseListCommand): - """Show list of statuses of all test sets ever been executed in Fuel.""" - - columns = ("id", - "testset", - "cluster_id", - "status", - "started_at", - "ended_at") - - def get_parser(self, prog_name): - parser = super(HealthTestSetsStatusList, self).get_parser(prog_name) - parser.add_argument('-e', - '--env', - type=int, - help='Id of the environment.') - return parser - - def take_action(self, parsed_args): - data = self.client.get_status_all(parsed_args.env) - - data = data_utils.get_display_data_multi(self.columns, data) - return self.columns, data - - -class HealthTestSetsStatusShow(HealthMixIn, base.BaseShowCommand): - """Show status about a test set with given id.""" - - columns = ("id", - "testset", - "cluster_id", - "status", - "started_at", - "ended_at", - "tests") - - def take_action(self, parsed_args): - data = self.client.get_status_single(parsed_args.id) - - data = data_utils.get_display_data_single(self.columns, data) - return self.columns, data diff --git a/fuelclient/commands/network_group.py b/fuelclient/commands/network_group.py deleted file mode 100644 index 5e16acf..0000000 --- a/fuelclient/commands/network_group.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 cliff import show - -from fuelclient.cli.serializers import Serializer -from fuelclient.commands import base -from fuelclient.common import data_utils - - -_updatable_keys = ( - 'name', 'vlan', 'cidr', 'gateway', 'group_id', 'meta') - - -def get_args_for_update(params, serializer=None): - result = {} - for attr in _updatable_keys: - value = getattr(params, attr, None) - if value is not None: - result[attr] = value - - if 'meta' in result: - serializer = serializer or Serializer.from_params(params) - result['meta'] = serializer.deserialize(result['meta']) - - return result - - -class NetworkGroupMixin(object): - entity_name = 'network-group' - - @staticmethod - def add_parser_arguments(parser, for_update=False): - parser.add_argument( - '-N', '--node-group', - type=int, - required=not for_update, - help='ID of the network group' - ) - - parser.add_argument( - '-C', '--cidr', - type=str, - required=not for_update, - help='CIDR of the network' - ) - - parser.add_argument( - '-V', '--vlan', - type=int, - help='VLAN of the network', - ) - - if not for_update: - parser.add_argument( - '-r', '--release', - type=int, - help='Release ID this network group belongs to' - ) - - parser.add_argument( - '-g', '--gateway', - type=str, - help='Gateway of the network' - ) - - parser.add_argument( - '-m', '--meta', - type=str, - help='Metadata in JSON format to override default network metadata' - ) - - -class NetworkGroupList(NetworkGroupMixin, base.BaseListCommand): - """List all network groups.""" - - columns = ( - 'id', - 'name', - 'vlan_start', - 'cidr', - 'gateway', - 'group_id' - ) - - -class NetworkGroupShow(NetworkGroupMixin, base.BaseShowCommand): - """Show network group.""" - - columns = NetworkGroupList.columns + ('meta',) - - -class NetworkGroupCreate(NetworkGroupMixin, base.BaseShowCommand): - """Create a new network group.""" - - columns = NetworkGroupList.columns - - def get_parser(self, prog_name): - parser = show.ShowOne.get_parser(self, prog_name) - - parser.add_argument( - 'name', - type=str, - help='Name of the new network group' - ) - - self.add_parser_arguments(parser) - - return parser - - def take_action(self, parsed_args): - meta = None - if parsed_args.meta: - serializer = Serializer.from_params(parsed_args) - meta = serializer.deserialize(parsed_args.meta) - - net_group = self.client.create( - name=parsed_args.name, - release=parsed_args.release, - vlan=parsed_args.vlan, - cidr=parsed_args.cidr, - gateway=parsed_args.gateway, - group_id=parsed_args.node_group, - meta=meta) - - net_group = data_utils.get_display_data_single(self.columns, net_group) - return self.columns, net_group - - -class NetworkGroupUpdate(NetworkGroupMixin, base.BaseShowCommand): - """Set parameters for the specified network group.""" - - columns = NetworkGroupList.columns - - def get_parser(self, prog_name): - parser = show.ShowOne.get_parser(self, prog_name) - - parser.add_argument( - 'id', - type=int, - help='ID of the network group to update') - parser.add_argument( - '-n', - '--name', - type=str, - help='New name for network group') - - self.add_parser_arguments(parser, for_update=True) - - return parser - - def take_action(self, parsed_args): - to_update = get_args_for_update(parsed_args) - - network_group = self.client.update(parsed_args.id, **to_update) - network_group = data_utils.get_display_data_single( - self.columns, network_group) - - return self.columns, network_group - - -class NetworkGroupDelete(NetworkGroupMixin, base.BaseDeleteCommand): - """Delete specified network group.""" diff --git a/fuelclient/commands/network_template.py b/fuelclient/commands/network_template.py deleted file mode 100644 index 19efb5b..0000000 --- a/fuelclient/commands/network_template.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient.commands import base - - -class NetworkTemplateMixin(object): - - entity_name = 'environment' - - @staticmethod - def add_env_argument(parser): - parser.add_argument( - 'env', - type=int, - help='Id of the environment' - ) - - @staticmethod - def add_dir_argument(parser): - parser.add_argument( - '-d', '--dir', - type=str, - help='Directory for the network template' - ) - - @staticmethod - def add_file_argument(parser): - parser.add_argument( - '-f', '--file', - required=True, - type=str, - help='Yaml file containing the network template' - ) - - -class NetworkTemplateUpload(NetworkTemplateMixin, base.BaseCommand): - """Upload network configuration for specified environment.""" - - def get_parser(self, prog_name): - parser = super(NetworkTemplateUpload, self).get_parser(prog_name) - - self.add_env_argument(parser) - self.add_file_argument(parser) - - return parser - - def take_action(self, parsed_args): - - file_path = self.client.upload_network_template( - parsed_args.env, parsed_args.file) - msg = "Network template {0} has been uploaded.\n".format(file_path) - self.app.stdout.write(msg) - - -class NetworkTemplateDownload(NetworkTemplateMixin, base.BaseCommand): - """Download network configuration for specified environment.""" - - def get_parser(self, prog_name): - parser = super(NetworkTemplateDownload, self).get_parser(prog_name) - - self.add_dir_argument(parser) - self.add_env_argument(parser) - - return parser - - def take_action(self, parsed_args): - file_path = self.client.download_network_template( - parsed_args.env, parsed_args.dir) - - msg = ("Network template configuration for environment with id={0}" - " downloaded to {1}\n").format( - parsed_args.env, file_path) - self.app.stdout.write(msg) - - -class NetworkTemplateDelete(NetworkTemplateMixin, base.BaseCommand): - """Delete the network template of the specified environment.""" - - def get_parser(self, prog_name): - parser = super(NetworkTemplateDelete, self).get_parser(prog_name) - - self.add_env_argument(parser) - - return parser - - def take_action(self, parsed_args): - self.client.delete_network_template(parsed_args.env) - - msg = ("Network template for environment id={0}" - " has been deleted.\n".format(parsed_args.env)) - self.app.stdout.write(msg) diff --git a/fuelclient/commands/node.py b/fuelclient/commands/node.py deleted file mode 100644 index 7b42574..0000000 --- a/fuelclient/commands/node.py +++ /dev/null @@ -1,609 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 abc -import collections -import json -import operator -import os - -from oslo_utils import fileutils -import six - -from fuelclient.cli import error -from fuelclient.commands import base -from fuelclient.common import data_utils -from fuelclient import utils - - -class NodeMixIn(object): - entity_name = 'node' - - numa_fields = ( - 'numa_nodes', - 'supported_hugepages', - 'distances') - - supported_file_formats = ('json', 'yaml') - allowed_attr_types = ('attributes', 'disks', 'interfaces') - - @classmethod - def get_numa_topology_info(cls, data): - numa_topology_info = {} - numa_topology = data['meta'].get('numa_topology', {}) - for key in cls.numa_fields: - numa_topology_info[key] = numa_topology.get(key) - return numa_topology_info - - -@six.add_metaclass(abc.ABCMeta) -class BaseUploadCommand(NodeMixIn, base.BaseCommand): - """Base class for uploading attributes of a node.""" - - @abc.abstractproperty - def attribute(self): - """String with the name of the attribute.""" - pass - - @abc.abstractproperty - def uploader(self): - """Callable for uploading data.""" - pass - - def get_parser(self, prog_name): - parser = super(BaseUploadCommand, self).get_parser(prog_name) - parser.add_argument('id', - type=int, - help='Id of a node.') - parser.add_argument('-f', - '--format', - required=True, - choices=self.supported_file_formats, - help='Format of serialized ' - '{} data.'.format(self.attribute)) - parser.add_argument('-d', - '--directory', - required=False, - default=os.curdir, - help='Source directory. Defaults to ' - 'the current directory.') - - return parser - - def take_action(self, parsed_args): - directory = parsed_args.directory - - file_path = self.get_attributes_path(self.attribute, - parsed_args.format, - parsed_args.id, - directory) - - try: - with open(file_path, 'r') as stream: - attributes = data_utils.safe_load(parsed_args.format, - stream) - self.uploader(parsed_args.id, attributes) - except (OSError, IOError): - msg = 'Could not read configuration of {} at {}.' - raise error.InvalidFileException(msg.format(self.attribute, - file_path)) - - msg = ('Configuration of {t} for node with id ' - '{node} was loaded from {path}\n') - self.app.stdout.write(msg.format(t=self.attribute, - node=parsed_args.id, - path=file_path)) - - -@six.add_metaclass(abc.ABCMeta) -class BaseDownloadCommand(NodeMixIn, base.BaseCommand): - """Base class for downloading attributes of a node.""" - - @abc.abstractproperty - def attribute(self): - """String with the name of the attribute.""" - pass - - @abc.abstractproperty - def downloader(self): - """Callable for downloading data.""" - pass - - def get_parser(self, prog_name): - parser = super(BaseDownloadCommand, self).get_parser(prog_name) - parser.add_argument('id', - type=int, - help='Id of a node.') - parser.add_argument('-f', - '--format', - required=True, - choices=self.supported_file_formats, - help='Format of serialized ' - '{} data.'.format(self.attribute)) - parser.add_argument('-d', - '--directory', - required=False, - default=os.curdir, - help='Destination directory. Defaults to ' - 'the current directory.') - return parser - - def take_action(self, parsed_args): - directory = parsed_args.directory - attributes = self.downloader(parsed_args.id) - file_path = self.get_attributes_path(self.attribute, - parsed_args.format, - parsed_args.id, - directory) - - try: - fileutils.ensure_tree(os.path.dirname(file_path)) - fileutils.delete_if_exists(file_path) - - with open(file_path, 'w') as stream: - data_utils.safe_dump(parsed_args.format, stream, attributes) - except (OSError, IOError): - msg = 'Could not store configuration of {} at {}.' - raise error.InvalidFileException(msg.format(self.attribute, - file_path)) - - msg = ('Configuration of {t} for node with id ' - '{node} was stored in {path}\n') - self.app.stdout.write(msg.format(t=self.attribute, - node=parsed_args.id, - path=file_path)) - - -class NodeList(NodeMixIn, base.BaseListCommand): - """Show list of all available nodes.""" - - columns = ('id', - 'name', - 'status', - 'os_platform', - 'roles', - 'ip', - 'mac', - 'cluster', - 'platform_name', - 'online') - - filters = { - 'environment_id': 'env', - 'labels': 'labels' - } - - def get_parser(self, prog_name): - parser = super(NodeList, self).get_parser(prog_name) - - parser.add_argument( - '-e', - '--env', - type=int, - help='Show only nodes that are in the specified environment') - - parser.add_argument( - '-l', - '--labels', - type=utils.str_to_unicode, - nargs='+', - help='Show only nodes that have specific labels') - - return parser - - -class NodeShow(NodeMixIn, base.BaseShowCommand): - """Show info about node with given id.""" - - columns = ('id', - 'name', - 'status', - 'os_platform', - 'roles', - 'kernel_params', - 'pending_roles', - 'ip', - 'mac', - 'error_type', - 'pending_addition', - 'hostname', - 'fqdn', - 'platform_name', - 'cluster', - 'online', - 'progress', - 'pending_deletion', - 'group_id', - # TODO(romcheg): network_data mostly never fits the screen - # 'network_data', - 'manufacturer') - columns += NodeMixIn.numa_fields - - def take_action(self, parsed_args): - data = self.client.get_by_id(parsed_args.id) - numa_topology = self.get_numa_topology_info(data) - data.update(numa_topology) - data = data_utils.get_display_data_single(self.columns, data) - return self.columns, data - - -class NodeUpdate(NodeMixIn, base.BaseShowCommand): - """Change given attributes for a node.""" - - columns = NodeShow.columns - - def get_parser(self, prog_name): - parser = super(NodeUpdate, self).get_parser(prog_name) - - parser.add_argument( - '-H', - '--hostname', - type=str, - default=None, - help='New hostname for node') - - parser.add_argument( - '--name', - type=lambda x: x.decode('utf-8') if six.PY2 else x, - default=None, - help='New name for node') - - return parser - - def take_action(self, parsed_args): - updates = {} - for attr in self.client._updatable_attributes: - if getattr(parsed_args, attr, None): - updates[attr] = getattr(parsed_args, attr) - - updated_node = self.client.update( - parsed_args.id, **updates) - numa_topology = self.get_numa_topology_info(updated_node) - updated_node.update(numa_topology) - updated_node = data_utils.get_display_data_single( - self.columns, updated_node) - - return self.columns, updated_node - - -class NodeVmsList(NodeMixIn, base.BaseShowCommand): - """Show list vms for node.""" - - columns = ('vms_conf',) - - def take_action(self, parsed_args): - data = self.client.get_node_vms_conf(parsed_args.id) - data = data_utils.get_display_data_single(self.columns, data) - - return (self.columns, data) - - -class NodeCreateVMsConf(NodeMixIn, base.BaseCommand): - """Create vms config in metadata for selected node.""" - - def get_parser(self, prog_name): - parser = super(NodeCreateVMsConf, self).get_parser(prog_name) - parser.add_argument('id', type=int, - help='Id of the {0}.'.format(self.entity_name)) - parser.add_argument( - '--conf', - type=json.loads, - required=True, - nargs='+', - help='JSONs with VMs configuration', - ) - - return parser - - def take_action(self, parsed_args): - try: - confs = utils.parse_to_list_of_dicts(parsed_args.conf) - except TypeError: - raise error.BadDataException( - 'VM configuration should be a dictionary ' - 'or a list of dictionaries') - data = self.client.node_vms_create(parsed_args.id, confs) - msg = "{0}".format(data) - self.app.stdout.write(msg) - - -class NodeLabelList(NodeMixIn, base.BaseListCommand): - """Show list of all labels.""" - - columns = ( - 'node_id', - 'label_name', - 'label_value') - - @property - def default_sorting_by(self): - return ['node_id'] - - def get_parser(self, prog_name): - parser = super(NodeLabelList, self).get_parser(prog_name) - - parser.add_argument( - '-n', - '--nodes', - nargs='+', - help='Show labels for specific nodes') - - return parser - - def take_action(self, parsed_args): - data = self.client.get_all_labels_for_nodes( - node_ids=parsed_args.nodes) - data = data_utils.get_display_data_multi(self.columns, data) - data = self._sort_data(parsed_args, data) - - return self.columns, data - - -class NodeLabelSet(NodeMixIn, base.BaseCommand): - """Create or update specifc labels on nodes.""" - - def get_parser(self, prog_name): - parser = super(NodeLabelSet, self).get_parser(prog_name) - - parser.add_argument( - '-l', - '--labels', - required=True, - nargs='+', - help='List of labels for create or update') - - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument( - '-n', - '--nodes', - nargs='+', - help='Create or update labels only for specific nodes') - group.add_argument( - '--nodes-all', - action='store_true', - help='Create or update labels for all nodes') - - return parser - - def take_action(self, parsed_args): - nodes_ids = None if parsed_args.nodes_all else parsed_args.nodes - data = self.client.set_labels_for_nodes( - labels=parsed_args.labels, node_ids=nodes_ids) - msg = "Labels have been updated on nodes: {0} \n".format( - ','.join(data)) - self.app.stdout.write(msg) - - -class NodeLabelDelete(NodeMixIn, base.BaseCommand): - """Delete specific labels on nodes.""" - - def get_parser(self, prog_name): - parser = super(NodeLabelDelete, self).get_parser(prog_name) - - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument( - '-l', - '--labels', - nargs='+', - help='List of labels keys for delete') - group.add_argument( - '--labels-all', - action='store_true', - help='Delete all labels for node') - - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument( - '-n', - '--nodes', - nargs='+', - help='Delete labels only for specific nodes') - group.add_argument( - '--nodes-all', - action='store_true', - help='Delete labels for all nodes') - - return parser - - def take_action(self, parsed_args): - nodes_ids = None if parsed_args.nodes_all else parsed_args.nodes - labels = None if parsed_args.labels_all \ - else parsed_args.labels - data = self.client.delete_labels_for_nodes( - labels=labels, node_ids=nodes_ids) - msg = "Labels have been deleted on nodes: {0} \n".format( - ','.join(data)) - self.app.stdout.write(msg) - - -class NodeAttributesDownload(NodeMixIn, base.BaseCommand): - """Download node attributes.""" - - def get_parser(self, prog_name): - parser = super(NodeAttributesDownload, self).get_parser(prog_name) - - parser.add_argument( - 'id', type=int, help='Node ID') - parser.add_argument( - '--dir', type=str, help='Directory to save attributes') - - return parser - - def take_action(self, parsed_args): - file_path = self.client.download_attributes( - parsed_args.id, parsed_args.dir) - self.app.stdout.write( - "Attributes for node {0} were written to {1}" - .format(parsed_args.id, file_path) + os.linesep) - - -class NodeAttributesUpload(NodeMixIn, base.BaseCommand): - """Upload node attributes.""" - - def get_parser(self, prog_name): - parser = super(NodeAttributesUpload, self).get_parser(prog_name) - - parser.add_argument( - 'id', type=int, help='Node ID') - parser.add_argument( - '--dir', type=str, help='Directory to read attributes from') - - return parser - - def take_action(self, parsed_args): - self.client.upload_attributes(parsed_args.id, parsed_args.dir) - self.app.stdout.write( - "Attributes for node {0} were uploaded." - .format(parsed_args.id) + os.linesep) - - -class NodeAnsibleInventory(NodeMixIn, base.BaseCommand): - """Generate ansible inventory file based on the nodes list.""" - - def get_parser(self, prog_name): - parser = super(NodeAnsibleInventory, self).get_parser(prog_name) - - # if this is a required argument, we'll avoid ambiguity of having nodes - # of multiple different clusters in the same inventory file - parser.add_argument( - '-e', - '--env', - type=int, - required=True, - help='Use only nodes that are in the specified environment') - - parser.add_argument( - '-l', - '--labels', - type=utils.str_to_unicode, - nargs='+', - help='Use only nodes that have specific labels') - - return parser - - def take_action(self, parsed_args): - data = self.client.get_all(environment_id=parsed_args.env, - labels=parsed_args.labels) - - nodes_by_role = collections.defaultdict(list) - for node in data: - for role in node['roles']: - nodes_by_role[role].append(node) - - for role, nodes in sorted(nodes_by_role.items()): - self.app.stdout.write(u'[{role}]\n'.format(role=role)) - self.app.stdout.write( - u'\n'.join( - u'{name} ansible_host={ip}'.format(name=node['hostname'], - ip=node['ip']) - for node in sorted(nodes_by_role[role], - key=operator.itemgetter('hostname')) - ) - ) - self.app.stdout.write(u'\n\n') - - -class NodeInterfacesDownload(BaseDownloadCommand): - """Download and store configuration of interfaces for a node to a file.""" - - attribute = 'interfaces' - - @property - def downloader(self): - return self.client.get_interfaces - - -class NodeInterfacesGetDefault(BaseDownloadCommand): - """Download default configuration of interfaces for a node to a file.""" - - attribute = 'interfaces' - - @property - def downloader(self): - return self.client.get_default_interfaces - - -class NodeInterfacesUpload(BaseUploadCommand): - """Upload stored configuration of interfaces for a node from a file.""" - - attribute = 'interfaces' - - @property - def uploader(self): - return self.client.set_interfaces - - -class NodeDisksDownload(BaseDownloadCommand): - """Download and store configuration of disks for a node to a file.""" - - attribute = 'disks' - - @property - def downloader(self): - return self.client.get_disks - - -class NodeDisksGetDefault(BaseDownloadCommand): - """Download default configuration of disks for a node to a file.""" - - attribute = 'disks' - - @property - def downloader(self): - return self.client.get_default_disks - - -class NodeDisksUpload(BaseUploadCommand): - """Upload stored configuration of disks for a node from a file.""" - - attribute = 'disks' - - @property - def uploader(self): - return self.client.set_disks - - -class NodeUndiscover(NodeMixIn, base.BaseCommand): - """Remove nodes from database.""" - - def get_parser(self, prog_name): - parser = super(NodeUndiscover, self).get_parser(prog_name) - - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-e', - '--env', - type=int, - help='Id of environment to remove all nodes ' - 'from database.') - group.add_argument('-n', - '--node', - type=int, - help='Id of the node to remove from database.') - - parser.add_argument( - '-f', - '--force', - action='store_true', - help='Forces deletion of nodes from database ' - 'regardless of their state.') - - return parser - - def take_action(self, parsed_args): - node_ids = self.client.undiscover_nodes(env_id=parsed_args.env, - node_id=parsed_args.node, - force=parsed_args.force) - - self.app.stdout.write( - 'Nodes {0} were deleted from the database\n'.format(node_ids) - ) diff --git a/fuelclient/commands/openstack_config.py b/fuelclient/commands/openstack_config.py deleted file mode 100644 index 865b8e4..0000000 --- a/fuelclient/commands/openstack_config.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient.commands import base -from fuelclient.common import data_utils - - -class OpenstackConfigMixin(object): - entity_name = 'openstack-config' - - columns = ( - 'id', 'is_active', 'config_type', - 'cluster_id', 'node_id', 'node_role') - - @staticmethod - def add_env_arg(parser): - parser.add_argument( - '-e', '--env', - type=int, required=True, - help='Environment ID.') - - @staticmethod - def add_file_arg(parser): - parser.add_argument( - '--file', required=True, - type=str, help='YAML file that contains openstack configuration.') - - @staticmethod - def add_config_id_arg(parser): - parser.add_argument( - 'config', - type=int, help='Id of the OpenStack configuration.' - ) - - @staticmethod - def add_node_ids_arg(parser): - parser.add_argument( - '-n', '--node', - type=int, nargs='+', default=None, help='Ids of the nodes.' - ) - - @staticmethod - def add_node_role_arg(parser): - parser.add_argument( - '-r', '--role', - type=str, default=None, help='Role of the nodes.' - ) - - @staticmethod - def add_deleted_arg(parser): - parser.add_argument( - '-D', '--deleted', - type=bool, default=False, help='Show deleted configurations.' - ) - - @staticmethod - def add_force_arg(parser): - parser.add_argument( - '-f', '--force', - action='store_true', help='Force the update of the configuration.' - ) - - -class OpenstackConfigList(OpenstackConfigMixin, base.BaseListCommand): - """List all OpenStack configurations.""" - - def get_parser(self, prog_name): - parser = super(OpenstackConfigList, self).get_parser(prog_name) - - self.add_env_arg(parser) - self.add_node_ids_arg(parser) - self.add_node_role_arg(parser) - self.add_deleted_arg(parser) - - return parser - - def take_action(self, args): - data = self.client.get_filtered( - cluster_id=args.env, node_ids=args.node, - node_role=args.role, is_active=(not args.deleted)) - data = data_utils.get_display_data_multi(self.columns, data) - data = self._sort_data(args, data) - - return self.columns, data - - -class OpenstackConfigDownload(OpenstackConfigMixin, base.BaseCommand): - """Download specified configuration file.""" - - def get_parser(self, prog_name): - parser = super(OpenstackConfigDownload, self).get_parser(prog_name) - - self.add_config_id_arg(parser) - self.add_file_arg(parser) - - return parser - - def take_action(self, args): - file_path = self.client.download(args.config, args.file) - - msg = 'OpenStack configuration with id={c} '\ - 'downloaded to {p}.\n'.format(c=args.config, p=file_path) - - self.app.stdout.write(msg) - - -class OpenstackConfigUpload(OpenstackConfigMixin, base.BaseListCommand): - """Upload new OpenStack configuration from file.""" - - def get_parser(self, prog_name): - parser = super(OpenstackConfigUpload, self).get_parser(prog_name) - - self.add_env_arg(parser) - self.add_node_ids_arg(parser) - self.add_node_role_arg(parser) - self.add_file_arg(parser) - - return parser - - def take_action(self, args): - configs = self.client.upload(path=args.file, - cluster_id=args.env, - node_ids=args.node, - node_role=args.role) - - data = data_utils.get_display_data_multi(self.columns, configs) - return self.columns, data - - -class OpenstackConfigExecute(OpenstackConfigMixin, base.BaseCommand): - """Execute OpenStack configuration deployment.""" - - def get_parser(self, prog_name): - parser = super(OpenstackConfigExecute, self).get_parser(prog_name) - - self.add_env_arg(parser) - self.add_node_ids_arg(parser) - self.add_node_role_arg(parser) - self.add_force_arg(parser) - - return parser - - def take_action(self, args): - task = self.client.execute(cluster_id=args.env, - node_ids=args.node, - node_role=args.role, - force=args.force) - - msg = ('Deployment of the OpenStack configuration was started within ' - 'task with id {task_id}.\n').format(task_id=task['id']) - - self.app.stdout.write(msg) - - -class OpenstackConfigDelete(OpenstackConfigMixin, base.BaseCommand): - """Delete OpenStack configuration with given id.""" - - def get_parser(self, prog_name): - parser = super(OpenstackConfigDelete, self).get_parser(prog_name) - - self.add_config_id_arg(parser) - - return parser - - def take_action(self, args): - self.client.delete(args.config) - - msg = 'Openstack configuration with id {c} '\ - 'was deleted.\n'.format(c=args.config) - - self.app.stdout.write(msg) diff --git a/fuelclient/commands/plugins.py b/fuelclient/commands/plugins.py deleted file mode 100644 index ef1df34..0000000 --- a/fuelclient/commands/plugins.py +++ /dev/null @@ -1,117 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient.commands import base - - -class PluginsMixIn(object): - entity_name = 'plugins' - - @staticmethod - def add_plugin_file_argument(parser): - parser.add_argument( - 'file', - type=str, - help='Path to plugin file to install' - ) - - @staticmethod - def add_plugin_name_argument(parser): - parser.add_argument( - 'name', - type=str, - help='Name of plugin to remove' - ) - - @staticmethod - def add_plugin_version_argument(parser): - parser.add_argument( - 'version', - type=str, - help='Version of plugin to remove' - ) - - @staticmethod - def add_plugin_ids_argument(parser): - parser.add_argument( - 'ids', - type=int, - nargs='*', - metavar='plugin-id', - help='Synchronise only plugins with specified ids' - ) - - @staticmethod - def add_plugin_install_force_argument(parser): - parser.add_argument( - '-f', '--force', - action='store_true', - help='Used for reinstall plugin with the same version' - ) - - -class PluginsList(PluginsMixIn, base.BaseListCommand): - """Show list of all available plugins.""" - - columns = ('id', - 'name', - 'version', - 'package_version', - 'releases') - - -class PluginsSync(PluginsMixIn, base.BaseCommand): - """Synchronise plugins on file system with plugins in API service.""" - - def get_parser(self, prog_name): - parser = super(PluginsSync, self).get_parser(prog_name) - self.add_plugin_ids_argument(parser) - return parser - - def take_action(self, parsed_args): - ids = parsed_args.ids if len(parsed_args.ids) > 0 else None - self.client.sync(ids=ids) - self.app.stdout.write("Plugins were successfully synchronized.\n") - - -class PluginInstall(PluginsMixIn, base.BaseCommand): - """Install plugin archive and register in API service.""" - - def get_parser(self, prog_name): - parser = super(PluginInstall, self).get_parser(prog_name) - self.add_plugin_file_argument(parser) - self.add_plugin_install_force_argument(parser) - return parser - - def take_action(self, parsed_args): - self.client.install(parsed_args.file, force=parsed_args.force) - self.app.stdout.write( - "Plugin {0} was successfully installed.\n".format(parsed_args.file) - ) - - -class PluginRemove(PluginsMixIn, base.BaseCommand): - """Remove the plugin package, and update data in API service.""" - - def get_parser(self, prog_name): - parser = super(PluginRemove, self).get_parser(prog_name) - self.add_plugin_name_argument(parser) - self.add_plugin_version_argument(parser) - return parser - - def take_action(self, parsed_args): - self.client.remove(parsed_args.name, parsed_args.version) - self.app.stdout.write( - "Plugin {0} was successfully removed.\n".format(parsed_args.name) - ) diff --git a/fuelclient/commands/release.py b/fuelclient/commands/release.py deleted file mode 100644 index 5edebcf..0000000 --- a/fuelclient/commands/release.py +++ /dev/null @@ -1,146 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient.commands import base -from fuelclient.common import data_utils -from fuelclient import utils - - -class ReleaseMixIn(object): - entity_name = 'release' - - -class ReleaseList(ReleaseMixIn, base.BaseListCommand): - """Show list of all available releases.""" - - columns = ("id", - "name", - "state", - "operating_system", - "version") - - -class ReleaseReposList(ReleaseMixIn, base.BaseListCommand): - """Show repos for a given release.""" - - columns = ( - 'name', - 'priority', - 'uri', - 'section', - 'suite', - 'type') - - @property - def default_sorting_by(self): - return ['priority'] - - def get_parser(self, prog_name): - parser = super(ReleaseReposList, self).get_parser(prog_name) - parser.add_argument('id', type=int, - help='Id of the {0}.'.format(self.entity_name)) - return parser - - def take_action(self, parsed_args): - data = self.client.get_attributes_metadata_by_id(parsed_args.id) - repos = data["editable"]["repo_setup"]["repos"]["value"] - repos = data_utils.get_display_data_multi(self.columns, repos) - repos = self._sort_data(parsed_args, repos) - return self.columns, repos - - -class ReleaseReposUpdate(ReleaseMixIn, base.BaseCommand): - """Update repos for a given release.""" - - def get_parser(self, prog_name): - parser = super(ReleaseReposUpdate, self).get_parser(prog_name) - parser.add_argument( - '-f', '--file', action='store', required=True, - help='Input yaml file with list of repositories') - parser.add_argument( - 'id', type=int, help='Id of the {0}.'.format(self.entity_name)) - return parser - - def take_action(self, parsed_args): - data = self.client.get_attributes_metadata_by_id(parsed_args.id) - new_repos = utils.parse_yaml_file(parsed_args.file) - data["editable"]["repo_setup"]["repos"]["value"] = new_repos - self.client.update_attributes_metadata_by_id(parsed_args.id, data) - self.app.stdout.write( - "Repositories for the release with " - "id {rel_id} were set from {file}.\n".format( - rel_id=parsed_args.id, - file=parsed_args.file - ) - ) - - -class ReleaseComponentList(ReleaseMixIn, base.BaseListCommand): - """Show list of components for a given release.""" - - columns = ("name", - "requires", - "compatible", - "incompatible", - "default") - - @property - def default_sorting_by(self): - return ['name'] - - @staticmethod - def retrieve_predicates(statement): - """Retrieve predicates with respective 'items' components - - :param statement: the dictionary to extract predicate values from - :return: retrieval result as a string - """ - predicates = ('any_of', 'all_of', 'one_of', 'none_of') - for predicate in predicates: - if predicate in statement: - result = ', '.join(statement[predicate].get('items')) - return "{0} ({1})".format(predicate, result) - raise ValueError('Predicates not found.') - - @classmethod - def retrieve_data(cls, value): - """Retrieve names of components or predicates from nested data - - :param value: data to extract name or to retrieve predicates from - :return: names of components or predicates as a string - """ - if isinstance(value, list): - # get only "name" of components otherwise retrieve predicates - return ', '.join([v['name'] if 'name' in v - else cls.retrieve_predicates(v) - for v in value]) - return value - - def get_parser(self, prog_name): - parser = super(ReleaseComponentList, self).get_parser(prog_name) - parser.add_argument('id', type=int, - help='Id of the {0}.'.format(self.entity_name)) - return parser - - def take_action(self, parsed_args): - data = self.client.get_components_by_id(parsed_args.id) - # some keys (columns) can be missed in origin data - # then create them with respective '-' value - data = [{k: self.retrieve_data(d.get(k, '-')) for k in self.columns} - for d in data] - data = data_utils.get_display_data_multi(self.columns, data) - data = self._sort_data(parsed_args, data) - return self.columns, data diff --git a/fuelclient/commands/role.py b/fuelclient/commands/role.py deleted file mode 100644 index 82fe3bc..0000000 --- a/fuelclient/commands/role.py +++ /dev/null @@ -1,268 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Vitalii Kulanov -# -# Licensed 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 abc -import os - -from oslo_utils import fileutils -import six - -from fuelclient.cli import error -from fuelclient.commands import base -from fuelclient.common import data_utils - - -class RoleMixIn(object): - entity_name = 'role' - supported_file_formats = ('json', 'yaml') - fields_mapper = ( - ('env', 'clusters'), - ('release', 'releases') - ) - - def parse_model(self, args): - for param, role_class in self.fields_mapper: - model_id = getattr(args, param) - if model_id: - return role_class, model_id - - @staticmethod - def get_file_path(directory, owner_type, owner_id, role_name, file_format): - return os.path.join(os.path.abspath(directory), - '{owner}_{id}'.format(owner=owner_type, - id=owner_id), - '{}.{}'.format(role_name, file_format)) - - -@six.add_metaclass(abc.ABCMeta) -class BaseUploadCommand(RoleMixIn, base.BaseCommand): - """Base class for uploading metadata of a role.""" - - @abc.abstractproperty - def action(self): - """String with the name of the action.""" - pass - - @abc.abstractproperty - def uploader(self): - """Callable for uploading data.""" - pass - - def get_parser(self, prog_name): - parser = super(BaseUploadCommand, self).get_parser(prog_name) - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-r', - '--release', - type=int, - help='Id of the release') - group.add_argument('-e', - '--env', - type=int, - help='Id of the environment') - parser.add_argument('-n', - '--name', - required=True, - help='Name of role.') - parser.add_argument('-f', - '--format', - required=True, - choices=self.supported_file_formats, - help='Format of serialized role description.') - parser.add_argument('-d', - '--directory', - required=False, - default=os.path.curdir, - help='Source directory. Defaults to ' - 'the current directory.') - return parser - - def take_action(self, parsed_args): - model, model_id = self.parse_model(parsed_args) - params = {"owner_type": model, - "owner_id": model_id, - "role_name": parsed_args.name} - - file_path = self.get_file_path(parsed_args.directory, - model, - model_id, - parsed_args.name, - parsed_args.format) - - try: - with open(file_path, 'r') as stream: - data = data_utils.safe_load(parsed_args.format, stream) - self.uploader(data, **params) - except (OSError, IOError): - msg = "Could not read description for role '{}' at {}".format( - parsed_args.name, file_path) - raise error.InvalidFileException(msg) - - msg = ("Description of role '{role}' for {owner} with id {id} was " - "{action}d from {file_path}\n".format(role=parsed_args.name, - owner=model, - id=model_id, - action=self.action, - file_path=file_path)) - self.app.stdout.write(msg) - - -class RoleList(RoleMixIn, base.BaseListCommand): - """Show list of all available roles for release or cluster.""" - - columns = ("name", - "group", - "conflicts", - "description") - - @property - def default_sorting_by(self): - return ['name'] - - def get_parser(self, prog_name): - parser = super(RoleList, self).get_parser(prog_name) - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-r', - '--release', - type=int, - help='Id of the release') - group.add_argument('-e', - '--env', - type=int, - help='Id of the environment' - ) - return parser - - def take_action(self, parsed_args): - model, model_id = self.parse_model(parsed_args) - data = self.client.get_all(model, model_id) - - data = data_utils.get_display_data_multi(self.columns, data) - data = self._sort_data(parsed_args, data) - return self.columns, data - - -class RoleDownload(RoleMixIn, base.BaseCommand): - """Download full role description to file.""" - - def get_parser(self, prog_name): - parser = super(RoleDownload, self).get_parser(prog_name) - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-r', - '--release', - type=int, - help='Id of the release') - group.add_argument('-e', - '--env', - type=int, - help='Id of the environment' - ) - parser.add_argument('-n', - '--name', - required=True, - help='Name of role.') - parser.add_argument('-f', - '--format', - required=True, - choices=self.supported_file_formats, - help='Format of serialized role description.') - parser.add_argument('-d', - '--directory', - required=False, - default=os.path.curdir, - help='Destination directory. Defaults to ' - 'the current directory.') - return parser - - def take_action(self, parsed_args): - model, model_id = self.parse_model(parsed_args) - file_path = self.get_file_path(parsed_args.directory, - model, - model_id, - parsed_args.name, - parsed_args.format) - data = self.client.get_one(model, - model_id, - parsed_args.name) - - try: - fileutils.ensure_tree(os.path.dirname(file_path)) - fileutils.delete_if_exists(file_path) - - with open(file_path, 'w') as stream: - data_utils.safe_dump(parsed_args.format, stream, data) - except (OSError, IOError): - msg = ("Could not store description data " - "for role {} at {}".format(parsed_args.name, file_path)) - raise error.InvalidFileException(msg) - - msg = ("Description data of role '{}' within {} id {} " - "was stored in {}\n".format(parsed_args.name, - model, - model_id, - file_path)) - self.app.stdout.write(msg) - - -class RoleUpdate(BaseUploadCommand): - """Update a role from file description.""" - - action = "update" - - @property - def uploader(self): - return self.client.update - - -class RoleCreate(BaseUploadCommand): - """Create a role from file description""" - - action = "create" - - @property - def uploader(self): - return self.client.create - - -class RoleDelete(RoleMixIn, base.BaseCommand): - """Delete a role from release or cluster""" - - def get_parser(self, prog_name): - parser = super(RoleDelete, self).get_parser(prog_name) - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-r', - '--release', - type=int, - help='Id of the release') - group.add_argument('-e', - '--env', - type=int, - help='Id of the environment' - ) - parser.add_argument('-n', - '--name', - required=True, - help='Name of role.') - return parser - - def take_action(self, parsed_args): - model, model_id = self.parse_model(parsed_args) - self.client.delete(model, - model_id, - parsed_args.name) - - msg = "Role '{}' was deleted from {} with id {}\n".format( - parsed_args.name, model, model_id) - self.app.stdout.write(msg) diff --git a/fuelclient/commands/sequence.py b/fuelclient/commands/sequence.py deleted file mode 100644 index 9798357..0000000 --- a/fuelclient/commands/sequence.py +++ /dev/null @@ -1,203 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli import serializers -from fuelclient.commands import base -from fuelclient.common import data_utils - - -class SequenceMixIn(object): - entity_name = 'sequence' - - -class SequenceCreate(SequenceMixIn, base.show.ShowOne, base.BaseCommand): - """Create a new deployment sequence.""" - - columns = ("id", "release_id", "name") - - def get_parser(self, prog_name): - parser = super(SequenceCreate, self).get_parser(prog_name) - - parser.add_argument( - "-r", "--release", - type=int, - required=True, - help="Release object id, sequence will be linked to." - ) - parser.add_argument( - '-n', '--name', - required=True, - help='The unique name for sequence.' - ) - parser.add_argument( - '-t', '--graph-type', - dest='graph_types', - nargs='+', - required=True, - help='Graph types, which will be included to sequence.\n' - 'Note: Order is important.' - ) - return parser - - def take_action(self, args): - new_sequence = self.client.create( - args.release, args.name, args.graph_types - ) - self.app.stdout.write("Sequence was successfully created:\n") - data = data_utils.get_display_data_single(self.columns, new_sequence) - - return self.columns, data - - -class SequenceUpload(SequenceMixIn, base.show.ShowOne, base.BaseCommand): - """Upload a new deployment sequence.""" - - columns = ("id", "release_id", "name") - - def get_parser(self, prog_name): - parser = super(SequenceUpload, self).get_parser(prog_name) - - parser.add_argument( - "-r", "--release", - type=int, - required=True, - help="Release object id, sequence will be linked to." - ) - parser.add_argument( - '--file', - required=True, - help='YAML file which contains deployment sequence properties.' - ) - return parser - - def take_action(self, args): - serializer = serializers.FileFormatBasedSerializer() - new_sequence = self.client.upload( - args.release, serializer.read_from_file(args.file) - ) - self.app.stdout.write("Sequence was successfully created:\n") - data = data_utils.get_display_data_single(self.columns, new_sequence) - return self.columns, data - - -class SequenceDownload(SequenceMixIn, base.BaseCommand): - """Download deployment sequence data.""" - - def get_parser(self, prog_name): - parser = super(SequenceDownload, self).get_parser(prog_name) - - parser.add_argument( - "id", - type=int, - help="Sequence ID." - ) - parser.add_argument( - '--file', - help='The file path where data will be saved.' - ) - return parser - - def take_action(self, args): - data = self.client.download(args.id) - if args.file: - serializer = serializers.FileFormatBasedSerializer() - serializer.write_to_file(args.file, data) - else: - serializer = serializers.Serializer("yaml") - serializer.write_to_file(self.app.stdout, data) - - -class SequenceUpdate(SequenceMixIn, base.BaseShowCommand): - """Update existing sequence.""" - - columns = ("id", "name") - - def get_parser(self, prog_name): - parser = super(SequenceUpdate, self).get_parser(prog_name) - parser.add_argument( - '-n', '--name', - required=False, - help='The unique name for sequence.' - ) - parser.add_argument( - '-t', '--graph-type', - dest='graph_types', - nargs='+', - required=False, - help='Graph types, which will be included to sequence.\n' - 'Note: Order is important.' - ) - return parser - - def take_action(self, args): - sequence = self.client.update( - args.id, name=args.name, graph_types=args.graph_types - ) - - if sequence: - self.app.stdout.write("Sequence was successfully updated:\n") - data = data_utils.get_display_data_single(self.columns, sequence) - return self.columns, data - else: - self.app.stdout.write("Nothing to update.\n") - - -class SequenceDelete(SequenceMixIn, base.BaseDeleteCommand): - """Delete existing sequence.""" - - -class SequenceShow(SequenceMixIn, base.BaseShowCommand): - """Display information about sequence.""" - columns = ("id", "release_id", "name", "graphs") - - -class SequenceList(SequenceMixIn, base.BaseListCommand): - """Show list of all existing sequences.""" - columns = ("id", "release_id", "name") - filters = {'release': 'release', 'cluster': 'env'} - - def get_parser(self, prog_name): - parser = super(SequenceList, self).get_parser(prog_name) - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument( - '-r', '--release', - type=int, - help='The Release object ID.' - ) - group.add_argument( - '-e', '--env', - type=int, - help='The environment object id.' - ) - return parser - - -class SequenceExecute(SequenceMixIn, base.BaseTasksExecuteCommand): - """Executes sequence on specified environment.""" - - def get_parser(self, prog_name): - parser = super(SequenceExecute, self).get_parser(prog_name) - parser.add_argument( - 'id', - type=int, - help='Id of the Sequence.' - ) - return parser - - def get_options(self, parsed_args): - return { - 'sequence_id': parsed_args.id, - } diff --git a/fuelclient/commands/snapshot.py b/fuelclient/commands/snapshot.py deleted file mode 100644 index 7c8e105..0000000 --- a/fuelclient/commands/snapshot.py +++ /dev/null @@ -1,132 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Vitalii Kulanov -# -# Licensed 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 argparse -import os - -from oslo_utils import fileutils - -from fuelclient.cli import error -from fuelclient.commands import base -from fuelclient.common import data_utils -from fuelclient import utils - - -class SnapshotMixIn(object): - - entity_name = 'snapshot' - supported_file_formats = ('json', 'yaml') - - @staticmethod - def config_file(file_path): - if not utils.file_exists(file_path): - raise argparse.ArgumentTypeError( - 'File "{0}" does not exist'.format(file_path)) - return file_path - - @staticmethod - def get_config_path(directory, file_format): - return os.path.join(os.path.abspath(directory), - 'snapshot_conf.{}'.format(file_format)) - - -class SnapshotGenerate(SnapshotMixIn, base.BaseCommand): - """Generate diagnostic snapshot.""" - - def get_parser(self, prog_name): - parser = super(SnapshotGenerate, self).get_parser(prog_name) - parser.add_argument('-c', - '--config', - required=False, - type=self.config_file, - help='Configuration file.') - return parser - - def take_action(self, parsed_args): - file_path = parsed_args.config - - config = dict() - if file_path: - file_format = os.path.splitext(file_path)[1].lstrip('.') - try: - with open(file_path, 'r') as stream: - config = data_utils.safe_load(file_format, stream) - except (OSError, IOError): - msg = 'Could not read configuration at {}.' - raise error.InvalidFileException(msg.format(file_path)) - - result = self.client.create_snapshot(config) - - msg = "Diagnostic snapshot generation task with id {id} was started\n" - self.app.stdout.write(msg.format(id=result.id)) - - -class SnapshotConfigGetDefault(SnapshotMixIn, base.BaseCommand): - """Download default config to generate custom diagnostic snapshot.""" - - def get_parser(self, prog_name): - parser = super(SnapshotConfigGetDefault, self).get_parser(prog_name) - parser.add_argument('-f', - '--format', - required=True, - choices=self.supported_file_formats, - help='Format of serialized diagnostic snapshot ' - 'configuration data.') - parser.add_argument('-d', - '--directory', - required=False, - default=os.path.curdir, - help='Destination directory. Defaults to ' - 'the current directory.') - return parser - - def take_action(self, parsed_args): - file_path = self.get_config_path(parsed_args.directory, - parsed_args.format) - config = self.client.get_default_config() - - try: - fileutils.ensure_tree(os.path.dirname(file_path)) - fileutils.delete_if_exists(file_path) - - with open(file_path, 'w') as stream: - data_utils.safe_dump(parsed_args.format, stream, config) - except (OSError, IOError): - msg = 'Could not store configuration at {}.' - raise error.InvalidFileException(msg.format(file_path)) - - msg = "Configuration was stored in {path}\n" - self.app.stdout.write(msg.format(path=file_path)) - - -class SnapshotGetLink(SnapshotMixIn, base.BaseShowCommand): - """Show link to download diagnostic snapshot.""" - - columns = ('status', - 'link') - - def take_action(self, parsed_args): - data = self.client.get_by_id(parsed_args.id) - if data['name'] != 'dump': - msg = "Task with id {0} is not a snapshot generation task" - raise error.ActionException(msg.format(data['id'])) - if data['status'] != 'ready': - data['link'] = None - else: - data['link'] = self.client.connection.root + data['message'] - - data = data_utils.get_display_data_single(self.columns, data) - return self.columns, data diff --git a/fuelclient/commands/tag.py b/fuelclient/commands/tag.py deleted file mode 100644 index 8f22014..0000000 --- a/fuelclient/commands/tag.py +++ /dev/null @@ -1,265 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 abc -import os - -from oslo_utils import fileutils -import six - -from fuelclient.cli import error -from fuelclient.commands import base -from fuelclient.common import data_utils - - -class TagMixIn(object): - entity_name = 'tag' - supported_file_formats = ('json', 'yaml') - fields_mapper = ( - ('env', 'clusters'), - ('release', 'releases') - ) - - def parse_model(self, args): - for param, tag_class in self.fields_mapper: - model_id = getattr(args, param) - if model_id: - return tag_class, model_id - - @staticmethod - def get_file_path(directory, owner_type, owner_id, tag_name, file_format): - return os.path.join(os.path.abspath(directory), - '{owner}_{id}'.format(owner=owner_type, - id=owner_id), - '{}.{}'.format(tag_name, file_format)) - - -@six.add_metaclass(abc.ABCMeta) -class BaseUploadCommand(TagMixIn, base.BaseCommand): - """Base class for uploading metadata of a tag.""" - - @abc.abstractproperty - def action(self): - """String with the name of the action.""" - pass - - @abc.abstractproperty - def uploader(self): - """Callable for uploading data.""" - pass - - def get_parser(self, prog_name): - parser = super(BaseUploadCommand, self).get_parser(prog_name) - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-r', - '--release', - type=int, - help='Id of the release') - group.add_argument('-e', - '--env', - type=int, - help='Id of the environment') - parser.add_argument('-n', - '--name', - required=True, - help='Name of tag.') - parser.add_argument('-f', - '--format', - required=True, - choices=self.supported_file_formats, - help='Format of serialized tag description.') - parser.add_argument('-d', - '--directory', - required=False, - default=os.path.curdir, - help='Source directory. Defaults to ' - 'the current directory.') - return parser - - def take_action(self, parsed_args): - model, model_id = self.parse_model(parsed_args) - params = {"owner_type": model, - "owner_id": model_id, - "tag_name": parsed_args.name} - - file_path = self.get_file_path(parsed_args.directory, - model, - model_id, - parsed_args.name, - parsed_args.format) - - try: - with open(file_path, 'r') as stream: - data = data_utils.safe_load(parsed_args.format, stream) - self.uploader(data, **params) - except (OSError, IOError): - msg = "Could not read description for tag '{}' at {}".format( - parsed_args.name, file_path) - raise error.InvalidFileException(msg) - - msg = ("Description of tag '{tag}' for {owner} with id {id} was " - "{action}d from {file_path}\n".format(tag=parsed_args.name, - owner=model, - id=model_id, - action=self.action, - file_path=file_path)) - self.app.stdout.write(msg) - - -class TagList(TagMixIn, base.BaseListCommand): - """Show list of all available tags for release or cluster.""" - - columns = ("name", - "group", - "conflicts", - "description") - - @property - def default_sorting_by(self): - return ['name'] - - def get_parser(self, prog_name): - parser = super(TagList, self).get_parser(prog_name) - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-r', - '--release', - type=int, - help='Id of the release') - group.add_argument('-e', - '--env', - type=int, - help='Id of the environment') - return parser - - def take_action(self, parsed_args): - model, model_id = self.parse_model(parsed_args) - data = self.client.get_all(model, model_id) - - data = data_utils.get_display_data_multi(self.columns, data) - data = self._sort_data(parsed_args, data) - return self.columns, data - - -class TagDownload(TagMixIn, base.BaseCommand): - """Download full tag description to file.""" - - def get_parser(self, prog_name): - parser = super(TagDownload, self).get_parser(prog_name) - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-r', - '--release', - type=int, - help='Id of the release') - group.add_argument('-e', - '--env', - type=int, - help='Id of the environment') - parser.add_argument('-n', - '--name', - required=True, - help='Name of tag.') - parser.add_argument('-f', - '--format', - required=True, - choices=self.supported_file_formats, - help='Format of serialized tag description.') - parser.add_argument('-d', - '--directory', - required=False, - default=os.path.curdir, - help='Destination directory. Defaults to ' - 'the current directory.') - return parser - - def take_action(self, parsed_args): - model, model_id = self.parse_model(parsed_args) - file_path = self.get_file_path(parsed_args.directory, - model, - model_id, - parsed_args.name, - parsed_args.format) - data = self.client.get_tag(model, - model_id, - parsed_args.name) - - try: - fileutils.ensure_tree(os.path.dirname(file_path)) - fileutils.delete_if_exists(file_path) - - with open(file_path, 'w') as stream: - data_utils.safe_dump(parsed_args.format, stream, data) - except (OSError, IOError): - msg = ("Could not store description data " - "for tag {} at {}".format(parsed_args.name, file_path)) - raise error.InvalidFileException(msg) - - msg = ("Description data of tag '{}' within {} id {} " - "was stored in {}\n".format(parsed_args.name, - model, - model_id, - file_path)) - self.app.stdout.write(msg) - - -class TagUpdate(BaseUploadCommand): - """Update a tag from file description.""" - - action = "update" - - @property - def uploader(self): - return self.client.update - - -class TagCreate(BaseUploadCommand): - """Create a tag from file description""" - - action = "create" - - @property - def uploader(self): - return self.client.create - - -class TagDelete(TagMixIn, base.BaseCommand): - """Delete a tag from release or cluster""" - - def get_parser(self, prog_name): - parser = super(TagDelete, self).get_parser(prog_name) - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-r', - '--release', - type=int, - help='Id of the release') - group.add_argument('-e', - '--env', - type=int, - help='Id of the environment') - parser.add_argument('-n', - '--name', - required=True, - help='Name of tag.') - return parser - - def take_action(self, parsed_args): - model, model_id = self.parse_model(parsed_args) - self.client.delete(model, - model_id, - parsed_args.name) - - msg = "Tag '{}' was deleted from {} with id {}\n".format( - parsed_args.name, model, model_id) - self.app.stdout.write(msg) diff --git a/fuelclient/commands/task.py b/fuelclient/commands/task.py deleted file mode 100644 index 3d7a3af..0000000 --- a/fuelclient/commands/task.py +++ /dev/null @@ -1,309 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 - -from fuelclient.cli.serializers import Serializer -from fuelclient.commands import base -from fuelclient.common import data_utils - - -class TaskMixIn(object): - entity_name = 'task' - - @staticmethod - def add_file_arg(parser): - parser.add_argument( - '-f', - '--file', - required=False, - type=str, - help='Output file in YAML format.' - ) - - @classmethod - def write_info_to_file(cls, info_type, data, transaction_id, - serializer=None, file_path=None): - """Write additional info to the given path. - - :param info_type: deployment_info | cluster_settings | - network_configuration - :type info_type: str - :param data: data - :type data: list of dict - :param serializer: serializer - :param transaction_id: Transaction ID - :type transaction_id: str or int - :param file_path: path - :type file_path: str - :return: path to resulting file - :rtype: str - """ - serializer = serializer or Serializer() - if file_path: - return serializer.write_to_full_path( - file_path, - data - ) - else: - return serializer.write_to_path( - cls.get_default_info_path(info_type, transaction_id), - data - ) - - @staticmethod - def get_default_info_path(info_type, transaction_id): - """Generate default path for task additional info e.g. deployment info - - :param info_type: deployment_info | cluster_settings | - network_configuration - :type info_type: str - :param transaction_id: Transaction ID - :type transaction_id: str or int - :return: path - :rtype: str - """ - return os.path.join( - os.path.abspath(os.curdir), - "{info_type}_{transaction_id}".format( - info_type=info_type, - transaction_id=transaction_id) - ) - - def download_info_to_file(self, transaction_id, info_type, file_path): - """Get and save to path for task additional info e.g. deployment info - - :param transaction_id: Transaction ID - :type transaction_id: str or int - :param info_type: deployment_info | cluster_settings | - network_configuration - :type info_type: str - :param file_path: path - :type file_path: str - :return: path - :rtype: str - """ - data = self.client.download(transaction_id=transaction_id) - return self.write_info_to_file( - info_type=info_type, - data=data, - transaction_id=transaction_id, - serializer=Serializer(), - file_path=file_path) - - -class TaskInfoFileMixIn(TaskMixIn): - - def get_parser(self, prog_name): - parser = super(TaskInfoFileMixIn, self).get_parser( - prog_name) - parser.add_argument('id', type=int, help='Id of the Task.') - self.add_file_arg(parser) - return parser - - def download_info(self, parsed_args): - data_file_path = self.download_info_to_file( - transaction_id=parsed_args.id, - info_type=self.info_type, - file_path=parsed_args.file) - - return data_file_path - - -class TaskList(TaskMixIn, base.BaseListCommand): - """Show list of all available tasks.""" - columns = ('id', - 'status', - 'name', - 'graph_type', - 'cluster', - 'result', - 'dry_run', - 'progress') - filters = {'cluster_id': 'env', - 'statuses': 'statuses', - 'transaction_types': 'names'} - - def get_parser(self, prog_name): - parser = super(TaskList, self).get_parser(prog_name) - - parser.add_argument( - '-e', - '--env', - type=int, - help='Show list of tasks that belong to specified environment') - - parser.add_argument( - '-t', - '--statuses', - type=str, - choices=['pending', 'error', 'ready', 'running'], - nargs='+', - help='Show list of tasks with specified statuses') - - parser.add_argument( - '-n', - '--names', - type=str, - nargs='+', - help='Show list of tasks with specified names') - - return parser - - -class TaskShow(TaskMixIn, base.BaseShowCommand): - """Show info about task with given id.""" - columns = ('id', - 'uuid', - 'status', - 'name', - 'graph_type', - 'cluster', - 'result', - 'dry_run', - 'progress', - 'message') - - -class TaskDelete(TaskMixIn, base.BaseDeleteCommand): - """Delete task with given id.""" - - def get_parser(self, prog_name): - parser = super(TaskDelete, self).get_parser(prog_name) - - parser.add_argument('-f', - '--force', - action='store_true', - default=False, - help='Force deletion of a task without ' - 'considering its state.') - - return parser - - def take_action(self, parsed_args): - self.client.delete_by_id(parsed_args.id, parsed_args.force) - - msg = 'Task with id {ent_id} was deleted\n' - self.app.stdout.write(msg.format(ent_id=parsed_args.id)) - - -class TaskHistoryShow(TaskMixIn, base.BaseListCommand): - """Show deployment history about task with given ID.""" - - entity_name = 'deployment_history' - - columns = () - - def get_parser(self, prog_name): - parser = super(TaskHistoryShow, self).get_parser(prog_name) - - parser.add_argument('id', type=int, help='Id of the Task') - - parser.add_argument( - '-n', - '--nodes', - type=str, - nargs='+', - help='Show deployment history for specific nodes') - - parser.add_argument( - '-t', - '--statuses', - type=str, - choices=['pending', 'error', 'ready', 'running', 'skipped'], - nargs='+', - help='Show deployment history for specific statuses') - - parser.add_argument( - '-d', - '--tasks-names', - type=str, - nargs='+', - help='Show deployment history for specific deployment tasks names') - - parser.add_argument( - '-p', - '--show-parameters', - action='store_true', - default=False, - help='Show deployment tasks parameters') - parser.add_argument( - '--include-summary', - action='store_true', - default=False, - help='Show deployment tasks summary') - return parser - - def take_action(self, parsed_args): - # print parser - show_parameters = parsed_args.show_parameters - include_summary = parsed_args.include_summary - data = self.client.get_all( - transaction_id=parsed_args.id, - nodes=parsed_args.nodes, - statuses=parsed_args.statuses, - tasks_names=parsed_args.tasks_names, - include_summary=include_summary, - show_parameters=show_parameters - ) - if show_parameters: - self.columns = self.client.tasks_records_keys - else: - self.columns = self.client.history_records_keys - if include_summary: - self.columns += ('summary',) - data = data_utils.get_display_data_multi(self.columns, data) - return self.columns, data - - -class TaskNetworkConfigurationDownload(TaskInfoFileMixIn, base.BaseCommand): - """Save task network configuration to a file.""" - - entity_name = 'network-configuration' - info_type = 'network_configuration' - - def take_action(self, parsed_args): - self.app.stdout.write( - "Network configuration for task with id={0}" - " downloaded to {1}\n".format(parsed_args.id, - self.download_info(parsed_args)) - ) - - -class TaskDeploymentInfoDownload(TaskInfoFileMixIn, base.BaseCommand): - """Save task deployment info to a file.""" - - entity_name = 'deployment-info' - info_type = 'deployment_info' - - def take_action(self, parsed_args): - self.app.stdout.write( - "Deployment info for task with id={0}" - " downloaded to {1}\n".format(parsed_args.id, - self.download_info(parsed_args)) - ) - - -class TaskClusterSettingsDownload(TaskInfoFileMixIn, base.BaseCommand): - """Save task settings to a file.""" - - entity_name = 'cluster-settings' - info_type = 'cluster_settings' - - def take_action(self, parsed_args): - self.app.stdout.write( - "Cluster settings for task with id={0}" - " downloaded to {1}\n".format(parsed_args.id, - self.download_info(parsed_args)) - ) diff --git a/fuelclient/commands/vip.py b/fuelclient/commands/vip.py deleted file mode 100644 index 5f070f7..0000000 --- a/fuelclient/commands/vip.py +++ /dev/null @@ -1,182 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient.commands import base - - -class VipMixIn(object): - entity_name = 'vip' - - @staticmethod - def add_env_id_arg(parser): - parser.add_argument( - '-e', - '--env', - type=int, - required=True, - help='Environment identifier' - ) - - @staticmethod - def add_network_id_arg(parser): - parser.add_argument( - "-n", - "--network", - type=int, - default=None, - required=False, - help="Network identifier" - ) - - -class VipDownload(VipMixIn, base.BaseCommand): - """Download VIPs configuration.""" - - @staticmethod - def add_ip_address_id_arg(parser): - parser.add_argument( - "-a", - "--ip-address-id", - type=int, - default=None, - required=False, - help="IP address entity identifier" - ) - - @staticmethod - def add_network_role_arg(parser): - parser.add_argument( - "-r", - "--network-role", - type=str, - default=None, - required=False, - help="Network role string" - ) - - @staticmethod - def add_file_arg(parser): - parser.add_argument( - '-f', - '--file', - type=str, - required=False, - default=None, - help='YAML file that contains openstack configuration.' - ) - - def get_parser(self, prog_name): - parser = super(VipDownload, self).get_parser(prog_name) - self.add_env_id_arg(parser) - self.add_ip_address_id_arg(parser) - self.add_file_arg(parser) - self.add_network_id_arg(parser) - self.add_network_role_arg(parser) - return parser - - def take_action(self, args): - vips_data_file_path = self.client.download( - env_id=args.env, - ip_addr_id=args.ip_address_id, - network_id=args.network, - network_role=args.network_role, - file_path=args.file - ) - - self.app.stdout.write( - "VIP configuration for environment with id={0}" - " downloaded to {1}".format(args.env, vips_data_file_path) - ) - - -class VipUpload(VipMixIn, base.BaseCommand): - """Upload new VIPs configuration from file.""" - - @staticmethod - def add_file_arg(parser): - parser.add_argument( - '-f', - '--file', - required=True, - type=str, - help='YAML file that contains openstack configuration.' - ) - - def get_parser(self, prog_name): - parser = super(VipUpload, self).get_parser(prog_name) - self.add_env_id_arg(parser) - self.add_file_arg(parser) - return parser - - def take_action(self, args): - self.client.upload(env_id=args.env, file_path=args.file) - self.app.stdout.write("VIP configuration uploaded.") - - -class VipCreate(VipMixIn, base.BaseCommand): - """Create VIP""" - - @staticmethod - def add_vip_name_arg(parser): - parser.add_argument( - '-N', - '--name', - required=True, - type=str, - help="VIP name" - ) - - @staticmethod - def add_ip_addr_arg(parser): - parser.add_argument( - '-a', - '--address', - required=True, - type=str, - help="IP-address for the VIP" - ) - - @staticmethod - def add_vip_namespace_arg(parser): - parser.add_argument( - '--namespace', - required=False, - type=str, - help="VIP namespace" - ) - - def get_parser(self, prog_name): - parser = super(VipCreate, self).get_parser(prog_name) - self.add_env_id_arg(parser) - self.add_network_id_arg(parser) - self.add_vip_name_arg(parser) - self.add_ip_addr_arg(parser) - self.add_vip_namespace_arg(parser) - return parser - - def take_action(self, args): - vip_kwargs = { - "env_id": args.env, - "ip_addr": args.address, - "network": args.network, - "vip_name": args.name, - } - if args.namespace is not None: - vip_kwargs['vip_namespace'] = args.namespace - - self.client.create(**vip_kwargs) - - self.app.stdout.write("VIP has been created.") diff --git a/fuelclient/common/__init__.py b/fuelclient/common/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fuelclient/common/data_utils.py b/fuelclient/common/data_utils.py deleted file mode 100644 index 7b52d68..0000000 --- a/fuelclient/common/data_utils.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 json -import os -import yaml - -from fuelclient import utils - - -def get_display_data_single(fields, data, missing_field_value=None): - """Performs slicing of data by set of given fields - - :param fields: Iterable containing names of fields to be retrieved - from data - :param data: Collection of JSON objects representing some - external entities - :param missing_field_value: the value will be used for all missing fields - - :return: list containing the collection of values of the - supplied attributes. - - """ - return [data.get(field, missing_field_value) for field in fields] - - -def get_display_data_multi(fields, data): - """Performs slice of data by set of given fields for multiple objects.""" - - return [get_display_data_single(fields, elem) for elem in data] - - -def safe_load(data_format, stream): - loaders = {'json': utils.safe_deserialize(json.load), - 'yaml': utils.safe_deserialize(yaml.safe_load)} - - if data_format not in loaders: - raise ValueError('Unsupported data format.') - - loader = loaders[data_format] - return loader(stream) - - -def safe_dump(data_format, stream, data): - # The reason these dumpers are assigned to individual variables is - # making PEP8 check happy. - yaml_dumper = lambda data, stream: yaml.safe_dump(data, - stream, - default_flow_style=False) - json_dumper = lambda data, stream: json.dump(data, stream, indent=4) - dumpers = {'json': json_dumper, - 'yaml': yaml_dumper} - - if data_format not in dumpers: - raise ValueError('Unsupported data format.') - - dumper = dumpers[data_format] - dumper(data, stream) - - -def read_from_file(file_path): - data_format = os.path.splitext(file_path)[1].lstrip('.') - with open(file_path, 'r') as stream: - return safe_load(data_format, stream) - - -def write_to_file(file_path, data): - data_format = os.path.splitext(file_path)[1].lstrip('.') - with open(file_path, 'w') as stream: - safe_dump(data_format, stream, data) diff --git a/fuelclient/consts.py b/fuelclient/consts.py deleted file mode 100644 index f76aebc..0000000 --- a/fuelclient/consts.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 collections import namedtuple - - -def Enum(*values, **kwargs): - names = kwargs.get('names') - if names: - return namedtuple('Enum', names)(*values) - return namedtuple('Enum', values)(*values) - - -SERIALIZATION_FORMAT_FLAG = 'serialization_format' - -TASK_STATUSES = Enum( - 'error', - 'pending', - 'ready', - 'running' -) diff --git a/fuelclient/fuel_client.yaml b/fuelclient/fuel_client.yaml deleted file mode 100644 index c89b3f3..0000000 --- a/fuelclient/fuel_client.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Connection settings -SERVER_ADDRESS: "127.0.0.1" -SERVER_PORT: "8000" -OS_USERNAME: -OS_PASSWORD: -# There's a need to provide default value for -# tenant name until fuel-library is updated. -# After that, it will be removed. -OS_TENANT_NAME: "admin" -HTTP_PROXY: null -HTTP_TIMEOUT: 10 - -# Performance tests settings -PERFORMANCE_PROFILING_TESTS: 0 -PERF_TESTS_PATHS: - perf_tests_base: "/tmp/fuelclient_performance_tests/tests/" - last_performance_test: "/tmp/fuelclient_performance_tests/tests/last/" - perf_tests_results: "/tmp/fuelclient_performance_tests/results/" diff --git a/fuelclient/fuelclient_settings.py b/fuelclient/fuelclient_settings.py deleted file mode 100644 index 9a94652..0000000 --- a/fuelclient/fuelclient_settings.py +++ /dev/null @@ -1,198 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2013-2014 Mirantis, Inc. -# -# Licensed 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 pkg_resources -import shutil -import sys - -import six -import yaml - -from fuelclient.cli import error - - -_SETTINGS = None - -# Format: old parameter: new parameter or None -DEPRECATION_TABLE = {'LISTEN_PORT': 'SERVER_PORT', - 'KEYSTONE_USER': 'OS_USERNAME', - 'KEYSTONE_PASS': 'OS_PASSWORD'} - -# Format: parameter: fallback parameter -FALLBACK_TABLE = {DEPRECATION_TABLE[p]: p for p in DEPRECATION_TABLE} - - -class FuelClientSettings(object): - """Represents a model of Fuel Clients settings - - Default settings are saved to $XDG_CONFIG_HOME/fuel/fuel_client.yaml on - the first run. If $XDG_CONFIG_HOME is not set, ~/.config/ directory is - used by default. - - Custom settings may be stored in any YAML-formatted file the path to - which should be supplied via the $FUELCLIENT_CUSTOM_SETTINGS environment - variable. Custom settings override default ones. - - Top level values may also be set as environment variables, e.g. - export SERVER_PORT=8080. These values have the highest priority. - - """ - def __init__(self): - settings_files = [] - - user_conf_dir = os.getenv('XDG_CONFIG_HOME', - os.path.expanduser('~/.config/')) - - # Look up for a default file distributed with the source code - default_settings = pkg_resources.resource_filename('fuelclient', - 'fuel_client.yaml') - - self.user_settings = os.path.join(user_conf_dir, 'fuel', - 'fuel_client.yaml') - custom_settings = os.getenv('FUELCLIENT_CUSTOM_SETTINGS') - - if not os.path.exists(self.user_settings) and not custom_settings: - self.populate_default_settings(default_settings, - self.user_settings) - six.print_('Settings for Fuel Client have been saved to {0}.\n' - 'Consider changing default values to the ones which ' - 'are appropriate for you.'.format(self.user_settings)) - - self._add_file_if_exists(default_settings, settings_files) - self._add_file_if_exists(self.user_settings, settings_files) - - # Add a custom settings file specified by user - self._add_file_if_exists(custom_settings, settings_files) - - self.config = {} - for sf in settings_files: - try: - self._update_from_file(sf) - except Exception as e: - msg = ('Error while reading config file ' - '%(file)s: %(err)s') % {'file': sf, 'err': str(e)} - - raise error.SettingsException(msg) - - self._update_from_env() - self._check_deprecated() - - def _add_file_if_exists(self, path_to_file, file_list): - if path_to_file and os.access(path_to_file, os.R_OK): - file_list.append(path_to_file) - - def _update_from_file(self, path): - with open(path, 'r') as custom_config: - self.config.update( - yaml.load(custom_config.read()) - ) - - def _update_from_env(self): - for k in self.config: - if k in os.environ: - self.config[k] = os.environ[k] - - def _print_deprecation_warning(self, old_option, new_option=None): - """Print deprecation warning for an option.""" - - deprecation_tpl = ('DEPRECATION WARNING: {} parameter was ' - 'deprecated and will not be supported in the next ' - 'version of python-fuelclient.') - replace_tpl = ' Please replace this parameter with {}' - - deprecation = deprecation_tpl.format(old_option) - replace = '' if new_option is None else replace_tpl.format(new_option) - - six.print_(deprecation, end='', file=sys.stderr) - six.print_(replace, file=sys.stderr) - - def _check_deprecated(self): - """Looks for deprecated options in user's configuration.""" - - dep_opts = [opt for opt in self.config if opt in DEPRECATION_TABLE] - - for opt in dep_opts: - - new_opt = DEPRECATION_TABLE.get(opt) - - # Clean up new option if it was not set by a user - # Produce a warning, if both old and new options are set. - if self.config.get(new_opt) is None: - self.config.pop(new_opt, None) - else: - six.print_('WARNING: configuration contains both {old} and ' - '{new} options set. Since {old} was deprecated, ' - 'only the value of {new} ' - 'will be used.'.format(old=opt, new=new_opt), - file=sys.stderr - ) - - self._print_deprecation_warning(opt, new_opt) - - def populate_default_settings(self, source, destination): - """Puts default configuration file to a user's home directory.""" - - try: - dst_dir = os.path.dirname(destination) - - if not os.path.exists(dst_dir): - os.makedirs(dst_dir, 0o700) - - shutil.copy(source, destination) - os.chmod(destination, 0o600) - except (IOError, OSError): - msg = ('Could not save settings to {0}. Please make sure the ' - 'directory is writable') - raise error.SettingsException(msg.format(dst_dir)) - - def update_from_command_line_options(self, options): - """Update parameters from valid command line options.""" - - for param in self.config: - opt_name = param.lower() - - value = getattr(options, opt_name, None) - if value is not None: - self.config[param] = value - - def dump(self): - return yaml.dump(self.config) - - def __getattr__(self, name): - if name in self.config: - return self.config[name] - - if name in FALLBACK_TABLE: - return self.config[FALLBACK_TABLE[name]] - - raise error.SettingsException('Value for {0} option is not ' - 'configured'.format(name)) - - def __repr__(self): - return '' - - -def _init_settings(): - global _SETTINGS - _SETTINGS = FuelClientSettings() - - -def get_settings(): - if _SETTINGS is None: - _init_settings() - - return _SETTINGS diff --git a/fuelclient/hooks.py b/fuelclient/hooks.py deleted file mode 100644 index 5b16a78..0000000 --- a/fuelclient/hooks.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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. - - -def setup_hook(config): - import pbr - import pbr.packaging - - # this monkey patch is to avoid appending git version to version - pbr.packaging._get_version_from_git = lambda pre_version: pre_version diff --git a/fuelclient/main.py b/fuelclient/main.py deleted file mode 100644 index 9843552..0000000 --- a/fuelclient/main.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 logging -import sys - -from cliff import app -from cliff.commandmanager import CommandManager - -from fuelclient import fuelclient_settings -from fuelclient import utils - - -LOG = logging.getLogger(__name__) - - -class FuelClient(app.App): - """Main cliff application class. - - Performs initialization of the command manager and - configuration of basic engines. - - """ - - def build_option_parser(self, description, version, argparse_kwargs=None): - """Overrides default options for backwards compatibility.""" - - p_inst = super(FuelClient, self) - parser = p_inst.build_option_parser(description=description, - version=version, - argparse_kwargs=argparse_kwargs) - - utils.add_os_cli_parameters(parser) - - return parser - - def configure_logging(self): - super(FuelClient, self).configure_logging() - - # there is issue with management url processing by keystone client - # code in our workflow, so we have to mute appropriate keystone - # loggers in order to get rid from unprocessable errors - logging.getLogger('keystoneclient.httpclient').setLevel(logging.ERROR) - - # increase level of loggin for urllib3 to avoid of displaying - # of useless messages. List of logger names is needed for - # consistency on different execution environments that could have - # installed requests packages (which is used urllib3) of different - # versions in turn - for logger_name in ('requests.packages.urllib3.connectionpool', - 'urllib3.connectionpool'): - logging.getLogger(logger_name).setLevel(logging.WARNING) - - def run(self, argv): - options, _ = self.parser.parse_known_args(argv) - - settings = fuelclient_settings.get_settings() - settings.update_from_command_line_options(options) - - return super(FuelClient, self).run(argv) - - -def main(argv=sys.argv[1:]): - fuelclient_app = FuelClient( - description='Command line interface and Python API wrapper for Fuel.', - version='10.0.0', - command_manager=CommandManager('fuelclient', convert_underscores=True), - deferred_help=True - ) - return fuelclient_app.run(argv) diff --git a/fuelclient/objects/__init__.py b/fuelclient/objects/__init__.py deleted file mode 100644 index 157cccc..0000000 --- a/fuelclient/objects/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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. - -"""fuelclient.objects sub-module contains classes that mirror -functionality from nailgun objects. -""" - -from fuelclient.objects.base import BaseObject -from fuelclient.objects.environment import Environment -from fuelclient.objects.extension import Extension -from fuelclient.objects.health import Health -from fuelclient.objects.node import Node -from fuelclient.objects.node import NodeCollection -from fuelclient.objects.openstack_config import OpenstackConfig -from fuelclient.objects.release import Release -from fuelclient.objects.role import Role -from fuelclient.objects.task import DeployTask -from fuelclient.objects.task import SnapshotTask -from fuelclient.objects.task import Task -from fuelclient.objects.tag import Tag -from fuelclient.objects.fuelversion import FuelVersion -from fuelclient.objects.network_group import NetworkGroup -from fuelclient.objects.plugins import Plugins -from fuelclient.objects.sequence import Sequence diff --git a/fuelclient/objects/base.py b/fuelclient/objects/base.py deleted file mode 100644 index 30a2980..0000000 --- a/fuelclient/objects/base.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli.serializers import Serializer -from fuelclient.client import DefaultAPIClient - - -class BaseObject(object): - """BaseObject class - base class for fuelclient.objects object classes - - 'class_api_path' - url path to object handler on Nailgun server. - 'instance_api_path' - url path template which formatted with object id - returns only one serialized object. - 'connection' - 'APIClient' class instance from fuelclient.client - """ - class_api_path = None - instance_api_path = None - connection = DefaultAPIClient - - def __init__(self, obj_id, **kwargs): - self.connection = DefaultAPIClient - self.serializer = Serializer.from_params(kwargs.get('params')) - self.id = obj_id - self._data = None - - @classmethod - def init_with_data(cls, data): - instance = cls(data["id"]) - instance._data = data - return instance - - @classmethod - def get_by_ids(cls, ids): - return map(cls, ids) - - def update(self): - self._data = self.connection.get_request( - self.instance_api_path.format(self.id)) - - def get_fresh_data(self): - self.update() - return self.data - - @property - def data(self): - if self._data is None: - return self.get_fresh_data() - else: - return self._data - - @classmethod - def get_all_data(cls, **kwargs): - return cls.connection.get_request(cls.class_api_path, params=kwargs) - - @classmethod - def get_all(cls, **kwargs): - return map(cls.init_with_data, cls.get_all_data(**kwargs)) diff --git a/fuelclient/objects/environment.py b/fuelclient/objects/environment.py deleted file mode 100644 index 79d2e65..0000000 --- a/fuelclient/objects/environment.py +++ /dev/null @@ -1,646 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 operator import attrgetter -import os -import shutil - -from fuelclient.cli import error -from fuelclient.cli.serializers import listdir_without_extensions -from fuelclient.objects.base import BaseObject -from fuelclient.objects.task import DeployTask -from fuelclient.objects.task import Task - - -class Environment(BaseObject): - - class_api_path = "clusters/" - instance_api_path = "clusters/{0}/" - deployment_tasks_path = 'clusters/{0}/deployment_tasks' - deployment_tasks_graph_path = 'clusters/{0}/deploy_tasks/graph.gv' - attributes_path = 'clusters/{0}/attributes' - network_template_path = 'clusters/{0}/network_configuration/template' - - @classmethod - def create(cls, name, release_id, net_segment_type): - data = { - "nodes": [], - "tasks": [], - "name": name, - "release_id": release_id, - "net_segment_type": net_segment_type, - } - - data = cls.connection.post_request("clusters/", data) - return cls.init_with_data(data) - - def __init__(self, *args, **kwargs): - super(Environment, self).__init__(*args, **kwargs) - self._testruns_ids = [] - - def set(self, data): - return self.connection.put_request( - "clusters/{0}/".format(self.id), - data - ) - - def delete(self): - return self.connection.delete_request( - "clusters/{0}/".format(self.id) - ) - - def assign(self, nodes, roles): - return self.connection.post_request( - "clusters/{0}/assignment/".format(self.id), - [{'id': node.id, 'roles': roles} for node in nodes] - ) - - def unassign(self, nodes): - return self.connection.post_request( - "clusters/{0}/unassignment/".format(self.id), - [{"id": n} for n in nodes] - ) - - def get_all_nodes(self): - from fuelclient.objects.node import Node - return sorted(map( - Node.init_with_data, - self.connection.get_request( - "nodes/?cluster_id={0}".format(self.id) - ) - ), key=attrgetter('id')) - - def unassign_all(self): - nodes = self.get_all_nodes() - if not nodes: - raise error.ActionException( - "Environment with id={0} doesn't have nodes to remove." - .format(self.id) - ) - return self.connection.post_request( - "clusters/{0}/unassignment/".format(self.id), - [{"id": n.id} for n in nodes] - ) - - def deploy_changes(self, dry_run=False, noop_run=False): - deploy_data = self.connection.put_request( - "clusters/{0}/changes".format(self.id), - {}, dry_run=int(dry_run), noop_run=int(noop_run) - ) - return DeployTask.init_with_data(deploy_data) - - def redeploy_changes(self, dry_run=False, noop_run=False): - deploy_data = self.connection.put_request( - "clusters/{0}/changes/redeploy".format(self.id), - {}, dry_run=int(dry_run), noop_run=int(noop_run) - ) - return DeployTask.init_with_data(deploy_data) - - def get_network_data_path(self, directory=os.curdir): - return os.path.join( - os.path.abspath(directory), - "network_{0}".format(self.id) - ) - - def get_settings_data_path(self, directory=os.curdir): - return os.path.join( - os.path.abspath(directory), - "settings_{0}".format(self.id) - ) - - def get_network_template_data_path(self, directory=None): - directory = directory or os.curdir - return os.path.join( - os.path.abspath(directory), - "network_template_{0}".format(self.id) - ) - - def write_network_data(self, network_data, directory=os.curdir, - serializer=None): - self._check_dir(directory) - return (serializer or self.serializer).write_to_path( - self.get_network_data_path(directory), - network_data - ) - - def write_settings_data(self, settings_data, directory=os.curdir, - serializer=None): - self._check_dir(directory) - return (serializer or self.serializer).write_to_path( - self.get_settings_data_path(directory), - settings_data - ) - - def write_network_template_data(self, template_data, directory=None, - serializer=None): - directory = directory or os.curdir - return (serializer or self.serializer).write_to_path( - self.get_network_template_data_path(directory), - template_data - ) - - def read_network_data(self, directory=os.curdir, - serializer=None): - self._check_dir(directory) - network_file_path = self.get_network_data_path(directory) - return (serializer or self.serializer).read_from_file( - network_file_path) - - def read_settings_data(self, directory=os.curdir, serializer=None): - self._check_dir(directory) - settings_file_path = self.get_settings_data_path(directory) - return (serializer or self.serializer).read_from_file( - settings_file_path) - - def _check_file_path(self, file_path): - if not os.path.exists(file_path): - raise error.InvalidFileException( - "File '{0}' doesn't exist.".format(file_path)) - - def _check_dir(self, directory): - if not os.path.exists(directory): - raise error.InvalidDirectoryException( - "Directory '{0}' doesn't exist.".format(directory)) - if not os.path.isdir(directory): - raise error.InvalidDirectoryException( - "Error: '{0}' is not a directory.".format(directory)) - - def read_network_template_data(self, directory=os.curdir, - serializer=None): - """Used by 'fuel' command line utility.""" - self._check_dir(directory) - network_template_file_path = self.get_network_template_data_path( - directory) - return (serializer or self.serializer).\ - read_from_file(network_template_file_path) - - def read_network_template_data_from_file(self, file_path=None, - serializer=None): - """Used by 'fuel2' command line utility.""" - return (serializer or self.serializer).\ - read_from_full_path(file_path) - - @property - def status(self): - return self.get_fresh_data()['status'] - - @property - def settings_url(self): - return self.attributes_path.format(self.id) - - @property - def default_settings_url(self): - return self.settings_url + "/defaults" - - @property - def network_url(self): - return "clusters/{id}/network_configuration/neutron".format( - **self.data - ) - - @property - def network_template_url(self): - return self.network_template_path.format(self.id) - - @property - def network_verification_url(self): - return self.network_url + "/verify" - - def get_network_data(self): - return self.connection.get_request(self.network_url) - - def get_settings_data(self): - return self.connection.get_request(self.settings_url) - - def get_default_settings_data(self): - return self.connection.get_request(self.default_settings_url) - - def get_network_template_data(self): - return self.connection.get_request(self.network_template_url) - - def set_network_data(self, data): - return self.connection.put_request( - self.network_url, data) - - def set_settings_data(self, data, force=False): - if force: - result = self.connection.put_request( - self.settings_url, data, force=1) - else: - result = self.connection.put_request( - self.settings_url, data) - return result - - def verify_network(self): - return self.connection.put_request( - self.network_verification_url, self.get_network_data()) - - def set_network_template_data(self, data): - return self.connection.put_request( - self.network_template_url, data) - - def delete_network_template_data(self): - return self.connection.delete_request(self.network_template_url) - - def _get_fact_dir_name(self, fact_type, directory=os.path.curdir): - return os.path.join( - os.path.abspath(directory), - "{0}_{1}".format(fact_type, self.id)) - - def _get_fact_url(self, fact_type, default=False): - fact_url = "clusters/{0}/orchestrator/{1}/{2}".format( - self.id, fact_type, 'defaults/' if default else '' - ) - return fact_url - - def get_default_facts(self, fact_type, **kwargs): - """Gets default facts for cluster. - :param fact_type: the type of facts (deployment, provision) - """ - return self.get_facts(fact_type, default=True, **kwargs) - - def get_facts(self, fact_type, default=False, nodes=None, split=None): - """Gets facts for cluster. - :param fact_type: the type of facts (deployment, provision) - :param default: if True, the default facts will be retrieved - :param nodes: if specified, get facts only for selected nodes - :param split: if True, the node part and common part will be split - """ - params = {} - if nodes is not None: - params['nodes'] = ','.join(str(x) for x in nodes) - if split is not None: - params['split'] = str(int(split)) - - facts = self.connection.get_request( - self._get_fact_url(fact_type, default=default), params=params - ) - if not facts: - raise error.ServerDataException( - "There is no {0} info for this " - "environment!".format(fact_type) - ) - return facts - - def upload_facts(self, fact_type, facts): - self.connection.put_request(self._get_fact_url(fact_type), facts) - - def delete_facts(self, fact_type): - self.connection.delete_request(self._get_fact_url(fact_type)) - - def read_fact_info(self, fact_type, directory, serializer=None): - return getattr( - self, "read_{0}_info".format(fact_type) - )(fact_type, directory=directory, serializer=serializer) - - def write_facts_to_dir(self, fact_type, facts, - directory=os.path.curdir, serializer=None): - dir_name = self._get_fact_dir_name(fact_type, directory=directory) - if os.path.exists(dir_name): - shutil.rmtree(dir_name) - os.makedirs(dir_name) - if isinstance(facts, dict): - engine_file_path = os.path.join(dir_name, "engine") - (serializer or self.serializer).write_to_path( - engine_file_path, facts["engine"]) - facts = facts["nodes"] - - def name_builder(fact): - return fact['name'] - else: - def name_builder(fact): - if 'role' in fact: - # from 9.0 the deployment info is serialized only per node - return "{role}_{uid}".format(**fact) - return fact['uid'] - - for _fact in facts: - fact_path = os.path.join( - dir_name, - name_builder(_fact) - ) - (serializer or self.serializer).write_to_path(fact_path, _fact) - return dir_name - - def read_deployment_info(self, fact_type, - directory=os.path.curdir, serializer=None): - self._check_dir(directory) - dir_name = self._get_fact_dir_name(fact_type, directory=directory) - self._check_dir(dir_name) - return map( - lambda f: (serializer or self.serializer).read_from_file(f), - [os.path.join(dir_name, json_file) - for json_file in listdir_without_extensions(dir_name)] - ) - - def read_provisioning_info(self, fact_type, - directory=os.path.curdir, serializer=None): - dir_name = self._get_fact_dir_name(fact_type, directory=directory) - node_facts = map( - lambda f: (serializer or self.serializer).read_from_file(f), - [os.path.join(dir_name, fact_file) - for fact_file in listdir_without_extensions(dir_name) - if "engine" != fact_file] - ) - engine = (serializer or self.serializer).read_from_file( - os.path.join(dir_name, "engine")) - return { - "engine": engine, - "nodes": node_facts - } - - # TODO(vkulanov): remove method when deprecate old cli - def get_testsets(self): - return self.connection.get_request( - 'testsets/{0}'.format(self.id), - ostf=True - ) - - @property - def is_customized(self): - data = self.get_fresh_data() - return data["is_customized"] - - # TODO(vkulanov): remove method when deprecate old cli - def is_in_running_test_sets(self, test_set): - return test_set["testset"] in self._test_sets_to_run - - # TODO(vkulanov): remove method when deprecate old cli - def run_test_sets(self, test_sets_to_run, ostf_credentials=None): - self._test_sets_to_run = test_sets_to_run - - def make_test_set(name): - result = { - "testset": name, - "metadata": { - "config": {}, - "cluster_id": self.id, - } - } - if ostf_credentials: - creds = result['metadata'].setdefault( - 'ostf_os_access_creds', {}) - if 'tenant' in ostf_credentials: - creds['ostf_os_tenant_name'] = ostf_credentials['tenant'] - if 'username' in ostf_credentials: - creds['ostf_os_username'] = ostf_credentials['username'] - if 'password' in ostf_credentials: - creds['ostf_os_password'] = ostf_credentials['password'] - return result - - tests_data = [make_test_set(ts) for ts in test_sets_to_run] - testruns = self.connection.post_request( - "testruns", tests_data, ostf=True) - self._testruns_ids = [tr['id'] for tr in testruns] - return testruns - - # TODO(vkulanov): remove method when deprecate old cli - def get_state_of_tests(self): - return [ - self.connection.get_request( - "testruns/{0}".format(testrun_id), ostf=True) - for testrun_id in self._testruns_ids - ] - - def stop(self): - return Task.init_with_data( - self.connection.put_request( - "clusters/{0}/stop_deployment/".format(self.id), - {} - ) - ) - - def reset(self, force=False): - return Task.init_with_data( - self.connection.put_request( - "clusters/{0}/reset/?force={force}".format(self.id, - force=int(force)), - {} - ) - ) - - def _get_method_url(self, method_type, nodes, force=False, noop_run=False): - endpoint = "clusters/{0}/{1}/?nodes={2}".format( - self.id, - method_type, - ','.join(map(lambda n: str(n.id), nodes))) - - if force: - endpoint += '&force=1' - if noop_run: - endpoint += '&noop_run=1' - - return endpoint - - def install_selected_nodes(self, method_type, nodes): - return Task.init_with_data( - self.connection.put_request( - self._get_method_url(method_type, nodes), - {} - ) - ) - - def execute_tasks(self, nodes, tasks, force, noop_run): - return Task.init_with_data( - self.connection.put_request( - self._get_method_url('deploy_tasks', nodes=nodes, force=force, - noop_run=noop_run), - tasks - ) - ) - - def get_tasks(self, skip=None, end=None, start=None, include=None): - """Stores logic to filter tasks by known parameters. - - :param skip: list of tasks or None - :param end: string or None - :param start: string or None - :param include: list or None - """ - tasks = [t['id'] for t in self.get_deployment_tasks( - end=end, start=start, include=include)] - if skip: - tasks_to_execute = set(tasks) - set(skip) - return list(tasks_to_execute) - return tasks - - def get_deployment_tasks(self, end=None, start=None, include=None): - url = self.deployment_tasks_path.format(self.id) - return self.connection.get_request( - url, params={ - 'end': end, - 'start': start, - 'include': include}) - - def update_deployment_tasks(self, data): - url = self.deployment_tasks_path.format(self.id) - return self.connection.put_request(url, data) - - def get_attributes(self): - return self.connection.get_request(self.settings_url) - - def update_attributes(self, data, force=False): - if force: - result = self.connection.put_request( - self.settings_url, data, force=1) - else: - result = self.connection.put_request( - self.settings_url, data) - return result - - def get_deployment_tasks_graph(self, tasks, parents_for=None, remove=None): - url = self.deployment_tasks_graph_path.format(self.id) - params = { - 'tasks': ','.join(tasks), - 'parents_for': parents_for, - 'remove': ','.join(remove) if remove else None, - } - resp = self.connection.get_request_raw(url, params=params) - resp.raise_for_status() - return resp.text - - def spawn_vms(self): - url = 'clusters/{0}/spawn_vms/'.format(self.id) - return self.connection.put_request(url, {}) - - def _get_ip_addrs_url(self, vips=True, ip_addr_id=None): - """Generate ip address management url. - - :param vips: manage vip properties of ip address - :type vips: bool - :param ip_addr_id: ip address identifier - :type ip_addr_id: int - :return: url - :rtype: str - """ - ip_addr_url = "clusters/{0}/network_configuration/ips/".format(self.id) - if ip_addr_id: - ip_addr_url += '{0}/'.format(ip_addr_id) - if vips: - ip_addr_url += 'vips/' - - return ip_addr_url - - def get_default_vips_data_path(self): - """Get path where VIPs data is located. - :return: path - :rtype: str - """ - return os.path.join( - os.path.abspath(os.curdir), - "vips_{0}".format(self.id) - ) - - def get_vips_data(self, ip_address_id=None, network=None, - network_role=None): - """Get one or multiple vip data records. - - :param ip_address_id: ip addr id could be specified to download single - vip if no ip_addr_id specified multiple entities is - returned respecting network and network_role - filters - :type ip_address_id: int - :param network: network id could be specified to filter vips - :type network: int - :param network_role: network role could be specified to filter vips - :type network_role: string - :return: response JSON - :rtype: list of dict - """ - params = {} - if network: - params['network'] = network - if network_role: - params['network-role'] = network_role - - result = self.connection.get_request( - self._get_ip_addrs_url(True, ip_addr_id=ip_address_id), - params=params - ) - if ip_address_id is not None: # single vip is returned - # wrapping with list is required to respect case when administrator - # is downloading vip address info to change it and upload - # back. Uploading works only with lists of records. - result = [result] - return result - - def write_vips_data_to_file(self, vips_data, serializer=None, - file_path=None): - """Write VIP data to the given path. - - :param vips_data: vip data - :type vips_data: list of dict - :param serializer: serializer - :param file_path: path - :type file_path: str - :return: path to resulting file - :rtype: str - """ - serializer = serializer or self.serializer - - if file_path: - return serializer.write_to_full_path( - file_path, - vips_data - ) - else: - return serializer.write_to_path( - self.get_default_vips_data_path(), - vips_data - ) - - def read_vips_data_from_file(self, file_path=None, serializer=None): - """Read VIPs data from given path. - - :param file_path: path - :type file_path: str - :param serializer: serializer object - :type serializer: object - :return: data - :rtype: list|object - """ - self._check_file_path(file_path) - return (serializer or self.serializer).read_from_file(file_path) - - def set_vips_data(self, data): - """Sending VIPs data to the Nailgun API. - - :param data: VIPs data - :type data: list of dict - :return: request result - :rtype: object - """ - return self.connection.put_request(self._get_ip_addrs_url(), data) - - def create_vip(self, **vip_kwargs): - """Create VIP through request to Nailgun API - - :param vip_data: attributes of the VIP to be created - """ - return self.connection.post_request(self._get_ip_addrs_url(), - vip_kwargs) - - def get_enabled_plugins(self): - """Get list of enabled plugins ids. - - :returns: plugins ids list - :rtype: list[int] - """ - attrs = self.get_attributes()['editable'] - enabled_plugins_ids = [] - for attr_name in attrs: - metadata = attrs[attr_name].get('metadata', {}) - if metadata.get('class') == 'plugin' and metadata.get('enabled'): - enabled_plugins_ids.append(metadata['chosen_id']) - return enabled_plugins_ids diff --git a/fuelclient/objects/extension.py b/fuelclient/objects/extension.py deleted file mode 100644 index 696253d..0000000 --- a/fuelclient/objects/extension.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient.objects.base import BaseObject - - -class Extension(BaseObject): - - class_api_path = "extensions/" - instance_api_path = "clusters/{0}/extensions/" - - @property - def extensions_url(self): - return self.instance_api_path.format(self.id) - - def get_env_extensions(self): - """Get list of extensions through request to the Nailgun API - - """ - return self.connection.get_request(self.extensions_url) - - def enable_env_extensions(self, extensions): - """Enable extensions through request to the Nailgun API - - :param extensions: list of extenstion to be enabled - """ - return self.connection.put_request(self.extensions_url, extensions) - - def disable_env_extensions(self, extensions): - """Disable extensions through request to the Nailgun API - - :param extensions: list of extenstion to be disabled - """ - url = '{0}?extension_names={1}'.format(self.extensions_url, - ','.join(extensions)) - return self.connection.delete_request(url) diff --git a/fuelclient/objects/fuelversion.py b/fuelclient/objects/fuelversion.py deleted file mode 100644 index b65c11e..0000000 --- a/fuelclient/objects/fuelversion.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient.objects.base import BaseObject - - -class FuelVersion(BaseObject): - - class_api_path = "version/" - - @classmethod - def get_feature_groups(cls): - return cls.get_all_data()['feature_groups'] diff --git a/fuelclient/objects/health.py b/fuelclient/objects/health.py deleted file mode 100644 index 1592cbd..0000000 --- a/fuelclient/objects/health.py +++ /dev/null @@ -1,86 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Vitalii Kulanov -# -# Licensed 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 fuelclient.objects.base import BaseObject - - -class Health(BaseObject): - - class_api_path = "testruns/" - instance_api_path = "testruns/{0}/" - test_sets_api_path = "testsets/{0}/" - - @classmethod - def get_test_sets(cls, environment_id): - return cls.connection.get_request( - cls.test_sets_api_path.format(environment_id), - ostf=True - ) - - @classmethod - def get_tests_status_all(cls): - return cls.connection.get_request(cls.class_api_path, ostf=True) - - def get_tests_status_single(self): - return self.connection.get_request( - self.instance_api_path.format(self.id), - ostf=True - ) - - @classmethod - def get_last_tests_status(cls, environment_id): - return cls.connection.get_request( - 'testruns/last/{0}'.format(environment_id), - ostf=True - ) - - @classmethod - def run_test_sets(cls, environment_id, test_sets_to_run, - ostf_credentials=None): - - def make_test_set(name): - result = { - "testset": name, - "metadata": { - "config": {}, - "cluster_id": environment_id, - } - } - if ostf_credentials: - creds = result['metadata'].setdefault( - 'ostf_os_access_creds', {}) - if 'tenant' in ostf_credentials: - creds['ostf_os_tenant_name'] = ostf_credentials['tenant'] - if 'username' in ostf_credentials: - creds['ostf_os_username'] = ostf_credentials['username'] - if 'password' in ostf_credentials: - creds['ostf_os_password'] = ostf_credentials['password'] - return result - - tests_data = [make_test_set(ts) for ts in test_sets_to_run] - test_runs = cls.connection.post_request(cls.class_api_path, - tests_data, - ostf=True) - return test_runs - - def action_test(self, action_status): - data = [{ - "id": self.id, - "status": action_status - }] - return self.connection.put_request( - 'testruns/', data, ostf=True - ) diff --git a/fuelclient/objects/network_group.py b/fuelclient/objects/network_group.py deleted file mode 100644 index 3547c7e..0000000 --- a/fuelclient/objects/network_group.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 operator import attrgetter - -from fuelclient.objects.base import BaseObject - - -class NetworkGroup(BaseObject): - - class_api_path = "networks/" - instance_api_path = "networks/{0}/" - - @property - def name(self): - return self.get_fresh_data()["name"] - - @classmethod - def create(cls, name, release, vlan, cidr, gateway, - group_id, meta=None): - - metadata = { - 'notation': 'cidr', - 'render_type': None, - 'map_priority': 2, - 'configurable': True, - 'use_gateway': False, - 'name': name, - 'cidr': cidr, - 'vlan_start': vlan - } - if meta: - metadata.update(meta) - - network_group = { - 'name': name, - 'release': release, - 'vlan_start': vlan, - 'cidr': cidr, - 'gateway': gateway, - 'meta': metadata, - 'group_id': group_id, - } - - data = cls.connection.post_request( - cls.class_api_path, - network_group, - ) - return cls.init_with_data(data) - - def set(self, data): - vlan = data.pop('vlan', None) - if vlan is not None: - data['vlan_start'] = vlan - - return self.connection.put_request( - self.instance_api_path.format(self.id), data) - - def delete(self): - return self.connection.delete_request( - self.instance_api_path.format(self.id) - ) - - -class NetworkGroupCollection(object): - - def __init__(self, networks): - self.collection = networks - - @classmethod - def init_with_ids(cls, ids): - return cls(map(NetworkGroup, ids)) - - @classmethod - def init_with_data(cls, data): - return cls(map(NetworkGroup.init_with_data, data)) - - def __str__(self): - return "{0} [{1}]".format( - self.__class__.__name__, - ", ".join(map(lambda n: str(n.id), self.collection)) - ) - - def __iter__(self): - return iter(self.collection) - - @property - def data(self): - return map(attrgetter("data"), self.collection) - - @classmethod - def get_all(cls): - return cls(NetworkGroup.get_all()) - - def filter_by_group_id(self, group_id): - self.collection = filter(lambda net: net.data['group_id'] == group_id, - self.collection) diff --git a/fuelclient/objects/node.py b/fuelclient/objects/node.py deleted file mode 100644 index f9d240d..0000000 --- a/fuelclient/objects/node.py +++ /dev/null @@ -1,206 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 operator import attrgetter -import os - -from fuelclient.cli.error import InvalidDirectoryException -from fuelclient.objects.base import BaseObject -from fuelclient.objects.environment import Environment - - -class Node(BaseObject): - - class_api_path = "nodes/" - instance_api_path = "nodes/{0}/" - attributes_api_path = "nodes/{0}/attributes/" - - attributes_urls = { - "interfaces": ("interfaces", "default_assignment"), - "disks": ("disks", "defaults") - } - - @property - def env_id(self): - return self.get_fresh_data()["cluster"] - - @property - def env(self): - return Environment(self.env_id) - - def get_attributes_path(self, directory): - return os.path.join( - os.path.abspath( - os.curdir if directory is None else directory), - "node_{0}".format(self.id) - ) - - def is_finished(self, latest=True): - if latest: - data = self.get_fresh_data() - else: - data = self.data - return data["status"] in ("ready", "error") - - @property - def progress(self): - data = self.get_fresh_data() - return data["progress"] - - @property - def labels(self): - return self.get_fresh_data().get('labels', {}) - - def get_attribute_default_url(self, attributes_type): - url_path, default_url_path = self.attributes_urls[attributes_type] - return "nodes/{0}/{1}/{2}".format(self.id, url_path, default_url_path) - - def get_attribute_url(self, attributes_type): - url_path, _ = self.attributes_urls[attributes_type] - return "nodes/{0}/{1}/".format(self.id, url_path) - - def get_default_attribute(self, attributes_type): - return self.connection.get_request( - self.get_attribute_default_url(attributes_type) - ) - - def get_node_attributes(self): - return self.connection.get_request( - self.attributes_api_path.format(self.id) - ) - - def update_node_attributes(self, data): - return self.connection.put_request( - self.attributes_api_path.format(self.id), - data - ) - - def get_attribute(self, attributes_type): - return self.connection.get_request( - self.get_attribute_url(attributes_type) - ) - - def upload_node_attribute(self, attributes_type, attributes): - url = self.get_attribute_url(attributes_type) - return self.connection.put_request( - url, - attributes - ) - - def write_attribute(self, attribute_type, attributes, - directory, serializer=None): - attributes_directory = self.get_attributes_path(directory) - if not os.path.exists(attributes_directory): - os.mkdir(attributes_directory) - attribute_path = os.path.join( - attributes_directory, - attribute_type - ) - if os.path.exists(attribute_path): - os.remove(attribute_path) - return (serializer or self.serializer).write_to_path( - attribute_path, - attributes - ) - - def read_attribute(self, attributes_type, directory, serializer=None): - attributes_directory = self.get_attributes_path(directory) - if not os.path.exists(attributes_directory): - raise InvalidDirectoryException( - "Folder {0} doesn't contain node folder '{1}'" - .format(directory, "node_{0}".format(self.id)) - ) - return (serializer or self.serializer).read_from_file( - os.path.join( - attributes_directory, - attributes_type - ) - ) - - def deploy(self): - self.env.install_selected_nodes("deploy", (self,)) - - def provision(self): - self.env.install_selected_nodes("provision", (self,)) - - def delete(self): - self.connection.delete_request(self.instance_api_path.format(self.id)) - - def node_vms_create(self, config): - url = "nodes/{0}/vms_conf/".format(self.id) - return self.connection.put_request(url, {'vms_conf': config}) - - def get_node_vms_conf(self): - url = "nodes/{0}/vms_conf/".format(self.id) - return self.connection.get_request(url) - - def set(self, data): - return self.connection.put_request( - self.instance_api_path.format(self.id), - data - ) - - @classmethod - def get_by_env_id(cls, cluster_id): - params = {'cluster_id': cluster_id} - return cls.connection.get_request(cls.class_api_path, params=params) - - -class NodeCollection(object): - - class_api_path = "nodes/" - - def __init__(self, nodes): - self.collection = nodes - - @classmethod - def init_with_ids(cls, ids): - return cls(list(map(Node, ids))) - - @classmethod - def init_with_data(cls, data): - return cls(list(map(Node.init_with_data, data))) - - def __str__(self): - return "nodes [{0}]".format( - ", ".join(map(lambda n: str(n.id), self.collection)) - ) - - def __iter__(self): - return iter(self.collection) - - @property - def data(self): - return map(attrgetter("data"), self.collection) - - @classmethod - def get_all(cls): - return cls(Node.get_all()) - - @classmethod - def update(cls, data): - return BaseObject.connection.put_request(cls.class_api_path, data) - - @classmethod - def delete_by_ids(cls, ids): - url = '{0}?ids={1}'.format( - cls.class_api_path, - ','.join(map(str, ids)) - ) - - return BaseObject.connection.delete_request(url) - - def filter_by_env_id(self, env_id): - predicate = lambda node: node.data['cluster'] == env_id - self.collection = filter(predicate, self.collection) diff --git a/fuelclient/objects/nodegroup.py b/fuelclient/objects/nodegroup.py deleted file mode 100644 index 0c82c06..0000000 --- a/fuelclient/objects/nodegroup.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 operator import attrgetter - -from fuelclient.objects.base import BaseObject -from fuelclient.objects import NodeCollection - - -class NodeGroup(BaseObject): - - class_api_path = "nodegroups/" - instance_api_path = "nodegroups/{0}/" - - @property - def env_id(self): - return self.get_fresh_data()["cluster_id"] - - @property - def name(self): - return self.get_fresh_data()["name"] - - @classmethod - def create(cls, name, cluster_id): - return cls.connection.post_request( - cls.class_api_path, - {'cluster_id': cluster_id, 'name': name}, - ) - - @classmethod - def delete(cls, group_id): - return cls.connection.delete_request( - cls.instance_api_path.format(group_id) - ) - - def assign(self, nodes): - data = [{"id": n, "group_id": int(self.id)} for n in nodes] - NodeCollection.update(data) - - -class NodeGroupCollection(object): - - def __init__(self, groups): - self.collection = groups - - @classmethod - def init_with_ids(cls, ids): - return cls(map(NodeGroup, ids)) - - @classmethod - def init_with_data(cls, data): - return cls(map(NodeGroup.init_with_data, data)) - - def __str__(self): - return "node groups [{0}]".format( - ", ".join(map(lambda n: str(n.id), self.collection)) - ) - - def __iter__(self): - return iter(self.collection) - - @property - def data(self): - return map(attrgetter("data"), self.collection) - - @classmethod - def get_all(cls): - return cls(NodeGroup.get_all()) - - def filter_by_env_id(self, env_id): - predicate = lambda group: group.data['cluster_id'] == env_id - self.collection = filter(predicate, self.collection) diff --git a/fuelclient/objects/notifications.py b/fuelclient/objects/notifications.py deleted file mode 100644 index 668e228..0000000 --- a/fuelclient/objects/notifications.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli import error - -from fuelclient.objects import base - - -class Notifications(base.BaseObject): - - class_api_path = "notifications/" - instance_api_path = "notifications/{0}" - - default_topic = 'done' - - @classmethod - def mark_as_read(cls, ids=None): - if not ids: - raise error.BadDataException('Message id not specified.') - - if '*' in ids: - data = Notifications.get_all_data() - else: - try: - ids = map(int, ids) - except ValueError: - raise error.BadDataException( - "Numerical ids expected or the '*' symbol.") - notifications = Notifications.get_by_ids(ids) - - data = [notification.get_fresh_data() - for notification in notifications] - - for notification in data: - notification['status'] = 'read' - - resp = cls.connection.put_request( - cls.class_api_path, data) - - return resp - - @classmethod - def send(cls, message, topic=default_topic): - if not topic: - topic = cls.default_topic - - if not message: - raise error.BadDataException('Message not specified.') - - resp = cls.connection.post_request( - cls.class_api_path, { - 'message': message, - 'topic': topic, - }) - - return resp diff --git a/fuelclient/objects/openstack_config.py b/fuelclient/objects/openstack_config.py deleted file mode 100644 index 299b040..0000000 --- a/fuelclient/objects/openstack_config.py +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 six - -from fuelclient.cli import error -from fuelclient.cli.serializers import Serializer -from fuelclient.objects.base import BaseObject - - -class OpenstackConfig(BaseObject): - - class_api_path = 'openstack-config/' - instance_api_path = 'openstack-config/{0}/' - execute_api_path = 'openstack-config/execute/' - - @classmethod - def _prepare_params(cls, filters): - return dict((k, v) for k, v in six.iteritems(filters) if v is not None) - - @classmethod - def create(cls, **kwargs): - params = cls._prepare_params(kwargs) - data = cls.connection.post_request(cls.class_api_path, params) - return [cls.init_with_data(item) for item in data] - - def delete(self): - return self.connection.delete_request( - self.instance_api_path.format(self.id)) - - @classmethod - def execute(cls, **kwargs): - params = cls._prepare_params(kwargs) - return cls.connection.put_request(cls.execute_api_path, params) - - @classmethod - def get_filtered_data(cls, **kwargs): - url = cls.class_api_path - params = cls._prepare_params(kwargs) - - node_ids = params.get('node_ids') - if node_ids is not None: - params['node_ids'] = ','.join([str(n) for n in node_ids]) - - return cls.connection.get_request(url, params=params) - - @classmethod - def read_file(cls, path): - if not os.path.exists(path): - raise error.InvalidFileException( - "File '{0}' doesn't exist.".format(path)) - - serializer = Serializer() - return serializer.read_from_full_path(path) - - @classmethod - def write_file(cls, path, data): - serializer = Serializer() - return serializer.write_to_full_path(path, data) diff --git a/fuelclient/objects/plugins.py b/fuelclient/objects/plugins.py deleted file mode 100644 index b9bea5e..0000000 --- a/fuelclient/objects/plugins.py +++ /dev/null @@ -1,526 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 abc -import json -import os -import shutil -import subprocess -import sys -import tarfile - -from distutils.version import StrictVersion - -import six -import yaml - -from fuelclient.cli import error -from fuelclient.objects import base -from fuelclient import utils - -IS_MASTER = None -FUEL_PACKAGE = 'fuel' -PLUGINS_PATH = '/var/www/nailgun/plugins/' -METADATA_MASK = '/var/www/nailgun/plugins/*/metadata.yaml' - - -def raise_error_if_not_master(): - """Raises error if it's not Fuel master - - :raises: error.WrongEnvironmentError - """ - msg_tail = 'Action can be performed from Fuel master node only.' - global IS_MASTER - if IS_MASTER is None: - IS_MASTER = False - rpm_exec = utils.find_exec('rpm') - if not rpm_exec: - msg = 'Command "rpm" not found. ' + msg_tail - raise error.WrongEnvironmentError(msg) - command = [rpm_exec, '-q', FUEL_PACKAGE] - p = subprocess.Popen( - command, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - p.communicate() - if p.poll() == 0: - IS_MASTER = True - if not IS_MASTER: - msg = 'Package "fuel" is not installed. ' + msg_tail - raise error.WrongEnvironmentError(msg) - - -def master_only(f): - """Decorator for the method, which raises error, if method - is called on the node which is not Fuel master - """ - @six.wraps(f) - def print_message(*args, **kwargs): - raise_error_if_not_master() - return f(*args, **kwargs) - - return print_message - - -@six.add_metaclass(abc.ABCMeta) -class BasePlugin(object): - - @abc.abstractmethod - def install(cls, plugin_path, force=False): - """Installs plugin package - """ - - @abc.abstractmethod - def update(cls, plugin_path): - """Updates the plugin - """ - - @abc.abstractmethod - def remove(cls, plugin_name, plugin_version): - """Removes the plugin from file system - """ - - @abc.abstractmethod - def downgrade(cls, plugin_path): - """Downgrades the plugin - """ - - @abc.abstractmethod - def name_from_file(cls, file_path): - """Retrieves name from plugin package - """ - - @abc.abstractmethod - def version_from_file(cls, file_path): - """Retrieves version from plugin package - """ - - -class PluginV1(BasePlugin): - - metadata_config = 'metadata.yaml' - - def deprecated(f): - """Prints deprecation warning for old plugins - """ - @six.wraps(f) - def print_message(*args, **kwargs): - six.print_( - 'DEPRECATION WARNING: The plugin has old 1.0 package format, ' - 'this format does not support many features, such as ' - 'plugins updates, find plugin in new format or migrate ' - 'and rebuild this one.', file=sys.stderr) - return f(*args, **kwargs) - - return print_message - - @classmethod - @master_only - @deprecated - def install(cls, plugin_path, force=False): - plugin_tar = tarfile.open(plugin_path, 'r') - try: - plugin_tar.extractall(PLUGINS_PATH) - finally: - plugin_tar.close() - - @classmethod - @master_only - @deprecated - def remove(cls, plugin_name, plugin_version): - plugin_path = os.path.join( - PLUGINS_PATH, '{0}-{1}'.format(plugin_name, plugin_version)) - shutil.rmtree(plugin_path) - - @classmethod - def update(cls, _): - raise error.BadDataException( - 'Update action is not supported for old plugins with ' - 'package version "1.0.0", you can install your plugin ' - 'or use newer plugin format.') - - @classmethod - def downgrade(cls, _): - raise error.BadDataException( - 'Downgrade action is not supported for old plugins with ' - 'package version "1.0.0", you can install your plugin ' - 'or use newer plugin format.') - - @classmethod - def name_from_file(cls, file_path): - """Retrieves plugin name from plugin archive. - - :param str plugin_path: path to the plugin - :returns: plugin name - """ - return cls._get_metadata(file_path)['name'] - - @classmethod - def version_from_file(cls, file_path): - """Retrieves plugin version from plugin archive. - - :param str plugin_path: path to the plugin - :returns: plugin version - """ - return cls._get_metadata(file_path)['version'] - - @classmethod - def _get_metadata(cls, plugin_path): - """Retrieves metadata from plugin archive - - :param str plugin_path: path to the plugin - :returns: metadata from the plugin - """ - plugin_tar = tarfile.open(plugin_path, 'r') - - try: - for member_name in plugin_tar.getnames(): - if cls.metadata_config in member_name: - return yaml.load( - plugin_tar.extractfile(member_name).read()) - finally: - plugin_tar.close() - - -class PluginV2(BasePlugin): - - @classmethod - @master_only - def install(cls, plugin_path, force=False): - if force: - utils.exec_cmd( - 'yum -y install --disablerepo=\'*\' {0} || ' - 'yum -y reinstall --disablerepo=\'*\' {0}' - .format(plugin_path)) - else: - utils.exec_cmd('yum -y install --disablerepo=\'*\' {0}' - .format(plugin_path)) - - @classmethod - @master_only - def remove(cls, name, version): - rpm_name = '{0}-{1}'.format(name, utils.major_plugin_version(version)) - utils.exec_cmd('yum -y remove {0}'.format(rpm_name)) - - @classmethod - @master_only - def update(cls, plugin_path): - utils.exec_cmd('yum -y update {0}'.format(plugin_path)) - - @classmethod - @master_only - def downgrade(cls, plugin_path): - utils.exec_cmd('yum -y downgrade {0}'.format(plugin_path)) - - @classmethod - def name_from_file(cls, file_path): - """Retrieves plugin name from RPM. RPM name contains - the version of the plugin, which should be removed. - - :param str file_path: path to rpm file - :returns: name of the plugin - """ - for line in utils.exec_cmd_iterator( - "rpm -qp --queryformat '%{{name}}' {0}".format(file_path)): - name = line - break - - return cls._remove_major_plugin_version(name) - - @classmethod - def version_from_file(cls, file_path): - """Retrieves plugin version from RPM. - - :param str file_path: path to rpm file - :returns: version of the plugin - """ - for line in utils.exec_cmd_iterator( - "rpm -qp --queryformat '%{{version}}' {0}".format(file_path)): - version = line - break - - return version - - @classmethod - def _remove_major_plugin_version(cls, name): - """Removes the version from plugin name. - Here is an example: "name-1.0" -> "name" - - :param str name: plugin name - :returns: the name withot version - """ - name_wo_version = name - - if '-' in name_wo_version: - name_wo_version = '-'.join(name.split('-')[:-1]) - - return name_wo_version - - -class Plugins(base.BaseObject): - - class_api_path = 'plugins/' - class_instance_path = 'plugins/{id}' - - @classmethod - def register(cls, name, version, force=False): - """Tries to find plugin on file system, creates - it in API service if it exists. - - :param str name: plugin name - :param str version: plugin version - :param bool force: if True updates meta information - about the plugin even it does not - support updates - """ - metadata = None - for m in utils.glob_and_parse_yaml(METADATA_MASK): - if m.get('version') == version and \ - m.get('name') == name: - metadata = m - break - - if not metadata: - raise error.BadDataException( - 'Plugin {0} with version {1} does ' - 'not exist, install it and try again'.format( - name, version)) - - return cls.update_or_create(metadata, force=force) - - @classmethod - def sync(cls, plugin_ids=None): - """Checks all of the plugins on file systems, - and makes sure that they have consistent information - in API service. - - :params plugin_ids: list of ids for plugins which should be synced - :type plugin_ids: list - :returns: None - """ - post_data = None - if plugin_ids is not None: - post_data = {'ids': plugin_ids} - - cls.connection.post_request( - api='plugins/sync/', data=post_data) - - @classmethod - def unregister(cls, name, version): - """Removes the plugin from API service - - :param str name: plugin name - :param str version: plugin version - """ - plugin = cls.get_plugin(name, version) - return cls.connection.delete_request( - cls.class_instance_path.format(**plugin)) - - @classmethod - def install(cls, plugin_path, force=False): - """Installs the package, and creates data in API service - - :param str plugin_path: Name of plugin file - :param bool force: Updates existent plugin even if it is not updatable - :return: Plugins information - :rtype: dict - """ - if not utils.file_exists(plugin_path): - raise error.BadDataException( - "No such plugin file: {0}".format(plugin_path) - ) - plugin = cls.make_obj_by_file(plugin_path) - - name = plugin.name_from_file(plugin_path) - version = plugin.version_from_file(plugin_path) - - plugin.install(plugin_path, force=force) - response = cls.register(name, version, force=force) - - return response - - @classmethod - def remove(cls, plugin_name, plugin_version): - """Removes the package, and updates data in API service - - :param str name: plugin name - :param str version: plugin version - """ - plugin = cls.make_obj_by_name(plugin_name, plugin_version) - cls.unregister(plugin_name, plugin_version) - return plugin.remove(plugin_name, plugin_version) - - @classmethod - def update(cls, plugin_path): - """Updates the package, and updates data in API service - - :param str plugin_path: path to the plugin - """ - plugin = cls.make_obj_by_file(plugin_path) - - name = plugin.name_from_file(plugin_path) - version = plugin.version_from_file(plugin_path) - - plugin.update(plugin_path) - return cls.register(name, version) - - @classmethod - def downgrade(cls, plugin_path): - """Downgrades the package, and updates data in API service - - :param str plugin_path: path to the plugin - """ - plugin = cls.make_obj_by_file(plugin_path) - - name = plugin.name_from_file(plugin_path) - version = plugin.version_from_file(plugin_path) - - plugin.downgrade(plugin_path) - return cls.register(name, version) - - @classmethod - def make_obj_by_name(cls, name, version): - """Finds appropriate plugin class version, - by plugin version and name. - - :param str name: - :param str version: - :returns: plugin class - :raises: error.BadDataException unsupported package version - """ - plugin = cls.get_plugin(name, version) - package_version = plugin['package_version'] - - if StrictVersion('1.0.0') <= \ - StrictVersion(package_version) < \ - StrictVersion('2.0.0'): - return PluginV1 - elif StrictVersion('2.0.0') <= StrictVersion(package_version): - return PluginV2 - - raise error.BadDataException( - 'Plugin {0}=={1} has unsupported package version {2}'.format( - name, version, package_version)) - - @classmethod - def make_obj_by_file(cls, file_path): - """Finds appropriate plugin class version, - by plugin file. - - :param str file_path: plugin path - :returns: plugin class - :raises: error.BadDataException unsupported package version - """ - _, ext = os.path.splitext(file_path) - - if ext == '.fp': - return PluginV1 - elif ext == '.rpm': - return PluginV2 - - raise error.BadDataException( - 'Plugin {0} has unsupported format {1}'.format( - file_path, ext)) - - @classmethod - def update_or_create(cls, metadata, force=False): - """Try to update existent plugin or create new one. - - :param dict metadata: plugin information - :param bool force: updates existent plugin even if - it is not updatable - """ - # Try to update plugin - plugin_for_update = cls.get_plugin_for_update(metadata) - if plugin_for_update: - url = cls.class_instance_path.format(id=plugin_for_update['id']) - resp = cls.connection.put_request(url, metadata) - return resp - - # If plugin is not updatable it means that we should - # create new instance in Nailgun - resp_raw = cls.connection.post_request_raw( - cls.class_api_path, metadata) - resp = resp_raw.json() - - if resp_raw.status_code == 409 and force: - # Replace plugin information - message = json.loads(resp['message']) - url = cls.class_instance_path.format(id=message['id']) - resp = cls.connection.put_request(url, metadata) - elif resp_raw.status_code == 409: - error.exit_with_error( - "Nothing to do: %(title)s, version " - "%(package_version)s, does not update " - "installed plugin." % metadata) - else: - resp_raw.raise_for_status() - - return resp - - @classmethod - def get_plugin_for_update(cls, metadata): - """Retrieves plugins which can be updated - - :param dict metadata: plugin metadata - :returns: dict with plugin which can be updated or None - """ - if not cls.is_updatable(metadata['package_version']): - return - - plugins = [p for p in cls.get_all_data() - if (p['name'] == metadata['name'] and - cls.is_updatable(p['package_version']) and - utils.major_plugin_version(metadata['version']) == - utils.major_plugin_version(p['version']))] - - plugin = None - if plugins: - # List should contain only one plugin, but just - # in case we make sure that we get plugin with - # higher version - plugin = sorted( - plugins, - key=lambda p: StrictVersion(p['version']))[0] - - return plugin - - @classmethod - def is_updatable(cls, package_version): - """Checks if plugin's package version supports updates. - - :param str package_version: package version of the plugin - :returns: True if plugin can be updated - False if plugin cannot be updated - """ - return StrictVersion('2.0.0') <= StrictVersion(package_version) - - @classmethod - def get_plugin(cls, name, version): - """Returns plugin fetched by name and version. - - :param str name: plugin name - :param str version: plugin version - :returns: dictionary with plugin data - :raises: error.BadDataException if no plugin was found - """ - plugins = [p for p in cls.get_all_data() - if (p['name'], p['version']) == (name, version)] - - if not plugins: - raise error.BadDataException( - 'Plugin "{name}" with version {version}, does ' - 'not exist'.format(name=name, version=version)) - - return plugins[0] diff --git a/fuelclient/objects/release.py b/fuelclient/objects/release.py deleted file mode 100644 index a4a91d3..0000000 --- a/fuelclient/objects/release.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 fuelclient.objects.base import BaseObject - - -class Release(BaseObject): - - class_api_path = "releases/" - instance_api_path = "releases/{0}/" - networks_path = 'releases/{0}/networks' - attributes_metadata_path = 'releases/{0}/attributes_metadata' - deployment_tasks_path = 'releases/{0}/deployment_tasks' - components_path = 'releases/{0}/components' - - def get_networks(self): - url = self.networks_path.format(self.id) - return self.connection.get_request(url) - - def update_networks(self, data): - url = self.networks_path.format(self.id) - return self.connection.put_request(url, data) - - def update_attributes_metadata(self, data): - url = self.attributes_metadata_path.format(self.id) - self.connection.put_request(url, data) - - def get_attributes_metadata(self): - url = self.attributes_metadata_path.format(self.id) - return self.connection.get_request(url) - - def get_deployment_tasks(self): - url = self.deployment_tasks_path.format(self.id) - return self.connection.get_request(url) - - def update_deployment_tasks(self, data): - url = self.deployment_tasks_path.format(self.id) - return self.connection.put_request(url, data) - - def get_components(self): - url = self.components_path.format(self.id) - return self.connection.get_request(url) diff --git a/fuelclient/objects/role.py b/fuelclient/objects/role.py deleted file mode 100644 index 1e6d761..0000000 --- a/fuelclient/objects/role.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient.objects.base import BaseObject - - -class Role(BaseObject): - - instance_api_path = "{owner_type}/{owner_id}/roles/" - class_api_path = "{owner_type}/{owner_id}/roles/{role_name}/" - - def __init__(self, owner_type, owner_id, **kwargs): - super(Role, self).__init__(owner_id, **kwargs) - self.owner_type = owner_type - - def get_all(self): - return self.connection.get_request( - self.instance_api_path.format( - owner_type=self.owner_type, - owner_id=self.id)) - - def get_role(self, role_name): - return self.connection.get_request( - self.class_api_path.format( - owner_type=self.owner_type, - owner_id=self.id, - role_name=role_name)) - - def update_role(self, role_name, data): - return self.connection.put_request( - self.class_api_path.format( - owner_type=self.owner_type, - owner_id=self.id, - role_name=role_name), - data) - - def create_role(self, data): - return self.connection.post_request( - self.instance_api_path.format( - owner_type=self.owner_type, owner_id=self.id), data) - - def delete_role(self, role_name): - return self.connection.delete_request( - self.class_api_path.format( - owner_type=self.owner_type, - owner_id=self.id, - role_name=role_name)) diff --git a/fuelclient/objects/sequence.py b/fuelclient/objects/sequence.py deleted file mode 100644 index 29ec992..0000000 --- a/fuelclient/objects/sequence.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient.objects.base import BaseObject - - -class Sequence(BaseObject): - - class_api_path = "sequences/" - instance_api_path = "sequences/{0}/" diff --git a/fuelclient/objects/tag.py b/fuelclient/objects/tag.py deleted file mode 100644 index 373142f..0000000 --- a/fuelclient/objects/tag.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient.objects.base import BaseObject - - -class Tag(BaseObject): - - instance_api_path = "{owner_type}/{owner_id}/tags/" - class_api_path = "{owner_type}/{owner_id}/tags/{tag_name}/" - - def __init__(self, owner_type, owner_id, **kwargs): - super(Tag, self).__init__(owner_id, **kwargs) - self.owner_type = owner_type - - def get_all(self): - return self.connection.get_request( - self.instance_api_path.format(owner_type=self.owner_type, - owner_id=self.id)) - - def get_tag(self, tag_name): - return self.connection.get_request( - self.class_api_path.format(owner_type=self.owner_type, - owner_id=self.id, - tag_name=tag_name)) - - def update_tag(self, tag_name, data): - return self.connection.put_request( - self.class_api_path.format(owner_type=self.owner_type, - owner_id=self.id, - tag_name=tag_name), - data) - - def create_tag(self, data): - return self.connection.post_request( - self.instance_api_path.format(owner_type=self.owner_type, - owner_id=self.id), - data) - - def delete_tag(self, tag_name): - return self.connection.delete_request( - self.class_api_path.format(owner_type=self.owner_type, - owner_id=self.id, - tag_name=tag_name)) diff --git a/fuelclient/objects/task.py b/fuelclient/objects/task.py deleted file mode 100644 index 10f2226..0000000 --- a/fuelclient/objects/task.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 operator import methodcaller -from time import sleep - -from fuelclient.cli.error import DeployProgressError -from fuelclient.objects.base import BaseObject - - -class Task(BaseObject): - - class_api_path = "transactions/" - instance_api_path = "transactions/{0}/" - info_types_url_map = { - 'deployment_info': 'deployment_info', - 'cluster_settings': 'settings', - 'network_configuration': 'network_configuration'} - - def delete(self, force=False): - return self.connection.delete_request( - "transactions/{0}/?force={1}".format( - self.id, - int(force), - )) - - @property - def progress(self): - return self.get_fresh_data()["progress"] - - @property - def status(self): - return self.get_fresh_data()["status"] - - @property - def is_finished(self): - return self.status in ("ready", "error") - - def wait(self): - while not self.is_finished: - sleep(0.5) - - def deployment_info(self): - return self.connection.get_request( - self._get_additional_info_url('deployment_info')) - - def network_configuration(self): - return self.connection.get_request( - self._get_additional_info_url('network_configuration')) - - def cluster_settings(self): - return self.connection.get_request( - self._get_additional_info_url('cluster_settings')) - - def _get_additional_info_url(self, info_type): - """Generate additional info url. - - :param info_type: one of deployment_info, cluster_settings, - network_configuration - :type info_type: str - :return: url - :rtype: str - """ - - return self.instance_api_path.format(self.id) +\ - self.info_types_url_map[info_type] - - -class DeployTask(Task): - - def __init__(self, obj_id, env_id): - from fuelclient.objects.environment import Environment - super(DeployTask, self).__init__(obj_id) - self.env = Environment(env_id) - self.nodes = self.env.get_all_nodes() - - @classmethod - def init_with_data(cls, data): - return cls(data["id"], data["cluster"]) - - @property - def not_finished_nodes(self): - return filter( - lambda n: not n.is_finished(latest=False), - self.nodes - ) - - @property - def is_finished(self): - return super(DeployTask, self).is_finished and all( - map( - methodcaller("is_finished"), - self.not_finished_nodes - ) - ) - - def __iter__(self): - return self - - def next(self): - if not self.is_finished: - sleep(1) - deploy_task_data = self.get_fresh_data() - if deploy_task_data["status"] == "error": - raise DeployProgressError(deploy_task_data["message"]) - for node in self.not_finished_nodes: - node.update() - return self.progress, self.nodes - else: - raise StopIteration - - -class SnapshotTask(Task): - - @classmethod - def start_snapshot_task(cls, conf): - dump_task = cls.connection.put_request("logs/package", conf) - return cls(dump_task["id"]) - - @classmethod - def get_default_config(cls): - return cls.connection.get_request("logs/package/config/default/") diff --git a/fuelclient/profiler.py b/fuelclient/profiler.py deleted file mode 100644 index df64dc0..0000000 --- a/fuelclient/profiler.py +++ /dev/null @@ -1,99 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 cProfile -import os -from pstats import Stats -import time - -from fuelclient.cli import error -from fuelclient import fuelclient_settings - - -def profiling_enabled(): - settings = fuelclient_settings.get_settings() - return bool(settings.PERFORMANCE_PROFILING_TESTS) - - -class Profiler(object): - """Runs profiler and saves results.""" - - def __init__(self, method='', handler_name=''): - self.method = method - self.handler_name = handler_name - settings = fuelclient_settings.get_settings() - self.paths = settings.PERF_TESTS_PATHS - - if not os.path.exists(self.paths['last_performance_test']): - os.makedirs(self.paths['last_performance_test']) - - self.profiler = cProfile.Profile() - self.profiler.enable() - self.start = time.time() - - def save_data(self): - try: - import gprof2dot - import pyprof2calltree - except ImportError: - msg = ('Unable to start profiling.\n Please either ' - 'disable performance profiling in settings.yaml or ' - 'install all modules listed in test-requirements.txt.') - raise error.ProfilingError(msg) - - self.profiler.disable() - elapsed = time.time() - self.start - pref_filename = os.path.join( - self.paths['last_performance_test'], - '{method:s}.{handler_name:s}.{elapsed_time:.0f}ms.{t_time}.'. - format( - method=self.method, - handler_name=self.handler_name or 'root', - elapsed_time=elapsed * 1000.0, - t_time=time.time())) - tree_file = pref_filename + 'prof' - stats_file = pref_filename + 'txt' - callgraph_file = pref_filename + 'dot' - - # write pstats - with file(stats_file, 'w') as file_o: - stats = Stats(self.profiler, stream=file_o) - stats.sort_stats('time', 'cumulative').print_stats() - - # write callgraph in dot format - parser = gprof2dot.PstatsParser(self.profiler) - - def get_function_name(args): - filename, line, name = args - module = os.path.splitext(filename)[0] - module_pieces = module.split(os.path.sep) - return "{module:s}:{line:d}:{name:s}".format( - module="/".join(module_pieces[-4:]), - line=line, - name=name) - - parser.get_function_name = get_function_name - gprof = parser.parse() - - with open(callgraph_file, 'w') as file_o: - dot = gprof2dot.DotWriter(file_o) - theme = gprof2dot.TEMPERATURE_COLORMAP - dot.graph(gprof, theme) - - # write calltree - call_tree = pyprof2calltree.CalltreeConverter(stats) - with file(tree_file, 'wb') as file_o: - call_tree.output(file_o) diff --git a/fuelclient/tests/__init__.py b/fuelclient/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fuelclient/tests/functional/__init__.py b/fuelclient/tests/functional/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fuelclient/tests/functional/base.py b/fuelclient/tests/functional/base.py deleted file mode 100644 index 0430039..0000000 --- a/fuelclient/tests/functional/base.py +++ /dev/null @@ -1,218 +0,0 @@ -# Copyright 2013-2014 Mirantis, Inc. -# -# Licensed 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 json -import logging -import os -import re -import shutil -import subprocess -import sys -import tempfile -import time - -from fuelclient import consts -from fuelclient.objects import Release - -from oslotest import base as oslo_base - -logging.basicConfig(stream=sys.stderr) -log = logging.getLogger("CliTest.ExecutionLog") -log.setLevel(logging.DEBUG) - - -class CliExecutionResult(object): - def __init__(self, process_handle, out, err): - self.return_code = process_handle.returncode - self.stdout = out - self.stderr = err - - @property - def has_errors(self): - return self.return_code != 0 - - @property - def is_return_code_zero(self): - return self.return_code == 0 - - -class BaseTestCase(oslo_base.BaseTestCase): - - handler = '' - nailgun_root = os.environ.get('NAILGUN_ROOT', '/tmp/fuel_web/nailgun') - fuel_web_root = os.environ.get('FUEL_WEB_ROOT', '/tmp/fuel_web') - - def setUp(self): - super(BaseTestCase, self).setUp() - - self.reload_nailgun_server() - self.temp_directory = tempfile.mkdtemp() - - self.addCleanup(shutil.rmtree, self.temp_directory) - - @staticmethod - def run_command(*args, **kwargs): - handle = subprocess.Popen( - [" ".join(args)], - stdout=kwargs.pop('stdout', subprocess.PIPE), - stderr=kwargs.pop('stderr', subprocess.PIPE), - shell=kwargs.pop('shell', True), - **kwargs - ) - log.debug("Running " + " ".join(args)) - out, err = handle.communicate() - log.debug("Finished command with {0} - {1}".format(out, err)) - - def upload_command(self, cmd): - return "{0} --upload --dir {1}".format(cmd, self.temp_directory) - - def download_command(self, cmd): - return "{0} --download --dir {1}".format(cmd, self.temp_directory) - - @classmethod - def reload_nailgun_server(cls): - for action in ("dropdb", "syncdb", "loaddefault"): - cmd = 'tox -evenv -- {0}/manage.py {1}'.format( - cls.nailgun_root, action) - cls.run_command(cmd, cwd=cls.fuel_web_root) - - @classmethod - def load_data_to_nailgun_server(cls): - file_path = os.path.join(cls.nailgun_root, - 'nailgun/fixtures/sample_environment.json') - cmd = 'tox -evenv -- {0}/manage.py loaddata {1}'.format( - cls.nailgun_root, file_path) - cls.run_command(cmd, cwd=cls.fuel_web_root) - - def run_cli_command(self, command_line, handler=None, - check_errors=True, env=os.environ.copy()): - - command_args = [" ".join((handler or self.handler, command_line))] - process_handle = subprocess.Popen( - command_args, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=True, - env=env - ) - out, err = process_handle.communicate() - result = CliExecutionResult(process_handle, out, err) - log.debug("command_args: '%s',stdout: '%s', stderr: '%s'", - command_args[0], out, err) - if check_errors: - if not result.is_return_code_zero or result.has_errors: - self.fail(err) - return result - - def get_first_deployable_release_id(self): - releases = sorted(Release.get_all_data(), - key=lambda x: x['id']) - for r in releases: - if r['is_deployable']: - return r['id'] - self.fail("There are no deployable releases.") - - def run_cli_commands(self, command_lines, **kwargs): - for command in command_lines: - self.run_cli_command(command, **kwargs) - - def check_if_required(self, command): - call = self.run_cli_command(command, check_errors=False) - # should not work without env id - self.assertIn("required", call.stderr) - - def check_for_stdout(self, command, msg, check_errors=True): - call = self.run_cli_command(command, check_errors=check_errors) - self.assertEqual(call.stdout, msg) - - def check_for_stdout_by_regexp(self, command, pattern, check_errors=True): - call = self.run_cli_command(command, check_errors=check_errors) - result = re.search(pattern, call.stdout) - self.assertIsNotNone(result) - return result - - def check_for_stderr(self, command, msg, check_errors=True): - call = self.run_cli_command(command, check_errors=check_errors) - self.assertIn(msg, call.stderr) - - def check_all_in_msg(self, command, substrings, **kwargs): - output = self.run_cli_command(command, **kwargs) - for substring in substrings: - self.assertIn(substring, output.stdout) - - def check_for_rows_in_table(self, command): - output = self.run_cli_command(command) - message = output.stdout.split("\n") - # no env - self.assertEqual(message[2], '') - - def check_number_of_rows_in_table(self, command, number_of_rows): - output = self.run_cli_command(command) - self.assertEqual(len(output.stdout.split("\n")), number_of_rows + 3) - - def _get_task_info(self, task_id): - """Get info about task with given ID. - - :param task_id: Task ID - :type task_id: str or int - :return: Task info - :rtype: dict - """ - return {} - - def wait_task_ready(self, task_id, timeout=60, interval=3): - """Wait for changing task status to 'ready'. - - :param task_id: Task ID - :type task_id: str or int - :param timeout: Max time of waiting, in seconds - :type timeout: int - :param interval: Interval of getting task info, in seconds - :type interval: int - """ - wait_until_in_statuses = (consts.TASK_STATUSES.running, - consts.TASK_STATUSES.pending) - timer = time.time() - while True: - task = self._get_task_info(task_id) - status = task.get('status', '') - if status not in wait_until_in_statuses: - self.assertEqual(status, consts.TASK_STATUSES.ready) - break - - if time.time() - timer > timeout: - raise Exception( - "Task '{0}' seems to be hanged".format(task['name']) - ) - time.sleep(interval) - - -class CLIv1TestCase(BaseTestCase): - - handler = 'fuel' - - def _get_task_info(self, task_id): - command = "task show -f json {0}".format(str(task_id)) - call = self.run_cli_command(command, handler='fuel2') - return json.loads(call.stdout) - - -class CLIv2TestCase(BaseTestCase): - - handler = 'fuel2' - - def _get_task_info(self, task_id): - command = "task show -f json {0}".format(str(task_id)) - call = self.run_cli_command(command) - return json.loads(call.stdout) diff --git a/fuelclient/tests/functional/common/__init__.py b/fuelclient/tests/functional/common/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fuelclient/tests/functional/v1/__init__.py b/fuelclient/tests/functional/v1/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fuelclient/tests/functional/v1/test_client.py b/fuelclient/tests/functional/v1/test_client.py deleted file mode 100644 index c3c1c6b..0000000 --- a/fuelclient/tests/functional/v1/test_client.py +++ /dev/null @@ -1,516 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2013-2014 Mirantis, Inc. -# -# Licensed 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 - -from fuelclient.tests.functional import base - - -class TestHandlers(base.CLIv1TestCase): - - def test_env_action(self): - # check env help - help_msgs = ["usage: fuel environment [-h]", - "[--list | --set | --delete | --create]", - "optional arguments:", "--help", "--list", "--set", - "--delete", "--rel", "--env-create", - "--create", "--name", "--env-name", "--nst", - "--net-segment-type"] - self.check_all_in_msg("env --help", help_msgs) - # no clusters - self.check_for_rows_in_table("env") - - for action in ("set", "create", "delete"): - self.check_if_required("env {0}".format(action)) - - release_id = self.get_first_deployable_release_id() - - # list of tuples (, ) - expected_stdout = \ - [( - "env --create --name=TestEnv --release={0}".format(release_id), - "Environment 'TestEnv' with id=1 was created!\n" - ), ( - "--env-id=1 env set --name=NewEnv", - ("Following attributes are changed for " - "the environment: name=NewEnv\n") - )] - - for cmd, msg in expected_stdout: - self.check_for_stdout(cmd, msg) - - def test_node_action(self): - help_msg = ["fuel node [-h] [--env ENV]", - "[--list | --set | --delete | --attributes |" - " --network | --disk | --deploy |" - " --hostname HOSTNAME | --name NAME |" - " --delete-from-db | --provision]", "-h", "--help", " -s", - "--default", " -d", "--download", " -u", - "--upload", "--dir", "--node", "--node-id", " -r", - "--role", "--net", "--hostname", "--name"] - self.check_all_in_msg("node --help", help_msg) - - self.check_for_rows_in_table("node") - - for action in ("set", "remove", "--network", "--disk"): - self.check_if_required("node {0}".format(action)) - - self.load_data_to_nailgun_server() - self.check_number_of_rows_in_table("node --node 9f:b6,9d:24,ab:aa", 3) - - def test_selected_node_provision(self): - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.run_cli_commands(( - "env create --name=NewEnv --release={0}".format(release_id), - "--env-id=1 node set --node 1 --role=controller" - )) - cmd = "--env-id=1 node --provision --node=1" - msg = "Started provisioning nodes [1].\n" - - self.check_for_stdout(cmd, msg) - - def test_help_works_without_connection(self): - fake_config = 'SERVER_ADDRESS: "333.333.333.333"' - - c_handle, c_path = tempfile.mkstemp(suffix='.json', text=True) - with open(c_path, 'w') as f: - f.write(fake_config) - - env = os.environ.copy() - env['FUELCLIENT_CUSTOM_SETTINGS'] = c_path - - try: - result = self.run_cli_command("--help", env=env) - self.assertEqual(result.return_code, 0) - finally: - os.remove(c_path) - - def test_error_when_destroying_online_node(self): - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.run_cli_commands(( - "env create --name=NewEnv --release={0}".format(release_id), - "--env-id=1 node set --node 1 --role=controller" - ), check_errors=False) - msg = ("Nodes with ids [1] cannot be deleted from cluster because " - "they are online. You might want to use the --force option.\n") - self.check_for_stderr( - "node --node 1 --delete-from-db", - msg, - check_errors=False - ) - - def test_force_destroy_online_node(self): - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.run_cli_commands(( - "env create --name=NewEnv --release={0}".format(release_id), - "--env-id=1 node set --node 1 --role=controller" - )) - msg = ("Nodes with ids [1] have been deleted from Fuel db.\n") - self.check_for_stdout( - "node --node 1 --delete-from-db --force", - msg - ) - - def test_destroy_offline_node(self): - - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - node_id = 4 - self.run_cli_commands(( - "env create --name=NewEnv --release={0}".format(release_id), - "--env-id=1 node set --node {0} --role=controller".format(node_id) - )) - msg = ("Nodes with ids [{0}] have been deleted from Fuel db.\n".format( - node_id)) - self.check_for_stdout( - "node --node {0} --delete-from-db".format(node_id), - msg - ) - - def test_node_change_hostname(self): - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.run_cli_commands(( - "env create --name=NewEnv --release={0}".format(release_id), - "--env-id=1 node set --node 2 --role=controller" - )) - msg = "Hostname for node with id 2 has been changed to test-name.\n" - self.check_for_stdout( - "node --node 2 --hostname test-name", - msg - ) - - def test_env_create_neutron_tun(self): - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.check_for_stdout( - "env create --name=NewEnv --release={0} --nst=tun" - .format(release_id), - "Environment 'NewEnv' with id=1 was created!\n") - - def test_destroy_multiple_nodes(self): - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.run_cli_commands(( - "env create --name=NewEnv --release={0}".format(release_id), - "--env-id=1 node set --node 1 2 --role=controller" - )) - msg = ("Nodes with ids [1, 2] have been deleted from Fuel db.\n") - self.check_for_stdout( - "node --node 1 2 --delete-from-db --force", - msg - ) - - def test_for_examples_in_action_help(self): - actions = ( - "node", "stop", "deployment", "reset", "network", - "settings", "provisioning", "environment", "deploy-changes", - "role", "release", "snapshot", "health", "vip" - ) - for action in actions: - self.check_all_in_msg("{0} -h".format(action), ("Examples",)) - - def test_get_release_list_without_errors(self): - cmd = 'release --list' - self.run_cli_command(cmd) - - def test_reassign_node_group(self): - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.run_cli_commands(( - "env create --name=NewEnv --release={0} --nst=gre" - .format(release_id), - "--env-id=1 node set --node 1 2 --role=controller", - "nodegroup --create --env 1 --name 'new group'" - )) - msg = ['PUT http://127.0.0.1', - '/api/v1/nodes/ data=', - '"id": 1', - '"group_id": 2'] - self.check_all_in_msg( - "nodegroup --assign --group 2 --node 1 --debug", - msg - ) - - def test_node_group_creation_prints_warning_w_seg_type_vlan(self): - warn_msg = ("WARNING: In VLAN segmentation type, there will be no " - "connectivity over private network between instances " - "running on hypervisors in different segments and that " - "it's a user's responsibility to handle this " - "situation.") - - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.run_cli_commands(( - "env create --name=NewEnv --release={0} --nst=vlan" - .format(release_id), - - )) - self.check_for_stderr( - "nodegroup create --name tor1 --env 1", - warn_msg, - check_errors=False - ) - - def test_create_network_group_fails_w_duplicate_name(self): - err_msg = ("(Network with name storage already exists " - "in node group default)\n") - release_id = self.get_first_deployable_release_id() - self.run_cli_commands(( - "env create --name=NewEnv --release={0} --nst=gre" - .format(release_id), - )) - self.check_for_stderr( - ("network-group --create --name storage --node-group 1 " - "--vlan 10 --cidr 10.0.0.0/24"), - err_msg, - check_errors=False - ) - - def test_create_network_group_fails_w_invalid_group(self): - err_msg = "(Node group with ID 997755 does not exist)\n" - - self.check_for_stderr( - ("network-group --create --name test --node-group 997755 " - "--vlan 10 --cidr 10.0.0.0/24"), - err_msg, - check_errors=False - ) - - -class TestCharset(base.CLIv1TestCase): - - def test_charset_problem(self): - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.run_cli_commands(( - "env create --name=привет --release={0}".format(release_id), - "--env-id=1 node set --node 1 --role=controller", - "env" - )) - - -class TestFiles(base.CLIv1TestCase): - - def test_file_creation(self): - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.run_cli_commands(( - "env create --name=NewEnv --release={0}".format(release_id), - "--env-id=1 node set --node 1 --role=controller", - "--env-id=1 node set --node 2,3 --role=compute" - )) - for action in ("network", "settings"): - for format_ in ("yaml", "json"): - self.check_if_files_created( - "--env 1 {0} --download --{1}".format(action, format_), - ("{0}_1.{1}".format(action, format_),) - ) - command_to_files_map = ( - ( - "--env 1 deployment --default", - ( - "deployment_1", - "deployment_1/1.yaml", - "deployment_1/2.yaml", - "deployment_1/3.yaml" - ) - ), - ( - "--env 1 provisioning --default", - ( - "provisioning_1", - "provisioning_1/engine.yaml", - "provisioning_1/node-1.yaml", - "provisioning_1/node-2.yaml", - "provisioning_1/node-3.yaml" - ) - ), - ( - "--env 1 deployment --default --json", - ( - "deployment_1/1.json", - "deployment_1/2.json", - "deployment_1/3.json" - ) - ), - ( - "--env 1 provisioning --default --json", - ( - "provisioning_1/engine.json", - "provisioning_1/node-1.json", - "provisioning_1/node-2.json", - "provisioning_1/node-3.json" - ) - ), - ( - "node --node 1 --disk --default", - ( - "node_1", - "node_1/disks.yaml" - ) - ), - ( - "node --node 1 --network --default", - ( - "node_1", - "node_1/interfaces.yaml" - ) - ), - ( - "node --node 1 --disk --default --json", - ( - "node_1/disks.json", - ) - ), - ( - "node --node 1 --network --default --json", - ( - "node_1/interfaces.json", - ) - ) - ) - for command, files in command_to_files_map: - self.check_if_files_created(command, files) - - def check_if_files_created(self, command, paths): - command_in_dir = "{0} --dir={1}".format(command, self.temp_directory) - self.run_cli_command(command_in_dir) - for path in paths: - self.assertTrue(os.path.exists( - os.path.join(self.temp_directory, path) - )) - - -class TestDownloadUploadNodeAttributes(base.CLIv1TestCase): - - def test_upload_download_interfaces(self): - self.load_data_to_nailgun_server() - - release_id = self.get_first_deployable_release_id() - env_create = "env create --name=test --release={0}".format(release_id) - add_node = "--env-id=1 node set --node 1 --role=controller" - - cmd = "node --node-id 1 --network" - self.run_cli_commands((env_create, - add_node, - self.download_command(cmd), - self.upload_command(cmd))) - - def test_upload_download_disks(self): - self.load_data_to_nailgun_server() - cmd = "node --node-id 1 --disk" - self.run_cli_commands((self.download_command(cmd), - self.upload_command(cmd))) - - -class TestDeployChanges(base.CLIv1TestCase): - - cmd_create_env = "env create --name=test --release={0}" - cmd_add_node = "--env-id=1 node set --node 1 --role=controller" - cmd_deploy_changes = "deploy-changes --env 1" - cmd_redeploy_changes = "redeploy-changes --env 1" - - pattern_success = (r"^Deployment task with id (\d{1,}) " - r"for the environment 1 has been started.\n$") - - def setUp(self): - super(TestDeployChanges, self).setUp() - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.cmd_create_env = self.cmd_create_env.format(release_id) - self.run_cli_commands(( - self.cmd_create_env, - self.cmd_add_node - )) - - def test_deploy_changes(self): - self.check_for_stdout_by_regexp(self.cmd_deploy_changes, - self.pattern_success) - - def test_redeploy_changes(self): - result = self.check_for_stdout_by_regexp(self.cmd_deploy_changes, - self.pattern_success) - task_id = result.group(1) - self.wait_task_ready(task_id) - self.check_for_stdout_by_regexp(self.cmd_redeploy_changes, - self.pattern_success) - - -class TestDirectoryDoesntExistErrorMessages(base.CLIv1TestCase): - - def test_settings_upload(self): - self.check_for_stderr( - "settings --upload --dir /foo/bar/baz --env 1", - "Directory '/foo/bar/baz' doesn't exist.\n", - check_errors=False - ) - - def test_deployment_upload(self): - self.check_for_stderr( - "deployment --upload --dir /foo/bar/baz --env 1", - "Directory '/foo/bar/baz' doesn't exist.\n", - check_errors=False - ) - - def test_net_upload(self): - self.check_for_stderr( - "network --upload --dir /foo/bar/baz --env 1", - "Directory '/foo/bar/baz' doesn't exist.\n", - check_errors=False - ) - - def test_env_download(self): - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.run_cli_commands(( - "env create --name=NewEnv --release={0}".format(release_id), - "--env-id=1 node set --node 2 --role=controller" - )) - self.check_for_stderr( - "network --download --dir /foo/bar/baz --env 1", - "Directory '/foo/bar/baz' doesn't exist.\n", - check_errors=False - ) - - def test_download_network_configuration(self): - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.run_cli_commands(( - "env create --name=NewEnv --release={0}".format(release_id), - "--env-id=1 node set --node 2 --role=controller" - )) - self.check_for_stderr( - "--env 1 network --download --dir /foo/bar/baz", - "Directory '/foo/bar/baz' doesn't exist.\n", - check_errors=False - ) - - def test_download_default_settings(self): - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.run_cli_commands(( - "env create --name=NewEnv --release={0}".format(release_id), - "--env-id=1 node set --node 2 --role=controller" - )) - self.check_for_stderr( - "--env 1 settings --default --dir /foo/bar/baz", - "Directory '/foo/bar/baz' doesn't exist.\n", - check_errors=False - ) - - def test_upload_network_configuration(self): - self.check_for_stderr( - "--env 1 network --upload --dir /foo/bar/baz", - "Directory '/foo/bar/baz' doesn't exist.\n", - check_errors=False - ) - - def test_upload_network_template(self): - self.check_for_stderr( - "--env 1 network-template --upload --dir /foo/bar/baz", - "Directory '/foo/bar/baz' doesn't exist.\n", - check_errors=False - ) - - -class TestUploadSettings(base.CLIv1TestCase): - - create_env = "env create --name=test --release={0}" - add_node = "--env-id=1 node set --node 1 --role=controller" - deploy_changes = "deploy-changes --env 1" - cmd = "settings --env 1" - cmd_force = "settings --env 1 --force" - - def setUp(self): - super(TestUploadSettings, self).setUp() - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.create_env = self.create_env.format(release_id) - self.run_cli_commands(( - self.create_env, - self.add_node, - self.download_command(self.cmd) - )) - - def test_upload_settings(self): - msg_success = "Settings configuration uploaded.\n" - self.check_for_stdout(self.upload_command(self.cmd), - msg_success) diff --git a/fuelclient/tests/functional/v2/__init__.py b/fuelclient/tests/functional/v2/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fuelclient/tests/functional/v2/test_client.py b/fuelclient/tests/functional/v2/test_client.py deleted file mode 100644 index 33ea9af..0000000 --- a/fuelclient/tests/functional/v2/test_client.py +++ /dev/null @@ -1,82 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2013-2014 Mirantis, Inc. -# -# Licensed 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 fuelclient.tests.functional import base - - -class TestDeployChanges(base.CLIv2TestCase): - - cmd_create_env = "env create -r {0} cluster-test" - cmd_add_node = "env add nodes -e 1 -n 1 -r controller" - cmd_deploy_changes = "env deploy 1" - cmd_redeploy_changes = "env redeploy 1" - - pattern_success = (r"^Deployment task with id (\d{1,}) " - r"for the environment 1 has been started.\n$") - - def setUp(self): - super(TestDeployChanges, self).setUp() - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.cmd_create_env = self.cmd_create_env.format(release_id) - self.run_cli_commands(( - self.cmd_create_env, - self.cmd_add_node - )) - - def test_deploy_changes(self): - self.check_for_stdout_by_regexp(self.cmd_deploy_changes, - self.pattern_success) - - def test_redeploy_changes(self): - result = self.check_for_stdout_by_regexp(self.cmd_deploy_changes, - self.pattern_success) - task_id = result.group(1) - self.wait_task_ready(task_id) - - self.check_for_stdout_by_regexp(self.cmd_redeploy_changes, - self.pattern_success) - - -class TestExtensionManagement(base.CLIv2TestCase): - - cmd_create_env = "env create -r {0} cluster-test-extensions-mgmt" - cmd_disable_exts = "env extension disable 1 --extensions volume_manager" - cmd_enable_exts = "env extension enable 1 --extensions volume_manager" - - pattern_enable_success = (r"^The following extensions: volume_manager " - r"have been enabled for the environment with " - r"id 1.\n$") - pattern_disable_success = (r"^The following extensions: volume_manager " - r"have been disabled for the environment with " - r"id 1.\n$") - - def setUp(self): - super(TestExtensionManagement, self).setUp() - self.load_data_to_nailgun_server() - release_id = self.get_first_deployable_release_id() - self.cmd_create_env = self.cmd_create_env.format(release_id) - self.run_cli_commands(( - self.cmd_create_env, - )) - - def test_disable_extensions(self): - self.check_for_stdout_by_regexp(self.cmd_disable_exts, - self.pattern_disable_success) - - def test_enable_extensions(self): - self.check_for_stdout_by_regexp(self.cmd_enable_exts, - self.pattern_enable_success) diff --git a/fuelclient/tests/unit/__init__.py b/fuelclient/tests/unit/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fuelclient/tests/unit/common/__init__.py b/fuelclient/tests/unit/common/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fuelclient/tests/unit/common/test_config.py b/fuelclient/tests/unit/common/test_config.py deleted file mode 100644 index 4d8f9fd..0000000 --- a/fuelclient/tests/unit/common/test_config.py +++ /dev/null @@ -1,145 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fixtures -import mock - -from fuelclient.cli import error -from fuelclient import fuelclient_settings -from fuelclient.tests.unit.v1 import base - - -class TestSettings(base.UnitTestCase): - - def setUp(self): - super(TestSettings, self).setUp() - - self.useFixture(fixtures.MockPatchObject(fuelclient_settings, - '_SETTINGS', - None)) - - @mock.patch('os.makedirs') - @mock.patch('shutil.copy') - @mock.patch('os.chmod') - @mock.patch('os.path.exists') - def test_config_generation(self, m_exists, m_chmod, m_copy, m_makedirs): - project_dir = os.path.dirname(fuelclient_settings.__file__) - - expected_fmode = 0o600 - expected_dmode = 0o700 - expected_default = os.path.join(project_dir, - 'fuel_client.yaml') - expected_path = os.path.expanduser('~/.config/fuel/fuel_client.yaml') - conf_home = os.path.expanduser('~/.config/') - conf_dir = os.path.dirname(expected_path) - - m_exists.return_value = False - f_confdir = fixtures.EnvironmentVariable('XDG_CONFIG_HOME', conf_home) - f_settings = fixtures.EnvironmentVariable('FUELCLIENT_CUSTOM_SETTINGS') - - self.useFixture(f_confdir) - self.useFixture(f_settings) - - fuelclient_settings.get_settings() - - m_makedirs.assert_called_once_with(conf_dir, expected_dmode) - m_copy.assert_called_once_with(expected_default, expected_path) - m_chmod.assert_called_once_with(expected_path, expected_fmode) - - @mock.patch('os.makedirs') - @mock.patch('os.path.exists') - def test_config_generation_write_error(self, m_exists, m_makedirs): - m_exists.return_value = False - m_makedirs.side_effect = OSError('[Errno 13] Permission denied') - - f_settings = fixtures.EnvironmentVariable('FUELCLIENT_CUSTOM_SETTINGS') - self.useFixture(f_settings) - - self.assertRaises(error.SettingsException, - fuelclient_settings.get_settings) - - @mock.patch('six.print_') - def test_deprecated_option_produces_warning(self, m_print): - expected_warings = [mock.call('DEPRECATION WARNING: LISTEN_PORT ' - 'parameter was deprecated and will not ' - 'be supported in the next version of ' - 'python-fuelclient.', end='', - file=sys.stderr), - mock.call(' Please replace this ' - 'parameter with SERVER_PORT', - file=sys.stderr)] - - m = mock.mock_open(read_data='LISTEN_PORT: 9000') - with mock.patch('fuelclient.fuelclient_settings.open', m): - fuelclient_settings.get_settings() - - m_print.assert_has_calls(expected_warings, any_order=False) - - @mock.patch('six.print_') - def test_both_deprecated_and_new_options_produce_warning(self, m_print): - expected_waring = ('WARNING: configuration contains both ' - 'LISTEN_PORT and SERVER_PORT options set. Since ' - 'LISTEN_PORT was deprecated, only the value of ' - 'SERVER_PORT will be used.') - - m = mock.mock_open(read_data='LISTEN_PORT: 9000\nSERVER_PORT: 9000') - with mock.patch('fuelclient.fuelclient_settings.open', m): - fuelclient_settings.get_settings() - - m_print.assert_has_calls([mock.call(expected_waring, file=sys.stderr)]) - - @mock.patch('six.print_') - def test_set_deprecated_option_overwrites_unset_new_option(self, m_print): - m = mock.mock_open(read_data='KEYSTONE_PASS: "admin"\n' - 'OS_PASSWORD:\n') - with mock.patch('fuelclient.fuelclient_settings.open', m): - settings = fuelclient_settings.get_settings() - - self.assertEqual('admin', settings.OS_PASSWORD) - self.assertNotIn('OS_PASSWORD', settings.config) - - def test_fallback_to_deprecated_option(self): - m = mock.mock_open(read_data='LISTEN_PORT: 9000') - with mock.patch('fuelclient.fuelclient_settings.open', m): - settings = fuelclient_settings.get_settings() - - self.assertEqual(9000, settings.LISTEN_PORT) - - def test_update_from_cli_params(self): - test_config_text = ('SERVER_ADDRESS: "127.0.0.1"\n' - 'SERVER_PORT: "8000"\n' - 'OS_USERNAME: "admin"\n' - 'OS_PASSWORD:\n' - 'OS_TENANT_NAME:\n') - - test_parsed_args = mock.Mock(os_password='test_password', - server_port="3000", - os_username=None) - del test_parsed_args.server_address - del test_parsed_args.os_tenant_name - - m = mock.mock_open(read_data=test_config_text) - with mock.patch('fuelclient.fuelclient_settings.open', m): - settings = fuelclient_settings.get_settings() - - settings.update_from_command_line_options(test_parsed_args) - - self.assertEqual('3000', settings.SERVER_PORT) - self.assertEqual('test_password', settings.OS_PASSWORD) - self.assertEqual('admin', settings.OS_USERNAME) diff --git a/fuelclient/tests/unit/common/test_environments.py b/fuelclient/tests/unit/common/test_environments.py deleted file mode 100644 index da31963..0000000 --- a/fuelclient/tests/unit/common/test_environments.py +++ /dev/null @@ -1,127 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 mock -import os - -from fuelclient import objects - -from fuelclient.tests.unit.v1 import base - - -class TestEnvironmentObject(base.UnitTestCase): - - def setUp(self): - super(TestEnvironmentObject, self).setUp() - self.env_object = objects.Environment(1) - - def _setup_os_mock(self, os_mock): - os_mock.path.exists.return_value = False - os_mock.path.join = os.path.join - os_mock.path.abspath = lambda x: x - - @mock.patch("fuelclient.objects.environment.os") - def test_write_facts_to_dir_for_legacy_envs(self, os_mock): - facts = [ - { - "uid": "1", - "role": "controller", - "data": "data1" - }, - { - "uid": "2", - "role": "compute", - "data": "data2" - }, - ] - - self._setup_os_mock(os_mock) - serializer = mock.MagicMock() - - self.env_object.write_facts_to_dir( - "deployment", facts, serializer=serializer - ) - - serializer.write_to_path.assert_has_calls( - [ - mock.call("./deployment_1/controller_1", facts[0]), - mock.call("./deployment_1/compute_2", facts[1]) - ] - ) - - @mock.patch("fuelclient.objects.environment.os") - def test_write_facts_to_dir_for_new_envs(self, os_mock): - facts = [ - { - "uid": "1", - "roles": ["controller"], - "data": "data1" - }, - { - "uid": "2", - "roles": ["compute"], - "data": "data2" - }, - ] - - self._setup_os_mock(os_mock) - serializer = mock.MagicMock() - - self.env_object.write_facts_to_dir( - "deployment", facts, serializer=serializer - ) - - serializer.write_to_path.assert_has_calls( - [ - mock.call("./deployment_1/1", facts[0]), - mock.call("./deployment_1/2", facts[1]) - ] - ) - - @mock.patch("fuelclient.objects.environment.os") - def test_write_facts_to_dir_if_facts_is_dict(self, os_mock): - facts = { - "engine": "test_engine", - "nodes": [ - { - "uid": "1", - "name": "node-1", - "roles": ["controller"], - "data": "data1" - }, - { - "uid": "2", - "name": "node-2", - "roles": ["compute"], - "data": "data2" - }, - ] - } - - self._setup_os_mock(os_mock) - serializer = mock.MagicMock() - - self.env_object.write_facts_to_dir( - "deployment", facts, serializer=serializer - ) - - serializer.write_to_path.assert_has_calls( - [ - mock.call("./deployment_1/engine", facts['engine']), - mock.call("./deployment_1/node-1", facts['nodes'][0]), - mock.call("./deployment_1/node-2", facts['nodes'][1]) - ] - ) diff --git a/fuelclient/tests/unit/common/test_network_template.py b/fuelclient/tests/unit/common/test_network_template.py deleted file mode 100644 index 60a2f72..0000000 --- a/fuelclient/tests/unit/common/test_network_template.py +++ /dev/null @@ -1,157 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 json -import mock -import six -import yaml - -from fuelclient.tests.unit.v1 import base - -YAML_TEMPLATE = """adv_net_template: - default: - network_assignments: - fuelweb_admin: - ep: br-fw-admin - management: - ep: br-mgmt - private: - ep: br-prv - public: - ep: br-ex - storage: - ep: br-storage - nic_mapping: - default: - if1: eth0 - templates_for_node_role: - ceph-osd: - - common - - storage - compute: - - common - - private - - storage - controller: - - public - - private - - storage - - common -""" - -JSON_TEMPLATE = """{ - "adv_net_template": { - "default": { - "nic_mapping": { - "default": { - "if1": "eth0" - } - }, - "templates_for_node_role": { - "controller": [ - "public", - "private", - "storage", - "common" - ], - "compute": [ - "common", - "private", - "storage" - ], - "ceph-osd": [ - "common", - "storage" - ] - }, - "network_assignments": { - "storage": { - "ep": "br-storage" - }, - "private": { - "ep": "br-prv" - }, - "public": { - "ep": "br-ex" - }, - "management": { - "ep": "br-mgmt" - }, - "fuelweb_admin": { - "ep": "br-fw-admin" - } - } - } - } -} -""" - - -class TestNetworkTemplate(base.UnitTestCase): - def setUp(self): - super(TestNetworkTemplate, self).setUp() - - self.env_id = 42 - self.req_path = ('/api/v1/clusters/{0}/network_configuration/' - 'template'.format(self.env_id)) - - def test_upload_action(self): - mput = self.m_request.put(self.req_path, json={}) - test_command = [ - 'fuel', 'network-template', '--env', str(self.env_id), '--upload'] - - m_open = mock.mock_open(read_data=YAML_TEMPLATE) - with mock.patch('fuelclient.cli.serializers.open', - m_open, - create=True): - self.execute(test_command) - - self.assertTrue(mput.called) - self.assertEqual(mput.last_request.json(), json.loads(JSON_TEMPLATE)) - m_open().read.assert_called_once_with() - - def test_download_action(self): - mget = self.m_request.get(self.req_path, text=JSON_TEMPLATE) - - test_command = [ - 'fuel', 'network-template', '--env', str(self.env_id), - '--download'] - - m_open = mock.mock_open() - with mock.patch('fuelclient.cli.serializers.open', m_open, - create=True): - self.execute(test_command) - - self.assertTrue(mget.called) - - written_yaml = yaml.safe_load(m_open().write.mock_calls[0][1][0]) - expected_yaml = yaml.safe_load(YAML_TEMPLATE) - self.assertEqual(written_yaml, expected_yaml) - - def test_delete_action(self): - mdelete = self.m_request.delete(self.req_path, json={}) - - cmd = ['fuel', 'network-template', '--env', str(self.env_id), - '--delete'] - - with mock.patch('sys.stdout', new=six.StringIO()) as m_out: - self.execute(cmd) - - self.assertTrue(mdelete.called) - - msg = ("Network template configuration for environment id={0}" - " has been deleted.".format(self.env_id)) - self.assertIn(msg, m_out.getvalue()) diff --git a/fuelclient/tests/unit/common/test_release.py b/fuelclient/tests/unit/common/test_release.py deleted file mode 100644 index d024a9e..0000000 --- a/fuelclient/tests/unit/common/test_release.py +++ /dev/null @@ -1,88 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient.commands.release import ReleaseComponentList -from fuelclient.tests.unit.v1 import base - - -class TestReleaseComponent(base.UnitTestCase): - - def test_retrieve_predicates(self): - predicates = ('any_of', 'all_of', 'one_of', 'none_of') - items = { - "items": ["fake:component:1", - "fake:component:2"] - } - - for predicate in predicates: - test_data = {predicate: items} - real_data = ReleaseComponentList.retrieve_predicates(test_data) - expected_data = "{} (fake:component:1, fake:component:2)".format( - predicate) - self.assertEqual(expected_data, real_data) - - def test_retrieve_predicates_w_wrong_predicate(self): - test_data = { - "bad_predicate": { - "items": ["fake:component:1", - "fake:component:2"], - } - } - - self.assertRaisesRegexp(ValueError, - "Predicates not found.", - ReleaseComponentList.retrieve_predicates, - test_data) - - def test_retrieve_data(self): - test_data = "fake:component:1" - real_data = ReleaseComponentList.retrieve_data(test_data) - self.assertEqual("fake:component:1", real_data) - - test_data = [{"name": "fake:component:1"}] - real_data = ReleaseComponentList.retrieve_data(test_data) - self.assertEqual("fake:component:1", real_data) - - test_data = [ - { - "one_of": { - "items": ["fake:component:1"] - } - }, - { - "any_of": { - "items": ["fake:component:1", - "fake:component:2"] - } - }, - { - "all_of": { - "items": ["fake:component:1", - "fake:component:2"] - } - }, - { - "none_of": { - "items": ["fake:component:1"] - } - } - ] - real_data = ReleaseComponentList.retrieve_data(test_data) - expected_data = ("one_of (fake:component:1), " - "any_of (fake:component:1, fake:component:2), " - "all_of (fake:component:1, fake:component:2), " - "none_of (fake:component:1)") - self.assertEqual(expected_data, real_data) diff --git a/fuelclient/tests/unit/common/test_serializers.py b/fuelclient/tests/unit/common/test_serializers.py deleted file mode 100644 index 13163ad..0000000 --- a/fuelclient/tests/unit/common/test_serializers.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 json - -import mock -import yaml - -from fuelclient.cli import error -from fuelclient.cli.serializers import Serializer -from fuelclient.tests.unit.v1 import base - - -class TestSerializers(base.UnitTestCase): - - DATA = { - 'a': 1, - 'b': { - 'c': [2, 3, 4], - 'd': 'string', - } - } - - def test_get_from_params(self): - params_to_formats = ( - ('yaml', 'yaml'), - ('json', 'json'), - ('xyz', Serializer.default_format), - ) - for param, format in params_to_formats: - params = mock.Mock(serialization_format=format) - serializer = Serializer.from_params(params) - self.assertEqual(serializer.format, format) - - def test_serialize(self): - deserializers = {'json': json.loads, 'yaml': yaml.load} - for format, deserialize in deserializers.items(): - serialized = Serializer(format).serialize(self.DATA) - self.assertEqual(self.DATA, deserialize(serialized)) - - def test_deserialize(self): - serializers = {'json': json.dumps, 'yaml': yaml.safe_dump} - for format, serialize in serializers.items(): - serialized = serialize(self.DATA) - deserialized = Serializer(format).deserialize(serialized) - self.assertEqual(self.DATA, deserialized) - - def test_deserialize_fail(self): - - broken_data = '{foo: bar: buzz:}' - for format in ('json', 'yaml'): - self.assertRaises(error.BadDataException, - Serializer(format).deserialize, broken_data) - - def test_write_to_path_invalid_file_exception(self): - serializer = Serializer('json') - mo = mock.mock_open() - with mock.patch('__main__.open', mo, create=True) as mocked_open: - mocked_open.side_effect = IOError() - self.assertRaises(error.InvalidFileException, - serializer.write_to_path, - '/foo/bar/baz', self.DATA) diff --git a/fuelclient/tests/unit/common/test_settings.py b/fuelclient/tests/unit/common/test_settings.py deleted file mode 100644 index 0cdad63..0000000 --- a/fuelclient/tests/unit/common/test_settings.py +++ /dev/null @@ -1,97 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock import mock_open -from mock import patch - -from fuelclient.tests.unit.v1 import base - - -YAML_SETTINGS_DATA = """editable: - access: - user: - value: test_user -""" -JSON_SETTINGS_DATA = { - 'editable': { - 'access': { - 'user': { - 'value': 'test_user' - } - } - } -} - - -class BaseSettings(base.UnitTestCase): - - def check_upload_action(self, test_command, test_url): - m = mock_open(read_data=YAML_SETTINGS_DATA) - put = self.m_request.put(test_url, json={}) - - with patch('six.moves.builtins.open', m, create=True): - self.execute(test_command) - - m().read.assert_called_once_with() - self.assertTrue(put.called) - self.assertDictEqual(put.last_request.json(), JSON_SETTINGS_DATA) - - def check_default_action(self, test_command, test_url): - m = mock_open() - get = self.m_request.get(test_url, json=JSON_SETTINGS_DATA) - - with patch('six.moves.builtins.open', m, create=True): - self.execute(test_command) - - self.assertTrue(get.called) - m().write.assert_called_once_with(YAML_SETTINGS_DATA) - - def check_download_action(self, test_command, test_url): - m = mock_open() - get = self.m_request.get(test_url, json=JSON_SETTINGS_DATA) - - with patch('six.moves.builtins.open', m, create=True): - self.execute(test_command) - - m().write.assert_called_once_with(YAML_SETTINGS_DATA) - self.assertTrue(get.called) - - -class TestSettings(BaseSettings): - - def test_upload_action(self): - self.check_upload_action( - test_command=[ - 'fuel', 'settings', '--env', '1', '--upload'], - test_url='/api/v1/clusters/1/attributes') - - def test_upload_force_action(self): - self.check_upload_action( - test_command=[ - 'fuel', 'settings', '--env', '1', '--upload', '--force'], - test_url='/api/v1/clusters/1/attributes?force=1') - - def test_default_action(self): - self.check_default_action( - test_command=[ - 'fuel', 'settings', '--env', '1', '--default'], - test_url='/api/v1/clusters/1/attributes/defaults') - - def test_download_action(self): - self.check_download_action( - test_command=[ - 'fuel', 'settings', '--env', '1', '--download'], - test_url='/api/v1/clusters/1/attributes') diff --git a/fuelclient/tests/unit/common/test_utils.py b/fuelclient/tests/unit/common/test_utils.py deleted file mode 100644 index 34c0cb2..0000000 --- a/fuelclient/tests/unit/common/test_utils.py +++ /dev/null @@ -1,331 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 json -import os -import six -import subprocess -import yaml - -import mock -import requests - -from fuelclient.cli import error -from fuelclient import client -from fuelclient.common import data_utils -from fuelclient.tests.unit.v1 import base -from fuelclient import utils - - -class TestUtils(base.UnitTestCase): - - @mock.patch('fuelclient.utils.os.walk') - def test_iterfiles(self, mwalk): - mwalk.return_value = [ - ('/some_directory/', [], ['valid.yaml', 'invalid.yml'])] - - pattern = '*.yaml' - directory = '/some_directory' - - expected_result = [os.path.join(directory, 'valid.yaml')] - files = list(utils.iterfiles(directory, pattern)) - - mwalk.assert_called_once_with(directory, followlinks=True) - self.assertEqual(expected_result, files) - - def make_process_mock(self, return_code=0): - process_mock = mock.Mock() - process_mock.stdout = ['Stdout line 1', 'Stdout line 2'] - process_mock.returncode = return_code - - return process_mock - - def test_exec_cmd(self): - cmd = 'some command' - - process_mock = self.make_process_mock() - with mock.patch.object( - subprocess, 'Popen', return_value=process_mock) as popen_mock: - utils.exec_cmd(cmd) - - popen_mock.assert_called_once_with( - cmd, - stdout=None, - stderr=subprocess.STDOUT, - shell=True, - cwd=None) - - def test_exec_cmd_raises_error(self): - cmd = 'some command' - return_code = 1 - - process_mock = self.make_process_mock(return_code=return_code) - - with mock.patch.object( - subprocess, 'Popen', return_value=process_mock) as popen_mock: - self.assertRaisesRegexp( - error.ExecutedErrorNonZeroExitCode, - 'Shell command executed with "{0}" ' - 'exit code: {1} '.format(return_code, cmd), - utils.exec_cmd, cmd) - - popen_mock.assert_called_once_with( - cmd, - stdout=None, - stderr=subprocess.STDOUT, - shell=True, - cwd=None) - - def test_exec_cmd_iterator(self): - cmd = 'some command' - - process_mock = self.make_process_mock() - with mock.patch.object( - subprocess, 'Popen', return_value=process_mock) as popen_mock: - for line in utils.exec_cmd_iterator(cmd): - self.assertTrue(line.startswith('Stdout line ')) - - popen_mock.assert_called_once_with( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=True) - - def test_exec_cmd_iterator_raises_error(self): - cmd = 'some command' - return_code = 1 - - process_mock = self.make_process_mock(return_code=return_code) - with mock.patch.object(subprocess, 'Popen', return_value=process_mock): - with self.assertRaisesRegexp( - error.ExecutedErrorNonZeroExitCode, - 'Shell command executed with "{0}" ' - 'exit code: {1} '.format(return_code, cmd)): - for line in utils.exec_cmd_iterator(cmd): - self.assertTrue(line.startswith('Stdout line ')) - - def test_parse_yaml_file(self): - mock_open = self.mock_open("key: value") - - with mock.patch('fuelclient.utils.io.open', mock_open): - self.assertEqual( - utils.parse_yaml_file('some_file_name'), - {'key': 'value'}) - - @mock.patch('fuelclient.utils.glob.iglob', - return_value=['file1', 'file2']) - @mock.patch('fuelclient.utils.parse_yaml_file', - side_effect=['content_file1', 'content_file2']) - def test_glob_and_parse_yaml(self, parse_mock, iglob_mock): - path = '/tmp/path/mask*' - - content = [] - for data in utils.glob_and_parse_yaml(path): - content.append(data) - - iglob_mock.assert_called_once_with(path) - self.assertEqual( - parse_mock.call_args_list, - [mock.call('file1'), - mock.call('file2')]) - - self.assertEqual(content, ['content_file1', 'content_file2']) - - def test_major_plugin_version(self): - pairs = [ - ['1.2.3', '1.2'], - ['123456789.123456789.12121', '123456789.123456789'], - ['1.2', '1.2']] - - for arg, expected in pairs: - self.assertEqual( - utils.major_plugin_version(arg), - expected) - - @mock.patch('fuelclient.utils.os.path.lexists', side_effect=[True, False]) - def test_file_exists(self, lexists_mock): - self.assertTrue(utils.file_exists('file1')) - self.assertFalse(utils.file_exists('file2')) - - self.assertEqual( - lexists_mock.call_args_list, - [mock.call('file1'), mock.call('file2')]) - - def test_get_error_body_get_from_json(self): - error_body = 'This is error body' - - body_json = json.dumps({ - 'message': error_body - }) - if isinstance(body_json, six.text_type): - body_json = body_json.encode('utf-8') - - resp = requests.Response() - resp._content = body_json - - exception = requests.HTTPError() - exception.response = resp - - self.assertEqual(error.get_error_body(exception), error_body) - - def test_get_error_body_get_from_plaintext(self): - error_body = b'This is error body' - - resp = requests.Response() - resp._content = error_body - - exception = requests.HTTPError() - exception.response = resp - - self.assertEqual(error.get_error_body(exception), - error_body.decode('utf-8')) - - def test_get_display_data_single(self): - test_data = {'a': 1, 'b': [], 'c': [1, 2, 3], 'd': 4} - fields = ('a', 'b', 'c') - - result = data_utils.get_display_data_single(fields, test_data) - self.assertEqual([1, [], [1, 2, 3]], result) - - def test_get_display_data_bad_key(self): - test_data = {'a': 1, 'b': 2, 'c': 3} - fields = ('b', 'bad_key') - self.assertEqual( - [2, None], - data_utils.get_display_data_single(fields, test_data) - ) - - def test_get_display_data_multi(self): - test_data = [{'a': 1, 'b': 2, 'c': 3}, {'b': 8, 'c': 9}] - fields = ('b', 'c') - - result = data_utils.get_display_data_multi(fields, test_data) - self.assertEqual([[2, 3], [8, 9]], result) - - @mock.patch('sys.getfilesystemencoding', return_value='utf-8') - def test_str_to_unicode(self, _): - test_data = 'тест' - expected_data = test_data if six.PY3 else u'тест' - result = utils.str_to_unicode(test_data) - self.assertIsInstance(result, six.text_type) - self.assertEqual(result, expected_data) - - @mock.patch('fuelclient.utils.sys') - def test_latin_str_to_unicode(self, sys_mock): - sys_mock.getfilesystemencoding.return_value = 'iso-8859-16' - - test_data = 'czegoś' if six.PY3 else u'czegoś'.encode('iso-8859-16') - expected_data = test_data if six.PY3 else u'czegoś' - result = utils.str_to_unicode(test_data) - self.assertIsInstance(result, six.text_type) - self.assertEqual(result, expected_data) - - def test_HTTP_error_message(self): - text = 'message text' - - self.m_request.post('/api/v1/address', - json={'message': text}, - status_code=403) - - with self.assertRaisesRegexp(error.HTTPError, - '403.*{}'.format(text)): - client.DefaultAPIClient.post_request('address') - - def test_parse_to_list_of_dicts(self): - items = utils.parse_to_list_of_dicts([{"id": 1}]) - self.assertEqual(items, [{"id": 1}]) - - items = utils.parse_to_list_of_dicts([{"id": 2}, {"id": 3}]) - self.assertEqual(items, [{"id": 2}, {"id": 3}]) - - items = utils.parse_to_list_of_dicts([[{"id": 4}]]) - self.assertEqual(items, [{"id": 4}]) - - items = utils.parse_to_list_of_dicts( - [[{"id": 5}, {"id": 6}], {"id": 7}]) - self.assertEqual(items, [{"id": 5}, {"id": 6}, {"id": 7}]) - - self.assertRaisesRegexp( - TypeError, 'A dict or list instance expected', - utils.parse_to_list_of_dicts, [42]) - - def test_safe_load_json(self): - test_data = {'test_key': 'test_val'} - - m_open = mock.mock_open(read_data=json.dumps(test_data)) - with mock.patch('fuelclient.tests.unit.common.test_utils.open', - m_open): - stream = open('/a/random/file', 'r') - loaded = data_utils.safe_load('json', stream) - - self.assertEqual(test_data, loaded) - - def test_safe_load_yaml(self): - test_data = {'test_key': 'test_val'} - - m_open = mock.mock_open(read_data=yaml.dump(test_data)) - with mock.patch('fuelclient.tests.unit.common.test_utils.open', - m_open): - stream = open('/a/random/file', 'r') - loaded = data_utils.safe_load('yaml', stream) - - self.assertEqual(test_data, loaded) - - @mock.patch('json.dump') - def test_safe_dump_json(self, m_dump): - test_data = {'test_key': 'test_val'} - - m_open = mock.mock_open() - with mock.patch('fuelclient.tests.unit.common.test_utils.open', - m_open): - stream = open('/a/random/file', 'w') - data_utils.safe_dump('json', stream, test_data) - - m_dump.assert_called_once_with(test_data, stream, indent=4) - - @mock.patch('yaml.safe_dump') - def test_safe_dump_yaml(self, m_dump): - test_data = {'test_key': 'test_val'} - - m_open = mock.mock_open() - with mock.patch('fuelclient.tests.unit.common.test_utils.open', - m_open): - stream = open('/a/random/file', 'w') - data_utils.safe_dump('yaml', stream, test_data) - - m_dump.assert_called_once_with(test_data, - stream, - default_flow_style=False) - - def test_safe_dump_wrong_format(self): - test_data = {'test_key': 'test_val'} - - m_open = mock.mock_open() - with mock.patch('fuelclient.tests.unit.common.test_utils.open', - m_open): - stream = open('/a/random/file', 'w') - self.assertRaises(ValueError, - data_utils.safe_dump, - 'bad', stream, test_data) - - def test_safe_load_wrong_format(self): - m_open = mock.mock_open() - with mock.patch('fuelclient.tests.unit.common.test_utils.open', - m_open): - stream = open('/a/random/file', 'w') - self.assertRaises(ValueError, - data_utils.safe_load, - 'bad', stream) diff --git a/fuelclient/tests/unit/v1/__init__.py b/fuelclient/tests/unit/v1/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fuelclient/tests/unit/v1/base.py b/fuelclient/tests/unit/v1/base.py deleted file mode 100644 index 71d3f8e..0000000 --- a/fuelclient/tests/unit/v1/base.py +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright 2013-2015 Mirantis, Inc. -# -# Licensed 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 mock -from oslotest import base as oslo_base -import requests_mock as rm -import six - -from fuelclient.cli import parser - - -class FakeFile(six.StringIO): - """Context manager for a fake file - - NOTE(eli): We cannot use mock_open from mock library - here, because it hangs when we use 'with' statement, - and when we want to read file by chunks. - - """ - def __enter__(self): - return self - - def __exit__(self, *args): - pass - - -class UnitTestCase(oslo_base.BaseTestCase): - """Base test class which does not require nailgun server to run.""" - - def setUp(self): - super(UnitTestCase, self).setUp() - - self.auth_required_patcher = mock.patch('fuelclient.client.' - 'APIClient.auth_required', - new_callable=mock.PropertyMock) - - self.auth_required_mock = self.auth_required_patcher.start() - self.auth_required_mock.return_value = False - - self.m_request = rm.Mocker() - self.m_request.start() - - self.addCleanup(self.auth_required_patcher.stop) - self.addCleanup(self.m_request.stop) - - def execute(self, command): - """Execute old CLI.""" - - return parser.main(command) - - def mock_open(self, text, filename='some.file'): - """Mocks builtin open function - - Usage example: - - with mock.patch('__builtin__.open', self.mock_open('file content')): - # call mocked code - """ - fileobj = FakeFile(text) - setattr(fileobj, 'name', filename) - return mock.MagicMock(return_value=fileobj) diff --git a/fuelclient/tests/unit/v1/test_attributes_actions.py b/fuelclient/tests/unit/v1/test_attributes_actions.py deleted file mode 100644 index 4b33107..0000000 --- a/fuelclient/tests/unit/v1/test_attributes_actions.py +++ /dev/null @@ -1,52 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock import patch - -from fuelclient.tests.unit.v1 import base - - -@patch('fuelclient.cli.serializers.open', create=True) -@patch('fuelclient.cli.actions.base.os') -class TestClusterAttributesActions(base.UnitTestCase): - - _input = { - 'editable': { - 'test': 'foo', - }} - - _output = 'editable:\n test: foo\n' - - def test_attributes_download(self, mos, mopen): - get = self.m_request.get('/api/v1/clusters/1/attributes', - json=self._input) - - self.execute( - ['fuel', 'env', '--env', '1', '--attributes', '--download']) - - self.assertTrue(get.called) - - mopen().__enter__().write.assert_called_once_with(self._output) - - def test_attributes_upload(self, mos, mopen): - mopen().__enter__().read.return_value = self._output - put = self.m_request.put('/api/v1/clusters/1/attributes', json={}) - - self.execute( - ['fuel', 'env', '--env', '1', '--attributes', '--upload']) - - self.assertTrue(put.called) - self.assertEqual(put.last_request.json(), self._input) diff --git a/fuelclient/tests/unit/v1/test_authentication.py b/fuelclient/tests/unit/v1/test_authentication.py deleted file mode 100644 index 5e1948c..0000000 --- a/fuelclient/tests/unit/v1/test_authentication.py +++ /dev/null @@ -1,105 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2013-2014 Mirantis, Inc. -# -# Licensed 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 fixtures -import mock - -from fuelclient import fuelclient_settings -from fuelclient.tests.unit.v1 import base - - -@mock.patch('keystoneclient.v2_0.client.Client', - return_value=mock.Mock(auth_token='')) -class TestAuthentication(base.UnitTestCase): - - def setUp(self): - super(TestAuthentication, self).setUp() - - self.auth_required_mock.return_value = True - self.m_request.get('/api/v1/nodes/', json={}) - - self.useFixture(fixtures.MockPatchObject(fuelclient_settings, - '_SETTINGS', - None)) - - def validate_credentials_response(self, m_client, username=None, - password=None, tenant_name=None): - """Checks whether keystone was called properly.""" - - conf = fuelclient_settings.get_settings() - - expected_url = 'http://{}:{}{}'.format(conf.SERVER_ADDRESS, - conf.SERVER_PORT, - '/keystone/v2.0') - m_client.__init__assert_called_once_with(auth_url=expected_url, - username=username, - password=password, - tenant_name=tenant_name) - - def test_credentials_settings(self, mkeystone_cli): - self.useFixture(fixtures.EnvironmentVariable('OS_USERNAME')) - self.useFixture(fixtures.EnvironmentVariable('OS_PASSWORD')) - self.useFixture(fixtures.EnvironmentVariable('OS_TENANT_NAME')) - - conf = fuelclient_settings.get_settings() - conf.config['OS_USERNAME'] = 'test_user' - conf.config['OS_PASSWORD'] = 'test_password' - conf.config['OS_TENANT_NAME'] = 'test_tenant_name' - - self.execute(['fuel', 'node']) - self.validate_credentials_response(mkeystone_cli, - username='test_user', - password='test_password', - tenant_name='test_tenant_name') - - def test_credentials_cli(self, mkeystone_cli): - self.useFixture(fixtures.EnvironmentVariable('OS_USERNAME')) - self.useFixture(fixtures.EnvironmentVariable('OS_PASSWORD')) - self.useFixture(fixtures.EnvironmentVariable('OS_TENANT_NAME')) - - self.execute(['fuel', '--os-username=a', '--os-tenant-name=admin', - '--os-password=b', 'node']) - self.validate_credentials_response(mkeystone_cli, - username='a', - password='b', - tenant_name='admin') - - def test_authentication_env_variables(self, mkeystone_cli): - self.useFixture(fixtures.EnvironmentVariable('OS_USERNAME', 'name')) - self.useFixture(fixtures.EnvironmentVariable('OS_PASSWORD', 'pass')) - self.useFixture(fixtures.EnvironmentVariable('OS_TENANT_NAME', 'ten')) - - self.execute(['fuel', 'node']) - self.validate_credentials_response(mkeystone_cli, - username='name', - password='pass', - tenant_name='ten') - - def test_credentials_override(self, mkeystone_cli): - self.useFixture(fixtures.EnvironmentVariable('OS_USERNAME')) - self.useFixture(fixtures.EnvironmentVariable('OS_PASSWORD', 'var_p')) - self.useFixture(fixtures.EnvironmentVariable('OS_TENANT_NAME', 'va_t')) - - conf = fuelclient_settings.get_settings() - conf.config['OS_USERNAME'] = 'conf_user' - conf.config['OS_PASSWORD'] = 'conf_password' - conf.config['OS_TENANT_NAME'] = 'conf_tenant_name' - - self.execute(['fuel', '--os-tenant-name=cli_tenant', 'node']) - self.validate_credentials_response(mkeystone_cli, - username='conf_user', - password='var_p', - tenant_name='cli_tenant') diff --git a/fuelclient/tests/unit/v1/test_base_action.py b/fuelclient/tests/unit/v1/test_base_action.py deleted file mode 100644 index 22eabbe..0000000 --- a/fuelclient/tests/unit/v1/test_base_action.py +++ /dev/null @@ -1,78 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock -from six import moves - -from fuelclient.cli.actions import base -from fuelclient.cli import error -from fuelclient.tests.unit.v1 import base as base_tests - - -class TestBaseAction(base_tests.UnitTestCase): - - def setUp(self): - super(TestBaseAction, self).setUp() - self.action = base.Action() - - @mock.patch('fuelclient.cli.actions.base.os') - def test_default_directory_with_param(self, m_os): - directory = 'some/dir' - self.action.default_directory(directory) - m_os.path.abspath.assert_called_once_with(directory) - - @mock.patch('fuelclient.cli.actions.base.os') - def test_default_directory_without_param(self, m_os): - self.action.default_directory() - m_os.path.abspath.assert_called_once_with(m_os.curdir) - - @mock.patch('fuelclient.cli.actions.base.os.mkdir') - @mock.patch('fuelclient.cli.actions.base.os.path.exists') - def test_full_path_directory(self, m_exists, m_mkdir): - m_exists.return_value = False - self.assertEqual( - self.action.full_path_directory('/base/path', 'subdir'), - '/base/path/subdir' - ) - m_mkdir.assert_called_once_with('/base/path/subdir') - - @mock.patch('fuelclient.cli.actions.base.os') - def test_full_path_directory_no_access(self, m_os): - exc_msg = 'Bas permissions' - m_os.path.exists.return_value = False - m_os.mkdir.side_effect = OSError(exc_msg) - - with self.assertRaisesRegexp(error.ActionException, exc_msg): - self.action.full_path_directory('/base/path', 'subdir') - - @mock.patch('fuelclient.cli.actions.base.os') - def test_full_path_directory_already_exists(self, m_os): - m_os.path.exists.return_value = True - self.action.full_path_directory('/base/path', 'subdir') - self.assertEqual(m_os.mkdir.call_count, 0) - - -class TestExtraArguments(base_tests.UnitTestCase): - - def test_error_on_extra_arguments(self): - err_msg = 'unrecognized arguments: extraarg1 extraarg2\n' - - with mock.patch('sys.stderr', new=moves.cStringIO()) as m_stderr: - self.assertRaises( - SystemExit, self.execute, - ['fuel', 'nodegroup', '--delete', 'extraarg1', 'extraarg2']) - - self.assertIn(err_msg, m_stderr.getvalue()) diff --git a/fuelclient/tests/unit/v1/test_deployment_history_action.py b/fuelclient/tests/unit/v1/test_deployment_history_action.py deleted file mode 100644 index 7e30ee1..0000000 --- a/fuelclient/tests/unit/v1/test_deployment_history_action.py +++ /dev/null @@ -1,166 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 mock import patch - -from fuelclient.cli.formatting import format_table -from fuelclient.cli.serializers import Serializer -from fuelclient.tests.unit.v1 import base -from fuelclient.tests import utils -from fuelclient.v1.deployment_history import DeploymentHistoryClient - - -class TestDeploymentTasksAction(base.UnitTestCase): - - @patch.object(Serializer, 'print_to_output') - def test_show_full_history(self, print_mock): - self.m_history_api = self.m_request.get( - '/api/v1/transactions/1/deployment_history/?' - 'nodes=&' - 'statuses=&' - 'tasks_names=', - json=utils.get_fake_deployment_history()) - - self.execute( - ['fuel', 'deployment-tasks', '--tid', '1'] - ) - print_mock.assert_called_once_with( - utils.get_fake_deployment_history(convert_legacy_fields=True), - format_table( - utils.get_fake_deployment_history(convert_legacy_fields=True), - acceptable_keys=DeploymentHistoryClient.history_records_keys)) - - @patch.object(Serializer, 'print_to_output') - def test_show_full_history_include_summary(self, print_mock): - self.m_history_api = self.m_request.get( - '/api/v1/transactions/1/deployment_history/?' - 'nodes=&' - 'statuses=&' - 'include_summary=1&' - 'tasks_names=', - json=utils.get_fake_deployment_history(include_summary=True)) - - self.execute( - ['fuel', 'deployment-tasks', '--tid', '1', '--include-summary'] - ) - print_mock.assert_called_once_with( - utils.get_fake_deployment_history(convert_legacy_fields=True, - include_summary=True), - format_table( - utils.get_fake_deployment_history(convert_legacy_fields=True, - include_summary=True), - acceptable_keys=(DeploymentHistoryClient.history_records_keys + - ('summary',)))) - - @patch.object(Serializer, 'print_to_output') - def test_show_tasks_history_with_parameters(self, print_mock): - tasks_after_facade = [ - { - 'task_name': 'controller-remaining-tasks', - 'task_parameters': 'parameters: {puppet_manifest: /etc/puppet/' - 'modules/osnailyfacter/modular/globals/' - 'globals.pp,\n puppet_modules: /etc/' - 'puppet/modules, timeout: 3600}\nrole: ' - '[controller]\ntype: puppet\nversion: 2.0.0' - '\n', - 'status_by_node': '1 - ready - 2016-03-25T17:22:10 - ' - '2016-03-25T17:22:30\n' - '2 - ready - 2016-03-25T17:22:10 - ' - '2016-03-25T17:22:30' - }, - { - 'task_name': 'pending-task', - 'task_parameters': 'parameters: {puppet_manifest: /etc/puppet/' - 'modules/osnailyfacter/modular/globals/' - 'globals.pp,\n puppet_modules: /etc/puppet' - '/modules, timeout: 3600}\nrole: ' - '[controller]\ntype: puppet\nversion: 2.0.0' - '\n', - 'status_by_node': '1 - pending - not started - not ended\n' - '2 - pending - not started - not ended' - } - ] - - self.m_history_api = self.m_request.get( - '/api/v1/transactions/1/deployment_history/?' - 'nodes=&' - 'statuses=&' - 'tasks_names=controller-remaining-tasks,pending-task', - json=utils.get_fake_deployment_history(add_task_data=True)) - - self.execute( - ['fuel', 'deployment-tasks', - '--tid', '1', - '--task-name', 'controller-remaining-tasks,pending-task', - '--node', '1,2', - '--show-parameters'] - ) - print_mock.assert_called_once_with( - tasks_after_facade, - format_table( - tasks_after_facade, - acceptable_keys=DeploymentHistoryClient.tasks_records_keys)) - - def test_show_history_for_special_nodes(self): - self.m_history_api = self.m_request.get( - '/api/v1/transactions/1/deployment_history/?' - 'nodes=1,2', - json={}) - - self.execute( - ['fuel', 'deployment-tasks', '--tid', '1', - '--node-id', '1,2'] - ) - - self.assertEqual(self.m_history_api.call_count, 1) - - def test_show_history_for_special_tasks(self): - self.m_history_api = self.m_request.get( - '/api/v1/transactions/1/deployment_history/?' - 'tasks_names=test1,test2', - json={}) - - self.execute( - ['fuel', 'deployment-tasks', '--tid', '1', - '--task-name', 'test1,test2'] - ) - - self.assertEqual(self.m_history_api.call_count, 1) - - def test_show_history_with_special_statuses(self): - self.m_history_api = self.m_request.get( - '/api/v1/transactions/1/deployment_history/?' - 'statuses=ready,skipped', - json={}) - self.execute( - ['fuel', 'deployment-tasks', '--tid', '1', - '--status', 'ready,skipped'] - ) - self.assertEqual(self.m_history_api.call_count, 1) - - def test_show_history_for_special_statuses_nodes_and_tasks(self): - self.m_history_api = self.m_request.get( - '/api/v1/transactions/1/deployment_history/?' - 'nodes=1,2&' - 'statuses=ready,skipped&' - 'tasks_names=test1,test2', - json={}) - self.execute( - ['fuel', 'deployment-tasks', '--tid', '1', - '--status', 'ready,skipped', '--node', '1,2', - '--task-name', 'test1,test2'] - ) - self.assertEqual(self.m_history_api.call_count, 1) diff --git a/fuelclient/tests/unit/v1/test_deployment_tasks_actions.py b/fuelclient/tests/unit/v1/test_deployment_tasks_actions.py deleted file mode 100644 index c8c92ba..0000000 --- a/fuelclient/tests/unit/v1/test_deployment_tasks_actions.py +++ /dev/null @@ -1,134 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 - -from mock import patch -import requests_mock as rm - -from fuelclient.tests.unit.v1 import base - - -API_INPUT = [{'id': 'primary-controller'}] -API_OUTPUT = '- id: primary-controller\n' -RELEASE_OUTPUT = [{'id': 1, 'version': '2014.2-6.0', 'name': 'Something'}] -MULTIPLE_RELEASES = [{'id': 1, 'version': '2014.2-6.0', 'name': 'Something'}, - {'id': 2, 'version': '2014.3-6.1', 'name': 'Something'}] - - -@patch('fuelclient.cli.serializers.open', create=True) -@patch('fuelclient.cli.actions.base.os') -class TestReleaseDeploymentTasksActions(base.UnitTestCase): - - def test_release_tasks_download(self, mos, mopen): - self.m_request.get(rm.ANY, json=API_INPUT) - self.execute( - ['fuel', 'rel', '--rel', '1', '--deployment-tasks', '--download']) - mopen().__enter__().write.assert_called_once_with(API_OUTPUT) - - def test_release_tasks_upload(self, mos, mopen): - mopen().__enter__().read.return_value = API_OUTPUT - put = self.m_request.put('/api/v1/releases/1/deployment_tasks', - json=API_OUTPUT) - - self.execute( - ['fuel', 'rel', '--rel', '1', '--deployment-tasks', '--upload']) - - self.assertTrue(put.called) - self.assertEqual(put.last_request.json(), API_INPUT) - - -@patch('fuelclient.cli.serializers.open', create=True) -@patch('fuelclient.cli.actions.base.os') -class TestClusterDeploymentTasksActions(base.UnitTestCase): - - def test_cluster_tasks_download(self, mos, mopen): - self.m_request.get(rm.ANY, json=API_INPUT) - self.execute( - ['fuel', 'env', '--env', '1', '--deployment-tasks', '--download']) - mopen().__enter__().write.assert_called_once_with(API_OUTPUT) - - def test_cluster_tasks_upload(self, mos, mopen): - mopen().__enter__().read.return_value = API_OUTPUT - put = self.m_request.put('/api/v1/clusters/1/deployment_tasks', - json=API_OUTPUT) - - self.execute( - ['fuel', 'env', '--env', '1', '--deployment-tasks', '--upload']) - - self.assertTrue(put.called) - self.assertEqual(put.last_request.json(), API_INPUT) - - -@patch('fuelclient.cli.serializers.open', create=True) -@patch('fuelclient.utils.iterfiles') -class TestSyncDeploymentTasks(base.UnitTestCase): - - def test_sync_deployment_scripts(self, mfiles, mopen): - self.m_request.get(rm.ANY, json=RELEASE_OUTPUT) - put = self.m_request.put('/api/v1/releases/1/deployment_tasks', - json={}) - - mfiles.return_value = ['/etc/puppet/2014.2-6.0/tasks.yaml'] - mopen().__enter__().read.return_value = API_OUTPUT - file_pattern = '*tests*' - self.execute( - ['fuel', 'rel', '--sync-deployment-tasks', '--fp', file_pattern]) - - mfiles.assert_called_once_with( - os.path.realpath(os.curdir), file_pattern) - - self.assertTrue(put.called) - self.assertEqual(put.last_request.json(), API_INPUT) - - @patch('fuelclient.cli.actions.release.os') - def test_sync_with_directory_path(self, mos, mfiles, mopen): - self.m_request.get(rm.ANY, json=RELEASE_OUTPUT) - put = self.m_request.put('/api/v1/releases/1/deployment_tasks', - json={}) - - mos.path.realpath.return_value = real_path = '/etc/puppet' - mfiles.return_value = [real_path + '/2014.2-6.0/tasks.yaml'] - mopen().__enter__().read.return_value = API_OUTPUT - self.execute( - ['fuel', 'rel', '--sync-deployment-tasks', '--dir', real_path]) - mfiles.assert_called_once_with(real_path, '*tasks.yaml') - self.assertTrue(put.called) - - def test_multiple_tasks_but_one_release(self, mfiles, mopen): - self.m_request.get(rm.ANY, json=RELEASE_OUTPUT) - put = self.m_request.put(rm.ANY, json={}) - - mfiles.return_value = ['/etc/puppet/2014.2-6.0/tasks.yaml', - '/etc/puppet/2014.3-6.1/tasks.yaml'] - mopen().__enter__().read.return_value = API_OUTPUT - - self.execute( - ['fuel', 'rel', '--sync-deployment-tasks']) - - self.assertEqual(put.call_count, 1) - - def test_multiple_releases(self, mfiles, mopen): - self.m_request.get(rm.ANY, json=MULTIPLE_RELEASES) - put = self.m_request.put(rm.ANY, json={}) - mfiles.return_value = ['/etc/puppet/2014.2-6.0/tasks.yaml', - '/etc/puppet/2014.3-6.1/tasks.yaml'] - mopen().__enter__().read.return_value = API_OUTPUT - - self.execute( - ['fuel', 'rel', '--sync-deployment-tasks']) - - self.assertEqual(put.call_count, 2) diff --git a/fuelclient/tests/unit/v1/test_environment.py b/fuelclient/tests/unit/v1/test_environment.py deleted file mode 100644 index 26803a3..0000000 --- a/fuelclient/tests/unit/v1/test_environment.py +++ /dev/null @@ -1,194 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 mock -import requests_mock as rm -from six import moves - -from fuelclient.objects.environment import Environment -from fuelclient.tests.unit.v1 import base - - -class TestEnvironment(base.UnitTestCase): - - def test_delete_operational_wo_force(self): - cluster_id = 1 - url = '/api/v1/clusters/{0}/'.format(cluster_id) - cmd = 'fuel --env {0} env delete'.format(cluster_id) - - self.m_request.get(url, - json={'id': cluster_id, 'status': 'operational'}) - m_delete = self.m_request.delete(url) - - with mock.patch('sys.stdout', new=moves.cStringIO()) as m_stdout: - self.execute(cmd.split()) - self.assertIn('--force', m_stdout.getvalue()) - - self.assertFalse(m_delete.called) - - def test_neutron_gre_using_warning(self): - cluster_id = 1 - cluster_data = { - 'id': cluster_id, - 'name': 'test', - } - self.m_request.post('/api/v1/clusters/', json=cluster_data) - self.m_request.get('/api/v1/clusters/{0}/'.format(cluster_id), - json=cluster_data) - - with mock.patch('sys.stderr', new=moves.cStringIO()) as m_stderr: - self.execute( - 'fuel env create --name test --rel 1 --nst gre' - .split() - ) - - self.assertIn("WARNING: GRE network segmentation type is " - "deprecated since 7.0 release.", - m_stderr.getvalue()) - - @mock.patch('fuelclient.objects.task.DeployTask.init_with_data') - def test_deploy_changes(self, task_data): - dry_run = False - noop_run = False - mdeploy = self.m_request.put('/api/v1/clusters/1/changes' - '?dry_run={0}&noop_run={1}'.format( - int(dry_run), int(noop_run)), json={}) - - cmd = ['fuel', 'deploy-changes', '--env', '1'] - self.execute(cmd) - self.check_deploy_redeploy_changes(dry_run, mdeploy) - - @mock.patch('fuelclient.objects.task.DeployTask.init_with_data') - def test_deploy_changes_dry_run(self, task_data): - dry_run = True - mdeploy = self.m_request.put('/api/v1/clusters/1/changes' - '?dry_run={0}'.format( - int(dry_run)), json={}) - - cmd = ['fuel', 'deploy-changes', '--env', '1'] - - cmd.append('--dry-run') - self.execute(cmd) - self.check_deploy_redeploy_changes(dry_run, mdeploy) - - @mock.patch('fuelclient.objects.task.DeployTask.init_with_data') - def test_redeploy_changes(self, task_data): - dry_run = False - mdeploy = self.m_request.put('/api/v1/clusters/1/changes/redeploy' - '?dry_run={0}'.format( - int(dry_run)), json={}) - - cmd = ['fuel', 'redeploy-changes', '--env', '1'] - - self.execute(cmd) - self.check_deploy_redeploy_changes(dry_run, mdeploy) - - @mock.patch('fuelclient.objects.task.DeployTask.init_with_data') - def test_redeploy_changes_dry_run(self, task_data): - dry_run = True - mdeploy = self.m_request.put('/api/v1/clusters/1/changes/redeploy' - '?dry_run={0}'.format( - int(dry_run)), json={}) - - cmd = ['fuel', 'redeploy-changes', '--env', '1'] - - cmd.append('--dry-run') - self.execute(cmd) - self.check_deploy_redeploy_changes(dry_run, mdeploy) - - def check_deploy_redeploy_changes(self, res, mdeploy, mode='dry_run'): - self.assertEqual(mdeploy.last_request.qs[mode][0], - str(int(res))) - - -class TestEnvironmentOstf(base.UnitTestCase): - - def setUp(self): - super(TestEnvironmentOstf, self).setUp() - - self.env = Environment(None) - - @mock.patch.object(Environment.connection, 'post_request', mock.Mock( - return_value=[ - {'id': 1}, - {'id': 2}, ])) - def test_run_test_sets(self): - self.assertEqual(self.env._testruns_ids, []) - - testruns = self.env.run_test_sets(['sanity', 'ha']) - - self.assertEqual(len(testruns), 2) - self.assertIn(1, self.env._testruns_ids) - self.assertIn(2, self.env._testruns_ids) - - @mock.patch.object(Environment.connection, 'post_request') - def test_credentials_are_passed_to_ostf(self, post_request): - self.env.run_test_sets(['sanity'], {'tenant': 't1', - 'username': 'u1', - 'password': 'p1'}) - run_test_request = post_request.call_args[0][1] - self.assertTrue(len(run_test_request) > 0, 'Got empty request') - self.assertIn('metadata', run_test_request[0]) - self.assertIn('ostf_os_access_creds', run_test_request[0]['metadata']) - creds = run_test_request[0]['metadata']['ostf_os_access_creds'] - self.assertEqual(creds['ostf_os_tenant_name'], 't1') - self.assertEqual(creds['ostf_os_username'], 'u1') - self.assertEqual(creds['ostf_os_password'], 'p1') - - @mock.patch.object(Environment.connection, 'get_request', mock.Mock( - side_effect=[ - {'id': 1, 'status': 'running'}, - {'id': 2, 'status': 'finished'}, ])) - def test_get_state_of_tests(self): - self.env._testruns_ids.extend([1, 2]) - tests = self.env.get_state_of_tests() - - self.env.connection.get_request.assert_has_calls([ - mock.call('testruns/1', ostf=True), - mock.call('testruns/2', ostf=True)]) - self.assertEqual(tests, [ - {'id': 1, 'status': 'running'}, - {'id': 2, 'status': 'finished'}]) - - def test_get_deployment_tasks_with_end(self): - end = 'task1' - get = self.m_request.get(rm.ANY, json={}) - - self.env.get_deployment_tasks(end=end) - - self.assertEqual(get.last_request.qs, {'end': ['task1']}) - - def test_get_default_facts(self): - legacy_format_facts = [ - {"uid": "1", "a": 1}, {"uid": "2", "a": 1} - ] - new_format_facts = [ - {"uid": "common", "a": 1}, {"uid": "1"}, {"uid": "2"} - ] - self.m_request.get( - '/api/v1/clusters/{0}/orchestrator/deployment/defaults/?split=0' - .format(self.env.id), - json=legacy_format_facts - ) - self.m_request.get( - '/api/v1/clusters/{0}/orchestrator/deployment/defaults/?split=1' - .format(self.env.id), - json=new_format_facts - ) - facts = self.env.get_default_facts("deployment", split=False) - self.assertItemsEqual(legacy_format_facts, facts) - facts = self.env.get_default_facts("deployment", split=True) - self.assertItemsEqual(new_format_facts, facts) diff --git a/fuelclient/tests/unit/v1/test_fuel_version.py b/fuelclient/tests/unit/v1/test_fuel_version.py deleted file mode 100644 index f906263..0000000 --- a/fuelclient/tests/unit/v1/test_fuel_version.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 json -import mock -import yaml - -from fuelclient.tests.unit.v1 import base -from fuelclient.tests.utils import fake_fuel_version - - -class TestFuelVersion(base.UnitTestCase): - - def test_return_yaml(self): - self.m_request.get('/api/v1/version/', - json=fake_fuel_version.get_fake_fuel_version()) - - with mock.patch('sys.stdout') as mstdout: - self.execute(['fuel', 'fuel-version', '--yaml']) - args, _ = mstdout.write.call_args_list[0] - regex = ('No JSON object could be decoded' - '|Expecting value: line 1 column 1') - with self.assertRaisesRegexp(ValueError, regex): - json.loads(args[0]) - self.assertEqual( - fake_fuel_version.get_fake_fuel_version(), - yaml.safe_load(args[0])) - - def test_return_json(self): - self.m_request.get('/api/v1/version/', - json=fake_fuel_version.get_fake_fuel_version()) - - with mock.patch('sys.stdout') as mstdout: - self.execute(['fuel', 'fuel-version', '--json']) - args, _ = mstdout.write.call_args_list[0] - self.assertEqual( - fake_fuel_version.get_fake_fuel_version(), - json.loads(args[0])) diff --git a/fuelclient/tests/unit/v1/test_graph_action.py b/fuelclient/tests/unit/v1/test_graph_action.py deleted file mode 100644 index e3eb245..0000000 --- a/fuelclient/tests/unit/v1/test_graph_action.py +++ /dev/null @@ -1,261 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 io -import os - -import mock - -from fuelclient.cli.actions import graph -from fuelclient.tests.unit.v1 import base - - -GRAPH_API_OUTPUT = "digraph G { A -> B -> C }" -TASKS_API_OUTPUT = [ - {'id': 'primary-controller'}, - {'id': 'sync-time'}, -] - - -class TestGraphAction(base.UnitTestCase): - - def setUp(self): - super(TestGraphAction, self).setUp() - self.m_tasks_api = self.m_request.get( - '/api/v1/clusters/1/deployment_tasks', - json=TASKS_API_OUTPUT) - self.m_graph_api = self.m_request.get( - '/api/v1/clusters/1/deploy_tasks/graph.gv', - text=GRAPH_API_OUTPUT) - - self.m_full_path = mock.patch.object(graph.GraphAction, - 'full_path_directory').start() - self.m_full_path.return_value = '/path' - - def tearDown(self): - super(TestGraphAction, self).tearDown() - self.m_full_path.stop() - - def test_download_all_tasks(self): - with mock.patch('sys.stdout', new=io.StringIO()) as m_stdout: - self.execute( - ['fuel', 'graph', '--download', '--env', '1', '--download'] - ) - - querystring = self.m_graph_api.last_request.qs - for task in TASKS_API_OUTPUT: - self.assertIn(task['id'], querystring['tasks'][0]) - self.assertIn(GRAPH_API_OUTPUT, m_stdout.getvalue()) - - def test_download_selected_tasks(self): - with mock.patch('sys.stdout', new=io.StringIO()) as m_stdout: - self.execute( - ['fuel', 'graph', '--download', '--env', '1', - '--tasks', 'task-a', 'task-b'] - ) - - querystring = self.m_graph_api.last_request.qs - self.assertIn('task-a', querystring['tasks'][0]) - self.assertIn('task-b', querystring['tasks'][0]) - self.assertIn(GRAPH_API_OUTPUT, m_stdout.getvalue()) - - def test_download_with_skip(self): - with mock.patch('sys.stdout', new=io.StringIO()) as m_stdout: - self.execute( - ['fuel', 'graph', '--download', '--env', '1', - '--skip', 'sync-time', 'task-b'] - ) - querystring = self.m_graph_api.last_request.qs - self.assertIn('primary-controller', querystring['tasks'][0]) - self.assertNotIn('sync-time', querystring['tasks'][0]) - self.assertNotIn('task-b', querystring['tasks'][0]) - self.assertIn(GRAPH_API_OUTPUT, m_stdout.getvalue()) - - def test_download_with_end_and_start(self): - with mock.patch('sys.stdout', new=io.StringIO()) as m_stdout: - self.execute( - ['fuel', 'graph', '--download', '--env', '1', - '--start', 'task-a', '--end', 'task-b'] - ) - - tasks_qs = self.m_tasks_api.last_request.qs - self.assertEqual('task-a', tasks_qs['start'][0]) - self.assertEqual('task-b', tasks_qs['end'][0]) - - graph_qs = self.m_graph_api.last_request.qs - for task in TASKS_API_OUTPUT: - self.assertIn(task['id'], graph_qs['tasks'][0]) - self.assertIn(GRAPH_API_OUTPUT, m_stdout.getvalue()) - - def test_download_only_parents(self): - with mock.patch('sys.stdout', new=io.StringIO()) as m_stdout: - self.execute( - ['fuel', 'graph', '--download', '--env', '1', - '--parents-for', 'task-z'] - ) - querystring = self.m_graph_api.last_request.qs - self.assertEqual('task-z', querystring['parents_for'][0]) - self.assertIn(GRAPH_API_OUTPUT, m_stdout.getvalue()) - - def test_download_with_removed(self): - with mock.patch('sys.stdout', new=io.StringIO()) as m_stdout: - self.execute( - ['fuel', 'graph', '--download', '--env', '1', - '--remove', 'skipped'] - ) - querystring = self.m_graph_api.last_request.qs - self.assertEqual('skipped', querystring['remove'][0]) - self.assertIn(GRAPH_API_OUTPUT, m_stdout.getvalue()) - - def test_params_saved_in_dotfile(self): - with mock.patch('sys.stdout', new=io.StringIO()) as m_stdout: - self.execute( - ['fuel', 'graph', '--download', '--env', '1', - '--parents-for', 'task-z', - '--skip', 'task-a'] - ) - saved_params = ("# params:\n" - "# - start: None\n" - "# - end: None\n" - "# - skip: ['task-a']\n" - "# - tasks: []\n" - "# - parents-for: task-z\n" - "# - remove: []\n") - self.assertIn(saved_params + GRAPH_API_OUTPUT, m_stdout.getvalue()) - - @mock.patch('fuelclient.cli.actions.graph.open', create=True) - @mock.patch('fuelclient.cli.actions.graph.render_graph') - @mock.patch('fuelclient.cli.actions.graph.os.access') - @mock.patch('fuelclient.cli.actions.graph.os.path.exists') - def test_render(self, m_exists, m_access, m_render, m_open): - graph_data = 'some-dot-data' - m_exists.return_value = True - m_open().__enter__().read.return_value = graph_data - - self.execute( - ['fuel', 'graph', '--render', 'graph.gv'] - ) - - m_open.assert_called_with('graph.gv', 'r') - m_render.assert_called_once_with( - graph_data, '/path/graph.gv.png', False) - - @mock.patch('fuelclient.cli.actions.graph.open', create=True) - @mock.patch('fuelclient.cli.actions.graph.render_graph') - @mock.patch('fuelclient.cli.actions.graph.os.access') - @mock.patch('fuelclient.cli.actions.graph.os.path.exists') - def test_render_with_tred(self, m_exists, m_access, m_render, m_open): - graph_data = 'some-dot-data' - m_exists.return_value = True - m_open().__enter__().read.return_value = graph_data - - self.execute( - ['fuel', 'graph', '--render', 'graph.gv', '--tred'] - ) - - m_open.assert_called_with('graph.gv', 'r') - m_render.assert_called_once_with( - graph_data, '/path/graph.gv.png', True) - - @mock.patch('fuelclient.cli.actions.graph.os.path.exists') - def test_render_no_file(self, m_exists): - m_exists.return_value = False - self.assertRaises(SystemExit, - self.execute, - ['fuel', 'graph', '--render', 'graph.gv']) - - @mock.patch('fuelclient.cli.actions.graph.open', create=True) - @mock.patch('fuelclient.cli.actions.graph.render_graph') - @mock.patch('fuelclient.cli.actions.graph.os.access') - @mock.patch('fuelclient.cli.actions.graph.os.path.exists') - def test_render_with_output_path(self, m_exists, m_access, m_render, - m_open): - output_dir = '/output/dir' - graph_data = 'some-dot-data' - m_exists.return_value = True - m_open().__enter__().read.return_value = graph_data - self.m_full_path.return_value = output_dir - - self.execute( - ['fuel', 'graph', '--render', 'graph.gv', '--dir', output_dir] - ) - - self.m_full_path.assert_called_once_with(output_dir, '') - m_render.assert_called_once_with( - graph_data, '/output/dir/graph.gv.png', False) - - @mock.patch('fuelclient.cli.actions.graph.open', create=True) - @mock.patch('fuelclient.cli.actions.graph.render_graph') - @mock.patch('fuelclient.cli.actions.graph.os.access') - @mock.patch('fuelclient.cli.actions.graph.os.path.exists') - def test_render_with_output_path_with_tred( - self, m_exists, m_access, m_render, m_open): - output_dir = '/output/dir' - graph_data = 'some-dot-data' - m_exists.return_value = True - m_open().__enter__().read.return_value = graph_data - self.m_full_path.return_value = output_dir - - self.execute( - ['fuel', 'graph', '--render', 'graph.gv', '--dir', output_dir, - '--tred'] - ) - - self.m_full_path.assert_called_once_with(output_dir, '') - m_render.assert_called_once_with( - graph_data, '/output/dir/graph.gv.png', True) - - @mock.patch('fuelclient.cli.actions.graph.os.access') - @mock.patch('fuelclient.cli.actions.graph.render_graph') - def test_render_from_stdin(self, m_render, m_access): - graph_data = u'graph data' - - with mock.patch('sys.stdin', new=io.StringIO(graph_data)): - self.execute( - ['fuel', 'graph', '--render', '-', ] - ) - - m_render.assert_called_once_with( - graph_data, '/path/graph.gv.png', False) - - @mock.patch('fuelclient.cli.actions.graph.os.access') - @mock.patch('fuelclient.cli.actions.graph.render_graph') - def test_render_from_stdin_with_tred(self, m_render, m_access): - graph_data = u'graph data' - - with mock.patch('sys.stdin', new=io.StringIO(graph_data)): - self.execute( - ['fuel', 'graph', '--render', '-', '--tred'] - ) - - m_render.assert_called_once_with( - graph_data, '/path/graph.gv.png', True) - - @mock.patch('fuelclient.cli.actions.graph.open', create=True) - @mock.patch('fuelclient.cli.actions.graph.os.path.exists') - @mock.patch('fuelclient.cli.actions.graph.os.access') - def test_render_no_access_to_output(self, m_access, m_exists, m_open): - m_exists.return_value = True - m_access.return_value = False - output_dir = '/output/dir' - self.m_full_path.return_value = output_dir - - self.assertRaises(SystemExit, - self.execute, - ['fuel', 'graph', '--render', - 'graph.gv', '--dir', output_dir]) - m_access.assert_called_once_with(output_dir, os.W_OK) diff --git a/fuelclient/tests/unit/v1/test_network_groups.py b/fuelclient/tests/unit/v1/test_network_groups.py deleted file mode 100644 index fcacd94..0000000 --- a/fuelclient/tests/unit/v1/test_network_groups.py +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock - -from fuelclient.tests.unit.v1 import base -from fuelclient.tests.utils import fake_network_group - - -class TestNetworkGroupActions(base.UnitTestCase): - - def setUp(self): - super(TestNetworkGroupActions, self).setUp() - - self.env_id = 42 - self.req_base_path = '/api/v1/networks/' - - self.ng = fake_network_group.get_fake_network_group() - - def test_list_network_groups(self): - mget = self.m_request.get(self.req_base_path, json={}) - list_commands = [ - ['fuel', 'network-group', '--list'], ['fuel', 'network-group']] - - for cmd in list_commands: - self.execute(cmd) - self.assertTrue(mget.called) - - def test_list_network_groups_filtering(self): - mget = self.m_request.get(self.req_base_path, json={}) - - self.execute( - ['fuel', 'network-group', '--node-group', str(self.ng['id'])] - ) - - self.assertTrue(mget.called) - - def create_network_group(self, cmd): - mpost = self.m_request.post(self.req_base_path, json={ - 'id': self.ng['id'], - 'name': self.ng['name'], - }) - self.execute(cmd) - - call_data = mpost.last_request.json() - self.assertEqual(self.ng['id'], call_data['group_id']) - self.assertEqual(self.ng['name'], call_data['name']) - - self.assertTrue(mpost.called) - - return call_data - - def test_create_network_group(self): - cmd = ['fuel', 'network-group', '--create', '--cidr', self.ng['cidr'], - '--name', self.ng['name'], '--node-group', str(self.ng['id'])] - self.create_network_group(cmd) - - def test_create_network_group_w_meta(self): - cmd = ['fuel', 'network-group', '--create', '--cidr', self.ng['cidr'], - '--name', self.ng['name'], '--node-group', str(self.ng['id']), - '--meta', '{"ip_ranges": ["10.0.0.2", "10.0.0.254"]}'] - self.create_network_group(cmd) - - meta = self.m_request.last_request.json()['meta'] - self.assertEqual(meta['ip_ranges'], ["10.0.0.2", "10.0.0.254"]) - - def test_create_network_group_required_args(self): - with mock.patch("sys.stderr") as m_stderr: - self.assertRaises(SystemExit, - self.execute, - ['fuel', 'network-group', '--create']) - - self.assertIn('--nodegroup", "--name" and "--cidr" required!', - m_stderr.write.call_args[0][0]) - - def test_delete_network_group_required_args(self): - with mock.patch("sys.stderr") as m_stderr: - self.assertRaises(SystemExit, - self.execute, - ['fuel', 'network-group', '--delete']) - - self.assertIn('"--network" required!', m_stderr.write.call_args[0][0]) - - def test_delete_network_group(self): - path = self.req_base_path + str(self.env_id) + '/' - mdelete = self.m_request.delete(path, status_code=204) - self.execute( - ['fuel', 'network-group', '--delete', - '--network', str(self.env_id)]) - - self.assertTrue(mdelete.called) - - def test_network_group_duplicate_name(self): - mpost = self.m_request.post(self.req_base_path, status_code=409) - - with mock.patch("sys.stderr") as m_stderr: - self.assertRaises(SystemExit, - self.execute, - ['fuel', 'network-group', '--create', '--cidr', - self.ng['cidr'], '--name', self.ng['name'], - '--node-group', str(self.ng['id'])]) - - self.assertIn("409 Client Error", m_stderr.write.call_args[0][0]) - self.assertTrue(mpost.called) - - def test_set_network_group(self): - path = self.req_base_path + str(self.env_id) + '/' - mput = self.m_request.put(path, json={}) - self.execute([ - 'fuel', 'network-group', '--set', '--network', str(self.ng['id']), - '--name', self.ng['name']]) - - self.assertTrue(mput.called) - - def test_set_network_group_meta(self): - path = self.req_base_path + str(self.env_id) + '/' - mput = self.m_request.put(path, json={}) - self.execute([ - 'fuel', 'network-group', '--set', '--network', str(self.ng['id']), - '--meta', '{"ip_ranges": ["10.0.0.2", "10.0.0.254"]}']) - - self.assertTrue(mput.called) - - meta = self.m_request.last_request.json()['meta'] - self.assertEqual(meta['ip_ranges'], ["10.0.0.2", "10.0.0.254"]) diff --git a/fuelclient/tests/unit/v1/test_networks_action.py b/fuelclient/tests/unit/v1/test_networks_action.py deleted file mode 100644 index 8fb6ed1..0000000 --- a/fuelclient/tests/unit/v1/test_networks_action.py +++ /dev/null @@ -1,81 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 yaml - -from mock import patch - -from fuelclient.tests.unit.v1 import base - - -ENV_OUTPUT = { - 'id': 1, - 'net_provider': 'neutron', -} - -FILE_INPUT = '''networks: -- name: public -- id: 1 -''' - -NETWORK_CONFIG_OK_OUTPUT = { - 'status': 'ready', - 'progress': 100, -} - -NETWORK_CONFIG_ERROR_OUTPUT = { - 'message': 'Some error', - 'errors': [], -} - - -@patch('fuelclient.cli.serializers.open', create=True) -@patch('fuelclient.cli.actions.base.os') -class TestNetworkActions(base.UnitTestCase): - - def test_network_download(self, mos, mopen): - self.m_request.get('/api/v1/clusters/1/', json=ENV_OUTPUT) - self.m_request.get('/api/v1/clusters/1/network_configuration/neutron', - json=yaml.load(FILE_INPUT)) - self.execute(['fuel', 'network', '--env', '1', '--download']) - mopen().__enter__().write.assert_called_once_with(FILE_INPUT) - - def test_network_upload(self, mos, mopen): - mopen().__enter__().read.return_value = FILE_INPUT - self.m_request.get('/api/v1/clusters/1/', json=ENV_OUTPUT) - mneutron_put = self.m_request.put( - '/api/v1/clusters/1/network_configuration/neutron', - json=NETWORK_CONFIG_OK_OUTPUT) - self.execute(['fuel', 'network', '--env', '1', '--upload']) - self.assertEqual(mneutron_put.call_count, 1) - url = mneutron_put.request_history[0].url - self.assertIn('clusters/1/network_configuration/neutron', url) - - def test_network_upload_with_error(self, mos, mopen): - mopen().__enter__().read.return_value = FILE_INPUT - self.m_request.get('/api/v1/clusters/1/', json=ENV_OUTPUT) - self.m_request.put( - '/api/v1/clusters/1/network_configuration/neutron', - status_code=400, json=NETWORK_CONFIG_ERROR_OUTPUT) - - with patch("sys.stderr") as m_stderr: - self.assertRaises( - SystemExit, self.execute, - ['fuel', 'network', '--env', '1', '--upload']) - - self.assertIn("400 Client Error", m_stderr.write.call_args[0][0]) - self.assertIn(NETWORK_CONFIG_ERROR_OUTPUT['message'], - m_stderr.write.call_args[0][0]) diff --git a/fuelclient/tests/unit/v1/test_nodegroups.py b/fuelclient/tests/unit/v1/test_nodegroups.py deleted file mode 100644 index f8e22ed..0000000 --- a/fuelclient/tests/unit/v1/test_nodegroups.py +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock -from six import StringIO - -from fuelclient.tests.unit.v1 import base -from fuelclient.tests import utils - - -class TestNodeGroupActions(base.UnitTestCase): - - def setUp(self): - super(TestNodeGroupActions, self).setUp() - - self.env = utils.get_fake_env() - self.req_base_path = '/api/v1/nodegroups/' - self.ng = utils.get_fake_node_group() - self.ngs = utils.get_fake_node_groups() - - def test_list_nodegroups(self): - mget = self.m_request.get(self.req_base_path, json=self.ngs) - self.execute(['fuel', 'nodegroup', '--list']) - - self.assertTrue(mget.called) - - def test_create_nodegroup(self): - neutron_url = \ - '/api/v1/clusters/{0}/network_configuration/neutron'.format( - self.env['id'] - ) - - self.m_request.get('/api/v1/clusters/{0[id]}/'.format(self.env), - json={'id': self.env['id']}) - mpost = self.m_request.post(self.req_base_path, - json={'id': self.ng['id'], - 'name': self.ng['name']}) - mget = self.m_request.get(neutron_url, - json={'networking_parameters': {}}) - with mock.patch('sys.stdout', new=StringIO()) as m_stdout: - self.execute([ - 'fuel', 'nodegroup', '--create', - '--name', self.ng['name'], '--env', str(self.env['id']) - ]) - - msg = "Node group '{name}' with id={id} "\ - "in environment {cluster} was created!" - self.assertIn( - msg.format(cluster=self.env['id'], **self.ng), - m_stdout.getvalue() - ) - - call_data = mpost.last_request.json() - self.assertEqual(self.env['id'], call_data['cluster_id']) - self.assertEqual(self.ng['name'], call_data['name']) - - self.assertTrue(mget.called) - - def _check_required_message_for_commands(self, err_msg, commands): - for cmd in commands: - with mock.patch("sys.stderr") as m_stderr: - self.assertRaises(SystemExit, self.execute, cmd) - - m_stderr.write.assert_called_with(err_msg) - - def test_create_nodegroup_arguments_required(self): - err_msg = '"--env" and "--name" required!\n' - - env_not_present = ['fuel', 'nodegroup', '--create', - '--name', 'test'] - - name_not_present = ['fuel', '--env', str(self.env['id']), - 'nodegroup', '--create'] - - self._check_required_message_for_commands( - err_msg, (env_not_present, name_not_present)) - - def test_delete_nodegroup(self): - path = self.req_base_path + str(self.env['id']) + '/' - mget = self.m_request.get(path, json={'name': 'test group'}) - delete_path = self.req_base_path + str(self.env['id']) + '/' - mdelete = self.m_request.delete(delete_path, status_code=204) - ngid = self.env['id'] - with mock.patch('sys.stdout', new=StringIO()) as m_stdout: - self.execute(['fuel', 'nodegroup', '--delete', '--group', - str(ngid)]) - msg = u"Node group with id={id} was deleted!" - self.assertIn( - msg.format(id=ngid), - m_stdout.getvalue() - ) - - self.assertTrue(mget.called) - self.assertTrue(mdelete.called) - - def test_delete_nodegroup_group_arg_required(self): - err_msg = '"--group" required!\n' - self._check_required_message_for_commands( - err_msg, - (['fuel', 'nodegroup', '--delete'],) - ) - - def test_assign_nodegroup_fails_w_multiple_groups(self): - err_msg = "Nodes can only be assigned to one node group.\n" - with mock.patch("sys.stderr") as m_stderr: - self.assertRaises(SystemExit, - self.execute, - ['fuel', 'nodegroup', '--assign', '--node', - '1', '--group', '2,3']) - - msg = m_stderr.write.call_args[0][0] - self.assertEqual(msg, err_msg) - - @mock.patch('fuelclient.objects.nodegroup.NodeGroup.assign') - def test_assign_nodegroup(self, m_assign): - self.execute(['fuel', 'nodegroup', '--assign', '--node', '1', - '--group', '2']) - m_assign.assert_called_with([1]) - - self.execute(['fuel', 'nodegroup', '--assign', '--node', '1,2,3', - '--group', '2']) - m_assign.assert_called_with([1, 2, 3]) - - def test_node_group_assign_arguments_required(self): - err_msg = '"--node" and "--group" required!\n' - - node_not_present_cmd = ['fuel', 'nodegroup', '--assign', - '--group', '1'] - group_not_present_cmd = ['fuel', 'nodegroup', '--assign', - '--node', '1'] - - commands = (node_not_present_cmd, group_not_present_cmd) - - self._check_required_message_for_commands(err_msg, commands) diff --git a/fuelclient/tests/unit/v1/test_nodes.py b/fuelclient/tests/unit/v1/test_nodes.py deleted file mode 100644 index f798d6b..0000000 --- a/fuelclient/tests/unit/v1/test_nodes.py +++ /dev/null @@ -1,139 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock -import yaml - -from fuelclient.cli.actions import node -from fuelclient.cli import error -from fuelclient.cli import serializers -from fuelclient.tests.unit.v1 import base - -NODE_ATTRIBUTES_DATA = { - 'test_attribute': 'value' -} - - -class TestNodeSetAction(base.UnitTestCase): - - def setUp(self): - super(TestNodeSetAction, self).setUp() - self.node_action = node.NodeAction() - self.node_id = 1 - self.params = mock.Mock() - self.params.node = [self.node_id] - - def test_more_than_one_node(self): - mput = self.m_request.put('/api/v1/nodes/{0}/'.format(self.node_id)) - self.params.hostname = 'whatever' - self.params.name = 'whatever2' - self.params.node = [1, 2] - - error_msg = r"You should select only one node to change\." - with self.assertRaisesRegexp(error.ArgumentException, error_msg): - self.node_action.set_hostname(self.params) - - with self.assertRaisesRegexp(error.ArgumentException, error_msg): - self.node_action.set_name(self.params) - - self.assertFalse(mput.called) - - def test_set_name(self): - test_cases = ('new-name', 'New Name', u'śćż∑ Pó', u'测试 测试') - for name in test_cases: - self.params.name = name - mput = self.m_request.put( - '/api/v1/nodes/{0}/'.format(self.node_id), - json={}) - with mock.patch.object(self.node_action.serializer, - 'print_to_output') as mprint: - self.node_action.set_name(self.params) - - self.assertEqual(mput.call_count, 1) - self.assertEqual({'name': name}, mput.last_request.json()) - mprint.assert_called_once_with( - {}, - u"Name for node with id {0} has been changed to {1}.".format( - self.node_id, name) - ) - - def test_set_hostname(self): - new_hostname = 'new_hostname' - self.params.hostname = new_hostname - - mput = self.m_request.put( - '/api/v1/nodes/{0}/'.format(self.node_id), - json={}) - - with mock.patch.object(self.node_action.serializer, - 'print_to_output') as mprint: - self.node_action.set_hostname(self.params) - - self.assertEqual(mput.call_count, 1) - self.assertEqual({'hostname': new_hostname}, mput.last_request.json()) - mprint.assert_called_once_with( - {}, - "Hostname for node with id {0} has been changed to {1}.".format( - self.node_id, new_hostname) - ) - - -class TestNodeActions(base.UnitTestCase): - def setUp(self): - super(TestNodeActions, self).setUp() - self.node_id = 1 - - @mock.patch('fuelclient.objects.node.os.mkdir', mock.Mock()) - def test_attributes_download(self): - mget = self.m_request.get( - '/api/v1/nodes/{0}/attributes/'.format(self.node_id), - json=NODE_ATTRIBUTES_DATA) - - cmd = ['fuel', 'node', '--node', '1', '--attributes', - '--dir', '/fake/dir/', '--download'] - m_open = mock.mock_open() - with mock.patch('fuelclient.cli.serializers.open', m_open, - create=True): - self.execute(cmd) - - self.assertTrue(mget.called) - m_open.assert_called_once_with( - '/fake/dir/node_{0}/attributes.yaml'.format(self.node_id), - mock.ANY) - serializer = serializers.Serializer() - m_open().write.assert_called_once_with( - serializer.serialize(NODE_ATTRIBUTES_DATA)) - - @mock.patch('fuelclient.objects.node.os.path.exists', - mock.Mock(return_value=True)) - def test_attributes_upload(self): - mput = self.m_request.put( - '/api/v1/nodes/{0}/attributes/'.format(self.node_id), - json=NODE_ATTRIBUTES_DATA) - - cmd = ['fuel', 'node', '--node', '1', '--attributes', - '--dir', '/fake/dir', '--upload'] - m_open = mock.mock_open(read_data=yaml.safe_dump(NODE_ATTRIBUTES_DATA)) - with mock.patch('fuelclient.cli.serializers.open', m_open, - create=True): - self.execute(cmd) - - self.assertTrue(mput.called) - m_open.assert_called_once_with( - '/fake/dir/node_{0}/attributes.yaml'.format(self.node_id), - mock.ANY) - self.assertEqual(mput.last_request.json(), NODE_ATTRIBUTES_DATA) - m_open().read.assert_called_once_with() diff --git a/fuelclient/tests/unit/v1/test_nodes_execute_tasks.py b/fuelclient/tests/unit/v1/test_nodes_execute_tasks.py deleted file mode 100644 index 160d853..0000000 --- a/fuelclient/tests/unit/v1/test_nodes_execute_tasks.py +++ /dev/null @@ -1,142 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock import patch -import requests_mock as rm - -from fuelclient.tests.unit.v1 import base -from fuelclient.tests.utils import fake_node - - -class TestNodeExecuteTasksAction(base.UnitTestCase): - - def setUp(self): - super(TestNodeExecuteTasksAction, self).setUp() - self.tasks = ['netconfig', 'hiera', 'install'] - - node_patch = patch('fuelclient.objects.node.Node.get_fresh_data') - m_fresh_data = node_patch.start() - m_fresh_data.return_value = fake_node.get_fake_node() - self.addCleanup(node_patch.stop) - - def test_execute_provided_list_of_tasks(self): - put = self.m_request.put(rm.ANY, json={'id': 43}) - - self.execute(['fuel', 'node', '--node', '1,2', '--tasks'] + self.tasks) - self.assertEqual( - put.last_request.path_url, - '/api/v1/clusters/1/deploy_tasks/?nodes=1,2' - ) - self.assertEqual(put.last_request.json(), self.tasks) - - def test_execute_provided_list_of_tasks_w_force(self): - put = self.m_request.put(rm.ANY, json={'id': 43}) - - self.execute((['fuel', 'node', '--node', '1,2', '--tasks'] - + self.tasks + ['--force'])) - self.assertEqual( - put.last_request.path_url, - '/api/v1/clusters/1/deploy_tasks/?nodes=1,2&force=1' - ) - self.assertEqual(put.last_request.json(), self.tasks) - - def test_execute_provided_list_of_tasks_noop_run(self): - put = self.m_request.put(rm.ANY, json={'id': 43}) - - self.execute((['fuel', 'node', '--node', '1,2', '--tasks'] - + self.tasks + ['--noop'])) - self.assertEqual( - put.last_request.url, - 'http://127.0.0.1:8000/api/v1/clusters/1/deploy_tasks/?nodes=1,2' - '&noop_run=1') - self.assertEqual(put.last_request.json(), self.tasks) - - @patch('fuelclient.objects.environment.Environment.get_deployment_tasks') - def test_skipped_tasks(self, get_tasks): - get_tasks.return_value = [{'id': t} for t in self.tasks] - put = self.m_request.put(rm.ANY, json={'id': 43}) - - self.execute( - ['fuel', 'node', '--node', '1,2', '--skip'] + self.tasks[:2]) - - self.assertEqual(put.last_request.json(), self.tasks[2:]) - - @patch('fuelclient.objects.environment.Environment.get_deployment_tasks') - def test_included_tasks(self, get_tasks): - get_tasks.return_value = [{'id': t} for t in self.tasks] - put = self.m_request.put(rm.ANY, json={'id': 43}) - - self.execute( - ['fuel', 'node', '--node', '1', '--start', 'netconfig', - '--tasks', 'hiera']) - self.assertEqual(put.last_request.json(), self.tasks) - get_tasks.assert_called_once_with( - start='netconfig', end=None, include=['hiera']) - - @patch('fuelclient.objects.environment.Environment.get_deployment_tasks') - def test_dont_fail_on_empty_tasks(self, get_tasks): - get_tasks.return_value = [] - self.execute( - ['fuel', 'node', '--node', '1', '--start', 'netconfig']) - - @patch('fuelclient.objects.environment.Environment.get_deployment_tasks') - def test_end_param(self, get_tasks): - put = self.m_request.put(rm.ANY, json={'id': 43}) - - get_tasks.return_value = [{'id': t} for t in self.tasks[:2]] - self.execute( - ['fuel', 'node', '--node', '1,2', '--end', self.tasks[-2]]) - self.assertEqual(put.last_request.json(), self.tasks[:2]) - get_tasks.assert_called_once_with( - end=self.tasks[-2], start=None, include=None) - - @patch('fuelclient.objects.environment.Environment.get_deployment_tasks') - def test_skip_with_end_param(self, get_tasks): - get_tasks.return_value = [{'id': t} for t in self.tasks] - put = self.m_request.put(rm.ANY, json={'id': 43}) - self.execute( - ['fuel', 'node', '--node', '1,2', - '--end', self.tasks[-1], '--skip'] + self.tasks[:2]) - - self.assertEqual(put.last_request.json(), self.tasks[2:]) - get_tasks.assert_called_once_with( - end=self.tasks[-1], start=None, include=None) - - @patch('fuelclient.objects.environment.Environment.get_deployment_tasks') - def test_start_with_end_param(self, get_tasks): - """end will be included.""" - put = self.m_request.put(rm.ANY, json={'id': 43}) - start = 1 - end = 2 - get_tasks.return_value = [{'id': t} for t in self.tasks[start:end + 1]] - self.execute( - ['fuel', 'node', '--node', '1,2', '--start', self.tasks[start], - '--end', self.tasks[end]]) - - self.assertEqual(put.last_request.json(), self.tasks[start:end + 1]) - get_tasks.assert_called_once_with( - end=self.tasks[2], start=self.tasks[1], include=None) - - @patch('fuelclient.objects.environment.Environment.get_deployment_tasks') - def test_start_param(self, get_tasks): - put = self.m_request.put(rm.ANY, json={'id': 43}) - get_tasks.return_value = [{'id': t} for t in self.tasks[1:]] - self.execute( - ['fuel', 'node', '--node', '1,2', '--start', self.tasks[1]]) - - self.assertEqual(put.last_request.json(), self.tasks[1:]) - get_tasks.assert_called_once_with( - start=self.tasks[1], end=None, include=None) diff --git a/fuelclient/tests/unit/v1/test_nodes_general_action.py b/fuelclient/tests/unit/v1/test_nodes_general_action.py deleted file mode 100644 index 4d83a51..0000000 --- a/fuelclient/tests/unit/v1/test_nodes_general_action.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock -from six import StringIO - -from fuelclient.cli.actions import node -from fuelclient.tests.unit.v1 import base - - -GRAPH_API_OUTPUT = "digraph G { A -> B -> C }" -TASKS_API_OUTPUT = [ - {'id': 'primary-controller'}, - {'id': 'sync-time'}, -] - - -class TestNodeStartAction(base.UnitTestCase): - - @mock.patch.object(node.NodeAction, 'get_env_id', return_value=None) - def test_node_not_assigend(self, _): - for method in ('--deploy', '--provision'): - with mock.patch('sys.stderr', new=StringIO()) as mstderr: - self.assertRaises(SystemExit, - self.execute, - ['fuel', 'node', method, '--node', '8']) - self.assertIn( - "Input nodes are not assigned to any environment!", - mstderr.getvalue()) diff --git a/fuelclient/tests/unit/v1/test_notifications_action.py b/fuelclient/tests/unit/v1/test_notifications_action.py deleted file mode 100644 index 93e3bb4..0000000 --- a/fuelclient/tests/unit/v1/test_notifications_action.py +++ /dev/null @@ -1,211 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock import patch -import requests_mock as rm - -from fuelclient.tests.unit.v1 import base - - -class TestNotificationsActions(base.UnitTestCase): - def test_notification_send(self): - post = self.m_request.post(rm.ANY, json={}) - - self.execute( - ['fuel', 'notifications', '--send', 'test message']) - self.assertEqual(post.call_count, 1) - - request = post.last_request.json() - self.assertEqual('test message', request['message']) - self.assertEqual('done', request['topic']) - - self.execute( - ['fuel', 'notify', '-m', 'test message 2']) - self.assertEqual(post.call_count, 2) - - request = post.last_request.json() - self.assertEqual('test message 2', request['message']) - self.assertEqual('done', request['topic']) - - def test_notification_send_with_topic(self): - post = self.m_request.post(rm.ANY, json={}) - - self.execute( - ['fuel', 'notifications', '--send', 'test error', - '--topic', 'error']) - self.assertEqual(post.call_count, 1) - request = post.last_request.json() - self.assertEqual('test error', request['message']) - self.assertEqual('error', request['topic']) - - self.execute( - ['fuel', 'notify', '-m', 'test error 2', '--topic', 'error']) - self.assertEqual(post.call_count, 2) - request = post.last_request.json() - self.assertEqual('test error 2', request['message']) - self.assertEqual('error', request['topic']) - - def test_notification_send_no_message(self): - post = self.m_request.post(rm.ANY, json={}) - - self.assertRaises( - SystemExit, - self.execute, - ['fuel', 'notifications', '--send'] - ) - self.assertFalse(post.called) - - self.assertRaises( - SystemExit, - self.execute, - ['fuel', 'notify', '-m'] - ) - self.assertFalse(post.called) - - def test_notification_send_invalid_topic(self): - post = self.m_request.post(rm.ANY, json={}) - - self.assertRaises( - SystemExit, - self.execute, - ['fuel', 'notifications', '--send', 'test message', - '--topic', 'x'] - ) - self.assertFalse(post.called) - - self.assertRaises( - SystemExit, - self.execute, - ['fuel', 'notify', '-m', 'test message', '--topic', 'x'] - ) - self.assertFalse(post.called) - - def test_mark_as_read(self): - results = [{'id': 1, - 'message': 'test message', - 'status': 'unread', - 'topic': 'done'}, - {'id': 2, - 'message': 'test message 2', - 'status': 'unread', - 'topic': 'done'}] - results.extend(results) - - get = self.m_request.get(rm.ANY, [{'json': r} for r in results]) - put = self.m_request.put(rm.ANY, json={}) - - self.execute( - ['fuel', 'notifications', '-r', '1']) - - self.assertEqual(get.call_count, 1) - self.assertEqual(put.call_count, 1) - - messages = put.last_request.json() - self.assertEqual(1, len(messages)) - - msg = messages.pop() - self.assertEqual('test message', msg['message']) - self.assertEqual('read', msg['status']) - self.assertEqual(1, msg['id']) - - self.execute( - ['fuel', 'notifications', '-r', '1', '2']) - - self.assertEqual(get.call_count, 3) - self.assertEqual(put.call_count, 2) - - messages = put.last_request.json() - self.assertEqual(2, len(messages)) - - msg = messages.pop() - self.assertEqual('test message', msg['message']) - self.assertEqual('read', msg['status']) - self.assertEqual(1, msg['id']) - - msg = messages.pop() - self.assertEqual('test message 2', msg['message']) - self.assertEqual('read', msg['status']) - self.assertEqual(2, msg['id']) - - def test_mark_all_as_read(self): - result = [{'id': 1, - 'message': 'test message', - 'status': 'unread', - 'topic': 'done'}, - {'id': 2, - 'message': 'test message 2', - 'status': 'unread', - 'topic': 'done'}] - - get = self.m_request.get(rm.ANY, json=result) - put = self.m_request.put(rm.ANY, json={}) - - self.execute( - ['fuel', 'notifications', '-r', '*']) - - self.assertEqual(get.call_count, 1) - self.assertEqual(put.call_count, 1) - request = put.last_request.json() - self.assertEqual('test message', request[0]['message']) - self.assertEqual('read', request[0]['status']) - self.assertEqual('test message 2', request[1]['message']) - self.assertEqual('read', request[1]['status']) - - @patch('fuelclient.cli.actions.notifications.format_table') - def test_list_notifications(self, mformat_table): - test_notifications = [{'id': 1, - 'message': 'test message', - 'status': 'unread', - 'topic': 'done'}, - {'id': 2, - 'message': 'test message 2', - 'status': 'read', - 'topic': 'done'}] - get = self.m_request.get(rm.ANY, json=test_notifications) - self.m_request.put(rm.ANY, json={}) - - self.execute(['fuel', 'notifications']) - - self.assertEqual(get.call_count, 1) - notifications = mformat_table.call_args[0][0] - self.assertEqual(len(notifications), 1) - self.assertDictEqual(notifications[0], test_notifications[0]) - - @patch('fuelclient.cli.actions.notifications.format_table') - def test_list_all_notifications(self, mformat_table): - test_notifications = [ - { - 'id': 1, - 'message': 'test message', - 'status': 'unread', - 'topic': 'done', - }, - { - 'id': 2, - 'message': 'test message 2', - 'status': 'read', - 'topic': 'done', - } - ] - get = self.m_request.get(rm.ANY, json=test_notifications) - self.m_request.put(rm.ANY, json={}) - - self.execute(['fuel', 'notifications', '-a']) - - self.assertEqual(get.call_count, 1) - notifications = mformat_table.call_args[0][0] - self.assertEqual(len(notifications), 2) - self.assertListEqual(notifications, test_notifications) diff --git a/fuelclient/tests/unit/v1/test_openstack_config.py b/fuelclient/tests/unit/v1/test_openstack_config.py deleted file mode 100644 index 5ad5252..0000000 --- a/fuelclient/tests/unit/v1/test_openstack_config.py +++ /dev/null @@ -1,204 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 json -import mock -import yaml - -from fuelclient.tests.unit.v1 import base -from fuelclient.tests import utils - - -class TestOpenstackConfigActions(base.UnitTestCase): - - def setUp(self): - super(TestOpenstackConfigActions, self).setUp() - - self.config = utils.get_fake_openstack_config() - - def test_config_download(self): - m_get = self.m_request.get( - '/api/v1/openstack-config/42/', json=self.config) - m_open = mock.mock_open() - with mock.patch('fuelclient.cli.serializers.open', - m_open, create=True): - self.execute(['fuel', 'openstack-config', - '--config-id', '42', '--download', - '--file', 'config.yaml']) - - self.assertTrue(m_get.called) - content = m_open().write.mock_calls[0][1][0] - content = yaml.safe_load(content) - self.assertEqual(self.config['configuration'], - content['configuration']) - - @mock.patch('sys.stderr') - def test_config_download_fail(self, mocked_stderr): - self.assertRaises( - SystemExit, - self.execute, ['fuel', 'openstack-config', '--download', - '--config-id', '1']) - mocked_stderr.write.assert_called_once_with( - '"--config-id" and "--file" required!\n') - mocked_stderr.reset_mock() - - self.assertRaises( - SystemExit, - self.execute, ['fuel', 'openstack-config', '--download', - '--file', 'config.yaml']) - mocked_stderr.write.assert_called_once_with( - '"--config-id" and "--file" required!\n') - - def test_config_upload(self): - m_post = self.m_request.post( - '/api/v1/openstack-config/', json=[self.config]) - m_open = mock.mock_open(read_data=yaml.safe_dump( - {'configuration': self.config['configuration']})) - with mock.patch('fuelclient.cli.serializers.open', - m_open, create=True): - with mock.patch('fuelclient.objects.openstack_config.os'): - self.execute(['fuel', 'openstack-config', '--env', '1', - '--upload', '--file', 'config.yaml']) - self.assertTrue(m_post.called) - - req = json.loads(m_post.last_request.text) - self.assertEqual(req['cluster_id'], 1) - - def test_config_upload_multinode(self): - configs = [utils.get_fake_openstack_config(node_id=node_id) - for node_id in [1, 2, 3]] - - m_post = self.m_request.post( - '/api/v1/openstack-config/', json=configs) - - m_open = mock.mock_open(read_data=yaml.safe_dump( - {'configuration': self.config['configuration']})) - with mock.patch('fuelclient.cli.serializers.open', - m_open, create=True): - with mock.patch('fuelclient.objects.openstack_config.os'): - self.execute(['fuel', 'openstack-config', '--env', '1', - '--node', '1,2,3', - '--upload', '--file', 'config.yaml']) - self.assertTrue(m_post.called) - - req = json.loads(m_post.last_request.text) - self.assertEqual(req['node_ids'], [1, 2, 3]) - self.assertEqual(req['cluster_id'], 1) - - @mock.patch('sys.stderr') - def test_config_upload_fail(self, mocked_stderr): - self.assertRaises( - SystemExit, - self.execute, ['fuel', 'openstack-config', '--env', '1', - '--upload']) - mocked_stderr.write.assert_called_once_with( - '"--env" and "--file" required!\n') - mocked_stderr.reset_mock() - - self.assertRaises( - SystemExit, - self.execute, ['fuel', 'openstack-config', '--upload', - '--file', 'config.yaml']) - mocked_stderr.write.assert_called_once_with( - '"--env" and "--file" required!\n') - - def test_config_list(self): - m_get = self.m_request.get( - '/api/v1/openstack-config/?cluster_id=84', json=[ - utils.get_fake_openstack_config(id=1, cluster_id=32), - utils.get_fake_openstack_config(id=2, cluster_id=64) - ]) - self.execute(['fuel', 'openstack-config', '--env', '84', '--list']) - self.assertTrue(m_get.called) - - def test_config_list_w_filters(self): - m_get = self.m_request.get( - '/api/v1/openstack-config/?cluster_id=84&node_role=controller', - json=[utils.get_fake_openstack_config(id=1, cluster_id=32)]) - self.execute(['fuel', 'openstack-config', '--env', '84', - '--role', 'controller', '--list']) - self.assertTrue(m_get.called) - - m_get = self.m_request.get( - '/api/v1/openstack-config/?cluster_id=84&node_ids=42', json=[ - utils.get_fake_openstack_config(id=1, cluster_id=32), - ]) - self.execute(['fuel', 'openstack-config', '--env', '84', - '--node', '42', '--list']) - self.assertTrue(m_get.called) - - def test_config_list_multinode(self): - m_get = self.m_request.get( - '/api/v1/openstack-config/?cluster_id=84&node_ids=1,2,3', - json=[utils.get_fake_openstack_config( - id=1, cluster_id=32, node_id=1)]) - - self.execute(['fuel', 'openstack-config', '--env', '84', - '--node', '1,2,3', '--list']) - self.assertTrue(m_get.called) - - @mock.patch('sys.stderr') - def test_config_list_fail(self, m_stderr): - self.assertRaises( - SystemExit, - self.execute, ['fuel', 'openstack-config', '--list']) - m_stderr.write.assert_called_once_with( - '"--env" required!\n') - - def test_config_delete(self): - m_del = self.m_request.delete( - '/api/v1/openstack-config/42/', json={}) - self.execute(['fuel', 'openstack-config', - '--config-id', '42', '--delete']) - self.assertTrue(m_del.called) - - def test_config_execute(self): - m_put = self.m_request.put('/api/v1/openstack-config/execute/', - json={'status': 'ready'}) - self.execute(['fuel', 'openstack-config', '--env', '42', '--execute']) - self.assertTrue(m_put.called) - self.assertEqual({"cluster_id": 42, "force": False}, - json.loads(m_put.last_request.text)) - - def test_config_execute_multinode(self): - m_put = self.m_request.put('/api/v1/openstack-config/execute/', - json={'status': 'ready'}) - - self.execute(['fuel', 'openstack-config', '--env', '42', - '--node', '1,2,3', '--execute']) - self.assertTrue(m_put.called) - self.assertEqual( - {"cluster_id": 42, "force": False, "node_ids": [1, 2, 3]}, - json.loads(m_put.last_request.text)) - - def test_config_force_execute(self): - m_put = self.m_request.put('/api/v1/openstack-config/execute/', - json={'status': 'ready'}) - self.execute(['fuel', 'openstack-config', '--env', '42', '--execute', - '--force']) - self.assertTrue(m_put.called) - self.assertEqual({"cluster_id": 42, "force": True}, - json.loads(m_put.last_request.text)) - - def test_config_execute_fail(self): - message = 'Some error' - m_put = self.m_request.put( - '/api/v1/openstack-config/execute/', - json={'status': 'error', 'message': message}) - - with mock.patch("sys.stdout") as m_stdout: - self.execute(['fuel', 'openstack-config', - '--env', '42', '--execute']) - self.assertTrue(m_put.called) - self.assertIn(message, m_stdout.write.call_args_list[0][0][0]) diff --git a/fuelclient/tests/unit/v1/test_parser.py b/fuelclient/tests/unit/v1/test_parser.py deleted file mode 100644 index 8843136..0000000 --- a/fuelclient/tests/unit/v1/test_parser.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock - -from fuelclient.tests.unit.v1 import base - - -class TestParser(base.UnitTestCase): - - def test_choose_only_one_format(self): - with mock.patch('sys.stderr') as mstderr: - self.assertRaises(SystemExit, - self.execute, - ['fuel', '--json', '--yaml']) - args, _ = mstderr.write.call_args - self.assertRegexpMatches( - args[0], - r"argument (--json|--yaml): not allowed with" - r" argument (--yaml|--json)") diff --git a/fuelclient/tests/unit/v1/test_performance.py b/fuelclient/tests/unit/v1/test_performance.py deleted file mode 100644 index 7509ff7..0000000 --- a/fuelclient/tests/unit/v1/test_performance.py +++ /dev/null @@ -1,153 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 json -import os -import shutil -import tarfile -import time - -import mock -import requests_mock as rm -from six import moves as six_moves -import testtools - -from fuelclient import client -from fuelclient import fuelclient_settings -from fuelclient import profiler -from fuelclient.tests.unit.v1 import base -from fuelclient.tests import utils - - -@testtools.skipUnless(profiler.profiling_enabled(), - 'Performance profiling tests are not ' - 'enabled in settings.yaml.') -class ClientPerfTest(base.UnitTestCase): - - NUMBER_OF_NODES = 100 - - @classmethod - def setUpClass(cls): - super(ClientPerfTest, cls).setUpClass() - - cls.nodes = cls.get_random_nodes(cls.NUMBER_OF_NODES) - settings = fuelclient_settings.get_settings() - test_base = settings.PERF_TESTS_PATHS['perf_tests_base'] - - if os.path.exists(test_base): - shutil.rmtree(test_base) - - os.makedirs(test_base) - - @classmethod - def tearDownClass(cls): - """Packs all the files from the profiling.""" - - settings = fuelclient_settings.get_settings() - test_base = settings.PERF_TESTS_PATHS['perf_tests_base'] - test_results = settings.PERF_TESTS_PATHS['perf_tests_results'] - - if not os.path.exists(test_results): - os.makedirs(test_results) - - if os.path.exists(test_base): - test_result_name = os.path.join( - test_results, - '{name:s}_{timestamp}.tar.gz'.format(name=cls.__name__, - timestamp=time.time())) - tar = tarfile.open(test_result_name, "w:gz") - tar.add(test_base) - tar.close() - - shutil.rmtree(test_base) - - def setUp(self): - super(ClientPerfTest, self).setUp() - - token_patcher = mock.patch.object(client.APIClient, 'auth_token', - new_callable=mock.PropertyMock) - self.mock_auth_token = token_patcher.start() - self.addCleanup(self.mock_auth_token.stop) - - @classmethod - def get_random_nodes(cls, number): - """Returns specified number of random fake nodes.""" - - return [utils.get_fake_node() for i in six_moves.range(number)] - - def _invoke_client(self, *args): - """Invokes Fuel Client with the specified arguments.""" - - args = ['fuelclient'] + list(args) - self.execute(args) - - def mock_nailgun_response(self, *responses): - """Mocks network requests in order to return specified content.""" - - m_responses = [] - - for resp in responses: - m_resp = {'text': resp, 'status': 200} - - m_responses.append(m_resp) - - self.m_request.stop() - self.m_request = rm.Mocker() - self.top_matcher = self.m_request.register_uri(rm.ANY, - rm.ANY, - m_responses) - - self.addCleanup(self.m_request.stop) - - def test_list_nodes(self): - nodes_text = json.dumps(self.nodes) - self.mock_nailgun_response(nodes_text) - - self._invoke_client('node', 'list') - - def test_assign_nodes(self): - node_ids = ','.join([str(n['id']) for n in self.nodes]) - - self.mock_nailgun_response('{}') - self._invoke_client('--env', '42', 'node', 'set', '--node', - node_ids, '--role', 'compute') - - def test_list_environment(self): - # NOTE(romcheg): After 100 nodes were added to an environment - # they are listed as pending changes so that may potentially - # affect the performance. - env = [utils.get_fake_env()] - resp_text = json.dumps(env) - - self.mock_nailgun_response(resp_text) - - self._invoke_client('env', '--list') - - @mock.patch('__builtin__.open', create=True) - def test_upload_node_settings(self, m_open): - node_configs = [json.dumps(utils.get_fake_network_config(3)) - for i in six_moves.range(self.NUMBER_OF_NODES)] - - node_ids = ','.join([str(n['id']) for n in self.nodes]) - - m_open.return_value = mock.MagicMock(spec=file) - m_file = m_open.return_value.__enter__.return_value - m_file.read.side_effect = node_configs - - self.mock_nailgun_response(*node_configs) - - self._invoke_client('--json', 'node', '--node-id', node_ids, - '--network', '--upload', '--dir', '/fake/dir') diff --git a/fuelclient/tests/unit/v1/test_plugins_action.py b/fuelclient/tests/unit/v1/test_plugins_action.py deleted file mode 100644 index 4c1166a..0000000 --- a/fuelclient/tests/unit/v1/test_plugins_action.py +++ /dev/null @@ -1,209 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 mock import patch - -from fuelclient.cli.actions import PluginAction -from fuelclient.cli import error -from fuelclient.cli.formatting import format_table -from fuelclient.cli.serializers import Serializer -from fuelclient.objects.plugins import Plugins -from fuelclient.tests.unit.v1 import base - - -class TestPluginsActions(base.UnitTestCase): - - def setUp(self): - super(TestPluginsActions, self).setUp() - self.file_name = '/tmp/path/plugin.fp' - self.attr_name = 'plugin_name==version' - self.name = 'plugin_name' - self.version = 'version' - - def exec_plugins(self, actions): - plugins_cmd = ['fuel', 'plugins'] - plugins_cmd.extend(actions) - self.execute(plugins_cmd) - - def assert_print_table(self, print_mock, plugins): - print_mock.assert_called_once_with( - plugins, format_table( - plugins, - acceptable_keys=PluginAction.acceptable_keys)) - - def assert_print(self, print_mock, result, msg): - print_mock.assert_called_once_with(result, msg) - - @patch.object(Serializer, 'print_to_output') - @patch.object(Plugins, 'get_all_data') - def test_list_default(self, get_mock, print_mock): - plugins = [ - {'id': 1, - 'name': 'plugin_name1', - 'version': '1.0.0', - 'package_version': '1.0.0', - 'releases': [{'os': 'ubuntu', 'version': 'liberty-8.0'}, - {'os': 'centos', 'version': 'liberty-8.0'}]}, - {'id': 2, - 'name': 'plugin_name2', - 'version': '1.0.0', - 'package_version': '1.0.0', - 'releases': [{'os': 'ubuntu', 'version': 'liberty-8.0'}, - {'os': 'ubuntu', 'version': 'mitaka-9.0'}]} - ] - get_mock.return_value = plugins - - self.exec_plugins([]) - - get_mock.assert_called_once_with() - self.assert_print_table(print_mock, plugins) - - @patch.object(Serializer, 'print_to_output') - @patch.object(Plugins, 'get_all_data') - def test_list(self, get_mock, print_mock): - plugins = [ - {'id': 1, - 'name': 'plugin_name1', - 'version': '1.0.0', - 'package_version': '1.0.0', - 'releases': [{'os': 'ubuntu', 'version': 'liberty-8.0'}, - {'os': 'centos', 'version': 'liberty-8.0'}]}, - {'id': 2, - 'name': 'plugin_name2', - 'version': '1.0.0', - 'package_version': '1.0.0', - 'releases': [{'os': 'ubuntu', 'version': 'liberty-8.0'}, - {'os': 'ubuntu', 'version': 'mitaka-9.0'}]} - ] - get_mock.return_value = plugins - - self.exec_plugins(['--list']) - - get_mock.assert_called_once_with() - self.assert_print_table(print_mock, plugins) - - @patch.object(Serializer, 'print_to_output') - @patch.object(PluginAction, 'check_file') - @patch.object(Plugins, 'install', return_value='some_result') - def test_install(self, install_mock, check_mock, print_mock): - self.exec_plugins(['--install', self.file_name]) - self.assert_print( - print_mock, - 'some_result', - 'Plugin /tmp/path/plugin.fp was successfully installed.') - install_mock.assert_called_once_with(self.file_name, force=False) - check_mock.assert_called_once_with(self.file_name) - - @patch.object(Serializer, 'print_to_output') - @patch.object(Plugins, 'remove', return_value='some_result') - def test_remove(self, remove_mock, print_mock): - self.exec_plugins(['--remove', self.attr_name]) - self.assert_print( - print_mock, - 'some_result', - 'Plugin plugin_name==version was successfully removed.') - remove_mock.assert_called_once_with(self.name, self.version) - - @patch.object(Serializer, 'print_to_output') - @patch.object(PluginAction, 'check_file') - @patch.object(Plugins, 'update', return_value='some_result') - def test_update(self, update_mock, check_mock, print_mock): - self.exec_plugins(['--update', self.file_name]) - self.assert_print( - print_mock, - 'some_result', - 'Plugin /tmp/path/plugin.fp was successfully updated.') - update_mock.assert_called_once_with(self.file_name) - check_mock.assert_called_once_with(self.file_name) - - @patch.object(Serializer, 'print_to_output') - @patch.object(PluginAction, 'check_file') - @patch.object(Plugins, 'downgrade', return_value='some_result') - def test_downgrade(self, downgrade_mock, check_mock, print_mock): - self.exec_plugins(['--downgrade', self.file_name]) - self.assert_print( - print_mock, - 'some_result', - 'Plugin /tmp/path/plugin.fp was successfully downgraded.') - downgrade_mock.assert_called_once_with(self.file_name) - check_mock.assert_called_once_with(self.file_name) - - @patch.object(Serializer, 'print_to_output') - @patch.object(Plugins, 'sync') - def test_sync(self, sync_mock, print_mock): - self.exec_plugins(['--sync']) - self.assert_print( - print_mock, - None, - 'Plugins were successfully synchronized.') - self.assertTrue(sync_mock.called) - - @patch.object(Serializer, 'print_to_output') - @patch.object(Plugins, 'sync') - def test_sync_with_specific_plugins(self, sync_mock, print_mock): - self.exec_plugins(['--sync', '--plugin-id=1,2,3']) - self.assert_print( - print_mock, - None, - 'Plugins were successfully synchronized.') - sync_mock.assert_called_once_with(plugin_ids=[1, 2, 3]) - - @patch.object(Serializer, 'print_to_output') - @patch.object(Plugins, 'register', return_value='some_result') - def test_register(self, register_mock, print_mock): - self.exec_plugins(['--register', 'plugin_name==version']) - self.assert_print( - print_mock, - 'some_result', - 'Plugin plugin_name==version was successfully registered.') - register_mock.assert_called_once_with( - self.name, self.version, force=False) - - @patch.object(Serializer, 'print_to_output') - @patch.object(Plugins, 'unregister', return_value='some_result') - def test_unregister(self, unregister_mock, print_mock): - self.exec_plugins(['--unregister', 'plugin_name==version']) - self.assert_print( - print_mock, - 'some_result', - 'Plugin plugin_name==version was successfully unregistered.') - unregister_mock.assert_called_once_with(self.name, self.version) - - def test_parse_name_version(self): - plugin = PluginAction() - self.assertEqual( - plugin.parse_name_version('name==version'), - ['name', 'version']) - - def test_parse_name_version_raises_error(self): - plugin = PluginAction() - self.assertRaisesRegexp( - error.ArgumentException, - 'Syntax: fuel plugins fuel_plugin==1.0.0', - plugin.parse_name_version, 'some_string') - - @patch('fuelclient.utils.file_exists', return_value=True) - def test_check_file(self, _): - plugin = PluginAction() - plugin.check_file(self.file_name) - - @patch('fuelclient.utils.file_exists', return_value=False) - def test_check_file_raises_error(self, _): - plugin = PluginAction() - self.assertRaisesRegexp( - error.ArgumentException, - 'File "/tmp/path/plugin.fp" does not exists', - plugin.check_file, self.file_name) diff --git a/fuelclient/tests/unit/v1/test_plugins_object.py b/fuelclient/tests/unit/v1/test_plugins_object.py deleted file mode 100644 index c959b5d..0000000 --- a/fuelclient/tests/unit/v1/test_plugins_object.py +++ /dev/null @@ -1,485 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fixtures -import mock -from mock import MagicMock -from mock import patch - -from fuelclient.cli import error -from fuelclient.objects import plugins -from fuelclient.objects.plugins import Plugins -from fuelclient.objects.plugins import PluginV1 -from fuelclient.objects.plugins import PluginV2 -from fuelclient.tests.unit.v1 import base -from fuelclient import utils - - -@patch('fuelclient.objects.plugins.raise_error_if_not_master') -class TestPluginV1(base.UnitTestCase): - - fake_meta = """ - name: 'plugin_name' - version: 'version' - """ - - def setUp(self): - super(TestPluginV1, self).setUp() - self.plugin = PluginV1 - self.path = '/tmp/plugin/path' - self.name = 'plugin_name' - self.version = 'version' - - @patch('fuelclient.objects.plugins.tarfile') - def test_install(self, tar_mock, master_only_mock): - tar_obj = MagicMock() - tar_mock.open.return_value = tar_obj - - self.plugin.install(self.path) - - master_only_mock.assert_called_once_with() - tar_obj.extractall.assert_called_once_with('/var/www/nailgun/plugins/') - tar_obj.close.assert_called_once_with() - - @patch('fuelclient.objects.plugins.shutil.rmtree') - def test_remove(self, rmtree_mock, master_only_mock): - self.plugin.remove(self.name, self.version) - - master_only_mock.assert_called_once_with() - rmtree_mock.assert_called_once_with( - '/var/www/nailgun/plugins/plugin_name-version') - - def test_update(self, _): - self.assertRaisesRegexp( - error.BadDataException, - 'Update action is not supported for old plugins with ' - 'package version "1.0.0", you can install your plugin ' - 'or use newer plugin format.', - self.plugin.update, 'some_string') - - def test_downgrade(self, _): - self.assertRaisesRegexp( - error.BadDataException, - 'Downgrade action is not supported for old plugins with ' - 'package version "1.0.0", you can install your plugin ' - 'or use newer plugin format.', - self.plugin.downgrade, 'some_string') - - def mock_tar(self, tar_mock): - tar_obj = MagicMock() - tar_mock.open.return_value = tar_obj - tar_file = MagicMock() - tar_obj.getnames.return_value = ['metadata.yaml'] - tar_obj.extractfile.return_value = tar_file - tar_file.read.return_value = self.fake_meta - - @patch('fuelclient.objects.plugins.tarfile') - def test_name_from_file(self, tar_mock, _): - self.mock_tar(tar_mock) - - self.assertEqual( - self.plugin.name_from_file(self.path), - self.name) - - @patch('fuelclient.objects.plugins.tarfile') - def test_version_from_file(self, tar_mock, _): - self.mock_tar(tar_mock) - - self.assertEqual( - self.plugin.version_from_file(self.path), - self.version) - - -@patch('fuelclient.objects.plugins.raise_error_if_not_master') -class TestPluginV2(base.UnitTestCase): - - def setUp(self): - super(TestPluginV2, self).setUp() - self.plugin = PluginV2 - self.path = '/tmp/plugin/path' - self.name = 'plugin_name' - self.version = '1.2.3' - - @patch('fuelclient.objects.plugins.utils.exec_cmd') - def test_install(self, exec_mock, master_only_mock): - self.plugin.install(self.path) - - exec_mock.assert_called_once_with( - 'yum -y install --disablerepo=\'*\' /tmp/plugin/path') - master_only_mock.assert_called_once_with() - - @patch('fuelclient.objects.plugins.utils.exec_cmd') - def test_install_w_force(self, exec_mock, master_only_mock): - self.plugin.install(self.path, force=True) - - exec_mock.assert_called_once_with( - 'yum -y install --disablerepo=\'*\' /tmp/plugin/path' - ' || yum -y reinstall --disablerepo=\'*\' /tmp/plugin/path') - master_only_mock.assert_called_once_with() - - @patch('fuelclient.objects.plugins.utils.exec_cmd') - def test_remove(self, exec_mock, master_only_mock): - self.plugin.remove(self.name, self.version) - - exec_mock.assert_called_once_with('yum -y remove plugin_name-1.2') - master_only_mock.assert_called_once_with() - - @patch('fuelclient.objects.plugins.utils.exec_cmd') - def test_update(self, exec_mock, master_only_mock): - self.plugin.update(self.path) - - exec_mock.assert_called_once_with('yum -y update /tmp/plugin/path') - master_only_mock.assert_called_once_with() - - @patch('fuelclient.objects.plugins.utils.exec_cmd') - def test_downgrade(self, exec_mock, master_only_mock): - self.plugin.downgrade(self.path) - - exec_mock.assert_called_once_with('yum -y downgrade /tmp/plugin/path') - master_only_mock.assert_called_once_with() - - @patch('fuelclient.objects.plugins.utils.exec_cmd_iterator', - return_value=['plugin_name-1.2']) - def test_name_from_file(self, exec_mock, _): - self.assertEqual( - self.plugin.name_from_file(self.path), - self.name) - - exec_mock.assert_called_once_with( - "rpm -qp --queryformat '%{name}' /tmp/plugin/path") - - @patch('fuelclient.objects.plugins.utils.exec_cmd_iterator', - return_value=['1.2.3']) - def test_version_from_file(self, exec_mock, _): - self.assertEqual( - self.plugin.version_from_file(self.path), - self.version) - - exec_mock.assert_called_once_with( - "rpm -qp --queryformat '%{version}' /tmp/plugin/path") - - -class TestPluginsObject(base.UnitTestCase): - - def setUp(self): - super(TestPluginsObject, self).setUp() - self.plugin = Plugins - self.path = '/tmp/plugin/path' - self.name = 'plugin_name' - self.version = 'version' - - def mock_make_obj_by_file(self, make_obj_by_file_mock): - plugin_obj = MagicMock() - plugin_obj.name_from_file.return_value = 'retrieved_name' - plugin_obj.version_from_file.return_value = 'retrieved_version' - make_obj_by_file_mock.return_value = plugin_obj - - return plugin_obj - - @patch('fuelclient.utils.glob_and_parse_yaml', - return_value=[ - {'name': 'name1', 'version': 'version1'}, - {'name': 'name2', 'version': 'version2'}, - {'name': 'name3', 'version': 'version3'}]) - @patch.object(Plugins, 'update_or_create') - def test_register(self, up_or_create_mock, glob_parse_mock): - self.plugin.register('name3', 'version3') - glob_parse_mock.assert_called_once_with( - '/var/www/nailgun/plugins/*/metadata.yaml') - up_or_create_mock.assert_called_once_with( - {'name': 'name3', 'version': 'version3'}, - force=False) - - @patch('fuelclient.utils.glob_and_parse_yaml', return_value=[]) - def test_register_raises_error(self, glob_parse_mock): - self.assertRaisesRegexp( - error.BadDataException, - 'Plugin name3 with version version3 does ' - 'not exist, install it and try again', - self.plugin.register, 'name3', 'version3') - - glob_parse_mock.assert_called_once_with( - '/var/www/nailgun/plugins/*/metadata.yaml') - - @patch.object(Plugins, 'get_plugin', return_value={'id': 123}) - @patch.object(Plugins.connection, 'delete_request') - def test_unregister(self, del_mock, get_mock): - self.plugin.unregister(self.name, self.version) - get_mock.assert_called_once_with(self.name, self.version) - del_mock.assert_called_once_with('plugins/123') - - @patch.object(utils, 'file_exists', return_value=True) - @patch.object(Plugins, 'register') - @patch.object(Plugins, 'make_obj_by_file') - def test_install(self, make_obj_by_file_mock, register_mock, - file_exists_mock): - plugin_obj = self.mock_make_obj_by_file(make_obj_by_file_mock) - register_mock.return_value = {'id': 1} - self.plugin.install(self.path) - - plugin_obj.install.assert_called_once_with(self.path, force=False) - register_mock.assert_called_once_with( - 'retrieved_name', 'retrieved_version', force=False) - file_exists_mock.assert_called_once_with(self.path) - - @patch.object(Plugins, 'unregister') - @patch.object(Plugins, 'make_obj_by_name') - def test_remove(self, make_obj_by_name_mock, unregister_mock): - plugin_obj = MagicMock() - make_obj_by_name_mock.return_value = plugin_obj - - self.plugin.remove(self.name, self.version) - - plugin_obj.remove.assert_called_once_with(self.name, self.version) - unregister_mock.assert_called_once_with(self.name, self.version) - - @patch.object(Plugins.connection, 'post_request') - def test_sync(self, post_mock): - self.plugin.sync() - post_mock.assert_called_once_with( - api='plugins/sync/', data=None) - - @patch.object(Plugins.connection, 'post_request') - def test_sync_with_specific_plugins(self, post_mock): - self.plugin.sync(plugin_ids=[1, 2]) - data = {'ids': [1, 2]} - post_mock.assert_called_once_with( - api='plugins/sync/', data=data) - - @patch.object(Plugins, 'register') - @patch.object(Plugins, 'make_obj_by_file') - def test_update(self, make_obj_by_file_mock, register_mock): - plugin_obj = self.mock_make_obj_by_file(make_obj_by_file_mock) - - self.plugin.update(self.path) - - plugin_obj.update.assert_called_once_with(self.path) - register_mock.assert_called_once_with( - 'retrieved_name', 'retrieved_version') - - @patch.object(Plugins, 'register') - @patch.object(Plugins, 'make_obj_by_file') - def test_downgrade(self, make_obj_by_file_mock, register_mock): - plugin_obj = self.mock_make_obj_by_file(make_obj_by_file_mock) - - self.plugin.downgrade(self.path) - - plugin_obj.downgrade.assert_called_once_with(self.path) - register_mock.assert_called_once_with( - 'retrieved_name', 'retrieved_version') - - @patch.object(Plugins, 'get_plugin') - def test_make_obj_by_name_v1(self, get_mock): - plugins = [{'package_version': '1.0.0'}, - {'package_version': '1.0.1'}, - {'package_version': '1.99.99'}] - - for plugin in plugins: - get_mock.return_value = plugin - self.assertEqual( - self.plugin.make_obj_by_name(self.name, self.version), - PluginV1) - - @patch.object(Plugins, 'get_plugin') - def test_make_obj_by_name_v2(self, get_mock): - plugins = [{'package_version': '2.0.0'}, - {'package_version': '2.0.1'}, - {'package_version': '3.0.0'}] - - for plugin in plugins: - get_mock.return_value = plugin - self.assertEqual( - self.plugin.make_obj_by_name(self.name, self.version), - PluginV2) - - @patch.object(Plugins, 'get_plugin') - def test_make_obj_by_name_v2_raises_error(self, get_mock): - get_mock.return_value = {'package_version': '0.0.1'} - - self.assertRaisesRegexp( - error.BadDataException, - 'Plugin plugin_name==version has ' - 'unsupported package version 0.0.1', - self.plugin.make_obj_by_name, self.name, self.version) - - def test_make_obj_by_file_v1(self): - self.assertEqual( - self.plugin.make_obj_by_file('file-name-1.2.3.fp'), - PluginV1) - - def test_make_obj_by_file_v2(self): - self.assertEqual( - self.plugin.make_obj_by_file('file-name-1.2-1.2.3-0.noarch.rpm'), - PluginV2) - - def test_make_obj_by_file_raises_error(self): - self.assertRaisesRegexp( - error.BadDataException, - 'Plugin file-name.ext has unsupported format .ext', - self.plugin.make_obj_by_file, 'file-name.ext') - - @patch.object(Plugins, 'get_plugin_for_update', return_value={'id': 99}) - @patch.object(Plugins.connection, 'put_request', return_value={'id': 99}) - def test_update_or_create_updates(self, put_mock, get_for_update_mock): - meta = {'id': 99, 'version': '1.0.0', 'package_version': '2.0.0'} - self.plugin.update_or_create(meta) - put_mock.assert_called_once_with('plugins/99', meta) - - @patch.object(Plugins, 'get_plugin_for_update', return_value=None) - @patch.object(Plugins.connection, 'post_request_raw', - return_value=MagicMock(status_code=201)) - @patch.object(Plugins.connection, 'put_request') - def test_update_or_create_creates( - self, put_mock, post_mock, get_for_update_mock): - meta = {'id': 99, 'version': '1.0.0', 'package_version': '2.0.0'} - self.plugin.update_or_create(meta) - post_mock.assert_called_once_with('plugins/', meta) - get_for_update_mock.assert_called_once_with(meta) - self.assertFalse(put_mock.called) - - @patch.object(Plugins, 'get_plugin_for_update', return_value=None) - @patch.object(Plugins.connection, 'post_request_raw', - return_value=MagicMock( - status_code=409, - **{'json.return_value': {'id': 99}})) - @patch.object(Plugins.connection, 'put_request', return_value='put_return') - def test_update_or_create_updates_without_force( - self, put_mock, post_mock, get_for_update_mock): - meta = {'id': 99, 'version': '1.0.0', 'package_version': '2.0.0', - 'title': 'Plugin title'} - self.assertRaises(SystemExit, - self.plugin.update_or_create, - meta, - force=False) - - @patch.object(Plugins, 'get_plugin_for_update', return_value=None) - @patch.object(Plugins.connection, 'post_request_raw', - return_value=MagicMock( - status_code=409, - **{'json.return_value': {'message': '{"id": 99}'}})) - @patch.object(Plugins.connection, 'put_request', return_value='put_return') - def test_update_or_create_updates_with_force( - self, put_mock, post_mock, get_for_update_mock): - meta = {'id': 99, 'version': '1.0.0', 'package_version': '2.0.0'} - self.assertEqual( - self.plugin.update_or_create(meta, force=True), - 'put_return') - post_mock.assert_called_once_with('plugins/', meta) - get_for_update_mock.assert_called_once_with(meta) - put_mock.assert_called_once_with('plugins/99', meta) - - @patch.object(Plugins, 'get_all_data') - def test_get_plugin_for_update(self, get_mock): - plugin_to_be_found = {'name': 'name', 'version': '2.2.0', - 'package_version': '2.0.0'} - - get_mock.return_value = [ - # Different major version - {'name': 'name', 'version': '2.3.0', - 'package_version': '2.0.0'}, - {'name': 'name', 'version': '2.1.0', - 'package_version': '2.0.0'}, - # Different name - {'name': 'different_name', 'version': '2.2.99', - 'package_version': '2.0.0'}, - # Package version is not updatable - {'name': 'name', 'version': '2.2.100', - 'package_version': '1.0.0'}, - plugin_to_be_found] - - self.assertEqual( - self.plugin.get_plugin_for_update( - {'name': 'name', - 'version': '2.2.99', - 'package_version': '2.0.0'}), - plugin_to_be_found) - - # Required plugin has not updatable package version - self.assertIsNone(self.plugin.get_plugin_for_update( - {'name': 'name', 'version': '2.2.99', 'package_version': '1.0.0'})) - - # Plugin does not exist - self.assertIsNone(self.plugin.get_plugin_for_update( - {'name': 'name2', 'version': '2.2.9', 'package_version': '2.0.0'})) - - def test_is_updatable(self): - for updatable in ['2.0.0', '2.0.1', '99.99.99']: - self.assertTrue(self.plugin.is_updatable(updatable)) - - for is_not_updatable in ['0.0.1', '1.0.0', '1.99.99']: - self.assertFalse(self.plugin.is_updatable(is_not_updatable)) - - @patch.object(Plugins, 'get_all_data', - return_value=[{'name': 'name1', 'version': '1.0.0'}, - {'name': 'name2', 'version': '1.0.1'}, - {'name': 'name2', 'version': '1.0.0'}]) - def test_get_plugin(self, get_mock): - self.assertEqual(self.plugin.get_plugin('name2', '1.0.0'), - {'name': 'name2', 'version': '1.0.0'}) - get_mock.assert_called_once_with() - - @patch('fuelclient.objects.plugins.utils.find_exec') - @patch('fuelclient.objects.plugins.subprocess.Popen') - def test_raise_error_if_not_master(self, mpop, mfe): - plugins.IS_MASTER = None - process = MagicMock() - mfe.return_value = '/bin/rpm' - mpop.return_value = process - process.poll.return_value = 0 - self.assertIsNone(plugins.raise_error_if_not_master()) - mpop.assert_called_once_with( - ['/bin/rpm', '-q', plugins.FUEL_PACKAGE], - stdout=mock.ANY, stderr=mock.ANY) - process.poll.assert_called_once_with() - process.communicate.assert_called_once_with() - - @patch('fuelclient.objects.plugins.utils.find_exec') - @patch('fuelclient.objects.plugins.subprocess.Popen') - def test_raise_error_if_not_master_fuel_not_installed(self, mpop, mfe): - plugins.IS_MASTER = None - process = MagicMock() - mpop.return_value = process - process.poll.return_value = 1 - self.assertRaises(error.WrongEnvironmentError, - plugins.raise_error_if_not_master) - - @patch('fuelclient.objects.plugins.utils.find_exec') - def test_raise_error_if_not_master_rpm_not_found(self, mfe): - plugins.IS_MASTER = None - mfe.return_value = None - self.assertRaises(error.WrongEnvironmentError, - plugins.raise_error_if_not_master) - - @patch('fuelclient.objects.plugins.os.access') - @patch('fuelclient.objects.plugins.os.path.isfile') - def test_find_exec(self, misf, macc): - misf.side_effect = [False, True, True] - macc.side_effect = [False, True] - # The combination will be like: - # 1) /foo/program does not exist - # 2) /bar/program does exist but isn't executable - # 3) /baz/program does exist and is executable - # So the function is to search 'program' in paths /foo, /bar, /baz - # and return /baz/program - self.useFixture(fixtures.EnvironmentVariable('PATH', '/foo:/bar:/baz')) - self.assertEqual('/baz/program', plugins.utils.find_exec('program')) - - @patch('fuelclient.objects.plugins.os.access') - @patch('fuelclient.objects.plugins.os.path.isfile') - def test_find_exec_not_found(self, misf, macc): - misf.return_value = False - self.useFixture(fixtures.EnvironmentVariable('PATH', '/foo')) - self.assertIsNone(plugins.utils.find_exec('program')) diff --git a/fuelclient/tests/unit/v1/test_release_networks_action.py b/fuelclient/tests/unit/v1/test_release_networks_action.py deleted file mode 100644 index d9b19cc..0000000 --- a/fuelclient/tests/unit/v1/test_release_networks_action.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 mock import patch -import requests_mock as rm - -from fuelclient.tests.unit.v1 import base - - -API_INPUT = {'config': 'neutron'} -API_OUTPUT = 'config: neutron\n' - - -@patch('fuelclient.cli.serializers.open', create=True) -@patch('fuelclient.cli.actions.base.os') -class TestReleaseNetworkActions(base.UnitTestCase): - - def test_release_network_download(self, mos, mopen): - self.m_request.get(rm.ANY, json=API_INPUT) - self.execute(['fuel', 'rel', '--rel', '1', '--network', '--download']) - mopen().__enter__().write.assert_called_once_with(API_OUTPUT) - - def test_release_network_upload(self, mos, mopen): - mopen().__enter__().read.return_value = API_OUTPUT - put = self.m_request.put('/api/v1/releases/1/networks', json={}) - self.execute(['fuel', 'rel', '--rel', '1', '--network', '--upload']) - - self.assertTrue(put.called) - self.assertEqual(put.last_request.json(), API_INPUT) diff --git a/fuelclient/tests/unit/v1/test_roles.py b/fuelclient/tests/unit/v1/test_roles.py deleted file mode 100644 index a4de90c..0000000 --- a/fuelclient/tests/unit/v1/test_roles.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock import patch -import yaml - -from fuelclient.cli.serializers import Serializer -from fuelclient.tests.unit.v1 import base - -API_IN = """name: my_role -""" - -API_OUT = yaml.load(API_IN) - - -class TestRoleActions(base.UnitTestCase): - - owner_id = 2 - - def test_list_release_roles(self): - url = '/api/v1/releases/{0}/roles/'.format(self.owner_id) - cmd = 'fuel role --rel {0}'.format(self.owner_id) - get_request = self.m_request.get(url, json=[API_OUT]) - - self.execute(cmd.split()) - - self.assertTrue(get_request.called) - self.assertIn(url, get_request.last_request.url) - - def test_list_cluster_roles(self): - url = '/api/v1/clusters/{0}/roles/'.format(self.owner_id) - cmd = 'fuel role --env {0}'.format(self.owner_id) - get_request = self.m_request.get(url, json=[API_OUT]) - - self.execute(cmd.split()) - - self.assertTrue(get_request.called) - self.assertIn(url, get_request.last_request.url) - - @patch('fuelclient.cli.serializers.open', create=True) - def test_get_release_role(self, mopen): - url = '/api/v1/releases/{0}/roles/my_role/'.format(self.owner_id) - cmd = 'fuel role --role my_role --file myfile.yaml --rel {0}'.format( - self.owner_id) - get_request = self.m_request.get(url, json=API_OUT) - - self.execute(cmd.split()) - - mopen().__enter__().write.assert_called_once_with(API_IN) - self.assertTrue(get_request.called) - self.assertIn(url, get_request.last_request.url) - - @patch('fuelclient.cli.serializers.open', create=True) - def test_get_cluster_role(self, mopen): - url = '/api/v1/clusters/{0}/roles/my_role/'.format(self.owner_id) - cmd = 'fuel role --role my_role --file myfile.yaml --env {0}'.format( - self.owner_id) - get_request = self.m_request.get(url, json=API_OUT) - - self.execute(cmd.split()) - - mopen().__enter__().write.assert_called_once_with(API_IN) - self.assertTrue(get_request.called) - self.assertIn(url, get_request.last_request.url) - - @patch('fuelclient.cli.serializers.open', create=True) - def test_create_release_role(self, mopen): - url = '/api/v1/releases/{0}/roles/'.format(self.owner_id) - cmd = 'fuel role --create --file myfile.yaml --rel {0}'.format( - self.owner_id) - mopen().__enter__().read.return_value = API_IN - post_request = self.m_request.post(url, json=API_OUT) - - self.execute(cmd.split()) - - self.assertTrue(post_request.called) - self.assertIn(url, post_request.last_request.url) - self.assertEqual( - API_OUT, post_request.last_request.json()) - - @patch('fuelclient.cli.serializers.open', create=True) - def test_create_cluster_role(self, mopen): - url = '/api/v1/clusters/{0}/roles/'.format(self.owner_id) - cmd = 'fuel role --create --file myfile.yaml --env {0}'.format( - self.owner_id) - mopen().__enter__().read.return_value = API_IN - post_request = self.m_request.post(url, json=API_OUT) - - self.execute(cmd.split()) - - self.assertTrue(post_request.called) - self.assertIn(url, post_request.last_request.url) - self.assertEqual( - API_OUT, post_request.last_request.json()) - - @patch('fuelclient.cli.serializers.open', create=True) - def test_update_release_role(self, mopen): - url = '/api/v1/releases/{0}/roles/my_role/'.format(self.owner_id) - cmd = 'fuel role --update --file myfile.yaml --rel {0}'.format( - self.owner_id) - mopen().__enter__().read.return_value = API_IN - put_request = self.m_request.put(url, json=API_OUT) - - self.execute(cmd.split()) - - self.assertTrue(put_request.called) - self.assertIn(url, put_request.last_request.url) - self.assertEqual( - API_OUT, put_request.last_request.json()) - - @patch('fuelclient.cli.serializers.open', create=True) - def test_update_cluster_role(self, mopen): - url = '/api/v1/clusters/{0}/roles/my_role/'.format(self.owner_id) - cmd = 'fuel role --update --file myfile.yaml --env {0}'.format( - self.owner_id) - mopen().__enter__().read.return_value = API_IN - put_request = self.m_request.put(url, json=API_OUT) - - self.execute(cmd.split()) - - self.assertTrue(put_request.called) - self.assertIn(url, put_request.last_request.url) - self.assertEqual( - API_OUT, put_request.last_request.json()) - - def test_delete_release_role(self): - url = '/api/v1/releases/{0}/roles/my_role/'.format(self.owner_id) - cmd = 'fuel role --delete --role my_role --rel {0}'.format( - self.owner_id) - delete_request = self.m_request.delete(url, json=API_OUT) - - self.execute(cmd.split()) - - self.assertTrue(delete_request.called) - self.assertIn(url, delete_request.last_request.url) - - def test_delete_cluster_role(self): - url = '/api/v1/clusters/{0}/roles/my_role/'.format(self.owner_id) - cmd = 'fuel role --delete --role my_role --env {0}'.format( - self.owner_id) - delete_request = self.m_request.delete(url, json=API_OUT) - - self.execute(cmd.split()) - - self.assertTrue(delete_request.called) - self.assertIn(url, delete_request.last_request.url) - - def test_formatting_for_list_roles(self): - url = '/api/v1/releases/{0}/roles/'.format(self.owner_id) - cmd = 'fuel role --rel {0}'.format(self.owner_id) - get_request = self.m_request.get(url, json=[API_OUT]) - - with patch.object(Serializer, 'print_to_output') as mock_print: - with patch('fuelclient.cli.actions.role.format_table') \ - as format_table_mock: - self.execute(cmd.split()) - - self.assertTrue(get_request.called) - self.assertIn(url, get_request.last_request.url) - - format_table_mock.assert_called_once_with( - [API_OUT], acceptable_keys=('name',)) - mock_print.assert_called_once_with( - [API_OUT], format_table_mock.return_value) diff --git a/fuelclient/tests/unit/v1/test_snapshot.py b/fuelclient/tests/unit/v1/test_snapshot.py deleted file mode 100644 index 6e33faa..0000000 --- a/fuelclient/tests/unit/v1/test_snapshot.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock import call -from mock import Mock -from mock import patch - -from fuelclient.tests.unit.v1 import base - - -class TestSnapshot(base.UnitTestCase): - - def setUp(self): - super(TestSnapshot, self).setUp() - - self.mtask = Mock(status='ready', data={'message': ''}) - self.mtask.connection = Mock(root='') - - @patch('fuelclient.cli.actions.snapshot.SnapshotTask.get_default_config') - @patch('sys.stdout') - def test_get_default_config(self, mstdout, mconf): - - mconf.return_value = {'key': 'value'} - - self.execute(['fuel', 'snapshot', '--conf']) - self.assertEqual(mstdout.write.call_args_list, [call('key: value\n')]) - - @patch('fuelclient.cli.actions.snapshot.SnapshotTask.start_snapshot_task') - @patch('sys.stdin') - @patch('sys.stdout') - def test_create_snapshot_with_provided_conf(self, mstdout, mstdin, mstart): - conf = 'key: value\n' - - mstdin.isatty.return_value = False - mstdin.read.return_value = conf - - mstart.return_value = self.mtask - - self.execute(['fuel', 'snapshot']) - - mstart.assert_called_once_with({'key': 'value'}) - self.assertEqual(mstdin.read.call_count, 1) - msg = mstdout.write.call_args_list[2][0][0] - self.assertIn("Diagnostic snapshot can be downloaded from", msg) - - @patch('fuelclient.cli.actions.snapshot.SnapshotTask.start_snapshot_task') - @patch('sys.stdin') - @patch('sys.stdout') - def test_create_snapshot_without_conf(self, mstdout, mstdin, mstart): - - mstdin.isatty.return_value = True - - mstart.return_value = self.mtask - - self.execute(['fuel', 'snapshot']) - - mstart.assert_called_once_with({}) - msg = mstdout.write.call_args_list[2][0][0] - self.assertIn("Diagnostic snapshot can be downloaded from", msg) - - @patch('fuelclient.cli.actions.snapshot.SnapshotTask.start_snapshot_task') - @patch('sys.stdin') - @patch('sys.stderr') - def test_create_snapshot_when_task_is_failed( - self, mstderr, mstdin, mstart): - mstdin.isatty.return_value = True - - mdata = {'message': 'mock task message'} - self.mtask.status = 'error' - self.mtask.data = mdata - - mstart.return_value = self.mtask - - self.execute(['fuel', 'snapshot']) - - err_msg = ("Snapshot generating task ended with error. " - "Task message: {0}".format(mdata['message'])) - mstderr.write.called_once_with(err_msg) - - @patch('fuelclient.cli.actions.snapshot.SnapshotTask.start_snapshot_task') - @patch('sys.stdin') - @patch('sys.stdout') - def test_downloadable_snapshot_url(self, mstdout, mstdin, mstart): - expected_url = 'http://127.0.0.1:8000' - mdata = {'message': '/api/dump/mock-fuel-snapshot.tar.xz'} - mstdin.isatty.return_value = True - self.mtask.connection.root = expected_url - self.mtask.data = mdata - - mstart.return_value = self.mtask - - self.execute(['fuel', 'snapshot']) - - expected_msg = ("...Completed...\n" - "Diagnostic snapshot can be downloaded from " - "{}{}".format(expected_url, mdata['message'])) - msg = mstdout.write.call_args_list[2][0][0] - self.assertEqual(expected_msg, msg) diff --git a/fuelclient/tests/unit/v1/test_token_action.py b/fuelclient/tests/unit/v1/test_token_action.py deleted file mode 100644 index 1071292..0000000 --- a/fuelclient/tests/unit/v1/test_token_action.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 io - -import mock - -from fuelclient.tests.unit.v1 import base - - -class TestPluginsActions(base.UnitTestCase): - - @mock.patch('fuelclient.cli.actions.token.DefaultAPIClient') - def test_token_action(self, mAPIClient): - with mock.patch('sys.stdout', new=io.StringIO()) as mstdout: - token = u'token123' - mauth_token = mock.PropertyMock(return_value=token) - type(mAPIClient).auth_token = mauth_token - - self.execute(['fuel', 'token']) - - self.assertEqual(mauth_token.call_count, 1) - self.assertEqual(mstdout.getvalue(), token) diff --git a/fuelclient/tests/unit/v1/test_user_action.py b/fuelclient/tests/unit/v1/test_user_action.py deleted file mode 100644 index a78cecc..0000000 --- a/fuelclient/tests/unit/v1/test_user_action.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock - -from fuelclient.cli.actions.user import UserAction -from fuelclient.cli.error import ArgumentException -from fuelclient.tests.unit.v1 import base - - -class TestChangePassword(base.UnitTestCase): - - def assert_print(self, print_mock, result, msg): - print_mock.assert_called_once_with(result, msg) - - def test_get_password_from_prompt(self): - user_action = UserAction() - passwd = 'secret!' - with mock.patch('fuelclient.cli.actions.user.getpass', - return_value=passwd): - user_passwd = user_action._get_password_from_prompt() - - self.assertEqual(passwd, user_passwd) - - @mock.patch('fuelclient.cli.actions.user.getpass', - side_effect=['pwd', 'otherpwd']) - def test_get_password_from_prompt_different_passwords(self, mgetpass): - user_action = UserAction() - with self.assertRaisesRegexp( - ArgumentException, 'Passwords are not the same'): - user_action._get_password_from_prompt() - - @mock.patch('fuelclient.cli.serializers.Serializer.print_to_output') - @mock.patch('fuelclient.cli.actions.user.fuelclient_settings') - @mock.patch('fuelclient.cli.actions.user.DefaultAPIClient') - def test_change_password(self, mapiclient, settings_mock, print_mock): - user_action = UserAction() - params = mock.Mock() - params.newpass = None - password = 'secret' - conf_file = '/tmp/fuel_client.yaml' - settings_mock.get_settings.return_value = mock.Mock( - user_settings=conf_file) - - with mock.patch('fuelclient.cli.actions.user.getpass', - return_value=password) as mgetpass: - user_action.change_password(params) - - calls = [ - mock.call("Changing password for Fuel User.\nNew Password:"), - mock.call("Retype new Password:"), - ] - - mgetpass.assert_has_calls(calls) - mapiclient.update_own_password.assert_called_once_with(password) - - msg = "\nPassword changed.\nPlease note that configuration " \ - "is not automatically updated.\nYou may want to update " \ - "{0}.".format(conf_file) - - self.assert_print( - print_mock, - None, - msg) - - @mock.patch('fuelclient.cli.actions.user.DefaultAPIClient') - def test_change_password_w_newpass(self, mapiclient): - user_action = UserAction() - params = mock.Mock() - params.newpass = 'secret' - user_action.change_password(params) - mapiclient.update_own_password.assert_called_once_with(params.newpass) diff --git a/fuelclient/tests/unit/v1/test_vip_action.py b/fuelclient/tests/unit/v1/test_vip_action.py deleted file mode 100644 index 2fdd6d8..0000000 --- a/fuelclient/tests/unit/v1/test_vip_action.py +++ /dev/null @@ -1,214 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 mock -import six -import yaml - -from fuelclient.tests.unit.v1 import base - -ENV_OUTPUT = { - "status": "new", - "is_customized": False, - "release_id": 2, - "ui_settings": { - "sort": [{"roles": "asc"}], - "sort_by_labels": [], - "search": "", - "filter_by_labels": {}, - "filter": {}, - "view_mode": "standard" - }, - "is_locked": False, - "fuel_version": "8.0", - "net_provider": "neutron", - "mode": "ha_compact", - "components": [], - "changes": [ - {"node_id": None, "name": "attributes"}, - {"node_id": None, "name": "networks"}], - "id": 6, "name": "test_not_deployed"} - - -MANY_VIPS_YAML = '''- id: 5 - network: 3 - node: null - ip_addr: 192.169.1.33 - vip_name: public - vip_namespace: haproxy - is_user_defined: false -- id: 6 - network: 3 - node: null - ip_addr: 192.169.1.34 - vip_namespace: null - vip_name: private - is_user_defined: true -''' - -ONE_VIP_YAML = ''' -- id: 5 - network: 3 - node: null - ip_addr: 192.169.1.33 - vip_name: public - vip_namespace: haproxy - is_user_defined: false -''' - - -@mock.patch('fuelclient.cli.serializers.open', create=True) -@mock.patch('fuelclient.cli.actions.base.os') -class TestVIPActions(base.UnitTestCase): - - def test_env_vips_download(self, mos, mopen): - self.m_request.get('/api/v1/clusters/1/', json=ENV_OUTPUT) - url = '/api/v1/clusters/1/network_configuration/ips/vips/' - get_request = self.m_request.get( - url, - json=yaml.load(MANY_VIPS_YAML)) - self.execute('fuel vip --env 1 --download'.split()) - self.assertTrue(get_request.called) - self.assertEqual(1, mopen().__enter__().write.call_count) - self.assertEqual( - yaml.safe_load(MANY_VIPS_YAML), - yaml.safe_load(mopen().__enter__().write.call_args[0][0]), - ) - - def test_env_vips_download_with_network_id(self, mos, mopen): - self.m_request.get('/api/v1/clusters/1/', json=ENV_OUTPUT) - url = '/api/v1/clusters/1/network_configuration/ips/vips/' - get_request = self.m_request.get( - url, - json=yaml.load(MANY_VIPS_YAML)) - self.execute('fuel vip --env 1 --network 3 --download'.split()) - self.assertTrue(get_request.called) - self.assertEqual(1, mopen().__enter__().write.call_count) - self.assertEqual( - yaml.safe_load(MANY_VIPS_YAML), - yaml.safe_load(mopen().__enter__().write.call_args[0][0]), - ) - - def test_env_vips_download_with_network_role(self, mos, mopen): - self.m_request.get('/api/v1/clusters/1/', json=ENV_OUTPUT) - url = '/api/v1/clusters/1/network_configuration/ips/vips/' - get_request = self.m_request.get( - url, - json=yaml.load(MANY_VIPS_YAML)) - self.execute( - 'fuel vip --env 1 --network-role some/role --download'.split()) - self.assertTrue(get_request.called) - self.assertEqual(1, mopen().__enter__().write.call_count) - self.assertEqual( - yaml.safe_load(MANY_VIPS_YAML), - yaml.safe_load(mopen().__enter__().write.call_args[0][0]), - ) - - def test_env_single_vip_download(self, mos, mopen): - self.m_request.get('/api/v1/clusters/1/', json=ENV_OUTPUT) - url = '/api/v1/clusters/1/network_configuration/ips/5/vips/' - get_request = self.m_request.get( - url, - json=yaml.safe_load(ONE_VIP_YAML)[0] - ) - self.execute('fuel vip --env 1 --ip-address-id 5 --download'.split()) - - self.assertTrue(get_request.called) - self.assertEqual(1, mopen().__enter__().write.call_count) - - self.assertEqual( - yaml.safe_load(ONE_VIP_YAML), - yaml.safe_load(mopen().__enter__().write.call_args[0][0]), - ) - self.assertIn( - 'vips_1.yaml', - mopen.call_args_list[0][0][0] - ) - - def test_env_single_vip_download_to_file(self, mos, mopen): - self.m_request.get('/api/v1/clusters/1/', json=ENV_OUTPUT) - url = '/api/v1/clusters/1/network_configuration/ips/5/vips/' - get_request = self.m_request.get( - url, - json=yaml.safe_load(ONE_VIP_YAML)[0] - ) - self.execute('fuel vip --env 1 --ip-address-id 5 ' - '--download --file vips.yaml'.split()) - - self.assertTrue(get_request.called) - self.assertEqual(1, mopen().__enter__().write.call_count) - - self.assertEqual( - yaml.safe_load(ONE_VIP_YAML), - yaml.safe_load(mopen().__enter__().write.call_args[0][0]), - ) - self.assertEqual( - 'vips.yaml', - mopen.call_args_list[0][0][0] - ) - - def check_request(self, request_mock, url): - self.assertEqual(request_mock.call_count, 1) - self.assertIn(url, request_mock.last_request.url) - - def test_vips_upload(self, mos, mopen): - url = '/api/v1/clusters/1/network_configuration/ips/vips/' - mopen().__enter__().read.return_value = MANY_VIPS_YAML - self.m_request.get('/api/v1/clusters/1/', json=ENV_OUTPUT) - request_put = self.m_request.put(url, json={}) - - file_path = 'vips.yaml' - - with mock.patch('fuelclient.objects.environment.os') as env_os: - env_os.path.exists.return_value = True - self.execute(['fuel', 'vip', '--env', '1', '--upload', file_path]) - self.assertEqual(env_os.path.exists.call_count, 1) - self.check_request(request_put, url) - # FileFormatBasedSerializer.read_from_file must not modify given - # file path string - self.assertEqual(file_path, mopen.call_args[0][0]) - - def test_vips_upload_bad_path(self, mos, mopen): - with mock.patch('sys.stderr', new=six.moves.cStringIO()) as mstderr: - with mock.patch('fuelclient.objects.environment.os') as env_os: - env_os.path.exists.return_value = False - self.assertRaises( - SystemExit, - self.execute, - 'fuel vip --env 1 --upload vips_1.yaml'.split() - ) - self.assertIn("doesn't exist", mstderr.getvalue()) - - def test_create_vip(self, *_): - url = '/api/v1/clusters/1/network_configuration/ips/vips/' - request_post = self.m_request.post(url, json={}) - - env_id = 1 - vip_data = { - "ip_addr": "127.0.0.1", - "network": -1, - "vip_name": 'test', - "vip_namespace": 'test-namespace' - } - - self.execute(["fuel", "--env", str(env_id), "vip", "create", - "--ip-addr", vip_data['ip_addr'], - "--network", str(vip_data['network']), - "--name", vip_data['vip_name'], - "--namespace", vip_data['vip_namespace']]) - - self.check_request(request_post, url) - self.assertEqual(request_post.last_request.json(), vip_data) diff --git a/fuelclient/tests/unit/v2/__init__.py b/fuelclient/tests/unit/v2/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fuelclient/tests/unit/v2/cli/__init__.py b/fuelclient/tests/unit/v2/cli/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fuelclient/tests/unit/v2/cli/test_deployment_graph.py b/fuelclient/tests/unit/v2/cli/test_deployment_graph.py deleted file mode 100644 index f70dee0..0000000 --- a/fuelclient/tests/unit/v2/cli/test_deployment_graph.py +++ /dev/null @@ -1,392 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 mock -import six -import yaml - -from fuelclient.cli import error -from fuelclient.tests.unit.v2.cli import test_engine - -TASKS_YAML = '''- id: custom-task-1 - type: puppet - parameters: - param: value -- id: custom-task-2 - type: puppet - parameters: - param: value -''' - -GRAPH_YAML = '''tasks: - - id: custom-task-1 - type: puppet - parameters: - param: value - - id: custom-task-2 - type: puppet - parameters: - param: value -node_filter: $.pending_deletion -''' - -GRAPH_METADATA_YAML = ''' -node_filter: $.pending_addition -on_success: - node_attributes: - status: provisioned -''' - - -class TestGraphActions(test_engine.BaseCLITest): - @mock.patch('fuelclient.commands.graph.os') - def _test_cmd(self, method, cmd_line, expected_kwargs, os_m): - os_m.exists.return_value = True - self.m_get_client.reset_mock() - self.m_client.get_filtered.reset_mock() - m_open = mock.mock_open(read_data=TASKS_YAML) - with mock.patch( - 'fuelclient.cli.serializers.open', m_open, create=True): - self.exec_command('graph {0} {1}'.format(method, cmd_line)) - self.m_get_client.assert_called_once_with('graph', mock.ANY) - self.m_client.__getattr__(method).assert_called_once_with( - **expected_kwargs) - - def test_upload(self): - self._test_cmd( - 'upload', '--env 1 --file new_tasks.yaml -t test', dict( - data=yaml.load(TASKS_YAML), - related_model='clusters', - related_id=1, - graph_type='test' - ) - ) - self._test_cmd( - 'upload', '--release 1 --file new_tasks.yaml -t test', dict( - data=yaml.load(TASKS_YAML), - related_model='releases', - related_id=1, - graph_type='test' - ) - ) - self._test_cmd( - 'upload', '--plugin 1 --file new_tasks.yaml -t test', dict( - data=yaml.load(TASKS_YAML), - related_model='plugins', - related_id=1, - graph_type='test' - ) - ) - self._test_cmd( - 'upload', - '--plugin 1 --file tasks.yaml --graph-type custom_type', - dict( - data=yaml.load(TASKS_YAML), - related_model='plugins', - related_id=1, - graph_type='custom_type' - ) - ) - - @mock.patch('fuelclient.commands.graph.os') - def test_graph_upload_from_file(self, os_m): - os_m.path.exists.return_value = True - self.m_get_client.reset_mock() - self.m_client.get_filtered.reset_mock() - m_open = mock.mock_open(read_data=GRAPH_YAML) - with mock.patch( - 'fuelclient.cli.serializers.open', m_open, create=True): - self.exec_command( - 'graph upload --env 1 --file new_graph.yaml -t custom' - ) - self.m_get_client.assert_called_once_with('graph', mock.ANY) - self.m_client.upload.assert_called_once_with( - data=yaml.load(GRAPH_YAML), - related_model='clusters', - related_id=1, - graph_type='custom' - ) - - @mock.patch('fuelclient.commands.graph.os') - @mock.patch('fuelclient.commands.graph.iterfiles') - @mock.patch('fuelclient.commands.graph.Serializer') - def test_graph_upload_from_dir(self, serializers_m, iterfiles_m, os_m): - tasks = yaml.load(TASKS_YAML) - graph_data = yaml.load(GRAPH_METADATA_YAML) - os_m.path.exists.return_value = True - os_m.path.isdir.return_value = True - serializers_m().read_from_full_path.side_effect = [graph_data, tasks] - iterfiles_m.return_value = ['tasks.yaml'] - - self.m_get_client.reset_mock() - self.m_client.get_filtered.reset_mock() - m_open = mock.mock_open(read_data=GRAPH_YAML) - with mock.patch( - 'fuelclient.cli.serializers.open', m_open, create=True): - self.exec_command( - 'graph upload --release 1 --dir /graph/provision -t provision' - ) - self.m_get_client.assert_called_once_with('graph', mock.ANY) - self.m_client.upload.assert_called_once_with( - data=dict(graph_data, tasks=tasks), - related_model='releases', - related_id=1, - graph_type='provision' - ) - - @mock.patch('fuelclient.commands.graph.os') - @mock.patch('fuelclient.commands.graph.iterfiles') - def test_graph_upload_from_dir_fail(self, iterfiles_m, os_m): - os_m.path.isdir.return_value = True - os_m.path.exists.side_effect = [True, False] - iterfiles_m.return_value = [] - args = 'graph upload --release 1 --dir /graph/provision -t provision' - - self.assertRaisesRegexp(error.ActionException, - "Nothing to upload", - self.exec_command, args) - - @mock.patch('sys.stderr') - def test_upload_fail(self, mocked_stderr): - cmd = 'graph upload --file new_graph.yaml -t test' - self.assertRaises(SystemExit, self.exec_command, cmd) - self.assertIn('-e/--env -r/--release -p/--plugin', - mocked_stderr.write.call_args_list[-1][0][0]) - - def test_execute(self): - self._test_cmd( - 'execute', - '--env 1 --graph-types graph1 graph2 --nodes 1 2 3', - dict( - env_id=1, - graph_types=['graph1', 'graph2'], - nodes=[1, 2, 3], - task_names=None, - dry_run=False, - noop_run=False, - force=False, - debug=False, - subgraphs=None - ) - ) - - def test_execute_w_dry_run(self): - self._test_cmd( - 'execute', - '--env 1 --graph-types graph1 graph2 --nodes 1 2 3 --dry-run', - dict( - env_id=1, - graph_types=['graph1', 'graph2'], - nodes=[1, 2, 3], - task_names=None, - dry_run=True, - noop_run=False, - force=False, - debug=False, - subgraphs=None - ) - ) - - def test_execute_w_force(self): - self._test_cmd( - 'execute', - '--env 1 --graph-types graph1 --force', - dict( - env_id=1, - graph_types=['graph1'], - nodes=None, - task_names=None, - dry_run=False, - noop_run=False, - force=True, - debug=False, - subgraphs=None - ) - ) - - def test_execute_w_task_names(self): - self._test_cmd( - 'execute', - '--env 1 --graph-types graph1 --task-names task1 task2', - dict( - env_id=1, - graph_types=['graph1'], - nodes=None, - task_names=['task1', 'task2'], - dry_run=False, - noop_run=False, - force=False, - debug=False, - subgraphs=None - ) - ) - - def test_execute_w_noop_run(self): - self._test_cmd( - 'execute', - '--env 1 --graph-types graph1 graph2 --nodes 1 2 3 --noop', - dict( - env_id=1, - graph_types=['graph1', 'graph2'], - nodes=[1, 2, 3], - task_names=None, - dry_run=False, - noop_run=True, - force=False, - debug=False, - subgraphs=None - ) - ) - - def test_execute_w_trace(self): - self._test_cmd( - 'execute', - '--env 1 --graph-types graph1 --trace', - dict( - env_id=1, - graph_types=['graph1'], - nodes=None, - task_names=None, - dry_run=False, - noop_run=False, - force=False, - debug=True, - subgraphs=None - ) - ) - - def test_execute_w_dry_run_subgraph(self): - self._test_cmd( - 'execute', - '--env 1 --graph-types custom_graph --nodes 1 2 3 ' - '--dry-run --subgraphs primary-database/1,3:keystone-db/1-2,5' - ' openstack-controller', - dict( - env_id=1, - force=False, - graph_types=['custom_graph'], - nodes=[1, 2, 3], - noop_run=False, - dry_run=True, - subgraphs=['primary-database/1,3:keystone-db/1-2,5', - 'openstack-controller'], - task_names=None, - debug=False - ) - ) - - def test_execute_with_json_output(self): - self.m_client.execute.return_value = mock.MagicMock( - data={'id': 1} - ) - with mock.patch('sys.stdout') as stdout_mock: - self.exec_command( - 'graph execute --env 1 --graph-types graph1 --format=json' - ) - stdout_mock.write.assert_called_with('{\n "id": 1\n}\n') - - def test_download(self): - self.m_client.download.return_value = yaml.safe_load(TASKS_YAML) - - self._test_cmd( - 'download', - '--env 1 --all --file existing_graph.yaml -t custom_graph', - dict( - env_id=1, - level='all', - graph_type='custom_graph' - ) - ) - - @mock.patch('json.dumps') - def test_download_json(self, m_dumps): - env_id = 1 - graph_data = [{'id': 1}] - args = 'graph download --env {0} --all --format json'.format(env_id) - expected_path = '/tmp/all_graph_{0}.json'.format(env_id) - - self.m_client.download.return_value = graph_data - - m_open = mock.mock_open() - with mock.patch('os.path.abspath', return_value='/tmp'): - with mock.patch( - 'fuelclient.cli.serializers.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_dumps.assert_called_once_with(graph_data, indent=4) - self.m_get_client.assert_called_once_with('graph', mock.ANY) - - @mock.patch('sys.stderr') - def test_download_fail(self, mocked_stderr): - cmd = 'graph download --env 1' - self.assertRaises(SystemExit, self.exec_command, cmd) - self.assertIn('-a/--all -c/--cluster -p/--plugins -r/--release', - mocked_stderr.write.call_args_list[-1][0][0]) - - def test_list(self): - with mock.patch('sys.stdout', new=six.moves.cStringIO()) as m_stdout: - self.m_get_client.reset_mock() - self.m_client.get_filtered.reset_mock() - self.m_client.list.return_value = [ - { - 'name': 'updated-graph-name', - 'tasks': [{ - 'id': 'test-task2', - 'type': 'puppet', - 'task_name': 'test-task2', - 'version': '2.0.0' - }], - 'relations': [{ - 'model': 'cluster', - 'model_id': 370, - 'type': 'custom-graph' - }], - 'id': 1 - } - ] - self.exec_command( - 'graph list --env 1 --release --plugins --cluster') - self.m_get_client.assert_called_once_with('graph', mock.ANY) - - self.assertIn('1', m_stdout.getvalue()) - self.assertIn('updated-graph-name', m_stdout.getvalue()) - self.assertIn('custom-graph', m_stdout.getvalue()) - self.assertIn('test-task2', m_stdout.getvalue()) - - self.exec_command('graph list --release') - self.exec_command('graph list --plugins') - self.exec_command('graph list --cluster') - self.exec_command('graph list') - - self.m_client.list.assert_has_calls([ - mock.call(env_id=1, filters=['release', 'plugin', 'cluster']), - mock.call(env_id=None, filters=['release']), - mock.call(env_id=None, filters=['plugin']), - mock.call(env_id=None, filters=['cluster']), - mock.call(env_id=None, filters=None) - ]) - - def test_delete(self): - self._test_cmd( - 'delete', - '--env 1 --graph-type custom_graph', - dict( - graph_type='custom_graph', - related_id=1, - related_model='clusters' - ) - ) diff --git a/fuelclient/tests/unit/v2/cli/test_engine.py b/fuelclient/tests/unit/v2/cli/test_engine.py deleted file mode 100644 index 5b3b0a9..0000000 --- a/fuelclient/tests/unit/v2/cli/test_engine.py +++ /dev/null @@ -1,171 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 shlex -import sys - -import mock -from oslotest import base as oslo_base - -import fuelclient -from fuelclient.commands import environment as env -from fuelclient.commands import node as node -from fuelclient import main as main_mod -from fuelclient.tests import utils - - -class BaseCLITest(oslo_base.BaseTestCase): - """Base class for testing the new CLI - - It mocks the whole API layer in order to be sure the - tests test only the stuff which is responsible for - the command line application. That allows to find bugs - more precisely and not confuse them with the bugs in the - API wrapper. - - """ - def setUp(self): - super(BaseCLITest, self).setUp() - - self._get_client_patcher = mock.patch.object(fuelclient, 'get_client') - self.m_get_client = self._get_client_patcher.start() - - self.m_client = mock.MagicMock() - self.m_get_client.return_value = self.m_client - self.addCleanup(self._get_client_patcher.stop) - - def exec_command(self, command=''): - """Executes fuelclient with the specified arguments.""" - argv = shlex.split(command) - if '--debug' not in argv: - argv = ['--debug'] + argv - - return main_mod.main(argv=argv) - - def exec_command_interactive(self, commands): - """Executes specified commands in one sesstion of interactive mode - - Starts Fuel Client's interactive console and passes - supplied commands there. - - :param commands: The list of commands to execute in the - Fuel Client's console. - :type commands: list of str - - """ - with mock.patch.object(sys, 'stdin') as m_stdin: - m_stdin.readline.side_effect = commands - self.exec_command() - - @mock.patch('cliff.app.App.run_subcommand') - def test_command_non_interactive(self, m_run_command): - args = ['help'] - self.exec_command(*args) - m_run_command.assert_called_once_with(args) - - @mock.patch('cliff.commandmanager.CommandManager.find_command') - def test_command_interactive(self, m_find_command): - commands = ['quit'] - - self.exec_command_interactive(commands) - m_find_command.assert_called_once_with(commands) - - @mock.patch('cliff.formatters.table.TableFormatter.emit_list') - def test_lister_sorting(self, m_emit_list): - cmd = 'env list -s status release_id' - - raw_data = [{'id': 43, - 'status': 'STATUS 2', - 'name': 'Test env 2', - 'release_id': 2}, - - {'id': 42, - 'status': 'STATUS 1', - 'name': 'Test env 1', - 'release_id': 2}, - - {'id': 44, - 'status': 'STATUS 2', - 'name': 'Test env 3', - 'release_id': 1}] - - expected_order = [1, 2, 0] - expected_data = [[raw_data[i][prop] for prop in env.EnvList.columns] - for i in expected_order] - - self.m_client.get_all.return_value = raw_data - - self.exec_command(cmd) - m_emit_list.assert_called_once_with(mock.ANY, - expected_data, - mock.ANY, - mock.ANY) - - @mock.patch('fuelclient.fuelclient_settings.' - 'FuelClientSettings.update_from_command_line_options') - def test_settings_override_called(self, m_update): - cmd = ('--os-password tpass --os-username tname --os-tenant-name tten ' - 'node list') - self.m_client.get_all.return_value = [utils.get_fake_node() - for _ in range(10)] - - self.exec_command(cmd) - - m_update.assert_called_once_with(mock.ANY) - passed_settings = m_update.call_args[0][0] - - self.assertEqual('tname', passed_settings.os_username) - self.assertEqual('tpass', passed_settings.os_password) - self.assertEqual('tten', passed_settings.os_tenant_name) - - def test_get_attribute_path(self): - cmd = node.NodeShow(None, None) - - attr_types = ('attributes', 'interfaces', 'disks') - file_format = 'json' - node_id = 42 - directory = '/test' - - for attr_type in attr_types: - expected_path = '/test/node_42/{t}.json'.format(t=attr_type) - real_path = cmd.get_attributes_path(attr_type, file_format, - node_id, directory) - - self.assertEqual(expected_path, real_path) - - def test_get_attribute_path_wrong_attr_type(self): - cmd = node.NodeShow(None, None) - - attr_type = 'wrong' - file_format = 'json' - node_id = 42 - directory = '/test' - - self.assertRaises(ValueError, - cmd.get_attributes_path, - attr_type, file_format, node_id, directory) - - def test_get_attribute_path_wrong_file_format(self): - cmd = node.NodeShow(None, None) - - attr_type = 'interfaces' - file_format = 'wrong' - node_id = 42 - directory = '/test' - - self.assertRaises(ValueError, - cmd.get_attributes_path, - attr_type, file_format, node_id, directory) diff --git a/fuelclient/tests/unit/v2/cli/test_env.py b/fuelclient/tests/unit/v2/cli/test_env.py deleted file mode 100644 index 87142f9..0000000 --- a/fuelclient/tests/unit/v2/cli/test_env.py +++ /dev/null @@ -1,714 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 json -import mock -import yaml - -from six import moves - -from fuelclient.tests.unit.v2.cli import test_engine -from fuelclient.tests.utils import fake_env -from fuelclient.tests.utils import fake_task -from fuelclient.v1 import environment - - -class TestEnvCommand(test_engine.BaseCLITest): - """Tests for fuel2 env * commands.""" - - def setUp(self): - super(TestEnvCommand, self).setUp() - - self.m_client.get_all.return_value = [fake_env.get_fake_env() - for i in range(10)] - self.m_client.get_by_id.return_value = fake_env.get_fake_env() - self.m_client.create.return_value = fake_env.get_fake_env() - self.m_client.update.return_value = fake_env.get_fake_env() - - def test_env_list(self): - args = 'env list' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.get_all.assert_called_once_with() - - def test_env_list_sorted(self): - args = 'env list -s name' - self.exec_command(args) - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.get_all.assert_called_once_with() - - def test_env_show(self): - args = 'env show 42' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.get_by_id.assert_called_once_with(42) - - def test_env_create(self): - args = 'env create -r 1 -nst gre env42' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - - m_client = self.m_client - m_client.create.assert_called_once_with(name='env42', - release_id=1, - net_segment_type='gre') - - def test_neutron_gre_deprecation_warning(self): - args = 'env create -r 1 -nst gre env42' - - with mock.patch('sys.stderr', new=moves.cStringIO()) as m_stderr: - self.exec_command(args) - self.assertIn( - "WARNING: GRE network segmentation type is deprecated " - "since 7.0 release", - m_stderr.getvalue() - ) - - def test_env_delete(self): - args = 'env delete --force 42' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.delete_by_id.assert_called_once_with(42) - - def test_env_delete_wo_force(self): - args = 'env delete 42' - - env = fake_env.get_fake_env(status='operational') - self.m_client.get_by_id.return_value = env - - with mock.patch('sys.stdout', new=moves.cStringIO()) as m_stdout: - self.exec_command(args) - self.assertIn('--force', m_stdout.getvalue()) - - def test_env_deploy(self): - dry_run = False - noop_run = False - args = 'env deploy' - - args += ' 42' - - self.exec_command(args) - - calls = list() - calls.append(mock.call.deploy_changes(42, - noop_run=noop_run, - dry_run=dry_run)) - - self.m_get_client.assert_called_with('environment', mock.ANY) - self.m_client.assert_has_calls(calls) - - def test_env_deploy_dry_run(self): - dry_run = True - noop_run = False - - args = 'env deploy -d' - args += ' 42' - - self.exec_command(args) - - calls = list() - calls.append(mock.call.deploy_changes(42, - noop_run=noop_run, - dry_run=dry_run)) - - self.m_get_client.assert_called_with('environment', mock.ANY) - self.m_client.assert_has_calls(calls) - - def test_env_deploy_noop_run(self): - dry_run = False - noop_run = True - - args = 'env deploy --noop' - args += ' 42' - - self.exec_command(args) - - calls = list() - calls.append(mock.call.deploy_changes(42, - noop_run=noop_run, - dry_run=dry_run)) - - self.m_get_client.assert_called_with('environment', mock.ANY) - self.m_client.assert_has_calls(calls) - - def test_env_redeploy(self): - dry_run = False - noop_run = False - args = 'env redeploy' - - args += ' 42' - - self.exec_command(args) - - calls = list() - calls.append(mock.call.redeploy_changes(42, - noop_run=noop_run, - dry_run=dry_run)) - - self.m_get_client.assert_called_with('environment', mock.ANY) - self.m_client.assert_has_calls(calls) - - def test_env_redeploy_dry_run(self): - dry_run = True - noop_run = False - args = 'env redeploy -d' - - args += ' 42' - - self.exec_command(args) - - calls = list() - calls.append(mock.call.redeploy_changes(42, - noop_run=noop_run, - dry_run=dry_run)) - - self.m_get_client.assert_called_with('environment', mock.ANY) - self.m_client.assert_has_calls(calls) - - def test_env_redeploy_noop_run(self): - dry_run = False - noop_run = True - args = 'env redeploy --noop' - - args += ' 42' - - self.exec_command(args) - - calls = list() - calls.append(mock.call.redeploy_changes(42, - noop_run=noop_run, - dry_run=dry_run)) - - self.m_get_client.assert_called_with('environment', mock.ANY) - self.m_client.assert_has_calls(calls) - - def test_env_reset(self): - env_id = 45 - args = 'env reset {env_id}'.format(env_id=env_id) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.reset.assert_called_once_with(env_id, force=False) - - def test_env_reset_force(self): - env_id = 45 - args = 'env reset {env_id} --force'.format(env_id=env_id) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.reset.assert_called_once_with(env_id, force=True) - - def test_env_add_nodes(self): - args = 'env add nodes -e 42 -n 24 25 -r compute cinder' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.add_nodes.assert_called_once_with(environment_id=42, - nodes=[24, 25], - roles=['compute', - 'cinder']) - - def test_env_remove_nodes_by_id(self): - args = 'env remove nodes -e 42 -n 24 25' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.remove_nodes.assert_called_once_with(environment_id=42, - nodes=[24, 25]) - - def test_env_remove_nodes_all(self): - args = 'env remove nodes -e 42 --nodes-all' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.remove_nodes.assert_called_once_with(environment_id=42, - nodes=None) - - def test_env_update(self): - self.m_client._updatable_attributes = \ - environment.EnvironmentClient._updatable_attributes - - args = 'env update -n test_name 42' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.update.assert_called_once_with(environment_id=42, - name='test_name') - - def test_env_spawn_vms(self): - env_id = 10 - args = 'env spawn-vms {0}'.format(env_id) - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.spawn_vms.assert_called_once_with(env_id) - - def test_env_nodes_deploy(self): - env_id = 42 - node_ids = [43, 44] - noop_run = False - args = ('env nodes deploy ' - '--nodes {n[0]} {n[1]} --env {e}').format(e=env_id, n=node_ids) - - self.exec_command(args) - - self.m_client.deploy_nodes.return_value = fake_task.get_fake_task() - self.m_client.deploy_nodes.assert_called_once_with(env_id, node_ids, - force=False, - noop_run=noop_run) - - def test_env_nodes_deploy_force(self): - env_id = 42 - node_ids = [43, 44] - force = True - noop_run = False - args = ('env nodes deploy --force ' - '--nodes {n[0]} {n[1]} --env {e}').format(e=env_id, n=node_ids) - - self.exec_command(args) - - self.m_client.deploy_nodes.return_value = fake_task.get_fake_task() - self.m_client.deploy_nodes.assert_called_once_with(env_id, node_ids, - noop_run=noop_run, - force=force) - - def test_env_nodes_deploy_noop_run(self): - env_id = 42 - node_ids = [43, 44] - force = False - noop_run = True - args = ('env nodes deploy --noop ' - '--nodes {n[0]} {n[1]} --env {e}').format(e=env_id, n=node_ids) - - self.exec_command(args) - - self.m_client.deploy_nodes.return_value = fake_task.get_fake_task() - self.m_client.deploy_nodes.assert_called_once_with(env_id, node_ids, - force=force, - noop_run=noop_run) - - def test_env_nodes_provision(self): - env_id = 42 - node_ids = [43, 44] - args = ('env nodes provision ' - '--nodes {n[0]} {n[1]} --env {e}').format(e=env_id, n=node_ids) - - self.m_client.provision_nodes.return_value = fake_task.get_fake_task() - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.provision_nodes.assert_called_once_with(env_id, node_ids) - - def test_env_stop(self): - env_id = 45 - args = 'env stop-deployment {env_id}'.format(env_id=env_id) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.stop.assert_called_once_with(env_id) - - def test_env_network_verify(self): - env_id = 42 - args = 'env network verify {}'.format(env_id) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.verify_network.assert_called_once_with(env_id) - - @mock.patch('json.dump') - def test_env_network_download_json(self, m_dump): - args = 'env network download --format json -d /tmp 42' - test_data = {'foo': 'bar'} - expected_path = '/tmp/environment_42/network.json' - - self.m_client.get_network_configuration.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.environment.open', - m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_dump.assert_called_once_with(test_data, mock.ANY, indent=4) - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.get_network_configuration.assert_called_once_with(42) - - def test_env_network_upload_json(self): - args = 'env network upload --format json -d /tmp 42' - config = {'foo': 'bar'} - expected_path = '/tmp/environment_42/network.json' - - m_open = mock.mock_open(read_data=json.dumps(config)) - with mock.patch('fuelclient.commands.environment.open', - m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.set_network_configuration.assert_called_once_with(42, - config) - - @mock.patch('yaml.safe_dump') - def test_env_network_download_yaml(self, m_safe_dump): - args = 'env network download --format yaml -d /tmp 42' - test_data = {'foo': 'bar'} - expected_path = '/tmp/environment_42/network.yaml' - - self.m_client.get_network_configuration.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.environment.open', - m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_safe_dump.assert_called_once_with(test_data, mock.ANY, - default_flow_style=False) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.get_network_configuration.assert_called_once_with(42) - - def test_env_network_upload_yaml(self): - args = 'env network upload --format yaml -d /tmp 42' - config = {'foo': 'bar'} - expected_path = '/tmp/environment_42/network.yaml' - - m_open = mock.mock_open(read_data=yaml.dump(config)) - with mock.patch('fuelclient.commands.environment.open', - m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.set_network_configuration.assert_called_once_with(42, - config) - - @mock.patch('json.dump') - def test_env_settings_download_json(self, m_dump): - args = 'env settings download --format json -d /tmp 42' - test_data = {'foo': 'bar'} - expected_path = '/tmp/environment_42/settings.json' - - self.m_client.get_settings.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.environment.open', - m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_dump.assert_called_once_with(test_data, mock.ANY, indent=4) - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.get_settings.assert_called_once_with(42) - - def test_env_settings_upload_json(self): - args = 'env settings upload --format json -d /tmp 42' - config = {'foo': 'bar'} - expected_path = '/tmp/environment_42/settings.json' - - m_open = mock.mock_open(read_data=json.dumps(config)) - with mock.patch('fuelclient.commands.environment.open', - m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.set_settings.assert_called_once_with(42, - config, - force=False) - - @mock.patch('yaml.safe_dump') - def test_env_settings_download_yaml(self, m_safe_dump): - args = 'env settings download --format yaml -d /tmp 42' - test_data = {'foo': 'bar'} - expected_path = '/tmp/environment_42/settings.yaml' - - self.m_client.get_settings.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.environment.open', - m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_safe_dump.assert_called_once_with(test_data, mock.ANY, - default_flow_style=False) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.get_settings.assert_called_once_with(42) - - def test_env_settings_upload_yaml(self): - args = 'env settings upload --format yaml -d /tmp 42' - config = {'foo': 'bar'} - expected_path = '/tmp/environment_42/settings.yaml' - - m_open = mock.mock_open(read_data=yaml.dump(config)) - with mock.patch('fuelclient.commands.environment.open', - m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.set_settings.assert_called_once_with(42, - config, - force=False) - - def test_env_settings_upload_force(self): - args = 'env settings upload --format yaml -d /tmp --force 42' - config = {'foo': 'bar'} - expected_path = '/tmp/environment_42/settings.yaml' - - m_open = mock.mock_open(read_data=yaml.dump(config)) - with mock.patch('fuelclient.commands.environment.open', - m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.set_settings.assert_called_once_with(42, - config, - force=True) - - def test_env_deployment_facts_delete(self): - args = "env deployment-facts delete 42" - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.delete_facts.assert_called_once_with(42, 'deployment') - - def test_env_provisioning_facts_delete(self): - args = "env provisioning-facts delete 42" - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.delete_facts.assert_called_once_with(42, 'provisioning') - - @mock.patch('json.dump') - def _deployment_facts_download_json(self, m_dump, default=False): - command = 'get-default' if default else 'download' - args = ( - "env deployment-facts {}" - " --env 42 --dir /tmp --nodes 2 --format json --no-split" - .format(command) - ) - data = [{'uid': 2, 'name': 'node'}] - expected_path = '/tmp/deployment_42/2.json' - - self.m_client.download_facts.return_value = data - - m_open = mock.mock_open() - with mock.patch('fuelclient.common.data_utils.open', - m_open, create=True): - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.download_facts.assert_called_once_with( - 42, 'deployment', nodes=[2], default=default, split=False) - m_open.assert_called_once_with(expected_path, 'w') - m_dump.assert_called_once_with(data[0], mock.ANY, indent=4) - - def test_env_deployment_facts_download_json(self): - self._deployment_facts_download_json(default=False) - - def test_env_deployment_facts_get_default_json(self): - self._deployment_facts_download_json(default=True) - - @mock.patch('yaml.safe_dump') - def _deployment_facts_download_yaml(self, m_safe_dump, default=False): - command = 'get-default' if default else 'download' - args = ( - "env deployment-facts {}" - " --env 42 --dir /tmp --nodes 2 --format yaml" - .format(command) - ) - data = [{'uid': 2, 'name': 'node'}] - expected_path = '/tmp/deployment_42/2.yaml' - - self.m_client.download_facts.return_value = data - - m_open = mock.mock_open() - with mock.patch('fuelclient.common.data_utils.open', - m_open, create=True): - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.download_facts.assert_called_once_with( - 42, 'deployment', nodes=[2], default=default, split=True) - m_open.assert_called_once_with(expected_path, 'w') - m_safe_dump.assert_called_once_with(data[0], mock.ANY, - default_flow_style=False) - - def test_env_deployment_facts_download_yaml(self): - self._deployment_facts_download_yaml(default=False) - - def test_env_deployment_facts_get_default_yaml(self): - self._deployment_facts_download_yaml(default=True) - - def test_env_deployment_facts_upload_json(self): - args = 'env deployment-facts upload --env 42 --dir /tmp --format json' - data = [{'uid': 2, 'name': 'node'}] - expected_path = '/tmp/deployment_42/2.json' - - m_open = mock.mock_open(read_data=json.dumps(data[0])) - with mock.patch('os.listdir', return_value=['2.json']): - with mock.patch('fuelclient.common.data_utils.open', - m_open, create=True): - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - m_open.assert_called_once_with(expected_path, 'r') - self.m_client.upload_facts.assert_called_once_with( - 42, 'deployment', data) - - def test_env_deployment_facts_upload_yaml(self): - args = 'env deployment-facts upload --env 42 --dir /tmp --format yaml' - data = [{'uid': 2, 'name': 'node'}] - expected_path = '/tmp/deployment_42/2.yaml' - - m_open = mock.mock_open(read_data=yaml.dump(data[0])) - with mock.patch('os.listdir', return_value=['2.yaml']): - with mock.patch('fuelclient.common.data_utils.open', - m_open, create=True): - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - m_open.assert_called_once_with(expected_path, 'r') - self.m_client.upload_facts.assert_called_once_with( - 42, 'deployment', data) - - @mock.patch('json.dump') - def _provisioning_facts_download_json(self, m_dump, default=False): - command = 'get-default' if default else 'download' - args = "env provisioning-facts {}" \ - " --env 42 --dir /tmp --nodes 2 --format json".format(command) - data = { - 'engine': {'foo': 'bar'}, - 'nodes': [{'uid': 2, 'name': 'node-2'}] - } - expected_path_engine = '/tmp/provisioning_42/engine.json' - expected_path_node = '/tmp/provisioning_42/2.json' - - self.m_client.download_facts.return_value = data - - m_open = mock.mock_open() - with mock.patch('fuelclient.common.data_utils.open', - m_open, create=True): - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.download_facts.assert_called_once_with( - 42, 'provisioning', nodes=[2], default=default, split=True) - m_open.assert_any_call(expected_path_engine, 'w') - m_dump.assert_any_call(data['engine'], mock.ANY, indent=4) - m_open.assert_any_call(expected_path_node, 'w') - m_dump.assert_any_call(data['nodes'][0], mock.ANY, indent=4) - - def test_env_provisioning_facts_download_json(self): - self._provisioning_facts_download_json(default=False) - - def test_env_provisioning_facts_get_default_json(self): - self._provisioning_facts_download_json(default=True) - - @mock.patch('yaml.safe_dump') - def _provisioning_facts_download_yaml(self, m_dump, default=False): - command = 'get-default' if default else 'download' - args = "env provisioning-facts {}" \ - " --env 42 --dir /tmp --nodes 2 --format yaml".format(command) - data = { - 'engine': {'foo': 'bar'}, - 'nodes': [{'uid': 2, 'name': 'node-2'}] - } - expected_path_engine = '/tmp/provisioning_42/engine.yaml' - expected_path_node = '/tmp/provisioning_42/2.yaml' - - self.m_client.download_facts.return_value = data - - m_open = mock.mock_open() - with mock.patch('fuelclient.common.data_utils.open', - m_open, create=True): - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.download_facts.assert_called_once_with( - 42, 'provisioning', nodes=[2], default=default, split=True) - m_open.assert_any_call(expected_path_engine, 'w') - m_dump.assert_any_call(data['engine'], mock.ANY, - default_flow_style=False) - m_open.assert_any_call(expected_path_node, 'w') - m_dump.assert_any_call(data['nodes'][0], mock.ANY, - default_flow_style=False) - - def test_env_provisioning_facts_download_yaml(self): - self._provisioning_facts_download_yaml(default=False) - - def test_env_provisioning_facts_get_default_yaml(self): - self._provisioning_facts_download_yaml(default=True) - - def test_env_provisioning_facts_upload_json(self): - args = 'env provisioning-facts upload' \ - ' --env 42 --dir /tmp --format json' - expected_data = { - 'engine': {'foo': 'bar'}, - 'nodes': [{'foo': 'bar'}] - } - expected_path_engine = '/tmp/provisioning_42/engine.json' - expected_path_node = '/tmp/provisioning_42/2.json' - - m_open = mock.mock_open(read_data=json.dumps({'foo': 'bar'})) - with mock.patch('os.listdir', return_value=['engine.json', '2.json']): - with mock.patch('fuelclient.common.data_utils.open', - m_open, create=True): - with mock.patch('os.path.lexists', return_value=True): - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - m_open.assert_any_call(expected_path_engine, 'r') - m_open.assert_any_call(expected_path_node, 'r') - self.m_client.upload_facts.assert_called_once_with( - 42, 'provisioning', expected_data) - - def test_env_provisioning_facts_upload_yaml(self): - args = 'env provisioning-facts upload' \ - ' --env 42 --dir /tmp --format yaml' - expected_data = { - 'engine': {'foo': 'bar'}, - 'nodes': [{'foo': 'bar'}] - } - expected_path_engine = '/tmp/provisioning_42/engine.yaml' - expected_path_node = '/tmp/provisioning_42/2.yaml' - - m_open = mock.mock_open(read_data=json.dumps({'foo': 'bar'})) - with mock.patch('os.listdir', return_value=['engine.yaml', '2.yaml']): - with mock.patch('fuelclient.common.data_utils.open', - m_open, create=True): - with mock.patch('os.path.lexists', return_value=True): - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - m_open.assert_any_call(expected_path_engine, 'r') - m_open.assert_any_call(expected_path_node, 'r') - self.m_client.upload_facts.assert_called_once_with( - 42, 'provisioning', expected_data) diff --git a/fuelclient/tests/unit/v2/cli/test_extension.py b/fuelclient/tests/unit/v2/cli/test_extension.py deleted file mode 100644 index 891b4d8..0000000 --- a/fuelclient/tests/unit/v2/cli/test_extension.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 mock - -from fuelclient.tests.unit.v2.cli import test_engine -from fuelclient.tests import utils - - -class TestExtensionCommand(test_engine.BaseCLITest): - """Tests for fuel2 extension * commands.""" - - def test_extensions_list(self): - self.m_client.get_all.return_value = utils.get_fake_extensions(2) - args = 'extension list' - self.exec_command(args) - self.m_client.get_all.assert_called_once_with() - self.m_get_client.assert_called_once_with('extension', mock.ANY) - - def test_env_extensions_show(self): - self.m_client.get_extensions.return_value = \ - utils.get_fake_env_extensions() - env_id = 45 - args = 'env extension show {id}'.format(id=env_id) - self.exec_command(args) - self.m_client.get_by_id.assert_called_once_with(env_id) - self.m_get_client.assert_called_once_with('extension', mock.ANY) - - @mock.patch('sys.stderr') - def test_env_extension_show_fail(self, mocked_stderr): - args = 'env extension show' - self.assertRaises(SystemExit, self.exec_command, args) - self.assertIn('id', - mocked_stderr.write.call_args_list[0][0][0]) - - @mock.patch('sys.stderr') - def test_env_extension_enable_fail(self, mocked_stderr): - args = 'env extension enable 1' - self.assertRaises(SystemExit, self.exec_command, args) - self.assertIn('-E/--extensions', - mocked_stderr.write.call_args_list[-1][0][0]) - - @mock.patch('sys.stderr') - def test_env_extension_disable_fail(self, mocked_stderr): - args = 'env extension disable 1' - self.assertRaises(SystemExit, self.exec_command, args) - self.assertIn('-E/--extensions', - mocked_stderr.write.call_args_list[-1][0][0]) - - def test_env_extensions_enable(self): - exts = utils.get_fake_env_extensions() - env_id = 45 - args = 'env extension enable {id} --extensions {exts}'.format( - id=env_id, exts=' '.join(exts)) - self.exec_command(args) - self.m_client.enable_extensions.assert_called_once_with(env_id, exts) - self.m_get_client.assert_called_once_with('extension', mock.ANY) - - def test_env_extensions_disable(self): - exts = utils.get_fake_env_extensions() - env_id = 45 - args = 'env extension disable {id} --extensions {exts}'.format( - id=env_id, exts=' '.join(exts)) - self.exec_command(args) - self.m_client.disable_extensions.assert_called_once_with(env_id, exts) - self.m_get_client.assert_called_once_with('extension', mock.ANY) diff --git a/fuelclient/tests/unit/v2/cli/test_fuel_version.py b/fuelclient/tests/unit/v2/cli/test_fuel_version.py deleted file mode 100644 index eb110e8..0000000 --- a/fuelclient/tests/unit/v2/cli/test_fuel_version.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 json -import mock -from six import moves -import yaml - -from fuelclient.tests.unit.v2.cli import test_engine -from fuelclient.tests.utils import fake_fuel_version - - -class TestFuelVersionCommand(test_engine.BaseCLITest): - """Tests for fuel2 version * commands.""" - - def setUp(self): - super(TestFuelVersionCommand, self).setUp() - self.m_client.get_all.return_value = \ - fake_fuel_version.get_fake_fuel_version() - - def test_fuel_version_yaml(self): - args = 'fuel-version -f yaml' - - with mock.patch('sys.stdout', new=moves.cStringIO()) as m_stdout: - self.exec_command(args) - self.assertEqual(fake_fuel_version.get_fake_fuel_version(), - yaml.safe_load(m_stdout.getvalue())) - - def test_fuel_version_json(self): - args = 'fuel-version -f json' - - with mock.patch('sys.stdout', new=moves.cStringIO()) as m_stdout: - self.exec_command(args) - self.assertEqual(fake_fuel_version.get_fake_fuel_version(), - json.loads(m_stdout.getvalue())) diff --git a/fuelclient/tests/unit/v2/cli/test_health.py b/fuelclient/tests/unit/v2/cli/test_health.py deleted file mode 100644 index 346b96c..0000000 --- a/fuelclient/tests/unit/v2/cli/test_health.py +++ /dev/null @@ -1,169 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Vitalii Kulanov -# -# Licensed 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 mock - -from fuelclient.tests.unit.v2.cli import test_engine -from fuelclient.tests.utils import fake_health - - -class TestHealthCommand(test_engine.BaseCLITest): - """Tests for fuel2 health * commands.""" - - def test_health_list_for_cluster(self): - self.m_client.get_all.return_value = fake_health.get_fake_test_sets(10) - cluster_id = 45 - args = 'health list -e {id}'.format(id=cluster_id) - self.exec_command(args) - self.m_client.get_all.assert_called_once_with( - environment_id=cluster_id) - self.m_get_client.assert_called_once_with('health', mock.ANY) - - @mock.patch('sys.stderr') - def test_health_list_for_cluster_fail(self, mocked_stderr): - args = 'health list' - self.assertRaises(SystemExit, self.exec_command, args) - self.assertIn('-e/--env', - mocked_stderr.write.call_args_list[-1][0][0]) - - def test_health_status_list(self): - self.m_client.get_status_all.return_value = [ - fake_health.get_fake_test_set_item(testset_id=12, cluster_id=30), - fake_health.get_fake_test_set_item(testset_id=13, cluster_id=32), - fake_health.get_fake_test_set_item(testset_id=14, cluster_id=35) - ] - args = 'health status list' - self.exec_command(args) - self.m_client.get_status_all.assert_called_once_with(None) - self.m_get_client.assert_called_once_with('health', mock.ANY) - - def test_health_status_list_for_cluster(self): - cluster_id = 45 - self.m_client.get_status_all.return_value = [ - fake_health.get_fake_test_set_item(testset_id=12, - cluster_id=cluster_id), - fake_health.get_fake_test_set_item(testset_id=13, - cluster_id=cluster_id), - fake_health.get_fake_test_set_item(testset_id=14, - cluster_id=cluster_id) - ] - args = 'health status list -e {id}'.format(id=cluster_id) - self.exec_command(args) - self.m_client.get_status_all.assert_called_once_with(cluster_id) - self.m_get_client.assert_called_once_with('health', mock.ANY) - - def test_health_status_show(self): - testset_id = 66 - self.m_client.get_status_single.return_value = \ - fake_health.get_fake_test_set_item(testset_id=testset_id) - args = 'health status show {id}'.format(id=testset_id) - self.exec_command(args) - self.m_client.get_status_single.assert_called_once_with(testset_id) - self.m_get_client.assert_called_once_with('health', mock.ANY) - - @mock.patch('sys.stderr') - def test_health_status_show_fail(self, mocked_stderr): - args = 'health status show' - self.assertRaises(SystemExit, self.exec_command, args) - self.assertIn('id', mocked_stderr.write.call_args_list[0][0][0]) - - def test_health_start_force(self): - cluster_id = 45 - testset = ['fake_test_set1', 'fake_test_set2'] - args = 'health start -e {id} -t {testset} --force'.format( - id=cluster_id, testset=' '.join(testset)) - self.exec_command(args) - self.m_client.start.assert_called_once_with(cluster_id, - ostf_credentials={}, - test_sets=testset, - force=True) - self.m_get_client.assert_called_once_with('health', mock.ANY) - - @mock.patch('sys.stderr') - def test_health_start_w_wrong_parameters(self, mocked_stderr): - args = 'health start' - self.assertRaises(SystemExit, self.exec_command, args) - self.assertIn('-e/--env', - mocked_stderr.write.call_args_list[-1][0][0]) - - def test_health_start_wo_force(self): - cluster_id = 45 - testset = ['fake_test_set1', 'fake_test_set2'] - args = 'health start -e {id} -t {testset}'.format( - id=cluster_id, testset=' '.join(testset)) - self.exec_command(args) - self.m_client.start.assert_called_once_with(cluster_id, - ostf_credentials={}, - test_sets=testset, - force=False) - self.m_get_client.assert_called_once_with('health', mock.ANY) - - def test_health_start_all_wo_force(self): - cluster_id = 45 - args = 'health start -e {id}'.format(id=cluster_id) - self.exec_command(args) - self.m_client.start.assert_called_once_with(cluster_id, - ostf_credentials={}, - test_sets=None, - force=False) - self.m_get_client.assert_called_once_with('health', mock.ANY) - - def test_health_start_force_w_ostf_credentials(self): - cluster_id = 45 - testset = ['fake_test_set1', 'fake_test_set2'] - ostf_credentials = {'username': 'fake_user', - 'password': 'fake_password', - 'tenant': 'fake_tenant_name'} - - args = ('health start -e {id} -t {testset} --force --ostf-username ' - 'fake_user --ostf-password fake_password --ostf-tenant-name ' - 'fake_tenant_name'.format(id=cluster_id, - testset=' '.join(testset))) - - self.exec_command(args) - self.m_client.start.assert_called_once_with( - cluster_id, - ostf_credentials=ostf_credentials, - test_sets=testset, - force=True - ) - self.m_get_client.assert_called_once_with('health', mock.ANY) - - def test_health_stop(self): - testset_id = 66 - args = 'health stop {id}'.format(id=testset_id) - self.exec_command(args) - self.m_client.action.assert_called_once_with(testset_id, 'stopped') - self.m_get_client.assert_called_once_with('health', mock.ANY) - - @mock.patch('sys.stderr') - def test_health_stop_fail(self, mocked_stderr): - args = 'health stop' - self.assertRaises(SystemExit, self.exec_command, args) - self.assertIn('id', mocked_stderr.write.call_args_list[0][0][0]) - - def test_health_restart(self): - testset_id = 66 - args = 'health restart {id}'.format(id=testset_id) - self.exec_command(args) - self.m_client.action.assert_called_once_with(testset_id, 'restarted') - self.m_get_client.assert_called_once_with('health', mock.ANY) - - @mock.patch('sys.stderr') - def test_health_restart_fail(self, mocked_stderr): - args = 'health restart' - self.assertRaises(SystemExit, self.exec_command, args) - self.assertIn('id', mocked_stderr.write.call_args_list[0][0][0]) diff --git a/fuelclient/tests/unit/v2/cli/test_network_group.py b/fuelclient/tests/unit/v2/cli/test_network_group.py deleted file mode 100644 index 8fbaed2..0000000 --- a/fuelclient/tests/unit/v2/cli/test_network_group.py +++ /dev/null @@ -1,88 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 json -import mock - -from fuelclient.tests.unit.v2.cli import test_engine -from fuelclient.tests.utils import fake_network_group -from fuelclient.v1.network_group import NetworkGroupClient - - -class TestNetworkGroupCommand(test_engine.BaseCLITest): - - def setUp(self): - super(TestNetworkGroupCommand, self).setUp() - - get_fake_ng = fake_network_group.get_fake_network_group - - self.m_client.get_all.return_value = [ - get_fake_ng() for _ in range(10)] - self.m_client.get_by_id.return_value = get_fake_ng() - self.m_client.create.return_value = get_fake_ng() - - def test_network_group_list(self): - args = 'network-group list' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('network-group', mock.ANY) - self.m_client.get_all.assert_called_once_with() - - def test_network_group_show(self): - args = 'network-group show 1' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('network-group', mock.ANY) - self.m_client.get_by_id.assert_called_once_with(1) - - def test_network_group_create(self): - meta = {'notation': 'cidr'} - meta_str = json.dumps(meta).replace(r'"', r'\"') - - args = 'network-group create -N 8 -C 10.10.0.0/24 -g 10.10.0.1' \ - ' -V 16 -r 32 testng --meta "{0}"'.format(meta_str) - self.exec_command(args) - - self.m_get_client.assert_called_once_with('network-group', mock.ANY) - - m_client = self.m_client - m_client.create.assert_called_once_with( - name='testng', group_id=8, cidr='10.10.0.0/24', vlan=16, - release=32, gateway='10.10.0.1', meta=meta) - - def test_network_group_update(self): - self.m_client.updatable_attributes = \ - NetworkGroupClient.updatable_attributes - - meta = {'notation': 'cidr'} - meta_str = json.dumps(meta).replace(r'"', r'\"') - - args = 'network-group update -C 10.10.0.0/24' \ - ' --meta "{0}" 1'.format(meta_str) - self.exec_command(args) - - self.m_get_client.assert_called_once_with('network-group', mock.ANY) - - m_client = self.m_client - m_client.update.assert_called_once_with( - 1, cidr='10.10.0.0/24', meta=meta) - - def test_network_group_delete(self): - args = 'network-group delete 42' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('network-group', mock.ANY) - self.m_client.delete_by_id.assert_called_once_with(42) diff --git a/fuelclient/tests/unit/v2/cli/test_network_template.py b/fuelclient/tests/unit/v2/cli/test_network_template.py deleted file mode 100644 index 4838a03..0000000 --- a/fuelclient/tests/unit/v2/cli/test_network_template.py +++ /dev/null @@ -1,64 +0,0 @@ -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock - -from fuelclient.tests.unit.v2.cli import test_engine - - -class TestNetworkTemplateCommand(test_engine.BaseCLITest): - - @mock.patch('sys.stderr') - def test_network_template_upload_fail(self, mocked_stderr): - args = 'network-template upload 1' - self.assertRaises(SystemExit, self.exec_command, args) - self.assertIn('--file', - mocked_stderr.write.call_args_list[-1][0][0]) - - def test_network_template_upload_w_file(self): - args = 'network-template upload --file /tmp/test-file 1' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - self.m_client.upload_network_template.assert_called_once_with( - 1, '/tmp/test-file') - - def test_network_template_download(self): - download_mock = self.m_client.download_network_template - download_mock.return_value = '/tmp/test-dir/settings_1' - - args = 'network-template download 1' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - download_mock.assert_called_once_with(1, None) - - def test_network_template_download_w_dir(self): - download_mock = self.m_client.download_network_template - download_mock.return_value = '/tmp/test-dir/settings_1' - - args = 'network-template download --dir /tmp/test-dir 1' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - download_mock.assert_called_once_with(1, '/tmp/test-dir') - - def test_network_template_delete(self): - args = 'network-template delete 1' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('environment', mock.ANY) - delete_mock = self.m_client.delete_network_template - delete_mock.assert_called_once_with(1) diff --git a/fuelclient/tests/unit/v2/cli/test_node.py b/fuelclient/tests/unit/v2/cli/test_node.py deleted file mode 100644 index 37c4bb7..0000000 --- a/fuelclient/tests/unit/v2/cli/test_node.py +++ /dev/null @@ -1,625 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 json - -import mock -import six -import yaml - -from six import StringIO - -from fuelclient.commands import node as cmd_node -from fuelclient import main as main_mod -from fuelclient.tests.unit.v2.cli import test_engine -from fuelclient.tests.utils import fake_node -from fuelclient.v1 import node - - -class TestNodeCommand(test_engine.BaseCLITest): - """Tests for fuel2 node * commands.""" - - def setUp(self): - super(TestNodeCommand, self).setUp() - - self.m_client.get_all.return_value = [fake_node.get_fake_node() - for i in range(10)] - self.m_client.get_by_id.return_value = fake_node.get_fake_node() - - def test_node_list(self): - args = 'node list' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_all.assert_called_once_with() - - def test_node_list_sorted(self): - args = 'node list -s name' - self.exec_command(args) - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_all.assert_called_once_with() - - def test_node_list_with_env(self): - env_id = 42 - args = 'node list --env {env}'.format(env=env_id) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_all.assert_called_once_with( - environment_id=env_id) - - def test_node_list_with_labels(self): - labels = ['key_1=val_1', 'key_2=val_2', 'key3'] - args = 'node list --labels {labels}'.format( - labels=' '.join(labels)) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_all.assert_called_once_with(labels=labels) - - def test_node_list_with_env_and_labels(self): - env_id = 42 - labels = ['key_1=val_1', 'key_2=val_2', 'key3'] - args = 'node list --env {env} --labels {labels}'.format( - env=env_id, labels=' '.join(labels)) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_all.assert_called_once_with( - environment_id=env_id, labels=labels) - self.assertIsInstance( - self.m_client.get_all.call_args[1].get('labels')[0], six.text_type) - - def test_node_list_ansible_inventory(self): - self.m_client.get_all.return_value = [ - fake_node.get_fake_node(hostname='node-1', - ip='10.20.0.2', - roles=['compute']), - fake_node.get_fake_node(hostname='node-2', - ip='10.20.0.3', - roles=['compute', 'ceph-osd']), - fake_node.get_fake_node(hostname='node-3', - ip='10.20.0.4', - roles=['controller']), - fake_node.get_fake_node(hostname='node-4', - ip='10.20.0.5', - roles=['controller', 'mongo']), - fake_node.get_fake_node(hostname='node-5', - ip='10.20.0.6', - roles=['controller', 'ceph-osd']), - ] - - expected_output = '''\ -[ceph-osd] -node-2 ansible_host=10.20.0.3 -node-5 ansible_host=10.20.0.6 - -[compute] -node-1 ansible_host=10.20.0.2 -node-2 ansible_host=10.20.0.3 - -[controller] -node-3 ansible_host=10.20.0.4 -node-4 ansible_host=10.20.0.5 -node-5 ansible_host=10.20.0.6 - -[mongo] -node-4 ansible_host=10.20.0.5 - -''' - - args = 'node ansible-inventory --env 1' - with mock.patch('sys.stdout', new=StringIO()) as mstdout: - rv = self.exec_command(args) - actual_output = mstdout.getvalue() - - self.assertFalse(rv) - self.assertEqual(expected_output, actual_output) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_all.assert_called_once_with( - environment_id=1, labels=None) - - def test_node_show(self): - node_id = 42 - args = 'node show {node_id}'.format(node_id=node_id) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_by_id.assert_called_once_with(node_id) - - def test_node_vms_conf_list(self): - node_id = 42 - args = 'node list-vms-conf {node_id}'.format(node_id=node_id) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_node_vms_conf.assert_called_once_with(node_id) - - def test_node_vms_conf_create(self): - vms_conf = r'{\"id\":2} {\"id\":3}' - config = [{'id': 2}, - {'id': 3}] - - node_id = 42 - - args = 'node create-vms-conf {0} --conf {1}'.format( - node_id, - vms_conf) - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.node_vms_create.assert_called_once_with(node_id, config) - - def test_node_vms_conf_create_from_list(self): - vms_conf = '[{"id": 2}, {"id": 3}]' - config = [{'id': 2}, {'id': 3}] - - node_id = 42 - - args = "node create-vms-conf {0} --conf '{1}'".format( - node_id, vms_conf) - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.node_vms_create.assert_called_once_with(node_id, config) - - def test_node_vms_conf_create_fail(self): - vms_conf = '[{"id": ' - node_id = 42 - - args = "node create-vms-conf {0} --conf '{1}'".format(node_id, - vms_conf) - self.assertRaises(SystemExit, - self.exec_command, - args) - - @mock.patch('cliff.formatters.table.TableFormatter.emit_one') - def test_node_set_hostname(self, m_emit_one): - self.m_client._updatable_attributes = \ - node.NodeClient._updatable_attributes - node_id = 42 - hostname = 'test-name' - expected_field_data = cmd_node.NodeShow.columns - - self.m_client.update.return_value = \ - fake_node.get_fake_node(node_id=node_id, - hostname=hostname) - - args = 'node update {node_id} --hostname {hostname}'\ - .format(node_id=node_id, hostname=hostname) - - self.exec_command(args) - m_emit_one.assert_called_once_with(expected_field_data, - mock.ANY, - mock.ANY, - mock.ANY) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.update.assert_called_once_with( - node_id, hostname=hostname) - - @mock.patch('cliff.formatters.table.TableFormatter.emit_one') - def test_node_set_name(self, m_emit_one): - self.m_client._updatable_attributes = \ - node.NodeClient._updatable_attributes - node_id = 37 - expected_field_data = cmd_node.NodeShow.columns - - test_cases = ('new-name', 'New Name', 'śćż∑ Pó', '你一定是无聊') - for name in test_cases: - self.m_client.update.return_value = fake_node.get_fake_node( - node_id=node_id, node_name=name) - - cmd = ['node', 'update', str(node_id), '--name', name] - - # NOTE(sbrzeczkowski): due to shlex inability to accept - # unicode arguments prior to python 2.7.3 - main_mod.main(argv=cmd) - - if six.PY2: - name = name.decode('utf-8') - - m_emit_one.assert_called_with(expected_field_data, - mock.ANY, - mock.ANY, - mock.ANY) - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.update.assert_called_once_with( - node_id, name=name) - self.m_get_client.reset_mock() - self.m_client.reset_mock() - - def test_node_label_list_for_all_nodes(self): - args = 'node label list' - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_all_labels_for_nodes.assert_called_once_with( - node_ids=None) - - def test_node_label_list_sorted(self): - args = 'node label list -s label_name' - self.exec_command(args) - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_all_labels_for_nodes.assert_called_once_with( - node_ids=None) - - def test_node_label_list_for_specific_nodes(self): - node_ids = ['42', '43'] - args = 'node label list --nodes {node_ids}'.format( - node_ids=' '.join(node_ids)) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_all_labels_for_nodes.assert_called_once_with( - node_ids=node_ids) - - def test_node_label_set_for_all_nodes(self): - labels = ['key_1=val_1', 'key_2=val_2'] - args = 'node label set -l {labels} --nodes-all'.format( - labels=' '.join(labels)) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.set_labels_for_nodes.assert_called_once_with( - labels=labels, node_ids=None) - - @mock.patch('argparse.ArgumentParser.error') - def test_node_label_set_for_all_nodes_wo_labels_arg(self, merror): - cmd = 'node label set --nodes-all' - self.exec_command(cmd) - args, _ = merror.call_args - self.assertIn('-l/--labels', args[0]) - - def test_node_label_set_for_specific_nodes(self): - labels = ['key_1=val_1', 'key_2=val_2'] - node_ids = ['42', '43'] - args = 'node label set -l {labels} --nodes {node_ids}'.format( - labels=' '.join(labels), node_ids=' '.join(node_ids)) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.set_labels_for_nodes.assert_called_once_with( - labels=labels, node_ids=node_ids) - - def test_node_delete_specific_labels_for_all_nodes(self): - labels = ['key_1', 'key_2'] - args = 'node label delete -l {labels} --nodes-all'.format( - labels=' '.join(labels)) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.delete_labels_for_nodes.assert_called_once_with( - labels=labels, node_ids=None) - - @mock.patch('json.dump') - def test_node_disks_download_json(self, m_dump): - args = 'node disks download --format json -d /tmp 42' - test_data = {'foo': 'bar'} - expected_path = '/tmp/node_42/disks.json' - - self.m_client.get_disks.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.node.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_dump.assert_called_once_with(test_data, mock.ANY, indent=4) - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_disks.assert_called_once_with(42) - - def test_node_disks_upload_json(self): - args = 'node disks upload --format json -d /tmp 42' - test_data = {'foo': 'bar'} - expected_path = '/tmp/node_42/disks.json' - - m_open = mock.mock_open(read_data=json.dumps(test_data)) - with mock.patch('fuelclient.commands.node.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.set_disks.assert_called_once_with(42, test_data) - - @mock.patch('json.dump') - def test_node_disks_getdefault_json(self, m_dump): - args = 'node disks get-default --format json -d /tmp 42' - test_data = {'foo': 'bar'} - expected_path = '/tmp/node_42/disks.json' - - self.m_client.get_default_disks.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.node.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_dump.assert_called_once_with(test_data, mock.ANY, indent=4) - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_default_disks.assert_called_once_with(42) - - @mock.patch('yaml.safe_dump') - def test_node_disks_download_yaml(self, m_safe_dump): - args = 'node disks download --format yaml -d /tmp 42' - test_data = {'foo': 'bar'} - expected_path = '/tmp/node_42/disks.yaml' - - self.m_client.get_disks.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.node.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_safe_dump.assert_called_once_with(test_data, mock.ANY, - default_flow_style=False) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_disks.assert_called_once_with(42) - - def test_node_disks_upload_yaml(self): - args = 'node disks upload --format yaml -d /tmp 42' - test_data = {'foo': 'bar'} - expected_path = '/tmp/node_42/disks.yaml' - - m_open = mock.mock_open(read_data=yaml.dump(test_data)) - with mock.patch('fuelclient.commands.node.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.set_disks.assert_called_once_with(42, test_data) - - @mock.patch('yaml.safe_dump') - def test_node_disks_getdefault_yaml(self, m_safe_dump): - args = 'node disks get-default --format yaml -d /tmp 42' - test_data = {'foo': 'bar'} - expected_path = '/tmp/node_42/disks.yaml' - - self.m_client.get_default_disks.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.node.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_safe_dump.assert_called_once_with(test_data, mock.ANY, - default_flow_style=False) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_default_disks.assert_called_once_with(42) - - def test_node_delete_specific_labels_for_specific_nodes(self): - labels_keys = ['key_1', 'key_2'] - node_ids = ['42', '43'] - args = 'node label delete -l {labels} --nodes {node_ids}'.format( - labels=' '.join(labels_keys), node_ids=' '.join(node_ids)) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.delete_labels_for_nodes.assert_called_once_with( - labels=labels_keys, node_ids=node_ids) - - def test_node_delete_all_labels_for_all_nodes(self): - args = 'node label delete --labels-all --nodes-all' - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.delete_labels_for_nodes.assert_called_once_with( - labels=None, node_ids=None) - - def test_node_delete_all_labels_for_specific_nodes(self): - node_ids = ['42', '43'] - args = 'node label delete --labels-all --nodes {node_ids}'.format( - node_ids=' '.join(node_ids)) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.delete_labels_for_nodes.assert_called_once_with( - labels=None, node_ids=node_ids) - - def test_node_label_delete_by_value(self): - labels = ['key_1', 'key_2=value2'] - node_ids = ['42', '43'] - args = 'node label delete -l {labels} --nodes {node_ids}'.format( - labels=' '.join(labels), node_ids=' '.join(node_ids)) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.delete_labels_for_nodes.assert_called_once_with( - labels=labels, node_ids=node_ids) - - def test_node_label_delete_by_value_with_whitespace(self): - labels = ['key_1', "'key_2 =value2'"] - labels_expected = [x.strip("'") for x in labels] - node_ids = ['42', '43'] - args = 'node label delete -l {labels} --nodes {node_ids}'.format( - labels=' '.join(labels), node_ids=' '.join(node_ids)) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.delete_labels_for_nodes.assert_called_once_with( - labels=labels_expected, node_ids=node_ids) - - def test_node_attributes_download(self): - args = 'node attributes-download 42' - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.download_attributes.assert_called_once_with(42, None) - - def test_node_attributes_upload(self): - args = 'node attributes-upload 42' - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.upload_attributes.assert_called_once_with(42, None) - - @mock.patch('json.dump') - def test_node_interfaces_download_json(self, m_dump): - args = 'node interfaces download --format json -d /tmp 42' - test_data = {'foo': 'bar'} - expected_path = '/tmp/node_42/interfaces.json' - - self.m_client.get_interfaces.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.node.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_dump.assert_called_once_with(test_data, mock.ANY, indent=4) - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_interfaces.assert_called_once_with(42) - - def test_node_interfaces_upload_json(self): - args = 'node interfaces upload --format json -d /tmp 42' - test_data = {'foo': 'bar'} - expected_path = '/tmp/node_42/interfaces.json' - - m_open = mock.mock_open(read_data=json.dumps(test_data)) - with mock.patch('fuelclient.commands.node.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.set_interfaces.assert_called_once_with(42, test_data) - - @mock.patch('json.dump') - def test_node_interfaces_getdefault_json(self, m_dump): - args = 'node interfaces get-default --format json -d /tmp 42' - test_data = {'foo': 'bar'} - expected_path = '/tmp/node_42/interfaces.json' - - self.m_client.get_default_interfaces.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.node.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_dump.assert_called_once_with(test_data, mock.ANY, indent=4) - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_default_interfaces.assert_called_once_with(42) - - @mock.patch('yaml.safe_dump') - def test_node_interfaces_download_yaml(self, m_safe_dump): - args = 'node interfaces download --format yaml -d /tmp 42' - test_data = {'foo': 'bar'} - expected_path = '/tmp/node_42/interfaces.yaml' - - self.m_client.get_interfaces.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.node.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_safe_dump.assert_called_once_with(test_data, mock.ANY, - default_flow_style=False) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_interfaces.assert_called_once_with(42) - - def test_node_interfaces_upload_yaml(self): - args = 'node interfaces upload --format yaml -d /tmp 42' - test_data = {'foo': 'bar'} - expected_path = '/tmp/node_42/interfaces.yaml' - - m_open = mock.mock_open(read_data=yaml.dump(test_data)) - with mock.patch('fuelclient.commands.node.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.set_interfaces.assert_called_once_with(42, test_data) - - @mock.patch('yaml.safe_dump') - def test_node_interfaces_getdefault_yaml(self, m_safe_dump): - args = 'node interfaces get-default --format yaml -d /tmp 42' - test_data = {'foo': 'bar'} - expected_path = '/tmp/node_42/interfaces.yaml' - - self.m_client.get_default_interfaces.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.node.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_safe_dump.assert_called_once_with(test_data, mock.ANY, - default_flow_style=False) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.get_default_interfaces.assert_called_once_with(42) - - def test_undiscover_nodes_by_id(self): - args = 'node undiscover -n 24' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.undiscover_nodes.assert_called_once_with( - env_id=None, node_id=24, force=False) - - def test_undiscover_nodes_by_id_force(self): - args = 'node undiscover -n 24 --force' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.undiscover_nodes.assert_called_once_with( - env_id=None, node_id=24, force=True) - - def test_undiscover_nodes_by_cluster_id(self): - args = 'node undiscover -e 45' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.undiscover_nodes.assert_called_once_with( - env_id=45, node_id=None, force=False) - - def test_undiscover_nodes_by_cluster_id_force(self): - args = 'node undiscover -e 45 --force' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('node', mock.ANY) - self.m_client.undiscover_nodes.assert_called_once_with( - env_id=45, node_id=None, force=True) - - @mock.patch('sys.stderr') - def test_undiscover_nodes_w_wrong_params(self, mocked_stderr): - args = 'node undiscover -e 45 -n 24' - self.assertRaises(SystemExit, self.exec_command, args) - self.assertIn('argument -n/--node: not allowed with argument -e/--env', - mocked_stderr.write.call_args_list[-1][0][0]) diff --git a/fuelclient/tests/unit/v2/cli/test_openstack_config.py b/fuelclient/tests/unit/v2/cli/test_openstack_config.py deleted file mode 100644 index 4b91abc..0000000 --- a/fuelclient/tests/unit/v2/cli/test_openstack_config.py +++ /dev/null @@ -1,146 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock - -from fuelclient.tests.unit.v2.cli import test_engine -from fuelclient.tests import utils - - -class TestOpenstackConfig(test_engine.BaseCLITest): - CLUSTER_ID = 42 - NODE_ID = 64 - - def _test_config_list(self, cmd_line, expected_kwargs): - self.m_get_client.reset_mock() - self.m_client.get_filtered.reset_mock() - self.exec_command('openstack-config list {0}'.format(cmd_line)) - self.m_get_client.assert_called_once_with('openstack-config', - mock.ANY) - self.m_client.get_filtered.assert_called_once_with( - **expected_kwargs) - - def test_config_list_for_node(self): - self._test_config_list( - cmd_line='--env {0} --node {1}'.format(self.CLUSTER_ID, - self.NODE_ID), - expected_kwargs={'cluster_id': self.CLUSTER_ID, - 'node_ids': [self.NODE_ID], 'node_role': None, - 'is_active': True} - ) - - def test_config_list_for_role(self): - self._test_config_list( - cmd_line='--env {0} --role compute'.format(self.CLUSTER_ID), - expected_kwargs={'cluster_id': self.CLUSTER_ID, 'node_ids': None, - 'node_role': 'compute', 'is_active': True} - ) - - def test_config_list_for_cluster(self): - self._test_config_list( - cmd_line='--env {0}'.format(self.CLUSTER_ID), - expected_kwargs={'cluster_id': self.CLUSTER_ID, 'node_ids': None, - 'node_role': None, 'is_active': True} - ) - - def test_config_list_sorted(self): - self._test_config_list( - cmd_line='--env {0} -s node_id'.format(self.CLUSTER_ID), - expected_kwargs={'cluster_id': self.CLUSTER_ID, 'node_ids': None, - 'node_role': None, 'is_active': True} - ) - - @mock.patch('sys.stderr') - def test_config_list_for_cluster_fail(self, mocked_stderr): - self.assertRaises(SystemExit, - self.exec_command, 'openstack-config list') - self.assertIn('-e/--env', - mocked_stderr.write.call_args_list[-1][0][0]) - - def test_config_upload(self): - self.m_client.upload.return_value = [utils.get_fake_openstack_config() - for i in range(10)] - - cmd = 'openstack-config upload --env {0} --node {1} --file ' \ - 'config.yaml'.format(self.CLUSTER_ID, self.NODE_ID) - self.exec_command(cmd) - - self.m_get_client.assert_called_once_with('openstack-config', mock.ANY) - self.m_client.upload.assert_called_once_with( - path='config.yaml', cluster_id=self.CLUSTER_ID, - node_ids=[self.NODE_ID], node_role=None) - - @mock.patch('sys.stderr') - def test_config_upload_fail(self, mocked_stderr): - cmd = 'openstack-config upload --env {0} ' \ - '--node {1}'.format(self.CLUSTER_ID, self.NODE_ID) - self.assertRaises(SystemExit, self.exec_command, cmd) - self.assertIn('--file', - mocked_stderr.write.call_args_list[-1][0][0]) - mocked_stderr.reset_mock() - - cmd = 'openstack-config upload --node {1} ' \ - '--file config.yaml'.format(self.CLUSTER_ID, self.NODE_ID) - self.assertRaises(SystemExit, self.exec_command, cmd) - self.assertIn('-e/--env', - mocked_stderr.write.call_args_list[-1][0][0]) - - def test_config_download(self): - self.m_client.download.return_value = 'config.yaml' - - cmd = 'openstack-config download 1 --file config.yaml' - self.exec_command(cmd) - - self.m_get_client.assert_called_once_with('openstack-config', mock.ANY) - self.m_client.download.assert_called_once_with(1, 'config.yaml') - - @mock.patch('sys.stderr') - def test_config_download_fail(self, mocked_stderr): - cmd = 'openstack-config download 1' - self.assertRaises(SystemExit, self.exec_command, cmd) - self.assertIn('--file', - mocked_stderr.write.call_args_list[-1][0][0]) - - def test_config_execute(self): - cmd = 'openstack-config execute --env {0} --node {1}' \ - ''.format(self.CLUSTER_ID, self.NODE_ID) - self.exec_command(cmd) - - self.m_get_client.assert_called_once_with('openstack-config', mock.ANY) - self.m_client.execute.assert_called_once_with( - cluster_id=self.CLUSTER_ID, node_ids=[self.NODE_ID], - node_role=None, force=False) - - def test_config_force_execute(self): - task_id = 42 - test_task = utils.get_fake_task(task_id=task_id) - - self.m_client.execute.return_value = test_task - - cmd = ('openstack-config execute --env {0}' - ' --node {1} --force ').format(self.CLUSTER_ID, self.NODE_ID) - - self.exec_command(cmd) - - self.m_get_client.assert_called_once_with('openstack-config', mock.ANY) - self.m_client.execute.assert_called_once_with( - cluster_id=self.CLUSTER_ID, node_ids=[self.NODE_ID], - node_role=None, force=True) - - def test_config_delete(self): - cmd = 'openstack-config delete 1' - self.exec_command(cmd) - - self.m_get_client.assert_called_once_with('openstack-config', mock.ANY) - self.m_client.delete.assert_called_once_with(1) diff --git a/fuelclient/tests/unit/v2/cli/test_plugins.py b/fuelclient/tests/unit/v2/cli/test_plugins.py deleted file mode 100644 index 95bf9e3..0000000 --- a/fuelclient/tests/unit/v2/cli/test_plugins.py +++ /dev/null @@ -1,84 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock -import tempfile - -from fuelclient.tests.unit.v2.cli import test_engine -from fuelclient.tests.utils import fake_plugin - - -class TestPluginsCommand(test_engine.BaseCLITest): - """Tests for fuel2 plugins * commands.""" - - def setUp(self): - super(TestPluginsCommand, self).setUp() - self.name = 'fuel_plugin' - self.version = '1.0.0' - - get_fake_plugins = fake_plugin.get_fake_plugins - - self.m_client.get_modified.return_value = get_fake_plugins(10) - - def test_plugin_list(self): - args = 'plugins list' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('plugins', mock.ANY) - self.m_client.get_all.assert_called_once_with() - - def test_plugin_list_sorted(self): - args = 'plugins list -s name' - self.exec_command(args) - self.m_get_client.assert_called_once_with('plugins', mock.ANY) - self.m_client.get_all.assert_called_once_with() - - def test_plugins_sync_all(self): - args = 'plugins sync' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('plugins', mock.ANY) - self.m_client.sync.assert_called_once_with(ids=None) - - def test_plugins_sync_specified_plugins(self): - ids = [1, 2] - args = 'plugins sync {ids}'.format(ids=' '.join(map(str, ids))) - self.exec_command(args) - - self.m_get_client.assert_called_once_with('plugins', mock.ANY) - self.m_client.sync.assert_called_once_with(ids=ids) - - def exec_install(self, ext='rpm', force=False): - path = tempfile.mkstemp(suffix='.{}'.format(ext))[1] - args = 'plugins install {0} {1}'.format(path, - '--force' if force else '') - self.exec_command(args) - - self.m_get_client.assert_called_once_with('plugins', mock.ANY) - self.m_client.install.assert_called_once_with(path, force=force) - - def test_plugin_install(self): - self.exec_install() - - def test_plugin_install_with_force(self): - self.exec_install(force=True) - - def test_plugin_remove(self): - args = 'plugins remove {0} {1}'.format(self.name, self.version) - self.exec_command(args) - - self.m_get_client.assert_called_once_with('plugins', mock.ANY) - self.m_client.remove.assert_called_once_with(self.name, self.version) diff --git a/fuelclient/tests/unit/v2/cli/test_release.py b/fuelclient/tests/unit/v2/cli/test_release.py deleted file mode 100644 index 6d397bc..0000000 --- a/fuelclient/tests/unit/v2/cli/test_release.py +++ /dev/null @@ -1,87 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 mock - -from fuelclient.tests.unit.v2.cli import test_engine -from fuelclient.tests.utils import fake_release - - -class TestReleaseCommand(test_engine.BaseCLITest): - """Tests for fuel2 release * commands.""" - - def setUp(self): - super(TestReleaseCommand, self).setUp() - self.m_client.get_by_id.return_value = fake_release.get_fake_release() - self.m_client.get_attributes_metadata_by_id.return_value = \ - fake_release.get_fake_attributes_metadata() - self.m_client.get_components_by_id.return_value = \ - fake_release.get_fake_release_components(10) - - def test_release_list(self): - args = 'release list' - self.exec_command(args) - self.m_client.get_all.assert_called_once_with() - self.m_get_client.assert_called_once_with('release', mock.ANY) - - def test_release_repos_list(self): - args = 'release repos list 1' - self.exec_command(args) - self.m_client.get_attributes_metadata_by_id.assert_called_once_with(1) - self.m_get_client.assert_called_once_with('release', mock.ANY) - - def test_release_repos_list_sorted(self): - args = 'release repos list 1 -s name' - self.exec_command(args) - self.m_client.get_attributes_metadata_by_id.assert_called_once_with(1) - self.m_get_client.assert_called_once_with('release', mock.ANY) - - @mock.patch('fuelclient.commands.release.utils.parse_yaml_file') - def test_release_repos_update(self, mock_parse_yaml): - args = 'release repos update 1 -f repos.yaml' - new_repos = [ - { - "name": "fake", - "type": "deb", - "uri": "some_uri", - "priority": 1050, - "section": "main", - "suite": "trusty" - } - ] - mock_parse_yaml.return_value = new_repos - data = fake_release.get_fake_attributes_metadata() - data["editable"]["repo_setup"]["repos"]["value"] = new_repos - self.exec_command(args) - mock_parse_yaml.assert_called_once_with('repos.yaml') - self.m_client.get_attributes_metadata_by_id.assert_called_once_with(1) - self.m_client.update_attributes_metadata_by_id \ - .assert_called_once_with(1, data) - self.m_get_client.assert_called_once_with('release', mock.ANY) - - def test_release_component_list(self): - release_id = 42 - args = 'release component list {0}'.format(release_id) - self.exec_command(args) - self.m_client.get_components_by_id.assert_called_once_with(release_id) - self.m_get_client.assert_called_once_with('release', mock.ANY) - - def test_release_component_list_sorted(self): - release_id = 42 - args = 'release component list {0} -s default'.format(release_id) - self.exec_command(args) - self.m_client.get_components_by_id.assert_called_once_with(release_id) - self.m_get_client.assert_called_once_with('release', mock.ANY) diff --git a/fuelclient/tests/unit/v2/cli/test_role.py b/fuelclient/tests/unit/v2/cli/test_role.py deleted file mode 100644 index d54f8c3..0000000 --- a/fuelclient/tests/unit/v2/cli/test_role.py +++ /dev/null @@ -1,359 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Vitalii Kulanov -# -# Licensed 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 json -import mock -import yaml - -from fuelclient.tests.unit.v2.cli import test_engine -from fuelclient.tests.utils import fake_role - - -class TestRoleCommand(test_engine.BaseCLITest): - """Tests for fuel2 role * commands.""" - - def test_role_list_for_release(self): - self.m_client.get_all.return_value = [ - {"name": "fake_role_1", - "group": "fake_group", - "conflicts": ["fake_role_2", "fake_role_3"], - "description": "some fake description"}, - {"name": "fake_role_2", - "group": "fake_group", - "conflicts": ["fake_role_1", "fake_role_3"], - "description": "some fake description"} - ] - release_id = 45 - args = 'role list -r {id}'.format(id=release_id) - self.exec_command(args) - self.m_client.get_all.assert_called_once_with('releases', release_id) - self.m_get_client.assert_called_once_with('role', mock.ANY) - - def test_role_list_for_cluster(self): - self.m_client.get_all.return_value = [ - {"name": "fake_role_1", - "group": "fake_group", - "conflicts": ["fake_role_2", "fake_role_3"], - "description": "some fake description"}, - {"name": "fake_role_2", - "group": "fake_group", - "conflicts": ["fake_role_1", "fake_role_3"], - "description": "some fake description"} - ] - env_id = 45 - args = 'role list -e {id}'.format(id=env_id) - self.exec_command(args) - self.m_client.get_all.assert_called_once_with('clusters', env_id) - self.m_get_client.assert_called_once_with('role', mock.ANY) - - def test_role_list_sorted(self): - self.m_client.get_all.return_value = [ - {"name": "fake_role_2", - "group": "fake_group_1", - "conflicts": ["fake_role_1", "fake_role_3"], - "description": "some fake description"}, - {"name": "fake_role_1", - "group": "fake_group_2", - "conflicts": ["fake_role_2", "fake_role_3"], - "description": "some fake description"}, - ] - env_id = 45 - args = 'role list -e {id} -s group'.format(id=env_id) - self.exec_command(args) - self.m_client.get_all.assert_called_once_with('clusters', env_id) - self.m_get_client.assert_called_once_with('role', mock.ANY) - - @mock.patch('sys.stderr') - def test_role_list_fail(self, mocked_stderr): - args = 'role list' - self.assertRaises(SystemExit, self.exec_command, args) - self.assertIn('-r/--release -e/--env', - mocked_stderr.write.call_args_list[-1][0][0]) - - @mock.patch('sys.stderr') - def test_role_list_with_mutually_exclusive_params(self, mocked_stderr): - args = 'role list -e 1 -r 2' - self.assertRaises(SystemExit, self.exec_command, args) - self.assertIn('not allowed', - mocked_stderr.write.call_args_list[-1][0][0]) - - @mock.patch('json.dump') - def test_release_role_download_json(self, m_dump): - release_id = 45 - role_name = 'fake_role' - test_data = fake_role.get_fake_role(fake_role) - args = 'role download -r {} -n {} -f json -d /tmp'.format(release_id, - role_name) - expected_path = '/tmp/releases_{id}/{name}.json'.format(id=release_id, - name=role_name) - - self.m_client.get_one.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.role.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_dump.assert_called_once_with(test_data, mock.ANY, indent=4) - self.m_get_client.assert_called_once_with('role', mock.ANY) - self.m_client.get_one.assert_called_once_with('releases', - release_id, - role_name) - - @mock.patch('json.dump') - def test_cluster_role_download_json(self, m_dump): - env_id = 45 - role_name = 'fake_role' - test_data = fake_role.get_fake_role(fake_role) - args = 'role download -e {} -n {} -f json -d /tmp'.format(env_id, - role_name) - expected_path = '/tmp/clusters_{id}/{name}.json'.format(id=env_id, - name=role_name) - - self.m_client.get_one.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.role.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_dump.assert_called_once_with(test_data, mock.ANY, indent=4) - self.m_get_client.assert_called_once_with('role', mock.ANY) - self.m_client.get_one.assert_called_once_with('clusters', - env_id, - role_name) - - @mock.patch('yaml.safe_dump') - def test_release_role_download_yaml(self, m_safe_dump): - release_id = 45 - role_name = 'fake_role' - test_data = fake_role.get_fake_role(fake_role) - args = 'role download -r {} -n {} -f yaml -d /tmp'.format(release_id, - role_name) - expected_path = '/tmp/releases_{id}/{name}.yaml'.format(id=release_id, - name=role_name) - - self.m_client.get_one.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.role.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_safe_dump.assert_called_once_with(test_data, mock.ANY, - default_flow_style=False) - self.m_get_client.assert_called_once_with('role', mock.ANY) - self.m_client.get_one.assert_called_once_with('releases', - release_id, - role_name) - - @mock.patch('yaml.safe_dump') - def test_cluster_role_download_yaml(self, m_safe_dump): - env_id = 45 - role_name = 'fake_role' - test_data = fake_role.get_fake_role(fake_role) - args = 'role download -e {} -n {} -f yaml -d /tmp'.format(env_id, - role_name) - expected_path = '/tmp/clusters_{id}/{name}.yaml'.format(id=env_id, - name=role_name) - - self.m_client.get_one.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.role.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_safe_dump.assert_called_once_with(test_data, mock.ANY, - default_flow_style=False) - self.m_get_client.assert_called_once_with('role', mock.ANY) - self.m_client.get_one.assert_called_once_with('clusters', - env_id, - role_name) - - def test_release_role_update_json(self): - release_id = 45 - role_name = 'fake_role' - params = {"owner_type": "releases", - "owner_id": release_id, - "role_name": role_name} - args = 'role update -r {} -n {} -f json -d /tmp'.format(release_id, - role_name) - test_data = fake_role.get_fake_role(role_name) - expected_path = '/tmp/releases_{}/fake_role.json'.format(release_id) - - m_open = mock.mock_open(read_data=json.dumps(test_data)) - with mock.patch('fuelclient.commands.role.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('role', mock.ANY) - self.m_client.update.assert_called_once_with(test_data, **params) - - def test_cluster_role_update_json(self): - env_id = 45 - role_name = 'fake_role' - params = {"owner_type": "clusters", - "owner_id": env_id, - "role_name": role_name} - args = 'role update -e {} -n {} -f json -d /tmp'.format(env_id, - role_name) - test_data = fake_role.get_fake_role(role_name) - expected_path = '/tmp/clusters_{}/fake_role.json'.format(env_id) - - m_open = mock.mock_open(read_data=json.dumps(test_data)) - with mock.patch('fuelclient.commands.role.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('role', mock.ANY) - self.m_client.update.assert_called_once_with(test_data, **params) - - def test_release_role_update_yaml(self): - release_id = 45 - role_name = 'fake_role' - params = {"owner_type": "releases", - "owner_id": release_id, - "role_name": role_name} - args = 'role update -r {} -n {} -f yaml -d /tmp'.format(release_id, - role_name) - test_data = fake_role.get_fake_role(role_name) - expected_path = '/tmp/releases_{}/fake_role.yaml'.format(release_id) - - m_open = mock.mock_open(read_data=yaml.safe_dump(test_data)) - with mock.patch('fuelclient.commands.role.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('role', mock.ANY) - self.m_client.update.assert_called_once_with(test_data, **params) - - def test_cluster_role_update_yaml(self): - env_id = 45 - role_name = 'fake_role' - params = {"owner_type": "clusters", - "owner_id": env_id, - "role_name": role_name} - args = 'role update -e {} -n {} -f yaml -d /tmp'.format(env_id, - role_name) - test_data = fake_role.get_fake_role(role_name) - expected_path = '/tmp/clusters_{}/fake_role.yaml'.format(env_id) - - m_open = mock.mock_open(read_data=yaml.safe_dump(test_data)) - with mock.patch('fuelclient.commands.role.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('role', mock.ANY) - self.m_client.update.assert_called_once_with(test_data, **params) - - def test_release_role_create_json(self): - release_id = 45 - role_name = 'fake_role' - params = {"owner_type": "releases", - "owner_id": release_id, - "role_name": role_name} - args = 'role create -r {} -n {} -f json -d /tmp'.format(release_id, - role_name) - test_data = fake_role.get_fake_role(role_name) - expected_path = '/tmp/releases_{}/fake_role.json'.format(release_id) - - m_open = mock.mock_open(read_data=json.dumps(test_data)) - with mock.patch('fuelclient.commands.role.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('role', mock.ANY) - self.m_client.create.assert_called_once_with(test_data, **params) - - def test_cluster_role_create_json(self): - env_id = 45 - role_name = 'fake_role' - params = {"owner_type": "clusters", - "owner_id": env_id, - "role_name": role_name} - args = 'role create -e {} -n {} -f json -d /tmp'.format(env_id, - role_name) - test_data = fake_role.get_fake_role(role_name) - expected_path = '/tmp/clusters_{}/fake_role.json'.format(env_id) - - m_open = mock.mock_open(read_data=json.dumps(test_data)) - with mock.patch('fuelclient.commands.role.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('role', mock.ANY) - self.m_client.create.assert_called_once_with(test_data, **params) - - def test_release_role_create_yaml(self): - release_id = 45 - role_name = 'fake_role' - params = {"owner_type": "releases", - "owner_id": release_id, - "role_name": role_name} - args = 'role create -r {} -n {} -f yaml -d /tmp'.format(release_id, - role_name) - test_data = fake_role.get_fake_role(role_name) - expected_path = '/tmp/releases_{}/fake_role.yaml'.format(release_id) - - m_open = mock.mock_open(read_data=yaml.safe_dump(test_data)) - with mock.patch('fuelclient.commands.role.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('role', mock.ANY) - self.m_client.create.assert_called_once_with(test_data, **params) - - def test_cluster_role_create_yaml(self): - env_id = 45 - role_name = 'fake_role' - params = {"owner_type": "clusters", - "owner_id": env_id, - "role_name": role_name} - args = 'role create -e {} -n {} -f yaml -d /tmp'.format(env_id, - role_name) - test_data = fake_role.get_fake_role(role_name) - expected_path = '/tmp/clusters_{}/fake_role.yaml'.format(env_id) - - m_open = mock.mock_open(read_data=yaml.safe_dump(test_data)) - with mock.patch('fuelclient.commands.role.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('role', mock.ANY) - self.m_client.create.assert_called_once_with(test_data, **params) - - def test_release_role_delete(self): - release_id = 45 - role_name = 'fake_role' - args = 'role delete -r {} -n {}'.format(release_id, role_name) - - self.exec_command(args) - self.m_get_client.assert_called_once_with('role', mock.ANY) - self.m_client.delete.assert_called_once_with('releases', - release_id, - role_name) - - def test_cluster_role_delete(self): - env_id = 45 - role_name = 'fake_role' - args = 'role delete -e {} -n {}'.format(env_id, role_name) - - self.exec_command(args) - self.m_get_client.assert_called_once_with('role', mock.ANY) - self.m_client.delete.assert_called_once_with('clusters', - env_id, - role_name) diff --git a/fuelclient/tests/unit/v2/cli/test_sequences.py b/fuelclient/tests/unit/v2/cli/test_sequences.py deleted file mode 100644 index 68453cb..0000000 --- a/fuelclient/tests/unit/v2/cli/test_sequences.py +++ /dev/null @@ -1,100 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 mock - -from fuelclient.tests.unit.v2.cli import test_engine - - -class TestSequenceActions(test_engine.BaseCLITest): - def test_create(self): - self.exec_command( - 'sequence create -r 1 -n test -t test_graph' - ) - self.m_client.create.assert_called_once_with( - 1, 'test', ['test_graph'] - ) - - def test_upload(self): - m_open = mock.mock_open(read_data='name: test\ngraphs: [test]') - module_path = 'fuelclient.cli.serializers.open' - with mock.patch(module_path, m_open, create=True): - self.exec_command( - 'sequence upload -r 1 --file sequence.yaml' - ) - - self.m_client.upload.assert_called_once_with( - 1, {'name': 'test', 'graphs': ['test']} - ) - - def test_download(self): - self.m_client.download.return_value = {"name": "test"} - m_open = mock.mock_open() - module_path = 'fuelclient.cli.serializers.open' - with mock.patch(module_path, m_open, create=True): - self.exec_command( - 'sequence download 1 --file sequence.json' - ) - self.m_client.download.assert_called_once_with(1) - with mock.patch('sys.stdout') as stdout_mock: - self.exec_command('sequence download 1') - stdout_mock.write.assert_called_with("name: test\n") - - def test_update(self): - self.exec_command( - 'sequence update 1 -n test -t test_graph' - ) - self.m_client.update.assert_called_once_with( - 1, name='test', graph_types=['test_graph'] - ) - - def test_show(self): - self.exec_command('sequence show 1') - self.m_client.get_by_id.assert_called_once_with(1) - - def test_list(self): - self.exec_command('sequence list -r 1') - self.m_client.get_all.assert_called_once_with(release=1) - - def test_delete(self): - self.exec_command('sequence delete 1') - self.m_client.delete_by_id.assert_called_once_with(1) - - def test_execute_with_dry_run_and_force(self): - self.exec_command( - 'sequence execute 1 -e 2 --dry-run --force' - ) - self.m_client.execute.assert_called_once_with( - sequence_id=1, env_id=2, - dry_run=True, noop_run=False, force=True, debug=False - ) - - def test_execute_with_noop_and_trace(self): - self.exec_command( - 'sequence execute 1 -e 2 --noop --trace' - ) - self.m_client.execute.assert_called_once_with( - sequence_id=1, env_id=2, - dry_run=False, noop_run=True, force=False, debug=True - ) - - def test_execute_with_json_output(self): - self.m_client.execute.return_value = mock.MagicMock( - data={'id': 1} - ) - with mock.patch('sys.stdout') as stdout_mock: - self.exec_command('sequence execute 1 -e 2 --format=json') - stdout_mock.write.assert_called_with('{\n "id": 1\n}\n') diff --git a/fuelclient/tests/unit/v2/cli/test_snapshot.py b/fuelclient/tests/unit/v2/cli/test_snapshot.py deleted file mode 100644 index d9f0457..0000000 --- a/fuelclient/tests/unit/v2/cli/test_snapshot.py +++ /dev/null @@ -1,131 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Vitalii Kulanov -# -# Licensed 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 json -import mock -import yaml - -from fuelclient.cli import error -from fuelclient.tests.unit.v2.cli import test_engine - - -class TestSnapshotCommand(test_engine.BaseCLITest): - - @mock.patch('json.dump') - def test_snapshot_config_download_json(self, m_dump): - args = 'snapshot get-default-config -f json -d /tmp' - test_data = {'foo': 'bar'} - expected_path = '/tmp/snapshot_conf.json' - - self.m_client.get_default_config.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.snapshot.open', - m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_dump.assert_called_once_with(test_data, mock.ANY, indent=4) - self.m_get_client.assert_called_once_with('snapshot', mock.ANY) - self.m_client.get_default_config.assert_called_once_with() - - @mock.patch('yaml.safe_dump') - def test_snapshot_config_download_yaml(self, m_safe_dump): - args = 'snapshot get-default-config -f yaml -d /tmp' - test_data = {'foo': 'bar'} - expected_path = '/tmp/snapshot_conf.yaml' - - self.m_client.get_default_config.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.snapshot.open', - m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_safe_dump.assert_called_once_with(test_data, mock.ANY, - default_flow_style=False) - - self.m_get_client.assert_called_once_with('snapshot', mock.ANY) - self.m_client.get_default_config.assert_called_once_with() - - def test_snapshot_create(self): - args = 'snapshot create' - test_data = {} - self.exec_command(args) - - self.m_get_client.assert_called_once_with('snapshot', mock.ANY) - self.m_client.create_snapshot.assert_called_once_with(test_data) - - @mock.patch('fuelclient.utils.file_exists', mock.Mock(return_value=True)) - def test_snapshot_create_w_config_json(self): - args = 'snapshot create -c /tmp/snapshot_conf.json' - test_data = {'foo': 'bar'} - expected_path = '/tmp/snapshot_conf.json' - - m_open = mock.mock_open(read_data=json.dumps(test_data)) - with mock.patch('fuelclient.commands.snapshot.open', - m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('snapshot', mock.ANY) - self.m_client.create_snapshot.assert_called_once_with(test_data) - - @mock.patch('fuelclient.utils.file_exists', mock.Mock(return_value=True)) - def test_snapshot_create_w_config_yaml(self): - args = 'snapshot create -c /tmp/snapshot_conf.yaml' - test_data = {'foo': 'bar'} - expected_path = '/tmp/snapshot_conf.yaml' - - m_open = mock.mock_open(read_data=yaml.dump(test_data)) - with mock.patch('fuelclient.commands.snapshot.open', - m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('snapshot', mock.ANY) - self.m_client.create_snapshot.assert_called_once_with(test_data) - - def test_snapshot_get_link(self): - task_id = 45 - args = 'snapshot get-link {}'.format(task_id) - test_data = {'id': task_id, - 'name': 'dump', - 'status': 'ready', - 'message': 'fake_message'} - - self.m_client.get_by_id.return_value = test_data - - self.exec_command(args) - self.m_get_client.assert_called_once_with('snapshot', mock.ANY) - self.m_client.get_by_id.assert_called_once_with(task_id) - - @mock.patch('sys.stderr') - def test_snapshot_get_link_fail(self, mocked_stderr): - task_id = 45 - args = 'snapshot get-link {}'.format(task_id) - test_data = {'id': task_id, - 'name': 'not_dump_name', - 'status': 'ready', - 'message': 'fake_message'} - - self.m_client.get_by_id.return_value = test_data - - self.assertRaises(error.ActionException, self.exec_command, args) - self.assertIn('Task with id {} is not a snapshot generation ' - 'task'.format(task_id), - mocked_stderr.write.call_args_list[0][0][0]) diff --git a/fuelclient/tests/unit/v2/cli/test_tag.py b/fuelclient/tests/unit/v2/cli/test_tag.py deleted file mode 100644 index c13fbef..0000000 --- a/fuelclient/tests/unit/v2/cli/test_tag.py +++ /dev/null @@ -1,367 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 json -import mock -import yaml - -from fuelclient.tests.unit.v2.cli import test_engine -from fuelclient.tests.utils import fake_tag - - -class TestTagCommand(test_engine.BaseCLITest): - """Tests for fuel2 tag * commands.""" - - def test_tag_list_for_release(self): - self.m_client.get_all.return_value = [ - {"tag": "fake_tag_1", - "has_primary": True, - "owner_id": 1, - "owner_type": 'release', - }, - {"tag": "fake_tag_2", - "has_primary": True, - "owner_id": 1, - "owner_type": 'release', - }, - ] - release_id = 45 - args = 'tag list -r {id}'.format(id=release_id) - self.exec_command(args) - self.m_client.get_all.assert_called_once_with('releases', release_id) - self.m_get_client.assert_called_once_with('tag', mock.ANY) - - def test_tag_list_for_cluster(self): - self.m_client.get_all.return_value = [ - {"tag": "fake_tag_1", - "has_primary": True, - "owner_id": 1, - "owner_type": 'release', - }, - {"tag": "fake_tag_2", - "has_primary": True, - "owner_id": 1, - "owner_type": 'release', - }, - ] - env_id = 45 - args = 'tag list -e {id}'.format(id=env_id) - self.exec_command(args) - self.m_client.get_all.assert_called_once_with('clusters', env_id) - self.m_get_client.assert_called_once_with('tag', mock.ANY) - - def test_tag_list_sorted(self): - self.m_client.get_all.return_value = [ - {"tag": "fake_tag_2", - "group": "group_1", - "has_primary": True, - "owner_id": 1, - "owner_type": 'release', - }, - {"tag": "fake_tag_1", - "group": "group_2", - "has_primary": True, - "owner_id": 1, - "owner_type": 'release', - } - ] - env_id = 45 - args = 'tag list -e {id} -s group'.format(id=env_id) - self.exec_command(args) - self.m_client.get_all.assert_called_once_with('clusters', env_id) - self.m_get_client.assert_called_once_with('tag', mock.ANY) - - @mock.patch('sys.stderr') - def test_tag_list_fail(self, mocked_stderr): - args = 'tag list' - self.assertRaises(SystemExit, self.exec_command, args) - self.assertIn('-r/--release -e/--env', - mocked_stderr.write.call_args_list[-1][0][0]) - - @mock.patch('sys.stderr') - def test_tag_list_with_mutually_exclusive_params(self, mocked_stderr): - args = 'tag list -e 1 -r 2' - self.assertRaises(SystemExit, self.exec_command, args) - self.assertIn('not allowed', - mocked_stderr.write.call_args_list[-1][0][0]) - - @mock.patch('json.dump') - def test_release_tag_download_json(self, m_dump): - release_id = 45 - tag_name = 'fake_tag' - test_data = fake_tag.get_fake_tag(fake_tag) - args = 'tag download -r {} -n {} -f json -d /tmp'.format(release_id, - tag_name) - expected_path = '/tmp/releases_{id}/{name}.json'.format(id=release_id, - name=tag_name) - - self.m_client.get_tag.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.tag.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_dump.assert_called_once_with(test_data, mock.ANY, indent=4) - self.m_get_client.assert_called_once_with('tag', mock.ANY) - self.m_client.get_tag.assert_called_once_with('releases', - release_id, - tag_name) - - @mock.patch('json.dump') - def test_cluster_tag_download_json(self, m_dump): - env_id = 45 - tag_name = 'fake_tag' - test_data = fake_tag.get_fake_tag(fake_tag) - args = 'tag download -e {} -n {} -f json -d /tmp'.format(env_id, - tag_name) - expected_path = '/tmp/clusters_{id}/{name}.json'.format(id=env_id, - name=tag_name) - - self.m_client.get_tag.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.tag.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_dump.assert_called_once_with(test_data, mock.ANY, indent=4) - self.m_get_client.assert_called_once_with('tag', mock.ANY) - self.m_client.get_tag.assert_called_once_with('clusters', - env_id, - tag_name) - - @mock.patch('yaml.safe_dump') - def test_release_tag_download_yaml(self, m_safe_dump): - release_id = 45 - tag_name = 'fake_tag' - test_data = fake_tag.get_fake_tag(fake_tag) - args = 'tag download -r {} -n {} -f yaml -d /tmp'.format(release_id, - tag_name) - expected_path = '/tmp/releases_{id}/{name}.yaml'.format(id=release_id, - name=tag_name) - - self.m_client.get_tag.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.tag.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_safe_dump.assert_called_once_with(test_data, mock.ANY, - default_flow_style=False) - self.m_get_client.assert_called_once_with('tag', mock.ANY) - self.m_client.get_tag.assert_called_once_with('releases', - release_id, - tag_name) - - @mock.patch('yaml.safe_dump') - def test_cluster_tag_download_yaml(self, m_safe_dump): - env_id = 45 - tag_name = 'fake_tag' - test_data = fake_tag.get_fake_tag(fake_tag) - args = 'tag download -e {} -n {} -f yaml -d /tmp'.format(env_id, - tag_name) - expected_path = '/tmp/clusters_{id}/{name}.yaml'.format(id=env_id, - name=tag_name) - - self.m_client.get_tag.return_value = test_data - - m_open = mock.mock_open() - with mock.patch('fuelclient.commands.tag.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'w') - m_safe_dump.assert_called_once_with(test_data, mock.ANY, - default_flow_style=False) - self.m_get_client.assert_called_once_with('tag', mock.ANY) - self.m_client.get_tag.assert_called_once_with('clusters', - env_id, - tag_name) - - def test_release_tag_update_json(self): - release_id = 45 - tag_name = 'fake_tag' - params = {"owner_type": "releases", - "owner_id": release_id, - "tag_name": tag_name} - args = 'tag update -r {} -n {} -f json -d /tmp'.format(release_id, - tag_name) - test_data = fake_tag.get_fake_tag(tag_name) - expected_path = '/tmp/releases_{}/fake_tag.json'.format(release_id) - - m_open = mock.mock_open(read_data=json.dumps(test_data)) - with mock.patch('fuelclient.commands.tag.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('tag', mock.ANY) - self.m_client.update.assert_called_once_with(test_data, **params) - - def test_cluster_tag_update_json(self): - env_id = 45 - tag_name = 'fake_tag' - params = {"owner_type": "clusters", - "owner_id": env_id, - "tag_name": tag_name} - args = 'tag update -e {} -n {} -f json -d /tmp'.format(env_id, - tag_name) - test_data = fake_tag.get_fake_tag(tag_name) - expected_path = '/tmp/clusters_{}/fake_tag.json'.format(env_id) - - m_open = mock.mock_open(read_data=json.dumps(test_data)) - with mock.patch('fuelclient.commands.tag.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('tag', mock.ANY) - self.m_client.update.assert_called_once_with(test_data, **params) - - def test_release_tag_update_yaml(self): - release_id = 45 - tag_name = 'fake_tag' - params = {"owner_type": "releases", - "owner_id": release_id, - "tag_name": tag_name} - args = 'tag update -r {} -n {} -f yaml -d /tmp'.format(release_id, - tag_name) - test_data = fake_tag.get_fake_tag(tag_name) - expected_path = '/tmp/releases_{}/fake_tag.yaml'.format(release_id) - - m_open = mock.mock_open(read_data=yaml.safe_dump(test_data)) - with mock.patch('fuelclient.commands.tag.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('tag', mock.ANY) - self.m_client.update.assert_called_once_with(test_data, **params) - - def test_cluster_tag_update_yaml(self): - env_id = 45 - tag_name = 'fake_tag' - params = {"owner_type": "clusters", - "owner_id": env_id, - "tag_name": tag_name} - args = 'tag update -e {} -n {} -f yaml -d /tmp'.format(env_id, - tag_name) - test_data = fake_tag.get_fake_tag(tag_name) - expected_path = '/tmp/clusters_{}/fake_tag.yaml'.format(env_id) - - m_open = mock.mock_open(read_data=yaml.safe_dump(test_data)) - with mock.patch('fuelclient.commands.tag.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('tag', mock.ANY) - self.m_client.update.assert_called_once_with(test_data, **params) - - def test_release_tag_create_json(self): - release_id = 45 - tag_name = 'fake_tag' - params = {"owner_type": "releases", - "owner_id": release_id, - "tag_name": tag_name} - args = 'tag create -r {} -n {} -f json -d /tmp'.format(release_id, - tag_name) - test_data = fake_tag.get_fake_tag(tag_name) - expected_path = '/tmp/releases_{}/fake_tag.json'.format(release_id) - - m_open = mock.mock_open(read_data=json.dumps(test_data)) - with mock.patch('fuelclient.commands.tag.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('tag', mock.ANY) - self.m_client.create.assert_called_once_with(test_data, **params) - - def test_cluster_tag_create_json(self): - env_id = 45 - tag_name = 'fake_tag' - params = {"owner_type": "clusters", - "owner_id": env_id, - "tag_name": tag_name} - args = 'tag create -e {} -n {} -f json -d /tmp'.format(env_id, - tag_name) - test_data = fake_tag.get_fake_tag(tag_name) - expected_path = '/tmp/clusters_{}/fake_tag.json'.format(env_id) - - m_open = mock.mock_open(read_data=json.dumps(test_data)) - with mock.patch('fuelclient.commands.tag.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('tag', mock.ANY) - self.m_client.create.assert_called_once_with(test_data, **params) - - def test_release_tag_create_yaml(self): - release_id = 45 - tag_name = 'fake_tag' - params = {"owner_type": "releases", - "owner_id": release_id, - "tag_name": tag_name} - args = 'tag create -r {} -n {} -f yaml -d /tmp'.format(release_id, - tag_name) - test_data = fake_tag.get_fake_tag(tag_name) - expected_path = '/tmp/releases_{}/fake_tag.yaml'.format(release_id) - - m_open = mock.mock_open(read_data=yaml.safe_dump(test_data)) - with mock.patch('fuelclient.commands.tag.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('tag', mock.ANY) - self.m_client.create.assert_called_once_with(test_data, **params) - - def test_cluster_tag_create_yaml(self): - env_id = 45 - tag_name = 'fake_tag' - params = {"owner_type": "clusters", - "owner_id": env_id, - "tag_name": tag_name} - args = 'tag create -e {} -n {} -f yaml -d /tmp'.format(env_id, - tag_name) - test_data = fake_tag.get_fake_tag(tag_name) - expected_path = '/tmp/clusters_{}/fake_tag.yaml'.format(env_id) - - m_open = mock.mock_open(read_data=yaml.safe_dump(test_data)) - with mock.patch('fuelclient.commands.tag.open', m_open, create=True): - self.exec_command(args) - - m_open.assert_called_once_with(expected_path, 'r') - self.m_get_client.assert_called_once_with('tag', mock.ANY) - self.m_client.create.assert_called_once_with(test_data, **params) - - def test_release_tag_delete(self): - release_id = 45 - tag_name = 'fake_tag' - args = 'tag delete -r {} -n {}'.format(release_id, tag_name) - - self.exec_command(args) - self.m_get_client.assert_called_once_with('tag', mock.ANY) - self.m_client.delete.assert_called_once_with('releases', - release_id, - tag_name) - - def test_cluster_tag_delete(self): - env_id = 45 - tag_name = 'fake_tag' - args = 'tag delete -e {} -n {}'.format(env_id, tag_name) - - self.exec_command(args) - self.m_get_client.assert_called_once_with('tag', mock.ANY) - self.m_client.delete.assert_called_once_with('clusters', - env_id, - tag_name) diff --git a/fuelclient/tests/unit/v2/cli/test_task.py b/fuelclient/tests/unit/v2/cli/test_task.py deleted file mode 100644 index fd7227a..0000000 --- a/fuelclient/tests/unit/v2/cli/test_task.py +++ /dev/null @@ -1,261 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock -import os -import yaml - -from fuelclient.tests.unit.v2.cli import test_engine -from fuelclient.tests import utils -from fuelclient.v1.deployment_history import DeploymentHistoryClient - - -class TestTaskCommand(test_engine.BaseCLITest): - - def setUp(self): - super(TestTaskCommand, self).setUp() - - self.m_client.get_all.return_value = [utils.get_fake_task() - for _ in range(10)] - self.m_client.get_by_id.return_value = utils.get_fake_task() - self.current_path = os.path.join(os.path.abspath(os.curdir)) - - def test_task_list(self): - args = 'task list' - self.exec_command(args) - - self.m_get_client.assert_called_once_with('task', mock.ANY) - self.m_client.get_all.assert_called_once_with() - - def test_task_list_w_parameters(self): - env_id = 45 - statuses = ['ready', 'error'] - names = ['provision', 'dump'] - args = 'task list -e {env_id} -t {statuses} -n {names}'.format( - env_id=env_id, - statuses=' '.join(statuses), - names=' '.join(names)) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('task', mock.ANY) - self.m_client.get_all.assert_called_once_with(cluster_id=env_id, - statuses=statuses, - transaction_types=names) - - @mock.patch('sys.stderr') - def test_task_list_w_wrong_parameters(self, mocked_stderr): - statuses = ['ready', 'wrong_status'] - args = 'task list -t {statuses}'.format(statuses=' '.join(statuses)) - self.assertRaises(SystemExit, self.exec_command, args) - self.assertIn('-t/--statuses: invalid choice', - mocked_stderr.write.call_args_list[-1][0][0]) - - def test_task_show(self): - task_id = 42 - args = 'task show {task_id}'.format(task_id=task_id) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('task', mock.ANY) - self.m_client.get_by_id.assert_called_once_with(task_id) - - def test_task_delete(self): - task_id = 42 - args = 'task delete {task_id}'.format(task_id=task_id) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('task', mock.ANY) - self.m_client.delete_by_id.assert_called_once_with(task_id, False) - - def test_task_delete_force(self): - task_id = 42 - args = 'task delete --force {task_id}'.format(task_id=task_id) - - self.exec_command(args) - - self.m_get_client.assert_called_once_with('task', mock.ANY) - self.m_client.delete_by_id.assert_called_once_with(task_id, True) - - def test_task_history_show(self): - task_id = 42 - args = 'task history show {task_id} '.format(task_id=task_id) - - self.m_client.get_all.return_value = \ - utils.get_fake_deployment_history() - self.exec_command(args) - - self.m_get_client.assert_called_once_with('deployment_history', - mock.ANY) - self.m_client.get_all.assert_called_once_with(transaction_id=task_id, - nodes=None, - statuses=None, - tasks_names=None, - include_summary=False, - show_parameters=False) - - def test_task_history_show_include_summary(self): - task_id = 42 - args = 'task history show {task_id} '.format(task_id=task_id) - args += '--include-summary ' - - self.m_client.get_all.return_value = \ - utils.get_fake_deployment_history(include_summary=True) - self.exec_command(args) - - self.m_get_client.assert_called_once_with('deployment_history', - mock.ANY) - self.m_client.get_all.assert_called_once_with(transaction_id=task_id, - nodes=None, - statuses=None, - tasks_names=None, - include_summary=True, - show_parameters=False) - - def test_task_history_parameters(self): - task_id = 42 - args = 'task history show {task_id} ' \ - '--tasks-names task1 task2 ' \ - '--statuses ready error --nodes 1 2 ' \ - '--show-parameters'.format(task_id=task_id) - - self.m_client.get_all.return_value = \ - utils.get_fake_deployment_history() - self.exec_command(args) - - self.m_get_client.assert_called_once_with('deployment_history', - mock.ANY) - self.m_client.get_all.assert_called_once_with( - transaction_id=task_id, nodes=['1', '2'], - statuses=['ready', 'error'], tasks_names=['task1', 'task2'], - include_summary=False, - show_parameters=True) - - def _test_cmd(self, cmd, method, cmd_line, client, - return_data, expected_file_path, expected_kwargs): - self.m_get_client.reset_mock() - self.m_client.get_filtered.reset_mock() - self.m_client.__getattr__(method).return_value =\ - yaml.safe_load(return_data) - m_open = mock.mock_open() - with mock.patch('fuelclient.cli.serializers.open', - m_open, create=True): - self.exec_command('task {0} {1} {2}'.format(cmd, method, - cmd_line)) - - m_open.assert_called_once_with(expected_file_path, 'w') - written_yaml = yaml.safe_load(m_open().write.mock_calls[0][1][0]) - expected_yaml = yaml.safe_load(return_data) - self.assertEqual(written_yaml, expected_yaml) - - self.m_get_client.assert_called_once_with(client, mock.ANY) - self.m_client.__getattr__(method).assert_called_once_with( - **expected_kwargs) - - def test_task_deployment_info_download(self): - self._test_cmd('deployment-info', 'download', '1 ', - 'deployment-info', - utils.get_fake_yaml_deployment_info(), - "{0}/deployment_info_1.yaml".format( - self.current_path), - dict(transaction_id=1)) - - def test_task_cluster_settings_download(self): - self._test_cmd('settings', 'download', '1 --file settings.yaml', - 'cluster-settings', - utils.get_fake_yaml_cluster_settings(), - 'settings.yaml', - dict(transaction_id=1)) - - def test_task_network_configuration_download(self): - self._test_cmd('network-configuration', 'download', '1', - 'network-configuration', - utils.get_fake_yaml_network_conf(), - "{0}/network_configuration_1.yaml".format( - self.current_path), - dict(transaction_id=1)) - - -class TestDeploymentTasksAction(test_engine.BaseCLITest): - - @mock.patch('cliff.formatters.table.TableFormatter.emit_list') - def test_show_tasks_history_with_parameters(self, m_formatter): - tasks_after_facade = utils.get_fake_deployment_history_w_params() - - expected_fields = ('task_name', 'task_parameters', 'status_by_node') - expected_data = [ - [ - 'controller-remaining-tasks', - - 'parameters: {puppet_manifest: /etc/puppet/modules/osnailyfact' - 'er/modular/globals/globals.pp,\n puppet_modules: /etc/' - 'puppet/modules, timeout: 3600}\nrole: [controller]\ntype: ' - 'puppet\nversion: 2.0.0\n', - - '1 - ready - 2016-03-25T17:22:10 - 2016-03-25T17:22:30\n' - '2 - ready - 2016-03-25T17:22:10 - 2016-03-25T17:22:30' - ], - [ - 'pending-task', - - 'parameters: {puppet_manifest: /etc/puppet/modules/osnailyfact' - 'er/modular/globals/globals.pp,\n puppet_modules: /etc/puppet' - '/modules, timeout: 3600}\nrole: [controller]\ntype: ' - 'puppet\nversion: 2.0.0\n', - - '1 - pending - not started - not ended\n' - '2 - pending - not started - not ended' - ], - [ - 'ironic-compute', - 'parameters: {puppet_manifest: /etc/puppet/modules/osnailyfact' - 'er/modular/globals/globals.pp,\n puppet_modules: /etc/' - 'puppet/modules, timeout: 3600}\nrole: [controller]\ntype: ' - 'puppet\nversion: 2.0.0\n', - - '1 - skipped - 2016-03-25T17:23:37 - 2016-03-25T17:23:37\n' - '2 - skipped - 2016-03-25T17:23:37 - 2016-03-25T17:23:37' - ] - ] - self.m_client.get_all.return_value = tasks_after_facade - self.m_client.tasks_records_keys = \ - DeploymentHistoryClient.tasks_records_keys - self.m_client.history_records_keys = \ - DeploymentHistoryClient.history_records_keys - - self.exec_command( - ' '.join(( - 'task history show', '1', - '--nodes', '1 2', - '--statuses', 'ready', - '--tasks-names', 'taskname1 taskname2', - '--show-parameters' - )) - ) - - self.m_client.get_all.assert_called_with( - nodes=['1', '2'], - statuses=['ready'], - tasks_names=['taskname1', 'taskname2'], - transaction_id=1, - include_summary=False, - show_parameters=True) - - m_formatter.assert_called_once_with(expected_fields, - expected_data, - mock.ANY, - mock.ANY) diff --git a/fuelclient/tests/unit/v2/cli/test_vip.py b/fuelclient/tests/unit/v2/cli/test_vip.py deleted file mode 100644 index 1118166..0000000 --- a/fuelclient/tests/unit/v2/cli/test_vip.py +++ /dev/null @@ -1,84 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 mock - -from fuelclient.tests.unit.v2.cli import test_engine - - -class TestVIPActions(test_engine.BaseCLITest): - - def _test_cmd(self, method, cmd_line, expected_kwargs): - self.m_get_client.reset_mock() - self.m_client.get_filtered.reset_mock() - self.m_client.__getattr__(method).return_value = 'vips_1.yaml' - self.exec_command('vip {0} {1}'.format(method, cmd_line)) - self.m_get_client.assert_called_once_with('vip', mock.ANY) - self.m_client.__getattr__(method).assert_called_once_with( - **expected_kwargs) - - def test_vip_create(self): - expected = { - "env_id": 1, - "ip_addr": '127.0.0.1', - "network": 1, - "vip_name": 'test', - "vip_namespace": 'test-namespace' - } - cmd_line = ( - '--env {0} --network {1} --address {2} --name {3} --namespace {4}' - .format(expected['env_id'], expected['network'], - expected['ip_addr'], expected['vip_name'], - expected['vip_namespace']) - ) - self._test_cmd('create', cmd_line, expected) - - def test_vip_download(self): - self._test_cmd('download', '--env 1', dict( - env_id=1, - file_path=None, - ip_addr_id=None, - network_id=None, - network_role=None)) - - def test_vip_download_with_network_id(self): - self._test_cmd('download', '--env 1 --network 3', dict( - env_id=1, - file_path=None, - ip_addr_id=None, - network_id=3, - network_role=None)) - - def test_vip_download_with_network_role(self): - self._test_cmd('download', '--env 1 --network-role some/role', dict( - env_id=1, - file_path=None, - ip_addr_id=None, - network_id=None, - network_role='some/role')) - - def test_single_vip_download(self): - self._test_cmd('download', '--env 1 --ip-address-id 5', dict( - env_id=1, - file_path=None, - ip_addr_id=5, - network_id=None, - network_role=None)) - - def test_vip_upload(self): - self._test_cmd('upload', '--env 1 --file vips_1.yaml', dict( - env_id=1, - file_path='vips_1.yaml')) diff --git a/fuelclient/tests/unit/v2/lib/__init__.py b/fuelclient/tests/unit/v2/lib/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fuelclient/tests/unit/v2/lib/test_api.py b/fuelclient/tests/unit/v2/lib/test_api.py deleted file mode 100644 index 15eecf7..0000000 --- a/fuelclient/tests/unit/v2/lib/test_api.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock -from mock import patch -from oslotest import base as oslo_base -import requests_mock as rm -from six.moves.urllib import parse as urlparse - -from fuelclient import client - - -class BaseLibTest(oslo_base.BaseTestCase): - def setUp(self): - super(BaseLibTest, self).setUp() - - self.m_request = rm.Mocker() - self.m_request.start() - - self.auth_required_patch = patch.object(client.APIClient, - 'auth_required', - new_callable=mock.PropertyMock) - self.m_auth_required = self.auth_required_patch.start() - self.m_auth_required.return_value = False - - self.addCleanup(self.m_request.stop) - self.addCleanup(self.auth_required_patch.stop) - - def get_object_uri(self, collection_path, object_id, attribute='/'): - return urlparse.urljoin(collection_path, str(object_id) + attribute) diff --git a/fuelclient/tests/unit/v2/lib/test_client.py b/fuelclient/tests/unit/v2/lib/test_client.py deleted file mode 100644 index 8f11d66..0000000 --- a/fuelclient/tests/unit/v2/lib/test_client.py +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient -from fuelclient.objects import base -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.v1 import base_v1 - - -class FakeObject(base.BaseObject): - class_api_path = 'fake/objects/' - - -class FakeClient(base_v1.BaseV1Client): - - _entity_wrapper = FakeObject - - -class TestClient(test_api.BaseLibTest): - - def setUp(self): - super(TestClient, self).setUp() - - self.host = 'test.host.tld' - self.port = 8888 - - self.connection = fuelclient.connect(self.host, self.port) - - self.client = FakeClient(connection=self.connection) - - self.version = 'v1' - self.res_uri = '/api/{version}/fake/objects/'.format( - version=self.version) - - def test_custom_connection_used(self): - m_get = self.m_request.get(self.res_uri, json={}) - self.client.get_all() - - self.assertTrue(m_get.called) - self.assertEqual( - m_get.last_request.netloc, - '{host}:{port}'.format(host=self.host, port=self.port)) diff --git a/fuelclient/tests/unit/v2/lib/test_deployment_graph.py b/fuelclient/tests/unit/v2/lib/test_deployment_graph.py deleted file mode 100644 index 234a568..0000000 --- a/fuelclient/tests/unit/v2/lib/test_deployment_graph.py +++ /dev/null @@ -1,377 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 mock -import yaml - -import fuelclient -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.tests import utils - - -TASKS_YAML = '''- id: custom-task-1 - type: puppet - parameters: - param: value -- id: custom-task-2 - type: puppet - parameters: - param: value -''' - - -class TestDeploymentGraphFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestDeploymentGraphFacade, self).setUp() - self.version = 'v1' - self.client = fuelclient.get_client('graph', self.version) - self.env_id = 1 - - def test_existing_graph_upload(self): - expected_body = { - 'tasks': yaml.load(TASKS_YAML)} - - matcher_post = self.m_request.post( - '/api/v1/clusters/1/deployment_graphs/custom_graph', - json=expected_body) - - matcher_get = self.m_request.get( - '/api/v1/clusters/1/deployment_graphs/custom_graph', - status_code=404, - json={'status': 'error', 'message': 'Does not exist'}) - - m_open = mock.mock_open(read_data=TASKS_YAML) - with mock.patch( - 'fuelclient.cli.serializers.open', m_open, create=True): - self.client.upload( - data=expected_body, - related_model='clusters', - related_id=1, - graph_type='custom_graph' - ) - - self.assertTrue(matcher_get.called) - self.assertTrue(matcher_post.called) - self.assertItemsEqual( - expected_body, - matcher_post.last_request.json() - ) - - def test_new_graph_upload(self): - expected_body = { - 'tasks': yaml.load(TASKS_YAML)} - - matcher_put = self.m_request.put( - '/api/v1/clusters/1/deployment_graphs/custom_graph', - json=expected_body) - - matcher_get = self.m_request.get( - '/api/v1/clusters/1/deployment_graphs/custom_graph', - status_code=200, - json={ - 'tasks': [{'id': 'imatask', 'type': 'puppet'}] - }) - - m_open = mock.mock_open(read_data=TASKS_YAML) - with mock.patch( - 'fuelclient.cli.serializers.open', m_open, create=True): - self.client.upload( - data=expected_body, - related_model='clusters', - related_id=1, - graph_type='custom_graph') - - self.assertTrue(matcher_get.called) - self.assertTrue(matcher_put.called) - self.assertItemsEqual( - expected_body, - matcher_put.last_request.json() - ) - - def test_new_graph_run_wo_params(self): - matcher_execute = self.m_request.post( - '/api/v1/graphs/execute/', - json=utils.fake_task.get_fake_task(cluster=370)) - # this is required to form running task info - self.m_request.get( - '/api/v1/nodes/?cluster_id=370', - json={} - ) - self.client.execute(env_id=1) - self.assertEqual( - matcher_execute.last_request.json(), - { - 'cluster': 1 - } - ) - - def test_new_graph_run_with_parameters(self): - matcher_execute = self.m_request.post( - '/api/v1/graphs/execute/', - json=utils.fake_task.get_fake_task(cluster=370)) - # this is required to form running task info - self.m_request.get( - '/api/v1/nodes/?cluster_id=370', - json={} - ) - self.client.execute( - env_id=1, - nodes=[1, 2, 3], - graph_types=["custom_graph", "another_custom_graph"], - task_names=["rsync_core_puppet"], - dry_run=True, - noop_run=True, - force=True - ) - self.assertEqual( - { - 'cluster': 1, - 'dry_run': True, - 'noop_run': True, - 'graphs': [ - {'nodes': [1, 2, 3], 'type': 'custom_graph', - 'tasks': ['rsync_core_puppet']}, - {'nodes': [1, 2, 3], 'type': 'another_custom_graph', - 'tasks': ['rsync_core_puppet']} - ], - 'force': True - }, - matcher_execute.last_request.json() - ) - - def test_env_graphs_list(self): - release_id = 101 - env_id = 11 - fake_env = utils.get_fake_env(release_id=release_id, env_id=env_id) - enabled_plugin_id = 331 - self.m_request.get( - '/api/v1/clusters/{}/'.format(env_id), - json=fake_env - ) - - self.m_request.get( - '/api/v1/clusters/{}/attributes'.format(env_id), - json={ - 'editable': { - 'test-plugin-1': { - 'metadata': { - 'class': 'plugin', - 'enabled': True, - 'chosen_id': enabled_plugin_id - } - }, - 'test-plugin-2': { - 'metadata': { - 'class': 'plugin', - 'enabled': False, - } - } - } - } - ) - - release_graphs = [ - { - "tasks": [], - "id": 1, - "relations": [ - { - "model_id": release_id, - "model": "release", - "type": "default" - } - ], - "name": None - } - ] - enabled_plugin_graphs = [ - { - "tasks": [], - "id": 2, - "relations": [ - { - "model_id": enabled_plugin_id, - "model": "plugin", - "type": "default" - } - ], - "name": None - } - ] - cluster_graphs = [ - { - "tasks": [], - "id": 3, - "relations": [ - { - "model_id": env_id, - "model": "cluster", - "type": "default" - } - ], - "name": None - } - ] - - all_env_graphs = \ - release_graphs + cluster_graphs + enabled_plugin_graphs - - not_this_env_cluster_graphs = [ - { - "tasks": [], - "id": 4, - "relations": [ - { - "model_id": env_id + 1, - "model": "cluster", - "type": "default" - } - ], - "name": None - } - ] - - self.m_request.get( - '/api/v1/releases/{}/deployment_graphs/'.format(release_id), - json=release_graphs - ) - - self.m_request.get( - '/api/v1/plugins/{}/deployment_graphs/'.format(enabled_plugin_id), - json=enabled_plugin_graphs - ) - - self.m_request.get( - '/api/v1/clusters/{}/deployment_graphs/'.format(env_id), - json=cluster_graphs - ) - - self.m_request.get( - '/api/v1/graphs/'.format(env_id), - json=all_env_graphs + not_this_env_cluster_graphs - ) - - self.assertItemsEqual( - all_env_graphs, self.client.list(env_id) - ) - self.assertItemsEqual( - release_graphs, self.client.list(env_id, filters=['release']) - ) - - self.assertItemsEqual( - enabled_plugin_graphs, - self.client.list(env_id, filters=['plugin']) - ) - - self.assertItemsEqual( - cluster_graphs, - self.client.list(env_id, filters=['cluster']) - ) - - self.assertItemsEqual( - all_env_graphs + not_this_env_cluster_graphs, - self.client.list() - ) - - self.assertItemsEqual( - cluster_graphs + not_this_env_cluster_graphs + release_graphs, - self.client.list(filters=['cluster', 'release'])) - - def test_new_graph_dry_run_subgraph(self): - matcher_post = self.m_request.post( - '/api/v1/graphs/execute/', - json=utils.get_fake_task(cluster=370)) - # this is required to form running task info - self.m_request.get( - '/api/v1/nodes/?cluster_id=370', - json={} - ) - self.client.execute( - env_id=1, - nodes=[1, 2, 3], - graph_types=["custom_graph"], - dry_run=True, - subgraphs=['primary-database/1,3:keystone-db/1-2,5', - 'openstack-controller'] - ) - self.assertTrue(matcher_post.called) - expected_body = {'cluster': 1, - 'dry_run': True, - 'graphs': - [{ - 'nodes': [1, 2, 3], 'type': 'custom_graph', - 'tasks': ['rsync_core_puppet']}, - { - 'nodes': [1, 2, 3], - 'type': 'another_custom_graph', - 'tasks': ['rsync_core_puppet']}], - 'subgraphs': [ - {'start': ['primary-database/1,3'], - 'end': ['keystone-db/1-2,5']}, - {'start': ['openstack-controller'], - 'end': [None]}] - } - self.assertItemsEqual(matcher_post.last_request.json(), expected_body) - - def test_graphs_download_all(self): - matcher_get = self.m_request.get( - '/api/v1/clusters/1/deployment_tasks/?graph_type=custom_graph', - json=[] - ) - self.client.download(env_id=1, level='all', - graph_type='custom_graph') - self.assertTrue(matcher_get.called) - - def test_graphs_download_release(self): - matcher_get = self.m_request.get( - '/api/v1/clusters/1/deployment_tasks/' - 'release/?graph_type=custom_graph', - json=[] - ) - self.client.download(env_id=1, level='release', - graph_type='custom_graph') - self.assertTrue(matcher_get.called) - - def test_graphs_download_plugins(self): - matcher_get = self.m_request.get( - '/api/v1/clusters/1/deployment_tasks/' - 'plugins/?graph_type=custom_graph', - json=[] - ) - self.client.download(env_id=1, level='plugins', - graph_type='custom_graph') - self.assertTrue(matcher_get.called) - - def test_graphs_download_cluster(self): - matcher_get = self.m_request.get( - '/api/v1/clusters/1/deployment_tasks/own/' - '?graph_type=custom_graph', - json=[{'tasks': []}] - ) - self.client.download(env_id=1, level='cluster', - graph_type='custom_graph') - self.assertTrue(matcher_get.called) - - def test_graph_delete(self): - matcher_delete = self.m_request.delete( - '/api/v1/clusters/1/deployment_graphs/custom_graph', - json={} - ) - self.client.delete(graph_type='custom_graph', - related_id=1, - related_model='clusters') - self.assertTrue(matcher_delete.called) diff --git a/fuelclient/tests/unit/v2/lib/test_deployment_history.py b/fuelclient/tests/unit/v2/lib/test_deployment_history.py deleted file mode 100644 index a79f5aa..0000000 --- a/fuelclient/tests/unit/v2/lib/test_deployment_history.py +++ /dev/null @@ -1,126 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.tests import utils - - -class TestDeploymentHistoryFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestDeploymentHistoryFacade, self).setUp() - - self.version = 'v1' - self.transaction_id = '1' - self.res_uri = '/api/{0}/transactions/{1}'\ - '/deployment_history/' \ - ''.format(self.version, self.transaction_id) - - self.fake_history = utils.get_fake_deployment_history() - - self.client = fuelclient.get_client('deployment_history', self.version) - - def get_url(self, nodes='', statuses='', tasks_names=''): - params = '?nodes={}&statuses={}&tasks_names={}' - return self.res_uri + params.format(nodes, statuses, tasks_names) - - def test_deployment_history_list(self): - - matcher = self.m_request.get(self.get_url(), json=self.fake_history) - - self.client.get_all( - transaction_id=self.transaction_id, - nodes=None, - statuses=None) - - self.assertTrue(matcher.called) - - def test_deployment_history(self): - - matcher = self.m_request.get( - self.get_url( - nodes='1,2', - statuses='ready,error,pending', - tasks_names='controller-remaining-tasks,' - 'ironic-compute,pending-task' - ), json=self.fake_history) - - tasks_after_facade = self.client.get_all( - transaction_id=self.transaction_id, - nodes=['1', '2'], - statuses=['ready', 'error', 'pending'], - tasks_names=['controller-remaining-tasks', - 'ironic-compute', 'pending-task'], - show_parameters=False - ) - - self.assertTrue(matcher.called) - self.assertItemsEqual( - utils.get_fake_deployment_history(convert_legacy_fields=True), - tasks_after_facade) - - def test_deployment_history_include_summary(self): - fake_history = utils.get_fake_deployment_history(include_summary=True) - matcher = self.m_request.get( - self.get_url( - nodes='1,2', - statuses='ready,error,pending', - tasks_names='controller-remaining-tasks,' - 'ironic-compute,pending-task' - ) + '&include_summary=1', json=fake_history) - - tasks_after_facade = self.client.get_all( - transaction_id=self.transaction_id, - nodes=['1', '2'], - statuses=['ready', 'error', 'pending'], - tasks_names=['controller-remaining-tasks', - 'ironic-compute', 'pending-task'], - include_summary=True, - show_parameters=False - ) - - self.assertTrue(matcher.called) - self.assertItemsEqual( - utils.get_fake_deployment_history(convert_legacy_fields=True, - include_summary=True), - tasks_after_facade) - - def test_deployment_history_parameters(self): - - matcher = self.m_request.get( - self.get_url( - nodes='1,2', - statuses='ready,error,pending', - tasks_names='controller-remaining-tasks,' - 'ironic-compute,pending-task' - ), - json=utils.get_fake_deployment_history(add_task_data=True), - ) - - tasks_after_facade = self.client.get_all( - transaction_id=self.transaction_id, - nodes=['1', '2'], - statuses=['ready', 'error', 'pending'], - tasks_names=['controller-remaining-tasks', - 'ironic-compute', 'pending-task'], - show_parameters=True - ) - - self.assertTrue(matcher.called) - self.assertItemsEqual( - utils.get_fake_deployment_history_w_params(), - tasks_after_facade) diff --git a/fuelclient/tests/unit/v2/lib/test_environment.py b/fuelclient/tests/unit/v2/lib/test_environment.py deleted file mode 100644 index e2cb9cd..0000000 --- a/fuelclient/tests/unit/v2/lib/test_environment.py +++ /dev/null @@ -1,531 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock - -import fuelclient -from fuelclient.cli import error -from fuelclient.objects import base as base_object -from fuelclient.objects import environment as env_object -from fuelclient.objects import fuelversion as fuelversion_object -from fuelclient.objects import task as task_object -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.tests import utils - - -class TestEnvFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestEnvFacade, self).setUp() - - self.version = 'v1' - self.res_uri = '/api/{version}/clusters/'.format(version=self.version) - self.net_conf_uri = '/network_configuration/neutron' - self.settings_uri = '/attributes' - self.net_verify_uri = '/network_configuration/neutron/verify' - - self.fake_env = utils.get_fake_env() - self.fake_envs = [utils.get_fake_env() for i in range(10)] - - self.client = fuelclient.get_client('environment', self.version) - - def test_env_list(self): - matcher = self.m_request.get(self.res_uri, json=self.fake_envs) - self.client.get_all() - - self.assertTrue(matcher.called) - - def test_env_show(self): - env_id = 42 - expected_uri = self.get_object_uri(self.res_uri, env_id) - - matcher = self.m_request.get(expected_uri, json=self.fake_env) - - self.client.get_by_id(env_id) - - self.assertTrue(matcher.called) - - def test_env_delete(self): - env_id = 42 - expected_uri = self.get_object_uri(self.res_uri, env_id) - - matcher = self.m_request.delete(expected_uri, json={}) - - self.client.delete_by_id(env_id) - - self.assertTrue(matcher.called) - - @mock.patch.object(env_object.Environment, 'init_with_data') - def test_env_create(self, m_init): - env_name = self.fake_env['name'] - release_id = self.fake_env['release_id'] - nst = 'vlan' - - matcher = self.m_request.post(self.res_uri, json=self.fake_env) - - self.client.create(name=env_name, - release_id=release_id, - net_segment_type=nst) - - req_data = matcher.last_request.json() - - self.assertTrue(matcher.called) - - self.assertEqual(release_id, req_data['release_id']) - self.assertEqual(env_name, req_data['name']) - self.assertEqual(nst, req_data['net_segment_type']) - - def test_env_create_bad_nst_neutron(self): - node_name = 'test_node' - release_id = 20 - nst = 'bad' - - self.assertRaises(error.BadDataException, - self.client.create, - node_name, release_id, nst) - - def test_env_create_neutron_tun(self): - env = utils.get_fake_env() - env_name = env['name'] - release_id = env['release_id'] - nst = env['net_segment_type'] = 'tun' - - matcher = self.m_request.post(self.res_uri, json=env) - - self.client.create(name=env_name, - release_id=release_id, - net_segment_type=nst) - - req_data = matcher.last_request.json() - - self.assertEqual(release_id, req_data['release_id']) - self.assertEqual(env_name, req_data['name']) - self.assertEqual(nst, req_data['net_segment_type']) - - @mock.patch.object(task_object.DeployTask, 'init_with_data') - def test_env_deploy(self, m_init): - env_id = 42 - expected_uri = self.get_object_uri(self.res_uri, env_id, '/changes') - matcher = self.m_request.put(expected_uri, json={}) - dry_run = False - - self.client.deploy_changes(env_id, dry_run=dry_run) - self.check_deploy_redeploy_changes(dry_run, matcher) - - def check_deploy_redeploy_changes(self, res, matcher, mode='dry_run'): - self.assertTrue(matcher.called) - self.assertEqual(matcher.last_request.qs[mode][0], str(int(res))) - - @mock.patch.object(task_object.DeployTask, 'init_with_data') - def test_env_deploy_dry_run(self, m_init): - env_id = 42 - expected_uri = self.get_object_uri(self.res_uri, env_id, '/changes') - matcher = self.m_request.put(expected_uri, json={}) - - dry_run = True - - self.client.deploy_changes(env_id, dry_run=dry_run) - self.check_deploy_redeploy_changes(dry_run, matcher) - - @mock.patch.object(task_object.DeployTask, 'init_with_data') - def test_env_deploy_noop_run(self, m_init): - env_id = 42 - expected_uri = self.get_object_uri(self.res_uri, env_id, '/changes') - matcher = self.m_request.put(expected_uri, json={}) - - noop_run = True - - self.client.deploy_changes(env_id, noop_run=noop_run) - self.check_deploy_redeploy_changes(noop_run, matcher, mode='noop_run') - - @mock.patch.object(task_object.DeployTask, 'init_with_data') - def test_env_redeploy(self, m_init): - env_id = 42 - expected_uri = self.get_object_uri(self.res_uri, env_id, - '/changes/redeploy') - matcher = self.m_request.put(expected_uri, json={}) - dry_run = False - - self.client.redeploy_changes(env_id, dry_run=dry_run) - self.check_deploy_redeploy_changes(dry_run, matcher) - - @mock.patch.object(task_object.DeployTask, 'init_with_data') - def test_env_redeploy_dry_run(self, m_init): - env_id = 42 - expected_uri = self.get_object_uri(self.res_uri, env_id, - '/changes/redeploy') - matcher = self.m_request.put(expected_uri, json={}) - - dry_run = True - - self.client.redeploy_changes(env_id, dry_run=dry_run) - self.check_deploy_redeploy_changes(dry_run, matcher) - - @mock.patch.object(task_object.DeployTask, 'init_with_data') - def test_env_redeploy_noop_run(self, m_init): - env_id = 42 - expected_uri = self.get_object_uri(self.res_uri, env_id, - '/changes/redeploy') - matcher = self.m_request.put(expected_uri, json={}) - - noop_run = True - - self.client.redeploy_changes(env_id, noop_run=noop_run) - self.check_deploy_redeploy_changes(noop_run, matcher, mode='noop_run') - - def test_env_reset(self): - env_id = 42 - force = False - expected_uri = self.get_object_uri(self.res_uri, env_id, '/reset/') - - matcher = self.m_request.put(expected_uri, json=utils.get_fake_task()) - - self.client.reset(env_id, force=force) - - self.assertTrue(matcher.called) - self.assertEqual(matcher.last_request.qs['force'][0], str(int(force))) - - def test_env_reset_force(self): - env_id = 42 - force = True - expected_uri = self.get_object_uri(self.res_uri, env_id, '/reset/') - - matcher = self.m_request.put(expected_uri, json=utils.get_fake_task()) - - self.client.reset(env_id, force=force) - - self.assertTrue(matcher.called) - self.assertEqual(matcher.last_request.qs['force'][0], str(int(force))) - - @mock.patch.object(base_object.BaseObject, 'init_with_data') - def test_env_update(self, m_init): - env_id = 42 - expected_uri = self.get_object_uri(self.res_uri, env_id) - - get_matcher = self.m_request.get(expected_uri, json=self.fake_env) - upd_matcher = self.m_request.put(expected_uri, json=self.fake_env) - - self.client.update(env_id, name="new_name") - - self.assertTrue(expected_uri, get_matcher.called) - self.assertTrue(expected_uri, upd_matcher.called) - - req_data = upd_matcher.last_request.json() - self.assertEqual('new_name', req_data['name']) - - def test_env_update_wrong_attribute(self): - env_id = 42 - self.assertRaises(error.BadDataException, - self.client.update, env_id, id=43) - - def test_env_add_nodes(self): - nodes = [25, 26] - roles = ['cinder', 'compute'] - env_id = 42 - - expected_body = [] - for n in nodes: - expected_body.append({'id': n, 'roles': roles}) - - expected_uri = self.get_object_uri(self.res_uri, - env_id, '/assignment/') - - matcher = self.m_request.post(expected_uri, json={}) - - self.client.add_nodes(env_id, nodes, roles) - - self.assertTrue(matcher.called) - - for assignment in matcher.last_request.json(): - # Check whether all assignments are expected - self.assertIn(assignment, expected_body) - - @mock.patch.object(fuelversion_object.FuelVersion, 'get_feature_groups') - def test_env_spawn_vms(self, m_feature_groups): - env_id = 10 - expected_uri = '/api/v1/clusters/{0}/spawn_vms/'.format(env_id) - m_feature_groups.return_value = \ - utils.get_fake_fuel_version()['feature_groups'] - - matcher = self.m_request.put(expected_uri, json={}) - - self.client.spawn_vms(env_id) - - self.assertTrue(matcher.called) - - def test_env_stop(self): - env_id = 42 - expected_uri = self.get_object_uri(self.res_uri, env_id, - '/stop_deployment/') - - matcher = self.m_request.put(expected_uri, json=utils.get_fake_task()) - - self.client.stop(env_id) - - self.assertTrue(matcher.called) - - def test_env_remove_nodes_by_id(self): - nodes = [25, 26] - env_id = 42 - - expected_body = [] - for n in nodes: - expected_body.append({'id': n}) - - expected_uri = self.get_object_uri(self.res_uri, - env_id, '/unassignment/') - - matcher = self.m_request.post(expected_uri, json={}) - - self.client.remove_nodes(env_id, nodes=nodes) - - self.assertTrue(matcher.called) - - for unassignment in matcher.last_request.json(): - # Check whether all unassignments are expected - self.assertIn(unassignment, expected_body) - - def test_env_remove_nodes_all(self): - nodes = [24, 25, 26] - env_id = 42 - - expected_body = [] - for n in nodes: - expected_body.append({'id': n}) - - fake_nodes = [utils.get_fake_node(node_name='node_' + str(n), - node_id=n, - cluster=env_id) for n in nodes] - - expected_uri = self.get_object_uri(self.res_uri, - env_id, '/unassignment/') - matcher_get = self.m_request.get( - '/api/v1/nodes/?cluster_id={}'.format(env_id), - json=fake_nodes - ) - matcher_post = self.m_request.post(expected_uri, json={}) - self.client.remove_nodes(env_id) - self.assertTrue(matcher_get.called) - self.assertTrue(matcher_post.called) - - for unassignment in matcher_post.last_request.json(): - # Check whether all unassignments are expected - self.assertIn(unassignment, expected_body) - - def test_env_deploy_nodes(self): - env_id = 42 - node_ids = [43, 44] - - expected_url = self.get_object_uri(self.res_uri, env_id, '/deploy/') - matcher = self.m_request.put(expected_url, json=utils.get_fake_task()) - - self.client.deploy_nodes(env_id, node_ids) - - self.assertTrue(matcher.called) - self.assertEqual([','.join(str(i) for i in node_ids)], - matcher.last_request.qs['nodes']) - - def test_env_deploy_nodes_force(self): - env_id = 42 - node_ids = [43, 44] - force = True - - expected_url = self.get_object_uri(self.res_uri, env_id, '/deploy/') - matcher = self.m_request.put(expected_url, json=utils.get_fake_task()) - - self.client.deploy_nodes(env_id, node_ids, force=force) - - self.assertTrue(matcher.called) - self.assertEqual([','.join(str(i) for i in node_ids)], - matcher.last_request.qs['nodes']) - self.assertEqual(matcher.last_request.qs['force'][0], str(int(force))) - - def test_env_deploy_nodes_noop_run(self): - env_id = 42 - node_ids = [43, 44] - noop_run = True - - expected_url = self.get_object_uri(self.res_uri, env_id, '/deploy/') - matcher = self.m_request.put(expected_url, json=utils.get_fake_task()) - - self.client.deploy_nodes(env_id, node_ids, noop_run=noop_run) - - self.assertTrue(matcher.called) - self.assertEqual([','.join(str(i) for i in node_ids)], - matcher.last_request.qs['nodes']) - self.assertEqual(matcher.last_request.qs['noop_run'][0], - str(int(noop_run))) - - def test_env_provision_nodes(self): - env_id = 42 - node_ids = [43, 44] - - expected_url = self.get_object_uri(self.res_uri, env_id, '/provision/') - matcher = self.m_request.put(expected_url, json=utils.get_fake_task()) - - self.client.provision_nodes(env_id, node_ids) - - self.assertTrue(matcher.called) - self.assertEqual([','.join(str(i) for i in node_ids)], - matcher.last_request.qs['nodes']) - - def test_env_network_verify(self): - env_id = 42 - fake_env = utils.get_fake_env(env_id=env_id) - test_conf = utils.get_fake_env_network_conf() - - env_uri = self.get_object_uri(self.res_uri, env_id) - download_uri = self.get_object_uri(self.res_uri, - env_id, - self.net_conf_uri) - verify_uri = self.get_object_uri(self.res_uri, - env_id, - self.net_verify_uri) - - m_get = self.m_request.get(env_uri, json=fake_env) - m_download = self.m_request.get(download_uri, json=test_conf) - m_verify = self.m_request.put(verify_uri, json=utils.get_fake_task()) - - self.client.verify_network(env_id) - - self.assertTrue(m_get.called) - self.assertTrue(m_download.called) - self.assertTrue(m_verify.called) - self.assertEqual(test_conf, m_verify.last_request.json()) - - def test_env_network_download(self): - env_id = 42 - fake_env = utils.get_fake_env(env_id=env_id) - env_uri = self.get_object_uri(self.res_uri, env_id) - download_uri = self.get_object_uri(self.res_uri, - env_id, - self.net_conf_uri) - test_conf = utils.get_fake_env_network_conf() - - m_get = self.m_request.get(env_uri, json=fake_env) - m_download = self.m_request.get(download_uri, json=test_conf) - - net_conf = self.client.get_network_configuration(env_id) - - self.assertEqual(test_conf, net_conf) - self.assertTrue(m_get.called) - self.assertTrue(m_download.called) - - def test_env_network_upload(self): - env_id = 42 - fake_env = utils.get_fake_env(env_id=env_id) - env_uri = self.get_object_uri(self.res_uri, env_id) - upload_uri = self.get_object_uri(self.res_uri, - env_id, - self.net_conf_uri) - test_conf = utils.get_fake_env_network_conf() - - m_get = self.m_request.get(env_uri, json=fake_env) - m_upload = self.m_request.put(upload_uri, json={}) - - self.client.set_network_configuration(env_id, test_conf) - - self.assertTrue(m_get.called) - self.assertTrue(m_upload.called) - self.assertEqual(test_conf, m_upload.last_request.json()) - - def test_env_settings_download(self): - env_id = 42 - download_uri = self.get_object_uri(self.res_uri, - env_id, - self.settings_uri) - test_settings = {'test-data': 42} - - m_download = self.m_request.get(download_uri, json=test_settings) - - settings = self.client.get_settings(env_id) - - self.assertEqual(test_settings, settings) - self.assertTrue(m_download.called) - - def test_env_settings_upload(self): - env_id = 42 - upload_uri = self.get_object_uri(self.res_uri, - env_id, - self.settings_uri) - test_settings = {'test-data': 42} - - m_upload = self.m_request.put(upload_uri, json={}) - - self.client.set_settings(env_id, test_settings) - - self.assertTrue(m_upload.called) - self.assertEqual(test_settings, m_upload.last_request.json()) - - def test_env_settings_upload_force(self): - env_id = 42 - upload_uri = self.get_object_uri(self.res_uri, - env_id, - self.settings_uri) - test_settings = {'test-data': 42} - - m_upload = self.m_request.put(upload_uri, json={}) - - self.client.set_settings(env_id, test_settings, force=True) - - self.assertTrue(m_upload.called) - self.assertEqual(test_settings, m_upload.last_request.json()) - self.assertEqual(['1'], m_upload.last_request.qs.get('force')) - - def test_delete_facts(self): - env_id = 42 - fact_type = 'deployment' - expected_uri = self.get_object_uri( - self.res_uri, - env_id, - '/orchestrator/{fact_type}/'.format(fact_type=fact_type)) - - matcher = self.m_request.delete(expected_uri, json={}) - self.client.delete_facts(env_id, fact_type) - self.assertTrue(matcher.called) - self.assertIsNone(matcher.last_request.body) - - def test_download_facts(self): - env_id = 42 - fact_type = 'deployment' - nodes = [2, 5] - expected_uri = self.get_object_uri( - self.res_uri, - env_id, - "/orchestrator/{fact_type}/?nodes={nodes}".format( - fact_type=fact_type, nodes=",".join(map(str, nodes)))) - fake_resp = {'foo': 'bar'} - - matcher = self.m_request.get(expected_uri, json=fake_resp) - facts = self.client.download_facts( - env_id, fact_type, nodes=nodes, default=False) - self.assertTrue(matcher.called) - self.assertIsNone(matcher.last_request.body) - self.assertEqual(facts, fake_resp) - - def test_upload_facts(self): - env_id = 42 - fact_type = 'deployment' - facts = {'foo': 'bar'} - expected_uri = self.get_object_uri( - self.res_uri, - env_id, - "/orchestrator/{fact_type}/".format(fact_type=fact_type)) - - matcher = self.m_request.put(expected_uri, json={}) - self.client.upload_facts(env_id, fact_type, facts) - self.assertTrue(matcher.called) - self.assertEqual(facts, matcher.last_request.json()) diff --git a/fuelclient/tests/unit/v2/lib/test_extension.py b/fuelclient/tests/unit/v2/lib/test_extension.py deleted file mode 100644 index 335a14f..0000000 --- a/fuelclient/tests/unit/v2/lib/test_extension.py +++ /dev/null @@ -1,83 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.tests import utils - - -class TestExtensionFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestExtensionFacade, self).setUp() - - self.version = 'v1' - self.res_uri = '/api/{version}/extensions/'.format( - version=self.version) - self.res_env_uri = '/api/{version}/clusters/'.format( - version=self.version) - self.fake_ext = ['fake_ext1'] - self.fake_extensions = utils.get_fake_extensions(10) - self.fake_env_extensions = utils.get_fake_env_extensions() - - self.client = fuelclient.get_client('extension', self.version) - - def test_extension_list(self): - matcher = self.m_request.get(self.res_uri, json=self.fake_extensions) - self.client.get_all() - - self.assertTrue(matcher.called) - - def test_env_extension_list(self): - env_id = 42 - expected_uri = self.get_object_uri(self.res_env_uri, env_id, - '/extensions/') - matcher = self.m_request.get(expected_uri, - json=self.fake_env_extensions) - extensions = self.client.get_by_id(env_id) - - self.assertTrue(matcher.called) - for ext in self.fake_env_extensions: - self.assertIn(ext, extensions['extensions']) - - def test_env_extension_enable(self): - env_id = 42 - fake_ext = ['enabled_fake_ext4'] - expected_uri = self.get_object_uri(self.res_env_uri, env_id, - '/extensions/') - put_matcher = self.m_request.put(expected_uri, - json=self.fake_env_extensions) - - self.client.enable_extensions(env_id, fake_ext) - - self.assertTrue(put_matcher.called) - self.assertIn(fake_ext[0], put_matcher.last_request.json()) - - def test_env_extension_disable(self): - env_id = 42 - expected_uri = self.get_object_uri( - self.res_env_uri, - env_id, - '/extensions/?extension_names={0}'.format( - ','.join(self.fake_env_extensions))) - - delete_matcher = self.m_request.delete(expected_uri, - complete_qs=True, - json=self.fake_env_extensions) - - self.client.disable_extensions(env_id, self.fake_env_extensions) - - self.assertTrue(delete_matcher.called) diff --git a/fuelclient/tests/unit/v2/lib/test_fuel_version.py b/fuelclient/tests/unit/v2/lib/test_fuel_version.py deleted file mode 100644 index d18484b..0000000 --- a/fuelclient/tests/unit/v2/lib/test_fuel_version.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.tests import utils - - -class TestFuelVersionFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestFuelVersionFacade, self).setUp() - - self.version = 'v1' - self.res_uri = '/api/{version}/version/'.format(version=self.version) - - self.fake_version = utils.get_fake_fuel_version() - - self.client = fuelclient.get_client('fuel-version', self.version) - - def test_fuel_version(self): - matcher = self.m_request.get(self.res_uri, json=self.fake_version) - - self.client.get_all() - - self.assertTrue(matcher.called) diff --git a/fuelclient/tests/unit/v2/lib/test_health.py b/fuelclient/tests/unit/v2/lib/test_health.py deleted file mode 100644 index c9ebb4d..0000000 --- a/fuelclient/tests/unit/v2/lib/test_health.py +++ /dev/null @@ -1,292 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Vitalii Kulanov -# -# Licensed 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 mock - -import fuelclient -from fuelclient.cli import error -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.tests import utils - - -class TestHealthFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestHealthFacade, self).setUp() - - self.version = 'v1' - self.res_uri = '/ostf/' - self.fake_test_sets = utils.get_fake_test_sets(10) - self.fake_test_sets_items = utils.get_fake_test_set_items(10) - - self.client = fuelclient.get_client('health', self.version) - - def test_health_list_for_cluster(self): - cluster_id = 65 - expected_uri = self.res_uri + 'testsets/{0}/'.format(cluster_id) - matcher = self.m_request.get(expected_uri, json=self.fake_test_sets) - - data = self.client.get_all(cluster_id) - - self.assertTrue(matcher.called) - self.assertEqual(len(data), 10) - - def test_health_status_list(self): - expected_uri = self.res_uri + 'testruns/' - matcher = self.m_request.get(expected_uri, - json=self.fake_test_sets_items) - - data = self.client.get_status_all() - - self.assertTrue(matcher.called) - self.assertEqual(len(data), 10) - - def test_health_status_list_for_cluster(self): - cluster_id = 32 - expected_uri = self.res_uri + 'testruns/' - fake_test_sets_items = [ - utils.get_fake_test_set_item(testset_id=12, cluster_id=cluster_id), - utils.get_fake_test_set_item(testset_id=13, cluster_id=cluster_id), - utils.get_fake_test_set_item(testset_id=14, cluster_id=35) - ] - matcher = self.m_request.get(expected_uri, - json=fake_test_sets_items) - - data = self.client.get_status_all(cluster_id) - - self.assertTrue(matcher.called) - self.assertEqual(len(data), 2) - - def test_health_status_show(self): - testrun_id = 65 - cluster_id = 32 - fake_test_set_item = utils.get_fake_test_set_item( - testset_id=testrun_id, cluster_id=cluster_id) - expected_uri = self.get_object_uri(self.res_uri + 'testruns/', - testrun_id) - matcher = self.m_request.get(expected_uri, - json=fake_test_set_item) - - data = self.client.get_status_single(testrun_id) - - self.assertTrue(matcher.called) - self.assertEqual(testrun_id, data["id"]) - self.assertEqual(cluster_id, data["cluster_id"]) - - def test_health_status_show_non_existing_testrun(self): - testrun_id = 65 - expected_uri = self.get_object_uri(self.res_uri + 'testruns/', - testrun_id) - matcher = self.m_request.get(expected_uri, json={}) - - msg = "Test sets with id {id} does not exist".format(id=testrun_id) - self.assertRaisesRegexp(error.ActionException, - msg, - self.client.get_status_single, - testrun_id) - self.assertTrue(matcher.called) - - @mock.patch('fuelclient.objects.Environment') - def test_health_start(self, m_env_obj): - cluster_id = 32 - cluster_state = 'operational' - test_sets = ['fake_test_set1', 'fake_test_set2'] - expected_uri = self.res_uri + 'testruns/' - type(m_env_obj.return_value).status = mock.PropertyMock( - return_value=cluster_state) - type(m_env_obj.return_value).is_customized = mock.PropertyMock( - return_value=False) - expected_body = [ - {'testset': test_sets[0], - 'metadata': {'cluster_id': cluster_id, 'config': {}}}, - {'testset': test_sets[1], - 'metadata': {'cluster_id': cluster_id, 'config': {}}} - ] - matcher = self.m_request.post(expected_uri, json=expected_body) - - data = self.client.start(cluster_id, - ostf_credentials={}, - test_sets=test_sets, - force=False) - self.assertTrue(matcher.called) - self.assertEqual(expected_body, matcher.last_request.json()) - self.assertEqual(data, matcher.last_request.json()) - - @mock.patch('fuelclient.objects.Environment') - def test_health_start_fail_not_allowed_env_status(self, m_env_obj): - cluster_id = 32 - cluster_state = 'new' - test_sets = ['fake_test_set1', 'fake_test_set2'] - type(m_env_obj.return_value).status = mock.PropertyMock( - return_value=cluster_state) - - msg = ("Environment is not ready to run health check " - "because it is in '{0}' state.".format(cluster_state)) - self.assertRaisesRegexp(error.EnvironmentException, - msg, - self.client.start, - cluster_id, - ostf_credentials={}, - test_sets=test_sets, - force=False) - - @mock.patch('fuelclient.objects.Environment') - def test_health_start_not_allowed_env_status_w_force(self, m_env_obj): - cluster_id = 32 - cluster_state = 'new' - test_sets = ['fake_test_set1', 'fake_test_set2'] - expected_uri = self.res_uri + 'testruns/' - type(m_env_obj.return_value).status = mock.PropertyMock( - return_value=cluster_state) - type(m_env_obj.return_value).is_customized = mock.PropertyMock( - return_value=False) - expected_body = [ - {'testset': test_sets[0], - 'metadata': {'cluster_id': cluster_id, 'config': {}}}, - {'testset': test_sets[1], - 'metadata': {'cluster_id': cluster_id, 'config': {}}} - ] - matcher = self.m_request.post(expected_uri, json=expected_body) - - data = self.client.start(cluster_id, - ostf_credentials={}, - test_sets=test_sets, - force=True) - self.assertTrue(matcher.called) - self.assertEqual(expected_body, matcher.last_request.json()) - self.assertEqual(data, matcher.last_request.json()) - - @mock.patch('fuelclient.objects.Environment') - def test_health_start_fail_customized_env(self, m_env_obj): - cluster_id = 32 - cluster_state = 'operational' - is_customized = True - test_sets = ['fake_test_set1', 'fake_test_set2'] - type(m_env_obj.return_value).status = mock.PropertyMock( - return_value=cluster_state) - type(m_env_obj.return_value).is_customized = mock.PropertyMock( - return_value=is_customized) - msg = ("Environment deployment facts were updated. " - "Health check is likely to fail because of that.") - self.assertRaisesRegexp(error.EnvironmentException, - msg, - self.client.start, - cluster_id, - ostf_credentials={}, - test_sets=test_sets, - force=False) - - @mock.patch('fuelclient.objects.Environment') - def test_health_start_customized_env_w_force(self, m_env_obj): - cluster_id = 32 - cluster_state = 'operational' - is_customized = True - test_sets = ['fake_test_set1', 'fake_test_set2'] - expected_uri = self.res_uri + 'testruns/' - type(m_env_obj.return_value).status = mock.PropertyMock( - return_value=cluster_state) - type(m_env_obj.return_value).is_customized = mock.PropertyMock( - return_value=is_customized) - expected_body = [ - {'testset': test_sets[0], - 'metadata': {'cluster_id': cluster_id, 'config': {}}}, - {'testset': test_sets[1], - 'metadata': {'cluster_id': cluster_id, 'config': {}}} - ] - matcher = self.m_request.post(expected_uri, json=expected_body) - - data = self.client.start(cluster_id, - ostf_credentials={}, - test_sets=test_sets, - force=True) - self.assertTrue(matcher.called) - self.assertEqual(expected_body, matcher.last_request.json()) - self.assertEqual(data, matcher.last_request.json()) - - @mock.patch('fuelclient.objects.Environment') - def test_health_start_w_ostf_credentials(self, m_env_obj): - cluster_id = 32 - cluster_state = 'operational' - is_customized = False - test_sets = ['fake_test_set1', 'fake_test_set2'] - ostf_credentials = { - 'username': 'admin', - 'password': 'admin', - 'tenant': 'admin' - } - expected_uri = self.res_uri + 'testruns/' - type(m_env_obj.return_value).status = mock.PropertyMock( - return_value=cluster_state) - type(m_env_obj.return_value).is_customized = mock.PropertyMock( - return_value=is_customized) - expected_body = [ - {'testset': test_sets[0], - 'metadata': { - 'ostf_os_access_creds': - {'ostf_os_username': 'admin', - 'ostf_os_tenant_name': 'admin', - 'ostf_os_password': 'admin'}, - 'cluster_id': cluster_id, - 'config': {}}}, - {'testset': test_sets[1], - 'metadata': { - 'ostf_os_access_creds': - {'ostf_os_username': 'admin', - 'ostf_os_tenant_name': 'admin', - 'ostf_os_password': 'admin'}, - 'cluster_id': cluster_id, - 'config': {}}} - ] - - matcher = self.m_request.post(expected_uri, json=expected_body) - - data = self.client.start(cluster_id, - ostf_credentials=ostf_credentials, - test_sets=test_sets, - force=False) - self.assertTrue(matcher.called) - self.assertEqual(expected_body, matcher.last_request.json()) - self.assertEqual(data, matcher.last_request.json()) - - def test_health_stop_action(self): - testrun_id = 65 - cluster_id = 32 - expected_uri = self.res_uri + 'testruns/' - fake_test_set_item = utils.get_fake_test_set_item( - testset_id=testrun_id, cluster_id=cluster_id) - matcher = self.m_request.put(expected_uri, - json=[fake_test_set_item]) - - data = self.client.action(testrun_id, action_status='stopped') - - self.assertTrue(matcher.called) - self.assertEqual(testrun_id, data["id"]) - self.assertEqual(cluster_id, data["cluster_id"]) - - def test_health_restart_action(self): - testrun_id = 65 - cluster_id = 32 - expected_uri = self.res_uri + 'testruns/' - fake_test_set_item = utils.get_fake_test_set_item( - testset_id=testrun_id, cluster_id=cluster_id) - matcher = self.m_request.put(expected_uri, - json=[fake_test_set_item]) - - data = self.client.action(testrun_id, action_status='restarted') - - self.assertTrue(matcher.called) - self.assertEqual(testrun_id, data["id"]) - self.assertEqual(cluster_id, data["cluster_id"]) diff --git a/fuelclient/tests/unit/v2/lib/test_network_group.py b/fuelclient/tests/unit/v2/lib/test_network_group.py deleted file mode 100644 index c3f6b22..0000000 --- a/fuelclient/tests/unit/v2/lib/test_network_group.py +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient -from fuelclient.cli import error -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.tests import utils - - -class TestNetworkGroupFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestNetworkGroupFacade, self).setUp() - - self.version = 'v1' - self.res_uri = '/api/{version}/networks/'.format(version=self.version) - - self.fake_network_group = utils.get_fake_network_group() - self.fake_network_groups = [utils.get_fake_network_group() - for i in range(10)] - - self.client = fuelclient.get_client('network-group') - - def test_network_group_list(self): - matcher = self.m_request.get( - self.res_uri, json=self.fake_network_groups) - - self.client.get_all() - self.assertTrue(matcher.called) - - def test_network_group_show(self): - expected_fields_names = ( - 'id', - 'name', - 'vlan_start', - 'cidr', - 'gateway', - 'group_id', - 'meta' - ) - net_id = 42 - uri = self.get_object_uri(self.res_uri, net_id) - - matcher = self.m_request.get( - uri, json=self.fake_network_group) - - data = self.client.get_by_id(net_id) - - self.assertTrue(matcher.called) - self.assertTrue(all(f in data for f - in expected_fields_names)) - - def test_network_group_create(self): - fake_ng = self.fake_network_group - matcher = self.m_request.post(self.res_uri, json=fake_ng) - - self.client.create( - name=fake_ng['name'], - release=fake_ng['release'], - vlan=fake_ng['vlan_start'], - cidr=fake_ng['cidr'], - gateway=fake_ng['gateway'], - group_id=fake_ng['group_id'], - meta=fake_ng['meta'], - ) - - req_data = matcher.last_request.json() - - self.assertTrue(matcher.called) - - self.assertEqual(req_data['name'], fake_ng['name']) - self.assertEqual(req_data['release'], fake_ng['release']) - self.assertEqual(req_data['vlan_start'], fake_ng['vlan_start']) - self.assertEqual(req_data['meta']['notation'], - fake_ng['meta']['notation']) - - def test_network_group_update(self): - net_id = 42 - uri = self.get_object_uri(self.res_uri, net_id) - - get_matcher = self.m_request.get(uri, json=self.fake_network_group) - put_matcher = self.m_request.put(uri, json=self.fake_network_group) - - self.client.update(net_id, name='new_name') - - self.assertTrue(get_matcher.called) - self.assertTrue(put_matcher.called) - - req_data = put_matcher.last_request.json() - self.assertEqual('new_name', req_data['name']) - - def test_network_group_update_wrong_attribute(self): - net_id = 42 - self.assertRaises(error.BadDataException, - self.client.update, net_id, vlan_start=42) - - def test_network_group_delete(self): - env_id = 42 - uri = self.get_object_uri(self.res_uri, env_id) - - matcher = self.m_request.delete(uri, json={}) - - self.client.delete_by_id(env_id) - - self.assertTrue(matcher.called) diff --git a/fuelclient/tests/unit/v2/lib/test_network_template.py b/fuelclient/tests/unit/v2/lib/test_network_template.py deleted file mode 100644 index 1acf44d..0000000 --- a/fuelclient/tests/unit/v2/lib/test_network_template.py +++ /dev/null @@ -1,78 +0,0 @@ -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock -import yaml - -from oslo_serialization import jsonutils as json - -import fuelclient -from fuelclient.tests.unit.common import \ - test_network_template as common_net_template -from fuelclient.tests.unit.v2.lib import test_api - - -class TestNetworkTemplateFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestNetworkTemplateFacade, self).setUp() - - self.version = 'v1' - self.env_id = 42 - self.res_uri = ( - '/api/{version}/clusters/{env_id}' - '/network_configuration/template'.format( - version=self.version, env_id=self.env_id)) - - self.client = fuelclient.get_client('environment', self.version) - - def test_network_template_upload(self): - expected_body = json.loads(common_net_template.JSON_TEMPLATE) - matcher = self.m_request.put( - self.res_uri, json=expected_body) - - m_open = mock.mock_open(read_data=common_net_template.YAML_TEMPLATE) - with mock.patch('fuelclient.cli.serializers.open', - m_open, create=True): - self.client.upload_network_template( - self.env_id, - 'fake_network_template_1.yaml' - ) - - m_open.assert_called_with('fake_network_template_1.yaml', 'r') - self.assertTrue(matcher.called) - self.assertEqual(expected_body, matcher.last_request.json()) - - def test_network_template_download(self): - expected_body = json.loads(common_net_template.JSON_TEMPLATE) - matcher = self.m_request.get(self.res_uri, json=expected_body) - - m_open = mock.mock_open() - with mock.patch('fuelclient.cli.serializers.open', - m_open, create=True): - self.client.download_network_template(self.env_id) - - self.assertTrue(matcher.called) - - written_yaml = yaml.safe_load(m_open().write.mock_calls[0][1][0]) - expected_yaml = yaml.safe_load(common_net_template.YAML_TEMPLATE) - self.assertEqual(written_yaml, expected_yaml) - - def test_network_template_delete(self): - matcher = self.m_request.delete(self.res_uri, json={}) - - self.client.delete_network_template(self.env_id) - - self.assertTrue(matcher.called) diff --git a/fuelclient/tests/unit/v2/lib/test_node.py b/fuelclient/tests/unit/v2/lib/test_node.py deleted file mode 100644 index 68f0609..0000000 --- a/fuelclient/tests/unit/v2/lib/test_node.py +++ /dev/null @@ -1,561 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 mock -import os -import yaml - -import fuelclient -from fuelclient.cli import error -from fuelclient.cli import serializers -from fuelclient.objects import base as base_object -from fuelclient.objects import fuelversion as fuelversion_object -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.tests import utils - - -class TestNodeFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestNodeFacade, self).setUp() - - self.version = 'v1' - self.res_uri = '/api/{version}/nodes/'.format(version=self.version) - - self.fake_node = utils.get_fake_node() - self.fake_nodes = [utils.get_fake_node() for _ in range(10)] - - self.client = fuelclient.get_client('node', self.version) - - def test_node_list(self): - matcher = self.m_request.get(self.res_uri, json=self.fake_nodes) - self.client.get_all() - - self.assertTrue(matcher.called) - - def test_node_list_with_labels(self): - labels = ['key1'] - fake_nodes = [ - utils.get_fake_node( - node_name='node_1', labels={'key1': 'val1'}), - utils.get_fake_node( - node_name='node_2', labels={'key2': 'val2'}), - utils.get_fake_node( - node_name='node_3', labels={'key1': 'val2', 'key3': 'val3'}) - ] - - matcher_get = self.m_request.get(self.res_uri, json=fake_nodes) - - data = self.client.get_all(labels=labels) - - self.assertTrue(matcher_get.called) - self.assertEqual(len(data), 2) - self.assertEqual(data[0]['name'], 'node_1') - self.assertEqual(data[1]['name'], 'node_3') - - def test_node_show(self): - node_id = 42 - expected_uri = self.get_object_uri(self.res_uri, node_id) - - matcher = self.m_request.get(expected_uri, json=self.fake_node) - - self.client.get_by_id(node_id) - - self.assertTrue(matcher.called) - - @mock.patch.object(fuelversion_object.FuelVersion, 'get_feature_groups') - def test_node_vms_list(self, m_feature_groups): - node_id = 42 - expected_uri = "/api/v1/nodes/{0}/vms_conf/".format(node_id) - m_feature_groups.return_value = \ - utils.get_fake_fuel_version()['feature_groups'] - - fake_vms = [{'id': 1, 'opt2': 'val2'}, - {'id': 2, 'opt4': 'val4'}] - matcher = self.m_request.get(expected_uri, json=fake_vms) - - self.client.get_node_vms_conf(node_id) - - self.assertTrue(matcher.called) - - @mock.patch.object(fuelversion_object.FuelVersion, 'get_feature_groups') - def test_node_vms_create(self, m_feature_groups): - config = [{'id': 1, 'opt2': 'val2'}, - {'id': 2, 'opt4': 'val4'}] - node_id = 42 - m_feature_groups.return_value = \ - utils.get_fake_fuel_version()['feature_groups'] - - expected_uri = "/api/v1/nodes/{0}/vms_conf/".format(node_id) - expected_body = {'vms_conf': config} - - matcher = self.m_request.put(expected_uri, json=expected_body) - - self.client.node_vms_create(node_id, config) - - self.assertTrue(matcher.called) - self.assertEqual(expected_body, matcher.last_request.json()) - - def test_node_set_hostname(self): - node_id = 42 - hostname = 'test-name' - data = {"hostname": hostname} - expected_uri = self.get_object_uri(self.res_uri, node_id) - - matcher = self.m_request.put(expected_uri, json=data) - - self.client.update(node_id, **data) - - self.assertTrue(matcher.called) - self.assertEqual(data, matcher.last_request.json()) - - def test_get_all_labels_for_all_nodes(self): - matcher = self.m_request.get(self.res_uri, json=self.fake_nodes) - self.client.get_all_labels_for_nodes() - - self.assertTrue(matcher.called) - - def test_set_labels_for_all_nodes(self): - labels = ['key_1=val_1', 'key_2=val_2', 'key_3 = val_4'] - data = {'labels': { - 'key_1': 'val_1', - 'key_2': 'val_2', - 'key_3': 'val_4' - }} - - expected_uri = self.get_object_uri(self.res_uri, 42) - - matcher_get = self.m_request.get(self.res_uri, json=self.fake_nodes) - matcher_put = self.m_request.put(expected_uri, json=data) - - self.client.set_labels_for_nodes(labels=labels) - - self.assertTrue(matcher_get.called) - self.assertTrue(matcher_put.called) - self.assertEqual(data, matcher_put.last_request.json()) - - def test_set_labels_for_specific_nodes(self): - labels = ['key_1=val_1', 'key_2=val_2', 'key_3 = val_4'] - node_ids = ['42'] - data = {'labels': { - 'key_1': 'val_1', - 'key_2': 'val_2', - 'key_3': 'val_4' - }} - expected_uri = self.get_object_uri(self.res_uri, 42) - - matcher_get = self.m_request.get(expected_uri, json=self.fake_node) - matcher_put = self.m_request.put(expected_uri, json=data) - - self.client.set_labels_for_nodes(labels=labels, node_ids=node_ids) - - self.assertTrue(matcher_get.called) - self.assertTrue(matcher_put.called) - self.assertEqual(data, matcher_put.last_request.json()) - - def test_set_labels_with_empty_key(self): - labels = ['key_1=val_1', ' = val_2', 'key_3 = '] - node_ids = ['42'] - - msg = 'Wrong label "{0}" was provided. Label key couldn\'t ' \ - 'be an empty string.'.format(labels[1]) - with self.assertRaisesRegexp(error.LabelEmptyKeyError, msg): - self.client.set_labels_for_nodes(labels=labels, node_ids=node_ids) - - def test_delete_specific_labels_for_all_nodes(self): - labels = ['key_1', ' key_3 '] - data = {'labels': {'key_2': None}} - expected_uri = self.get_object_uri(self.res_uri, 42) - - matcher_get = self.m_request.get(self.res_uri, json=self.fake_nodes) - matcher_put = self.m_request.put(expected_uri, json=data) - - self.client.delete_labels_for_nodes(labels=labels) - - self.assertTrue(matcher_get.called) - self.assertTrue(matcher_put.called) - self.assertEqual(data, matcher_put.last_request.json()) - - def test_delete_specific_labels_for_specific_nodes(self): - labels = ['key_2'] - node_ids = ['42'] - data = {'labels': {'key_1': 'val_1', 'key_3': 'val_3'}} - expected_uri = self.get_object_uri(self.res_uri, 42) - - matcher_get = self.m_request.get(expected_uri, json=self.fake_node) - matcher_put = self.m_request.put(expected_uri, json=data) - - self.client.delete_labels_for_nodes(labels=labels, node_ids=node_ids) - - self.assertTrue(matcher_get.called) - self.assertTrue(matcher_put.called) - self.assertEqual(data, matcher_put.last_request.json()) - - def test_delete_all_labels_for_all_nodes(self): - data = {'labels': {}} - expected_uri = self.get_object_uri(self.res_uri, 42) - - matcher_get = self.m_request.get(self.res_uri, json=self.fake_nodes) - matcher_put = self.m_request.put(expected_uri, json=data) - - self.client.delete_labels_for_nodes(labels=None) - - self.assertTrue(matcher_get.called) - self.assertTrue(matcher_put.called) - self.assertEqual(data, matcher_put.last_request.json()) - - def test_delete_all_labels_for_specific_nodes(self): - node_ids = ['42'] - data = {'labels': {}} - expected_uri = self.get_object_uri(self.res_uri, 42) - - matcher_get = self.m_request.get(expected_uri, json=self.fake_node) - matcher_put = self.m_request.put(expected_uri, json=data) - - self.client.delete_labels_for_nodes(labels=None, node_ids=node_ids) - - self.assertTrue(matcher_get.called) - self.assertTrue(matcher_put.called) - self.assertEqual(data, matcher_put.last_request.json()) - - def test_delete_labels_by_value(self): - labels = ['key_1=val_1', 'key_3=anothervalue', 'key_2'] - node_ids = ['42'] - result_labels = {'labels': {'key_3': 'val_3'}} - expected_uri = self.get_object_uri(self.res_uri, 42) - - self.m_request.get(expected_uri, json=self.fake_node) - matcher_put = self.m_request.put(expected_uri, json=self.fake_node) - - self.client.delete_labels_for_nodes( - labels=labels, node_ids=node_ids) - - self.assertTrue(matcher_put.called) - self.assertEqual(result_labels, matcher_put.last_request.json()) - - def test_delete_labels_by_value_with_whitespace(self): - labels = ['key_1 =val_1', 'key_3= anothervalue', 'key_2'] - node_ids = ['42'] - result_labels = {'labels': {'key_3': 'val_3'}} - expected_uri = self.get_object_uri(self.res_uri, 42) - - self.m_request.get(expected_uri, json=self.fake_node) - matcher_put = self.m_request.put(expected_uri, json=self.fake_node) - - self.client.delete_labels_for_nodes( - labels=labels, node_ids=node_ids) - - self.assertTrue(matcher_put.called) - self.assertEqual(result_labels, matcher_put.last_request.json()) - - def test_get_name_and_value_from_labels(self): - for label in ( - 'key=value', - ' key =value', - 'key= value ', - ' key = value ', - ): - name, value, has_separator = self.client._split_label(label) - self.assertEqual(name, 'key') - self.assertEqual(value, 'value') - self.assertTrue(has_separator) - - def test_get_name_and_empty_value_from_lables(self): - for label in ( - 'key=', - ' key =', - 'key= ', - ' key = ', - ): - name, value, has_separator = self.client._split_label(label) - self.assertEqual(name, 'key') - self.assertIsNone(value) - self.assertTrue(has_separator) - - def test_get_name_without_separator(self): - for label in ( - 'key', - ' key ', - ): - name, value, has_separator = self.client._split_label(label) - self.assertEqual(name, 'key') - self.assertIsNone(value) - self.assertFalse(has_separator) - - def test_label_with_many_separators(self): - label = 'key1= key2 = val2' - name, value, has_separator = self.client._split_label(label) - self.assertEqual(name, 'key1') - self.assertEqual(value, 'key2 = val2') - self.assertTrue(has_separator) - - def test_labels_after_delete(self): - all_labels = { - 'label_A': 'A', - 'label_B': None, - 'label_C': 'C', - 'label_D': None, - } - expected_labels = { - 'label_A': 'A', - 'label_D': None, - } - - for labels_to_delete in ( - ('label_B', 'label_C'), - (' label_B', 'label_C '), - ('label_B', 'label_C ', 'unknown_label'), - ('label_A = trololo', 'label_B=', 'label_C =C', 'label_D=value') - ): - result = self.client._labels_after_delete( - all_labels, labels_to_delete) - self.assertEqual(result, expected_labels) - - @mock.patch.object(base_object.BaseObject, 'init_with_data') - def test_node_update(self, m_init): - node_id = 42 - expected_uri = self.get_object_uri(self.res_uri, node_id) - - get_matcher = self.m_request.get(expected_uri, json=self.fake_node) - upd_matcher = self.m_request.put(expected_uri, json=self.fake_node) - - self.client.update(node_id, hostname="new-name") - - self.assertTrue(expected_uri, get_matcher.called) - self.assertTrue(expected_uri, upd_matcher.called) - - req_data = upd_matcher.last_request.json() - self.assertEqual('new-name', req_data['hostname']) - - def test_node_update_wrong_attribute(self): - node_id = 42 - self.assertRaises(error.BadDataException, - self.client.update, node_id, status=42) - - @mock.patch('fuelclient.objects.node.os.mkdir', mock.Mock()) - def test_node_attributes_download(self): - node_id = 42 - expected_uri = self.get_object_uri( - self.res_uri, node_id, '/attributes/') - fake_attributes = { - 'attribute_name': 'attribute_value' - } - - m_get = self.m_request.get(expected_uri, json=fake_attributes) - - m_open = mock.mock_open() - with mock.patch('fuelclient.cli.serializers.open', - m_open, create=True): - self.client.download_attributes(node_id, directory='/fake/dir') - - self.assertTrue(m_get.called) - m_open.assert_called_once_with( - '/fake/dir/node_{0}/attributes.yaml'.format(node_id), mock.ANY) - serializer = serializers.Serializer() - m_open().write.assert_called_once_with( - serializer.serialize(fake_attributes)) - - def test_node_disks_upload(self): - node_id = 42 - new_disks = {'test_key': u'test ☃ value'} - - node_uri = self.get_object_uri(self.res_uri, node_id) - disks_uri = os.path.join(node_uri, 'disks/') - - get_matcher = self.m_request.get(node_uri, json=self.fake_node) - upd_matcher = self.m_request.put(disks_uri, json={}) - - self.client.set_disks(node_id, new_disks) - - self.assertTrue(node_uri, get_matcher.called) - self.assertTrue(disks_uri, upd_matcher.called) - - req_data = upd_matcher.last_request.json() - self.assertEqual(new_disks, req_data) - - def test_node_disks_download(self): - node_id = 42 - fake_resp = {'test_key': u'test ☃ value'} - - node_uri = self.get_object_uri(self.res_uri, node_id) - disks_uri = os.path.join(node_uri, 'disks/') - - node_matcher = self.m_request.get(node_uri, json=self.fake_node) - disks_matcher = self.m_request.get(disks_uri, json=fake_resp) - - disks = self.client.get_disks(node_id) - - self.assertTrue(node_uri, node_matcher.called) - self.assertTrue(disks_uri, disks_matcher.called) - - self.assertEqual(disks, fake_resp) - - def test_node_disks_defaults(self): - node_id = 42 - fake_resp = {'test_key': u'test ☃ value'} - - node_uri = self.get_object_uri(self.res_uri, node_id) - disks_uri = os.path.join(node_uri, 'disks/defaults') - - node_matcher = self.m_request.get(node_uri, json=self.fake_node) - disks_matcher = self.m_request.get(disks_uri, json=fake_resp) - - disks = self.client.get_default_disks(node_id) - - self.assertTrue(node_uri, node_matcher.called) - self.assertTrue(disks_uri, disks_matcher.called) - - self.assertEqual(disks, fake_resp) - - @mock.patch('fuelclient.objects.node.os.path.exists', - mock.Mock(return_value=True)) - def test_node_attribute_upload(self): - node_id = 42 - expected_uri = self.get_object_uri( - self.res_uri, node_id, '/attributes/') - fake_attributes = { - 'attribute_name': 'attribute_value' - } - - m_put = self.m_request.put(expected_uri, json=fake_attributes) - - m_open = mock.mock_open(read_data=yaml.safe_dump(fake_attributes)) - with mock.patch('fuelclient.cli.serializers.open', - m_open, create=True): - self.client.upload_attributes(node_id, directory='/fake/dir') - - self.assertTrue(m_put.called) - m_open.assert_called_once_with( - '/fake/dir/node_{0}/attributes.yaml'.format(node_id), mock.ANY) - self.assertEqual(m_put.last_request.json(), fake_attributes) - m_open().read.assert_called_once_with() - - def test_node_interfaces_upload(self): - node_id = 42 - new_interfaces = {'test_key': u'test ☃ value'} - - node_uri = self.get_object_uri(self.res_uri, node_id) - interfaces_uri = os.path.join(node_uri, 'interfaces/') - - get_matcher = self.m_request.get(node_uri, json=self.fake_node) - upd_matcher = self.m_request.put(interfaces_uri, json={}) - - self.client.set_interfaces(node_id, new_interfaces) - - self.assertTrue(node_uri, get_matcher.called) - self.assertTrue(interfaces_uri, upd_matcher.called) - - req_data = upd_matcher.last_request.json() - self.assertEqual(new_interfaces, req_data) - - def test_node_interfaces_download(self): - node_id = 42 - fake_resp = {'test_key': u'test ☃ value'} - - node_uri = self.get_object_uri(self.res_uri, node_id) - interfaces_uri = os.path.join(node_uri, 'interfaces/') - - node_matcher = self.m_request.get(node_uri, json=self.fake_node) - interfaces_matcher = self.m_request.get(interfaces_uri, json=fake_resp) - - interfaces = self.client.get_interfaces(node_id) - - self.assertTrue(node_uri, node_matcher.called) - self.assertTrue(interfaces_uri, interfaces_matcher.called) - - self.assertEqual(interfaces, fake_resp) - - def test_node_interfaces_default(self): - node_id = 42 - fake_resp = {'test_key': u'test ☃ value'} - - node_uri = self.get_object_uri(self.res_uri, node_id) - interfaces_uri = os.path.join(node_uri, - 'interfaces/default_assignment') - - node_matcher = self.m_request.get(node_uri, json=self.fake_node) - interfaces_matcher = self.m_request.get(interfaces_uri, json=fake_resp) - - interfaces = self.client.get_default_interfaces(node_id) - - self.assertTrue(node_uri, node_matcher.called) - self.assertTrue(interfaces_uri, interfaces_matcher.called) - - self.assertEqual(interfaces, fake_resp) - - def test_undiscover_nodes_by_id_force(self): - node_id = 42 - expected_uri = '/api/v1/nodes/?ids={node_id}'.format(node_id=node_id) - request_url = self.get_object_uri(self.res_uri, node_id) - - node_matcher = self.m_request.get(request_url, json=self.fake_node) - matcher = self.m_request.delete(expected_uri, json={}) - - self.client.undiscover_nodes(node_id=node_id, force=True) - - self.assertTrue(matcher.called) - self.assertTrue(node_matcher.called) - self.assertEqual([str(node_id)], matcher.last_request.qs.get('ids')) - - def test_undiscover_nodes_by_id(self): - node_id = 42 - expected_uri = self.get_object_uri(self.res_uri, node_id) - node_matcher = self.m_request.get(expected_uri, json=self.fake_node) - - self.assertRaises(error.ActionException, - self.client.undiscover_nodes, - node_id=node_id, force=False) - self.assertTrue(node_matcher.called) - - def test_undiscover_nodes_by_env_force(self): - env_id = 24 - node_ids = ['42', '43', '44'] - expected_uri = '/api/v1/nodes/?ids={node_ids}'.format( - node_ids=','.join(node_ids)) - fake_nodes = [utils.get_fake_node(node_name='node_' + n_id, - node_id=n_id, - cluster=env_id) for n_id in node_ids] - - nodes_matcher = self.m_request.get(self.res_uri, json=fake_nodes) - matcher = self.m_request.delete(expected_uri, json={}) - - self.client.undiscover_nodes(env_id=env_id, node_id=None, force=True) - - self.assertTrue(matcher.called) - self.assertTrue(nodes_matcher.called) - self.assertEqual([','.join(node_ids)], - matcher.last_request.qs.get('ids')) - - def test_undiscover_nodes_by_env(self): - env_id = 24 - node_ids = ['42', '43', '44'] - fake_nodes = [utils.get_fake_node(node_name='node_' + n_id, - node_id=n_id, - cluster=env_id) for n_id in node_ids] - nodes_matcher = self.m_request.get(self.res_uri, json=fake_nodes) - - self.assertRaises(error.ActionException, - self.client.undiscover_nodes, - env_id=env_id, node_id=None, force=False) - self.assertTrue(nodes_matcher.called) - - def test_undiscover_nodes_w_wrong_params(self): - env_id = None - node_id = None - - self.assertRaises(ValueError, - self.client.undiscover_nodes, - env_id=env_id, node_id=node_id, force=False) diff --git a/fuelclient/tests/unit/v2/lib/test_openstack_config.py b/fuelclient/tests/unit/v2/lib/test_openstack_config.py deleted file mode 100644 index 7108239..0000000 --- a/fuelclient/tests/unit/v2/lib/test_openstack_config.py +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 mock -import yaml - -import fuelclient -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.tests import utils - - -class TestOpenstackConfigClient(test_api.BaseLibTest): - - def setUp(self): - super(TestOpenstackConfigClient, self).setUp() - - self.version = 'v1' - self.uri = '/api/{version}/openstack-config/'.format( - version=self.version) - - self.client = fuelclient.get_client('openstack-config', self.version) - - def test_config_list_for_cluster(self): - cluster_id = 1 - fake_configs = [ - utils.get_fake_openstack_config(cluster_id=cluster_id) - ] - - uri = self.uri + '?cluster_id={0}&is_active=True'.format(cluster_id) - m_get = self.m_request.get(uri, complete_qs=True, json=fake_configs) - data = self.client.get_filtered(cluster_id=1) - - self.assertTrue(m_get.called) - self.assertEqual(data[0]['cluster_id'], cluster_id) - - def test_config_list_for_node(self): - cluster_id = 1 - fake_configs = [ - utils.get_fake_openstack_config( - cluster_id=cluster_id, node_id=22), - ] - - uri = self.uri + '?cluster_id={0}&node_ids=22' \ - '&is_active=True'.format(cluster_id) - m_get = self.m_request.get(uri, complete_qs=True, json=fake_configs) - data = self.client.get_filtered(cluster_id=1, node_ids=[22]) - - self.assertTrue(m_get.called) - self.assertEqual(data[0]['cluster_id'], cluster_id) - - def test_config_list_for_multinode(self): - cluster_id = 1 - fake_configs = [ - utils.get_fake_openstack_config( - cluster_id=cluster_id, node_id=22), - utils.get_fake_openstack_config( - cluster_id=cluster_id, node_id=44), - ] - - uri = self.uri + '?cluster_id={0}&node_ids=22,44' \ - '&is_active=True'.format(cluster_id) - m_get = self.m_request.get(uri, complete_qs=True, json=fake_configs) - data = self.client.get_filtered(cluster_id=1, node_ids=[22, 44]) - - self.assertTrue(m_get.called) - self.assertEqual(data[0]['cluster_id'], cluster_id) - - def test_config_download(self): - config_id = 42 - uri = self.uri + '{0}/'.format(42) - fake_config = utils.get_fake_openstack_config(id=config_id) - - m_get = self.m_request.get(uri, json=fake_config) - - m_open = mock.mock_open() - with mock.patch('fuelclient.cli.serializers.open', - m_open, create=True): - self.client.download(config_id, '/path/to/config') - - self.assertTrue(m_get.called) - written_yaml = yaml.safe_load(m_open().write.mock_calls[0][1][0]) - self.assertEqual(written_yaml, - {'configuration': fake_config['configuration']}) - - def test_config_upload(self): - cluster_id = 1 - fake_config = utils.get_fake_openstack_config( - cluster_id=cluster_id) - - m_post = self.m_request.post(self.uri, json=[fake_config]) - - m_open = mock.mock_open(read_data=yaml.safe_dump({ - 'configuration': fake_config['configuration'] - })) - with mock.patch( - 'fuelclient.cli.serializers.open', m_open, create=True), \ - mock.patch('os.path.exists', mock.Mock(return_value=True)): - self.client.upload('/path/to/config', cluster_id) - - self.assertTrue(m_post.called) - body = m_post.last_request.json() - self.assertEqual(body['cluster_id'], cluster_id) - self.assertNotIn('node_ids', body) - self.assertNotIn('node_role', body) - - def test_config_upload_multinode(self): - cluster_id = 1 - fake_configs = [ - utils.get_fake_openstack_config( - cluster_id=cluster_id, node_id=42), - utils.get_fake_openstack_config( - cluster_id=cluster_id, node_id=44) - ] - - m_post = self.m_request.post(self.uri, json=fake_configs) - - m_open = mock.mock_open(read_data=yaml.safe_dump({ - 'configuration': fake_configs[0]['configuration'] - })) - with mock.patch( - 'fuelclient.cli.serializers.open', m_open, create=True), \ - mock.patch('os.path.exists', mock.Mock(return_value=True)): - self.client.upload( - '/path/to/config', cluster_id, node_ids=[42, 44]) - - self.assertTrue(m_post.called) - body = m_post.last_request.json() - self.assertEqual(body['cluster_id'], cluster_id) - self.assertEqual(body['node_ids'], [42, 44]) - self.assertNotIn('node_role', body) - - def test_config_delete(self): - config_id = 42 - uri = self.uri + '{0}/'.format(config_id) - fake_config = utils.get_fake_openstack_config(id=config_id) - - m_del = self.m_request.delete(uri, json=fake_config) - - self.client.delete(config_id) - self.assertTrue(m_del.called) diff --git a/fuelclient/tests/unit/v2/lib/test_plugins.py b/fuelclient/tests/unit/v2/lib/test_plugins.py deleted file mode 100644 index 24681f9..0000000 --- a/fuelclient/tests/unit/v2/lib/test_plugins.py +++ /dev/null @@ -1,170 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 json - -from mock import mock - -import fuelclient -from fuelclient.cli import error -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.tests import utils - - -class TestPluginsFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestPluginsFacade, self).setUp() - - self.version = 'v1' - self.res_uri = '/api/{version}/plugins/'.format(version=self.version) - - self.fake_plugins = utils.get_fake_plugins(10) - - self.client = fuelclient.get_client('plugins', self.version) - - def test_plugins_list(self): - matcher = self.m_request.get(self.res_uri, json=self.fake_plugins) - self.client.get_all() - self.assertTrue(self.res_uri, matcher.called) - - def test_sync_plugins(self): - expected_uri = '/api/{version}/plugins/sync/'.format( - version=self.version - ) - matcher = self.m_request.post(expected_uri, json={}) - self.client.sync(None) - self.assertTrue(matcher.called) - self.assertIsNone(matcher.last_request.body) - - def test_sync_plugins_empty_ids(self): - expected_uri = '/api/{version}/plugins/sync/'.format( - version=self.version - ) - matcher = self.m_request.post(expected_uri, json={}) - self.client.sync([]) - self.assertTrue(matcher.called) - self.assertEqual([], matcher.last_request.json()['ids']) - - def test_sync_specified_plugins(self): - expected_uri = '/api/{version}/plugins/sync/'.format( - version=self.version - ) - ids = [1, 2] - matcher = self.m_request.post(expected_uri, json={}) - self.client.sync(ids=ids) - self.assertTrue(matcher.called) - self.assertEqual(ids, matcher.last_request.json()['ids']) - - -class TestPluginInstallFacade(TestPluginsFacade): - - def setUp(self): - super(TestPluginInstallFacade, self).setUp() - - self.m_exec = mock.patch.object(fuelclient.utils, 'exec_cmd') - self.m_is_master = mock.patch('fuelclient.objects.plugins.IS_MASTER', - True) - self.m_meta = mock.patch.object(fuelclient.utils, - 'glob_and_parse_yaml', - return_value=self.fake_plugins) - - self.m_file_exists = mock.patch.object(fuelclient.utils, - 'file_exists', - return_value=True) - - def exec_install(self, force=False): - path = '/path/to/plugin.rpm' - - post_matcher = self.m_request.post(self.res_uri, json={}) - get_matcher = self.m_request.get(self.res_uri, json={}) - put_matcher = None - - fake_plugin = self.fake_plugins[0] - if force: - put_uri = '/api/{version}/plugins/{id}'.format( - version=self.version, - id=fake_plugin['id']) - put_matcher = self.m_request.put(put_uri, json={}) - post_matcher = self.m_request.post(self.res_uri, json={ - 'message': json.dumps({'id': fake_plugin['id']}) - }, status_code=409) - m_name = mock.patch.object(fuelclient.objects.plugins.PluginV2, - 'name_from_file', - return_value=fake_plugin['name']) - m_version = mock.patch.object(fuelclient.objects.plugins.PluginV2, - 'version_from_file', - return_value=fake_plugin['version']) - - with m_name, m_version, self.m_is_master, self.m_meta, self.m_exec,\ - self.m_file_exists: - self.client.install(path, force) - - self.assertTrue(get_matcher.called) - self.assertTrue(post_matcher.called) - self.assertEqual(fake_plugin, - json.loads(post_matcher.last_request.body)) - if force: - self.assertTrue(put_matcher.called) - self.assertEqual(fake_plugin, - json.loads(put_matcher.last_request.body)) - - def test_install_plugin(self): - - self.exec_install() - - def test_install_plugin_force(self): - self.exec_install(True) - - def test_install_plugin_fail_not_master(self): - self.m_is_master = mock.patch('fuelclient.objects.plugins.IS_MASTER', - False) - self.assertRaises(error.WrongEnvironmentError, self.exec_install) - - def test_install_plugin_fail_file_not_exists(self): - self.m_file_exists = mock.patch.object(fuelclient.utils, - 'file_exists', - return_value=False) - self.assertRaises(error.BadDataException, self.exec_install) - - -class TestPluginRemoveFacade(TestPluginsFacade): - - def setUp(self): - super(TestPluginRemoveFacade, self).setUp() - - self.m_exec = mock.patch.object(fuelclient.utils, 'exec_cmd') - self.m_is_master = mock.patch('fuelclient.objects.plugins.IS_MASTER', - True) - - def exec_remove(self): - fake_plugin = self.fake_plugins[0] - expected_uri = '/api/{version}/plugins/{id}'.format( - version=self.version, id=fake_plugin['id']) - del_matcher = self.m_request.delete(expected_uri, json={}) - get_matcher = self.m_request.get(self.res_uri, json=self.fake_plugins) - with self.m_is_master, self.m_exec: - self.client.remove(fake_plugin['name'], fake_plugin['version']) - self.assertTrue(get_matcher.called) - self.assertTrue(del_matcher.called) - self.assertIsNone(del_matcher.last_request.body) - - def test_remove_plugin(self): - self.exec_remove() - - def test_remove_plugin_fail_not_master(self): - self.m_is_master = mock.patch('fuelclient.objects.plugins.IS_MASTER', - False) - self.assertRaises(error.WrongEnvironmentError, self.exec_remove) diff --git a/fuelclient/tests/unit/v2/lib/test_release.py b/fuelclient/tests/unit/v2/lib/test_release.py deleted file mode 100644 index e6afa63..0000000 --- a/fuelclient/tests/unit/v2/lib/test_release.py +++ /dev/null @@ -1,75 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 mock - -import fuelclient -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.tests import utils - - -class TestReleaseFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestReleaseFacade, self).setUp() - - self.version = 'v1' - self.res_uri = '/api/{version}/releases/'.format(version=self.version) - self.fake_releases = utils.get_fake_releases(10) - self.fake_release_components = utils.get_fake_release_components(10) - self.fake_attributes_metadata = utils.get_fake_attributes_metadata() - self.client = fuelclient.get_client('release', self.version) - - def test_release_list(self): - matcher = self.m_request.get(self.res_uri, json=self.fake_releases) - self.client.get_all() - self.assertTrue(matcher.called) - - def test_release_repos_list(self): - release_id = 42 - expected_uri = self.get_object_uri(self.res_uri, release_id, - '/attributes_metadata') - matcher = self.m_request.get(expected_uri, - json=self.fake_attributes_metadata) - self.client.get_attributes_metadata_by_id(release_id) - self.assertTrue(matcher.called) - - def test_release_repos_update(self): - release_id = 42 - expected_uri = self.get_object_uri(self.res_uri, release_id, - '/attributes_metadata') - m_put = self.m_request.put(expected_uri, - json=self.fake_attributes_metadata) - - m_open = mock.mock_open(read_data=self.fake_attributes_metadata) - with mock.patch('fuelclient.cli.serializers.open', - m_open, create=True): - self.client.update_attributes_metadata_by_id( - release_id=release_id, - data=self.fake_attributes_metadata - ) - self.assertTrue(m_put.called) - self.assertEqual(m_put.last_request.json(), - self.fake_attributes_metadata) - - def test_release_component_list(self): - release_id = 42 - expected_uri = self.get_object_uri(self.res_uri, release_id, - '/components') - matcher = self.m_request.get(expected_uri, - json=self.fake_release_components) - self.client.get_components_by_id(release_id) - self.assertTrue(matcher.called) diff --git a/fuelclient/tests/unit/v2/lib/test_role.py b/fuelclient/tests/unit/v2/lib/test_role.py deleted file mode 100644 index fcd8368..0000000 --- a/fuelclient/tests/unit/v2/lib/test_role.py +++ /dev/null @@ -1,160 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Vitalii Kulanov -# -# Licensed 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 fuelclient -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.tests import utils - - -class TestRoleFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestRoleFacade, self).setUp() - - self.version = 'v1' - self.role_name = 'fake_role' - self.fake_role = utils.get_fake_role(self.role_name) - self.fake_roles = utils.get_fake_roles(10) - - self.client = fuelclient.get_client('role', self.version) - - def get_uri(self, owner): - return '/api/{version}/{owner}/'.format(version=self.version, - owner=owner) - - def test_release_role_list(self): - owner, owner_id = 'releases', 42 - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/roles/') - matcher = self.m_request.get(expected_uri, json=self.fake_roles) - self.client.get_all(owner, owner_id) - - self.assertTrue(matcher.called) - - def test_cluster_role_list(self): - owner, owner_id = 'clusters', 42 - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/roles/') - matcher = self.m_request.get(expected_uri, json=self.fake_roles) - self.client.get_all(owner_type=owner, owner_id=owner_id) - - self.assertTrue(matcher.called) - - def test_release_role_download(self): - owner, owner_id = 'releases', 45 - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/roles/{}/'.format(self.role_name)) - role_matcher = self.m_request.get(expected_uri, json=self.fake_role) - - role = self.client.get_one(owner, owner_id, self.role_name) - - self.assertTrue(expected_uri, role_matcher.called) - self.assertEqual(role, self.fake_role) - - def test_cluster_role_download(self): - owner, owner_id = 'clusters', 45 - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/roles/{}/'.format(self.role_name)) - role_matcher = self.m_request.get(expected_uri, json=self.fake_role) - - role = self.client.get_one(owner, owner_id, self.role_name) - - self.assertTrue(expected_uri, role_matcher.called) - self.assertEqual(role, self.fake_role) - - def test_release_role_update(self): - owner, owner_id = 'releases', 45 - params = {"owner_type": owner, - "owner_id": owner_id, - "role_name": self.role_name} - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/roles/{}/'.format(self.role_name)) - upd_matcher = self.m_request.put(expected_uri, json=self.fake_role) - - self.client.update(self.fake_role, **params) - - self.assertTrue(upd_matcher.called) - self.assertEqual(self.fake_role, upd_matcher.last_request.json()) - - def test_cluster_role_update(self): - owner, owner_id = 'clusters', 45 - params = {"owner_type": owner, - "owner_id": owner_id, - "role_name": self.role_name} - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/roles/{}/'.format(self.role_name)) - upd_matcher = self.m_request.put(expected_uri, json=self.fake_role) - - self.client.update(self.fake_role, **params) - - self.assertTrue(upd_matcher.called) - self.assertEqual(self.fake_role, upd_matcher.last_request.json()) - - def test_release_role_create(self): - owner, owner_id = 'releases', 45 - params = {"owner_type": owner, - "owner_id": owner_id} - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/roles/') - post_matcher = self.m_request.post(expected_uri, json=self.fake_role) - - self.client.create(self.fake_role, **params) - - self.assertTrue(post_matcher.called) - self.assertEqual(self.fake_role, post_matcher.last_request.json()) - - def test_cluster_role_create(self): - owner, owner_id = 'clusters', 45 - params = {"owner_type": owner, - "owner_id": owner_id} - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/roles/') - post_matcher = self.m_request.post(expected_uri, json=self.fake_role) - - self.client.create(self.fake_role, **params) - - self.assertTrue(post_matcher.called) - self.assertEqual(self.fake_role, post_matcher.last_request.json()) - - def test_release_role_delete(self): - owner, owner_id = 'releases', 45 - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/roles/{}/'.format(self.role_name)) - delete_matcher = self.m_request.delete(expected_uri, json={}) - - self.client.delete(owner, owner_id, self.role_name) - - self.assertTrue(delete_matcher.called) - - def test_cluster_role_delete(self): - owner, owner_id = 'clusters', 45 - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/roles/{}/'.format(self.role_name)) - delete_matcher = self.m_request.delete(expected_uri, json={}) - - self.client.delete(owner, owner_id, self.role_name) - - self.assertTrue(delete_matcher.called) diff --git a/fuelclient/tests/unit/v2/lib/test_sequence.py b/fuelclient/tests/unit/v2/lib/test_sequence.py deleted file mode 100644 index 8cc40ab..0000000 --- a/fuelclient/tests/unit/v2/lib/test_sequence.py +++ /dev/null @@ -1,105 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient -from fuelclient.tests.unit.v2.lib import test_api - - -class TestDeploymentSequence(test_api.BaseLibTest): - - def setUp(self): - super(TestDeploymentSequence, self).setUp() - self.version = 'v1' - self.client = fuelclient.get_client('sequence', self.version) - self.env_id = 1 - self.sequence_body = { - 'id': 1, 'release_id': 1, 'name': 'test', - 'graphs': [{'type': 'graph1'}] - } - - def _check_sequence_object(self, sequence): - self.assertEqual(self.sequence_body, sequence) - - def test_create(self): - matcher_post = self.m_request.post( - '/api/v1/sequences/', json=self.sequence_body - ) - sequence = self.client.create(1, name='test', graph_types=['graph1']) - self.assertTrue(matcher_post.called) - self._check_sequence_object(sequence) - - def test_update(self): - matcher_put = self.m_request.put( - '/api/v1/sequences/1/', json=self.sequence_body - ) - sequence = self.client.update(1, name='test') - self.assertTrue(matcher_put.called) - self.assertEqual('{"name": "test"}', matcher_put.last_request.body) - self._check_sequence_object(sequence) - - def test_delete(self): - mathcher_delete = self.m_request.delete( - '/api/v1/sequences/1/', status_code=204 - ) - self.client.delete_by_id(1) - self.assertTrue(mathcher_delete.called) - - def test_get_one(self): - matcher_get = self.m_request.get( - '/api/v1/sequences/1/', json=self.sequence_body - ) - sequence = self.client.get_by_id(1) - self.assertTrue(matcher_get.called) - self.assertEqual('test', sequence['name']) - self.assertEqual('graph1', sequence['graphs']) - - def test_get_all(self): - matcher_get = self.m_request.get( - '/api/v1/sequences/?release=1', json=[self.sequence_body] - ) - sequences = self.client.get_all(release=1) - self.assertTrue(matcher_get.called) - self.assertEqual(1, len(sequences)) - self._check_sequence_object(sequences[0]) - - def test_execute(self): - self.m_request.get('/api/v1/nodes/?cluster_id=2', json=[]) - self.m_request.get('/api/v1/cluster/2', json={'id': 2}) - - matcher_post = self.m_request.post( - '/api/v1/sequences/1/execute/', json={'id': 10, 'cluster': 2} - ) - self.client.execute(1, 2, dry_run=True, noop_run=False) - self.assertTrue(matcher_post.called) - self.assertIn('"cluster": 2', matcher_post.last_request.body) - self.assertIn('"noop_run": false', matcher_post.last_request.body) - self.assertIn('"dry_run": true', matcher_post.last_request.body) - - def test_upload(self): - matcher_post = self.m_request.post( - '/api/v1/sequences/', json=self.sequence_body - ) - sequence = self.client.upload(1, self.sequence_body) - self.assertTrue(matcher_post.called) - self._check_sequence_object(sequence) - - def test_download(self): - matcher_get = self.m_request.get( - '/api/v1/sequences/1/', json=self.sequence_body - ) - sequence = self.client.download(1) - self.assertTrue(matcher_get.called) - self._check_sequence_object(sequence) diff --git a/fuelclient/tests/unit/v2/lib/test_snapshot.py b/fuelclient/tests/unit/v2/lib/test_snapshot.py deleted file mode 100644 index fae69bf..0000000 --- a/fuelclient/tests/unit/v2/lib/test_snapshot.py +++ /dev/null @@ -1,61 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Vitalii Kulanov -# -# Licensed 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 fuelclient -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.tests import utils - - -class TestSnapshotFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestSnapshotFacade, self).setUp() - - self.version = 'v1' - self.res_uri = '/api/{version}/logs/package'.format( - version=self.version) - self.client = fuelclient.get_client('snapshot', self.version) - self.fake_task = utils.get_fake_task() - - def test_snapshot_config_download(self): - fake_resp = {'test_key': 'test_value'} - expected_uri = '/api/{version}/logs/package/config/default/'.format( - version=self.version) - - matcher = self.m_request.get(expected_uri, json=fake_resp) - - conf = self.client.get_default_config() - self.assertTrue(matcher.called) - self.assertEqual(conf, fake_resp) - - def test_snapshot_create(self): - fake_config = {} - matcher = self.m_request.put(self.res_uri, json=self.fake_task) - - self.client.create_snapshot(fake_config) - - self.assertTrue(matcher.called) - self.assertEqual(fake_config, matcher.last_request.json()) - - def test_snapshot_create_w_config(self): - fake_config = {'key_value': 'data_value'} - - matcher = self.m_request.put(self.res_uri, json=self.fake_task) - - self.client.create_snapshot(fake_config) - - self.assertTrue(matcher.called) - self.assertEqual(fake_config, matcher.last_request.json()) diff --git a/fuelclient/tests/unit/v2/lib/test_tag.py b/fuelclient/tests/unit/v2/lib/test_tag.py deleted file mode 100644 index c49d445..0000000 --- a/fuelclient/tests/unit/v2/lib/test_tag.py +++ /dev/null @@ -1,160 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.tests import utils - - -class TestTagFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestTagFacade, self).setUp() - - self.version = 'v1' - self.tag_name = 'fake_tag' - self.fake_tag = utils.get_fake_tag(self.tag_name) - self.fake_tags = utils.get_fake_tags(10) - - self.client = fuelclient.get_client('tag', self.version) - - def get_uri(self, owner): - return '/api/{version}/{owner}/'.format(version=self.version, - owner=owner) - - def test_release_tag_list(self): - owner, owner_id = 'releases', 42 - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/tags/') - matcher = self.m_request.get(expected_uri, json=self.fake_tags) - self.client.get_all(owner, owner_id) - - self.assertTrue(matcher.called) - - def test_cluster_tag_list(self): - owner, owner_id = 'clusters', 42 - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/tags/') - matcher = self.m_request.get(expected_uri, json=self.fake_tags) - self.client.get_all(owner_type=owner, owner_id=owner_id) - - self.assertTrue(matcher.called) - - def test_release_tag_download(self): - owner, owner_id = 'releases', 45 - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/tags/{}/'.format(self.tag_name)) - tag_matcher = self.m_request.get(expected_uri, json=self.fake_tag) - - tag = self.client.get_tag(owner, owner_id, self.tag_name) - - self.assertTrue(expected_uri, tag_matcher.called) - self.assertEqual(tag, self.fake_tag) - - def test_cluster_tag_download(self): - owner, owner_id = 'clusters', 45 - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/tags/{}/'.format(self.tag_name)) - tag_matcher = self.m_request.get(expected_uri, json=self.fake_tag) - - tag = self.client.get_tag(owner, owner_id, self.tag_name) - - self.assertTrue(expected_uri, tag_matcher.called) - self.assertEqual(tag, self.fake_tag) - - def test_release_tag_update(self): - owner, owner_id = 'releases', 45 - params = {"owner_type": owner, - "owner_id": owner_id, - "tag_name": self.tag_name} - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/tags/{}/'.format(self.tag_name)) - upd_matcher = self.m_request.put(expected_uri, json=self.fake_tag) - - self.client.update(self.fake_tag, **params) - - self.assertTrue(upd_matcher.called) - self.assertEqual(self.fake_tag, upd_matcher.last_request.json()) - - def test_cluster_tag_update(self): - owner, owner_id = 'clusters', 45 - params = {"owner_type": owner, - "owner_id": owner_id, - "tag_name": self.tag_name} - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/tags/{}/'.format(self.tag_name)) - upd_matcher = self.m_request.put(expected_uri, json=self.fake_tag) - - self.client.update(self.fake_tag, **params) - - self.assertTrue(upd_matcher.called) - self.assertEqual(self.fake_tag, upd_matcher.last_request.json()) - - def test_release_tag_create(self): - owner, owner_id = 'releases', 45 - params = {"owner_type": owner, - "owner_id": owner_id} - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/tags/') - post_matcher = self.m_request.post(expected_uri, json=self.fake_tag) - - self.client.create(self.fake_tag, **params) - - self.assertTrue(post_matcher.called) - self.assertEqual(self.fake_tag, post_matcher.last_request.json()) - - def test_cluster_tag_create(self): - owner, owner_id = 'clusters', 45 - params = {"owner_type": owner, - "owner_id": owner_id} - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/tags/') - post_matcher = self.m_request.post(expected_uri, json=self.fake_tag) - - self.client.create(self.fake_tag, **params) - - self.assertTrue(post_matcher.called) - self.assertEqual(self.fake_tag, post_matcher.last_request.json()) - - def test_release_tag_delete(self): - owner, owner_id = 'releases', 45 - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/tags/{}/'.format(self.tag_name)) - delete_matcher = self.m_request.delete(expected_uri, json={}) - - self.client.delete(owner, owner_id, self.tag_name) - - self.assertTrue(delete_matcher.called) - - def test_cluster_tag_delete(self): - owner, owner_id = 'clusters', 45 - expected_uri = self.get_object_uri(self.get_uri(owner), - owner_id, - '/tags/{}/'.format(self.tag_name)) - delete_matcher = self.m_request.delete(expected_uri, json={}) - - self.client.delete(owner, owner_id, self.tag_name) - - self.assertTrue(delete_matcher.called) diff --git a/fuelclient/tests/unit/v2/lib/test_task.py b/fuelclient/tests/unit/v2/lib/test_task.py deleted file mode 100644 index fa8a161..0000000 --- a/fuelclient/tests/unit/v2/lib/test_task.py +++ /dev/null @@ -1,101 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.tests import utils - - -class TestTaskFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestTaskFacade, self).setUp() - - self.version = 'v1' - self.res_uri = '/api/{version}/transactions/'\ - .format(version=self.version) - - self.fake_task = utils.get_fake_task() - self.fake_tasks = [utils.get_fake_task() for _ in range(10)] - - self.client = fuelclient.get_client('task', self.version) - - def test_task_list(self): - - matcher = self.m_request.get(self.res_uri, json=self.fake_tasks) - - self.client.get_all() - - self.assertTrue(self.res_uri, matcher.called) - - def test_task_list_w_parameters(self): - env_id = 36 - statuses = ['ready', 'error'] - names = ['dump', 'provision'] - fake_tasks = [ - utils.get_fake_task(task_id=45, cluster=env_id, - status=statuses[0], name=names[0]), - utils.get_fake_task(task_id=46, cluster=env_id, - status=statuses[0], name=names[1]), - utils.get_fake_task(task_id=49, cluster=env_id, - status=[1], name=names[1]), - ] - params = ('?cluster_id={env_id}' - '&statuses={statuses}' - '&transaction_types={names}') - expected_url = self.res_uri + params.format( - env_id=env_id, - statuses=','.join(statuses), - names=','.join(names)) - - matcher = self.m_request.get(expected_url, json=fake_tasks) - - tasks = self.client.get_all(cluster_id=env_id, - statuses=statuses, - transaction_types=names) - - self.assertTrue(matcher.called) - self.assertEqual(3, len(tasks)) - - def test_task_show(self): - task_id = 42 - expected_uri = self.get_object_uri(self.res_uri, task_id) - - matcher = self.m_request.get(expected_uri, json=self.fake_task) - - self.client.get_by_id(task_id) - - self.assertTrue(matcher.called) - - def test_task_delete(self): - task_id = 42 - expected_uri = self.get_object_uri(self.res_uri, task_id) - matcher = self.m_request.delete(expected_uri, json=self.fake_task) - - self.client.delete_by_id(task_id, force=False) - - self.assertTrue(matcher.called) - self.assertEqual(['0'], matcher.last_request.qs.get('force')) - - def test_task_delete_force(self): - task_id = 42 - expected_uri = self.get_object_uri(self.res_uri, task_id) - matcher = self.m_request.delete(expected_uri, json=self.fake_task) - - self.client.delete_by_id(task_id, force=True) - - self.assertTrue(matcher.called) - self.assertEqual(['1'], matcher.last_request.qs.get('force')) diff --git a/fuelclient/tests/unit/v2/lib/test_task_additional_info.py b/fuelclient/tests/unit/v2/lib/test_task_additional_info.py deleted file mode 100644 index 758e4a8..0000000 --- a/fuelclient/tests/unit/v2/lib/test_task_additional_info.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 yaml - -import fuelclient -from fuelclient.tests.unit.v2.lib import test_api -from fuelclient.tests import utils - - -class TestTaskAdditionalInfoFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestTaskAdditionalInfoFacade, self).setUp() - - self.version = 'v1' - self.task_id = 42 - self.res_uri = ( - '/api/{version}/transactions/{task_id}/'.format( - version=self.version, task_id=self.task_id)) - - def _test_info_download(self, client_name, yaml_data, uri): - client = fuelclient.get_client(client_name, self.version) - expected_body = yaml.load(yaml_data) - matcher = self.m_request.get("{0}{1}".format(self.res_uri, uri), - json=expected_body) - result = client.download(self.task_id) - - self.assertTrue(matcher.called) - self.assertEqual(expected_body, result) - - def test_network_configuration_download(self): - self._test_info_download('network-configuration', - utils.get_fake_yaml_network_conf(), - 'network_configuration') - - def test_cluster_settings_download(self): - self._test_info_download('cluster-settings', - utils.get_fake_yaml_cluster_settings(), - 'settings') - - def test_deployment_info_download(self): - self._test_info_download('deployment-info', - utils.get_fake_yaml_deployment_info(), - 'deployment_info') diff --git a/fuelclient/tests/unit/v2/lib/test_vip.py b/fuelclient/tests/unit/v2/lib/test_vip.py deleted file mode 100644 index 9bfb4f8..0000000 --- a/fuelclient/tests/unit/v2/lib/test_vip.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 mock -import yaml - -import fuelclient -from fuelclient.tests.unit.v1.test_vip_action import MANY_VIPS_YAML -from fuelclient.tests.unit.v2.lib import test_api - - -class TestVipFacade(test_api.BaseLibTest): - - def setUp(self): - super(TestVipFacade, self).setUp() - - self.version = 'v1' - self.env_id = 42 - self.res_uri = ( - '/api/{version}/clusters/{env_id}' - '/network_configuration/ips/vips/'.format( - version=self.version, env_id=self.env_id)) - - self.client = fuelclient.get_client('vip', self.version) - - def test_vip_upload(self): - expected_body = yaml.load(MANY_VIPS_YAML) - matcher = self.m_request.put(self.res_uri, json=expected_body) - - m_open = mock.mock_open(read_data=MANY_VIPS_YAML) - with mock.patch('fuelclient.cli.serializers.open', - m_open, create=True): - with mock.patch('fuelclient.objects.environment.os') as env_os: - env_os.path.exists.return_value = True - self.client.upload(self.env_id, 'vips_1.yaml') - - self.assertTrue(matcher.called) - self.assertEqual(expected_body, matcher.last_request.json()) - - def test_vip_download(self): - expected_body = yaml.load(MANY_VIPS_YAML) - matcher = self.m_request.get(self.res_uri, json=expected_body) - - m_open = mock.mock_open() - with mock.patch('fuelclient.cli.serializers.open', - m_open, create=True): - self.client.download(self.env_id) - - self.assertTrue(matcher.called) - - written_yaml = yaml.safe_load(m_open().write.mock_calls[0][1][0]) - expected_yaml = yaml.safe_load(MANY_VIPS_YAML) - self.assertEqual(written_yaml, expected_yaml) - - def test_vip_create(self): - vip_kwargs = {'ip_addr': '127.0.0.1', 'vip_name': 'test', 'network': 1, - 'vip_namespace': 'test-namespace'} - request_post = self.m_request.post(self.res_uri, json={}) - self.client.create(self.env_id, **vip_kwargs) - self.assertTrue(request_post.called) - self.assertEqual(request_post.last_request.json(), vip_kwargs) diff --git a/fuelclient/tests/utils/__init__.py b/fuelclient/tests/utils/__init__.py deleted file mode 100644 index 94bb1d9..0000000 --- a/fuelclient/tests/utils/__init__.py +++ /dev/null @@ -1,92 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 fuelclient.tests.utils.random_data import random_string -from fuelclient.tests.utils.fake_additional_info \ - import get_fake_yaml_cluster_settings -from fuelclient.tests.utils.fake_additional_info \ - import get_fake_yaml_deployment_info -from fuelclient.tests.utils.fake_additional_info \ - import get_fake_yaml_network_conf -from fuelclient.tests.utils.fake_additional_info \ - import get_fake_env_network_conf -from fuelclient.tests.utils.fake_deployment_history \ - import get_fake_deployment_history -from fuelclient.tests.utils.fake_deployment_history \ - import get_fake_deployment_history_w_params -from fuelclient.tests.utils.fake_net_conf import get_fake_interface_config -from fuelclient.tests.utils.fake_net_conf import get_fake_network_config -from fuelclient.tests.utils.fake_network_group import get_fake_network_group -from fuelclient.tests.utils.fake_node import get_fake_node -from fuelclient.tests.utils.fake_env import get_fake_env -from fuelclient.tests.utils.fake_extension import get_fake_env_extensions -from fuelclient.tests.utils.fake_extension import get_fake_extension -from fuelclient.tests.utils.fake_extension import get_fake_extensions -from fuelclient.tests.utils.fake_fuel_version import get_fake_fuel_version -from fuelclient.tests.utils.fake_health import get_fake_test_set -from fuelclient.tests.utils.fake_health import get_fake_test_sets -from fuelclient.tests.utils.fake_health import get_fake_test_set_item -from fuelclient.tests.utils.fake_health import get_fake_test_set_items -from fuelclient.tests.utils.fake_task import get_fake_task -from fuelclient.tests.utils.fake_node_group import get_fake_node_group -from fuelclient.tests.utils.fake_node_group import get_fake_node_groups -from fuelclient.tests.utils.fake_openstack_config \ - import get_fake_openstack_config -from fuelclient.tests.utils.fake_plugin import get_fake_plugin -from fuelclient.tests.utils.fake_plugin import get_fake_plugins -from fuelclient.tests.utils.fake_release import get_fake_release -from fuelclient.tests.utils.fake_release import get_fake_releases -from fuelclient.tests.utils.fake_release import get_fake_attributes_metadata -from fuelclient.tests.utils.fake_release import get_fake_release_component -from fuelclient.tests.utils.fake_release import get_fake_release_components -from fuelclient.tests.utils.fake_role import get_fake_role -from fuelclient.tests.utils.fake_role import get_fake_roles -from fuelclient.tests.utils.fake_tag import get_fake_tag -from fuelclient.tests.utils.fake_tag import get_fake_tags - - -__all__ = (get_fake_deployment_history, - get_fake_deployment_history_w_params, - get_fake_yaml_cluster_settings, - get_fake_yaml_deployment_info, - get_fake_yaml_network_conf, - get_fake_env, - get_fake_env_network_conf, - get_fake_test_set, - get_fake_test_sets, - get_fake_test_set_item, - get_fake_test_set_items, - get_fake_release, - get_fake_releases, - get_fake_attributes_metadata, - get_fake_release_component, - get_fake_release_components, - get_fake_role, - get_fake_roles, - get_fake_fuel_version, - get_fake_interface_config, - get_fake_network_group, - get_fake_node, - get_fake_network_config, - get_fake_task, - random_string, - get_fake_node_group, - get_fake_node_groups, - get_fake_openstack_config, - get_fake_plugin, - get_fake_plugins, - get_fake_tag, - get_fake_tags) diff --git a/fuelclient/tests/utils/fake_additional_info.py b/fuelclient/tests/utils/fake_additional_info.py deleted file mode 100644 index 181918d..0000000 --- a/fuelclient/tests/utils/fake_additional_info.py +++ /dev/null @@ -1,97 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 yaml - - -CLUSTER_SETTINGS = '''--- - editable: - service_user: - name: - type: "hidden" - value: "fuel" - sudo: - type: "hidden" - value: "ALL=(ALL) NOPASSWD: ALL" - homedir: - type: "hidden" - value: "/var/lib/fuel" -''' - -DEPLOYMENT_INFO = '''--- -glance_glare: - user_password: yBw0bY60owLC1C0AplHpEiEX -user_node_name: Untitled (5e:89) -uid: '5' -aodh: - db_password: JnEjYacrjxU2TLdTUQE9LdKq - user_password: 8MhyQgtWjWkl0Dv1r1worTjK -mysql: - root_password: bQhzpWjWIOTHOwEA4qNI8X4K - wsrep_password: 01QSoq3bYHgA7oS0OPYQurgX -murano-cfapi: - db_password: hGrAhxUjv3kAPEjiV7uYNwgZ - user_password: 43x0pvQMXugwd8JBaRSQXX4l - enabled: false - rabbit_password: ZqTnnw7lsGQNOFJRN6pTaI8t -''' - -NETWORK_CONF = '''--- - vips: - vrouter_pub: - network_role: "public/vip" - ipaddr: "10.109.3.2" - namespace: "vrouter" - is_user_defined: false - vendor_specific: - iptables_rules: - ns_start: - - "iptables -t nat -A POSTROUTING -o <%INT%> -j MASQUERADE" -''' - - -def get_fake_yaml_cluster_settings(): - """Create a fake cluster settings - - Returns the serialized and parametrized representation of a dumped Fuel - Cluster Settings. Represents the average amount of data. - - """ - return CLUSTER_SETTINGS - - -def get_fake_yaml_deployment_info(): - """Create a fake cluster settings - - Returns the serialized and parametrized representation of a dumped Fuel - Deployment Info. Represents the average amount of data. - - """ - return DEPLOYMENT_INFO - - -def get_fake_yaml_network_conf(): - """Create a fake cluster settings - - Returns the serialized and parametrized representation of a dumped Fuel - Network Conf. Represents the average amount of data. - - """ - return NETWORK_CONF - - -def get_fake_env_network_conf(): - return yaml.load(get_fake_yaml_network_conf()) diff --git a/fuelclient/tests/utils/fake_deployment_history.py b/fuelclient/tests/utils/fake_deployment_history.py deleted file mode 100644 index a8d538d..0000000 --- a/fuelclient/tests/utils/fake_deployment_history.py +++ /dev/null @@ -1,156 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 itertools - - -def get_fake_deployment_history( - add_task_data=False, convert_legacy_fields=False, - include_summary=False): - """Create a fake deployment history. - - Returns the serialized and parametrized representation of a dumped Fuel - Deployment History. Represents the average amount of data. - - :param add_task_data: add task description to history records using - Fuel 10.0 history output format - :type add_task_data: bool - :param convert_legacy_fields: Fuel 9.0 output fields are renamed to 10.0 - if True - :type convert_legacy_fields: True - :returns: fake deployment fixtures - :rtype: list[dict] - """ - if add_task_data: - result = list(itertools.chain(*[[ - { - 'status': 'ready', - 'time_start': '2016-03-25T17:22:10.687135', - 'time_end': '2016-03-25T17:22:30.830701', - 'node_id': node_id, - 'task_name': 'controller-remaining-tasks', - 'type': 'puppet', - 'role': ['controller'], - 'version': '2.0.0', - 'parameters': { - 'puppet_manifest': '/etc/puppet/modules/osnailyfacter' - '/modular/globals/globals.pp', - 'puppet_modules': '/etc/puppet/modules', - 'timeout': 3600 - }, - }, - { - 'status': 'skipped', - 'time_start': '2016-03-25T17:23:37.313212', - 'time_end': '2016-03-25T17:23:37.313234', - 'node_id': node_id, - 'task_name': 'ironic-compute', - 'type': 'puppet', - 'role': ['controller'], - 'version': '2.0.0', - 'parameters': { - 'puppet_manifest': '/etc/puppet/modules/osnailyfacter' - '/modular/globals/globals.pp', - 'puppet_modules': '/etc/puppet/modules', - 'timeout': 3600 - } - }, - { - 'status': 'pending', - 'time_start': None, - 'node_id': node_id, - 'task_name': 'pending-task', - 'type': 'puppet', - 'role': ['controller'], - 'version': '2.0.0', - 'parameters': { - 'puppet_manifest': '/etc/puppet/modules/osnailyfacter' - '/modular/globals/globals.pp', - 'puppet_modules': '/etc/puppet/modules', - 'timeout': 3600 - } - } - ] for node_id in ['1', '2']])) - else: - result = list(itertools.chain(*[[ - { - 'status': 'ready', - 'time_start': '2016-03-25T17:22:10.687135', - 'time_end': '2016-03-25T17:22:30.830701', - 'node_id': node_id, - 'deployment_graph_task_name': 'controller-remaining-tasks', - }, - { - 'status': 'skipped', - 'time_start': '2016-03-25T17:23:37.313212', - 'time_end': '2016-03-25T17:23:37.313234', - 'node_id': node_id, - 'deployment_graph_task_name': 'ironic-compute' - }, - { - 'status': 'pending', - 'time_start': None, - 'node_id': node_id, - 'deployment_graph_task_name': 'pending-task' - } - ] for node_id in ['1', '2']])) - - if convert_legacy_fields: - for record in result: - record['task_name'] = record['deployment_graph_task_name'] - record.pop('deployment_graph_task_name', None) - if include_summary: - for record in result: - record['summary'] = '{}' - return result - - -def get_fake_deployment_history_w_params(): - return [ - { - 'task_name': 'controller-remaining-tasks', - 'task_parameters': 'parameters: {puppet_manifest: /etc/puppet/' - 'modules/osnailyfacter/modular/globals/' - 'globals.pp,\n puppet_modules: /etc/' - 'puppet/modules, timeout: 3600}\nrole: ' - '[controller]\ntype: puppet\nversion: 2.0.0' - '\n', - 'status_by_node': '1 - ready - 2016-03-25T17:22:10 - ' - '2016-03-25T17:22:30\n' - '2 - ready - 2016-03-25T17:22:10 - ' - '2016-03-25T17:22:30' - }, - { - 'task_name': 'pending-task', - 'task_parameters': 'parameters: {puppet_manifest: /etc/puppet/' - 'modules/osnailyfacter/modular/globals/' - 'globals.pp,\n puppet_modules: /etc/puppet' - '/modules, timeout: 3600}\nrole: ' - '[controller]\ntype: puppet\nversion: 2.0.0' - '\n', - 'status_by_node': '1 - pending - not started - not ended\n' - '2 - pending - not started - not ended' - }, - { - 'task_name': 'ironic-compute', - 'status_by_node': '1 - skipped - 2016-03-25T17:23:37 - ' - '2016-03-25T17:23:37\n2 - skipped - ' - '2016-03-25T17:23:37 - 2016-03-25T17:23:37', - 'task_parameters': 'parameters: {puppet_manifest: /etc/puppet/' - 'modules/osnailyfacter/modular/globals/' - 'globals.pp,\n puppet_modules: /etc/' - 'puppet/modules, timeout: 3600}\nrole: ' - '[controller]\ntype: puppet\nversion: 2.0.0\n'}, - ] diff --git a/fuelclient/tests/utils/fake_env.py b/fuelclient/tests/utils/fake_env.py deleted file mode 100644 index 200856a..0000000 --- a/fuelclient/tests/utils/fake_env.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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. - - -def get_fake_env(name=None, status=None, release_id=None, - fuel_version=None, env_id=None): - """Create a random fake environment - - Returns the serialized and parametrized representation of a dumped Fuel - environment. Represents the average amount of data. - - """ - return {'status': status or 'new', - 'is_customized': False, - 'release_id': release_id or 2, - 'name': name or 'fake_env', - 'fuel_version': fuel_version or '10.0', - 'id': env_id or 1, - 'changes': []} diff --git a/fuelclient/tests/utils/fake_extension.py b/fuelclient/tests/utils/fake_extension.py deleted file mode 100644 index eaa57f0..0000000 --- a/fuelclient/tests/utils/fake_extension.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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. - - -def get_fake_env_extensions(names=None): - """Create a list of fake extensions for particular env""" - - return names or ['fake_ext1', 'fake_ext2', 'fake_ext3'] - - -def get_fake_extension(name=None, version=None, provides=None, - description=None): - return {'name': name or 'fake_name', - 'version': version or 'fake_version', - 'provides': provides or ['fake_method_call'], - 'description': description or 'fake_description', - } - - -def get_fake_extensions(extension_count, **kwargs): - """Create a random fake list of extensions.""" - return [get_fake_extension(**kwargs) - for _ in range(extension_count)] diff --git a/fuelclient/tests/utils/fake_fuel_version.py b/fuelclient/tests/utils/fake_fuel_version.py deleted file mode 100644 index 97b8497..0000000 --- a/fuelclient/tests/utils/fake_fuel_version.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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. - - -def get_fake_fuel_version(): - """Creates a fake fuel version - - Returns the serialized and parametrized representation of a dumped Fuel - environment. Represents the average amount of data. - - """ - return {"api": "1", - "auth_required": True, - "feature_groups": ['advanced'], - "openstack_version": "newton-10.0", - "release": "10.0"} diff --git a/fuelclient/tests/utils/fake_health.py b/fuelclient/tests/utils/fake_health.py deleted file mode 100644 index 711ee24..0000000 --- a/fuelclient/tests/utils/fake_health.py +++ /dev/null @@ -1,70 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Vitalii Kulanov -# -# Licensed 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. - - -def get_fake_test_set(testset_id=None, name=None): - """Create a random fake test set for environment.""" - return { - "id": testset_id or "fake_test_set", - "name": name or "Fake tests. Duration 30 sec - 2 min" - } - - -def get_fake_test_sets(testsets_count, **kwargs): - """Create a random fake list of test sets for environment.""" - return [get_fake_test_set(**kwargs) - for _ in range(testsets_count)] - - -def get_fake_test_set_item(testset_id=None, testset=None, cluster_id=None, - status=None, tests=None): - """Create a random fake test set item.""" - return { - "id": testset_id or 45, - "testset": testset or "fake_test_set", - "cluster_id": cluster_id or 65, - "status": status or "finished", - "started_at": "2016-09-15 09:03:07.697393", - "ended_at": "2016-09-15 09:03:19.280296", - "tests": tests or [ - { - "status": "failure", - "taken": 1.0, - "testset": "fake_test_set", - "name": "Create fake instance", - "duration": "30 s.", - "message": "Fake test message", - "id": "fuel_health.tests.fake_test", - "description": "fake description" - }, - { - "status": "stopped", - "taken": 0.5, - "testset": "fake_test_set", - "name": "Check create, update and delete fake instance image", - "duration": "70 s.", - "message": "Can not set proxy for Health Check.", - "id": "fuel_health.tests.fake_test.test_update_fake_images", - "description": "fake description" - } - ] - } - - -def get_fake_test_set_items(items_count, **kwargs): - """Create a random fake list of test sets items.""" - return [get_fake_test_set_item(**kwargs) - for _ in range(items_count)] diff --git a/fuelclient/tests/utils/fake_net_conf.py b/fuelclient/tests/utils/fake_net_conf.py deleted file mode 100644 index 1cb6c85..0000000 --- a/fuelclient/tests/utils/fake_net_conf.py +++ /dev/null @@ -1,52 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 random - -from six import moves as six_moves - - -def get_fake_interface_config(iface=None, iface_id=None, state=None, mac=None, - iface_type=None, networks=None): - """Create a random fake interface configuration - - Returns the serialized and parametrized representation of a node's - interface configuration. Represents the average amount of data. - - """ - - return {"name": iface or "eth0", - "id": iface_id or random.randint(0, 1000), - "state": state or "unknown", - "mac": mac or "08:00:27:a4:01:6b", - "max_speed": 100, - "type": iface_type or "ether", - "current_speed": 100, - "assigned_networks": networks or [{"id": 1, - "name": "fuelweb_admin"}, - {"id": 3, - "name": "management"}, - {"id": 4, - "name": "storage"}, - {"id": 5, - "name": "fixed"}]} - - -def get_fake_network_config(iface_number): - """Creates a fake network configuration for a single node.""" - - return [get_fake_interface_config(iface='eth{0}'.format(i)) - for i in six_moves.range(iface_number)] diff --git a/fuelclient/tests/utils/fake_network_group.py b/fuelclient/tests/utils/fake_network_group.py deleted file mode 100644 index 2d2dab3..0000000 --- a/fuelclient/tests/utils/fake_network_group.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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. - - -def get_fake_network_group( - name=None, release=None, vlan=None, cidr=None, gateway=None, - group_id=None, meta=None, net_id=None): - """Create a random fake network group - - Returns the serialized and parametrized representation of a dumped Fuel - environment. Represents the average amount of data. - - """ - return { - 'name': name or 'testng', - 'release': release or 24, - 'vlan_start': vlan or 10, - 'cidr': cidr or '10.0.0.0/24', - 'gateway': gateway or '10.0.0.1', - 'group_id': group_id or 42, - 'meta': meta or {'notation': 'cidr'}, - 'id': net_id or 42, - } diff --git a/fuelclient/tests/utils/fake_node.py b/fuelclient/tests/utils/fake_node.py deleted file mode 100644 index ced8c8d..0000000 --- a/fuelclient/tests/utils/fake_node.py +++ /dev/null @@ -1,135 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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. - - -def get_fake_node(cluster=None, hostname=None, node_id=None, cpu_model=None, - roles=None, mac=None, memory_b=None, os_platform=None, - status=None, node_name=None, group_id=None, labels=None, - ip=None): - """Creates a fake node - - Returns the serialized and parametrized representation of a dumped Fuel - environment. Represents the average amount of data. - - """ - host_name = hostname or 'fake-node-42' - labels = labels or { - 'key_1': 'val_1', - 'key_2': None, - 'key_3': 'val_3' - } - - return {'name': node_name or host_name, - 'error_type': None, - 'cluster': cluster or 1, - 'id': node_id or 42, - 'ip': ip or '10.20.0.4', - 'kernel_params': None, - 'group_id': group_id or 1, - 'mac': mac or 'd6:11:3f:b0:f1:43', - 'manufacturer': 'VirtualBox', - 'online': True, - 'os_platform': os_platform or 'ubuntu', - 'pending_addition': False, - 'pending_deletion': False, - 'pending_roles': [], - 'platform_name': None, - 'progress': 100, - 'roles': roles or ['compute'], - 'status': status or 'ready', - 'hostname': host_name, - 'fqdn': '{hostname}.example.com'.format(hostname=host_name), - - 'meta': {'cpu': {'real': 0, - 'spec': [{'frequency': 2553, - 'model': cpu_model or 'Random CPU'}], - 'total': 1}, - - 'disks': [{'disk': 'disk/by-path/pci:00:0d.0-scsi-2:0:0', - 'extra': ['disk/by-id/scsi-SATA_VBOX_aef0bb5c', - 'disk/by-id/ata-VBOX_HARDDISK_VB37'], - 'model': 'VBOX HARDDISK', - 'name': 'sdc', - 'removable': '0', - 'size': 68718428160}, - - {'disk': 'disk/by-path/pci:0:0d.0-scsi-1:0:0:0', - 'extra': ['disk/by-id/scsi-SATA_VBOX_30fbc3bb', - 'disk/by-id/ata-VBOX_HARDD30fbc3bb'], - 'model': 'VBOX HARDDISK', - 'name': 'sdb', - 'removable': '0', - 'size': 68718428160}, - - {'disk': 'disk/by-path/pci:00:d.0-scsi-0:0:0:0', - 'extra': ['disk/by-id/scsi-SATA_VBOX-17e33653', - 'disk/by-id/ata-VBOX_HARDD17e33653'], - 'model': 'VBOX HARDDISK', - 'name': 'sda', - 'removable': '0', - 'size': 68718428160}], - - 'interfaces': [{'name': 'eth2', - 'current_speed': 100, - 'mac': '08:00:27:88:9C:46', - 'max_speed': 100, - 'state': 'unknown'}, - - {'name': 'eth1', - 'current_speed': 100, - 'mac': '08:00:27:24:BD:6D', - 'max_speed': 100, - 'state': 'unknown'}, - - {'name': 'eth0', - 'current_speed': 100, - 'mac': '08:00:27:C1:C5:72', - 'max_speed': 100, - 'state': 'unknown'}], - 'memory': {'total': memory_b or 1968627712}, - - 'system': {'family': 'Virtual Machine', - 'fqdn': host_name, - 'manufacturer': 'VirtualBox', - 'serial': '0', - 'version': '1.2'}}, - 'network_data': [{'brd': '192.168.0.255', - 'dev': 'eth0', - 'gateway': None, - 'ip': '192.168.0.2/24', - 'name': 'management', - 'netmask': '255.255.255.0', - 'vlan': 101}, - - {'brd': '192.168.1.255', - 'dev': 'eth0', - 'gateway': None, - 'ip': '192.168.1.2/24', - 'name': 'storage', - 'netmask': '255.255.255.0', - 'vlan': 102}, - - {'brd': '172.16.0.255', - 'dev': 'eth1', - 'gateway': '172.16.0.1', - 'ip': '172.16.0.3/24', - 'name': 'public', - 'netmask': '255.255.255.0', - 'vlan': None}, - - {'dev': 'eth0', - 'name': 'admin'}], - 'labels': labels} diff --git a/fuelclient/tests/utils/fake_node_group.py b/fuelclient/tests/utils/fake_node_group.py deleted file mode 100644 index 0f4a1be..0000000 --- a/fuelclient/tests/utils/fake_node_group.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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. - - -def get_fake_node_group(name=None, cluster_id=None, id=None): - """Create a random fake network node group - - Returns the serialized and parametrized representation of a dumped Fuel - nodegroup. Represents the average amount of data. - - """ - return { - 'name': name or 'testng', - 'id': id or 42, - 'cluster_id': cluster_id or 5, - } - - -def get_fake_node_groups(): - """Create a fake network node group list - - Returns the serialized and parametrized representation of a dumped Fuel - nodegroups list. - - """ - return [ - {"cluster_id": 1, "id": 1, "name": "default"}, - {"cluster_id": 1, "id": 2, "name": "custom-group"} - ] diff --git a/fuelclient/tests/utils/fake_openstack_config.py b/fuelclient/tests/utils/fake_openstack_config.py deleted file mode 100644 index 06360b5..0000000 --- a/fuelclient/tests/utils/fake_openstack_config.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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. - - -def get_fake_openstack_config( - id=None, config_type=None, cluster_id=None, node_id=None, - node_role=None, configuration=None): - config = { - 'id': id or 42, - 'is_active': True, - 'config_type': config_type or 'cluster', - 'cluster_id': cluster_id or 84, - 'node_id': node_id or None, - 'node_role': node_role or None, - 'configuration': configuration or { - 'nova_config': { - 'DEFAULT/debug': { - 'value': True, - }, - }, - 'keystone_config': { - 'DEFAULT/debug': { - 'value': True, - }, - }, - }, - } - return config diff --git a/fuelclient/tests/utils/fake_plugin.py b/fuelclient/tests/utils/fake_plugin.py deleted file mode 100644 index 0db9f54..0000000 --- a/fuelclient/tests/utils/fake_plugin.py +++ /dev/null @@ -1,49 +0,0 @@ -# -*- coding:utf8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 six -from six import moves as six_moves - - -def get_fake_plugin(**kwargs): - """Creates a fake plugin - - Returns the serialized and parametrized representation of a dumped Fuel - Plugin. Represents the average amount of data. - - """ - plugin = {'id': 1, - 'name': 'plugin_name', - 'title': 'plugin_title', - 'version': '1.0.0', - 'description': 'plugin_description', - 'authors': ['author1', 'author2'], - 'package_version': '3.0.0', - 'releases': [{'os': 'ubuntu', - 'version': 'liberty-8.0'}, - {'os': 'ubuntu', - 'version': 'mitaka-9.0'}], - 'is_hotpluggable': True} - for k, v in six.iteritems(kwargs): - if k in plugin: - plugin[k] = v - return plugin - - -def get_fake_plugins(plugins_number, **kwargs): - """Creates fake plugins list.""" - return [get_fake_plugin(plugin_id=i, **kwargs) - for i in six_moves.range(1, plugins_number + 1)] diff --git a/fuelclient/tests/utils/fake_release.py b/fuelclient/tests/utils/fake_release.py deleted file mode 100644 index 9a74649..0000000 --- a/fuelclient/tests/utils/fake_release.py +++ /dev/null @@ -1,129 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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. - - -def get_fake_attributes_metadata(repos=None): - return { - 'editable': { - 'repo_setup': { - 'repos': { - 'value': repos or [ - { - 'name': 'upstream', - 'type': 'deb', - 'uri': 'fake_upstream_uri', - 'suite': 'trusty', - 'section': 'main restricted', - 'priority': 1000 - }, - { - 'name': 'mos', - 'type': 'deb', - 'uri': 'fake_mos_uri', - 'suite': 'mos', - 'section': 'main restricted', - 'priority': 1050 - } - ] - } - } - } - } - - -def get_fake_release(release_id=None, name=None, state=None, - operating_system=None, version=None, repos=None): - """Create a random fake release - - Returns the serialized and parametrized representation of a dumped Fuel - release. Represents the average amount of data. - - """ - return { - 'id': release_id or 1, - 'name': name or 'Mitaka on Ubuntu 14.04', - 'state': state or 'available', - 'operating_system': operating_system or 'environment', - 'version': version or 'mitaka-9.0', - 'attributes_metadata': get_fake_attributes_metadata(repos=repos), - } - - -def get_fake_releases(release_count, **kwargs): - """Create a random fake release list.""" - return [get_fake_release(release_id=i, **kwargs) - for i in range(1, release_count + 1)] - - -def get_fake_release_component(name=None, requires=None, incompatible=None, - compatible=None, default=None): - """Create a random fake component of release - - Returns the serialized and parametrized representation of a dumped Fuel - component of release. Represents the average amount of data. - - """ - return { - 'name': name or 'network:neutron:ml2:vlan', - 'description': - 'dialog.create_cluster_wizard.network.neutron_vlan_description', - 'weight': 5, - 'requires': requires or [ - { - 'one_of': { - 'items': ['hypervisor:qemu'], - 'message': 'dialog.create_cluster_wizard.compute.' - 'vcenter_warning' - } - }, - { - 'one_of': { - 'items': ['network:neutron:ml2:dvs', - 'network:neutron:ml2:nsx'], - 'message': 'dialog.create_cluster_wizard.compute.' - 'vcenter_requires_network_backend', - 'message_invalid': 'dialog.create_cluster_wizard.compute.' - 'vcenter_requires_network_plugins' - } - } - ], - 'incompatible': incompatible or [ - {'message': 'dialog.create_cluster_wizard.network.vlan_tun_alert', - 'name': 'network:neutron:ml2:tun'} - ], - 'compatible': compatible or [ - {'name': 'network:neutron:core:ml2'}, - {'name': 'hypervisor:qemu'}, - {'name': 'hypervisor:vmware'}, - {'name': 'storage:block:lvm'}, - {'name': 'storage:block:ceph'}, - {'name': 'storage:object:ceph'}, - {'name': 'storage:ephemeral:ceph'}, - {'name': 'storage:image:ceph'}, - {'name': 'additional_service:sahara'}, - {'name': 'additional_service:murano'}, - {'name': 'additional_service:ceilometer'}, - {'name': 'additional_service:ironic'} - ], - 'default': default, - 'label': 'common.network.neutron_vlan', - } - - -def get_fake_release_components(component_count, **kwargs): - """Create a random fake list of release components.""" - return [get_fake_release_component(**kwargs) - for _ in range(component_count)] diff --git a/fuelclient/tests/utils/fake_role.py b/fuelclient/tests/utils/fake_role.py deleted file mode 100644 index d9d2d5b..0000000 --- a/fuelclient/tests/utils/fake_role.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Vitalii Kulanov -# -# Licensed 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. - - -def get_fake_role(name=None, meta=None, volumes_roles_mapping=None): - """Create a random fake role - - Returns the serialized and parametrized representation of a dumped Fuel - role. Represents the average amount of data. - - """ - return { - "name": name or "controller", - "meta": meta or { - "group": "base", - "name": "Controller", - "conflicts": ["compute", "ceph-osd"], - "description": "The Controller initiates orchestration activities " - "and provides an external API. Other components " - "like Glance (image storage), Keystone (identity " - "management), Horizon (OpenStack dashboard) and " - "Nova-Scheduler are installed on the controller " - "as well." - }, - "volumes_roles_mapping": volumes_roles_mapping or [ - {"id": "os", "allocate_size": "min"}, - {"id": "logs", "allocate_size": "min"}, - {"id": "image", "allocate_size": "all"}, - {"id": "mysql", "allocate_size": "min"}, - {"id": "horizon", "allocate_size": "min"} - ] - } - - -def get_fake_roles(role_count, **kwargs): - """Create a random fake list of roles.""" - return [get_fake_role(**kwargs) - for _ in range(role_count)] diff --git a/fuelclient/tests/utils/fake_tag.py b/fuelclient/tests/utils/fake_tag.py deleted file mode 100644 index d516b89..0000000 --- a/fuelclient/tests/utils/fake_tag.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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. - - -def get_fake_tag(tag_name=None, has_primary=False, owner_id=None, - owner_type=None): - """Create a random fake tag - - Returns the serialized and parametrized representation of a dumped Fuel - tag. Represents the average amount of data. - - """ - return { - "id": 1, - "tag": tag_name or "controller", - "has_primary": has_primary, - "owner_id": owner_id or 1, - "owner_type": owner_type or 'release' - } - - -def get_fake_tags(tag_count, **kwargs): - """Create a random fake list of tags.""" - return [get_fake_tag(**kwargs) for _ in range(tag_count)] diff --git a/fuelclient/tests/utils/fake_task.py b/fuelclient/tests/utils/fake_task.py deleted file mode 100644 index d1a3576..0000000 --- a/fuelclient/tests/utils/fake_task.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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. - - -def get_fake_task(task_id=None, status=None, name=None, - cluster=None, result=None, progress=None, - message=None, uuid=None): - """Create a fake task - - Returns the serialized and parametrized representation of a dumped Fuel - Task. Represents the average amount of data. - - """ - return {'status': status or 'running', - 'name': name or 'deploy', - 'id': task_id or 42, - 'uuid': uuid or '14474652-4f3e-4dc6-b2f3-5921b62b4a9e', - 'message': message or 'I am a human being!', - 'task_id': task_id or 42, - 'cluster': cluster or 34, - 'result': result or '', - 'progress': progress or 50} diff --git a/fuelclient/tests/utils/random_data.py b/fuelclient/tests/utils/random_data.py deleted file mode 100644 index 942e909..0000000 --- a/fuelclient/tests/utils/random_data.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2014 Mirantis, Inc. -# -# Licensed 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 random -import string - - -def random_string(lenght, prefix='', postfix='', charset=None): - """Returns a random string of the specified length - - :param length: The length of the resulting string. - :type lenght: int. - :param prefix: Prefix for the random string. - :type prefix: str, default: ''. - :param postfix: Postfix for the random string. - :type postfix: str, default ''. - :param charset: A set of characters to use for building random strings. - :type chartet: Iterable object. Default: ASCII letters and digits. - :return: str - - """ - charset = charset or string.ascii_letters + string.digits - base_length = lenght - (len(prefix) + len(postfix)) - - base = ''.join([str(random.choice(charset)) for i in range(base_length)]) - - return '{prefix}{base}{postfix}'.format(prefix=prefix, - postfix=postfix, - base=base) diff --git a/fuelclient/utils.py b/fuelclient/utils.py deleted file mode 100644 index 856f7ac..0000000 --- a/fuelclient/utils.py +++ /dev/null @@ -1,214 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 functools -import glob -import io -import os -import six -import subprocess -import sys -import yaml - -from distutils.version import StrictVersion -from fnmatch import fnmatch - -from fuelclient.cli import error - - -def _wait_and_check_exit_code(cmd, child): - """Wait for child and check it's exit code - - :param cmd: command - :param child: object which returned by subprocess.Popen - :raises: ExecutedErrorNonZeroExitCode - """ - child.wait() - exit_code = child.returncode - - if exit_code != 0: - raise error.ExecutedErrorNonZeroExitCode( - u'Shell command executed with "{0}" ' - 'exit code: {1} '.format(exit_code, cmd)) - - -def exec_cmd(cmd, cwd=None): - """Execute shell command logging. - - :param str cmd: shell command - :param str cwd: None is default - """ - child = subprocess.Popen( - cmd, stdout=None, - stderr=subprocess.STDOUT, - shell=True, - cwd=cwd) - - _wait_and_check_exit_code(cmd, child) - - -def exec_cmd_iterator(cmd): - """Execute command with logging. - :param cmd: shell command - :returns: generator where yeach item - is line from stdout - """ - child = subprocess.Popen( - cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=True) - - for line in child.stdout: - yield line - - _wait_and_check_exit_code(cmd, child) - - -def parse_yaml_file(path): - """Parses yaml - - :param str path: path to yaml file - :returns: deserialized file - """ - with io.open(path, encoding='utf-8') as f: - data = yaml.load(f) - - return data - - -def glob_and_parse_yaml(path): - """Parses yaml files by mask. - - :param str path: mask - :returns: iterator - """ - for f in glob.iglob(path): - yield parse_yaml_file(f) - - -def major_plugin_version(version): - """Retrieves major version. - "1.2.3" -> "1.2" - - :param str version: version - :returns: only major version - """ - version_tuple = StrictVersion(version).version - major = '.'.join(map(str, version_tuple[:2])) - - return major - - -def iterfiles(dir_path, file_pattern): - """Returns generator where each item is a path to file, that satisfies - file_patterns condtion - - :param dir_path: path to directory, e.g /etc/puppet/ - :param file_pattern: unix filepattern to match files - """ - for root, dirs, file_names in os.walk(dir_path, followlinks=True): - for file_name in file_names: - if fnmatch(file_name, file_pattern): - yield os.path.join(root, file_name) - - -def file_exists(path): - """Checks if file exists - - :param str path: path to the file - :returns: True if file is exist, Flase if is not - """ - return os.path.lexists(path) - - -def parse_to_list_of_dicts(items): - """Parse list of json strings to dictionaries - - :param list: list of dicts and json string - :returns" list of dictionaries - - """ - dict_list = [] - for item in items: - if isinstance(item, dict): - dict_list.append(item) - elif isinstance(item, list): - dict_list.extend(item) - else: - raise TypeError( - 'A dict or list instance expected: {0}'.format(item)) - return dict_list - - -def str_to_unicode(string): - """Normalize input string from command line to unicode standard. - - :param str string: string to normalize - :returns: normalized string - - """ - return string if six.PY3 else string.decode(sys.getfilesystemencoding()) - - -def find_exec(program): - """Tries to find an executable in PATHs. - - :param str program: Name of executable to find - """ - for path in os.getenv('PATH').split(os.pathsep): - path = path.strip('"') - candidate = os.path.join(path, program) - if os.path.isfile(candidate) and os.access(candidate, os.X_OK): - return candidate - - -def safe_deserialize(loader): - """Wrapper for deserializers. - - Exceptions are raising during deserialization will be transformed - into BadDataException - - :param loader: deserializer function - :return: wrapped loader - """ - @functools.wraps(loader) - def wrapper(data): - try: - return loader(data) - except (ValueError, TypeError, yaml.error.YAMLError) as e: - raise error.BadDataException('{0}: {1}' - ''.format(e.__class__.__name__, - six.text_type(e))) - return wrapper - - -def add_os_cli_parameters(parser): - parser.add_argument( - '--os-auth-url', metavar='', - help='Authentication URL, defaults to env[OS_AUTH_URL].') - - parser.add_argument( - '--os-tenant-name', metavar='', - help='Authentication tenant name, defaults to ' - 'env[OS_TENANT_NAME].') - - parser.add_argument( - '--os-username', metavar='', - help='Authentication username, defaults to env[OS_USERNAME].') - - parser.add_argument( - '--os-password', metavar='', - help='Authentication password, defaults to env[OS_PASSWORD].') diff --git a/fuelclient/v1/__init__.py b/fuelclient/v1/__init__.py deleted file mode 100644 index d103952..0000000 --- a/fuelclient/v1/__init__.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient.v1 import cluster_settings -from fuelclient.v1 import deployment_history -from fuelclient.v1 import deployment_info -from fuelclient.v1 import environment -from fuelclient.v1 import extension -from fuelclient.v1 import fuelversion -from fuelclient.v1 import graph -from fuelclient.v1 import health -from fuelclient.v1 import network_configuration -from fuelclient.v1 import network_group -from fuelclient.v1 import node -from fuelclient.v1 import openstack_config -from fuelclient.v1 import release -from fuelclient.v1 import role -from fuelclient.v1 import plugins -from fuelclient.v1 import sequence -from fuelclient.v1 import snapshot -from fuelclient.v1 import task -from fuelclient.v1 import tag -from fuelclient.v1 import vip - -# Please keeps the list in alphabetical order -__all__ = ('cluster_settings', - 'deployment_history', - 'deployment_info', - 'environment', - 'extension', - 'fuelversion', - 'graph', - 'health', - 'network_configuration', - 'network_group', - 'node', - 'openstack_config', - 'plugins', - 'release', - 'role', - 'sequence', - 'snapshot', - 'task', - 'tag', - 'vip') diff --git a/fuelclient/v1/base_v1.py b/fuelclient/v1/base_v1.py deleted file mode 100644 index 3639eba..0000000 --- a/fuelclient/v1/base_v1.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 abc - -import six - -from fuelclient import client - - -@six.add_metaclass(abc.ABCMeta) -class BaseV1Client(object): - - @abc.abstractproperty - def _entity_wrapper(self): - pass - - def __init__(self, connection=None): - if connection is None: - connection = client.DefaultAPIClient - self.connection = connection - - cls_wrapper = self.__class__._entity_wrapper - self._entity_wrapper = type( - cls_wrapper.__name__, - (cls_wrapper, ), - {'connection': self.connection} - ) - - def get_all(self, **kwargs): - filters = {} - for k, v in six.iteritems(kwargs): - if isinstance(v, list): - if v: - filters[k] = ','.join(str(s) for s in v) - elif v is not None: - filters[k] = str(v) - result = self._entity_wrapper.get_all_data(**filters) - - return result - - def get_by_id(self, entity_id): - obj = self._entity_wrapper(obj_id=entity_id) - - return obj.data diff --git a/fuelclient/v1/cluster_settings.py b/fuelclient/v1/cluster_settings.py deleted file mode 100644 index e5140de..0000000 --- a/fuelclient/v1/cluster_settings.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient import objects -from fuelclient.v1 import base_v1 - - -class ClusterSettingsClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.Task - - def download(self, transaction_id): - task = self._entity_wrapper(transaction_id) - return task.cluster_settings() - - -def get_client(connection): - return ClusterSettingsClient(connection) diff --git a/fuelclient/v1/deployment_history.py b/fuelclient/v1/deployment_history.py deleted file mode 100644 index dad4312..0000000 --- a/fuelclient/v1/deployment_history.py +++ /dev/null @@ -1,117 +0,0 @@ -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 collections import defaultdict - -import six -import yaml - -from fuelclient import objects -from fuelclient.v1 import base_v1 - - -class DeploymentHistoryClient(base_v1.BaseV1Client): - - class_api_path = "transactions/{transaction_id}/deployment_history/" - - history_records_keys = ("task_name", "node_id", "status", - "time_start", "time_end") - tasks_records_keys = ("task_name", "task_parameters", "status_by_node") - - _entity_wrapper = objects.Environment - - def get_all(self, transaction_id, nodes=None, statuses=None, - tasks_names=None, show_parameters=False, - include_summary=False): - parameters = { - 'statuses': statuses, - 'nodes': nodes, - 'tasks_names': tasks_names, - 'include_summary': (str(int(include_summary)),), - } - # remove unused parameters or parameters with empty list as value - parameters = {k: v for k, v in six.iteritems(parameters) - if v is not None and v} - # 'parameters': ['param1', 'param2'] --> 'parameters': 'param1,param2' - for k in parameters: - parameters[k] = ",".join(s for s in parameters[k]) - - history_with_tasks = self.connection.get_request( - self.class_api_path.format( - transaction_id=transaction_id, - ), params=parameters - ) - # rename legacy field for Fuel 9.0 - for record in history_with_tasks: - if 'deployment_graph_task_name' in record: - record['task_name'] = record['deployment_graph_task_name'] - record.pop('deployment_graph_task_name', None) - - # metadata for each task - tasks_parameters = defaultdict(dict) - # history records by task ID - history_records_by_task = defaultdict(list) - # history records in initial order - history_records = [] - # split keys to history- and task-specific - - for record in history_with_tasks: - task_name = record['task_name'] - if tasks_names and task_name not in tasks_names: - # API gave us a task, that we actually want to filter out - continue - history_record = {} - for key in record: - if key in self.history_records_keys or key == 'summary': - history_record[key] = record[key] - else: - tasks_parameters[task_name][key] = record[key] - if include_summary: - history_record['summary'] = history_record.get('summary', None) - history_records.append(history_record) - history_records_by_task[task_name].append(history_record) - - if show_parameters: - result = [] - for task_name, value in sorted(six.iteritems(tasks_parameters)): - statuses_by_node = [] - for record in history_records_by_task[task_name]: - time_start = record.get('time_start') - time_start = time_start.partition(u'.')[0] if time_start\ - else u'not started' - record['time_start'] = time_start - time_end = record.get('time_end') - time_end = time_end.partition(u'.')[0] if time_end \ - else u'not ended' - record['time_end'] = time_end - - statuses_by_node.append( - '{node_id} - {status} - {time_start} - {time_end}' - ''.format(**record) - ) - - result.append( - { - "task_name": task_name, - "task_parameters": yaml.safe_dump( - tasks_parameters[task_name]), - "status_by_node": '\n'.join(statuses_by_node) - } - ) - return result - else: - return history_records - - -def get_client(connection): - return DeploymentHistoryClient(connection) diff --git a/fuelclient/v1/deployment_info.py b/fuelclient/v1/deployment_info.py deleted file mode 100644 index 14555d1..0000000 --- a/fuelclient/v1/deployment_info.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient import objects -from fuelclient.v1 import base_v1 - - -class DeploymentInfoClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.Task - - def download(self, transaction_id): - task = self._entity_wrapper(transaction_id) - return task.deployment_info() - - -def get_client(connection): - return DeploymentInfoClient(connection) diff --git a/fuelclient/v1/environment.py b/fuelclient/v1/environment.py deleted file mode 100644 index 6b7725f..0000000 --- a/fuelclient/v1/environment.py +++ /dev/null @@ -1,189 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli import error -from fuelclient import objects -from fuelclient.v1 import base_v1 -from fuelclient.v1 import fuelversion - - -class EnvironmentClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.Environment - _updatable_attributes = ('name',) - - provision_nodes_url = 'clusters/{env_id}/provision/?nodes={nodes}' - deploy_nodes_url = ('clusters/{env_id}/deploy/?' - 'nodes={nodes}&force={force}&noop_run={noop_run}') - - def create(self, name, release_id, net_segment_type): - - supported_nst = ('gre', 'vlan', 'tun') - - if net_segment_type not in supported_nst: - msg = ('Network segmentation type should be one ' - 'of {0}'.format(' '.join(supported_nst))) - raise error.BadDataException(msg) - - env = self._entity_wrapper.create(name, release_id, net_segment_type) - - return env.data - - def update(self, environment_id, **kwargs): - allowed_changes = {} - extra_args = {} - - for i in kwargs: - if i in self._updatable_attributes: - allowed_changes[i] = kwargs[i] - else: - extra_args[i] = kwargs[i] - - if extra_args != {}: - msg = 'Only {0} are updatable'.format(self._updatable_attributes) - raise error.BadDataException(msg) - - env = self._entity_wrapper(obj_id=environment_id) - env.set(allowed_changes) - - return env.data - - def delete_by_id(self, environment_id): - env_obj = self._entity_wrapper(obj_id=environment_id) - env_obj.delete() - - def add_nodes(self, environment_id, nodes, roles): - env = self._entity_wrapper(obj_id=environment_id) - nodes = [objects.Node(obj_id=n_id) for n_id in nodes] - - env.assign(nodes, roles) - - def remove_nodes(self, environment_id, nodes=None): - """Remove nodes from environment. If nodes are empty list then - all nodes will be removed - - :param environment_id: Id of specific environment (cluster) - :type environment_id: int - :param nodes: List of node ids that should be removed - :type nodes: list - """ - env = self._entity_wrapper(obj_id=environment_id) - if nodes is not None: - env.unassign(nodes) - else: - env.unassign_all() - - def deploy_changes(self, environment_id, dry_run=False, noop_run=False): - env = self._entity_wrapper(obj_id=environment_id) - - deploy_task = env.deploy_changes(dry_run=dry_run, noop_run=noop_run) - return deploy_task.id - - def provision_nodes(self, environment_id, node_ids): - """Provision specified nodes for the specified environment.""" - - nodes = ','.join(str(i) for i in node_ids) - uri = self.provision_nodes_url.format(env_id=environment_id, - nodes=nodes) - return self.connection.put_request(uri, {}) - - def deploy_nodes(self, environment_id, node_ids, force=False, - noop_run=False): - """Deploy specified nodes for the specified environment.""" - - nodes = ','.join(str(i) for i in node_ids) - uri = self.deploy_nodes_url.format(env_id=environment_id, nodes=nodes, - force=int(force), - noop_run=int(noop_run)) - return self.connection.put_request(uri, {}) - - def redeploy_changes(self, environment_id, dry_run=False, noop_run=False): - env = self._entity_wrapper(obj_id=environment_id) - - redeploy_task = env.redeploy_changes(dry_run=dry_run, - noop_run=noop_run) - return redeploy_task.id - - def spawn_vms(self, environment_id): - env = self._entity_wrapper(obj_id=environment_id) - fuelversion.FuelVersionClient.check_advanced_feature() - return env.spawn_vms() - - def upload_network_template(self, environment_id, - file_path=None): - env = self._entity_wrapper(environment_id) - network_template_data = env.read_network_template_data_from_file( - file_path=file_path) - env.set_network_template_data(network_template_data) - - return file_path - - def download_network_template(self, environment_id, directory=None): - env = self._entity_wrapper(environment_id) - template_data = env.get_network_template_data() - file_path = env.write_network_template_data( - template_data, - directory=directory) - - return file_path - - def delete_network_template(self, environment_id): - env = self._entity_wrapper(environment_id) - env.delete_network_template_data() - - def get_network_configuration(self, environment_id): - env = self._entity_wrapper(environment_id) - return env.get_network_data() - - def set_network_configuration(self, environment_id, new_configuration): - env = self._entity_wrapper(environment_id) - env.set_network_data(new_configuration) - - def verify_network(self, environment_id): - """Start network verification for an environment.""" - - env = self._entity_wrapper(environment_id) - return env.verify_network() - - def get_settings(self, environment_id): - env = self._entity_wrapper(environment_id) - return env.get_settings_data() - - def set_settings(self, environment_id, new_configuration, force=False): - env = self._entity_wrapper(environment_id) - env.set_settings_data(new_configuration, force=force) - - def delete_facts(self, env_id, fact_type): - env = self._entity_wrapper(env_id) - return env.delete_facts(fact_type) - - def download_facts(self, env_id, fact_type, default=False, **kwargs): - env = self._entity_wrapper(env_id) - return env.get_facts(fact_type, default=default, **kwargs) - - def upload_facts(self, env_id, fact_type, facts): - env = self._entity_wrapper(env_id) - return env.upload_facts(fact_type, facts) - - def reset(self, env_id, force=False): - env = self._entity_wrapper(obj_id=env_id) - return env.reset(force) - - def stop(self, env_id): - env = self._entity_wrapper(obj_id=env_id) - return env.stop() - - -def get_client(connection): - return EnvironmentClient(connection) diff --git a/fuelclient/v1/extension.py b/fuelclient/v1/extension.py deleted file mode 100644 index e7e427e..0000000 --- a/fuelclient/v1/extension.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient import objects -from fuelclient.v1 import base_v1 - - -class ExtensionClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.Extension - - def get_by_id(self, environment_id): - ext_obj = self._entity_wrapper(environment_id) - return {'extensions': ', '.join(ext_obj.get_env_extensions())} - - def enable_extensions(self, environment_id, extensions): - ext_obj = self._entity_wrapper(environment_id) - return ext_obj.enable_env_extensions(extensions) - - def disable_extensions(self, environment_id, extensions): - ext_obj = self._entity_wrapper(environment_id) - return ext_obj.disable_env_extensions(extensions) - - -def get_client(connection): - return ExtensionClient(connection) diff --git a/fuelclient/v1/fuelversion.py b/fuelclient/v1/fuelversion.py deleted file mode 100644 index 3e8fd8a..0000000 --- a/fuelclient/v1/fuelversion.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli import error -from fuelclient import objects -from fuelclient.v1 import base_v1 - - -class FuelVersionClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.FuelVersion - - @classmethod - def check_advanced_feature(cls): - if 'advanced' not in cls._entity_wrapper.get_feature_groups(): - msg = "Advanced feature should be enabled in feature groups" - raise error.ActionException(msg) - - -def get_client(connection): - return FuelVersionClient(connection) diff --git a/fuelclient/v1/graph.py b/fuelclient/v1/graph.py deleted file mode 100644 index e87131f..0000000 --- a/fuelclient/v1/graph.py +++ /dev/null @@ -1,296 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 re -import six - -from fuelclient.cli import error -from fuelclient import objects -from fuelclient.v1 import base_v1 - - -class GraphClient(base_v1.BaseV1Client): - _entity_wrapper = objects.Environment - - related_graphs_list_api_path = "{related_model}/{related_model_id}" \ - "/deployment_graphs/" - - related_graph_api_path = "{related_model}/{related_model_id}" \ - "/deployment_graphs/{graph_type}" - - graphs_list_api = "graphs/" - cluster_deploy_api_path = "graphs/execute/" - - cluster_own_tasks_api_path = "clusters/{env_id}/deployment_tasks/own/" - - merged_cluster_tasks_api_path = "clusters/{env_id}/deployment_tasks/" - - merged_plugins_tasks_api_path = "clusters/{env_id}/deployment_tasks/" \ - "plugins/" - - cluster_release_tasks_api_path = "clusters/{env_id}/deployment_tasks/" \ - "release/" - - def update_graph_for_model( - self, data, related_model, related_model_id, graph_type): - return self.connection.put_request( - self.related_graph_api_path.format( - related_model=related_model, - related_model_id=related_model_id, - graph_type=graph_type), - data - ) - - def create_graph_for_model( - self, data, related_model, related_model_id, graph_type): - return self.connection.post_request( - self.related_graph_api_path.format( - related_model=related_model, - related_model_id=related_model_id, - graph_type=graph_type), - data - ) - - def get_graph_for_model( - self, related_model, related_model_id, graph_type): - return self.connection.get_request( - self.related_graph_api_path.format( - related_model=related_model, - related_model_id=related_model_id, - graph_type=graph_type)) - - def upload(self, data, related_model, related_id, graph_type): - # create or update - if not isinstance(data, dict): - data = {'tasks': data} - - method = self.update_graph_for_model - # FIXME(bgaifullin) need to remove loading whole graph only - # for detecting that it does not exist - try: - self.get_graph_for_model(related_model, related_id, graph_type) - except error.HTTPError as exc: - if '404' in exc.message: - method = self.create_graph_for_model - - # could accept {tasks: [], metadata: {}} or just tasks list - method(data, related_model, related_id, graph_type) - - def execute(self, env_id, nodes=None, graph_types=None, task_names=None, - subgraphs=None, **kwargs): - request_data = {'cluster': env_id} - - def map_args_to_graph_types(graph): - result = dict() - result['type'] = graph - if nodes: - result['nodes'] = nodes - if task_names: - result['tasks'] = task_names - return result - - def munge_subgraphs(subgraph): - regexp = re.compile("^([\w\-,]+(?:\/(?:(?:\d+(?:,|-)?)+))?)" - "?(:[\w\-,]+(?:\/(?:(?:\d+(?:,|-)?)+))?)?$") - result = regexp.match(subgraph) - start_vertex = None - end_vertex = None - if result: - if result.group(1): - start_vertex = result.group(1) - if result.group(2): - end_vertex = result.group(2)[1:] - return {'start': [start_vertex], 'end': [end_vertex]} - - if graph_types: - request_data['graphs'] = list(six.moves.map( - map_args_to_graph_types, graph_types - )) - - if subgraphs: - request_data['subgraphs'] = list( - six.moves.map(lambda s: munge_subgraphs(s), subgraphs)) - - request_data.update(kwargs) - - deploy_data = self.connection.post_request( - self.cluster_deploy_api_path, - request_data - ) - return objects.DeployTask.init_with_data(deploy_data) - - def get_merged_cluster_tasks(self, env_id, graph_type=None): - params = {} - if graph_type is not None: - params['graph_type'] = graph_type - - return self.connection.get_request( - self.merged_cluster_tasks_api_path.format(env_id=env_id), - params=params - ) - - def get_merged_plugins_tasks(self, env_id, graph_type=None): - params = {} - if graph_type is not None: - params['graph_type'] = graph_type - - return self.connection.get_request( - self.merged_plugins_tasks_api_path.format(env_id=env_id), - params=params - ) - - def get_release_tasks_for_cluster(self, env_id, graph_type=None): - params = {} - if graph_type is not None: - params['graph_type'] = graph_type - - return self.connection.get_request( - self.cluster_release_tasks_api_path.format(env_id=env_id), - params=params - ) - - def get_own_tasks_for_cluster(self, env_id, graph_type=None): - params = {} - if graph_type is not None: - params['graph_type'] = graph_type - - return self.connection.get_request( - self.cluster_own_tasks_api_path.format(env_id=env_id), - params=params - ) - - def download(self, env_id, level, graph_type): - tasks_levels = { - 'all': lambda: self.get_merged_cluster_tasks( - env_id=env_id, graph_type=graph_type), - - 'cluster': lambda: self.get_own_tasks_for_cluster( - env_id=env_id, graph_type=graph_type), - - 'plugins': lambda: self.get_merged_plugins_tasks( - env_id=env_id, graph_type=graph_type), - - 'release': lambda: self.get_release_tasks_for_cluster( - env_id=env_id, graph_type=graph_type) - } - return tasks_levels[level]() - - def get_env_release_graphs_list(self, env_id): - """Get list of graphs related to the environment's release. - - :param env_id: environment ID - :type env_id: int - :return: list of graphs records - :rtype: list[dict] - """ - data = self.get_by_id(env_id) - release_id = data['release_id'] - return self.connection.get_request( - self.related_graphs_list_api_path.format( - related_model='releases', - related_model_id=release_id - ), params={'fetch_related': '0'} - ) - - def get_env_cluster_graphs_list(self, env_id, fetch_related=True): - """Get list of graphs related to the environment. - - :param env_id: environment ID - :type env_id: int - :param fetch_related: fetch graphs related to - cluster plugins and release - :type fetch_related: bool - - :return: list of graphs records - :rtype: list[dict] - """ - return self.connection.get_request( - self.related_graphs_list_api_path.format( - related_model='clusters', - related_model_id=env_id, - ), params={'fetch_related': '1' if fetch_related else '0'} - ) - - def get_env_plugins_graphs_list(self, env_id): - """Get list of graphs related to plugins active for the - - given environment. - - :param env_id: environment ID - :type env_id: int - :return: list of graphs records - :rtype: list[dict] - """ - env = objects.Environment(env_id) - enabled_plugins_ids = env.get_enabled_plugins() - result = [] - for plugin_id in enabled_plugins_ids: - result += self.connection.get_request( - self.related_graphs_list_api_path.format( - related_model='plugins', - related_model_id=plugin_id - ), params={'fetch_related': '0'} - ) - return result - - def get_all_graphs_list(self): - return self.connection.get_request(self.graphs_list_api) - - def list(self, env_id=None, filters=None): - """Get graphs list. - - If all filter flags are set to False, then it fill be considered as - 'show all' and all filter flags will be toggled to True. - - :param env_id: environment ID - :type env_id: int - :param filters: the name of models which graphs will be included - to result - :return: list of graphs records - :rtype: list[dict] - """ - # we cannot use dict here, because order is important - handlers = ( - ('release', self.get_env_release_graphs_list), - ('plugin', self.get_env_plugins_graphs_list), - ('cluster', self.get_env_cluster_graphs_list) - ) - - graphs_list = [] - filters = filters and set(filters) - - if env_id: - for relation, handler in handlers: - if not filters or relation in filters: - graphs_list.extend(handler(env_id=env_id)) - else: - all_graphs_list = self.get_all_graphs_list() - for graph in all_graphs_list: - for relation in graph['relations']: - if not filters or relation['model'] in filters: - graphs_list.append(graph) - break - - return graphs_list - - def delete(self, related_model, related_id, graph_type): - return self.connection.delete_request( - self.related_graph_api_path.format(related_model=related_model, - related_model_id=related_id, - graph_type=graph_type)) - - -def get_client(connection): - return GraphClient(connection) diff --git a/fuelclient/v1/health.py b/fuelclient/v1/health.py deleted file mode 100644 index f9ebda2..0000000 --- a/fuelclient/v1/health.py +++ /dev/null @@ -1,127 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Vitalii Kulanov -# -# Licensed 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 fuelclient.cli import error -from fuelclient import objects -from fuelclient.v1 import base_v1 - - -class HealthClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.Health - _allowed_statuses = ( - 'error', - 'operational', - 'update_error', - ) - - def get_all(self, environment_id): - """Get list of test sets for a given environment. - - :param environment_id: Id of environment - :type environment_id: int - :return: health test sets as a list of dict - :rtype: list - """ - return self._entity_wrapper.get_test_sets(environment_id) - - def get_status_all(self, environment_id=None): - """Get test sets statuses. If environment_id is None then statuses of - all test sets will be retrieved. - - :param environment_id: Id of environment - :type environment_id: int - :return: health test sets as a list of dict - :rtype: list - """ - data = self._entity_wrapper.get_tests_status_all() - # OSTF API doesn't support filtering by cluster, then do it 'manually' - if environment_id is not None: - data = [i for i in data if i['cluster_id'] == environment_id] - return data - - def get_status_single(self, testset_id): - testrun_obj = self._entity_wrapper(testset_id) - data = testrun_obj.get_tests_status_single() - if data: - result = [] - # Retrieve and re-format 'tests' from nested data for clarity - for tests in data.get('tests'): - result.append("\n* {} - {}, ('{}')".format(tests["status"], - tests["name"], - tests["message"])) - else: - msg = "Test sets with id {0} does not exist".format(testset_id) - raise error.ActionException(msg) - data['tests'] = ' '.join(result) - return data - - def get_last_test_status(self, environment_id): - return self._entity_wrapper.get_last_tests_status(environment_id) - - def start(self, environment_id, ostf_credentials=None, test_sets=None, - force=False): - """Run test sets for a given environment. If test_sets is None then - all test sets will be run - - :param environment_id: Id of environment - :type environment_id: int - :param ostf_credentials: ostf credentials - :type ostf_credentials: dict - :param test_sets: list of test sets - :type test_sets: list - :param force: - :type force: bool - :return: running health test sets as a list of dict - :rtype: list - """ - env_obj = objects.Environment(environment_id) - - if env_obj.status not in self._allowed_statuses and not force: - raise error.EnvironmentException( - "Environment is not ready to run health check " - "because it is in '{0}' state. Health check is likely " - "to fail because of this. Use '--force' flag " - "to proceed anyway.".format(env_obj.status) - ) - - if env_obj.is_customized and not force: - raise error.EnvironmentException( - "Environment deployment facts were updated. " - "Health check is likely to fail because of " - "that. Use '--force' flag to proceed anyway." - ) - test_sets_to_run = test_sets or set(ts['id'] for ts in - self.get_all(environment_id)) - - return self._entity_wrapper.run_test_sets(environment_id, - test_sets_to_run, - ostf_credentials) - - def action(self, testrun_id, action_status): - """Make an action on specific test set. - - :param testrun_id: id of test set - :type testrun_id: int - :param action_status: the type of action ('stopped', 'restarted') - :type action_status: str - """ - testrun_obj = self._entity_wrapper(obj_id=testrun_id) - return testrun_obj.action_test(action_status)[0] - - -def get_client(connection): - return HealthClient(connection) diff --git a/fuelclient/v1/network_configuration.py b/fuelclient/v1/network_configuration.py deleted file mode 100644 index d4790f0..0000000 --- a/fuelclient/v1/network_configuration.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient import objects -from fuelclient.v1 import base_v1 - - -class NetworkConfigurationClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.Task - - def download(self, transaction_id): - task = self._entity_wrapper(transaction_id) - return task.network_configuration() - - -def get_client(connection): - return NetworkConfigurationClient(connection) diff --git a/fuelclient/v1/network_group.py b/fuelclient/v1/network_group.py deleted file mode 100644 index ff375b1..0000000 --- a/fuelclient/v1/network_group.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli import error -from fuelclient import objects -from fuelclient.v1 import base_v1 - - -class NetworkGroupClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.NetworkGroup - - updatable_attributes = ( - 'name', 'vlan', 'cidr', 'gateway', 'group_id', 'meta') - - def create(self, name, release, vlan, cidr, - gateway, group_id, meta=None): - net_group = self._entity_wrapper.create( - name, release, vlan, cidr, gateway, group_id, meta) - return net_group.data - - def update(self, network_id, **kwargs): - for attr in kwargs: - if attr not in self.updatable_attributes: - raise error.BadDataException( - 'Update of attribute "{0}" is not allowed'.format(attr)) - - net_group = self._entity_wrapper(network_id) - net_group.set(kwargs) - - return net_group.data - - def delete_by_id(self, network_id): - env_obj = self._entity_wrapper(network_id) - env_obj.delete() - - -def get_client(connection): - return NetworkGroupClient(connection) diff --git a/fuelclient/v1/node.py b/fuelclient/v1/node.py deleted file mode 100644 index aa2fa71..0000000 --- a/fuelclient/v1/node.py +++ /dev/null @@ -1,320 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 collections import namedtuple -import copy - -from fuelclient.cli import error -from fuelclient import objects -from fuelclient.v1 import base_v1 -from fuelclient.v1 import fuelversion - - -SplittedLabel = namedtuple('SplittedLabel', ['key', 'value', 'has_separator']) - - -class NodeClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.Node - _updatable_attributes = ('hostname', 'labels', 'name') - - def get_all(self, environment_id=None, labels=None): - """Get nodes by specific environment or labels - - :param environment_id: Id of specific environment(cluster) - :type environment_id: int - :param labels: List of string labels for filtering nodes - :type labels: list - :returns: list -- filtered list of nodes - """ - if environment_id is not None: - result = self._entity_wrapper.get_by_env_id( - cluster_id=environment_id) - else: - result = self._entity_wrapper.get_all_data() - - if labels: - result = [item for item in result - if self._check_label(labels, item)] - - return result - - def undiscover_nodes(self, env_id=None, node_id=None, force=False): - """Delete nodes from database. If node_id is None then all nodes - from specified environment will be deleted. - - :param env_id: Id of env to delete nodes from database - :type env_id: int - :param node_id: Id of node to delete from database - :type node_id: int - :param force: Forces deletion of nodes regardless of their state - :type force: bool - :returns: list -- ids of nodes that were deleted from database - """ - nodes = [] - if node_id is not None: - nodes.append(self._entity_wrapper(obj_id=node_id).data) - elif env_id is not None: - nodes.extend(self.get_all(environment_id=env_id)) - if not nodes: - raise error.ActionException( - "Cluster with id {0} does not exist or " - "does not contain any nodes".format(env_id) - ) - else: - raise ValueError('Expected either env_id or node_id args') - - # If 'force' flag is not specified then check nodes status - if not force: - online_nodes = [node for node in nodes if node['online']] - if online_nodes: - raise error.ActionException( - "Nodes with ids {0} cannot be deleted from database " - "because they are online. You might want to use the " - "--force option.".format( - [node['id'] for node in online_nodes])) - - node_ids = [node['id'] for node in nodes] - objects.NodeCollection.delete_by_ids(node_ids) - return node_ids - - def get_node_vms_conf(self, node_id): - node = self._entity_wrapper(node_id) - fuelversion.FuelVersionClient.check_advanced_feature() - return node.get_node_vms_conf() - - def node_vms_create(self, node_id, config): - node = self._entity_wrapper(node_id) - fuelversion.FuelVersionClient.check_advanced_feature() - return node.node_vms_create(config) - - def update(self, node_id, **updated_attributes): - node = self._entity_wrapper(obj_id=node_id) - - for attr in updated_attributes: - if attr not in self._updatable_attributes: - msg = 'Only {0} are updatable'.format( - self._updatable_attributes) - raise error.BadDataException(msg) - - return node.set(updated_attributes) - - def get_all_labels_for_nodes(self, node_ids=None): - """Get list of labels for specific nodes. If no node_ids then all - labels should be returned - - :param node_ids: List of node ids for filtering labels - :type node_ids: list - :returns: list -- filtered list of labels - """ - labels = [] - - result = self._entity_wrapper.get_all_data() - - if node_ids: - result = filter(lambda node: str(node['id']) in node_ids, result) - - for node in result: - for key, value in node.get('labels', []).items(): - labels.append({ - 'node_id': node.get('id'), - 'label_name': key, - 'label_value': value - }) - - return labels - - def set_labels_for_nodes(self, labels=None, node_ids=None): - """Update nodes labels attribute with new data. If node_ids - are empty list then labels will be updated on all nodes - - :param labels: List of string pairs `key=val` for labels - :type labels: list - :param node_ids: List of node ids where labels should be updated - :type node_ids: list - :return: list -- ids of nodes where labels were updated - """ - data_to_return = [] - labels_to_update = {} - - for label in labels: - key, val, _ = self._split_label(label) - if not key: - msg = 'Wrong label "{0}" was provided. Label key couldn\'t ' \ - 'be an empty string.'.format(label) - raise error.LabelEmptyKeyError(msg) - labels_to_update[key] = val - - if node_ids: - for node_id in node_ids: - node = self._entity_wrapper(obj_id=node_id) - db_labels = copy.deepcopy(node.labels) - db_labels.update(labels_to_update) - - result = self.update(node_id, **{'labels': db_labels}) - data_to_return.append(str(result.get('id'))) - else: - nodes = self._entity_wrapper.get_all_data() - for node in nodes: - db_labels = copy.deepcopy(node['labels']) - db_labels.update(labels_to_update) - - result = self.update(node['id'], **{'labels': db_labels}) - data_to_return.append(str(result.get('id'))) - - return data_to_return - - def delete_labels_for_nodes(self, labels=None, node_ids=None): - """Delete labels data from nodes labels. If node_ids are - empty list then labels will be deleted on all nodes - - :param labels: List of string label keys - :type labels: list - :param node_ids: List of node ids where labels should be deleted - :type node_ids: list - :returns: list -- ids of nodes where labels were deleted - """ - data_to_return = [] - - if node_ids: - nodes = (self._entity_wrapper(obj_id=n_id).data - for n_id in node_ids) - else: - nodes = self._entity_wrapper.get_all_data() - - for node in nodes: - updated_labels = self._labels_after_delete( - node['labels'], labels) - - result = self.update(node['id'], **{'labels': updated_labels}) - data_to_return.append(str(result.get('id'))) - - return data_to_return - - def download_attributes(self, node_id, directory=None): - node = self._entity_wrapper(node_id) - attributes = node.get_node_attributes() - return node.write_attribute( - 'attributes', attributes, directory=directory) - - def get_disks(self, node_id): - """Download configuration of disks for a node - - :param node_id: Id of a node. - :return: dict with the configuration of disks for the node. - - """ - node = self._entity_wrapper(node_id) - return node.get_attribute('disks') - - def get_default_disks(self, node_id): - """Download default configuration of disks for a node - - :param node_id: Id of a node. - :return: dict with the default configuration of disks - for the node. - - """ - node = self._entity_wrapper(node_id) - return node.get_default_attribute('disks') - - def set_disks(self, node_id, disks): - """Upload and set configuration of disks for a node - - :param node_id: Id of a node. - :param interfaces: dict that contains valid configuration - for disks - - """ - node = self._entity_wrapper(node_id) - return node.upload_node_attribute('disks', disks) - - def upload_attributes(self, node_id, directory=None): - node = self._entity_wrapper(node_id) - attributes = node.read_attribute('attributes', directory=directory) - node.update_node_attributes(attributes) - - def get_interfaces(self, node_id): - """Download configuration of interfaces for a node - - :param node_id: Id of a node. - :return: dict with the configuration of interfaces for the node. - - """ - node = self._entity_wrapper(node_id) - return node.get_attribute('interfaces') - - def get_default_interfaces(self, node_id): - """Download default configuration of interfaces for a node - - :param node_id: Id of a node. - :return: dict with the configuration of interfaces for the node. - - """ - node = self._entity_wrapper(node_id) - return node.get_default_attribute('interfaces') - - def set_interfaces(self, node_id, interfaces): - """Upload and set configuration of interfaces for a node - - :param node_id: Id of a node. - :param interfaces: dict that contains valid configuration - for interfaces - - """ - node = self._entity_wrapper(node_id) - return node.upload_node_attribute('interfaces', interfaces) - - def _check_label(self, labels, item): - checking_list = [] - - for label in labels: - key, val, has_separator = self._split_label(label) - if key in item.get('labels'): - if not has_separator: - checking_val = True - else: - checking_val = item['labels'][key] == val - checking_list.append(checking_val) - - return any(checking_list) - - @classmethod - def _labels_after_delete(cls, labels, labels_to_delete): - if not labels_to_delete: - return {} - - db_labels = copy.deepcopy(labels) - for label in labels_to_delete: - label = label.strip() - sl = cls._split_label(label) - if sl.has_separator: - if sl.key in db_labels and db_labels[sl.key] == sl.value: - db_labels.pop(sl.key) - else: - db_labels.pop(sl.key, None) - - return db_labels - - @staticmethod - def _split_label(label): - name, separator, value = label.partition('=') - name = name.strip() - value = value.strip() - value = None if value == '' else value - return SplittedLabel(name, value, bool(separator)) - - -def get_client(connection): - return NodeClient(connection) diff --git a/fuelclient/v1/openstack_config.py b/fuelclient/v1/openstack_config.py deleted file mode 100644 index 414977a..0000000 --- a/fuelclient/v1/openstack_config.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient import objects -from fuelclient.v1 import base_v1 - - -class OpenstackConfigClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.OpenstackConfig - - def upload(self, path, cluster_id, node_ids=None, node_role=None): - data = self._entity_wrapper.read_file(path) - configuration = data['configuration'] - - config_obj = self._entity_wrapper.create(cluster_id=cluster_id, - configuration=configuration, - node_ids=node_ids, - node_role=node_role) - return [obj.data for obj in config_obj] - - def download(self, config_id, path): - config = self._entity_wrapper(config_id) - config.write_file(path, { - 'configuration': config.data['configuration']}) - - return path - - def execute(self, cluster_id, config_id=None, node_ids=None, - node_role=None, force=False): - task = self._entity_wrapper.execute(cluster_id=cluster_id, - config_id=config_id, - node_ids=node_ids, - node_role=node_role, - force=force) - - return task.data - - def get_filtered(self, cluster_id, node_ids=None, - node_role=None, is_active=True): - return self._entity_wrapper.get_filtered_data( - cluster_id=cluster_id, node_ids=node_ids, - node_role=node_role, is_active=is_active) - - def delete(self, config_id): - config = self._entity_wrapper(config_id) - config.delete() - - -def get_client(connection): - return OpenstackConfigClient(connection) diff --git a/fuelclient/v1/plugins.py b/fuelclient/v1/plugins.py deleted file mode 100644 index 904ca3d..0000000 --- a/fuelclient/v1/plugins.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 collections -import six - -from fuelclient import objects -from fuelclient.v1 import base_v1 - - -class PluginsClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.Plugins - - def get_all(self): - """Get plugins data and re-format 'releases' info to display - supported 'os', 'version' in a user-friendly way, e.g.: - ubuntu (liberty-8.0, liberty-9.0, mitaka-9.0) - centos (liberty-8.0), ubuntu (liberty-8.0) - - :returns: list of plugins - :rtype: list - """ - # Replace original nested 'releases' dictionary (from plugins meta - # dictionary) to a new user-friendly form with releases info, i.e. - # 'os', 'version' that specific plugin supports - plugins = self._entity_wrapper.get_all_data() - for plugin in plugins: - releases = collections.defaultdict(list) - for key in plugin['releases']: - releases[key['os']].append(key['version']) - plugin['releases'] = ', '.join('{} ({})'.format(k, ', '.join(v)) - for k, v in six.iteritems(releases)) - return plugins - - def sync(self, ids): - """Synchronise plugins on file system with plugins in API service. - - :param ids: List of ids for filtering plugins - :type ids: list - """ - - self._entity_wrapper.sync(plugin_ids=ids) - - def install(self, plugin_path, force=False): - """Install plugin archive and register in API service. - - :param plugin_path: Path to plugin file - :type plugin_path: str - :param force: Update existent plugin even if it is not updatable - :type force: bool - """ - return self._entity_wrapper.install(plugin_path, force=force) - - def remove(self, plugin_name, plugin_version): - """Remove the plugin package, and update data in API service. - - :param str plugin_name: Name of plugin to remove - :param str plugin_version: Version of plugin to remove - """ - return self._entity_wrapper.remove(plugin_name, plugin_version) - - -def get_client(connection): - return PluginsClient(connection) diff --git a/fuelclient/v1/release.py b/fuelclient/v1/release.py deleted file mode 100644 index 5554c1e..0000000 --- a/fuelclient/v1/release.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient import objects -from fuelclient.v1 import base_v1 - - -class ReleaseClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.Release - - def update_attributes_metadata_by_id(self, release_id, data): - release_obj = self._entity_wrapper(obj_id=release_id) - release_obj.update_attributes_metadata(data) - - def get_attributes_metadata_by_id(self, release_id): - release_obj = self._entity_wrapper(obj_id=release_id) - return release_obj.get_attributes_metadata() - - def get_components_by_id(self, release_id): - release_obj = self._entity_wrapper(obj_id=release_id) - return release_obj.get_components() - - -def get_client(connection): - return ReleaseClient(connection) diff --git a/fuelclient/v1/role.py b/fuelclient/v1/role.py deleted file mode 100644 index f38fe4c..0000000 --- a/fuelclient/v1/role.py +++ /dev/null @@ -1,67 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Vitalii Kulanov -# -# Licensed 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 fuelclient import objects -from fuelclient.v1 import base_v1 - - -class RoleClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.Role - - def get_all(self, owner_type, owner_id): - """Get all available roles for specific release or cluster. - - :param owner_type: release or cluster - :type owner_id: int - :return: roles data as a list of dict - :rtype: list - """ - - data = self._entity_wrapper(owner_type, owner_id).get_all() - - # Retrieve nested data from 'meta' and add it as a new key-value pair - for role in data: - role_meta = role.pop('meta') - role['group'] = role_meta.get('group') - role['conflicts'] = role_meta.get('conflicts') - role['description'] = role_meta.get('description') - - return data - - def get_one(self, owner_type, owner_id, role_name): - role = self._entity_wrapper(owner_type, owner_id) - return role.get_role(role_name) - - def update(self, data, **kwargs): - role = self._entity_wrapper(owner_type=kwargs['owner_type'], - owner_id=kwargs['owner_id']) - return role.update_role(kwargs['role_name'], data) - - def create(self, data, **kwargs): - role = self._entity_wrapper(owner_type=kwargs['owner_type'], - owner_id=kwargs['owner_id']) - return role.create_role(data) - - def delete(self, owner_type, owner_id, role_name): - role = self._entity_wrapper(owner_type=owner_type, - owner_id=owner_id) - return role.delete_role(role_name) - - -def get_client(connection): - return RoleClient(connection) diff --git a/fuelclient/v1/sequence.py b/fuelclient/v1/sequence.py deleted file mode 100644 index 7d5fc35..0000000 --- a/fuelclient/v1/sequence.py +++ /dev/null @@ -1,107 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient import objects -from fuelclient.v1 import base_v1 - - -class SequenceClient(base_v1.BaseV1Client): - _entity_wrapper = objects.Sequence - - executor_path = _entity_wrapper.instance_api_path + 'execute/' - - def create(self, release_id, name, graph_types): - """Creates new sequence object. - - :param release_id: the release object id - :param name: the sequence name - :param graph_types: the types of graphs - :returns: created object - """ - data = {'name': name} - graphs = data['graphs'] = [] - for graph_type in graph_types: - graphs.append({'type': graph_type}) - - return self.upload(release_id, data) - - def upload(self, release_id, data): - """Creates new sequence object from data. - - :param release_id: release object id - :param data: the sequence properties - :returns: created object - """ - url = self._entity_wrapper.class_api_path - data['release'] = release_id - return self.connection.post_request(url, data) - - def download(self, sequence_id): - """Get raw content of sequence.""" - return super(SequenceClient, self).get_by_id(sequence_id) - - def update(self, sequence_id, name=None, graph_types=None): - """Updates existing object. - - :param sequence_id: the sequence object id - :param name: new name - :param graph_types: new graph types - :returns: updated object or False if nothing to update - """ - data = {} - if name: - data['name'] = name - if graph_types: - graphs = data['graphs'] = [] - for graph_type in graph_types: - graphs.append({'type': graph_type}) - - if not data: - return False - - url = self._entity_wrapper.instance_api_path.format(sequence_id) - return self.connection.put_request(url, data) - - def get_by_id(self, sequence_id): - """Gets formatted sequence data by id.""" - data = super(SequenceClient, self).get_by_id(sequence_id) - data['graphs'] = ', '.join(g['type'] for g in data['graphs']) - return data - - def delete_by_id(self, sequence_id): - """Deletes existed object. - - :param sequence_id: the sequence object id - """ - url = self._entity_wrapper.instance_api_path.format(sequence_id) - self.connection.delete_request(url) - - def execute(self, sequence_id, env_id, **kwargs): - """Executes sequence on cluster. - - :param sequence_id: the sequence object id - :param env_id: the cluster id - :param kwargs: options - force, dry_run and noop. - """ - data = {'cluster': env_id} - data.update(kwargs) - url = self.executor_path.format(sequence_id) - deploy_data = self.connection.post_request(url, data) - return objects.DeployTask.init_with_data(deploy_data) - - -def get_client(connection): - return SequenceClient(connection) diff --git a/fuelclient/v1/snapshot.py b/fuelclient/v1/snapshot.py deleted file mode 100644 index 6ca2a12..0000000 --- a/fuelclient/v1/snapshot.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Vitalii Kulanov -# -# Licensed 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 fuelclient import objects -from fuelclient.v1 import base_v1 - - -class SnapshotClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.SnapshotTask - - def create_snapshot(self, config): - return self._entity_wrapper.start_snapshot_task(config) - - def get_default_config(self): - return self._entity_wrapper.get_default_config() - - -def get_client(connection): - return SnapshotClient(connection) diff --git a/fuelclient/v1/tag.py b/fuelclient/v1/tag.py deleted file mode 100644 index ae6fdf6..0000000 --- a/fuelclient/v1/tag.py +++ /dev/null @@ -1,57 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient import objects -from fuelclient.v1 import base_v1 - - -class TagClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.Tag - - def get_all(self, owner_type, owner_id): - """Get all available tags for specific release or cluster. - - :param owner_type: release or cluster - :type owner_id: int - :return: tags data as a list of dict - :rtype: list - """ - tags = self._entity_wrapper(owner_type, owner_id).get_all() - return tags - - def get_tag(self, owner_type, owner_id, tag_name=''): - tag = self._entity_wrapper(owner_type, owner_id) - return tag.get_tag(tag_name) - - def update(self, data, **kwargs): - tag = self._entity_wrapper(owner_type=kwargs['owner_type'], - owner_id=kwargs['owner_id']) - return tag.update_tag(kwargs['tag_name'], data) - - def create(self, data, **kwargs): - tag = self._entity_wrapper(owner_type=kwargs['owner_type'], - owner_id=kwargs['owner_id']) - return tag.create_tag(data) - - def delete(self, owner_type, owner_id, tag_name): - tag = self._entity_wrapper(owner_type=owner_type, owner_id=owner_id) - return tag.delete_tag(tag_name) - - -def get_client(connection): - return TagClient(connection) diff --git a/fuelclient/v1/task.py b/fuelclient/v1/task.py deleted file mode 100644 index 3c80582..0000000 --- a/fuelclient/v1/task.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed 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 fuelclient import objects -from fuelclient.v1 import base_v1 - - -class TaskClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.Task - - def delete_by_id(self, task_id, force=False): - """Delete a given task by its id - - :param task_id: Id of a task to delete. - :type task_id: int - :param force: Force deletion of a task without - considering its state - - """ - task_obj = self._entity_wrapper(obj_id=task_id) - task_obj.delete(force=force) - - -def get_client(connection): - return TaskClient(connection) diff --git a/fuelclient/v1/vip.py b/fuelclient/v1/vip.py deleted file mode 100644 index 66aefd2..0000000 --- a/fuelclient/v1/vip.py +++ /dev/null @@ -1,67 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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 fuelclient.cli.serializers import Serializer -from fuelclient import objects -from fuelclient.v1 import base_v1 - - -class VipClient(base_v1.BaseV1Client): - - _entity_wrapper = objects.Environment - - @staticmethod - def download(env_id, ip_addr_id=None, network_id=None, - network_role=None, file_path=None): - - env = objects.Environment(env_id) - vips_data = env.get_vips_data( - ip_address_id=ip_addr_id, - network=network_id, - network_role=network_role - ) - vips_data_file_path = env.write_vips_data_to_file( - vips_data, - file_path=file_path, - serializer=Serializer() - ) - return vips_data_file_path - - @staticmethod - def upload(env_id, file_path): - env = objects.Environment(env_id) - vips_data = env.read_vips_data_from_file( - file_path=file_path, - serializer=Serializer() - ) - env.set_vips_data(vips_data) - - @staticmethod - def create(env_id, ip_addr, network, vip_name, vip_namespace=None): - env = objects.Environment(env_id) - vip_data = { - 'ip_addr': ip_addr, - 'network': network, - 'vip_name': vip_name - } - if vip_namespace is not None: - vip_data['vip_namespace'] = vip_namespace - - env.create_vip(**vip_data) - - -def get_client(connection): - return VipClient(connection) diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 22ec29b..0000000 --- a/requirements.txt +++ /dev/null @@ -1,10 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -cliff!=1.16.0,>=1.15.0 # Apache-2.0 -oslo.utils>=3.5.0 # Apache-2.0 -pbr>=1.6 # Apache-2.0 -python-keystoneclient!=1.8.0,!=2.1.0,>=1.6.0 # Apache-2.0 -PyYAML>=3.1.0 # MIT -requests!=2.9.0,>=2.8.1 # Apache-2.0 -six>=1.9.0 # MIT diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index eda59dc..0000000 --- a/setup.cfg +++ /dev/null @@ -1,152 +0,0 @@ -[metadata] -name = python-fuelclient -version = 10.0.0 -summary = Command line interface and Python API wrapper for Fuel. -author = Mirantis Inc. -author-email = product@mirantis.com -home-page = https://docs.fuel-infra.org/fuel-dev -description-file = - README.rst -classifier = - Environment :: OpenStack - Intended Audience :: Information Technology - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.4 - -[files] -packages = - fuelclient - -[entry_points] -console_scripts = - fuel=fuelclient.cli.parser:main - fuel2=fuelclient.main:main - -fuelclient = - env_add_nodes=fuelclient.commands.environment:EnvAddNodes - env_create=fuelclient.commands.environment:EnvCreate - env_delete=fuelclient.commands.environment:EnvDelete - env_deploy=fuelclient.commands.environment:EnvDeploy - env_deployment-facts_delete=fuelclient.commands.environment:EnvDeploymentFactsDelete - env_deployment-facts_download=fuelclient.commands.environment:EnvDeploymentFactsDownload - env_deployment-facts_get-default=fuelclient.commands.environment:EnvDeploymentFactsGetDefault - env_deployment-facts_upload=fuelclient.commands.environment:EnvDeploymentFactsUpload - env_extension_disable=fuelclient.commands.extension:EnvExtensionDisable - env_extension_enable=fuelclient.commands.extension:EnvExtensionEnable - env_extension_show=fuelclient.commands.extension:EnvExtensionShow - env_list=fuelclient.commands.environment:EnvList - env_network_download=fuelclient.commands.environment:EnvNetworkDownload - env_network_upload=fuelclient.commands.environment:EnvNetworkUpload - env_network_verify=fuelclient.commands.environment:EnvNetworkVerify - env_nodes_deploy=fuelclient.commands.environment:EnvDeployNodes - env_nodes_provision=fuelclient.commands.environment:EnvProvisionNodes - env_provisioning-facts_delete=fuelclient.commands.environment:EnvProvisioningFactsDelete - env_provisioning-facts_download=fuelclient.commands.environment:EnvProvisioningFactsDownload - env_provisioning-facts_get-default=fuelclient.commands.environment:EnvProvisioningFactsGetDefault - env_provisioning-facts_upload=fuelclient.commands.environment:EnvProvisioningFactsUpload - env_redeploy=fuelclient.commands.environment:EnvRedeploy - env_remove_nodes=fuelclient.commands.environment:EnvRemoveNodes - env_reset=fuelclient.commands.environment:EnvReset - env_settings_download=fuelclient.commands.environment:EnvSettingsDownload - env_settings_upload=fuelclient.commands.environment:EnvSettingsUpload - env_show=fuelclient.commands.environment:EnvShow - env_spawn-vms=fuelclient.commands.environment:EnvSpawnVms - env_stop-deployment=fuelclient.commands.environment:EnvStopDeploy - env_update=fuelclient.commands.environment:EnvUpdate - extension_list=fuelclient.commands.extension:ExtensionList - fuel-version=fuelclient.commands.fuelversion:FuelVersion - graph_delete=fuelclient.commands.graph:GraphDelete - graph_download=fuelclient.commands.graph:GraphDownload - graph_execute=fuelclient.commands.graph:GraphExecute - graph_list=fuelclient.commands.graph:GraphList - graph_upload=fuelclient.commands.graph:GraphUpload - health_list=fuelclient.commands.health:HealthTestSetsList - health_restart=fuelclient.commands.health:HealthCheckRestart - health_start=fuelclient.commands.health:HealthCheckStart - health_status_list=fuelclient.commands.health:HealthTestSetsStatusList - health_status_show=fuelclient.commands.health:HealthTestSetsStatusShow - health_stop=fuelclient.commands.health:HealthCheckStop - network-group_create=fuelclient.commands.network_group:NetworkGroupCreate - network-group_delete=fuelclient.commands.network_group:NetworkGroupDelete - network-group_list=fuelclient.commands.network_group:NetworkGroupList - network-group_show=fuelclient.commands.network_group:NetworkGroupShow - network-group_update=fuelclient.commands.network_group:NetworkGroupUpdate - network-template_delete=fuelclient.commands.network_template:NetworkTemplateDelete - network-template_download=fuelclient.commands.network_template:NetworkTemplateDownload - network-template_upload=fuelclient.commands.network_template:NetworkTemplateUpload - node_ansible-inventory=fuelclient.commands.node:NodeAnsibleInventory - node_attributes-download=fuelclient.commands.node:NodeAttributesDownload - node_attributes-upload=fuelclient.commands.node:NodeAttributesUpload - node_create-vms-conf=fuelclient.commands.node:NodeCreateVMsConf - node_interfaces_download=fuelclient.commands.node:NodeInterfacesDownload - node_interfaces_get-default=fuelclient.commands.node:NodeInterfacesGetDefault - node_interfaces_upload=fuelclient.commands.node:NodeInterfacesUpload - node_disks_download=fuelclient.commands.node:NodeDisksDownload - node_disks_get-default=fuelclient.commands.node:NodeDisksGetDefault - node_disks_upload=fuelclient.commands.node:NodeDisksUpload - node_label_delete=fuelclient.commands.node:NodeLabelDelete - node_label_list=fuelclient.commands.node:NodeLabelList - node_label_set=fuelclient.commands.node:NodeLabelSet - node_list-vms-conf=fuelclient.commands.node:NodeVmsList - node_list=fuelclient.commands.node:NodeList - node_show=fuelclient.commands.node:NodeShow - node_undiscover = fuelclient.commands.node:NodeUndiscover - node_update=fuelclient.commands.node:NodeUpdate - openstack-config_delete=fuelclient.commands.openstack_config:OpenstackConfigDelete - openstack-config_download=fuelclient.commands.openstack_config:OpenstackConfigDownload - openstack-config_execute=fuelclient.commands.openstack_config:OpenstackConfigExecute - openstack-config_list=fuelclient.commands.openstack_config:OpenstackConfigList - openstack-config_upload=fuelclient.commands.openstack_config:OpenstackConfigUpload - plugins_install=fuelclient.commands.plugins:PluginInstall - plugins_list=fuelclient.commands.plugins:PluginsList - plugins_remove=fuelclient.commands.plugins:PluginRemove - plugins_sync=fuelclient.commands.plugins:PluginsSync - release_component_list=fuelclient.commands.release:ReleaseComponentList - release_list=fuelclient.commands.release:ReleaseList - release_repos_list=fuelclient.commands.release:ReleaseReposList - release_repos_update=fuelclient.commands.release:ReleaseReposUpdate - role_create=fuelclient.commands.role:RoleCreate - role_delete=fuelclient.commands.role:RoleDelete - role_download=fuelclient.commands.role:RoleDownload - role_list=fuelclient.commands.role:RoleList - role_update=fuelclient.commands.role:RoleUpdate - tag_create=fuelclient.commands.tag:TagCreate - tag_delete=fuelclient.commands.tag:TagDelete - tag_download=fuelclient.commands.tag:TagDownload - tag_list=fuelclient.commands.tag:TagList - tag_update=fuelclient.commands.tag:TagUpdate - task_delete=fuelclient.commands.task:TaskDelete - task_deployment-info_download=fuelclient.commands.task:TaskDeploymentInfoDownload - task_history_show=fuelclient.commands.task:TaskHistoryShow - task_list=fuelclient.commands.task:TaskList - task_network-configuration_download=fuelclient.commands.task:TaskNetworkConfigurationDownload - task_settings_download=fuelclient.commands.task:TaskClusterSettingsDownload - task_show=fuelclient.commands.task:TaskShow - sequence_create=fuelclient.commands.sequence:SequenceCreate - sequence_delete=fuelclient.commands.sequence:SequenceDelete - sequence_download=fuelclient.commands.sequence:SequenceDownload - sequence_execute=fuelclient.commands.sequence:SequenceExecute - sequence_list=fuelclient.commands.sequence:SequenceList - sequence_show=fuelclient.commands.sequence:SequenceShow - sequence_update=fuelclient.commands.sequence:SequenceUpdate - sequence_upload=fuelclient.commands.sequence:SequenceUpload - snapshot_create=fuelclient.commands.snapshot:SnapshotGenerate - snapshot_get-default-config=fuelclient.commands.snapshot:SnapshotConfigGetDefault - snapshot_get-link=fuelclient.commands.snapshot:SnapshotGetLink - vip_create=fuelclient.commands.vip:VipCreate - vip_download=fuelclient.commands.vip:VipDownload - vip_upload=fuelclient.commands.vip:VipUpload - -[global] -setup-hooks = - pbr.hooks.setup_hook - fuelclient.hooks.setup_hook - -[wheel] -python-tag = py2 diff --git a/setup.py b/setup.py deleted file mode 100644 index 782bb21..0000000 --- a/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed 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. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr>=1.8'], - pbr=True) diff --git a/specs/python-fuelclient.spec b/specs/python-fuelclient.spec deleted file mode 100644 index 12038e3..0000000 --- a/specs/python-fuelclient.spec +++ /dev/null @@ -1,67 +0,0 @@ -%if 0%{?rhel} && 0%{?rhel} <= 7 -%{!?__python2: %global __python2 /usr/bin/python2} -%{!?python2_sitelib: %global python2_sitelib %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")} -%{!?python2_sitearch: %global python2_sitearch %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")} -%endif - -%define name python-fuelclient -%{!?version: %define version 10.0.0} -%{!?release: %define release 1} - -Summary: Console utility for working with fuel rest api -Name: %{name} -Version: %{version} -Release: %{release} -Source0: %{name}-%{version}.tar.gz -License: Apache -Group: Development/Libraries -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot -Prefix: %{_prefix} - -BuildArch: noarch - -BuildRequires: python-setuptools -BuildRequires: python-pbr >= 1.8.0 - -%if 0%{!?rhel:0} == 6 -Requires: python-argparse -%endif - -Conflicts: python-requests == 2.8.0 - -Requires: perl -Requires: python-cliff >= 1.14.0 -Requires: python-pbr >= 1.6 -Requires: python-keystoneclient >= 1.6.0 -Requires: PyYAML >= 3.1.0 -Requires: python-requests >= 2.5.2 -Requires: python-six >= 1.9.0 - - -Requires: bash-completion - -%description -Summary: Console utility for working with fuel rest api - -%prep -%setup -cq -n %{name}-%{version} - -%build -cd %{_builddir}/%{name}-%{version} && %{__python2} setup.py build - -%install -rm -rf $RPM_BUILD_ROOT -cd %{_builddir}/%{name}-%{version} && %{__python2} setup.py install --single-version-externally-managed -O1 --root=$RPM_BUILD_ROOT - -%post -# FIXME(mkwiek): fix fuelclient to generate usable autocomplete bash -fuel2 complete | perl -pe "s/-(?=.*=')/_/g" | perl -pe 's;(?<=cmds_\$\{)proposed;proposed//-/_;g' | sed -e "s/local cur prev words/local -a words/g" > %{_datadir}/bash-completion/completions/fuel2 - -%clean -rm -rf $RPM_BUILD_ROOT - -%files -%defattr(-,root,root) -%{python2_sitelib}/* -%{_bindir}/* -%doc fuelclient/fuel_client.yaml diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 9186cd6..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,17 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -os-testr>=0.4.1 # Apache-2.0 -coverage>=3.6 # Apache-2.0 -fixtures>=1.3.1 # Apache-2.0/BSD -hacking>=0.12.0,!=0.13.0,<0.14 # Apache-2.0 -mock>=1.2 # BSD -oslotest>=1.10.0 # Apache-2.0 -requests-mock>=0.7.0 # Apache-2.0 -testrepository>=0.0.18 # Apache-2.0/BSD -testtools>=1.4.0 # MIT - -# Files beyond this line are not in Global Requirements list -# and must be added there. -pyprof2calltree>=1.3.2 -gprof2dot>=2014.09.29 diff --git a/tools/env.sh b/tools/env.sh deleted file mode 100755 index 96dbe28..0000000 --- a/tools/env.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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. - -set -eu - -. $(dirname $0)/env_functions.sh - -case $1 in - prepare_nailgun) - prepare_nailgun - ;; - cleanup_nailgun) - cleanup_nailgun - ;; - prepare_fuelclient) - prepare_fuelclient_config - ;; - cleanup_fuelclient) - cleanup_fuelclient_config - ;; - prepare_fuel_web_repo) - prepare_fuel_web_repo - ;; - cleanup_fuel_web_repo) - cleanup_fuel_web_repo - ;; - *) - echo "Not supported subcommand. Available subcommands: " - echo "cleanup_nailgun" - echo "prepare_nailgun" - echo "cleanup_fuelclient" - echo "prepare_fuelclient" - echo "cleanup_fuel_web_repo" - echo "prepare_fuel_web_repo" - exit 1 - ;; -esac diff --git a/tools/env_functions.sh b/tools/env_functions.sh deleted file mode 100644 index 466ee5f..0000000 --- a/tools/env_functions.sh +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2016 Mirantis, Inc. -# -# Licensed 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. - -function cleanup_nailgun { - echo "Cleaning up nailgun." - pushd "$FUEL_WEB_ROOT" > /dev/null - tox -e stop || echo "Error while stopping nailgun." - popd > /dev/null - - pushd "$FUEL_WEB_ROOT" > /dev/null - tox -e cleanup - popd > /dev/null -} - -function prepare_nailgun { - echo "Preparing nailgun." - pushd "$FUEL_WEB_ROOT" > /dev/null - tox -e start - popd > /dev/null -} - -function prepare_fuelclient_config { - echo "Creating fuelclient config file $FUELCLIENT_CUSTOM_SETTINGS" - mkdir -p $(dirname $FUELCLIENT_CUSTOM_SETTINGS) - cat > $FUELCLIENT_CUSTOM_SETTINGS < /dev/null - - if [[ -n $FUEL_WEB_FETCH_REPO ]]; then - git fetch "$FUEL_WEB_FETCH_REPO" "$FUEL_WEB_FETCH_REFSPEC" || \ - { echo "Failed to fetch $FUEL_WEB_FETCH_REPO"; exit 1; } - fi - - git checkout "$FUEL_WEB_COMMIT" || \ - { echo "Failed to checkout to $FUEL_WEB_COMMIT"; exit 1; } - - popd > /dev/null - -} - -function cleanup_fuel_web_repo { - echo "Removing $FUEL_WEB_ROOT directory." - - if [[ "$FUEL_WEB_CLONE" == "yes" ]]; then - rm -rf $FUEL_WEB_ROOT - fi -} diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 98d3f59..0000000 --- a/tox.ini +++ /dev/null @@ -1,81 +0,0 @@ -[tox] -minversion = 2.1 -skipsdist = True -envlist = py27,pep8,functional,cleanup - -[base] -ARTS = {env:ARTS:test_run} - -[common] -changedir={toxinidir}/nailgun -setenv = - NAILGUN_DB={env:TEST_NAILGUN_DB:nailgun} - NAILGUN_DB_USER={env:NAILGUN_DB_USER:nailgun} - NAILGUN_DB_USERPW={env:NAILGUN_DB_USERPW:nailgun} - NAILGUN_DB_PREPARE={env:NAILGUN_DB_PREPARE:no} - - FUEL_WEB_CLONE={env:FUEL_WEB_CLONE:yes} - FUEL_WEB_REPO={env:FUEL_WEB_REPO:https://github.com/openstack/fuel-web.git} - FUEL_WEB_COMMIT={env:FUEL_COMMIT:master} - FUEL_WEB_ROOT={env:FUEL_WEB_ROOT:/tmp/fuel_web} - FUEL_WEB_FETCH_REPO={env:FUEL_WEB_FETCH_REPO:} - FUEL_WEB_FETCH_REFSPEC={env:FUEL_WEB_FETCH_REFSPEC:} - - NAILGUN_PORT={env:NAILGUN_PORT:8000} - NAILGUN_ROOT={env:FUEL_WEB_ROOT}/nailgun - FUELCLIENT_CUSTOM_SETTINGS={[base]ARTS}/fuelclient_custom_settings.yaml - -[testenv] -usedevelop = True -whitelist_externals = bash - python -setenv = VIRTUAL_ENV={envdir} - {[common]setenv} -passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY -deps = -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -commands = - ostestr --serial {posargs} - -[testenv:functional] -setenv = VIRTUAL_ENV={envdir} - {[common]setenv} - OS_TEST_PATH={toxinidir}/fuelclient/tests/functional -commands = - bash -c "{toxinidir}/tools/env.sh prepare_fuel_web_repo" - bash -c "{toxinidir}/tools/env.sh prepare_nailgun" - bash -c "{toxinidir}/tools/env.sh prepare_fuelclient" - ostestr --serial {posargs} - -[testenv:cleanup] -commands = - bash -c "{toxinidir}/tools/env.sh cleanup_nailgun" - bash -c "{toxinidir}/tools/env.sh cleanup_fuel_web_repo" - bash -c "{toxinidir}/tools/env.sh cleanup_fuelclient" - bash -c "find {toxinidir} -name \"*.pyc\" -delete" - -[testenv:pep8] -commands = - flake8 {posargs:fuelclient} - -[testenv:cover] -commands = - python setup.py test --coverage --testr-args '{posargs}' - -[testenv:venv] -commands = {posargs:} - -[testenv:devenv] -envdir = devenv -usedevelop = True - -[flake8] -# TODO(atykhonov): H405 must be removed when old CLI is removed -ignore = H405 -exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build,tools,__init__.py,docs -show-pep8 = True -show-source = True -count = True - -[hacking] -import_exceptions = testtools.matchers