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
This commit is contained in:
parent
2b1ebf7016
commit
d1ce60ba62
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'))
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue