Locality support for clusters

In order to allow clusters to be all on the same hypervisor
(affinity) or all on different hypervisors (anti-affinity) a new
argument (locality) needed to be added to the Trove cluster-create API.

This changeset addresses the Trove server part of this feature.
'locality' can now be added to the ReST payload for a cluster-create
command and it is passed along as a scheduler hint to Nova.

The cluster scenario tests were enhanced to test that 'affinity'
works. Testing that 'anti-affinity' fails proved to be too
time consuming, since at present the only way for a cluster to
'fail' is to timeout (and that takes 10 hours).

The server-group is checked to make sure it is created properly,
and that it has been deleted after all the related instances are gone.

DocImpact: New functionality

Partially implements: blueprint replication-cluster-locality
Depends-On: Ie46cfa69ffe6a64760aca38c495563f5724bd0d0

Change-Id: I657bf5c023d0257e462cc39f57c16eb6ee83807a
This commit is contained in:
Peter Stachowski 2016-04-05 21:38:53 +00:00
parent ff49045744
commit 51f2655770
24 changed files with 277 additions and 95 deletions

View File

@ -0,0 +1,7 @@
---
features:
- A locality flag was added to the trove ReST API to
allow a user to specify whether the instances of a
cluster should be on the same hypervisor (affinity)
or on different hypervisors (anti-affinity).

View File

@ -24,6 +24,7 @@ from trove.common.i18n import _
from trove.common.notification import DBaaSClusterGrow, DBaaSClusterShrink from trove.common.notification import DBaaSClusterGrow, DBaaSClusterShrink
from trove.common.notification import StartNotification from trove.common.notification import StartNotification
from trove.common import remote from trove.common import remote
from trove.common import server_group as srv_grp
from trove.common.strategies.cluster import strategy from trove.common.strategies.cluster import strategy
from trove.common import utils from trove.common import utils
from trove.datastore import models as datastore_models from trove.datastore import models as datastore_models
@ -89,6 +90,9 @@ class Cluster(object):
self.ds = (datastore_models.Datastore. self.ds = (datastore_models.Datastore.
load(self.ds_version.datastore_id)) load(self.ds_version.datastore_id))
self._db_instances = None self._db_instances = None
self._server_group = None
self._server_group_loaded = False
self._locality = None
@classmethod @classmethod
def get_guest(cls, instance): def get_guest(cls, instance):
@ -198,13 +202,39 @@ class Cluster(object):
return inst_models.Instances.load_all_by_cluster_id( return inst_models.Instances.load_all_by_cluster_id(
self.context, self.db_info.id, load_servers=False) self.context, self.db_info.id, load_servers=False)
@property
def server_group(self):
# The server group could be empty, so we need a flag to cache it
if not self._server_group_loaded and self.instances:
self._server_group = self.instances[0].server_group
self._server_group_loaded = True
return self._server_group
@property
def locality(self):
if not self._locality:
if self.server_group:
self._locality = srv_grp.ServerGroup.get_locality(
self._server_group)
return self._locality
@locality.setter
def locality(self, value):
"""This is to facilitate the fact that the server group may not be
set up before the create command returns.
"""
self._locality = value
@classmethod @classmethod
def create(cls, context, name, datastore, datastore_version, def create(cls, context, name, datastore, datastore_version,
instances, extended_properties): instances, extended_properties, locality):
locality = srv_grp.ServerGroup.build_scheduler_hint(
context, locality, name)
api_strategy = strategy.load_api_strategy(datastore_version.manager) api_strategy = strategy.load_api_strategy(datastore_version.manager)
return api_strategy.cluster_class.create(context, name, datastore, return api_strategy.cluster_class.create(context, name, datastore,
datastore_version, instances, datastore_version, instances,
extended_properties) extended_properties,
locality)
def validate_cluster_available(self, valid_states=[ClusterTasks.NONE]): def validate_cluster_available(self, valid_states=[ClusterTasks.NONE]):
if self.db_info.task_status not in valid_states: if self.db_info.task_status not in valid_states:
@ -224,6 +254,11 @@ class Cluster(object):
self.update_db(task_status=ClusterTasks.DELETING) self.update_db(task_status=ClusterTasks.DELETING)
# we force the server-group delete here since we need to load the
# group while the instances still exist. Also, since the instances
# take a while to be removed they might not all be gone even if we
# do it after the delete.
srv_grp.ServerGroup.delete(self.context, self.server_group, force=True)
for db_inst in db_insts: for db_inst in db_insts:
instance = inst_models.load_any_instance(self.context, db_inst.id) instance = inst_models.load_any_instance(self.context, db_inst.id)
instance.delete() instance.delete()
@ -261,7 +296,7 @@ class Cluster(object):
@staticmethod @staticmethod
def load_instance(context, cluster_id, instance_id): def load_instance(context, cluster_id, instance_id):
return inst_models.load_instance_with_guest( return inst_models.load_instance_with_info(
inst_models.DetailInstance, context, instance_id, cluster_id) inst_models.DetailInstance, context, instance_id, cluster_id)
@staticmethod @staticmethod

View File

@ -172,12 +172,24 @@ class ClusterController(wsgi.Controller):
"nics": nics, "nics": nics,
"availability_zone": availability_zone}) "availability_zone": availability_zone})
locality = body['cluster'].get('locality')
if locality:
locality_domain = ['affinity', 'anti-affinity']
locality_domain_msg = ("Invalid locality '%s'. "
"Must be one of ['%s']" %
(locality,
"', '".join(locality_domain)))
if locality not in locality_domain:
raise exception.BadRequest(msg=locality_domain_msg)
context.notification = notification.DBaaSClusterCreate(context, context.notification = notification.DBaaSClusterCreate(context,
request=req) request=req)
with StartNotification(context, name=name, datastore=datastore.name, with StartNotification(context, name=name, datastore=datastore.name,
datastore_version=datastore_version.name): datastore_version=datastore_version.name):
cluster = models.Cluster.create(context, name, datastore, cluster = models.Cluster.create(context, name, datastore,
datastore_version, instances, datastore_version, instances,
extended_properties) extended_properties,
locality)
cluster.locality = locality
view = views.load_view(cluster, req=req, load_servers=False) view = views.load_view(cluster, req=req, load_servers=False)
return wsgi.Result(view.data(), 200) return wsgi.Result(view.data(), 200)

View File

@ -53,6 +53,8 @@ class ClusterView(object):
if extended_properties: if extended_properties:
cluster_dict["extended_properties"] = extended_properties cluster_dict["extended_properties"] = extended_properties
if self.cluster.locality:
cluster_dict['locality'] = self.cluster.locality
LOG.debug(cluster_dict) LOG.debug(cluster_dict)
return {"cluster": cluster_dict} return {"cluster": cluster_dict}

View File

@ -255,7 +255,8 @@ cluster = {
"modules": module_list, "modules": module_list,
} }
} }
} },
"locality": non_empty_string
} }
} }
} }

View File

