Merge "Add a cell and host mapping utility to nova-manage"
This commit is contained in:
commit
bc5035343d
@ -66,6 +66,7 @@ from oslo_db import exception as db_exc
|
||||
from oslo_log import log as logging
|
||||
import oslo_messaging as messaging
|
||||
from oslo_utils import importutils
|
||||
from oslo_utils import uuidutils
|
||||
import six
|
||||
|
||||
from nova.api.ec2 import ec2utils
|
||||
@ -95,6 +96,7 @@ CONF.import_opt('vlan_start', 'nova.network.manager')
|
||||
CONF.import_opt('vpn_start', 'nova.network.manager')
|
||||
CONF.import_opt('default_floating_pool', 'nova.network.floating_ips')
|
||||
CONF.import_opt('public_interface', 'nova.network.linux_net')
|
||||
CONF.import_opt('connection', 'oslo_db.options', group='database')
|
||||
|
||||
QUOTAS = quota.QUOTAS
|
||||
|
||||
@ -1360,6 +1362,74 @@ class CellV2Commands(object):
|
||||
instance = instances[-1]
|
||||
print('Next marker: - %s' % instance.uuid)
|
||||
|
||||
# TODO(melwitt): Remove this when the oslo.messaging function
|
||||
# for assembling a transport url from ConfigOpts is available
|
||||
@args('--transport-url', metavar='<transport url>', required=True,
|
||||
dest='transport_url',
|
||||
help='The transport url for the cell message queue')
|
||||
@args('--name', metavar='<name>', help='The name of the cell')
|
||||
@args('--verbose', action='store_true',
|
||||
help='Return and output the uuid of the created cell')
|
||||
def map_cell_and_hosts(self, transport_url, name=None, verbose=False):
|
||||
"""EXPERIMENTAL. Create a cell mapping and host mappings for a cell.
|
||||
|
||||
Users not dividing their cloud into multiple cells will be a single
|
||||
cell v2 deployment and should specify:
|
||||
|
||||
nova-manage cell_v2 map_cell_and_hosts --config-file <nova.conf>
|
||||
|
||||
Users running multiple cells can add a cell v2 by specifying:
|
||||
|
||||
nova-manage cell_v2 map_cell_and_hosts --config-file <cell nova.conf>
|
||||
"""
|
||||
ctxt = context.RequestContext()
|
||||
cell_mapping_uuid = cell_mapping = None
|
||||
# First, try to detect if a CellMapping has already been created
|
||||
compute_nodes = objects.ComputeNodeList.get_all(ctxt)
|
||||
if not compute_nodes:
|
||||
print(_('No hosts found to map to cell, exiting.'))
|
||||
return(0)
|
||||
missing_nodes = []
|
||||
for compute_node in compute_nodes:
|
||||
try:
|
||||
host_mapping = objects.HostMapping.get_by_host(
|
||||
ctxt, compute_node.host)
|
||||
except exception.HostMappingNotFound:
|
||||
missing_nodes.append(compute_node)
|
||||
else:
|
||||
if verbose:
|
||||
print(_(
|
||||
'Host %(host)s is already mapped to cell %(uuid)s'
|
||||
) % {'host': host_mapping.host,
|
||||
'uuid': host_mapping.cell_mapping.uuid})
|
||||
# Re-using the existing UUID in case there is already a mapping
|
||||
# NOTE(sbauza): There could be possibly multiple CellMappings
|
||||
# if the operator provides another configuration file and moves
|
||||
# the hosts to another cell v2, but that's not really something
|
||||
# we should support.
|
||||
cell_mapping_uuid = host_mapping.cell_mapping.uuid
|
||||
if not missing_nodes:
|
||||
print(_('All hosts are already mapped to cell(s), exiting.'))
|
||||
return(0)
|
||||
# Create the cell mapping in the API database
|
||||
if cell_mapping_uuid is not None:
|
||||
cell_mapping = objects.CellMapping.get_by_uuid(
|
||||
ctxt, cell_mapping_uuid)
|
||||
if cell_mapping is None:
|
||||
cell_mapping_uuid = uuidutils.generate_uuid()
|
||||
cell_mapping = objects.CellMapping(
|
||||
ctxt, uuid=cell_mapping_uuid, name=name,
|
||||
transport_url=transport_url,
|
||||
database_connection=CONF.database.connection)
|
||||
cell_mapping.create()
|
||||
# Pull the hosts from the cell database and create the host mappings
|
||||
for compute_node in missing_nodes:
|
||||
host_mapping = objects.HostMapping(
|
||||
ctxt, host=compute_node.host, cell_mapping=cell_mapping)
|
||||
host_mapping.create()
|
||||
if verbose:
|
||||
print(cell_mapping_uuid)
|
||||
|
||||
|
||||
CATEGORIES = {
|
||||
'account': AccountCommands,
|
||||
|
@ -18,6 +18,7 @@ import sys
|
||||
|
||||
import fixtures
|
||||
import mock
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from nova.cmd import manage
|
||||
from nova import context
|
||||
@ -680,3 +681,140 @@ class CellCommandsTestCase(test.NoDBTestCase):
|
||||
'weight_offset': 0.0,
|
||||
'weight_scale': 0.0}
|
||||
mock_db_cell_create.assert_called_once_with(ctxt, exp_values)
|
||||
|
||||
|
||||
class CellV2CommandsTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(CellV2CommandsTestCase, self).setUp()
|
||||
self.useFixture(fixtures.MonkeyPatch('sys.stdout', StringIO()))
|
||||
self.commands = manage.CellV2Commands()
|
||||
|
||||
def test_map_cell_and_hosts(self):
|
||||
# Create some fake compute nodes and check if they get host mappings
|
||||
ctxt = context.RequestContext()
|
||||
values = {
|
||||
'vcpus': 4,
|
||||
'memory_mb': 4096,
|
||||
'local_gb': 1024,
|
||||
'vcpus_used': 2,
|
||||
'memory_mb_used': 2048,
|
||||
'local_gb_used': 512,
|
||||
'hypervisor_type': 'Hyper-Dan-VM-ware',
|
||||
'hypervisor_version': 1001,
|
||||
'cpu_info': 'Schmintel i786',
|
||||
}
|
||||
for i in range(3):
|
||||
host = 'host%s' % i
|
||||
compute_node = objects.ComputeNode(ctxt, host=host, **values)
|
||||
compute_node.create()
|
||||
cell_transport_url = "fake://guest:devstack@127.0.0.1:9999/"
|
||||
self.commands.map_cell_and_hosts(cell_transport_url, name='ssd',
|
||||
verbose=True)
|
||||
cell_mapping_uuid = sys.stdout.getvalue().strip()
|
||||
# Verify the cell mapping
|
||||
cell_mapping = objects.CellMapping.get_by_uuid(ctxt, cell_mapping_uuid)
|
||||
self.assertEqual('ssd', cell_mapping.name)
|
||||
self.assertEqual(cell_transport_url, cell_mapping.transport_url)
|
||||
# Verify the host mappings
|
||||
for i in range(3):
|
||||
host = 'host%s' % i
|
||||
host_mapping = objects.HostMapping.get_by_host(ctxt, host)
|
||||
self.assertEqual(cell_mapping.uuid, host_mapping.cell_mapping.uuid)
|
||||
|
||||
def test_map_cell_and_hosts_duplicate(self):
|
||||
# Create a cell mapping and hosts and check that nothing new is created
|
||||
ctxt = context.RequestContext()
|
||||
cell_mapping_uuid = uuidutils.generate_uuid()
|
||||
cell_mapping = objects.CellMapping(
|
||||
ctxt, uuid=cell_mapping_uuid, name='fake',
|
||||
transport_url='fake://', database_connection='fake://')
|
||||
cell_mapping.create()
|
||||
# Create compute nodes that will map to the cell
|
||||
values = {
|
||||
'vcpus': 4,
|
||||
'memory_mb': 4096,
|
||||
'local_gb': 1024,
|
||||
'vcpus_used': 2,
|
||||
'memory_mb_used': 2048,
|
||||
'local_gb_used': 512,
|
||||
'hypervisor_type': 'Hyper-Dan-VM-ware',
|
||||
'hypervisor_version': 1001,
|
||||
'cpu_info': 'Schmintel i786',
|
||||
}
|
||||
for i in range(3):
|
||||
host = 'host%s' % i
|
||||
compute_node = objects.ComputeNode(ctxt, host=host, **values)
|
||||
compute_node.create()
|
||||
host_mapping = objects.HostMapping(
|
||||
ctxt, host=host, cell_mapping=cell_mapping)
|
||||
host_mapping.create()
|
||||
cell_transport_url = "fake://guest:devstack@127.0.0.1:9999/"
|
||||
retval = self.commands.map_cell_and_hosts(cell_transport_url,
|
||||
name='ssd',
|
||||
verbose=True)
|
||||
self.assertEqual(0, retval)
|
||||
output = sys.stdout.getvalue().strip()
|
||||
expected = ''
|
||||
for i in range(3):
|
||||
expected += ('Host host%s is already mapped to cell %s\n' %
|
||||
(i, cell_mapping_uuid))
|
||||
expected += 'All hosts are already mapped to cell(s), exiting.'
|
||||
self.assertEqual(expected, output)
|
||||
|
||||
def test_map_cell_and_hosts_partial_update(self):
|
||||
# Create a cell mapping and partial hosts and check that
|
||||
# missing HostMappings are created
|
||||
ctxt = context.RequestContext()
|
||||
cell_mapping_uuid = uuidutils.generate_uuid()
|
||||
cell_mapping = objects.CellMapping(
|
||||
ctxt, uuid=cell_mapping_uuid, name='fake',
|
||||
transport_url='fake://', database_connection='fake://')
|
||||
cell_mapping.create()
|
||||
# Create compute nodes that will map to the cell
|
||||
values = {
|
||||
'vcpus': 4,
|
||||
'memory_mb': 4096,
|
||||
'local_gb': 1024,
|
||||
'vcpus_used': 2,
|
||||
'memory_mb_used': 2048,
|
||||
'local_gb_used': 512,
|
||||
'hypervisor_type': 'Hyper-Dan-VM-ware',
|
||||
'hypervisor_version': 1001,
|
||||
'cpu_info': 'Schmintel i786',
|
||||
}
|
||||
for i in range(3):
|
||||
host = 'host%s' % i
|
||||
compute_node = objects.ComputeNode(ctxt, host=host, **values)
|
||||
compute_node.create()
|
||||
# Only create 2 existing HostMappings out of 3
|
||||
for i in range(2):
|
||||
host = 'host%s' % i
|
||||
host_mapping = objects.HostMapping(
|
||||
ctxt, host=host, cell_mapping=cell_mapping)
|
||||
host_mapping.create()
|
||||
cell_transport_url = "fake://guest:devstack@127.0.0.1:9999/"
|
||||
self.commands.map_cell_and_hosts(cell_transport_url,
|
||||
name='ssd',
|
||||
verbose=True)
|
||||
# Verify the HostMapping for the last host was created
|
||||
host_mapping = objects.HostMapping.get_by_host(ctxt, 'host2')
|
||||
self.assertEqual(cell_mapping.uuid, host_mapping.cell_mapping.uuid)
|
||||
# Verify the output
|
||||
output = sys.stdout.getvalue().strip()
|
||||
expected = ''
|
||||
for i in range(2):
|
||||
expected += ('Host host%s is already mapped to cell %s\n' %
|
||||
(i, cell_mapping_uuid))
|
||||
# The expected CellMapping UUID for the last host should be the same
|
||||
expected += cell_mapping.uuid
|
||||
self.assertEqual(expected, output)
|
||||
|
||||
def test_map_cell_and_hosts_no_hosts_found(self):
|
||||
cell_transport_url = "fake://guest:devstack@127.0.0.1:9999/"
|
||||
retval = self.commands.map_cell_and_hosts(cell_transport_url,
|
||||
name='ssd',
|
||||
verbose=True)
|
||||
self.assertEqual(0, retval)
|
||||
output = sys.stdout.getvalue().strip()
|
||||
expected = 'No hosts found to map to cell, exiting.'
|
||||
self.assertEqual(expected, output)
|
||||
|
Loading…
x
Reference in New Issue
Block a user