Fix replica source state validation
Creating a replica did not check that the specified source was available. It is necessary that the source's state is active and that it is not busy. This is done by verifying the state and status of the master. The new checks will throw a HTTP 422 UnprocessableEntity in cases when the status is not ACTIVE or source is busy performing a task Changes: - adding validation step that checks if master exists and in proper state. - added appropriate API and unit tests Co-authored by: Denis Makogon <dmakogon@mirantis.com> DocImpact Change-Id: Ib4e37ff0036998bc53058e400054ed93fcc2e144 Closes-Bug: #1357704
This commit is contained in:
parent
417719c5a7
commit
32387f8ffd
@ -718,6 +718,18 @@ class Instance(BuiltInstance):
|
||||
raise exception.Forbidden(
|
||||
_("Cannot create a replica of a replica %(id)s.")
|
||||
% {'id': slave_of_id})
|
||||
# load the replica source status to check if
|
||||
# source is available
|
||||
load_simple_instance_server_status(
|
||||
context,
|
||||
replica_source)
|
||||
replica_source_instance = Instance(
|
||||
context, replica_source,
|
||||
None,
|
||||
InstanceServiceStatus.find_by(
|
||||
context,
|
||||
instance_id=slave_of_id))
|
||||
replica_source_instance.validate_can_perform_action()
|
||||
except exception.ModelNotFoundError:
|
||||
LOG.exception(
|
||||
_("Cannot create a replica of %(id)s "
|
||||
|
@ -67,6 +67,16 @@ def slave_is_running(running=True):
|
||||
groups=[GROUP])
|
||||
class CreateReplicationSlave(object):
|
||||
|
||||
@test
|
||||
def test_replica_provisioning_with_missing_replica_source(self):
|
||||
assert_raises(exceptions.NotFound,
|
||||
instance_info.dbaas.instances.create,
|
||||
instance_info.name + "_slave",
|
||||
instance_info.dbaas_flavor_href,
|
||||
instance_info.volume,
|
||||
slave_of="Missing replica source")
|
||||
assert_equal(404, instance_info.dbaas.last_http_code)
|
||||
|
||||
@test
|
||||
def test_create_db_on_master(self):
|
||||
databases = [{'name': existing_db_on_master}]
|
||||
|
@ -18,7 +18,6 @@ from trove.common import cfg
|
||||
from trove.common import exception
|
||||
from trove.backup import models as backup_models
|
||||
from trove.datastore import models as datastore_models
|
||||
from trove.datastore.models import DBDatastoreVersion
|
||||
from trove.common.instance import ServiceStatuses
|
||||
from trove.instance.models import filter_ips
|
||||
from trove.instance.models import InstanceServiceStatus
|
||||
@ -216,35 +215,77 @@ class TestReplication(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
util.init_db()
|
||||
self.replica_datastore_version = Mock(spec=DBDatastoreVersion)
|
||||
|
||||
self.datastore = datastore_models.DBDatastore.create(
|
||||
id=str(uuid.uuid4()),
|
||||
name='name',
|
||||
default_version_id=str(uuid.uuid4()))
|
||||
|
||||
self.datastore_version = datastore_models.DBDatastoreVersion.create(
|
||||
id=self.datastore.default_version_id,
|
||||
name='name',
|
||||
image_id=str(uuid.uuid4()),
|
||||
packages=str(uuid.uuid4()),
|
||||
datastore_id=self.datastore.id,
|
||||
manager='mysql',
|
||||
active=1)
|
||||
|
||||
self.master = DBInstance(
|
||||
InstanceTasks.NONE,
|
||||
id=str(uuid.uuid4()),
|
||||
name="TestMasterInstance",
|
||||
datastore_version_id=self.datastore_version.id)
|
||||
self.master.set_task_status(InstanceTasks.NONE)
|
||||
self.master.save()
|
||||
self.master_status = InstanceServiceStatus(
|
||||
ServiceStatuses.RUNNING,
|
||||
id=str(uuid.uuid4()),
|
||||
instance_id=self.master.id)
|
||||
self.master_status.save()
|
||||
|
||||
self.safe_nova_client = models.create_nova_client
|
||||
models.create_nova_client = nova.fake_create_nova_client
|
||||
super(TestReplication, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
self.master.delete()
|
||||
self.master_status.delete()
|
||||
self.datastore.delete()
|
||||
self.datastore_version.delete()
|
||||
models.create_nova_client = self.safe_nova_client
|
||||
super(TestReplication, self).tearDown()
|
||||
|
||||
def test_replica_of_not_active_master(self):
|
||||
self.master.set_task_status(InstanceTasks.BUILDING)
|
||||
self.master.save()
|
||||
self.master_status.set_status(ServiceStatuses.BUILDING)
|
||||
self.master_status.save()
|
||||
self.assertRaises(exception.UnprocessableEntity,
|
||||
Instance.create,
|
||||
None, 'name', 1, "UUID", [], [], None,
|
||||
self.datastore_version, 1,
|
||||
None, slave_of_id=self.master.id)
|
||||
|
||||
def test_replica_with_invalid_slave_of_id(self):
|
||||
self.assertRaises(exception.NotFound,
|
||||
Instance.create,
|
||||
None, 'name', 1, "UUID", [], [], None,
|
||||
self.datastore_version, 1,
|
||||
None, slave_of_id=str(uuid.uuid4()))
|
||||
|
||||
def test_create_replica_from_replica(self):
|
||||
self.replica_datastore_version = Mock(
|
||||
spec=datastore_models.DBDatastoreVersion)
|
||||
self.replica_datastore_version.id = "UUID"
|
||||
self.replica_datastore_version.manager = 'mysql'
|
||||
self.root_info = DBInstance(
|
||||
InstanceTasks.NONE,
|
||||
id="Another_instance",
|
||||
name="TestInstance",
|
||||
datastore_version_id=self.replica_datastore_version.id)
|
||||
self.root_info.save()
|
||||
self.replica_info = DBInstance(
|
||||
InstanceTasks.NONE,
|
||||
id="UUID",
|
||||
name="TestInstance",
|
||||
datastore_version_id=self.replica_datastore_version.id,
|
||||
slave_of_id="Another_instance")
|
||||
slave_of_id=self.master.id)
|
||||
self.replica_info.save()
|
||||
self.safe_nova = models.create_nova_client
|
||||
models.create_nova_client = nova.fake_create_nova_client
|
||||
|
||||
super(TestReplication, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
models.create_nova_client = self.safe_nova
|
||||
self.replica_info.delete()
|
||||
self.root_info.delete()
|
||||
super(TestReplication, self).tearDown()
|
||||
|
||||
def test_create_replica_from_replica(self):
|
||||
self.assertRaises(exception.Forbidden, Instance.create,
|
||||
None, 'name', 2, "UUID", [], [], None,
|
||||
self.replica_datastore_version, 1,
|
||||
self.datastore_version, 1,
|
||||
None, slave_of_id=self.replica_info.id)
|
||||
|
Loading…
x
Reference in New Issue
Block a user