@ -19,6 +19,7 @@ from trove.cluster import models
from trove.cluster.tasks import ClusterTasks from trove.cluster.tasks import ClusterTasks
from trove.cluster.views import ClusterView from trove.cluster.views import ClusterView
from trove.common import cfg from trove.common import cfg
from trove.common import server_group as srv_grp
from trove.common.strategies.cluster import base from trove.common.strategies.cluster import base
from trove.common.strategies.cluster.experimental.cassandra.taskmanager import( from trove.common.strategies.cluster.experimental.cassandra.taskmanager import(
CassandraClusterTasks) CassandraClusterTasks)
@ -81,7 +82,7 @@ class CassandraCluster(models.Cluster):
@classmethod @classmethod
def create(cls, context, name, datastore, datastore_version, def create(cls, context, name, datastore, datastore_version,
instances, extended_properties): instances, extended_properties, locality):
LOG.debug("Processing a request for creating a new cluster.") LOG.debug("Processing a request for creating a new cluster.")
# Updating Cluster Task. # Updating Cluster Task.
@ -92,7 +93,8 @@ class CassandraCluster(models.Cluster):
cls._create_cluster_instances( cls._create_cluster_instances(
context, db_info.id, db_info.name, context, db_info.id, db_info.name,
datastore, datastore_version, instances, extended_properties) datastore, datastore_version, instances, extended_properties,
locality)
# Calling taskmanager to further proceed for cluster-configuration. # Calling taskmanager to further proceed for cluster-configuration.
task_api.load(context, datastore_version.manager).create_cluster( task_api.load(context, datastore_version.manager).create_cluster(
@ -103,7 +105,8 @@ class CassandraCluster(models.Cluster):
@classmethod @classmethod
def _create_cluster_instances( def _create_cluster_instances(
cls, context, cluster_id, cluster_name, cls, context, cluster_id, cluster_name,
datastore, datastore_version, instances, extended_properties=None): datastore, datastore_version, instances, extended_properties,
locality):
LOG.debug("Processing a request for new cluster instances.") LOG.debug("Processing a request for new cluster instances.")
cassandra_conf = CONF.get(datastore_version.manager) cassandra_conf = CONF.get(datastore_version.manager)
@ -151,7 +154,8 @@ class CassandraCluster(models.Cluster):
nics=instance.get('nics', None), nics=instance.get('nics', None),
availability_zone=instance_az, availability_zone=instance_az,
configuration_id=None, configuration_id=None,
cluster_config=member_config) cluster_config=member_config,
locality=locality)
new_instances.append(new_instance) new_instances.append(new_instance)
@ -173,9 +177,10 @@ class CassandraCluster(models.Cluster):
db_info.update(task_status=ClusterTasks.GROWING_CLUSTER) db_info.update(task_status=ClusterTasks.GROWING_CLUSTER)
locality = srv_grp.ServerGroup.convert_to_hint(self.server_group)
new_instances = self._create_cluster_instances( new_instances = self._create_cluster_instances(
context, db_info.id, db_info.name, datastore, datastore_version, context, db_info.id, db_info.name, datastore, datastore_version,
instances) instances, None, locality)
task_api.load(context, datastore_version.manager).grow_cluster( task_api.load(context, datastore_version.manager).grow_cluster(
db_info.id, [instance.id for instance in new_instances]) db_info.id, [instance.id for instance in new_instances])

View File

