Nova keypair support

Now Trove doesn't support to specify keypair when creating the db
instance, the ssh key is injected into the guest agent image at the
build time, which makes it very hard to manage.

This patch adds a config option `nova_keypair` that is used as keypair
name when creating db instance. The old way of the image building will
be changed in the subsequent patches.

Change-Id: I41d4e41fc4bc413cdd48b8d761429b0204481932
Story: #2005429
Task: #30462
This commit is contained in:
Lingxian Kong 2019-04-17 20:04:58 +12:00
parent f4e17a34b9
commit a3de34dbc7
5 changed files with 49 additions and 15 deletions

View File

@ -0,0 +1,13 @@
features:
- Added a new config option ``nova_keypair`` to specify an existing Nova
keypair name for the database instance creation, the cloud administrator is
responsible for the keypair management and configuration. It's recommended
to create Trove database instance in the admin project for security
reasons, so only the cloud administrator who has the private key can access
the database instance. With the keypair support, ssh keys are no longer
injected into Trove guest agent image at build time.
upgrade:
- Cloud administrator needs to create a Nova keypair and specify the keypair
name for config option ``nova_keypair``, the private key is used to ssh
into new database instances created. The previous private key is also
needed to ssh into the existing database instances.

View File

@ -81,6 +81,10 @@ common_opts = [
help="The version of the image service client."),
cfg.BoolOpt('nova_api_insecure', default=False,
help="Allow to perform insecure SSL requests to nova."),
cfg.StrOpt('nova_keypair', default=None,
help="Name of a Nova keypair to inject into a database "
"instance to enable SSH access. The keypair should be "
"prior created by the cloud operator."),
cfg.URIOpt('neutron_url', help='URL without the tenant segment.'),
cfg.StrOpt('neutron_service_type', default='network',
help='Service type to use when searching catalog.'),

View File

@ -890,14 +890,16 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
name = self.hostname or self.name
bdmap_v2 = block_device_mapping_v2
config_drive = CONF.use_nova_server_config_drive
key_name = CONF.nova_keypair
server = self.nova_client.servers.create(
name, image_id, flavor_id, files=files, userdata=userdata,
security_groups=security_groups, block_device_mapping_v2=bdmap_v2,
availability_zone=availability_zone, nics=nics,
config_drive=config_drive, scheduler_hints=scheduler_hints)
config_drive=config_drive, scheduler_hints=scheduler_hints,
key_name=key_name)
LOG.debug("Created new compute instance %(server_id)s "
"for instance %(id)s",
"for database instance %(id)s",
{'server_id': server.id, 'id': self.id})
return server

View File

@ -101,7 +101,7 @@ class FakeServer(object):
next_local_id = 0
def __init__(self, parent, owner, id, name, image_id, flavor_ref,
volumes):
volumes, key_name):
self.owner = owner # This is a context.
self.id = id
self.parent = parent
@ -125,6 +125,7 @@ class FakeServer(object):
setattr(self, 'OS-EXT-AZ:availability_zone', 'nova')
self._info = {'os:volumes': info_vols}
self.key_name = key_name
@property
def addresses(self):
@ -268,11 +269,11 @@ class FakeServers(object):
def create(self, name, image_id, flavor_ref, files=None, userdata=None,
block_device_mapping_v2=None, security_groups=None,
availability_zone=None, nics=None, config_drive=False,
scheduler_hints=None):
scheduler_hints=None, key_name=None):
id = "FAKE_%s" % uuid.uuid4()
volumes = self._get_volumes_from_bdm_v2(block_device_mapping_v2)
server = FakeServer(self, self.context, id, name, image_id, flavor_ref,
volumes)
volumes, key_name)
self.db[id] = server
if name.endswith('SERVER_ERROR'):
raise nova_exceptions.ClientException("Fake server create error.")

View File

@ -79,6 +79,7 @@ class fake_Server(object):
self.security_groups = None
self.block_device_mapping_v2 = None
self.status = 'ACTIVE'
self.key_name = None
class fake_ServerManager(object):
@ -86,7 +87,7 @@ class fake_ServerManager(object):
security_groups, block_device_mapping_v2=None,
availability_zone=None,
nics=None, config_drive=False,
scheduler_hints=None):
scheduler_hints=None, key_name=None):
server = fake_Server()
server.id = "server_id"
server.name = name
@ -98,6 +99,8 @@ class fake_ServerManager(object):
server.block_device_mapping_v2 = block_device_mapping_v2
server.availability_zone = availability_zone
server.nics = nics
server.key_name = key_name
return server
@ -239,6 +242,14 @@ class FreshInstanceTasksTest(BaseFreshInstanceTasksTest):
None, None, None, datastore_manager, None, None, None)
self.assertEqual(server.userdata, self.userdata)
def test_create_instance_with_keypair(self):
cfg.CONF.set_override('nova_keypair', 'fake_keypair')
server = self.freshinstancetasks._create_server(
None, None, None, None, None, None, None)
self.assertEqual('fake_keypair', server.key_name)
@patch.object(DBInstance, 'get_by')
def test_create_instance_guestconfig(self, patch_get_by):
cfg.CONF.set_override('guest_config', self.guestconfig)
@ -303,15 +314,18 @@ class FreshInstanceTasksTest(BaseFreshInstanceTasksTest):
self.freshinstancetasks._create_server('fake-flavor', 'fake-image',
None, 'mysql', None, None,
None)
mock_servers_create.assert_called_with('fake-hostname', 'fake-image',
'fake-flavor', files={},
userdata=None,
security_groups=None,
block_device_mapping_v2=None,
availability_zone=None,
nics=None,
config_drive=True,
scheduler_hints=None)
mock_servers_create.assert_called_with(
'fake-hostname', 'fake-image',
'fake-flavor', files={},
userdata=None,
security_groups=None,
block_device_mapping_v2=None,
availability_zone=None,
nics=None,
config_drive=True,
scheduler_hints=None,
key_name=None
)
@patch.object(InstanceServiceStatus, 'find_by',
return_value=fake_InstanceServiceStatus.find_by())