diff --git a/fuelclient/cli/actions/environment.py b/fuelclient/cli/actions/environment.py index 9c00524..9522678 100644 --- a/fuelclient/cli/actions/environment.py +++ b/fuelclient/cli/actions/environment.py @@ -14,6 +14,7 @@ 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 @@ -61,9 +62,19 @@ class EnvironmentAction(Action): ), Args.get_nst_arg( "Set network segment type" - ) + ), + Args.get_deployment_tasks_arg("Environment tasks configuration."), + 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), ("create", self.create), ("set", self.set), ("delete", self.delete), @@ -182,3 +193,25 @@ class EnvironmentAction(Action): {}, msg ) + + @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_file(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 release {0} " + " uploaded from {1}.yaml".format(cluster.id, full_path)) diff --git a/fuelclient/cli/actions/release.py b/fuelclient/cli/actions/release.py index ac8835b..cae71e6 100644 --- a/fuelclient/cli/actions/release.py +++ b/fuelclient/cli/actions/release.py @@ -31,7 +31,8 @@ class ReleaseAction(Action): self.args = [ Args.get_release_arg('Specify particular release id'), Args.get_list_arg("List all available releases."), - Args.get_network_arg("Node network configuration."), + Args.get_network_arg("Release network configuration."), + Args.get_deployment_tasks_arg("Release tasks configuration."), Args.get_dir_arg( "Select directory to which download release attributes"), group( @@ -42,6 +43,7 @@ class ReleaseAction(Action): ) ] self.flag_func_map = ( + ('deployment-tasks', self.deployment_tasks), ('network', self.network), (None, self.list), ) @@ -94,3 +96,25 @@ class ReleaseAction(Action): 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_file(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)) diff --git a/fuelclient/cli/arguments.py b/fuelclient/cli/arguments.py index d3536be..678c592 100644 --- a/fuelclient/cli/arguments.py +++ b/fuelclient/cli/arguments.py @@ -226,6 +226,11 @@ 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", flags=("--deployment-tasks",), help=help_msg) + + def get_network_arg(help_msg): return get_boolean_arg("network", flags=("--net",), help=help_msg) diff --git a/fuelclient/objects/environment.py b/fuelclient/objects/environment.py index 328fedd..7f4e1a7 100644 --- a/fuelclient/objects/environment.py +++ b/fuelclient/objects/environment.py @@ -29,6 +29,7 @@ class Environment(BaseObject): class_api_path = "clusters/" instance_api_path = "clusters/{0}/" + deployment_tasks_path = 'clusters/{0}/deployment_tasks' @classmethod def create(cls, name, release_id, net, net_segment_type=None): @@ -368,3 +369,11 @@ class Environment(BaseObject): {} ) ) + + 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) diff --git a/fuelclient/objects/release.py b/fuelclient/objects/release.py index 0020365..49facde 100644 --- a/fuelclient/objects/release.py +++ b/fuelclient/objects/release.py @@ -20,6 +20,7 @@ class Release(BaseObject): class_api_path = "releases/" instance_api_path = "releases/{0}/" networks_path = 'releases/{0}/networks' + deployment_tasks_path = 'releases/{0}/deployment_tasks' @classmethod def get_all(cls): @@ -32,3 +33,11 @@ class Release(BaseObject): def update_networks(self, data): url = self.networks_path.format(self.id) return self.connection.put_request(url, data) + + 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) diff --git a/fuelclient/tests/base.py b/fuelclient/tests/base.py index 4cb9331..f2e44df 100644 --- a/fuelclient/tests/base.py +++ b/fuelclient/tests/base.py @@ -18,6 +18,8 @@ except ImportError: # Runing unit-tests in production environment from unittest2.case import TestCase +from mock import patch + import logging import os import shutil @@ -54,6 +56,11 @@ class UnitTestCase(TestCase): def execute(self, command): return main(command) + def execute_wo_auth(self, command): + with patch('fuelclient.client.Client.auth_required') as auth: + auth.return_value = False + return self.execute(command) + class BaseTestCase(UnitTestCase): root_path = os.path.abspath( diff --git a/fuelclient/tests/test_deployment_tasks_actions.py b/fuelclient/tests/test_deployment_tasks_actions.py new file mode 100644 index 0000000..ecbafbf --- /dev/null +++ b/fuelclient/tests/test_deployment_tasks_actions.py @@ -0,0 +1,73 @@ +# -*- 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 + +from mock import patch + +from fuelclient.tests import base + + +API_INPUT = [{'id': 'primary-controller'}] +API_OUTPUT = '- id: primary-controller\n' + + +@patch('fuelclient.client.requests') +@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, mrequests): + mrequests.get().json.return_value = API_INPUT + self.execute_wo_auth( + ['fuel', 'rel', '--rel', '1', '--deployment-tasks', '--download']) + mopen().__enter__().write.assert_called_once_with(API_OUTPUT) + + def test_release_tasks_upload(self, mos, mopen, mrequests): + mopen().__enter__().read.return_value = API_OUTPUT + self.execute_wo_auth( + ['fuel', 'rel', '--rel', '1', '--deployment-tasks', '--upload']) + self.assertEqual(mrequests.put.call_count, 1) + call_args = mrequests.put.call_args_list[0] + url = call_args[0][0] + kwargs = call_args[1] + self.assertIn('releases/1/deployment_tasks', url) + self.assertEqual( + json.loads(kwargs['data']), API_INPUT) + + +@patch('fuelclient.client.requests') +@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, mrequests): + mrequests.get().json.return_value = API_INPUT + self.execute_wo_auth( + ['fuel', 'env', '--env', '1', '--deployment-tasks', '--download']) + mopen().__enter__().write.assert_called_once_with(API_OUTPUT) + + def test_cluster_tasks_upload(self, mos, mopen, mrequests): + mopen().__enter__().read.return_value = API_OUTPUT + self.execute_wo_auth( + ['fuel', 'env', '--env', '1', '--deployment-tasks', '--upload']) + self.assertEqual(mrequests.put.call_count, 1) + call_args = mrequests.put.call_args_list[0] + url = call_args[0][0] + kwargs = call_args[1] + self.assertIn('clusters/1/deployment_tasks', url) + self.assertEqual( + json.loads(kwargs['data']), API_INPUT)