@ -22,6 +22,7 @@ from trove.cluster.views import ClusterView
from trove.common import cfg from trove.common import cfg
from trove.common import exception from trove.common import exception
from trove.common import remote from trove.common import remote
from trove.common import server_group as srv_grp
from trove.common.strategies.cluster import base as cluster_base from trove.common.strategies.cluster import base as cluster_base
from trove.extensions.mgmt.clusters.views import MgmtClusterView from trove.extensions.mgmt.clusters.views import MgmtClusterView
from trove.instance.models import DBInstance from trove.instance.models import DBInstance
@ -115,7 +116,7 @@ class GaleraCommonCluster(cluster_models.Cluster):
@staticmethod @staticmethod
def _create_instances(context, db_info, datastore, datastore_version, def _create_instances(context, db_info, datastore, datastore_version,
instances): instances, extended_properties, locality):
member_config = {"id": db_info.id, member_config = {"id": db_info.id,
"instance_type": "member"} "instance_type": "member"}
name_index = 1 name_index = 1
@ -137,13 +138,14 @@ class GaleraCommonCluster(cluster_models.Cluster):
'availability_zone', None), 'availability_zone', None),
nics=instance.get('nics', None), nics=instance.get('nics', None),
configuration_id=None, configuration_id=None,
cluster_config=member_config cluster_config=member_config,
locality=locality
) )
for instance in instances] for instance in instances]
@classmethod @classmethod
def create(cls, context, name, datastore, datastore_version, def create(cls, context, name, datastore, datastore_version,
instances, extended_properties): instances, extended_properties, locality):
LOG.debug("Initiating Galera cluster creation.") LOG.debug("Initiating Galera cluster creation.")
cls._validate_cluster_instances(context, instances, datastore, cls._validate_cluster_instances(context, instances, datastore,
datastore_version) datastore_version)
@ -154,7 +156,7 @@ class GaleraCommonCluster(cluster_models.Cluster):
task_status=ClusterTasks.BUILDING_INITIAL) task_status=ClusterTasks.BUILDING_INITIAL)
cls._create_instances(context, db_info, datastore, datastore_version, cls._create_instances(context, db_info, datastore, datastore_version,
instances) instances, extended_properties, locality)
# Calling taskmanager to further proceed for cluster-configuration # Calling taskmanager to further proceed for cluster-configuration
task_api.load(context, datastore_version.manager).create_cluster( task_api.load(context, datastore_version.manager).create_cluster(
@ -187,8 +189,10 @@ class GaleraCommonCluster(cluster_models.Cluster):
for instance in instances: for instance in instances:
instance["nics"] = interface_ids instance["nics"] = interface_ids
locality = srv_grp.ServerGroup.convert_to_hint(self.server_group)
new_instances = self._create_instances( new_instances = self._create_instances(
context, db_info, datastore, datastore_version, instances) context, db_info, datastore, datastore_version, instances,
None, locality)
task_api.load(context, datastore_version.manager).grow_cluster( task_api.load(context, datastore_version.manager).grow_cluster(
db_info.id, [instance.id for instance in new_instances]) db_info.id, [instance.id for instance in new_instances])

View File

@ -25,6 +25,7 @@ from trove.common.i18n import _
from trove.common.notification import DBaaSClusterGrow from trove.common.notification import DBaaSClusterGrow
from trove.common.notification import StartNotification from trove.common.notification import StartNotification
from trove.common import remote from trove.common import remote
from trove.common import server_group as srv_grp
from trove.common.strategies.cluster import base from trove.common.strategies.cluster import base
from trove.common import utils from trove.common import utils
from trove.datastore import models as datastore_models from trove.datastore import models as datastore_models
@ -57,7 +58,7 @@ class MongoDbCluster(models.Cluster):
@classmethod @classmethod
def create(cls, context, name, datastore, datastore_version, def create(cls, context, name, datastore, datastore_version,
instances, extended_properties): instances, extended_properties, locality):
# TODO(amcreynolds): consider moving into CONF and even supporting # TODO(amcreynolds): consider moving into CONF and even supporting
# TODO(amcreynolds): an array of values, e.g. [3, 5, 7] # TODO(amcreynolds): an array of values, e.g. [3, 5, 7]
@ -144,7 +145,8 @@ class MongoDbCluster(models.Cluster):
availability_zone=azs[i], availability_zone=azs[i],
nics=nics[i], nics=nics[i],
configuration_id=None, configuration_id=None,
cluster_config=member_config) cluster_config=member_config,
locality=locality)
for i in range(1, num_configsvr + 1): for i in range(1, num_configsvr + 1):
instance_name = "%s-%s-%s" % (name, "configsvr", str(i)) instance_name = "%s-%s-%s" % (name, "configsvr", str(i))
@ -157,7 +159,8 @@ class MongoDbCluster(models.Cluster):
availability_zone=None, availability_zone=None,
nics=None, nics=None,
configuration_id=None, configuration_id=None,
cluster_config=configsvr_config) cluster_config=configsvr_config,
locality=locality)
for i in range(1, num_mongos + 1): for i in range(1, num_mongos + 1):
instance_name = "%s-%s-%s" % (name, "mongos", str(i)) instance_name = "%s-%s-%s" % (name, "mongos", str(i))
@ -170,7 +173,8 @@ class MongoDbCluster(models.Cluster):
availability_zone=None, availability_zone=None,
nics=None, nics=None,
configuration_id=None, configuration_id=None,
cluster_config=mongos_config) cluster_config=mongos_config,
locality=locality)
task_api.load(context, datastore_version.manager).create_cluster( task_api.load(context, datastore_version.manager).create_cluster(
db_info.id) db_info.id)
@ -276,6 +280,7 @@ class MongoDbCluster(models.Cluster):
"instance_type": "member", "instance_type": "member",
"replica_set_name": new_replica_set_name, "replica_set_name": new_replica_set_name,
"key": key} "key": key}
locality = srv_grp.ServerGroup.convert_to_hint(self.server_group)
for i in range(1, num_members_per_shard + 1): for i in range(1, num_members_per_shard + 1):
instance_name = "%s-%s-%s" % (self.name, new_replica_set_name, instance_name = "%s-%s-%s" % (self.name, new_replica_set_name,
str(i)) str(i))
@ -288,7 +293,8 @@ class MongoDbCluster(models.Cluster):
availability_zone=None, availability_zone=None,
nics=None, nics=None,
configuration_id=None, configuration_id=None,
cluster_config=member_config) cluster_config=member_config,
locality=locality)
self.update_db(task_status=ClusterTasks.ADDING_SHARD) self.update_db(task_status=ClusterTasks.ADDING_SHARD)
manager.mongodb_add_shard_cluster( manager.mongodb_add_shard_cluster(
@ -316,12 +322,13 @@ class MongoDbCluster(models.Cluster):
self._check_instances(self.context, query_routers, self._check_instances(self.context, query_routers,
self.datastore_version) self.datastore_version)
# all checks are done before any instances are created # all checks are done before any instances are created
locality = srv_grp.ServerGroup.convert_to_hint(self.server_group)
instance_ids = [] instance_ids = []
for shard in shards: for shard in shards:
instance_ids.extend(self._create_shard_instances(shard)) instance_ids.extend(self._create_shard_instances(shard, locality))
if query_routers: if query_routers:
instance_ids.extend( instance_ids.extend(
self._create_query_router_instances(query_routers) self._create_query_router_instances(query_routers, locality)
) )
self.update_db(task_status=ClusterTasks.GROWING_CLUSTER) self.update_db(task_status=ClusterTasks.GROWING_CLUSTER)
@ -400,7 +407,7 @@ class MongoDbCluster(models.Cluster):
self.manager.shrink_cluster(self.id, instance_ids) self.manager.shrink_cluster(self.id, instance_ids)
def _create_instances(self, instances, cluster_config, def _create_instances(self, instances, cluster_config,
default_name_tag, key=None): default_name_tag, locality, key=None):
"""Loop through the instances and create them in this cluster.""" """Loop through the instances and create them in this cluster."""
cluster_config['id'] = self.id cluster_config['id'] = self.id
if CONF.get(self.datastore_version.manager).cluster_secure: if CONF.get(self.datastore_version.manager).cluster_secure:
@ -418,12 +425,13 @@ class MongoDbCluster(models.Cluster):
instance['volume_size'], None, instance['volume_size'], None,
availability_zone=instance.get('availability_zone', None), availability_zone=instance.get('availability_zone', None),
nics=instance.get('nics', None), nics=instance.get('nics', None),
cluster_config=cluster_config cluster_config=cluster_config,
locality=locality
) )
instance_ids.append(new_instance.id) instance_ids.append(new_instance.id)
return instance_ids return instance_ids
def _create_shard_instances(self, instances, def _create_shard_instances(self, instances, locality,
replica_set_name=None, key=None): replica_set_name=None, key=None):
"""Create the instances for a new shard in the cluster.""" """Create the instances for a new shard in the cluster."""
shard_id = utils.generate_uuid() shard_id = utils.generate_uuid()
@ -433,13 +441,13 @@ class MongoDbCluster(models.Cluster):
'instance_type': 'member', 'instance_type': 'member',
'replica_set_name': replica_set_name} 'replica_set_name': replica_set_name}
return self._create_instances(instances, cluster_config, return self._create_instances(instances, cluster_config,
replica_set_name, key=key) replica_set_name, locality, key=key)
def _create_query_router_instances(self, instances, key=None): def _create_query_router_instances(self, instances, locality, key=None):
"""Create the instances for the new query router.""" """Create the instances for the new query router."""
cluster_config = {'instance_type': 'query_router'} cluster_config = {'instance_type': 'query_router'}
return self._create_instances(instances, cluster_config, return self._create_instances(instances, cluster_config,
'mongos', key=key) 'mongos', locality, key=key)
def _prep_resize(self): def _prep_resize(self):
"""Get information about the cluster's current state.""" """Get information about the cluster's current state."""

View File

