Support creating a swap partition

BREAKING: --root-disk-size => --root-size

Story: #2002171
Task: #20033
Change-Id: I5d6b38e1a9e71b608b40e140e34c4509b896a1ff
This commit is contained in:
Dmitry Tantsur 2018-09-10 12:44:26 +02:00
parent c06e2c9baf
commit 2afd20938d
10 changed files with 213 additions and 532 deletions

View File

@ -124,6 +124,7 @@
metalsmith_precreate_port: false metalsmith_precreate_port: false
metalsmith_partition_image: test-centos-partition metalsmith_partition_image: test-centos-partition
metalsmith_whole_disk_image: test-centos-wholedisk metalsmith_whole_disk_image: test-centos-wholedisk
metalsmith_swap_size: 1024
metalsmith_traits: [CUSTOM_GOLD] metalsmith_traits: [CUSTOM_GOLD]
- job: - job:

View File

@ -81,7 +81,8 @@ def _do_deploy(api, args, formatter):
instance = api.provision_node(node, instance = api.provision_node(node,
image=source, image=source,
nics=args.nics, nics=args.nics,
root_disk_size=args.root_disk_size, root_size_gb=args.root_size,
swap_size_mb=args.swap_size,
config=config, config=config,
hostname=args.hostname, hostname=args.hostname,
netboot=args.netboot, netboot=args.netboot,
@ -150,9 +151,12 @@ def _parse_args(args, config):
dest='nics', action=NICAction) dest='nics', action=NICAction)
deploy.add_argument('--netboot', action='store_true', deploy.add_argument('--netboot', action='store_true',
help='boot from network instead of local disk') help='boot from network instead of local disk')
deploy.add_argument('--root-disk-size', type=int, deploy.add_argument('--root-size', type=int,
help='root disk size (in GiB), defaults to (local_gb ' help='root partition size (in GiB), defaults to '
'- 2)') '(local_gb - 1)')
deploy.add_argument('--swap-size', type=int,
help='swap partition size (in MiB), defaults to '
'no swap')
deploy.add_argument('--capability', action='append', metavar='NAME=VALUE', deploy.add_argument('--capability', action='append', metavar='NAME=VALUE',
default=[], help='capabilities the node should have') default=[], help='capabilities the node should have')
deploy.add_argument('--trait', action='append', deploy.add_argument('--trait', action='append',

View File

@ -17,6 +17,7 @@ import logging
import random import random
import sys import sys
import time import time
import warnings
from openstack import connection from openstack import connection
import six import six
@ -194,9 +195,10 @@ class Provisioner(object):
return hostname return hostname
def provision_node(self, node, image, nics=None, root_disk_size=None, def provision_node(self, node, image, nics=None, root_size_gb=None,
config=None, hostname=None, netboot=False, swap_size_mb=None, config=None, hostname=None,
capabilities=None, traits=None, wait=None): netboot=False, capabilities=None, traits=None,
wait=None, root_disk_size=None):
"""Provision the node with the given image. """Provision the node with the given image.
Example:: Example::
@ -204,7 +206,7 @@ class Provisioner(object):
provisioner.provision_node("compute-1", "centos", provisioner.provision_node("compute-1", "centos",
nics=[{"network": "private"}, nics=[{"network": "private"},
{"network": "external"}], {"network": "external"}],
root_disk_size=50, root_size_gb=50,
wait=3600) wait=3600)
:param node: Node object, UUID or name. Will be reserved first, if :param node: Node object, UUID or name. Will be reserved first, if
@ -216,8 +218,10 @@ class Provisioner(object):
Each item is a dict with a key describing the type of the NIC: Each item is a dict with a key describing the type of the NIC:
either a port (``{"port": "<port name or ID>"}``) or a network either a port (``{"port": "<port name or ID>"}``) or a network
to create a port on (``{"network": "<network name or ID>"}``). to create a port on (``{"network": "<network name or ID>"}``).
:param root_disk_size: The size of the root partition. By default :param root_size_gb: The size of the root partition. By default
the value of the local_gb property is used. the value of the local_gb property is used.
:param swap_size_mb: The size of the swap partition. It's an error
to specify it for a whole disk image.
:param config: :py:class:`metalsmith.InstanceConfig` object with :param config: :py:class:`metalsmith.InstanceConfig` object with
the configuration to pass to the instance. the configuration to pass to the instance.
:param hostname: Hostname to assign to the instance. Defaults to the :param hostname: Hostname to assign to the instance. Defaults to the
@ -233,6 +237,7 @@ class Provisioner(object):
:meth:`reserve_node` for that. :meth:`reserve_node` for that.
:param wait: How many seconds to wait for the deployment to finish, :param wait: How many seconds to wait for the deployment to finish,
None to return immediately. None to return immediately.
:param root_disk_size: DEPRECATED, use ``root_size_gb``.
:return: :py:class:`metalsmith.Instance` object with the current :return: :py:class:`metalsmith.Instance` object with the current
status of provisioning. If ``wait`` is not ``None``, provisioning status of provisioning. If ``wait`` is not ``None``, provisioning
is already finished. is already finished.
@ -242,6 +247,10 @@ class Provisioner(object):
config = _config.InstanceConfig() config = _config.InstanceConfig()
if isinstance(image, six.string_types): if isinstance(image, six.string_types):
image = sources.GlanceImage(image) image = sources.GlanceImage(image)
if root_disk_size is not None:
warnings.warn("root_disk_size is deprecated, use root_size_gb "
"instead", DeprecationWarning)
root_size_gb = root_disk_size
node = self._check_node_for_deploy(node) node = self._check_node_for_deploy(node)
created_ports = [] created_ports = []
@ -249,7 +258,7 @@ class Provisioner(object):
try: try:
hostname = self._check_hostname(node, hostname) hostname = self._check_hostname(node, hostname)
root_disk_size = _utils.get_root_disk(root_disk_size, node) root_size_gb = _utils.get_root_disk(root_size_gb, node)
image._validate(self.connection) image._validate(self.connection)
@ -268,7 +277,7 @@ class Provisioner(object):
capabilities['boot_option'] = 'netboot' if netboot else 'local' capabilities['boot_option'] = 'netboot' if netboot else 'local'
updates = {'/instance_info/root_gb': root_disk_size, updates = {'/instance_info/root_gb': root_size_gb,
'/instance_info/capabilities': capabilities, '/instance_info/capabilities': capabilities,
'/extra/%s' % _CREATED_PORTS: created_ports, '/extra/%s' % _CREATED_PORTS: created_ports,
'/extra/%s' % _ATTACHED_PORTS: attached_ports, '/extra/%s' % _ATTACHED_PORTS: attached_ports,
@ -276,6 +285,8 @@ class Provisioner(object):
updates.update(image._node_updates(self.connection)) updates.update(image._node_updates(self.connection))
if traits is not None: if traits is not None:
updates['/instance_info/traits'] = traits updates['/instance_info/traits'] = traits
if swap_size_mb is not None:
updates['/instance_info/swap_mb'] = swap_size_mb
LOG.debug('Updating node %(node)s with %(updates)s', LOG.debug('Updating node %(node)s with %(updates)s',
{'node': _utils.log_node(node), 'updates': updates}) {'node': _utils.log_node(node), 'updates': updates})

View File

@ -42,22 +42,22 @@ def get_capabilities(node):
return caps return caps
def get_root_disk(root_disk_size, node): def get_root_disk(root_size_gb, node):
"""Validate and calculate the root disk size.""" """Validate and calculate the root disk size."""
if root_disk_size is not None: if root_size_gb is not None:
if not isinstance(root_disk_size, int): if not isinstance(root_size_gb, int):
raise TypeError("The root_disk_size argument must be " raise TypeError("The root_size_gb argument must be "
"a positive integer, got %r" % root_disk_size) "a positive integer, got %r" % root_size_gb)
elif root_disk_size <= 0: elif root_size_gb <= 0:
raise ValueError("The root_disk_size argument must be " raise ValueError("The root_size_gb argument must be "
"a positive integer, got %d" % root_disk_size) "a positive integer, got %d" % root_size_gb)
else: else:
try: try:
assert int(node.properties['local_gb']) > 0 assert int(node.properties['local_gb']) > 0
except KeyError: except KeyError:
raise exceptions.UnknownRootDiskSize( raise exceptions.UnknownRootDiskSize(
'No local_gb for node %s and no root disk size requested' % 'No local_gb for node %s and no root partition size '
log_node(node)) 'specified' % log_node(node))
except (TypeError, ValueError, AssertionError): except (TypeError, ValueError, AssertionError):
raise exceptions.UnknownRootDiskSize( raise exceptions.UnknownRootDiskSize(
'The local_gb for node %(node)s is invalid: ' 'The local_gb for node %(node)s is invalid: '
@ -66,9 +66,9 @@ def get_root_disk(root_disk_size, node):
'value': node.properties['local_gb']}) 'value': node.properties['local_gb']})
# allow for partitioning and config drive # allow for partitioning and config drive
root_disk_size = int(node.properties['local_gb']) - 1 root_size_gb = int(node.properties['local_gb']) - 1
return root_disk_size return root_size_gb
_HOSTNAME_RE = re.compile(r"""^ _HOSTNAME_RE = re.compile(r"""^

View File

@ -29,7 +29,6 @@ from metalsmith import sources
@mock.patch.object(_provisioner, 'Provisioner', autospec=True) @mock.patch.object(_provisioner, 'Provisioner', autospec=True)
@mock.patch.object(_cmd.os_config, 'OpenStackConfig', autospec=True)
class TestDeploy(testtools.TestCase): class TestDeploy(testtools.TestCase):
def setUp(self): def setUp(self):
super(TestDeploy, self).setUp() super(TestDeploy, self).setUp()
@ -37,8 +36,42 @@ class TestDeploy(testtools.TestCase):
'metalsmith._format._print', autospec=True)) 'metalsmith._format._print', autospec=True))
self.mock_print = self.print_fixture.mock self.mock_print = self.print_fixture.mock
self.os_conf_fixture = self.useFixture(fixtures.MockPatchObject(
_cmd.os_config, 'OpenStackConfig', autospec=True))
self.mock_os_conf = self.os_conf_fixture.mock
def _check(self, mock_pr, args, reserve_args, provision_args,
dry_run=False):
reserve_defaults = dict(resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None)
reserve_defaults.update(reserve_args)
provision_defaults = dict(image='myimg',
nics=[{'network': 'mynet'}],
root_size_gb=None,
swap_size_mb=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
provision_defaults.update(provision_args)
_cmd.main(args)
mock_pr.assert_called_once_with(
cloud_region=self.mock_os_conf.return_value.get_one.return_value,
dry_run=dry_run)
mock_pr.return_value.reserve_node.assert_called_once_with(
**reserve_defaults)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
**provision_defaults)
@mock.patch.object(_cmd, 'logging', autospec=True) @mock.patch.object(_cmd, 'logging', autospec=True)
def test_args_ok(self, mock_log, mock_os_conf, mock_pr): def test_args_ok(self, mock_log, mock_pr):
instance = mock_pr.return_value.provision_node.return_value instance = mock_pr.return_value.provision_node.return_value
instance.create_autospec(_instance.Instance) instance.create_autospec(_instance.Instance)
instance.node.name = None instance.node.name = None
@ -49,27 +82,8 @@ class TestDeploy(testtools.TestCase):
args = ['deploy', '--network', 'mynet', '--image', 'myimg', args = ['deploy', '--network', 'mynet', '--image', 'myimg',
'--resource-class', 'compute'] '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'network': 'mynet'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
config = mock_pr.return_value.provision_node.call_args[1]['config'] config = mock_pr.return_value.provision_node.call_args[1]['config']
self.assertEqual([], config.ssh_keys) self.assertEqual([], config.ssh_keys)
mock_log.basicConfig.assert_called_once_with(level=mock_log.WARNING, mock_log.basicConfig.assert_called_once_with(level=mock_log.WARNING,
@ -86,7 +100,7 @@ class TestDeploy(testtools.TestCase):
]) ])
@mock.patch.object(_cmd, 'logging', autospec=True) @mock.patch.object(_cmd, 'logging', autospec=True)
def test_args_json_format(self, mock_log, mock_os_conf, mock_pr): def test_args_json_format(self, mock_log, mock_pr):
instance = mock_pr.return_value.provision_node.return_value instance = mock_pr.return_value.provision_node.return_value
instance.create_autospec(_instance.Instance) instance.create_autospec(_instance.Instance)
instance.to_dict.return_value = {'node': 'dict'} instance.to_dict.return_value = {'node': 'dict'}
@ -95,29 +109,10 @@ class TestDeploy(testtools.TestCase):
'--image', 'myimg', '--resource-class', 'compute'] '--image', 'myimg', '--resource-class', 'compute']
fake_io = six.StringIO() fake_io = six.StringIO()
with mock.patch('sys.stdout', fake_io): with mock.patch('sys.stdout', fake_io):
_cmd.main(args) self._check(mock_pr, args, {}, {})
self.assertEqual(json.loads(fake_io.getvalue()), self.assertEqual(json.loads(fake_io.getvalue()),
{'node': 'dict'}) {'node': 'dict'})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'network': 'mynet'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
mock_log.basicConfig.assert_called_once_with(level=mock_log.WARNING, mock_log.basicConfig.assert_called_once_with(level=mock_log.WARNING,
format=mock.ANY) format=mock.ANY)
self.assertEqual( self.assertEqual(
@ -126,7 +121,7 @@ class TestDeploy(testtools.TestCase):
mock_log.CRITICAL).call_list(), mock_log.CRITICAL).call_list(),
mock_log.getLogger.mock_calls) mock_log.getLogger.mock_calls)
def test_no_ips(self, mock_os_conf, mock_pr): def test_no_ips(self, mock_pr):
instance = mock_pr.return_value.provision_node.return_value instance = mock_pr.return_value.provision_node.return_value
instance.create_autospec(_instance.Instance) instance.create_autospec(_instance.Instance)
instance.is_deployed = True instance.is_deployed = True
@ -137,12 +132,12 @@ class TestDeploy(testtools.TestCase):
args = ['deploy', '--network', 'mynet', '--image', 'myimg', args = ['deploy', '--network', 'mynet', '--image', 'myimg',
'--resource-class', 'compute'] '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {})
self.mock_print.assert_called_once_with(mock.ANY, node='123', self.mock_print.assert_called_once_with(mock.ANY, node='123',
state='active'), state='active'),
def test_not_deployed_no_ips(self, mock_os_conf, mock_pr): def test_not_deployed_no_ips(self, mock_pr):
instance = mock_pr.return_value.provision_node.return_value instance = mock_pr.return_value.provision_node.return_value
instance.create_autospec(_instance.Instance) instance.create_autospec(_instance.Instance)
instance.is_deployed = False instance.is_deployed = False
@ -152,72 +147,34 @@ class TestDeploy(testtools.TestCase):
args = ['deploy', '--network', 'mynet', '--image', 'myimg', args = ['deploy', '--network', 'mynet', '--image', 'myimg',
'--resource-class', 'compute'] '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {})
self.mock_print.assert_called_once_with(mock.ANY, node='123', self.mock_print.assert_called_once_with(mock.ANY, node='123',
state='deploying'), state='deploying'),
@mock.patch.object(_cmd.LOG, 'info', autospec=True) @mock.patch.object(_cmd.LOG, 'info', autospec=True)
def test_no_logs_not_deployed(self, mock_log, mock_os_conf, mock_pr): def test_no_logs_not_deployed(self, mock_log, mock_pr):
instance = mock_pr.return_value.provision_node.return_value instance = mock_pr.return_value.provision_node.return_value
instance.create_autospec(_instance.Instance) instance.create_autospec(_instance.Instance)
instance.is_deployed = False instance.is_deployed = False
args = ['deploy', '--network', 'mynet', '--image', 'myimg', args = ['deploy', '--network', 'mynet', '--image', 'myimg',
'--resource-class', 'compute'] '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {})
self.assertFalse(mock_log.called) self.assertFalse(mock_log.called)
self.assertFalse(instance.ip_addresses.called) self.assertFalse(instance.ip_addresses.called)
def test_args_dry_run(self, mock_os_conf, mock_pr): def test_args_dry_run(self, mock_pr):
args = ['--dry-run', 'deploy', '--network', 'mynet', args = ['--dry-run', 'deploy', '--network', 'mynet',
'--image', 'myimg', '--resource-class', 'compute'] '--image', 'myimg', '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {}, dry_run=True)
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=True)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'network': 'mynet'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
@mock.patch.object(_cmd, 'logging', autospec=True) @mock.patch.object(_cmd, 'logging', autospec=True)
def test_args_debug(self, mock_log, mock_os_conf, mock_pr): def test_args_debug(self, mock_log, mock_pr):
args = ['--debug', 'deploy', '--network', 'mynet', '--image', 'myimg', args = ['--debug', 'deploy', '--network', 'mynet', '--image', 'myimg',
'--resource-class', 'compute'] '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'network': 'mynet'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
mock_log.basicConfig.assert_called_once_with(level=mock_log.DEBUG, mock_log.basicConfig.assert_called_once_with(level=mock_log.DEBUG,
format=mock.ANY) format=mock.ANY)
@ -228,29 +185,10 @@ class TestDeploy(testtools.TestCase):
mock_log.getLogger.mock_calls) mock_log.getLogger.mock_calls)
@mock.patch.object(_cmd, 'logging', autospec=True) @mock.patch.object(_cmd, 'logging', autospec=True)
def test_args_quiet(self, mock_log, mock_os_conf, mock_pr): def test_args_quiet(self, mock_log, mock_pr):
args = ['--quiet', 'deploy', '--network', 'mynet', '--image', 'myimg', args = ['--quiet', 'deploy', '--network', 'mynet', '--image', 'myimg',
'--resource-class', 'compute'] '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'network': 'mynet'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
mock_log.basicConfig.assert_called_once_with(level=mock_log.CRITICAL, mock_log.basicConfig.assert_called_once_with(level=mock_log.CRITICAL,
format=mock.ANY) format=mock.ANY)
@ -263,29 +201,10 @@ class TestDeploy(testtools.TestCase):
self.assertFalse(self.mock_print.called) self.assertFalse(self.mock_print.called)
@mock.patch.object(_cmd, 'logging', autospec=True) @mock.patch.object(_cmd, 'logging', autospec=True)
def test_args_verbose_1(self, mock_log, mock_os_conf, mock_pr): def test_args_verbose_1(self, mock_log, mock_pr):
args = ['-v', 'deploy', '--network', 'mynet', '--image', 'myimg', args = ['-v', 'deploy', '--network', 'mynet', '--image', 'myimg',
'--resource-class', 'compute'] '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'network': 'mynet'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
mock_log.basicConfig.assert_called_once_with(level=mock_log.WARNING, mock_log.basicConfig.assert_called_once_with(level=mock_log.WARNING,
format=mock.ANY) format=mock.ANY)
@ -296,29 +215,10 @@ class TestDeploy(testtools.TestCase):
mock_log.getLogger.mock_calls) mock_log.getLogger.mock_calls)
@mock.patch.object(_cmd, 'logging', autospec=True) @mock.patch.object(_cmd, 'logging', autospec=True)
def test_args_verbose_2(self, mock_log, mock_os_conf, mock_pr): def test_args_verbose_2(self, mock_log, mock_pr):
args = ['-vv', 'deploy', '--network', 'mynet', '--image', 'myimg', args = ['-vv', 'deploy', '--network', 'mynet', '--image', 'myimg',
'--resource-class', 'compute'] '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'network': 'mynet'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
mock_log.basicConfig.assert_called_once_with(level=mock_log.INFO, mock_log.basicConfig.assert_called_once_with(level=mock_log.INFO,
format=mock.ANY) format=mock.ANY)
@ -329,29 +229,10 @@ class TestDeploy(testtools.TestCase):
mock_log.getLogger.mock_calls) mock_log.getLogger.mock_calls)
@mock.patch.object(_cmd, 'logging', autospec=True) @mock.patch.object(_cmd, 'logging', autospec=True)
def test_args_verbose_3(self, mock_log, mock_os_conf, mock_pr): def test_args_verbose_3(self, mock_log, mock_pr):
args = ['-vvv', 'deploy', '--network', 'mynet', '--image', 'myimg', args = ['-vvv', 'deploy', '--network', 'mynet', '--image', 'myimg',
'--resource-class', 'compute'] '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'network': 'mynet'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
mock_log.basicConfig.assert_called_once_with(level=mock_log.DEBUG, mock_log.basicConfig.assert_called_once_with(level=mock_log.DEBUG,
format=mock.ANY) format=mock.ANY)
@ -362,7 +243,7 @@ class TestDeploy(testtools.TestCase):
mock_log.getLogger.mock_calls) mock_log.getLogger.mock_calls)
@mock.patch.object(_cmd.LOG, 'critical', autospec=True) @mock.patch.object(_cmd.LOG, 'critical', autospec=True)
def test_reservation_failure(self, mock_log, mock_os_conf, mock_pr): def test_reservation_failure(self, mock_log, mock_pr):
args = ['deploy', '--network', 'mynet', '--image', 'myimg', args = ['deploy', '--network', 'mynet', '--image', 'myimg',
'--resource-class', 'compute'] '--resource-class', 'compute']
failure = RuntimeError('boom') failure = RuntimeError('boom')
@ -371,7 +252,7 @@ class TestDeploy(testtools.TestCase):
mock_log.assert_called_once_with('%s', failure, exc_info=False) mock_log.assert_called_once_with('%s', failure, exc_info=False)
@mock.patch.object(_cmd.LOG, 'critical', autospec=True) @mock.patch.object(_cmd.LOG, 'critical', autospec=True)
def test_deploy_failure(self, mock_log, mock_os_conf, mock_pr): def test_deploy_failure(self, mock_log, mock_pr):
args = ['deploy', '--network', 'mynet', '--image', 'myimg', args = ['deploy', '--network', 'mynet', '--image', 'myimg',
'--resource-class', 'compute'] '--resource-class', 'compute']
failure = RuntimeError('boom') failure = RuntimeError('boom')
@ -380,356 +261,116 @@ class TestDeploy(testtools.TestCase):
mock_log.assert_called_once_with('%s', failure, exc_info=False) mock_log.assert_called_once_with('%s', failure, exc_info=False)
@mock.patch.object(_cmd.LOG, 'critical', autospec=True) @mock.patch.object(_cmd.LOG, 'critical', autospec=True)
def test_invalid_hostname(self, mock_log, mock_os_conf, mock_pr): def test_invalid_hostname(self, mock_log, mock_pr):
args = ['deploy', '--hostname', 'n_1', '--image', 'myimg', args = ['deploy', '--hostname', 'n_1', '--image', 'myimg',
'--resource-class', 'compute'] '--resource-class', 'compute']
self.assertRaises(SystemExit, _cmd.main, args) self.assertRaises(SystemExit, _cmd.main, args)
self.assertTrue(mock_log.called) self.assertTrue(mock_log.called)
def test_args_capabilities(self, mock_os_conf, mock_pr): def test_args_capabilities(self, mock_pr):
args = ['deploy', '--network', 'mynet', '--image', 'myimg', args = ['deploy', '--network', 'mynet', '--image', 'myimg',
'--capability', 'foo=bar', '--capability', 'answer=42', '--capability', 'foo=bar', '--capability', 'answer=42',
'--resource-class', 'compute'] '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args,
mock_pr.assert_called_once_with( {'capabilities': {'foo': 'bar', 'answer': '42'}}, {})
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={'foo': 'bar', 'answer': '42'},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'network': 'mynet'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
def test_args_traits(self, mock_os_conf, mock_pr): def test_args_traits(self, mock_pr):
args = ['deploy', '--network', 'mynet', '--image', 'myimg', args = ['deploy', '--network', 'mynet', '--image', 'myimg',
'--trait', 'foo:bar', '--trait', 'answer:42', '--trait', 'foo:bar', '--trait', 'answer:42',
'--resource-class', 'compute'] '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args,
mock_pr.assert_called_once_with( {'traits': ['foo:bar', 'answer:42']}, {})
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=['foo:bar', 'answer:42'],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'network': 'mynet'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
def test_args_configdrive(self, mock_os_conf, mock_pr): def test_args_configdrive(self, mock_pr):
with tempfile.NamedTemporaryFile() as fp: with tempfile.NamedTemporaryFile() as fp:
fp.write(b'foo\n') fp.write(b'foo\n')
fp.flush() fp.flush()
args = ['deploy', '--network', 'mynet', '--image', 'myimg', args = ['deploy', '--network', 'mynet', '--image', 'myimg',
'--ssh-public-key', fp.name, '--resource-class', 'compute'] '--ssh-public-key', fp.name, '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'network': 'mynet'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
config = mock_pr.return_value.provision_node.call_args[1]['config'] config = mock_pr.return_value.provision_node.call_args[1]['config']
self.assertEqual(['foo'], config.ssh_keys) self.assertEqual(['foo'], config.ssh_keys)
@mock.patch.object(_config.InstanceConfig, 'add_user', autospec=True) @mock.patch.object(_config.InstanceConfig, 'add_user', autospec=True)
def test_args_user_name(self, mock_add_user, mock_os_conf, mock_pr): def test_args_user_name(self, mock_add_user, mock_pr):
args = ['deploy', '--network', 'mynet', '--image', 'myimg', args = ['deploy', '--network', 'mynet', '--image', 'myimg',
'--user-name', 'banana', '--resource-class', 'compute'] '--user-name', 'banana', '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'network': 'mynet'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
config = mock_pr.return_value.provision_node.call_args[1]['config'] config = mock_pr.return_value.provision_node.call_args[1]['config']
self.assertEqual([], config.ssh_keys) self.assertEqual([], config.ssh_keys)
mock_add_user.assert_called_once_with(config, 'banana', sudo=False) mock_add_user.assert_called_once_with(config, 'banana', sudo=False)
@mock.patch.object(_config.InstanceConfig, 'add_user', autospec=True) @mock.patch.object(_config.InstanceConfig, 'add_user', autospec=True)
def test_args_user_name_with_sudo(self, mock_add_user, mock_os_conf, def test_args_user_name_with_sudo(self, mock_add_user, mock_pr):
mock_pr):
args = ['deploy', '--network', 'mynet', '--image', 'myimg', args = ['deploy', '--network', 'mynet', '--image', 'myimg',
'--user-name', 'banana', '--resource-class', 'compute', '--user-name', 'banana', '--resource-class', 'compute',
'--passwordless-sudo'] '--passwordless-sudo']
_cmd.main(args) self._check(mock_pr, args, {}, {})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'network': 'mynet'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
config = mock_pr.return_value.provision_node.call_args[1]['config'] config = mock_pr.return_value.provision_node.call_args[1]['config']
self.assertEqual([], config.ssh_keys) self.assertEqual([], config.ssh_keys)
mock_add_user.assert_called_once_with(config, 'banana', sudo=True) mock_add_user.assert_called_once_with(config, 'banana', sudo=True)
def test_args_port(self, mock_os_conf, mock_pr): def test_args_port(self, mock_pr):
args = ['deploy', '--port', 'myport', '--image', 'myimg', args = ['deploy', '--port', 'myport', '--image', 'myimg',
'--resource-class', 'compute'] '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {'nics': [{'port': 'myport'}]})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'port': 'myport'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
def test_args_no_nics(self, mock_os_conf, mock_pr): def test_args_no_nics(self, mock_pr):
args = ['deploy', '--image', 'myimg', '--resource-class', 'compute'] args = ['deploy', '--image', 'myimg', '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {'nics': None})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=None,
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
def test_args_networks_and_ports(self, mock_os_conf, mock_pr): def test_args_networks_and_ports(self, mock_pr):
args = ['deploy', '--network', 'net1', '--port', 'port1', args = ['deploy', '--network', 'net1', '--port', 'port1',
'--port', 'port2', '--network', 'net2', '--port', 'port2', '--network', 'net2',
'--image', 'myimg', '--resource-class', 'compute'] '--image', 'myimg', '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {},
mock_pr.assert_called_once_with( {'nics': [{'network': 'net1'}, {'port': 'port1'},
cloud_region=mock_os_conf.return_value.get_one.return_value, {'port': 'port2'}, {'network': 'net2'}]})
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'network': 'net1'}, {'port': 'port1'},
{'port': 'port2'}, {'network': 'net2'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
def test_args_hostname(self, mock_os_conf, mock_pr): def test_args_hostname(self, mock_pr):
args = ['deploy', '--hostname', 'host', '--image', 'myimg', args = ['deploy', '--network', 'mynet', '--image', 'myimg',
'--hostname', 'host', '--resource-class', 'compute']
self._check(mock_pr, args, {}, {'hostname': 'host'})
def test_args_with_candidates(self, mock_pr):
args = ['deploy', '--network', 'mynet', '--image', 'myimg',
'--candidate', 'node1', '--candidate', 'node2',
'--resource-class', 'compute'] '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {'candidates': ['node1', 'node2']}, {})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=None,
root_disk_size=None,
config=mock.ANY,
hostname='host',
netboot=False,
wait=1800)
def test_args_with_candidates(self, mock_os_conf, mock_pr): def test_args_conductor_group(self, mock_pr):
args = ['deploy', '--hostname', 'host', '--image', 'myimg', args = ['deploy', '--network', 'mynet', '--image', 'myimg',
'--candidate', 'node1', '--candidate', 'node2'] '--conductor-group', 'loc1', '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {'conductor_group': 'loc1'}, {})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class=None,
conductor_group=None,
capabilities={},
traits=[],
candidates=['node1', 'node2']
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=None,
root_disk_size=None,
config=mock.ANY,
hostname='host',
netboot=False,
wait=1800)
def test_args_conductor_group(self, mock_os_conf, mock_pr): def test_args_http_image_with_checksum(self, mock_pr):
args = ['deploy', '--conductor-group', 'loc1', '--image', 'myimg',
'--resource-class', 'compute']
_cmd.main(args)
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group='loc1',
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=None,
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
def test_args_http_image_with_checksum(self, mock_os_conf, mock_pr):
args = ['deploy', '--image', 'https://example.com/image.img', args = ['deploy', '--image', 'https://example.com/image.img',
'--image-checksum', '95e750180c7921ea0d545c7165db66b8', '--image-checksum', '95e750180c7921ea0d545c7165db66b8',
'--resource-class', 'compute'] '--network', 'mynet', '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {'image': mock.ANY})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image=mock.ANY,
nics=None,
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
source = mock_pr.return_value.provision_node.call_args[1]['image'] source = mock_pr.return_value.provision_node.call_args[1]['image']
self.assertIsInstance(source, sources.HttpWholeDiskImage) self.assertIsInstance(source, sources.HttpWholeDiskImage)
self.assertEqual('https://example.com/image.img', source.url) self.assertEqual('https://example.com/image.img', source.url)
self.assertEqual('95e750180c7921ea0d545c7165db66b8', source.checksum) self.assertEqual('95e750180c7921ea0d545c7165db66b8', source.checksum)
def test_args_http_image_with_checksum_url(self, mock_os_conf, mock_pr): def test_args_http_image_with_checksum_url(self, mock_pr):
args = ['deploy', '--image', 'http://example.com/image.img', args = ['deploy', '--image', 'http://example.com/image.img',
'--image-checksum', 'http://example.com/CHECKSUMS', '--image-checksum', 'http://example.com/CHECKSUMS',
'--resource-class', 'compute'] '--network', 'mynet', '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {'image': mock.ANY})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image=mock.ANY,
nics=None,
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=1800)
source = mock_pr.return_value.provision_node.call_args[1]['image'] source = mock_pr.return_value.provision_node.call_args[1]['image']
self.assertIsInstance(source, sources.HttpWholeDiskImage) self.assertIsInstance(source, sources.HttpWholeDiskImage)
self.assertEqual('http://example.com/image.img', source.url) self.assertEqual('http://example.com/image.img', source.url)
self.assertEqual('http://example.com/CHECKSUMS', source.checksum_url) self.assertEqual('http://example.com/CHECKSUMS', source.checksum_url)
@mock.patch.object(_cmd.LOG, 'critical', autospec=True) @mock.patch.object(_cmd.LOG, 'critical', autospec=True)
def test_args_http_image_without_checksum(self, mock_log, mock_os_conf, def test_args_http_image_without_checksum(self, mock_log, mock_pr):
mock_pr):
args = ['deploy', '--image', 'http://example.com/image.img', args = ['deploy', '--image', 'http://example.com/image.img',
'--resource-class', 'compute'] '--resource-class', 'compute']
self.assertRaises(SystemExit, _cmd.main, args) self.assertRaises(SystemExit, _cmd.main, args)
@ -737,53 +378,25 @@ class TestDeploy(testtools.TestCase):
self.assertFalse(mock_pr.return_value.reserve_node.called) self.assertFalse(mock_pr.return_value.reserve_node.called)
self.assertFalse(mock_pr.return_value.provision_node.called) self.assertFalse(mock_pr.return_value.provision_node.called)
def test_args_custom_wait(self, mock_os_conf, mock_pr): def test_args_custom_wait(self, mock_pr):
args = ['deploy', '--network', 'mynet', '--image', 'myimg', args = ['deploy', '--network', 'mynet', '--image', 'myimg',
'--wait', '3600', '--resource-class', 'compute'] '--wait', '3600', '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {'wait': 3600})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value,
dry_run=False)
mock_pr.return_value.reserve_node.assert_called_once_with(
resource_class='compute',
conductor_group=None,
capabilities={},
traits=[],
candidates=None
)
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'network': 'mynet'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=3600)
def test_args_no_wait(self, mock_os_conf, mock_pr): def test_args_no_wait(self, mock_pr):
args = ['deploy', '--network', 'mynet', '--image', 'myimg', args = ['deploy', '--network', 'mynet', '--image', 'myimg',
'--no-wait', '--resource-class', 'compute'] '--no-wait', '--resource-class', 'compute']
_cmd.main(args) self._check(mock_pr, args, {}, {'wait': None})
mock_pr.assert_called_once_with(
cloud_region=mock_os_conf.return_value.get_one.return_value, def test_with_root_size(self, mock_pr):
dry_run=False) args = ['deploy', '--network', 'mynet', '--image', 'myimg',
mock_pr.return_value.reserve_node.assert_called_once_with( '--root-size', '100', '--resource-class', 'compute']
resource_class='compute', self._check(mock_pr, args, {}, {'root_size_gb': 100})
conductor_group=None,
capabilities={}, def test_with_swap_size(self, mock_pr):
traits=[], args = ['deploy', '--network', 'mynet', '--image', 'myimg',
candidates=None '--swap-size', '4096', '--resource-class', 'compute']
) self._check(mock_pr, args, {}, {'swap_size_mb': 4096})
mock_pr.return_value.provision_node.assert_called_once_with(
mock_pr.return_value.reserve_node.return_value,
image='myimg',
nics=[{'network': 'mynet'}],
root_disk_size=None,
config=mock.ANY,
hostname=None,
netboot=False,
wait=None)
@mock.patch.object(_provisioner, 'Provisioner', autospec=True) @mock.patch.object(_provisioner, 'Provisioner', autospec=True)

View File

@ -585,7 +585,26 @@ abcd image
self.assertFalse(self.api.release_node.called) self.assertFalse(self.api.release_node.called)
self.assertFalse(self.conn.network.delete_port.called) self.assertFalse(self.conn.network.delete_port.called)
def test_with_root_disk_size(self): def test_with_root_size(self):
self.updates['/instance_info/root_gb'] = 50
self.pr.provision_node(self.node, 'image', [{'network': 'network'}],
root_size_gb=50)
self.conn.network.create_port.assert_called_once_with(
network_id=self.conn.network.find_network.return_value.id)
self.api.attach_port_to_node.assert_called_once_with(
self.node.uuid, self.conn.network.create_port.return_value.id)
self.api.update_node.assert_called_once_with(self.node, self.updates)
self.api.validate_node.assert_called_once_with(self.node,
validate_deploy=True)
self.api.node_action.assert_called_once_with(self.node, 'active',
configdrive=mock.ANY)
self.assertFalse(self.wait_mock.called)
self.assertFalse(self.api.release_node.called)
self.assertFalse(self.conn.network.delete_port.called)
def test_with_deprecated_root_size(self):
self.updates['/instance_info/root_gb'] = 50 self.updates['/instance_info/root_gb'] = 50
self.pr.provision_node(self.node, 'image', [{'network': 'network'}], self.pr.provision_node(self.node, 'image', [{'network': 'network'}],
@ -604,6 +623,25 @@ abcd image
self.assertFalse(self.api.release_node.called) self.assertFalse(self.api.release_node.called)
self.assertFalse(self.conn.network.delete_port.called) self.assertFalse(self.conn.network.delete_port.called)
def test_with_swap_size(self):
self.updates['/instance_info/swap_mb'] = 4096
self.pr.provision_node(self.node, 'image', [{'network': 'network'}],
swap_size_mb=4096)
self.conn.network.create_port.assert_called_once_with(
network_id=self.conn.network.find_network.return_value.id)
self.api.attach_port_to_node.assert_called_once_with(
self.node.uuid, self.conn.network.create_port.return_value.id)
self.api.update_node.assert_called_once_with(self.node, self.updates)
self.api.validate_node.assert_called_once_with(self.node,
validate_deploy=True)
self.api.node_action.assert_called_once_with(self.node, 'active',
configdrive=mock.ANY)
self.assertFalse(self.wait_mock.called)
self.assertFalse(self.api.release_node.called)
self.assertFalse(self.conn.network.delete_port.called)
def test_with_capabilities(self): def test_with_capabilities(self):
inst = self.pr.provision_node(self.node, 'image', inst = self.pr.provision_node(self.node, 'image',
[{'network': 'network'}], [{'network': 'network'}],

View File

@ -13,6 +13,8 @@
vars: vars:
image: "{{ metalsmith_whole_disk_image }}" image: "{{ metalsmith_whole_disk_image }}"
image_checksum: "{{ metalsmith_whole_disk_checksum | default('') }}" image_checksum: "{{ metalsmith_whole_disk_checksum | default('') }}"
# NOTE(dtantsur): cannot specify swap with whole disk images
metalsmith_swap_size:
- name: Test a partition image - name: Test a partition image
include: exercise.yaml include: exercise.yaml

View File

@ -35,6 +35,8 @@ The following optional variables provide the defaults for Instance_ attributes:
the default for ``root_size``. the default for ``root_size``.
``metalsmith_ssh_public_keys`` ``metalsmith_ssh_public_keys``
the default for ``ssh_public_keys``. the default for ``ssh_public_keys``.
``metalsmith_swap_size``
the default for ``swap_size``.
``metalsmith_traits`` ``metalsmith_traits``
the default for ``traits``. the default for ``traits``.
``metalsmith_user_name`` ``metalsmith_user_name``
@ -87,7 +89,7 @@ Each instances has the following attributes:
``resource_class`` (defaults to ``metalsmith_resource_class``) ``resource_class`` (defaults to ``metalsmith_resource_class``)
requested node's resource class. requested node's resource class.
``root_size`` (defaults to ``metalsmith_root_size``) ``root_size`` (defaults to ``metalsmith_root_size``)
size of the root partition, if partition images are used. size of the root partition (in GiB), if partition images are used.
.. note:: .. note::
Also required for whole-disk images due to how the Bare Metal service Also required for whole-disk images due to how the Bare Metal service
@ -95,6 +97,9 @@ Each instances has the following attributes:
``ssh_public_keys`` (defaults to ``metalsmith_ssh_public_keys``) ``ssh_public_keys`` (defaults to ``metalsmith_ssh_public_keys``)
list of file names with SSH public keys to put to the node. list of file names with SSH public keys to put to the node.
``swap_size`` (defaults to ``metalsmith_swap_size``)
size of the swap partition (in MiB), if partition images are used
(it's an error to set it for a whole disk image).
``traits`` ``traits``
list of traits the node should have. list of traits the node should have.
``user_name`` (defaults to ``metalsmith_user_name``) ``user_name`` (defaults to ``metalsmith_user_name``)
@ -123,6 +128,7 @@ Example
- hostname: compute-0 - hostname: compute-0
resource_class: compute resource_class: compute
root_size: 100 root_size: 100
swap_size: 4096
capabilities: capabilities:
boot_mode: uefi boot_mode: uefi
traits: traits:
@ -130,6 +136,7 @@ Example
- hostname: compute-1 - hostname: compute-1
resource_class: compute resource_class: compute
root_size: 100 root_size: 100
swap_size: 4096
capabilities: capabilities:
boot_mode: uefi boot_mode: uefi
user_name: heat-admin user_name: heat-admin

View File

@ -8,8 +8,9 @@ metalsmith_netboot: false
metalsmith_nics: [] metalsmith_nics: []
metalsmith_resource_class: metalsmith_resource_class:
metalsmith_root_size: metalsmith_root_size:
metalsmith_traits: []
metalsmith_ssh_public_keys: [] metalsmith_ssh_public_keys: []
metalsmith_swap_size:
metalsmith_traits: []
metalsmith_user_name: metalsmith metalsmith_user_name: metalsmith
# Wait parameters # Wait parameters

View File

@ -15,7 +15,10 @@
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
{% if root_size %} {% if root_size %}
--root-disk-size {{ root_size }} --root-size {{ root_size }}
{% endif %}
{% if swap_size %}
--swap-size {{ swap_size }}
{% endif %} {% endif %}
{% for ssh_key in ssh_public_keys %} {% for ssh_key in ssh_public_keys %}
--ssh-public-key {{ ssh_key }} --ssh-public-key {{ ssh_key }}
@ -54,6 +57,7 @@
root_size: "{{ instance.root_size | default(metalsmith_root_size) }}" root_size: "{{ instance.root_size | default(metalsmith_root_size) }}"
ssh_public_keys: "{{ instance.ssh_public_keys | default(metalsmith_ssh_public_keys) }}" ssh_public_keys: "{{ instance.ssh_public_keys | default(metalsmith_ssh_public_keys) }}"
state: "{{ instance.state | default('present') }}" state: "{{ instance.state | default('present') }}"
swap_size: "{{ instance.swap_size | default(metalsmith_swap_size) }}"
traits: "{{ instance.traits | default(metalsmith_traits) }}" traits: "{{ instance.traits | default(metalsmith_traits) }}"
user_name: "{{ instance.user_name | default(metalsmith_user_name) }}" user_name: "{{ instance.user_name | default(metalsmith_user_name) }}"
with_items: "{{ metalsmith_instances }}" with_items: "{{ metalsmith_instances }}"