From d1ce60ba62f79748325a5c7fca170e632c43396b Mon Sep 17 00:00:00 2001 From: Roman Prykhodchenko Date: Tue, 19 Jul 2016 16:51:32 +0200 Subject: [PATCH] Add new CLI commands for managing cluster networks and settings This patch introduces the following commands to the new fuel2 CLI: - fuel2 env network download - fuel2 env network upload - fuel2 env network verify - fuel2 env settings download - fuel2 env settings upload DocImpact Change-Id: Iab92de0f0dbc453d5ea36f83d10252911e37d163 --- fuelclient/commands/base.py | 32 +++ fuelclient/commands/environment.py | 199 +++++++++++++++++- fuelclient/commands/node.py | 23 -- fuelclient/tests/unit/v2/cli/test_engine.py | 40 ++++ fuelclient/tests/unit/v2/cli/test_env.py | 169 ++++++++++++++- fuelclient/tests/unit/v2/cli/test_node.py | 41 ---- .../tests/unit/v2/lib/test_environment.py | 106 ++++++++++ fuelclient/tests/utils/__init__.py | 3 + .../tests/utils/fake_additional_info.py | 7 + fuelclient/v1/environment.py | 22 ++ setup.cfg | 5 + 11 files changed, 579 insertions(+), 68 deletions(-) diff --git a/fuelclient/commands/base.py b/fuelclient/commands/base.py index 904c0900..e5058b5f 100644 --- a/fuelclient/commands/base.py +++ b/fuelclient/commands/base.py @@ -13,6 +13,7 @@ # under the License. import abc +import os from cliff import command from cliff import lister @@ -30,6 +31,29 @@ VERSION = 'v1' 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) @@ -39,6 +63,14 @@ class BaseCommand(command.Command): """Name of the Fuel entity.""" pass + @property + def supported_file_formats(self): + raise NotImplemented() + + @property + def allowed_attr_types(self): + raise NotImplemented() + @six.add_metaclass(abc.ABCMeta) class BaseListCommand(lister.Lister, BaseCommand): diff --git a/fuelclient/commands/environment.py b/fuelclient/commands/environment.py index e5b568a2..7166d982 100644 --- a/fuelclient/commands/environment.py +++ b/fuelclient/commands/environment.py @@ -12,8 +12,15 @@ # License for the specific language governing permissions and limitations # under the License. -from cliff import show +import abc +import functools +import os +from cliff import show +from oslo_utils import fileutils +import six + +from fuelclient.cli import error from fuelclient.commands import base from fuelclient.common import data_utils @@ -21,6 +28,122 @@ from fuelclient.common import data_utils class EnvMixIn(object): entity_name = 'environment' + supported_file_formats = ('json', 'yaml') + allowed_attr_types = ('network', 'settings') + + +@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.""" @@ -355,3 +478,77 @@ class EnvSpawnVms(EnvMixIn, base.BaseCommand): 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 diff --git a/fuelclient/commands/node.py b/fuelclient/commands/node.py index 5a7a0dad..56773684 100644 --- a/fuelclient/commands/node.py +++ b/fuelclient/commands/node.py @@ -44,29 +44,6 @@ class NodeMixIn(object): numa_topology_info[key] = numa_topology.get(key) return numa_topology_info - def get_attributes_path(self, attr_type, file_format, node_id, directory): - """Returnes a path for attributes of a node - - :param attr_type: Attribute type. - Should be one of {attributes, disks, interfaces} - :param file_format: The format of the file that contains or will - contain the attributes. Must be json or yaml. - :param node_id: Id of a node - :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), - 'node_{0}'.format(node_id), - '{}.{}'.format(attr_type, file_format)) - class NodeList(NodeMixIn, base.BaseListCommand): """Show list of all available nodes.""" diff --git a/fuelclient/tests/unit/v2/cli/test_engine.py b/fuelclient/tests/unit/v2/cli/test_engine.py index 80393f5d..5b3b0a93 100644 --- a/fuelclient/tests/unit/v2/cli/test_engine.py +++ b/fuelclient/tests/unit/v2/cli/test_engine.py @@ -22,6 +22,7 @@ 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 @@ -129,3 +130,42 @@ class BaseCLITest(oslo_base.BaseTestCase): 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 index 625455b4..bb2ec952 100644 --- a/fuelclient/tests/unit/v2/cli/test_env.py +++ b/fuelclient/tests/unit/v2/cli/test_env.py @@ -15,8 +15,10 @@ # 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_env @@ -200,11 +202,9 @@ class TestEnvCommand(test_engine.BaseCLITest): args = ('env nodes deploy ' '--nodes {n[0]} {n[1]} --env {e}').format(e=env_id, n=node_ids) - self.m_client.deploy_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.deploy_nodes.return_value = fake_task.get_fake_task() self.m_client.deploy_nodes.assert_called_once_with(env_id, node_ids) def test_env_nodes_provision(self): @@ -219,3 +219,166 @@ class TestEnvCommand(test_engine.BaseCLITest): 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_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) diff --git a/fuelclient/tests/unit/v2/cli/test_node.py b/fuelclient/tests/unit/v2/cli/test_node.py index cc184792..3472aba7 100644 --- a/fuelclient/tests/unit/v2/cli/test_node.py +++ b/fuelclient/tests/unit/v2/cli/test_node.py @@ -374,44 +374,3 @@ node-4 ansible_host=10.20.0.5 self.m_get_client.assert_called_once_with('node', mock.ANY) self.m_client.upload_attributes.assert_called_once_with(42, None) - - -class TestNodeMixIn(test_engine.BaseCLITest): - def test_get_attribute_path(self): - mixin = cmd_node.NodeMixIn() - - 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 = mixin.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): - mixin = cmd_node.NodeMixIn() - - attr_type = 'wrong' - file_format = 'json' - node_id = 42 - directory = '/test' - - self.assertRaises(ValueError, - mixin.get_attributes_path, - attr_type, file_format, node_id, directory) - - def test_get_attribute_path_wrong_file_format(self): - mixin = cmd_node.NodeMixIn() - - attr_type = 'interfaces' - file_format = 'wrong' - node_id = 42 - directory = '/test' - - self.assertRaises(ValueError, - mixin.get_attributes_path, - attr_type, file_format, node_id, directory) diff --git a/fuelclient/tests/unit/v2/lib/test_environment.py b/fuelclient/tests/unit/v2/lib/test_environment.py index 6bfdfb40..7ec6bb78 100644 --- a/fuelclient/tests/unit/v2/lib/test_environment.py +++ b/fuelclient/tests/unit/v2/lib/test_environment.py @@ -32,6 +32,9 @@ class TestEnvFacade(test_api.BaseLibTest): 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)] @@ -286,3 +289,106 @@ class TestEnvFacade(test_api.BaseLibTest): 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')) diff --git a/fuelclient/tests/utils/__init__.py b/fuelclient/tests/utils/__init__.py index bfa73987..85e4d526 100644 --- a/fuelclient/tests/utils/__init__.py +++ b/fuelclient/tests/utils/__init__.py @@ -21,6 +21,8 @@ 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 \ @@ -51,6 +53,7 @@ __all__ = (get_fake_deployment_history, get_fake_yaml_deployment_info, get_fake_yaml_network_conf, get_fake_env, + get_fake_env_network_conf, get_fake_release, get_fake_releases, get_fake_attributes_metadata, diff --git a/fuelclient/tests/utils/fake_additional_info.py b/fuelclient/tests/utils/fake_additional_info.py index f2e8d8a4..181918d5 100644 --- a/fuelclient/tests/utils/fake_additional_info.py +++ b/fuelclient/tests/utils/fake_additional_info.py @@ -14,6 +14,9 @@ # License for the specific language governing permissions and limitations # under the License. +import yaml + + CLUSTER_SETTINGS = '''--- editable: service_user: @@ -88,3 +91,7 @@ def get_fake_yaml_network_conf(): """ return NETWORK_CONF + + +def get_fake_env_network_conf(): + return yaml.load(get_fake_yaml_network_conf()) diff --git a/fuelclient/v1/environment.py b/fuelclient/v1/environment.py index cefcdd66..6ebfed3f 100644 --- a/fuelclient/v1/environment.py +++ b/fuelclient/v1/environment.py @@ -138,6 +138,28 @@ class EnvironmentClient(base_v1.BaseV1Client): 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 get_client(connection): return EnvironmentClient(connection) diff --git a/setup.cfg b/setup.cfg index 3c3dda21..26196c81 100644 --- a/setup.cfg +++ b/setup.cfg @@ -36,8 +36,13 @@ fuelclient = env_nodes_deploy=fuelclient.commands.environment:EnvDeployNodes env_list=fuelclient.commands.environment:EnvList env_nodes_provision=fuelclient.commands.environment:EnvProvisionNodes + env_network_download=fuelclient.commands.environment:EnvNetworkDownload + env_network_upload=fuelclient.commands.environment:EnvNetworkUpload + env_network_verify=fuelclient.commands.environment:EnvNetworkVerify env_redeploy=fuelclient.commands.environment:EnvRedeploy env_remove_nodes=fuelclient.commands.environment:EnvRemoveNodes + 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_update=fuelclient.commands.environment:EnvUpdate