@ -21,6 +21,7 @@ from trove.cluster.views import ClusterView
from trove.common import cfg from trove.common import cfg
from trove.common import exception from trove.common import exception
from trove.common import remote from trove.common import remote
from trove.common import server_group as srv_grp
from trove.common.strategies.cluster import base from trove.common.strategies.cluster import base
from trove.extensions.mgmt.clusters.views import MgmtClusterView from trove.extensions.mgmt.clusters.views import MgmtClusterView
from trove.instance import models as inst_models from trove.instance import models as inst_models
@ -49,7 +50,7 @@ class RedisCluster(models.Cluster):
@staticmethod @staticmethod
def _create_instances(context, db_info, datastore, datastore_version, def _create_instances(context, db_info, datastore, datastore_version,
instances): instances, extended_properties, locality):
Redis_conf = CONF.get(datastore_version.manager) Redis_conf = CONF.get(datastore_version.manager)
num_instances = len(instances) num_instances = len(instances)
total_volume_allocation = 0 total_volume_allocation = 0
@ -103,13 +104,14 @@ class RedisCluster(models.Cluster):
configuration_id=None, configuration_id=None,
cluster_config={ cluster_config={
"id": db_info.id, "id": db_info.id,
"instance_type": "member"} "instance_type": "member"},
locality=locality
) )
for instance in instances] for instance in instances]
@classmethod @classmethod
def create(cls, context, name, datastore, datastore_version, def create(cls, context, name, datastore, datastore_version,
instances, extended_properties): instances, extended_properties, locality):
LOG.debug("Initiating cluster creation.") LOG.debug("Initiating cluster creation.")
# Updating Cluster Task # Updating Cluster Task
@ -120,7 +122,7 @@ class RedisCluster(models.Cluster):
task_status=ClusterTasks.BUILDING_INITIAL) task_status=ClusterTasks.BUILDING_INITIAL)
cls._create_instances(context, db_info, datastore, datastore_version, cls._create_instances(context, db_info, datastore, datastore_version,
instances) instances, extended_properties, locality)
# Calling taskmanager to further proceed for cluster-configuration # Calling taskmanager to further proceed for cluster-configuration
task_api.load(context, datastore_version.manager).create_cluster( task_api.load(context, datastore_version.manager).create_cluster(
@ -140,9 +142,10 @@ class RedisCluster(models.Cluster):
db_info.update(task_status=ClusterTasks.GROWING_CLUSTER) db_info.update(task_status=ClusterTasks.GROWING_CLUSTER)
locality = srv_grp.ServerGroup.convert_to_hint(self.server_group)
new_instances = self._create_instances(context, db_info, new_instances = self._create_instances(context, db_info,
datastore, datastore_version, datastore, datastore_version,
instances) instances, None, locality)
task_api.load(context, datastore_version.manager).grow_cluster( task_api.load(context, datastore_version.manager).grow_cluster(
db_info.id, [instance.id for instance in new_instances]) db_info.id, [instance.id for instance in new_instances])

View File

@ -20,6 +20,7 @@ from trove.cluster.views import ClusterView
from trove.common import cfg from trove.common import cfg
from trove.common import exception from trove.common import exception
from trove.common import remote from trove.common import remote
from trove.common import server_group as srv_grp
from trove.common.strategies.cluster import base from trove.common.strategies.cluster import base
from trove.common import utils from trove.common import utils
from trove.extensions.mgmt.clusters.views import MgmtClusterView from trove.extensions.mgmt.clusters.views import MgmtClusterView
@ -70,7 +71,8 @@ class VerticaCluster(models.Cluster):
@staticmethod @staticmethod
def _create_instances(context, db_info, datastore, datastore_version, def _create_instances(context, db_info, datastore, datastore_version,
instances, new_cluster): instances, extended_properties, locality,
new_cluster=True):
vertica_conf = CONF.get(datastore_version.manager) vertica_conf = CONF.get(datastore_version.manager)
num_instances = len(instances) num_instances = len(instances)
@ -78,8 +80,8 @@ class VerticaCluster(models.Cluster):
num_existing = len(existing) num_existing = len(existing)
# Matching number of instances with configured cluster_member_count # Matching number of instances with configured cluster_member_count
if new_cluster \ if (new_cluster and
and num_instances != vertica_conf.cluster_member_count: num_instances != vertica_conf.cluster_member_count):
raise exception.ClusterNumInstancesNotSupported( raise exception.ClusterNumInstancesNotSupported(
num_instances=vertica_conf.cluster_member_count) num_instances=vertica_conf.cluster_member_count)
@ -140,13 +142,14 @@ class VerticaCluster(models.Cluster):
nics=nics[i], nics=nics[i],
availability_zone=azs[i], availability_zone=azs[i],
configuration_id=None, configuration_id=None,
cluster_config=member_config) cluster_config=member_config,
locality=locality)
) )
return minstances return minstances
@classmethod @classmethod
def create(cls, context, name, datastore, datastore_version, def create(cls, context, name, datastore, datastore_version,
instances, extended_properties): instances, extended_properties, locality):
LOG.debug("Initiating cluster creation.") LOG.debug("Initiating cluster creation.")
vertica_conf = CONF.get(datastore_version.manager) vertica_conf = CONF.get(datastore_version.manager)
@ -163,7 +166,8 @@ class VerticaCluster(models.Cluster):
task_status=ClusterTasks.BUILDING_INITIAL) task_status=ClusterTasks.BUILDING_INITIAL)
cls._create_instances(context, db_info, datastore, datastore_version, cls._create_instances(context, db_info, datastore, datastore_version,
instances, new_cluster=True) instances, extended_properties, locality,
new_cluster=True)
# Calling taskmanager to further proceed for cluster-configuration # Calling taskmanager to further proceed for cluster-configuration
task_api.load(context, datastore_version.manager).create_cluster( task_api.load(context, datastore_version.manager).create_cluster(
db_info.id) db_info.id)
@ -196,8 +200,10 @@ class VerticaCluster(models.Cluster):
db_info.update(task_status=ClusterTasks.GROWING_CLUSTER) db_info.update(task_status=ClusterTasks.GROWING_CLUSTER)
locality = srv_grp.ServerGroup.convert_to_hint(self.server_group)
new_instances = self._create_instances(context, db_info, datastore, new_instances = self._create_instances(context, db_info, datastore,
datastore_version, instances, datastore_version, instances,
None, locality,
new_cluster=False) new_cluster=False)
task_api.load(context, datastore_version.manager).grow_cluster( task_api.load(context, datastore_version.manager).grow_cluster(

View File

@ -40,6 +40,16 @@ class ClusterActionsGroup(TestGroup):
"""Create a cluster.""" """Create a cluster."""
self.test_runner.run_cluster_create() self.test_runner.run_cluster_create()
@test(depends_on=[cluster_create])
def cluster_list(self):
"""List the clusters."""
self.test_runner.run_cluster_list()
@test(depends_on=[cluster_create])
def cluster_show(self):
"""Show a cluster."""
self.test_runner.run_cluster_show()
@test(depends_on=[cluster_create]) @test(depends_on=[cluster_create])
def add_initial_cluster_data(self): def add_initial_cluster_data(self):
"""Add data to cluster.""" """Add data to cluster."""
@ -61,7 +71,8 @@ class ClusterActionsGroup(TestGroup):
self.test_runner.run_verify_cluster_root_enable() self.test_runner.run_verify_cluster_root_enable()
@test(depends_on=[cluster_create], @test(depends_on=[cluster_create],
runs_after=[verify_initial_cluster_data, verify_cluster_root_enable]) runs_after=[verify_initial_cluster_data, verify_cluster_root_enable,
cluster_list, cluster_show])
def cluster_grow(self): def cluster_grow(self):
"""Grow cluster.""" """Grow cluster."""
self.test_runner.run_cluster_grow() self.test_runner.run_cluster_grow()

View File

@ -41,8 +41,13 @@ class ClusterActionsRunner(TestRunner):
def __init__(self): def __init__(self):
super(ClusterActionsRunner, self).__init__() super(ClusterActionsRunner, self).__init__()
self.cluster_name = 'test_cluster'
self.cluster_id = 0 self.cluster_id = 0
self.cluster_inst_ids = None
self.cluster_count_before_create = None
self.srv_grp_id = None
self.current_root_creds = None self.current_root_creds = None
self.locality = 'affinity'
@property @property
def is_using_existing_cluster(self): def is_using_existing_cluster(self):
@ -52,9 +57,15 @@ class ClusterActionsRunner(TestRunner):
def has_do_not_delete_cluster(self): def has_do_not_delete_cluster(self):
return self.has_env_flag(self.DO_NOT_DELETE_CLUSTER_FLAG) return self.has_env_flag(self.DO_NOT_DELETE_CLUSTER_FLAG)
@property
def min_cluster_node_count(self):
return 2
def run_cluster_create(self, num_nodes=None, expected_task_name='BUILDING', def run_cluster_create(self, num_nodes=None, expected_task_name='BUILDING',
expected_instance_states=['BUILD', 'ACTIVE'], expected_instance_states=['BUILD', 'ACTIVE'],
expected_http_code=200): expected_http_code=200):
self.cluster_count_before_create = len(
self.auth_client.clusters.list())
if not num_nodes: if not num_nodes:
num_nodes = self.min_cluster_node_count num_nodes = self.min_cluster_node_count
@ -64,15 +75,11 @@ class ClusterActionsRunner(TestRunner):
volume_size=self.instance_info.volume['size'])] * num_nodes volume_size=self.instance_info.volume['size'])] * num_nodes
self.cluster_id = self.assert_cluster_create( self.cluster_id = self.assert_cluster_create(
'test_cluster', instances_def, expected_task_name, self.cluster_name, instances_def, self.locality,
expected_instance_states, expected_http_code) expected_task_name, expected_instance_states, expected_http_code)
@property
def min_cluster_node_count(self):
return 2
def assert_cluster_create( def assert_cluster_create(
self, cluster_name, instances_def, expected_task_name, self, cluster_name, instances_def, locality, expected_task_name,
expected_instance_states, expected_http_code): expected_instance_states, expected_http_code):
self.report.log("Testing cluster create: %s" % cluster_name) self.report.log("Testing cluster create: %s" % cluster_name)
@ -86,8 +93,11 @@ class ClusterActionsRunner(TestRunner):
cluster = self.auth_client.clusters.create( cluster = self.auth_client.clusters.create(
cluster_name, self.instance_info.dbaas_datastore, cluster_name, self.instance_info.dbaas_datastore,
self.instance_info.dbaas_datastore_version, self.instance_info.dbaas_datastore_version,
instances=instances_def) instances=instances_def, locality=locality)
self._assert_cluster_action(cluster.id, expected_task_name, self._assert_cluster_values(cluster, expected_task_name)
# Don't give an expected task here or it will do a 'get' on
# the cluster. We tested the cluster values above.
self._assert_cluster_action(cluster.id, None,
expected_http_code) expected_http_code)
cluster_instances = self._get_cluster_instances(cluster.id) cluster_instances = self._get_cluster_instances(cluster.id)
self.assert_all_instance_states( self.assert_all_instance_states(
@ -95,6 +105,13 @@ class ClusterActionsRunner(TestRunner):
# Create the helper user/database on the first node. # Create the helper user/database on the first node.
# The cluster should handle the replication itself. # The cluster should handle the replication itself.
self.create_test_helper_on_instance(cluster_instances[0]) self.create_test_helper_on_instance(cluster_instances[0])
# make sure the server_group was created
self.cluster_inst_ids = [inst.id for inst in cluster_instances]
for id in self.cluster_inst_ids:
srv_grp_id = self.assert_server_group_exists(id)
if self.srv_grp_id and self.srv_grp_id != srv_grp_id:
self.fail("Found multiple server groups for cluster")
self.srv_grp_id = srv_grp_id
cluster_id = cluster.id cluster_id = cluster.id
@ -103,7 +120,6 @@ class ClusterActionsRunner(TestRunner):
# it may take up to the periodic task interval until the task name # it may take up to the periodic task interval until the task name
# gets updated in the Trove database. # gets updated in the Trove database.
self._assert_cluster_states(cluster_id, ['NONE']) self._assert_cluster_states(cluster_id, ['NONE'])
self._assert_cluster_response(cluster_id, 'NONE')
return cluster_id return cluster_id
@ -112,7 +128,26 @@ class ClusterActionsRunner(TestRunner):
cluster_id = os.environ.get(self.USE_CLUSTER_ID_FLAG) cluster_id = os.environ.get(self.USE_CLUSTER_ID_FLAG)
return self.auth_client.clusters.get(cluster_id) return self.auth_client.clusters.get(cluster_id)
return None def run_cluster_list(self, expected_http_code=200):
self.assert_cluster_list(
self.cluster_count_before_create + 1,
expected_http_code)
def assert_cluster_list(self, expected_count,
expected_http_code):
count = len(self.auth_client.clusters.list())
self.assert_client_code(expected_http_code)
self.assert_equal(expected_count, count, "Unexpected cluster count")
def run_cluster_show(self, expected_http_code=200,
expected_task_name='NONE'):
self.assert_cluster_show(
self.cluster_id, expected_task_name, expected_http_code)
def assert_cluster_show(self, cluster_id, expected_task_name,
expected_http_code):
self._assert_cluster_response(cluster_id, expected_task_name)
def run_cluster_root_enable(self, expected_task_name=None, def run_cluster_root_enable(self, expected_task_name=None,
expected_http_code=200): expected_http_code=200):
@ -267,11 +302,15 @@ class ClusterActionsRunner(TestRunner):
cluster_instances = self._get_cluster_instances(cluster_id) cluster_instances = self._get_cluster_instances(cluster_id)
self.auth_client.clusters.delete(cluster_id) self.auth_client.clusters.delete(cluster_id)
# Since the server_group is removed right at the beginning of the
# cluster delete process we can't check for locality anymore.
self._assert_cluster_action(cluster_id, expected_task_name, self._assert_cluster_action(cluster_id, expected_task_name,
expected_http_code) expected_http_code, check_locality=False)
self.assert_all_gone(cluster_instances, expected_last_instance_state) self.assert_all_gone(cluster_instances, expected_last_instance_state)
self._assert_cluster_gone(cluster_id) self._assert_cluster_gone(cluster_id)
# make sure the server group is gone too
self.assert_server_group_gone(self.srv_grp_id)
def _get_cluster_instances(self, cluster_id): def _get_cluster_instances(self, cluster_id):
cluster = self.auth_client.clusters.get(cluster_id) cluster = self.auth_client.clusters.get(cluster_id)
@ -279,11 +318,13 @@ class ClusterActionsRunner(TestRunner):
for instance in cluster.instances] for instance in cluster.instances]
def _assert_cluster_action( def _assert_cluster_action(
self, cluster_id, expected_state, expected_http_code): self, cluster_id, expected_task_name, expected_http_code,
check_locality=True):
if expected_http_code is not None: if expected_http_code is not None:
self.assert_client_code(expected_http_code) self.assert_client_code(expected_http_code)
if expected_state: if expected_task_name:
self._assert_cluster_response(cluster_id, expected_state) self._assert_cluster_response(cluster_id, expected_task_name,
check_locality=check_locality)
def _assert_cluster_states(self, cluster_id, expected_states, def _assert_cluster_states(self, cluster_id, expected_states,
fast_fail_status=None): fast_fail_status=None):
@ -314,8 +355,15 @@ class ClusterActionsRunner(TestRunner):
% (cluster_id, task)) % (cluster_id, task))
return task_name == task return task_name == task
def _assert_cluster_response(self, cluster_id, expected_state): def _assert_cluster_response(self, cluster_id, expected_task_name,
expected_http_code=200, check_locality=True):
cluster = self.auth_client.clusters.get(cluster_id) cluster = self.auth_client.clusters.get(cluster_id)
self.assert_client_code(expected_http_code)
self._assert_cluster_values(cluster, expected_task_name,
check_locality=check_locality)
def _assert_cluster_values(self, cluster, expected_task_name,
check_locality=True):
with TypeCheck('Cluster', cluster) as check: with TypeCheck('Cluster', cluster) as check:
check.has_field("id", six.string_types) check.has_field("id", six.string_types)
check.has_field("name", six.string_types) check.has_field("name", six.string_types)
@ -324,13 +372,18 @@ class ClusterActionsRunner(TestRunner):
check.has_field("links", list) check.has_field("links", list)
check.has_field("created", six.text_type) check.has_field("created", six.text_type)
check.has_field("updated", six.text_type) check.has_field("updated", six.text_type)
if check_locality:
check.has_field("locality", six.text_type)
for instance in cluster.instances: for instance in cluster.instances:
isinstance(instance, dict) isinstance(instance, dict)
self.assert_is_not_none(instance['id']) self.assert_is_not_none(instance['id'])
self.assert_is_not_none(instance['links']) self.assert_is_not_none(instance['links'])
self.assert_is_not_none(instance['name']) self.assert_is_not_none(instance['name'])
self.assert_equal(expected_state, cluster.task['name'], self.assert_equal(expected_task_name, cluster.task['name'],
'Unexpected cluster task name') 'Unexpected cluster task name')
if check_locality:
self.assert_equal(self.locality, cluster.locality,
"Unexpected cluster locality")
def _assert_cluster_gone(self, cluster_id): def _assert_cluster_gone(self, cluster_id):
t0 = timer.time() t0 = timer.time()

