Merge "Adapt to file injection deprecation in nova"
This commit is contained in:
commit
10ac7a6138
trove
@ -23,9 +23,9 @@ from oslo_config import cfg
|
||||
from oslo_config import types
|
||||
from oslo_config.cfg import NoSuchOptError
|
||||
from oslo_log import log as logging
|
||||
from oslo_log import versionutils
|
||||
from oslo_middleware import cors
|
||||
from osprofiler import opts as profiler
|
||||
from oslo_log import versionutils
|
||||
|
||||
from trove.common.i18n import _
|
||||
from trove.version import version_info as version
|
||||
@ -245,7 +245,7 @@ common_opts = [
|
||||
cfg.IntOpt('trove_conductor_workers',
|
||||
help='Number of workers for the Conductor service. The default '
|
||||
'will be the number of CPUs available.'),
|
||||
cfg.BoolOpt('use_nova_server_config_drive', default=True,
|
||||
cfg.BoolOpt('use_nova_server_config_drive', default=False,
|
||||
help='Use config drive for file injection when booting '
|
||||
'instance.'),
|
||||
cfg.StrOpt('device_path', default='/dev/vdb',
|
||||
|
@ -15,12 +15,14 @@
|
||||
# under the License.
|
||||
|
||||
"""Model classes that form the core of instances functionality."""
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
import base64
|
||||
import json
|
||||
import os.path
|
||||
import re
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
from novaclient import exceptions as nova_exceptions
|
||||
from oslo_config.cfg import NoSuchOptError
|
||||
from oslo_log import log as logging
|
||||
@ -43,8 +45,8 @@ from trove.common.i18n import _
|
||||
from trove.common.trove_remote import create_trove_client
|
||||
from trove.configuration.models import Configuration
|
||||
from trove.datastore import models as datastore_models
|
||||
from trove.datastore.models import DatastoreVersionMetadata as dvm
|
||||
from trove.datastore.models import DBDatastoreVersionMetadata
|
||||
from trove.datastore.models import DatastoreVersionMetadata as dvm
|
||||
from trove.db import get_db_api
|
||||
from trove.db import models as dbmodels
|
||||
from trove.extensions.security_group.models import SecurityGroup
|
||||
@ -614,9 +616,10 @@ def load_instance(cls, context, id, needs_server=False,
|
||||
|
||||
def update_service_status(task_status, service_status, ins_id):
|
||||
"""Update service status as needed."""
|
||||
RESTART_REQUIRED = srvstatus.ServiceStatuses.RESTART_REQUIRED
|
||||
if (task_status == InstanceTasks.NONE and
|
||||
service_status.status != srvstatus.ServiceStatuses.RESTART_REQUIRED and
|
||||
not service_status.is_uptodate()):
|
||||
service_status.status != RESTART_REQUIRED and
|
||||
not service_status.is_uptodate()):
|
||||
LOG.warning('Guest agent heartbeat for instance %s has expried',
|
||||
ins_id)
|
||||
service_status.status = \
|
||||
@ -718,7 +721,8 @@ class BaseInstance(SimpleInstance):
|
||||
|
||||
from trove.cluster.models import is_cluster_deleting
|
||||
if (self.db_info.cluster_id is not None and not
|
||||
is_cluster_deleting(self.context, self.db_info.cluster_id)):
|
||||
is_cluster_deleting(context=self.context,
|
||||
cluster_id=self.db_info.cluster_id)):
|
||||
raise exception.ClusterInstanceOperationNotSupported()
|
||||
|
||||
if self.slaves:
|
||||
@ -963,6 +967,25 @@ class BaseInstance(SimpleInstance):
|
||||
self._server_group_loaded = True
|
||||
return self._server_group
|
||||
|
||||
def prepare_cloud_config(self, files):
|
||||
userdata = (
|
||||
"#cloud-config\n"
|
||||
"write_files:\n"
|
||||
)
|
||||
|
||||
for filename, content in files.items():
|
||||
ud = encodeutils.safe_encode(content)
|
||||
body_userdata = (
|
||||
"- encoding: b64\n"
|
||||
" owner: trove:trove\n"
|
||||
" path: %s\n"
|
||||
" content: %s\n" % (
|
||||
filename, encodeutils.safe_decode(base64.b64encode(ud)))
|
||||
)
|
||||
userdata = userdata + body_userdata
|
||||
|
||||
return userdata
|
||||
|
||||
def get_injected_files(self, datastore_manager, datastore_version):
|
||||
injected_config_location = CONF.get('injected_config_location')
|
||||
guest_info = CONF.get('guest_info')
|
||||
@ -1034,12 +1057,14 @@ class BaseInstance(SimpleInstance):
|
||||
|
||||
|
||||
class FreshInstance(BaseInstance):
|
||||
|
||||
@classmethod
|
||||
def load(cls, context, id):
|
||||
return load_instance(cls, context, id, needs_server=False)
|
||||
|
||||
|
||||
class BuiltInstance(BaseInstance):
|
||||
|
||||
@classmethod
|
||||
def load(cls, context, id, needs_server=True):
|
||||
return load_instance(cls, context, id, needs_server=needs_server)
|
||||
@ -1509,7 +1534,7 @@ class Instance(BuiltInstance):
|
||||
|
||||
if not self.slaves:
|
||||
raise exception.BadRequest(_("Instance %s is not a replica"
|
||||
" source.") % self.id)
|
||||
" source.") % self.id)
|
||||
|
||||
service = InstanceServiceStatus.find_by(instance_id=self.id)
|
||||
last_heartbeat_delta = timeutils.utcnow() - service.updated_at
|
||||
@ -1934,6 +1959,7 @@ class DBInstance(dbmodels.DatabaseModelBase):
|
||||
|
||||
|
||||
class instance_encryption_key_cache(object):
|
||||
|
||||
def __init__(self, func, lru_cache_size=10):
|
||||
self._table = {}
|
||||
self._lru = []
|
||||
|
@ -229,8 +229,8 @@ class ClusterTasks(Cluster):
|
||||
)
|
||||
|
||||
def _all_instances_acquire_status(
|
||||
self, instance_ids, cluster_id, shard_id, expected_status,
|
||||
fast_fail_statuses=None):
|
||||
self, instance_ids, cluster_id, shard_id, expected_status,
|
||||
fast_fail_statuses=None):
|
||||
|
||||
def _is_fast_fail_status(status):
|
||||
return ((fast_fail_statuses is not None) and
|
||||
@ -244,7 +244,7 @@ class ClusterTasks(Cluster):
|
||||
task_status = DBInstance.find_by(
|
||||
id=instance_id).get_task_status()
|
||||
if (_is_fast_fail_status(status) or
|
||||
(task_status == InstanceTasks.BUILDING_ERROR_SERVER)):
|
||||
(task_status == InstanceTasks.BUILDING_ERROR_SERVER)):
|
||||
# if one has failed, no need to continue polling
|
||||
LOG.debug("Instance %(id)s has acquired a fast-fail "
|
||||
"status %(status)s and"
|
||||
@ -269,7 +269,7 @@ class ClusterTasks(Cluster):
|
||||
task_status = DBInstance.find_by(
|
||||
id=instance_id).get_task_status()
|
||||
if (_is_fast_fail_status(status) or
|
||||
(task_status == InstanceTasks.BUILDING_ERROR_SERVER)):
|
||||
(task_status == InstanceTasks.BUILDING_ERROR_SERVER)):
|
||||
failed_instance_ids.append(instance_id)
|
||||
return failed_instance_ids
|
||||
|
||||
@ -373,8 +373,8 @@ class ClusterTasks(Cluster):
|
||||
context.notification = (
|
||||
DBaaSInstanceUpgrade(context, **request_info))
|
||||
with StartNotification(
|
||||
context, instance_id=instance.id,
|
||||
datastore_version_id=datastore_version.id):
|
||||
context, instance_id=instance.id,
|
||||
datastore_version_id=datastore_version.id):
|
||||
with EndNotification(context):
|
||||
instance.update_db(
|
||||
datastore_version_id=datastore_version.id,
|
||||
@ -781,8 +781,8 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
||||
status = service.get_status()
|
||||
|
||||
if (status == srvstatus.ServiceStatuses.RUNNING or
|
||||
status == srvstatus.ServiceStatuses.INSTANCE_READY or
|
||||
status == srvstatus.ServiceStatuses.HEALTHY):
|
||||
status == srvstatus.ServiceStatuses.INSTANCE_READY or
|
||||
status == srvstatus.ServiceStatuses.HEALTHY):
|
||||
return True
|
||||
elif status not in [srvstatus.ServiceStatuses.NEW,
|
||||
srvstatus.ServiceStatuses.BUILDING,
|
||||
@ -986,6 +986,16 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
|
||||
config_drive = CONF.use_nova_server_config_drive
|
||||
key_name = CONF.nova_keypair
|
||||
|
||||
# Use config_drive instead by userdata
|
||||
# We will inject guest config by cloud-config
|
||||
if not config_drive:
|
||||
if not userdata:
|
||||
userdata = self.prepare_cloud_config(files)
|
||||
else:
|
||||
userdata = userdata + self.prepare_cloud_config(files)
|
||||
|
||||
files = {}
|
||||
|
||||
server = self.nova_client.servers.create(
|
||||
self.name, image_id, flavor_id, key_name=key_name, nics=nics,
|
||||
block_device_mapping_v2=bdmap_v2,
|
||||
@ -1432,6 +1442,7 @@ class BuiltInstanceTasks(Instance, NotifyMixin, ConfigurationMixin):
|
||||
|
||||
|
||||
class BackupTasks(object):
|
||||
|
||||
@classmethod
|
||||
def _parse_manifest(cls, manifest):
|
||||
# manifest is in the format 'container/prefix'
|
||||
@ -1530,11 +1541,11 @@ class ModuleTasks(object):
|
||||
for instance_module in instance_modules:
|
||||
instance_id = instance_module.instance_id
|
||||
if (instance_module.md5 != current_md5 or force) and (
|
||||
not md5 or md5 == instance_module.md5):
|
||||
not md5 or md5 == instance_module.md5):
|
||||
instance = BuiltInstanceTasks.load(context, instance_id,
|
||||
needs_server=False)
|
||||
if instance and (
|
||||
include_clustered or not instance.cluster_id):
|
||||
include_clustered or not instance.cluster_id):
|
||||
try:
|
||||
module_models.Modules.validate(
|
||||
modules, instance.datastore.id,
|
||||
@ -1550,8 +1561,8 @@ class ModuleTasks(object):
|
||||
|
||||
# Sleep if we've fired off too many in a row.
|
||||
if (batch_size and
|
||||
not reapply_count % batch_size and
|
||||
(reapply_count + skipped_count) < total_count):
|
||||
not reapply_count % batch_size and
|
||||
(reapply_count + skipped_count) < total_count):
|
||||
LOG.debug("Applied module to %(cnt)d of %(total)d "
|
||||
"instances - sleeping for %(batch)ds",
|
||||
{'cnt': reapply_count,
|
||||
@ -1908,7 +1919,7 @@ class ResizeActionBase(object):
|
||||
self._perform_nova_action()
|
||||
finally:
|
||||
if self.instance.db_info.task_status != (
|
||||
inst_models.InstanceTasks.NONE):
|
||||
inst_models.InstanceTasks.NONE):
|
||||
self.instance.reset_task_status()
|
||||
|
||||
def _guest_is_awake(self):
|
||||
@ -1988,6 +1999,7 @@ class ResizeActionBase(object):
|
||||
|
||||
|
||||
class ResizeAction(ResizeActionBase):
|
||||
|
||||
def __init__(self, instance, old_flavor, new_flavor):
|
||||
"""
|
||||
:type instance: trove.taskmanager.models.BuiltInstanceTasks
|
||||
@ -2043,6 +2055,7 @@ class ResizeAction(ResizeActionBase):
|
||||
|
||||
|
||||
class MigrateAction(ResizeActionBase):
|
||||
|
||||
def __init__(self, instance, host=None):
|
||||
super(MigrateAction, self).__init__(instance)
|
||||
self.instance = instance
|
||||
@ -2070,6 +2083,7 @@ class MigrateAction(ResizeActionBase):
|
||||
|
||||
|
||||
class RebuildAction(ResizeActionBase):
|
||||
|
||||
def __init__(self, instance, image_id):
|
||||
"""The action to perform rebuild.
|
||||
|
||||
|
@ -12,43 +12,46 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import os
|
||||
|
||||
from tempfile import NamedTemporaryFile
|
||||
from unittest import mock
|
||||
from unittest.mock import call
|
||||
from unittest.mock import MagicMock
|
||||
from unittest.mock import Mock
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import PropertyMock
|
||||
from unittest.mock import call
|
||||
from unittest.mock import patch
|
||||
|
||||
import cinderclient.v3.client as cinderclient
|
||||
import neutronclient.v2_0.client as neutronclient
|
||||
import novaclient.v2.flavors
|
||||
import novaclient.v2.servers
|
||||
|
||||
from cinderclient import exceptions as cinder_exceptions
|
||||
from cinderclient.v3 import volumes as cinderclient_volumes
|
||||
import cinderclient.v3.client as cinderclient
|
||||
import neutronclient.v2_0.client as neutronclient
|
||||
from novaclient import exceptions as nova_exceptions
|
||||
import novaclient.v2.flavors
|
||||
import novaclient.v2.servers
|
||||
from oslo_config import cfg
|
||||
from swiftclient.client import ClientException
|
||||
from testtools.matchers import Equals
|
||||
from testtools.matchers import Is
|
||||
|
||||
import trove.backup.models
|
||||
import trove.common.context
|
||||
import trove.common.template as template
|
||||
import trove.db.models
|
||||
import trove.guestagent.api
|
||||
|
||||
from trove import rpc
|
||||
from trove.backup import models as backup_models
|
||||
from trove.backup import state
|
||||
import trove.backup.models
|
||||
from trove.common import exception
|
||||
from trove.common import timeutils
|
||||
from trove.common import utils
|
||||
import trove.common.context
|
||||
from trove.common import exception
|
||||
from trove.common.exception import GuestError
|
||||
from trove.common.exception import PollTimeOut
|
||||
from trove.common.exception import TroveError
|
||||
import trove.common.template as template
|
||||
from trove.datastore import models as datastore_models
|
||||
import trove.db.models
|
||||
from trove.extensions.common import models as common_models
|
||||
from trove.extensions.mysql import models as mysql_models
|
||||
import trove.guestagent.api
|
||||
from trove.instance.models import BaseInstance
|
||||
from trove.instance.models import DBInstance
|
||||
from trove.instance.models import InstanceServiceStatus
|
||||
@ -64,6 +67,7 @@ VOLUME_ID = 'volume-id-1'
|
||||
|
||||
|
||||
class FakeOptGroup(object):
|
||||
|
||||
def __init__(self, tcp_ports=['3306', '3301-3307'],
|
||||
udp_ports=[], icmp=False):
|
||||
self.tcp_ports = tcp_ports
|
||||
@ -72,6 +76,7 @@ class FakeOptGroup(object):
|
||||
|
||||
|
||||
class fake_Server(object):
|
||||
|
||||
def __init__(self):
|
||||
self.id = None
|
||||
self.name = None
|
||||
@ -108,6 +113,7 @@ class fake_ServerManager(object):
|
||||
|
||||
|
||||
class fake_nova_client(object):
|
||||
|
||||
def __init__(self):
|
||||
self.servers = fake_ServerManager()
|
||||
|
||||
@ -236,7 +242,8 @@ class FreshInstanceTasksTest(BaseFreshInstanceTasksTest):
|
||||
server = self.freshinstancetasks._create_server(
|
||||
None, None, datastore_manager, None, None, None)
|
||||
|
||||
self.assertEqual(server.userdata, self.userdata)
|
||||
userdata = self.userdata + "#cloud-config\nwrite_files:\n"
|
||||
self.assertEqual(server.userdata, userdata)
|
||||
|
||||
def test_create_instance_with_keypair(self):
|
||||
cfg.CONF.set_override('nova_keypair', 'fake_keypair')
|
||||
@ -310,7 +317,8 @@ class FreshInstanceTasksTest(BaseFreshInstanceTasksTest):
|
||||
def test_servers_create_block_device_mapping_v2(self,
|
||||
mock_hostname,
|
||||
mock_name):
|
||||
self.freshinstancetasks.prepare_userdata = Mock(return_value=None)
|
||||
self.freshinstancetasks.prepare_userdata = Mock(
|
||||
return_value="#cloud-config\nwrite_files:\n")
|
||||
mock_nova_client = self.freshinstancetasks.nova_client = Mock()
|
||||
mock_servers_create = mock_nova_client.servers.create
|
||||
self.freshinstancetasks._create_server('fake-flavor', 'fake-image',
|
||||
@ -318,14 +326,18 @@ class FreshInstanceTasksTest(BaseFreshInstanceTasksTest):
|
||||
meta = {'trove_project_id': self.freshinstancetasks.tenant_id,
|
||||
'trove_user_id': 'test_user',
|
||||
'trove_instance_id': self.freshinstancetasks.id}
|
||||
|
||||
userdata = self.freshinstancetasks.prepare_userdata('mysql')
|
||||
userdata = userdata + \
|
||||
self.freshinstancetasks.prepare_cloud_config({})
|
||||
mock_servers_create.assert_called_with(
|
||||
'fake-name', 'fake-image',
|
||||
'fake-flavor', files={},
|
||||
userdata=None,
|
||||
userdata=userdata,
|
||||
block_device_mapping_v2=None,
|
||||
availability_zone=None,
|
||||
nics=None,
|
||||
config_drive=True,
|
||||
config_drive=False,
|
||||
scheduler_hints=None,
|
||||
key_name=None,
|
||||
meta=meta,
|
||||
@ -599,6 +611,7 @@ class ResizeVolumeTest(trove_testtools.TestCase):
|
||||
self.new_vol_size)
|
||||
|
||||
class FakeGroup(object):
|
||||
|
||||
def __init__(self):
|
||||
self.mount_point = 'var/lib/mysql'
|
||||
self.device_path = '/dev/vdb'
|
||||
@ -1105,6 +1118,7 @@ class BackupTasksTest(trove_testtools.TestCase):
|
||||
|
||||
|
||||
class NotifyMixinTest(trove_testtools.TestCase):
|
||||
|
||||
def test_get_service_id(self):
|
||||
id_map = {
|
||||
'mysql': '123',
|
||||
|
Loading…
x
Reference in New Issue
Block a user