View File

@ -53,7 +53,7 @@ class ClusterTest(trove_testtools.TestCase):
CassandraCluster._create_cluster_instances( CassandraCluster._create_cluster_instances(
self.context, 'test_cluster_id', 'test_cluster', self.context, 'test_cluster_id', 'test_cluster',
datastore, datastore_version, datastore, datastore_version,
test_instances) test_instances, None, None)
check_quotas.assert_called_once_with( check_quotas.assert_called_once_with(
ANY, instances=num_instances, volumes=get_vol_size.return_value) ANY, instances=num_instances, volumes=get_vol_size.return_value)

View File

@ -61,6 +61,7 @@ class ClusterTest(trove_testtools.TestCase):
self.cluster = mongodb_api.MongoDbCluster(self.context, self.db_info, self.cluster = mongodb_api.MongoDbCluster(self.context, self.db_info,
self.datastore, self.datastore,
self.datastore_version) self.datastore_version)
self.cluster._server_group_loaded = True
self.instances = [{'volume_size': 1, 'flavor_id': '1234'}, self.instances = [{'volume_size': 1, 'flavor_id': '1234'},
{'volume_size': 1, 'flavor_id': '1234'}, {'volume_size': 1, 'flavor_id': '1234'},
{'volume_size': 1, 'flavor_id': '1234'}] {'volume_size': 1, 'flavor_id': '1234'}]
@ -80,7 +81,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
[], [],
None None, None
) )
def test_create_unequal_flavors(self): def test_create_unequal_flavors(self):
@ -93,7 +94,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, instances,
None None, None
) )
@patch.object(remote, 'create_nova_client') @patch.object(remote, 'create_nova_client')
@ -110,7 +111,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, instances,
None None, None
) )
@patch.object(remote, 'create_nova_client') @patch.object(remote, 'create_nova_client')
@ -140,7 +141,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, instances,
None None, None
) )
@patch('trove.cluster.models.LOG') @patch('trove.cluster.models.LOG')

View File

@ -37,6 +37,7 @@ class TestClusterController(TestCase):
def setUp(self): def setUp(self):
super(TestClusterController, self).setUp() super(TestClusterController, self).setUp()
self.controller = ClusterController() self.controller = ClusterController()
self.locality = 'anti-affinity'
instances = [ instances = [
{ {
"flavorRef": "7", "flavorRef": "7",
@ -57,7 +58,8 @@ class TestClusterController(TestCase):
"type": "mongodb", "type": "mongodb",
"version": "2.4.10" "version": "2.4.10"
}, },
"instances": instances "instances": instances,
"locality": self.locality,
} }
} }
self.add_shard = { self.add_shard = {
@ -112,6 +114,20 @@ class TestClusterController(TestCase):
self.assertIn("'' does not match '^.*[0-9a-zA-Z]+.*$'", error_messages) self.assertIn("'' does not match '^.*[0-9a-zA-Z]+.*$'", error_messages)
self.assertIn("type", error_paths) self.assertIn("type", error_paths)
def test_validate_create_bad_locality(self):
body = self.cluster
body['cluster']['locality'] = "$%^&"
schema = self.controller.get_schema('create', body)
validator = jsonschema.Draft4Validator(schema)
self.assertFalse(validator.is_valid(body))
errors = sorted(validator.iter_errors(body), key=lambda e: e.path)
error_messages = [error.message for error in errors]
error_paths = [error.path.pop() for error in errors]
self.assertThat(len(errors), Is(1))
self.assertIn("'$%^&' does not match '^.*[0-9a-zA-Z]+.*$'",
error_messages)
self.assertIn("locality", error_paths)
@patch.object(Cluster, 'create') @patch.object(Cluster, 'create')
@patch.object(datastore_models, 'get_datastore_version') @patch.object(datastore_models, 'get_datastore_version')
def test_create_clusters_disabled(self, def test_create_clusters_disabled(self,
@ -176,7 +192,8 @@ class TestClusterController(TestCase):
self.controller.create(req, body, tenant_id) self.controller.create(req, body, tenant_id)
mock_cluster_create.assert_called_with(context, 'products', mock_cluster_create.assert_called_with(context, 'products',
datastore, datastore_version, datastore, datastore_version,
instances, {}) instances, {},
self.locality)
@patch.object(Cluster, 'load') @patch.object(Cluster, 'load')
def test_show_cluster(self, def test_show_cluster(self,
@ -193,6 +210,7 @@ class TestClusterController(TestCase):
mock_cluster.instances_without_server = [] mock_cluster.instances_without_server = []
mock_cluster.datastore_version.manager = 'mongodb' mock_cluster.datastore_version.manager = 'mongodb'
mock_cluster_load.return_value = mock_cluster mock_cluster_load.return_value = mock_cluster
mock_cluster.locality = self.locality
self.controller.show(req, tenant_id, id) self.controller.show(req, tenant_id, id)
mock_cluster_load.assert_called_with(context, id) mock_cluster_load.assert_called_with(context, id)

View File

@ -19,6 +19,7 @@ from trove.cluster import models
from trove.common.strategies.cluster.experimental.mongodb.api import ( from trove.common.strategies.cluster.experimental.mongodb.api import (
MongoDbCluster) MongoDbCluster)
from trove.datastore import models as datastore_models from trove.datastore import models as datastore_models
from trove.instance import models as instance_models
from trove.tests.unittests import trove_testtools from trove.tests.unittests import trove_testtools
@ -27,12 +28,20 @@ class TestClusterModel(trove_testtools.TestCase):
@patch.object(datastore_models.Datastore, 'load') @patch.object(datastore_models.Datastore, 'load')
@patch.object(datastore_models.DatastoreVersion, 'load_by_uuid') @patch.object(datastore_models.DatastoreVersion, 'load_by_uuid')
@patch.object(models.DBCluster, 'find_by') @patch.object(models.DBCluster, 'find_by')
def test_load(self, mock_find_by, mock_load_dsv_by_uuid, mock_ds_load): @patch.object(instance_models.Instances, 'load_all_by_cluster_id')
def test_load(self, mock_inst_load, mock_find_by,
mock_load_dsv_by_uuid, mock_ds_load):
context = trove_testtools.TroveTestContext(self) context = trove_testtools.TroveTestContext(self)
id = Mock() id = Mock()
inst_mock = Mock()
server_group = Mock()
inst_mock.server_group = server_group
mock_inst_load.return_value = [inst_mock]
dsv = Mock() dsv = Mock()
dsv.manager = 'mongodb' dsv.manager = 'mongodb'
mock_load_dsv_by_uuid.return_value = dsv mock_load_dsv_by_uuid.return_value = dsv
cluster = models.Cluster.load(context, id) cluster = models.Cluster.load(context, id)
self.assertIsInstance(cluster, MongoDbCluster) self.assertIsInstance(cluster, MongoDbCluster)
self.assertEqual(server_group, cluster.server_group,
"Unexpected server group")

View File

@ -157,7 +157,7 @@ class TestClusterController(trove_testtools.TestCase):
self.controller.create(req, body, tenant_id) self.controller.create(req, body, tenant_id)
mock_cluster_create.assert_called_with(context, 'products', mock_cluster_create.assert_called_with(context, 'products',
datastore, datastore_version, datastore, datastore_version,
instances, {}) instances, {}, None)
@patch.object(Cluster, 'load') @patch.object(Cluster, 'load')
def test_show_cluster(self, def test_show_cluster(self,

View File

@ -190,7 +190,7 @@ class TestClusterController(trove_testtools.TestCase):
self.controller.create(req, body, tenant_id) self.controller.create(req, body, tenant_id)
mock_cluster_create.assert_called_with(context, 'products', mock_cluster_create.assert_called_with(context, 'products',
datastore, datastore_version, datastore, datastore_version,
instances, {}) instances, {}, None)
@patch.object(Cluster, 'load') @patch.object(Cluster, 'load')
def test_show_cluster(self, def test_show_cluster(self,

View File

@ -157,7 +157,7 @@ class TestClusterController(trove_testtools.TestCase):
self.controller.create(req, body, tenant_id) self.controller.create(req, body, tenant_id)
mock_cluster_create.assert_called_with(context, 'products', mock_cluster_create.assert_called_with(context, 'products',
datastore, datastore_version, datastore, datastore_version,
instances, {}) instances, {}, None)
@patch.object(Cluster, 'load') @patch.object(Cluster, 'load')
def test_show_cluster(self, def test_show_cluster(self,

View File

@ -33,6 +33,7 @@ class ClusterViewTest(trove_testtools.TestCase):
def setUp(self): def setUp(self):
super(ClusterViewTest, self).setUp() super(ClusterViewTest, self).setUp()
self.locality = 'anti-affinity'
self.cluster = Mock() self.cluster = Mock()
self.cluster.created = 'Yesterday' self.cluster.created = 'Yesterday'
self.cluster.updated = 'Now' self.cluster.updated = 'Now'
@ -46,6 +47,7 @@ class ClusterViewTest(trove_testtools.TestCase):
self.cluster.instances[0].volume.size = 1 self.cluster.instances[0].volume.size = 1
self.cluster.instances[0].slave_of_id = None self.cluster.instances[0].slave_of_id = None
self.cluster.instances[0].slaves = None self.cluster.instances[0].slaves = None
self.cluster.locality = self.locality
def tearDown(self): def tearDown(self):
super(ClusterViewTest, self).tearDown() super(ClusterViewTest, self).tearDown()
@ -64,6 +66,7 @@ class ClusterViewTest(trove_testtools.TestCase):
self.assertEqual(self.cluster.name, result['cluster']['name']) self.assertEqual(self.cluster.name, result['cluster']['name'])
self.assertEqual(self.cluster.datastore_version.name, self.assertEqual(self.cluster.datastore_version.name,
result['cluster']['datastore']['version']) result['cluster']['datastore']['version'])
self.assertEqual(self.locality, result['cluster']['locality'])
@patch.object(ClusterView, 'build_instances', return_value=('10.0.0.1', @patch.object(ClusterView, 'build_instances', return_value=('10.0.0.1',
[])) []))

View File

@ -65,6 +65,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore_version = self.dv self.datastore_version = self.dv
self.cluster = galera_api.GaleraCommonCluster( self.cluster = galera_api.GaleraCommonCluster(
self.context, self.db_info, self.datastore, self.datastore_version) self.context, self.db_info, self.datastore, self.datastore_version)
self.cluster._server_group_loaded = True
self.instances = [ self.instances = [
{'volume_size': 1, 'flavor_id': '1234', {'volume_size': 1, 'flavor_id': '1234',
'nics': [{"net-id": "foo-bar"}]}, 'nics': [{"net-id": "foo-bar"}]},
@ -83,7 +84,7 @@ class ClusterTest(trove_testtools.TestCase):
self.cluster_name, self.cluster_name,
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
[], {}, [], {}, None
) )
def test_create_flavor_not_specified(self): def test_create_flavor_not_specified(self):
@ -95,7 +96,7 @@ class ClusterTest(trove_testtools.TestCase):
self.cluster_name, self.cluster_name,
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, {} instances, {}, None
) )
@patch.object(remote, 'create_nova_client') @patch.object(remote, 'create_nova_client')
@ -115,7 +116,7 @@ class ClusterTest(trove_testtools.TestCase):
self.cluster_name, self.cluster_name,
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, {} instances, {}, None
) )
@patch.object(remote, 'create_nova_client') @patch.object(remote, 'create_nova_client')
@ -131,7 +132,7 @@ class ClusterTest(trove_testtools.TestCase):
self.cluster_name, self.cluster_name,
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, {} instances, {}, None
) )
@patch.object(remote, 'create_nova_client') @patch.object(remote, 'create_nova_client')
@ -151,7 +152,7 @@ class ClusterTest(trove_testtools.TestCase):
self.cluster_name, self.cluster_name,
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, {} instances, {}, None
) )
@patch.object(remote, 'create_nova_client') @patch.object(remote, 'create_nova_client')
@ -183,7 +184,7 @@ class ClusterTest(trove_testtools.TestCase):
self.cluster_name, self.cluster_name,
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, {} instances, {}, None
) )
@patch.object(remote, 'create_nova_client') @patch.object(remote, 'create_nova_client')
@ -198,7 +199,7 @@ class ClusterTest(trove_testtools.TestCase):
self.cluster_name, self.cluster_name,
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, {} instances, {}, None
) )
@patch.object(inst_models.DBInstance, 'find_all') @patch.object(inst_models.DBInstance, 'find_all')
@ -218,7 +219,7 @@ class ClusterTest(trove_testtools.TestCase):
self.cluster_name, self.cluster_name,
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, {}) instances, {}, None)
mock_task_api.return_value.create_cluster.assert_called_with( mock_task_api.return_value.create_cluster.assert_called_with(
mock_db_create.return_value.id) mock_db_create.return_value.id)
self.assertEqual(3, mock_ins_create.call_count) self.assertEqual(3, mock_ins_create.call_count)
@ -240,7 +241,7 @@ class ClusterTest(trove_testtools.TestCase):
self.cluster_name, self.cluster_name,
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, {}) instances, {}, None)
mock_task_api.return_value.create_cluster.assert_called_with( mock_task_api.return_value.create_cluster.assert_called_with(
mock_db_create.return_value.id) mock_db_create.return_value.id)
self.assertEqual(4, mock_ins_create.call_count) self.assertEqual(4, mock_ins_create.call_count)
@ -278,7 +279,7 @@ class ClusterTest(trove_testtools.TestCase):
self.cluster_name, self.cluster_name,
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, {}) instances, {}, None)
mock_task_api.return_value.create_cluster.assert_called_with( mock_task_api.return_value.create_cluster.assert_called_with(
mock_db_create.return_value.id) mock_db_create.return_value.id)
self.assertEqual(3, mock_ins_create.call_count) self.assertEqual(3, mock_ins_create.call_count)

View File

@ -50,6 +50,7 @@ class MongoDBClusterTest(trove_testtools.TestCase):
self.cluster = api.MongoDbCluster(self.context, self.db_info, self.cluster = api.MongoDbCluster(self.context, self.db_info,
self.datastore, self.datastore,
self.datastore_version) self.datastore_version)
self.cluster._server_group_loaded = True
self.manager = mock.Mock() self.manager = mock.Mock()
self.cluster.manager = self.manager self.cluster.manager = self.manager
self.volume_support = CONF.get('mongodb').volume_support self.volume_support = CONF.get('mongodb').volume_support
@ -83,8 +84,9 @@ class MongoDBClusterTest(trove_testtools.TestCase):
self.assertEqual(mock_prep_resize.called, True) self.assertEqual(mock_prep_resize.called, True)
mock_create_shard_instances.assert_called_with([instance1, instance2, mock_create_shard_instances.assert_called_with([instance1, instance2,
instance3]) instance3], None)
mock_create_query_router_instances.assert_called_with([instance4]) mock_create_query_router_instances.assert_called_with([instance4],
None)
mock_update_db.assert_called_with( mock_update_db.assert_called_with(
task_status=tasks.ClusterTasks.GROWING_CLUSTER task_status=tasks.ClusterTasks.GROWING_CLUSTER
) )

View File

@ -72,6 +72,7 @@ class ClusterTest(trove_testtools.TestCase):
self.cluster = redis_api.RedisCluster(self.context, self.db_info, self.cluster = redis_api.RedisCluster(self.context, self.db_info,
self.datastore, self.datastore,
self.datastore_version) self.datastore_version)
self.cluster._server_group_loaded = True
self.instances_w_volumes = [{'volume_size': 1, self.instances_w_volumes = [{'volume_size': 1,
'flavor_id': '1234'}] * 3 'flavor_id': '1234'}] * 3
self.instances_no_volumes = [{'flavor_id': '1234'}] * 3 self.instances_no_volumes = [{'flavor_id': '1234'}] * 3
@ -93,7 +94,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
self.instances_w_volumes, self.instances_w_volumes,
{}) {}, None)
@patch.object(remote, 'create_nova_client') @patch.object(remote, 'create_nova_client')
@patch.object(redis_api, 'CONF') @patch.object(redis_api, 'CONF')
@ -107,7 +108,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
self.instances_no_volumes, self.instances_no_volumes,
{}) {}, None)
@patch.object(remote, 'create_nova_client') @patch.object(remote, 'create_nova_client')
@patch.object(redis_api, 'CONF') @patch.object(redis_api, 'CONF')
@ -124,7 +125,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
self.instances_w_volumes, self.instances_w_volumes,
{}) {}, None)
@patch.object(remote, 'create_nova_client') @patch.object(remote, 'create_nova_client')
@patch.object(redis_api, 'CONF') @patch.object(redis_api, 'CONF')
@ -153,7 +154,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
self.instances_no_volumes, self.instances_no_volumes,
{}) {}, None)
@patch.object(redis_api, 'CONF') @patch.object(redis_api, 'CONF')
@patch.object(inst_models.Instance, 'create') @patch.object(inst_models.Instance, 'create')
@ -169,7 +170,7 @@ class ClusterTest(trove_testtools.TestCase):
self.cluster_name, self.cluster_name,
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
self.instances_w_volumes, {}) self.instances_w_volumes, {}, None)
mock_task_api.return_value.create_cluster.assert_called_with( mock_task_api.return_value.create_cluster.assert_called_with(
self.dbcreate_mock.return_value.id) self.dbcreate_mock.return_value.id)
self.assertEqual(3, mock_ins_create.call_count) self.assertEqual(3, mock_ins_create.call_count)
@ -201,7 +202,7 @@ class ClusterTest(trove_testtools.TestCase):
self.cluster_name, self.cluster_name,
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
self.instances_no_volumes, {}) self.instances_no_volumes, {}, None)
mock_task_api.return_value.create_cluster.assert_called_with( mock_task_api.return_value.create_cluster.assert_called_with(
self.dbcreate_mock.return_value.id) self.dbcreate_mock.return_value.id)
self.assertEqual(3, mock_ins_create.call_count) self.assertEqual(3, mock_ins_create.call_count)

View File

@ -83,7 +83,7 @@ class ClusterTest(trove_testtools.TestCase):
self.cluster_name, self.cluster_name,
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
[], None) [], None, None)
@patch.object(DBCluster, 'create') @patch.object(DBCluster, 'create')
@patch.object(inst_models.DBInstance, 'find_all') @patch.object(inst_models.DBInstance, 'find_all')
@ -97,7 +97,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, instances,
None None, None
) )
@patch.object(DBCluster, 'create') @patch.object(DBCluster, 'create')
@ -120,7 +120,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, instances,
None None, None
) )
@patch.object(DBCluster, 'create') @patch.object(DBCluster, 'create')
@ -139,7 +139,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, instances,
None None, None
) )
@patch.object(DBCluster, 'create') @patch.object(DBCluster, 'create')
@ -164,7 +164,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, instances,
None None, None
) )
@patch.object(DBCluster, 'create') @patch.object(DBCluster, 'create')
@ -201,7 +201,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, instances,
None None, None
) )
@patch.object(DBCluster, 'create') @patch.object(DBCluster, 'create')
@ -220,7 +220,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, instances,
None None, None
) )
@patch.object(inst_models.DBInstance, 'find_all') @patch.object(inst_models.DBInstance, 'find_all')
@ -239,7 +239,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, instances,
None) None, None)
mock_task_api.return_value.create_cluster.assert_called_with( mock_task_api.return_value.create_cluster.assert_called_with(
mock_db_create.return_value.id) mock_db_create.return_value.id)
self.assertEqual(3, mock_ins_create.call_count) self.assertEqual(3, mock_ins_create.call_count)
@ -278,7 +278,7 @@ class ClusterTest(trove_testtools.TestCase):
self.datastore, self.datastore,
self.datastore_version, self.datastore_version,
instances, instances,
None) None, None)
mock_task_api.return_value.create_cluster.assert_called_with( mock_task_api.return_value.create_cluster.assert_called_with(
mock_db_create.return_value.id) mock_db_create.return_value.id)
self.assertEqual(3, mock_ins_create.call_count) self.assertEqual(3, mock_ins_create.call_count)