ng-3: Adapt existing drivers

The existing drivers are adapted to get node_count and master_count
information from the cluster's nodegroups. At the same time the
output mappings were updated to reflect the changes in the stack to
the nodegroups.

story: 2005266

Change-Id: I725413e77f5a7bdb48131e8a10e5dc884b5e066a
This commit is contained in:
Theodoros Tsioutsias 2019-03-07 16:39:03 +00:00
parent 18c77a288d
commit ea95b0dc5c
14 changed files with 820 additions and 196 deletions

View File

@ -164,11 +164,17 @@ class HeatDriver(driver.Driver):
rollback=False): rollback=False):
definition = self.get_template_definition() definition = self.get_template_definition()
osc = clients.OpenStackClients(context)
heat_params = {} heat_params = {}
# stack node_count parameter name
stack_nc_param = definition.get_heat_param(cluster_attr='node_count')
heat_params[stack_nc_param] = cluster.node_count
# Find what changed checking the stack params
# against the ones in the template_def.
stack = osc.heat().stacks.get(cluster.stack_id,
resolve_outputs=True)
stack_params = stack.parameters
definition.add_nodegroup_params(cluster)
heat_params = definition.get_stack_diff(context, stack_params, cluster)
LOG.debug('Updating stack with these params: %s', heat_params)
scale_params = definition.get_scale_params(context, scale_params = definition.get_scale_params(context,
cluster, cluster,
scale_manager) scale_manager)
@ -180,16 +186,22 @@ class HeatDriver(driver.Driver):
'disable_rollback': not rollback 'disable_rollback': not rollback
} }
osc = clients.OpenStackClients(context)
osc.heat().stacks.update(cluster.stack_id, **fields) osc.heat().stacks.update(cluster.stack_id, **fields)
def _resize_stack(self, context, cluster, resize_manager, def _resize_stack(self, context, cluster, resize_manager,
node_count, nodes_to_remove, nodegroup=None, node_count, nodes_to_remove, nodegroup=None,
rollback=False): rollback=False):
definition = self.get_template_definition() definition = self.get_template_definition()
heat_params = {} osc = clients.OpenStackClients(context)
stack_nc_param = definition.get_heat_param(cluster_attr='node_count')
heat_params[stack_nc_param] = node_count or cluster.node_count # Find what changed checking the stack params
# against the ones in the template_def.
stack = osc.heat().stacks.get(cluster.stack_id,
resolve_outputs=True)
stack_params = stack.parameters
definition.add_nodegroup_params(cluster)
heat_params = definition.get_stack_diff(context, stack_params, cluster)
LOG.debug('Updating stack with these params: %s', heat_params)
scale_params = definition.get_scale_params(context, scale_params = definition.get_scale_params(context,
cluster, cluster,
@ -244,6 +256,8 @@ class HeatPoller(object):
self._sync_cluster_and_template_status(stack) self._sync_cluster_and_template_status(stack)
elif stack.stack_status != self.cluster.status: elif stack.stack_status != self.cluster.status:
self.template_def.update_outputs(stack, self.cluster_template,
self.cluster)
self._sync_cluster_status(stack) self._sync_cluster_status(stack)
if stack.stack_status in (fields.ClusterStatus.CREATE_FAILED, if stack.stack_status in (fields.ClusterStatus.CREATE_FAILED,
@ -273,9 +287,6 @@ class HeatPoller(object):
def _sync_cluster_status(self, stack): def _sync_cluster_status(self, stack):
self.cluster.status = stack.stack_status self.cluster.status = stack.stack_status
self.cluster.status_reason = stack.stack_status_reason self.cluster.status_reason = stack.stack_status_reason
stack_nc_param = self.template_def.get_heat_param(
cluster_attr='node_count')
self.cluster.node_count = stack.parameters[stack_nc_param]
self.cluster.save() self.cluster.save()
def get_version_info(self, stack): def get_version_info(self, stack):

View File

@ -26,14 +26,16 @@ CONF = cfg.CONF
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class ServerAddressOutputMapping(template_def.OutputMapping): class ServerAddressOutputMapping(template_def.NodeGroupOutputMapping):
public_ip_output_key = None public_ip_output_key = None
private_ip_output_key = None private_ip_output_key = None
def __init__(self, dummy_arg, cluster_attr=None): def __init__(self, dummy_arg, nodegroup_attr=None, nodegroup_uuid=None):
self.cluster_attr = cluster_attr self.nodegroup_attr = nodegroup_attr
self.nodegroup_uuid = nodegroup_uuid
self.heat_output = self.public_ip_output_key self.heat_output = self.public_ip_output_key
self.is_stack_param = False
def set_output(self, stack, cluster_template, cluster): def set_output(self, stack, cluster_template, cluster):
if not cluster_template.floating_ip_enabled: if not cluster_template.floating_ip_enabled:
@ -63,12 +65,43 @@ class CoreOSK8sTemplateDefinition(k8s_template_def.K8sTemplateDefinition):
cluster_attr='docker_volume_size') cluster_attr='docker_volume_size')
self.add_parameter('docker_storage_driver', self.add_parameter('docker_storage_driver',
cluster_template_attr='docker_storage_driver') cluster_template_attr='docker_storage_driver')
def add_nodegroup_params(self, cluster):
super(CoreOSK8sTemplateDefinition,
self).add_nodegroup_params(cluster)
worker_ng = cluster.default_ng_worker
master_ng = cluster.default_ng_master
self.add_parameter('number_of_minions',
nodegroup_attr='node_count',
nodegroup_uuid=worker_ng.uuid,
param_class=template_def.NodeGroupParameterMapping)
self.add_parameter('minion_flavor',
nodegroup_attr='flavor_id',
nodegroup_uuid=worker_ng.uuid,
param_class=template_def.NodeGroupParameterMapping)
self.add_parameter('master_flavor',
nodegroup_attr='flavor_id',
nodegroup_uuid=master_ng.uuid,
param_class=template_def.NodeGroupParameterMapping)
def update_outputs(self, stack, cluster_template, cluster):
worker_ng = cluster.default_ng_worker
master_ng = cluster.default_ng_master
self.add_output('kube_minions', self.add_output('kube_minions',
cluster_attr='node_addresses', nodegroup_attr='node_addresses',
nodegroup_uuid=worker_ng.uuid,
mapping_type=NodeAddressOutputMapping) mapping_type=NodeAddressOutputMapping)
self.add_output('kube_masters', self.add_output('kube_masters',
cluster_attr='master_addresses', nodegroup_attr='node_addresses',
nodegroup_uuid=master_ng.uuid,
mapping_type=MasterAddressOutputMapping) mapping_type=MasterAddressOutputMapping)
self.add_output('number_of_minions',
nodegroup_attr='node_count',
nodegroup_uuid=worker_ng.uuid,
is_stack_param=True)
super(CoreOSK8sTemplateDefinition,
self).update_outputs(stack, cluster_template, cluster)
def get_params(self, context, cluster_template, cluster, **kwargs): def get_params(self, context, cluster_template, cluster, **kwargs):
extra_params = kwargs.pop('extra_params', {}) extra_params = kwargs.pop('extra_params', {})

View File

@ -27,14 +27,16 @@ CONF = cfg.CONF
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class ServerAddressOutputMapping(template_def.OutputMapping): class ServerAddressOutputMapping(template_def.NodeGroupOutputMapping):
public_ip_output_key = None public_ip_output_key = None
private_ip_output_key = None private_ip_output_key = None
def __init__(self, dummy_arg, cluster_attr=None): def __init__(self, dummy_arg, nodegroup_attr=None, nodegroup_uuid=None):
self.cluster_attr = cluster_attr self.nodegroup_attr = nodegroup_attr
self.nodegroup_uuid = nodegroup_uuid
self.heat_output = self.public_ip_output_key self.heat_output = self.public_ip_output_key
self.is_stack_param = False
def set_output(self, stack, cluster_template, cluster): def set_output(self, stack, cluster_template, cluster):
if not cluster_template.floating_ip_enabled: if not cluster_template.floating_ip_enabled:
@ -64,12 +66,21 @@ class K8sFedoraTemplateDefinition(k8s_template_def.K8sTemplateDefinition):
cluster_attr='docker_volume_size') cluster_attr='docker_volume_size')
self.add_parameter('docker_storage_driver', self.add_parameter('docker_storage_driver',
cluster_template_attr='docker_storage_driver') cluster_template_attr='docker_storage_driver')
def update_outputs(self, stack, cluster_template, cluster):
worker_ng = cluster.default_ng_worker
master_ng = cluster.default_ng_master
self.add_output('kube_minions', self.add_output('kube_minions',
cluster_attr='node_addresses', nodegroup_attr='node_addresses',
nodegroup_uuid=worker_ng.uuid,
mapping_type=NodeAddressOutputMapping) mapping_type=NodeAddressOutputMapping)
self.add_output('kube_masters', self.add_output('kube_masters',
cluster_attr='master_addresses', nodegroup_attr='node_addresses',
nodegroup_uuid=master_ng.uuid,
mapping_type=MasterAddressOutputMapping) mapping_type=MasterAddressOutputMapping)
super(K8sFedoraTemplateDefinition,
self).update_outputs(stack, cluster_template, cluster)
def get_params(self, context, cluster_template, cluster, **kwargs): def get_params(self, context, cluster_template, cluster, **kwargs):
extra_params = kwargs.pop('extra_params', {}) extra_params = kwargs.pop('extra_params', {})

View File

@ -55,12 +55,6 @@ class K8sTemplateDefinition(template_def.BaseTemplateDefinition):
def __init__(self): def __init__(self):
super(K8sTemplateDefinition, self).__init__() super(K8sTemplateDefinition, self).__init__()
self.add_parameter('master_flavor',
cluster_attr='master_flavor_id')
self.add_parameter('minion_flavor',
cluster_attr='flavor_id')
self.add_parameter('number_of_minions',
cluster_attr='node_count')
self.add_parameter('external_network', self.add_parameter('external_network',
cluster_template_attr='external_network_id', cluster_template_attr='external_network_id',
required=True) required=True)
@ -93,6 +87,34 @@ class K8sTemplateDefinition(template_def.BaseTemplateDefinition):
self.add_output('kube_masters_private', self.add_output('kube_masters_private',
cluster_attr=None) cluster_attr=None)
def add_nodegroup_params(self, cluster):
super(K8sTemplateDefinition,
self).add_nodegroup_params(cluster)
worker_ng = cluster.default_ng_worker
master_ng = cluster.default_ng_master
self.add_parameter('number_of_minions',
nodegroup_attr='node_count',
nodegroup_uuid=worker_ng.uuid,
param_class=template_def.NodeGroupParameterMapping)
self.add_parameter('minion_flavor',
nodegroup_attr='flavor_id',
nodegroup_uuid=worker_ng.uuid,
param_class=template_def.NodeGroupParameterMapping)
self.add_parameter('master_flavor',
nodegroup_attr='flavor_id',
nodegroup_uuid=master_ng.uuid,
param_class=template_def.NodeGroupParameterMapping)
def update_outputs(self, stack, cluster_template, cluster):
worker_ng = cluster.default_ng_worker
self.add_output('number_of_minions',
nodegroup_attr='node_count',
nodegroup_uuid=worker_ng.uuid,
is_stack_param=True,
mapping_type=template_def.NodeGroupOutputMapping)
super(K8sTemplateDefinition,
self).update_outputs(stack, cluster_template, cluster)
def get_params(self, context, cluster_template, cluster, **kwargs): def get_params(self, context, cluster_template, cluster, **kwargs):
extra_params = kwargs.pop('extra_params', {}) extra_params = kwargs.pop('extra_params', {})

View File

@ -45,12 +45,6 @@ class SwarmFedoraTemplateDefinition(template_def.BaseTemplateDefinition):
self.add_parameter('cluster_uuid', self.add_parameter('cluster_uuid',
cluster_attr='uuid', cluster_attr='uuid',
param_type=str) param_type=str)
self.add_parameter('number_of_nodes',
cluster_attr='node_count')
self.add_parameter('master_flavor',
cluster_attr='master_flavor_id')
self.add_parameter('node_flavor',
cluster_attr='flavor_id')
self.add_parameter('docker_volume_size', self.add_parameter('docker_volume_size',
cluster_attr='docker_volume_size') cluster_attr='docker_volume_size')
self.add_parameter('volume_driver', self.add_parameter('volume_driver',
@ -79,15 +73,49 @@ class SwarmFedoraTemplateDefinition(template_def.BaseTemplateDefinition):
mapping_type=SwarmApiAddressOutputMapping) mapping_type=SwarmApiAddressOutputMapping)
self.add_output('swarm_master_private', self.add_output('swarm_master_private',
cluster_attr=None) cluster_attr=None)
self.add_output('swarm_masters',
cluster_attr='master_addresses')
self.add_output('swarm_nodes_private', self.add_output('swarm_nodes_private',
cluster_attr=None) cluster_attr=None)
self.add_output('swarm_nodes',
cluster_attr='node_addresses')
self.add_output('discovery_url', self.add_output('discovery_url',
cluster_attr='discovery_url') cluster_attr='discovery_url')
def add_nodegroup_params(self, cluster):
super(SwarmFedoraTemplateDefinition,
self).add_nodegroup_params(cluster)
master_ng = cluster.default_ng_master
worker_ng = cluster.default_ng_worker
self.add_parameter('number_of_nodes',
nodegroup_attr='node_count',
nodegroup_uuid=worker_ng.uuid,
param_class=template_def.NodeGroupParameterMapping)
self.add_parameter('node_flavor',
nodegroup_attr='flavor_id',
nodegroup_uuid=worker_ng.uuid,
param_class=template_def.NodeGroupParameterMapping)
self.add_parameter('master_flavor',
nodegroup_attr='flavor_id',
nodegroup_uuid=master_ng.uuid,
param_class=template_def.NodeGroupParameterMapping)
def update_outputs(self, stack, cluster_template, cluster):
worker_ng = cluster.default_ng_worker
master_ng = cluster.default_ng_master
self.add_output('swarm_masters',
nodegroup_attr='node_addresses',
nodegroup_uuid=master_ng.uuid,
mapping_type=template_def.NodeGroupOutputMapping)
self.add_output('swarm_nodes',
nodegroup_attr='node_addresses',
nodegroup_uuid=worker_ng.uuid,
mapping_type=template_def.NodeGroupOutputMapping)
self.add_output('number_of_nodes',
nodegroup_attr='node_count',
nodegroup_uuid=worker_ng.uuid,
is_stack_param=True,
mapping_type=template_def.NodeGroupOutputMapping)
super(SwarmFedoraTemplateDefinition,
self).update_outputs(stack, cluster_template, cluster)
def get_params(self, context, cluster_template, cluster, **kwargs): def get_params(self, context, cluster_template, cluster, **kwargs):
extra_params = kwargs.pop('extra_params', {}) extra_params = kwargs.pop('extra_params', {})
extra_params['discovery_url'] = \ extra_params['discovery_url'] = \

View File

@ -39,13 +39,15 @@ class SwarmModeApiAddressOutputMapping(template_def.OutputMapping):
setattr(cluster, self.cluster_attr, value) setattr(cluster, self.cluster_attr, value)
class ServerAddressOutputMapping(template_def.OutputMapping): class ServerAddressOutputMapping(template_def.NodeGroupOutputMapping):
public_ip_output_key = None public_ip_output_key = None
private_ip_output_key = None private_ip_output_key = None
def __init__(self, dummy_arg, cluster_attr=None): def __init__(self, dummy_arg, nodegroup_attr=None, nodegroup_uuid=None):
self.cluster_attr = cluster_attr
self.heat_output = self.public_ip_output_key self.heat_output = self.public_ip_output_key
self.nodegroup_attr = nodegroup_attr
self.nodegroup_uuid = nodegroup_uuid
self.is_stack_param = False
class MasterAddressOutputMapping(ServerAddressOutputMapping): class MasterAddressOutputMapping(ServerAddressOutputMapping):
@ -63,7 +65,10 @@ class MasterAddressOutputMapping(ServerAddressOutputMapping):
for output in stack.to_dict().get('outputs', []): for output in stack.to_dict().get('outputs', []):
if output['output_key'] in self.heat_output: if output['output_key'] in self.heat_output:
_master_addresses += output['output_value'] _master_addresses += output['output_value']
setattr(cluster, self.cluster_attr, _master_addresses)
for ng in cluster.nodegroups:
if ng.uuid == self.nodegroup_uuid:
setattr(ng, self.nodegroup_attr, _master_addresses)
class NodeAddressOutputMapping(ServerAddressOutputMapping): class NodeAddressOutputMapping(ServerAddressOutputMapping):
@ -87,12 +92,6 @@ class SwarmModeTemplateDefinition(template_def.BaseTemplateDefinition):
self.add_parameter('cluster_uuid', self.add_parameter('cluster_uuid',
cluster_attr='uuid', cluster_attr='uuid',
param_type=str) param_type=str)
self.add_parameter('number_of_nodes',
cluster_attr='node_count')
self.add_parameter('master_flavor',
cluster_attr='master_flavor_id')
self.add_parameter('node_flavor',
cluster_attr='flavor_id')
self.add_parameter('docker_volume_size', self.add_parameter('docker_volume_size',
cluster_attr='docker_volume_size') cluster_attr='docker_volume_size')
self.add_parameter('volume_driver', self.add_parameter('volume_driver',
@ -113,12 +112,6 @@ class SwarmModeTemplateDefinition(template_def.BaseTemplateDefinition):
self.add_output('api_address', self.add_output('api_address',
cluster_attr='api_address', cluster_attr='api_address',
mapping_type=SwarmModeApiAddressOutputMapping) mapping_type=SwarmModeApiAddressOutputMapping)
self.add_output('swarm_masters',
cluster_attr='master_addresses',
mapping_type=MasterAddressOutputMapping)
self.add_output('swarm_nodes',
cluster_attr='node_addresses',
mapping_type=NodeAddressOutputMapping)
def get_params(self, context, cluster_template, cluster, **kwargs): def get_params(self, context, cluster_template, cluster, **kwargs):
extra_params = kwargs.pop('extra_params', {}) extra_params = kwargs.pop('extra_params', {})
@ -148,6 +141,44 @@ class SwarmModeTemplateDefinition(template_def.BaseTemplateDefinition):
extra_params=extra_params, extra_params=extra_params,
**kwargs) **kwargs)
def add_nodegroup_params(self, cluster):
super(SwarmModeTemplateDefinition,
self).add_nodegroup_params(cluster)
worker_ng = cluster.default_ng_worker
master_ng = cluster.default_ng_master
self.add_parameter('number_of_nodes',
nodegroup_attr='node_count',
nodegroup_uuid=worker_ng.uuid,
param_class=template_def.NodeGroupParameterMapping)
self.add_parameter('node_flavor',
nodegroup_attr='flavor_id',
nodegroup_uuid=worker_ng.uuid,
param_class=template_def.NodeGroupParameterMapping)
self.add_parameter('master_flavor',
nodegroup_attr='flavor_id',
nodegroup_uuid=master_ng.uuid,
param_class=template_def.NodeGroupParameterMapping)
def update_outputs(self, stack, cluster_template, cluster):
worker_ng = cluster.default_ng_worker
master_ng = cluster.default_ng_master
self.add_output('swarm_masters',
nodegroup_attr='node_addresses',
nodegroup_uuid=master_ng.uuid,
mapping_type=MasterAddressOutputMapping)
self.add_output('swarm_nodes',
nodegroup_attr='node_addresses',
nodegroup_uuid=worker_ng.uuid,
mapping_type=NodeAddressOutputMapping)
self.add_output('number_of_nodes',
nodegroup_attr='node_count',
nodegroup_uuid=worker_ng.uuid,
is_stack_param=True,
mapping_type=template_def.NodeGroupOutputMapping)
super(SwarmModeTemplateDefinition,
self).update_outputs(stack, cluster_template, cluster)
def get_env_files(self, cluster_template, cluster): def get_env_files(self, cluster_template, cluster):
env_files = [] env_files = []

View File

@ -16,6 +16,7 @@ import ast
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import strutils from oslo_utils import strutils
from oslo_utils import uuidutils
import re import re
import requests import requests
import six import six
@ -51,8 +52,7 @@ class ParameterMapping(object):
isn't set, a RequiredArgumentNotProvided exception will be raised. isn't set, a RequiredArgumentNotProvided exception will be raised.
""" """
def __init__(self, heat_param, cluster_template_attr=None, def __init__(self, heat_param, cluster_template_attr=None,
cluster_attr=None, required=False, cluster_attr=None, required=False, param_type=lambda x: x):
param_type=lambda x: x):
self.heat_param = heat_param self.heat_param = heat_param
self.cluster_template_attr = cluster_template_attr self.cluster_template_attr = cluster_template_attr
self.cluster_attr = cluster_attr self.cluster_attr = cluster_attr
@ -60,8 +60,17 @@ class ParameterMapping(object):
self.param_type = param_type self.param_type = param_type
def set_param(self, params, cluster_template, cluster): def set_param(self, params, cluster_template, cluster):
value = None value = self.get_value(cluster_template, cluster)
if self.required and value is None:
kwargs = dict(heat_param=self.heat_param)
raise exception.RequiredParameterNotProvided(**kwargs)
if value is not None:
value = self.param_type(value)
params[self.heat_param] = value
def get_value(self, cluster_template, cluster):
value = None
if (self.cluster_template_attr and if (self.cluster_template_attr and
getattr(cluster_template, self.cluster_template_attr, None) getattr(cluster_template, self.cluster_template_attr, None)
is not None): is not None):
@ -69,13 +78,26 @@ class ParameterMapping(object):
elif (self.cluster_attr and elif (self.cluster_attr and
getattr(cluster, self.cluster_attr, None) is not None): getattr(cluster, self.cluster_attr, None) is not None):
value = getattr(cluster, self.cluster_attr) value = getattr(cluster, self.cluster_attr)
elif self.required: return value
kwargs = dict(heat_param=self.heat_param)
raise exception.RequiredParameterNotProvided(**kwargs)
if value is not None:
value = self.param_type(value) class NodeGroupParameterMapping(ParameterMapping):
params[self.heat_param] = value
def __init__(self, heat_param, nodegroup_attr=None, nodegroup_uuid=None,
required=False, param_type=lambda x: x):
self.heat_param = heat_param
self.nodegroup_attr = nodegroup_attr
self.nodegroup_uuid = nodegroup_uuid
self.required = required
self.param_type = param_type
def get_value(self, cluster_template, cluster):
value = None
for ng in cluster.nodegroups:
if ng.uuid == self.nodegroup_uuid:
value = getattr(ng, self.nodegroup_attr)
break
return value
class OutputMapping(object): class OutputMapping(object):
@ -94,8 +116,9 @@ class OutputMapping(object):
return return
output_value = self.get_output_value(stack) output_value = self.get_output_value(stack)
if output_value is not None: if output_value is None:
setattr(cluster, self.cluster_attr, output_value) return
setattr(cluster, self.cluster_attr, output_value)
def matched(self, output_key): def matched(self, output_key):
return self.heat_output == output_key return self.heat_output == output_key
@ -109,6 +132,51 @@ class OutputMapping(object):
return None return None
class NodeGroupOutputMapping(OutputMapping):
"""A mapping associating stack info and nodegroup attr.
A NodeGroupOutputMapping is an association of a Heat output or parameter
with a nodegroup field. By default stack output values are reflected to the
specified nodegroup attribute. In the case where is_stack_param is set to
True, the specified heat information will come from the stack parameters.
"""
def __init__(self, heat_output, nodegroup_attr=None, nodegroup_uuid=None,
is_stack_param=False):
self.nodegroup_attr = nodegroup_attr
self.nodegroup_uuid = nodegroup_uuid
self.heat_output = heat_output
self.is_stack_param = is_stack_param
def set_output(self, stack, cluster_template, cluster):
if self.nodegroup_attr is None:
return
output_value = self.get_output_value(stack)
if output_value is None:
return
for ng in cluster.nodegroups:
if ng.uuid == self.nodegroup_uuid:
# nodegroups are fetched from the database every
# time, so the bad thing here is that we need to
# save each change.
setattr(ng, self.nodegroup_attr, output_value)
ng.save()
def get_output_value(self, stack):
if not self.is_stack_param:
return super(NodeGroupOutputMapping, self).get_output_value(stack)
return self.get_param_value(stack)
def get_param_value(self, stack):
for param, value in stack.parameters.items():
if param == self.heat_output:
return value
LOG.warning('stack does not have param %s', self.heat_output)
return None
@six.add_metaclass(abc.ABCMeta) @six.add_metaclass(abc.ABCMeta)
class TemplateDefinition(object): class TemplateDefinition(object):
"""A mapping between Magnum objects and Heat templates. """A mapping between Magnum objects and Heat templates.
@ -123,7 +191,8 @@ class TemplateDefinition(object):
self.output_mappings = list() self.output_mappings = list()
def add_parameter(self, *args, **kwargs): def add_parameter(self, *args, **kwargs):
param = ParameterMapping(*args, **kwargs) param_class = kwargs.pop('param_class', ParameterMapping)
param = param_class(*args, **kwargs)
self.param_mappings.append(param) self.param_mappings.append(param)
def add_output(self, *args, **kwargs): def add_output(self, *args, **kwargs):
@ -171,7 +240,8 @@ class TemplateDefinition(object):
""" """
return [] return []
def get_heat_param(self, cluster_attr=None, cluster_template_attr=None): def get_heat_param(self, cluster_attr=None, cluster_template_attr=None,
nodegroup_attr=None, nodegroup_uuid=None):
"""Returns stack param name. """Returns stack param name.
Return stack param name using cluster and cluster_template attributes Return stack param name using cluster and cluster_template attributes
@ -183,12 +253,53 @@ class TemplateDefinition(object):
:return: stack parameter name or None :return: stack parameter name or None
""" """
for mapping in self.param_mappings: for mapping in self.param_mappings:
if (mapping.cluster_attr == cluster_attr and if hasattr(mapping, 'cluster_attr'):
mapping.cluster_template_attr == cluster_template_attr): if mapping.cluster_attr == cluster_attr and \
return mapping.heat_param mapping.cluster_template_attr == cluster_template_attr:
return mapping.heat_param
if hasattr(mapping, 'nodegroup_attr'):
if mapping.nodegroup_attr == nodegroup_attr and \
mapping.nodegroup_uuid == nodegroup_uuid:
return mapping.heat_param
return None return None
def get_stack_diff(self, context, heat_params, cluster):
"""Returns all the params that are changed.
Compares the current params of a stack with the template def for
the cluster and return the ones that changed.
:param heat_params: a dict containing the current params and values
for a stack
:param cluster: the cluster we need to compare with.
"""
diff = {}
for mapping in self.param_mappings:
try:
heat_param_name = mapping.heat_param
stack_value = heat_params[heat_param_name]
value = mapping.get_value(cluster.cluster_template, cluster)
if value is None:
continue
# We need to avoid changing the param values if it's not
# necessary, so for some attributes we need to resolve the
# value either to name or uuid.
value = self.resolve_ambiguous_values(context, heat_param_name,
stack_value, value)
if stack_value != value:
diff.update({heat_param_name: value})
except KeyError:
# If the key is not in heat_params just skip it. In case
# of update we don't want to trigger a rebuild....
continue
return diff
def resolve_ambiguous_values(self, context, heat_param, heat_value, value):
return str(value)
def add_nodegroup_params(self, cluster):
pass
def update_outputs(self, stack, cluster_template, cluster): def update_outputs(self, stack, cluster_template, cluster):
for output in self.output_mappings: for output in self.output_mappings:
output.set_output(stack, cluster_template, cluster) output.set_output(stack, cluster_template, cluster)
@ -224,8 +335,6 @@ class BaseTemplateDefinition(TemplateDefinition):
cluster_template_attr='https_proxy') cluster_template_attr='https_proxy')
self.add_parameter('no_proxy', self.add_parameter('no_proxy',
cluster_template_attr='no_proxy') cluster_template_attr='no_proxy')
self.add_parameter('number_of_masters',
cluster_attr='master_count')
@property @property
def driver_module_path(self): def driver_module_path(self):
@ -243,6 +352,9 @@ class BaseTemplateDefinition(TemplateDefinition):
def get_params(self, context, cluster_template, cluster, **kwargs): def get_params(self, context, cluster_template, cluster, **kwargs):
osc = self.get_osc(context) osc = self.get_osc(context)
# Add all the params from the cluster's nodegroups
self.add_nodegroup_params(cluster)
extra_params = kwargs.pop('extra_params', {}) extra_params = kwargs.pop('extra_params', {})
extra_params['trustee_domain_id'] = osc.keystone().trustee_domain_id extra_params['trustee_domain_id'] = osc.keystone().trustee_domain_id
extra_params['trustee_user_id'] = cluster.trustee_user_id extra_params['trustee_user_id'] = cluster.trustee_user_id
@ -271,6 +383,39 @@ class BaseTemplateDefinition(TemplateDefinition):
extra_params=extra_params, extra_params=extra_params,
**kwargs) **kwargs)
def resolve_ambiguous_values(self, context, heat_param, heat_value, value):
# Ambiguous values should be converted to the same format.
osc = self.get_osc(context)
if heat_param == 'external_network':
network = osc.neutron().show_network(heat_value).get('network')
if uuidutils.is_uuid_like(heat_value):
value = network.get('id')
else:
value = network('name')
# Any other values we might need to resolve?
return super(BaseTemplateDefinition, self).resolve_ambiguous_values(
context, heat_param, heat_value, value)
def add_nodegroup_params(self, cluster):
# Assuming that all the drivers that will not override
# this method do not support more than two nodegroups.
# Meaning that we have one master and one worker.
master_ng = cluster.default_ng_master
self.add_parameter('number_of_masters',
nodegroup_attr='node_count',
nodegroup_uuid=master_ng.uuid,
param_class=NodeGroupParameterMapping)
def update_outputs(self, stack, cluster_template, cluster):
master_ng = cluster.default_ng_master
self.add_output('number_of_masters',
nodegroup_attr='node_count',
nodegroup_uuid=master_ng.uuid,
is_stack_param=True,
mapping_type=NodeGroupOutputMapping)
super(BaseTemplateDefinition,
self).update_outputs(stack, cluster_template, cluster)
def validate_discovery_url(self, discovery_url, expect_size): def validate_discovery_url(self, discovery_url, expect_size):
url = str(discovery_url) url = str(discovery_url)
if url[len(url)-1] == '/': if url[len(url)-1] == '/':
@ -327,11 +472,8 @@ class BaseTemplateDefinition(TemplateDefinition):
def get_discovery_url(self, cluster, cluster_template=None): def get_discovery_url(self, cluster, cluster_template=None):
if hasattr(cluster, 'discovery_url') and cluster.discovery_url: if hasattr(cluster, 'discovery_url') and cluster.discovery_url:
if getattr(cluster, 'master_count', None) is not None: self.validate_discovery_url(cluster.discovery_url,
self.validate_discovery_url(cluster.discovery_url, cluster.master_count)
cluster.master_count)
else:
self.validate_discovery_url(cluster.discovery_url, 1)
discovery_url = cluster.discovery_url discovery_url = cluster.discovery_url
else: else:
discovery_endpoint = ( discovery_endpoint = (

View File

@ -31,12 +31,6 @@ class UbuntuMesosTemplateDefinition(template_def.BaseTemplateDefinition):
cluster_template_attr='fixed_network') cluster_template_attr='fixed_network')
self.add_parameter('fixed_subnet', self.add_parameter('fixed_subnet',
cluster_template_attr='fixed_subnet') cluster_template_attr='fixed_subnet')
self.add_parameter('number_of_slaves',
cluster_attr='node_count')
self.add_parameter('master_flavor',
cluster_attr='master_flavor_id')
self.add_parameter('slave_flavor',
cluster_attr='flavor_id')
self.add_parameter('cluster_name', self.add_parameter('cluster_name',
cluster_attr='name') cluster_attr='name')
self.add_parameter('volume_driver', self.add_parameter('volume_driver',
@ -46,12 +40,45 @@ class UbuntuMesosTemplateDefinition(template_def.BaseTemplateDefinition):
cluster_attr='api_address') cluster_attr='api_address')
self.add_output('mesos_master_private', self.add_output('mesos_master_private',
cluster_attr=None) cluster_attr=None)
self.add_output('mesos_master',
cluster_attr='master_addresses')
self.add_output('mesos_slaves_private', self.add_output('mesos_slaves_private',
cluster_attr=None) cluster_attr=None)
def add_nodegroup_params(self, cluster):
super(UbuntuMesosTemplateDefinition,
self).add_nodegroup_params(cluster)
master_ng = cluster.default_ng_master
worker_ng = cluster.default_ng_worker
self.add_parameter('number_of_slaves',
nodegroup_attr='node_count',
nodegroup_uuid=worker_ng.uuid,
param_class=template_def.NodeGroupParameterMapping)
self.add_parameter('slave_flavor',
nodegroup_attr='flavor_id',
nodegroup_uuid=worker_ng.uuid,
param_class=template_def.NodeGroupParameterMapping)
self.add_parameter('master_flavor',
nodegroup_attr='flavor_id',
nodegroup_uuid=master_ng.uuid,
param_class=template_def.NodeGroupParameterMapping)
def update_outputs(self, stack, cluster_template, cluster):
worker_ng = cluster.default_ng_worker
master_ng = cluster.default_ng_master
self.add_output('mesos_master',
nodegroup_attr='node_addresses',
nodegroup_uuid=master_ng.uuid,
mapping_type=template_def.NodeGroupOutputMapping)
self.add_output('mesos_slaves', self.add_output('mesos_slaves',
cluster_attr='node_addresses') nodegroup_attr='node_addresses',
nodegroup_uuid=worker_ng.uuid,
mapping_type=template_def.NodeGroupOutputMapping)
self.add_output('number_of_slaves',
nodegroup_attr='node_count',
nodegroup_uuid=worker_ng.uuid,
is_stack_param=True,
mapping_type=template_def.NodeGroupOutputMapping)
super(UbuntuMesosTemplateDefinition,
self).update_outputs(stack, cluster_template, cluster)
def get_params(self, context, cluster_template, cluster, **kwargs): def get_params(self, context, cluster_template, cluster, **kwargs):
extra_params = kwargs.pop('extra_params', {}) extra_params = kwargs.pop('extra_params', {})

View File

@ -121,8 +121,8 @@ class TestHandler(db_base.DbTestCase):
taxonomy.OUTCOME_FAILURE, notifications[0].payload['outcome']) taxonomy.OUTCOME_FAILURE, notifications[0].payload['outcome'])
cluster = objects.Cluster.get(self.context, self.cluster.uuid) cluster = objects.Cluster.get(self.context, self.cluster.uuid)
self.assertEqual(1, cluster.node_count)
self.assertEqual(1, self.worker.node_count) self.assertEqual(1, self.worker.node_count)
self.assertEqual(1, cluster.node_count)
@patch('magnum.conductor.scale_manager.get_scale_manager') @patch('magnum.conductor.scale_manager.get_scale_manager')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
@ -218,8 +218,8 @@ class TestHandler(db_base.DbTestCase):
# created and the previous solution seems kind of hacky. # created and the previous solution seems kind of hacky.
cluster_dict = utils.get_test_cluster(node_count=1) cluster_dict = utils.get_test_cluster(node_count=1)
cluster = objects.Cluster(self.context, **cluster_dict) cluster = objects.Cluster(self.context, **cluster_dict)
node_count = cluster.node_count node_count = 1
master_count = cluster.node_count master_count = 1
del cluster_dict['id'] del cluster_dict['id']
del cluster_dict['uuid'] del cluster_dict['uuid']
cluster_obj = objects.Cluster(self.context, **cluster_dict) cluster_obj = objects.Cluster(self.context, **cluster_dict)
@ -242,6 +242,8 @@ class TestHandler(db_base.DbTestCase):
mock_trust_manager.create_trustee_and_trust.assert_called_once_with( mock_trust_manager.create_trustee_and_trust.assert_called_once_with(
osc, cluster) osc, cluster)
self.assertEqual(2, len(cluster.nodegroups)) self.assertEqual(2, len(cluster.nodegroups))
self.assertEqual(node_count, cluster.node_count)
self.assertEqual(master_count, cluster.master_count)
self.assertEqual(node_count, cluster.default_ng_worker.node_count) self.assertEqual(node_count, cluster.default_ng_worker.node_count)
self.assertEqual(master_count, cluster.default_ng_master.node_count) self.assertEqual(master_count, cluster.default_ng_master.node_count)

View File

@ -114,6 +114,38 @@ class TestClusterConductorWithK8s(base.TestCase):
'flavor_id': 'flavor_id', 'flavor_id': 'flavor_id',
'project_id': 'project_id', 'project_id': 'project_id',
} }
self.worker_ng_dict = {
'uuid': '5d12f6fd-a196-4bf0-ae4c-1f639a523a53',
'name': 'worker_ng',
'cluster_id': '5d12f6fd-a196-4bf0-ae4c-1f639a523a52',
'project_id': 'project_id',
'docker_volume_size': 20,
'labels': self.cluster_dict['labels'],
'flavor_id': 'flavor_id',
'image_id': 'image_id',
'node_addresses': ['172.17.2.4'],
'node_count': 1,
'role': 'worker',
'max_nodes': 5,
'min_nodes': 1,
'is_default': True
}
self.master_ng_dict = {
'uuid': '5d12f6fd-a196-4bf0-ae4c-1f639a523a54',
'name': 'master_ng',
'cluster_id': '5d12f6fd-a196-4bf0-ae4c-1f639a523a52',
'project_id': 'project_id',
'docker_volume_size': 20,
'labels': self.cluster_dict['labels'],
'flavor_id': 'master_flavor_id',
'image_id': 'image_id',
'node_addresses': ['172.17.2.18'],
'node_count': 1,
'role': 'master',
'max_nodes': 5,
'min_nodes': 1,
'is_default': True
}
self.context.user_name = 'fake_user' self.context.user_name = 'fake_user'
self.context.project_id = 'fake_tenant' self.context.project_id = 'fake_tenant'
osc_patcher = mock.patch('magnum.common.clients.OpenStackClients') osc_patcher = mock.patch('magnum.common.clients.OpenStackClients')
@ -137,6 +169,7 @@ class TestClusterConductorWithK8s(base.TestCase):
@patch('requests.get') @patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
@patch('magnum.conductor.handlers.common.cert_manager' @patch('magnum.conductor.handlers.common.cert_manager'
'.sign_node_certificate') '.sign_node_certificate')
@ -146,11 +179,13 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_generate_csr_and_key, mock_generate_csr_and_key,
mock_sign_node_certificate, mock_sign_node_certificate,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get): mock_get):
self._test_extract_template_definition( self._test_extract_template_definition(
mock_generate_csr_and_key, mock_sign_node_certificate, mock_generate_csr_and_key, mock_sign_node_certificate,
mock_driver, mock_objects_cluster_template_get_by_uuid, mock_get) mock_driver, mock_objects_cluster_template_get_by_uuid, mock_get,
mock_objects_nodegroup_list)
def _test_extract_template_definition( def _test_extract_template_definition(
self, self,
@ -159,11 +194,16 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_driver, mock_driver,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get, mock_get,
mock_objects_nodegroup_list,
missing_attr=None): missing_attr=None):
if missing_attr in self.cluster_template_dict: if missing_attr in self.cluster_template_dict:
self.cluster_template_dict[missing_attr] = None self.cluster_template_dict[missing_attr] = None
elif missing_attr in self.cluster_dict: elif missing_attr in self.cluster_dict:
self.cluster_dict[missing_attr] = None self.cluster_dict[missing_attr] = None
elif missing_attr == 'node_count':
self.worker_ng_dict['node_count'] = None
elif missing_attr == 'master_count':
self.master_ng_dict['node_count'] = None
cluster_template = objects.ClusterTemplate( cluster_template = objects.ClusterTemplate(
self.context, **self.cluster_template_dict) self.context, **self.cluster_template_dict)
mock_generate_csr_and_key.return_value = {'csr': 'csr', mock_generate_csr_and_key.return_value = {'csr': 'csr',
@ -179,6 +219,9 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_resp.status_code = 200 mock_resp.status_code = 200
mock_get.return_value = mock_resp mock_get.return_value = mock_resp
cluster = objects.Cluster(self.context, **self.cluster_dict) cluster = objects.Cluster(self.context, **self.cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
mock_driver.return_value = k8s_dr.Driver() mock_driver.return_value = k8s_dr.Driver()
(template_path, (template_path,
@ -310,6 +353,7 @@ class TestClusterConductorWithK8s(base.TestCase):
@patch('requests.get') @patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
@patch('magnum.conductor.handlers.common.cert_manager' @patch('magnum.conductor.handlers.common.cert_manager'
'.sign_node_certificate') '.sign_node_certificate')
@ -319,6 +363,7 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_generate_csr_and_key, mock_generate_csr_and_key,
mock_sign_node_certificate, mock_sign_node_certificate,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get): mock_get):
self.cluster_template_dict['registry_enabled'] = True self.cluster_template_dict['registry_enabled'] = True
@ -336,6 +381,9 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_resp.text = expected_result mock_resp.text = expected_result
mock_get.return_value = mock_resp mock_get.return_value = mock_resp
cluster = objects.Cluster(self.context, **self.cluster_dict) cluster = objects.Cluster(self.context, **self.cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
mock_driver.return_value = k8s_dr.Driver() mock_driver.return_value = k8s_dr.Driver()
CONF.set_override('swift_region', CONF.set_override('swift_region',
@ -431,6 +479,7 @@ class TestClusterConductorWithK8s(base.TestCase):
@patch('requests.get') @patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
@patch('magnum.conductor.handlers.common.cert_manager' @patch('magnum.conductor.handlers.common.cert_manager'
'.sign_node_certificate') '.sign_node_certificate')
@ -440,6 +489,7 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_generate_csr_and_key, mock_generate_csr_and_key,
mock_sign_node_certificate, mock_sign_node_certificate,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get): mock_get):
@ -467,6 +517,9 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_get.return_value = mock_resp mock_get.return_value = mock_resp
mock_driver.return_value = k8s_dr.Driver() mock_driver.return_value = k8s_dr.Driver()
cluster = objects.Cluster(self.context, **self.cluster_dict) cluster = objects.Cluster(self.context, **self.cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
(template_path, (template_path,
definition, definition,
@ -540,10 +593,12 @@ class TestClusterConductorWithK8s(base.TestCase):
@patch('requests.get') @patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
def test_extract_template_definition_coreos_with_disovery( def test_extract_template_definition_coreos_with_disovery(
self, self,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get): mock_get):
self.cluster_template_dict['cluster_distro'] = 'coreos' self.cluster_template_dict['cluster_distro'] = 'coreos'
@ -558,6 +613,9 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_resp.status_code = 200 mock_resp.status_code = 200
mock_get.return_value = mock_resp mock_get.return_value = mock_resp
cluster = objects.Cluster(self.context, **self.cluster_dict) cluster = objects.Cluster(self.context, **self.cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
mock_driver.return_value = k8s_coreos_dr.Driver() mock_driver.return_value = k8s_coreos_dr.Driver()
(template_path, (template_path,
@ -640,10 +698,12 @@ class TestClusterConductorWithK8s(base.TestCase):
@patch('requests.get') @patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
def test_extract_template_definition_coreos_no_discoveryurl( def test_extract_template_definition_coreos_no_discoveryurl(
self, self,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
reqget): reqget):
self.cluster_template_dict['cluster_distro'] = 'coreos' self.cluster_template_dict['cluster_distro'] = 'coreos'
@ -656,6 +716,9 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_objects_cluster_template_get_by_uuid.return_value = \ mock_objects_cluster_template_get_by_uuid.return_value = \
cluster_template cluster_template
cluster = objects.Cluster(self.context, **self.cluster_dict) cluster = objects.Cluster(self.context, **self.cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
mock_driver.return_value = k8s_coreos_dr.Driver() mock_driver.return_value = k8s_coreos_dr.Driver()
(template_path, (template_path,
@ -738,6 +801,7 @@ class TestClusterConductorWithK8s(base.TestCase):
@patch('requests.get') @patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
@patch('magnum.conductor.handlers.common.cert_manager' @patch('magnum.conductor.handlers.common.cert_manager'
'.sign_node_certificate') '.sign_node_certificate')
@ -747,6 +811,7 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_generate_csr_and_key, mock_generate_csr_and_key,
mock_sign_node_certificate, mock_sign_node_certificate,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get): mock_get):
mock_driver.return_value = k8s_dr.Driver() mock_driver.return_value = k8s_dr.Driver()
@ -756,10 +821,12 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_driver, mock_driver,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get, mock_get,
mock_objects_nodegroup_list,
missing_attr='dns_nameserver') missing_attr='dns_nameserver')
@patch('requests.get') @patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
@patch('magnum.conductor.handlers.common.cert_manager' @patch('magnum.conductor.handlers.common.cert_manager'
'.sign_node_certificate') '.sign_node_certificate')
@ -769,6 +836,7 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_generate_csr_and_key, mock_generate_csr_and_key,
mock_sign_node_certificate, mock_sign_node_certificate,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get): mock_get):
mock_driver.return_value = k8s_dr.Driver() mock_driver.return_value = k8s_dr.Driver()
@ -778,10 +846,12 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_driver, mock_driver,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get, mock_get,
mock_objects_nodegroup_list,
missing_attr='image_id') missing_attr='image_id')
@patch('requests.get') @patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
@patch('magnum.conductor.handlers.common.cert_manager' @patch('magnum.conductor.handlers.common.cert_manager'
'.sign_node_certificate') '.sign_node_certificate')
@ -791,6 +861,7 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_generate_csr_and_key, mock_generate_csr_and_key,
mock_sign_node_certificate, mock_sign_node_certificate,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get): mock_get):
mock_driver.return_value = k8s_dr.Driver() mock_driver.return_value = k8s_dr.Driver()
@ -800,10 +871,12 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_driver, mock_driver,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get, mock_get,
mock_objects_nodegroup_list,
missing_attr='docker_storage_driver') missing_attr='docker_storage_driver')
@patch('requests.get') @patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
@patch('magnum.conductor.handlers.common.cert_manager' @patch('magnum.conductor.handlers.common.cert_manager'
'.sign_node_certificate') '.sign_node_certificate')
@ -813,6 +886,7 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_generate_csr_and_key, mock_generate_csr_and_key,
mock_sign_node_certificate, mock_sign_node_certificate,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get): mock_get):
mock_driver.return_value = k8s_dr.Driver() mock_driver.return_value = k8s_dr.Driver()
@ -822,54 +896,12 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_driver, mock_driver,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get, mock_get,
mock_objects_nodegroup_list,
missing_attr='apiserver_port') missing_attr='apiserver_port')
@patch('requests.get') @patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.objects.NodeGroup.list')
@patch('magnum.conductor.handlers.common.cert_manager'
'.sign_node_certificate')
@patch('magnum.common.x509.operations.generate_csr_and_key')
def test_extract_template_definition_without_node_count(
self,
mock_generate_csr_and_key,
mock_sign_node_certificate,
mock_driver,
mock_objects_cluster_template_get_by_uuid,
mock_get):
mock_driver.return_value = k8s_dr.Driver()
self._test_extract_template_definition(
mock_generate_csr_and_key,
mock_sign_node_certificate,
mock_driver,
mock_objects_cluster_template_get_by_uuid,
mock_get,
missing_attr='node_count')
@patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.drivers.common.driver.Driver.get_driver')
@patch('magnum.conductor.handlers.common.cert_manager'
'.sign_node_certificate')
@patch('magnum.common.x509.operations.generate_csr_and_key')
def test_extract_template_definition_without_master_count(
self,
mock_generate_csr_and_key,
mock_sign_node_certificate,
mock_driver,
mock_objects_cluster_template_get_by_uuid,
mock_get):
mock_driver.return_value = k8s_dr.Driver()
self._test_extract_template_definition(
mock_generate_csr_and_key,
mock_sign_node_certificate,
mock_driver,
mock_objects_cluster_template_get_by_uuid,
mock_get,
missing_attr='master_count')
@patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
@patch('magnum.conductor.handlers.common.cert_manager' @patch('magnum.conductor.handlers.common.cert_manager'
'.sign_node_certificate') '.sign_node_certificate')
@ -879,6 +911,7 @@ class TestClusterConductorWithK8s(base.TestCase):
mock_generate_csr_and_key, mock_generate_csr_and_key,
mock_sign_node_certificate, mock_sign_node_certificate,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
reqget): reqget):
cluster_template = objects.ClusterTemplate( cluster_template = objects.ClusterTemplate(
@ -892,6 +925,9 @@ class TestClusterConductorWithK8s(base.TestCase):
cluster_dict = self.cluster_dict cluster_dict = self.cluster_dict
cluster_dict['discovery_url'] = None cluster_dict['discovery_url'] = None
cluster = objects.Cluster(self.context, **cluster_dict) cluster = objects.Cluster(self.context, **cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
mock_driver.return_value = k8s_dr.Driver() mock_driver.return_value = k8s_dr.Driver()
CONF.set_override('etcd_discovery_service_endpoint_format', CONF.set_override('etcd_discovery_service_endpoint_format',
@ -1109,21 +1145,35 @@ class TestClusterConductorWithK8s(base.TestCase):
@patch('magnum.drivers.k8s_fedora_atomic_v1.driver.Driver.' @patch('magnum.drivers.k8s_fedora_atomic_v1.driver.Driver.'
'_extract_template_definition') '_extract_template_definition')
@patch('magnum.common.clients.OpenStackClients') @patch('magnum.common.clients.OpenStackClients')
@patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
def test_update_stack(self, def test_update_stack(self,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid,
mock_osc, mock_osc,
mock_extract_template_definition, mock_extract_template_definition,
mock_get_template_contents): mock_get_template_contents):
mock_stack_id = 'xx-xx-xx-xx' mock_stack_id = 'xx-xx-xx-xx'
mock_heat_client = mock.MagicMock() mock_stack = mock.MagicMock(parameters={'number_of_minions': 1})
mock_stacks = mock.MagicMock()
mock_stacks.get.return_value = mock_stack
mock_heat_client = mock.MagicMock(stacks=mock_stacks)
mock_osc.return_value.heat.return_value = mock_heat_client mock_osc.return_value.heat.return_value = mock_heat_client
mock_cluster = mock.MagicMock() mock_template = objects.ClusterTemplate(
mock_cluster.stack_id = mock_stack_id self.context, **self.cluster_template_dict)
mock_objects_cluster_template_get_by_uuid.return_value = mock_template
mock_cluster = objects.Cluster(self.context, **self.cluster_dict)
mock_cluster.cluster_template = mock_template
self.worker_ng_dict['node_count'] = 2
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
k8s_dr.Driver().update_cluster({}, mock_cluster) k8s_dr.Driver().update_cluster({}, mock_cluster)
expected_args = { expected_args = {
'parameters': {'number_of_minions': mock_cluster.node_count}, 'parameters': {'number_of_minions': '2'},
'existing': True, 'existing': True,
'disable_rollback': True 'disable_rollback': True
} }

View File

@ -76,6 +76,38 @@ class TestClusterConductorWithMesos(base.TestCase):
'mesos_slave_work_dir': '/tmp/mesos/slave' 'mesos_slave_work_dir': '/tmp/mesos/slave'
}, },
} }
self.worker_ng_dict = {
'uuid': '5d12f6fd-a196-4bf0-ae4c-1f639a523a53',
'name': 'worker_ng',
'cluster_id': '5d12f6fd-a196-4bf0-ae4c-1f639a523a52',
'project_id': 'project_id',
'docker_volume_size': 20,
'labels': self.cluster_dict['labels'],
'flavor_id': 'flavor_id',
'image_id': 'image_id',
'node_addresses': ['172.17.2.4'],
'node_count': 1,
'role': 'worker',
'max_nodes': 5,
'min_nodes': 1,
'is_default': True
}
self.master_ng_dict = {
'uuid': '5d12f6fd-a196-4bf0-ae4c-1f639a523a54',
'name': 'master_ng',
'cluster_id': '5d12f6fd-a196-4bf0-ae4c-1f639a523a52',
'project_id': 'project_id',
'docker_volume_size': 20,
'labels': self.cluster_dict['labels'],
'flavor_id': 'master_flavor_id',
'image_id': 'image_id',
'node_addresses': ['172.17.2.18'],
'node_count': 1,
'role': 'master',
'max_nodes': 5,
'min_nodes': 1,
'is_default': True
}
self.context.user_name = 'mesos_user' self.context.user_name = 'mesos_user'
self.context.project_id = 'admin' self.context.project_id = 'admin'
self.context.domain_name = 'domainname' self.context.domain_name = 'domainname'
@ -91,16 +123,21 @@ class TestClusterConductorWithMesos(base.TestCase):
self.mock_osc.url_for.return_value = 'http://192.168.10.10:5000/v3' self.mock_osc.url_for.return_value = 'http://192.168.10.10:5000/v3'
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
def test_extract_template_definition_all_values( def test_extract_template_definition_all_values(
self, self,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid): mock_objects_cluster_template_get_by_uuid):
cluster_template = objects.ClusterTemplate( cluster_template = objects.ClusterTemplate(
self.context, **self.cluster_template_dict) self.context, **self.cluster_template_dict)
mock_objects_cluster_template_get_by_uuid.return_value = \ mock_objects_cluster_template_get_by_uuid.return_value = \
cluster_template cluster_template
cluster = objects.Cluster(self.context, **self.cluster_dict) cluster = objects.Cluster(self.context, **self.cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
mock_driver.return_value = mesos_dr.Driver() mock_driver.return_value = mesos_dr.Driver()
(template_path, (template_path,
@ -150,10 +187,12 @@ class TestClusterConductorWithMesos(base.TestCase):
env_files) env_files)
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
def test_extract_template_definition_only_required( def test_extract_template_definition_only_required(
self, self,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid): mock_objects_cluster_template_get_by_uuid):
not_required = ['image_id', 'master_flavor_id', 'flavor_id', not_required = ['image_id', 'master_flavor_id', 'flavor_id',
'dns_nameserver', 'fixed_network', 'http_proxy', 'dns_nameserver', 'fixed_network', 'http_proxy',
@ -167,6 +206,9 @@ class TestClusterConductorWithMesos(base.TestCase):
mock_objects_cluster_template_get_by_uuid.return_value = \ mock_objects_cluster_template_get_by_uuid.return_value = \
cluster_template cluster_template
cluster = objects.Cluster(self.context, **self.cluster_dict) cluster = objects.Cluster(self.context, **self.cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
mock_driver.return_value = mesos_dr.Driver() mock_driver.return_value = mesos_dr.Driver()
(template_path, (template_path,
@ -208,12 +250,14 @@ class TestClusterConductorWithMesos(base.TestCase):
env_files) env_files)
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
@patch('magnum.common.keystone.KeystoneClientV3') @patch('magnum.common.keystone.KeystoneClientV3')
def test_extract_template_definition_with_lb_neutron( def test_extract_template_definition_with_lb_neutron(
self, self,
mock_kc, mock_kc,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid): mock_objects_cluster_template_get_by_uuid):
self.cluster_template_dict['master_lb_enabled'] = True self.cluster_template_dict['master_lb_enabled'] = True
cluster_template = objects.ClusterTemplate( cluster_template = objects.ClusterTemplate(
@ -221,6 +265,9 @@ class TestClusterConductorWithMesos(base.TestCase):
mock_objects_cluster_template_get_by_uuid.return_value = \ mock_objects_cluster_template_get_by_uuid.return_value = \
cluster_template cluster_template
cluster = objects.Cluster(self.context, **self.cluster_dict) cluster = objects.Cluster(self.context, **self.cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
mock_driver.return_value = mesos_dr.Driver() mock_driver.return_value = mesos_dr.Driver()
mock_kc.return_value.client.services.list.return_value = [] mock_kc.return_value.client.services.list.return_value = []
@ -272,12 +319,14 @@ class TestClusterConductorWithMesos(base.TestCase):
env_files) env_files)
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
@patch('magnum.common.keystone.KeystoneClientV3') @patch('magnum.common.keystone.KeystoneClientV3')
def test_extract_template_definition_with_lb_octavia( def test_extract_template_definition_with_lb_octavia(
self, self,
mock_kc, mock_kc,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid): mock_objects_cluster_template_get_by_uuid):
self.cluster_template_dict['master_lb_enabled'] = True self.cluster_template_dict['master_lb_enabled'] = True
cluster_template = objects.ClusterTemplate( cluster_template = objects.ClusterTemplate(
@ -285,6 +334,9 @@ class TestClusterConductorWithMesos(base.TestCase):
mock_objects_cluster_template_get_by_uuid.return_value = \ mock_objects_cluster_template_get_by_uuid.return_value = \
cluster_template cluster_template
cluster = objects.Cluster(self.context, **self.cluster_dict) cluster = objects.Cluster(self.context, **self.cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
mock_driver.return_value = mesos_dr.Driver() mock_driver.return_value = mesos_dr.Driver()
class Service(object): class Service(object):
@ -341,20 +393,25 @@ class TestClusterConductorWithMesos(base.TestCase):
env_files) env_files)
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
@patch('magnum.common.keystone.KeystoneClientV3') @patch('magnum.common.keystone.KeystoneClientV3')
def test_extract_template_definition_multi_master( def test_extract_template_definition_multi_master(
self, self,
mock_kc, mock_kc,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid): mock_objects_cluster_template_get_by_uuid):
self.cluster_template_dict['master_lb_enabled'] = True self.cluster_template_dict['master_lb_enabled'] = True
self.cluster_dict['master_count'] = 2 self.master_ng_dict['node_count'] = 2
cluster_template = objects.ClusterTemplate( cluster_template = objects.ClusterTemplate(
self.context, **self.cluster_template_dict) self.context, **self.cluster_template_dict)
mock_objects_cluster_template_get_by_uuid.return_value = \ mock_objects_cluster_template_get_by_uuid.return_value = \
cluster_template cluster_template
cluster = objects.Cluster(self.context, **self.cluster_dict) cluster = objects.Cluster(self.context, **self.cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
mock_driver.return_value = mesos_dr.Driver() mock_driver.return_value = mesos_dr.Driver()
mock_kc.return_value.client.services.list.return_value = [] mock_kc.return_value.client.services.list.return_value = []
@ -409,11 +466,23 @@ class TestClusterConductorWithMesos(base.TestCase):
@patch('magnum.conf.CONF') @patch('magnum.conf.CONF')
@patch('magnum.common.clients.OpenStackClients') @patch('magnum.common.clients.OpenStackClients')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
def setup_poll_test(self, mock_driver, mock_openstack_client, mock_conf, def setup_poll_test(self, mock_driver, mock_openstack_client,
mock_retrieve_cluster_template): mock_conf, mock_retrieve_cluster_template):
mock_conf.cluster_heat.max_attempts = 10 mock_conf.cluster_heat.max_attempts = 10
cluster = mock.MagicMock() worker_ng = mock.MagicMock(
uuid='5d12f6fd-a196-4bf0-ae4c-1f639a523a53',
role='worker',
node_count=1,
)
master_ng = mock.MagicMock(
uuid='5d12f6fd-a196-4bf0-ae4c-1f639a523a54',
role='master',
node_count=1,
)
cluster = mock.MagicMock(nodegroups=[worker_ng, master_ng],
default_ng_worker=worker_ng,
default_ng_master=master_ng)
mock_heat_stack = mock.MagicMock() mock_heat_stack = mock.MagicMock()
mock_heat_client = mock.MagicMock() mock_heat_client = mock.MagicMock()
mock_heat_client.stacks.get.return_value = mock_heat_stack mock_heat_client.stacks.get.return_value = mock_heat_stack
@ -425,23 +494,30 @@ class TestClusterConductorWithMesos(base.TestCase):
poller = heat_driver.HeatPoller(mock_openstack_client, poller = heat_driver.HeatPoller(mock_openstack_client,
mock.MagicMock(), cluster, mock.MagicMock(), cluster,
mesos_dr.Driver()) mesos_dr.Driver())
poller.template_def.add_nodegroup_params(cluster)
poller.get_version_info = mock.MagicMock() poller.get_version_info = mock.MagicMock()
return (mock_heat_stack, cluster, poller) return (mock_heat_stack, cluster, poller)
def test_poll_node_count(self): def test_poll_node_count(self):
mock_heat_stack, cluster, poller = self.setup_poll_test() mock_heat_stack, cluster, poller = self.setup_poll_test()
mock_heat_stack.parameters = {'number_of_slaves': 1} mock_heat_stack.parameters = {
'number_of_slaves': 1,
'number_of_masters': 1
}
mock_heat_stack.stack_status = cluster_status.CREATE_IN_PROGRESS mock_heat_stack.stack_status = cluster_status.CREATE_IN_PROGRESS
poller.poll_and_check() poller.poll_and_check()
self.assertEqual(1, cluster.node_count) self.assertEqual(1, cluster.default_ng_worker.node_count)
def test_poll_node_count_by_update(self): def test_poll_node_count_by_update(self):
mock_heat_stack, cluster, poller = self.setup_poll_test() mock_heat_stack, cluster, poller = self.setup_poll_test()
mock_heat_stack.parameters = {'number_of_slaves': 2} mock_heat_stack.parameters = {
'number_of_slaves': 2,
'number_of_masters': 1
}
mock_heat_stack.stack_status = cluster_status.UPDATE_COMPLETE mock_heat_stack.stack_status = cluster_status.UPDATE_COMPLETE
poller.poll_and_check() poller.poll_and_check()
self.assertEqual(2, cluster.node_count) self.assertEqual(2, cluster.default_ng_worker.node_count)

View File

@ -86,6 +86,38 @@ class TestClusterConductorWithSwarm(base.TestCase):
'availability_zone': 'az_1'}, 'availability_zone': 'az_1'},
'coe_version': 'fake-version' 'coe_version': 'fake-version'
} }
self.worker_ng_dict = {
'uuid': '5d12f6fd-a196-4bf0-ae4c-1f639a523a53',
'name': 'worker_ng',
'cluster_id': '5d12f6fd-a196-4bf0-ae4c-1f639a523a52',
'project_id': 'project_id',
'docker_volume_size': 20,
'labels': self.cluster_dict['labels'],
'flavor_id': 'flavor_id',
'image_id': 'image_id',
'node_addresses': ['172.17.2.4'],
'node_count': 1,
'role': 'worker',
'max_nodes': 5,
'min_nodes': 1,
'is_default': True
}
self.master_ng_dict = {
'uuid': '5d12f6fd-a196-4bf0-ae4c-1f639a523a54',
'name': 'master_ng',
'cluster_id': '5d12f6fd-a196-4bf0-ae4c-1f639a523a52',
'project_id': 'project_id',
'docker_volume_size': 20,
'labels': self.cluster_dict['labels'],
'flavor_id': 'master_flavor_id',
'image_id': 'image_id',
'node_addresses': ['172.17.2.18'],
'node_count': 1,
'role': 'master',
'max_nodes': 5,
'min_nodes': 1,
'is_default': True
}
# We need this due to volume_driver=rexray # We need this due to volume_driver=rexray
CONF.set_override('cluster_user_trust', CONF.set_override('cluster_user_trust',
@ -105,10 +137,12 @@ class TestClusterConductorWithSwarm(base.TestCase):
@patch('requests.get') @patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
def test_extract_template_definition_all_values( def test_extract_template_definition_all_values(
self, self,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get): mock_get):
cluster_template = objects.ClusterTemplate( cluster_template = objects.ClusterTemplate(
@ -122,6 +156,9 @@ class TestClusterConductorWithSwarm(base.TestCase):
mock_get.return_value = mock_resp mock_get.return_value = mock_resp
mock_driver.return_value = swarm_dr.Driver() mock_driver.return_value = swarm_dr.Driver()
cluster = objects.Cluster(self.context, **self.cluster_dict) cluster = objects.Cluster(self.context, **self.cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
(template_path, (template_path,
definition, definition,
@ -177,10 +214,12 @@ class TestClusterConductorWithSwarm(base.TestCase):
@patch('requests.get') @patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
def test_extract_template_definition_with_registry( def test_extract_template_definition_with_registry(
self, self,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get): mock_get):
self.cluster_template_dict['registry_enabled'] = True self.cluster_template_dict['registry_enabled'] = True
@ -195,6 +234,9 @@ class TestClusterConductorWithSwarm(base.TestCase):
mock_get.return_value = mock_resp mock_get.return_value = mock_resp
mock_driver.return_value = swarm_dr.Driver() mock_driver.return_value = swarm_dr.Driver()
cluster = objects.Cluster(self.context, **self.cluster_dict) cluster = objects.Cluster(self.context, **self.cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
CONF.set_override('swift_region', CONF.set_override('swift_region',
'RegionOne', 'RegionOne',
@ -256,10 +298,12 @@ class TestClusterConductorWithSwarm(base.TestCase):
@patch('requests.get') @patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
def test_extract_template_definition_only_required( def test_extract_template_definition_only_required(
self, self,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get): mock_get):
@ -284,6 +328,9 @@ class TestClusterConductorWithSwarm(base.TestCase):
mock_get.return_value = mock_resp mock_get.return_value = mock_resp
mock_driver.return_value = swarm_dr.Driver() mock_driver.return_value = swarm_dr.Driver()
cluster = objects.Cluster(self.context, **self.cluster_dict) cluster = objects.Cluster(self.context, **self.cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
(template_path, (template_path,
definition, definition,
@ -329,12 +376,14 @@ class TestClusterConductorWithSwarm(base.TestCase):
@patch('requests.get') @patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
@patch('magnum.common.keystone.KeystoneClientV3') @patch('magnum.common.keystone.KeystoneClientV3')
def test_extract_template_definition_with_lb_neutron( def test_extract_template_definition_with_lb_neutron(
self, self,
mock_kc, mock_kc,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get): mock_get):
self.cluster_template_dict['master_lb_enabled'] = True self.cluster_template_dict['master_lb_enabled'] = True
@ -349,6 +398,9 @@ class TestClusterConductorWithSwarm(base.TestCase):
mock_get.return_value = mock_resp mock_get.return_value = mock_resp
mock_driver.return_value = swarm_dr.Driver() mock_driver.return_value = swarm_dr.Driver()
cluster = objects.Cluster(self.context, **self.cluster_dict) cluster = objects.Cluster(self.context, **self.cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
mock_kc.return_value.client.services.list.return_value = [] mock_kc.return_value.client.services.list.return_value = []
@ -406,12 +458,14 @@ class TestClusterConductorWithSwarm(base.TestCase):
@patch('requests.get') @patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
@patch('magnum.common.keystone.KeystoneClientV3') @patch('magnum.common.keystone.KeystoneClientV3')
def test_extract_template_definition_with_lb_octavia( def test_extract_template_definition_with_lb_octavia(
self, self,
mock_kc, mock_kc,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get): mock_get):
self.cluster_template_dict['master_lb_enabled'] = True self.cluster_template_dict['master_lb_enabled'] = True
@ -426,6 +480,9 @@ class TestClusterConductorWithSwarm(base.TestCase):
mock_get.return_value = mock_resp mock_get.return_value = mock_resp
mock_driver.return_value = swarm_dr.Driver() mock_driver.return_value = swarm_dr.Driver()
cluster = objects.Cluster(self.context, **self.cluster_dict) cluster = objects.Cluster(self.context, **self.cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
class Service(object): class Service(object):
def __init__(self): def __init__(self):
@ -488,16 +545,19 @@ class TestClusterConductorWithSwarm(base.TestCase):
@patch('requests.get') @patch('requests.get')
@patch('magnum.objects.ClusterTemplate.get_by_uuid') @patch('magnum.objects.ClusterTemplate.get_by_uuid')
@patch('magnum.objects.NodeGroup.list')
@patch('magnum.drivers.common.driver.Driver.get_driver') @patch('magnum.drivers.common.driver.Driver.get_driver')
@patch('magnum.common.keystone.KeystoneClientV3') @patch('magnum.common.keystone.KeystoneClientV3')
def test_extract_template_definition_multi_master( def test_extract_template_definition_multi_master(
self, self,
mock_kc, mock_kc,
mock_driver, mock_driver,
mock_objects_nodegroup_list,
mock_objects_cluster_template_get_by_uuid, mock_objects_cluster_template_get_by_uuid,
mock_get): mock_get):
self.cluster_template_dict['master_lb_enabled'] = True self.cluster_template_dict['master_lb_enabled'] = True
self.cluster_dict['master_count'] = 2 self.cluster_dict['master_count'] = 2
self.master_ng_dict['node_count'] = 2
cluster_template = objects.ClusterTemplate( cluster_template = objects.ClusterTemplate(
self.context, **self.cluster_template_dict) self.context, **self.cluster_template_dict)
mock_objects_cluster_template_get_by_uuid.return_value = \ mock_objects_cluster_template_get_by_uuid.return_value = \
@ -509,6 +569,9 @@ class TestClusterConductorWithSwarm(base.TestCase):
mock_get.return_value = mock_resp mock_get.return_value = mock_resp
mock_driver.return_value = swarm_dr.Driver() mock_driver.return_value = swarm_dr.Driver()
cluster = objects.Cluster(self.context, **self.cluster_dict) cluster = objects.Cluster(self.context, **self.cluster_dict)
worker_ng = objects.NodeGroup(self.context, **self.worker_ng_dict)
master_ng = objects.NodeGroup(self.context, **self.master_ng_dict)
mock_objects_nodegroup_list.return_value = [master_ng, worker_ng]
mock_kc.return_value.client.services.list.return_value = [] mock_kc.return_value.client.services.list.return_value = []
@ -572,7 +635,19 @@ class TestClusterConductorWithSwarm(base.TestCase):
mock_retrieve_cluster_template): mock_retrieve_cluster_template):
mock_conf.cluster_heat.max_attempts = 10 mock_conf.cluster_heat.max_attempts = 10
cluster = mock.MagicMock() worker_ng = mock.MagicMock(
uuid='5d12f6fd-a196-4bf0-ae4c-1f639a523a53',
role='worker',
node_count=1,
)
master_ng = mock.MagicMock(
uuid='5d12f6fd-a196-4bf0-ae4c-1f639a523a54',
role='master',
node_count=1,
)
cluster = mock.MagicMock(nodegroups=[worker_ng, master_ng],
default_ng_worker=worker_ng,
default_ng_master=master_ng)
mock_heat_stack = mock.MagicMock() mock_heat_stack = mock.MagicMock()
mock_heat_client = mock.MagicMock() mock_heat_client = mock.MagicMock()
mock_heat_client.stacks.get.return_value = mock_heat_stack mock_heat_client.stacks.get.return_value = mock_heat_stack
@ -585,23 +660,30 @@ class TestClusterConductorWithSwarm(base.TestCase):
poller = heat_driver.HeatPoller(mock_openstack_client, poller = heat_driver.HeatPoller(mock_openstack_client,
mock.MagicMock(), cluster, mock.MagicMock(), cluster,
swarm_dr.Driver()) swarm_dr.Driver())
poller.template_def.add_nodegroup_params(cluster)
poller.get_version_info = mock.MagicMock() poller.get_version_info = mock.MagicMock()
return (mock_heat_stack, cluster, poller) return (mock_heat_stack, cluster, poller)
def test_poll_node_count(self): def test_poll_node_count(self):
mock_heat_stack, cluster, poller = self.setup_poll_test() mock_heat_stack, cluster, poller = self.setup_poll_test()
mock_heat_stack.parameters = {'number_of_nodes': 1} mock_heat_stack.parameters = {
'number_of_nodes': 1,
'number_of_masters': 1
}
mock_heat_stack.stack_status = cluster_status.CREATE_IN_PROGRESS mock_heat_stack.stack_status = cluster_status.CREATE_IN_PROGRESS
poller.poll_and_check() poller.poll_and_check()
self.assertEqual(1, cluster.node_count) self.assertEqual(1, cluster.default_ng_worker.node_count)
def test_poll_node_count_by_update(self): def test_poll_node_count_by_update(self):
mock_heat_stack, cluster, poller = self.setup_poll_test() mock_heat_stack, cluster, poller = self.setup_poll_test()
mock_heat_stack.parameters = {'number_of_nodes': 2} mock_heat_stack.parameters = {
'number_of_nodes': 2,
'number_of_masters': 1
}
mock_heat_stack.stack_status = cluster_status.UPDATE_COMPLETE mock_heat_stack.stack_status = cluster_status.UPDATE_COMPLETE
poller.poll_and_check() poller.poll_and_check()
self.assertEqual(2, cluster.node_count) self.assertEqual(2, cluster.default_ng_worker.node_count)

View File

@ -34,7 +34,12 @@ class TestHeatPoller(base.TestCase):
mock_retrieve_cluster_template): mock_retrieve_cluster_template):
cfg.CONF.cluster_heat.max_attempts = 10 cfg.CONF.cluster_heat.max_attempts = 10
cluster = mock.MagicMock() worker_ng = mock.MagicMock(uuid='worker_ng', role='worker')
master_ng = mock.MagicMock(uuid='master_ng', role='master')
nodegroups = [worker_ng, master_ng]
cluster = mock.MagicMock(nodegroups=nodegroups,
default_ng_worker=worker_ng,
default_ng_master=master_ng)
cluster_template_dict = utils.get_test_cluster_template( cluster_template_dict = utils.get_test_cluster_template(
coe='kubernetes') coe='kubernetes')
mock_heat_stack = mock.MagicMock() mock_heat_stack = mock.MagicMock()
@ -85,45 +90,63 @@ class TestHeatPoller(base.TestCase):
mock_heat_stack, cluster, poller = self.setup_poll_test() mock_heat_stack, cluster, poller = self.setup_poll_test()
mock_heat_stack.stack_status = cluster_status.UPDATE_COMPLETE mock_heat_stack.stack_status = cluster_status.UPDATE_COMPLETE
mock_heat_stack.parameters = {'number_of_minions': 2} mock_heat_stack.parameters = {
'number_of_minions': 2,
'number_of_masters': 1
}
self.assertIsNone(poller.poll_and_check()) self.assertIsNone(poller.poll_and_check())
self.assertEqual(1, cluster.save.call_count) self.assertEqual(1, cluster.save.call_count)
self.assertEqual(1, cluster.default_ng_worker.save.call_count)
self.assertEqual(1, cluster.default_ng_master.save.call_count)
self.assertEqual(cluster_status.UPDATE_COMPLETE, cluster.status) self.assertEqual(cluster_status.UPDATE_COMPLETE, cluster.status)
self.assertEqual(2, cluster.node_count) self.assertEqual(2, cluster.default_ng_worker.node_count)
self.assertEqual(1, cluster.default_ng_master.node_count)
def test_poll_done_by_update_failed(self): def test_poll_done_by_update_failed(self):
mock_heat_stack, cluster, poller = self.setup_poll_test() mock_heat_stack, cluster, poller = self.setup_poll_test()
mock_heat_stack.stack_status = cluster_status.UPDATE_FAILED mock_heat_stack.stack_status = cluster_status.UPDATE_FAILED
mock_heat_stack.parameters = {'number_of_minions': 2} mock_heat_stack.parameters = {
'number_of_minions': 2,
'number_of_masters': 1
}
self.assertIsNone(poller.poll_and_check()) self.assertIsNone(poller.poll_and_check())
self.assertEqual(2, cluster.save.call_count) self.assertEqual(2, cluster.save.call_count)
self.assertEqual(cluster_status.UPDATE_FAILED, cluster.status) self.assertEqual(cluster_status.UPDATE_FAILED, cluster.status)
self.assertEqual(2, cluster.node_count) self.assertEqual(2, cluster.default_ng_worker.node_count)
self.assertEqual(1, cluster.default_ng_master.node_count)
def test_poll_done_by_rollback_complete(self): def test_poll_done_by_rollback_complete(self):
mock_heat_stack, cluster, poller = self.setup_poll_test() mock_heat_stack, cluster, poller = self.setup_poll_test()
mock_heat_stack.stack_status = cluster_status.ROLLBACK_COMPLETE mock_heat_stack.stack_status = cluster_status.ROLLBACK_COMPLETE
mock_heat_stack.parameters = {'number_of_minions': 1} mock_heat_stack.parameters = {
'number_of_minions': 1,
'number_of_masters': 1
}
self.assertIsNone(poller.poll_and_check()) self.assertIsNone(poller.poll_and_check())
self.assertEqual(2, cluster.save.call_count) self.assertEqual(2, cluster.save.call_count)
self.assertEqual(cluster_status.ROLLBACK_COMPLETE, cluster.status) self.assertEqual(cluster_status.ROLLBACK_COMPLETE, cluster.status)
self.assertEqual(1, cluster.node_count) self.assertEqual(1, cluster.default_ng_worker.node_count)
self.assertEqual(1, cluster.default_ng_master.node_count)
def test_poll_done_by_rollback_failed(self): def test_poll_done_by_rollback_failed(self):
mock_heat_stack, cluster, poller = self.setup_poll_test() mock_heat_stack, cluster, poller = self.setup_poll_test()
mock_heat_stack.stack_status = cluster_status.ROLLBACK_FAILED mock_heat_stack.stack_status = cluster_status.ROLLBACK_FAILED
mock_heat_stack.parameters = {'number_of_minions': 1} mock_heat_stack.parameters = {
'number_of_minions': 1,
'number_of_masters': 1
}
self.assertIsNone(poller.poll_and_check()) self.assertIsNone(poller.poll_and_check())
self.assertEqual(2, cluster.save.call_count) self.assertEqual(2, cluster.save.call_count)
self.assertEqual(cluster_status.ROLLBACK_FAILED, cluster.status) self.assertEqual(cluster_status.ROLLBACK_FAILED, cluster.status)
self.assertEqual(1, cluster.node_count) self.assertEqual(1, cluster.default_ng_worker.node_count)
self.assertEqual(1, cluster.default_ng_master.node_count)
@patch('os.path.join') @patch('os.path.join')
def test_poll_destroy(self, mock_join): def test_poll_destroy(self, mock_join):
@ -147,20 +170,28 @@ class TestHeatPoller(base.TestCase):
def test_poll_node_count(self): def test_poll_node_count(self):
mock_heat_stack, cluster, poller = self.setup_poll_test() mock_heat_stack, cluster, poller = self.setup_poll_test()
mock_heat_stack.parameters = {'number_of_minions': 1} mock_heat_stack.parameters = {
'number_of_minions': 1,
'number_of_masters': 1
}
mock_heat_stack.stack_status = cluster_status.CREATE_IN_PROGRESS mock_heat_stack.stack_status = cluster_status.CREATE_IN_PROGRESS
poller.poll_and_check() poller.poll_and_check()
self.assertEqual(1, cluster.node_count) self.assertEqual(1, cluster.default_ng_worker.node_count)
self.assertEqual(1, cluster.default_ng_master.node_count)
def test_poll_node_count_by_update(self): def test_poll_node_count_by_update(self):
mock_heat_stack, cluster, poller = self.setup_poll_test() mock_heat_stack, cluster, poller = self.setup_poll_test()
mock_heat_stack.parameters = {'number_of_minions': 2} mock_heat_stack.parameters = {
'number_of_minions': 2,
'number_of_masters': 3
}
mock_heat_stack.stack_status = cluster_status.UPDATE_COMPLETE mock_heat_stack.stack_status = cluster_status.UPDATE_COMPLETE
self.assertIsNone(poller.poll_and_check()) self.assertIsNone(poller.poll_and_check())
self.assertEqual(2, cluster.node_count) self.assertEqual(2, cluster.default_ng_worker.node_count)
self.assertEqual(3, cluster.default_ng_master.node_count)
@patch('magnum.drivers.heat.driver.trust_manager') @patch('magnum.drivers.heat.driver.trust_manager')
@patch('magnum.drivers.heat.driver.cert_manager') @patch('magnum.drivers.heat.driver.cert_manager')

View File

@ -303,6 +303,15 @@ class TemplateDefinitionTestCase(base.TestCase):
@six.add_metaclass(abc.ABCMeta) @six.add_metaclass(abc.ABCMeta)
class BaseK8sTemplateDefinitionTestCase(base.TestCase): class BaseK8sTemplateDefinitionTestCase(base.TestCase):
def setUp(self):
super(BaseK8sTemplateDefinitionTestCase, self).setUp()
self.master_ng = mock.MagicMock(uuid='master_ng', role='master')
self.worker_ng = mock.MagicMock(uuid='worker_ng', role='worker')
self.nodegroups = [self.master_ng, self.worker_ng]
self.mock_cluster = mock.MagicMock(nodegroups=self.nodegroups,
default_ng_worker=self.worker_ng,
default_ng_master=self.master_ng)
@abc.abstractmethod @abc.abstractmethod
def get_definition(self): def get_definition(self):
"""Returns the template definition.""" """Returns the template definition."""
@ -313,7 +322,9 @@ class BaseK8sTemplateDefinitionTestCase(base.TestCase):
floating_ip_enabled=True, floating_ip_enabled=True,
public_ip_output_key='kube_masters', public_ip_output_key='kube_masters',
private_ip_output_key='kube_masters_private', private_ip_output_key='kube_masters_private',
cluster_attr='master_addresses', cluster_attr=None,
nodegroup_attr=None,
is_master=False
): ):
definition = self.get_definition() definition = self.get_definition()
@ -332,14 +343,23 @@ class BaseK8sTemplateDefinitionTestCase(base.TestCase):
] ]
mock_stack = mock.MagicMock() mock_stack = mock.MagicMock()
mock_stack.to_dict.return_value = {'outputs': outputs} mock_stack.to_dict.return_value = {'outputs': outputs}
mock_cluster = mock.MagicMock()
mock_cluster_template = mock.MagicMock() mock_cluster_template = mock.MagicMock()
mock_cluster_template.floating_ip_enabled = floating_ip_enabled mock_cluster_template.floating_ip_enabled = floating_ip_enabled
definition.update_outputs(mock_stack, mock_cluster_template, definition.update_outputs(mock_stack, mock_cluster_template,
mock_cluster) self.mock_cluster)
self.assertEqual(expected_address, getattr(mock_cluster, cluster_attr)) actual = None
if cluster_attr:
actual = getattr(self.mock_cluster, cluster_attr)
elif is_master:
actual = getattr(
self.mock_cluster.default_ng_master, nodegroup_attr)
else:
actual = getattr(
self.mock_cluster.default_ng_worker, nodegroup_attr)
self.assertEqual(expected_address, actual)
class AtomicK8sTemplateDefinitionTestCase(BaseK8sTemplateDefinitionTestCase): class AtomicK8sTemplateDefinitionTestCase(BaseK8sTemplateDefinitionTestCase):
@ -1107,8 +1127,13 @@ class AtomicK8sTemplateDefinitionTestCase(BaseK8sTemplateDefinitionTestCase):
def test_k8s_get_heat_param(self): def test_k8s_get_heat_param(self):
k8s_def = k8sa_tdef.AtomicK8sTemplateDefinition() k8s_def = k8sa_tdef.AtomicK8sTemplateDefinition()
heat_param = k8s_def.get_heat_param(cluster_attr='node_count') k8s_def.add_nodegroup_params(self.mock_cluster)
heat_param = k8s_def.get_heat_param(nodegroup_attr='node_count',
nodegroup_uuid='worker_ng')
self.assertEqual('number_of_minions', heat_param) self.assertEqual('number_of_minions', heat_param)
heat_param = k8s_def.get_heat_param(nodegroup_attr='node_count',
nodegroup_uuid='master_ng')
self.assertEqual('number_of_masters', heat_param)
@mock.patch('requests.get') @mock.patch('requests.get')
def test_k8s_get_discovery_url_not_found(self, mock_get): def test_k8s_get_discovery_url_not_found(self, mock_get):
@ -1246,14 +1271,16 @@ class AtomicK8sTemplateDefinitionTestCase(BaseK8sTemplateDefinitionTestCase):
self._test_update_outputs_server_address( self._test_update_outputs_server_address(
public_ip_output_key='kube_masters', public_ip_output_key='kube_masters',
private_ip_output_key='kube_masters_private', private_ip_output_key='kube_masters_private',
cluster_attr='master_addresses', nodegroup_attr='node_addresses',
is_master=True
) )
def test_update_outputs_node_address(self): def test_update_outputs_node_address(self):
self._test_update_outputs_server_address( self._test_update_outputs_server_address(
public_ip_output_key='kube_minions', public_ip_output_key='kube_minions',
private_ip_output_key='kube_minions_private', private_ip_output_key='kube_minions_private',
cluster_attr='node_addresses', nodegroup_attr='node_addresses',
is_master=False
) )
def test_update_outputs_master_address_fip_disabled(self): def test_update_outputs_master_address_fip_disabled(self):
@ -1261,7 +1288,8 @@ class AtomicK8sTemplateDefinitionTestCase(BaseK8sTemplateDefinitionTestCase):
floating_ip_enabled=False, floating_ip_enabled=False,
public_ip_output_key='kube_masters', public_ip_output_key='kube_masters',
private_ip_output_key='kube_masters_private', private_ip_output_key='kube_masters_private',
cluster_attr='master_addresses', nodegroup_attr='node_addresses',
is_master=True
) )
def test_update_outputs_node_address_fip_disabled(self): def test_update_outputs_node_address_fip_disabled(self):
@ -1269,7 +1297,8 @@ class AtomicK8sTemplateDefinitionTestCase(BaseK8sTemplateDefinitionTestCase):
floating_ip_enabled=False, floating_ip_enabled=False,
public_ip_output_key='kube_minions', public_ip_output_key='kube_minions',
private_ip_output_key='kube_minions_private', private_ip_output_key='kube_minions_private',
cluster_attr='node_addresses', nodegroup_attr='node_addresses',
is_master=False
) )
@ -1379,6 +1408,15 @@ class FedoraK8sIronicTemplateDefinitionTestCase(base.TestCase):
class AtomicSwarmModeTemplateDefinitionTestCase(base.TestCase): class AtomicSwarmModeTemplateDefinitionTestCase(base.TestCase):
def setUp(self):
super(AtomicSwarmModeTemplateDefinitionTestCase, self).setUp()
self.master_ng = mock.MagicMock(uuid='master_ng', role='master')
self.worker_ng = mock.MagicMock(uuid='worker_ng', role='worker')
self.nodegroups = [self.master_ng, self.worker_ng]
self.mock_cluster = mock.MagicMock(nodegroups=self.nodegroups,
default_ng_worker=self.worker_ng,
default_ng_master=self.master_ng)
def get_definition(self): def get_definition(self):
return swarm_v2_dr.Driver().get_template_definition() return swarm_v2_dr.Driver().get_template_definition()
@ -1387,7 +1425,9 @@ class AtomicSwarmModeTemplateDefinitionTestCase(base.TestCase):
floating_ip_enabled=True, floating_ip_enabled=True,
public_ip_output_key='swarm_nodes', public_ip_output_key='swarm_nodes',
private_ip_output_key='swarm_nodes_private', private_ip_output_key='swarm_nodes_private',
cluster_attr='node_addresses', cluster_attr=None,
nodegroup_attr=None,
is_master=False
): ):
definition = self.get_definition() definition = self.get_definition()
@ -1407,14 +1447,20 @@ class AtomicSwarmModeTemplateDefinitionTestCase(base.TestCase):
] ]
mock_stack = mock.MagicMock() mock_stack = mock.MagicMock()
mock_stack.to_dict.return_value = {'outputs': outputs} mock_stack.to_dict.return_value = {'outputs': outputs}
mock_cluster = mock.MagicMock()
mock_cluster_template = mock.MagicMock() mock_cluster_template = mock.MagicMock()
mock_cluster_template.floating_ip_enabled = floating_ip_enabled mock_cluster_template.floating_ip_enabled = floating_ip_enabled
definition.update_outputs(mock_stack, mock_cluster_template, definition.update_outputs(mock_stack, mock_cluster_template,
mock_cluster) self.mock_cluster)
self.assertEqual(expected_address, getattr(mock_cluster, cluster_attr)) actual = None
if cluster_attr:
actual = getattr(self.mock_cluster, cluster_attr)
elif is_master:
actual = getattr(self.master_ng, nodegroup_attr)
else:
actual = getattr(self.worker_ng, nodegroup_attr)
self.assertEqual(expected_address, actual)
@mock.patch('magnum.common.clients.OpenStackClients') @mock.patch('magnum.common.clients.OpenStackClients')
@mock.patch('magnum.drivers.swarm_fedora_atomic_v2.template_def' @mock.patch('magnum.drivers.swarm_fedora_atomic_v2.template_def'
@ -1472,8 +1518,12 @@ class AtomicSwarmModeTemplateDefinitionTestCase(base.TestCase):
def test_swarm_get_heat_param(self): def test_swarm_get_heat_param(self):
swarm_def = swarm_v2_tdef.AtomicSwarmTemplateDefinition() swarm_def = swarm_v2_tdef.AtomicSwarmTemplateDefinition()
heat_param = swarm_def.get_heat_param(cluster_attr='node_count') swarm_def.add_nodegroup_params(self.mock_cluster)
heat_param = swarm_def.get_heat_param(nodegroup_attr='node_count',
nodegroup_uuid='worker_ng')
self.assertEqual('number_of_nodes', heat_param) self.assertEqual('number_of_nodes', heat_param)
heat_param = swarm_def.get_heat_param(cluster_attr='uuid')
self.assertEqual('cluster_uuid', heat_param)
def test_update_outputs(self): def test_update_outputs(self):
swarm_def = swarm_v2_tdef.AtomicSwarmTemplateDefinition() swarm_def = swarm_v2_tdef.AtomicSwarmTemplateDefinition()
@ -1500,27 +1550,29 @@ class AtomicSwarmModeTemplateDefinitionTestCase(base.TestCase):
] ]
mock_stack = mock.MagicMock() mock_stack = mock.MagicMock()
mock_stack.to_dict.return_value = {'outputs': outputs} mock_stack.to_dict.return_value = {'outputs': outputs}
mock_cluster = mock.MagicMock()
mock_cluster_template = mock.MagicMock() mock_cluster_template = mock.MagicMock()
swarm_def.update_outputs(mock_stack, mock_cluster_template, swarm_def.update_outputs(mock_stack, mock_cluster_template,
mock_cluster) self.mock_cluster)
expected_api_address = "tcp://%s:2375" % expected_api_address expected_api_address = "tcp://%s:2375" % expected_api_address
self.assertEqual(expected_api_address, mock_cluster.api_address) self.assertEqual(expected_api_address, self.mock_cluster.api_address)
self.assertEqual(expected_node_addresses, mock_cluster.node_addresses) self.assertEqual(expected_node_addresses,
self.mock_cluster.default_ng_worker.node_addresses)
def test_update_outputs_master_address(self): def test_update_outputs_master_address(self):
self._test_update_outputs_server_address( self._test_update_outputs_server_address(
public_ip_output_key='swarm_primary_master', public_ip_output_key='swarm_primary_master',
private_ip_output_key='swarm_primary_master_private', private_ip_output_key='swarm_primary_master_private',
cluster_attr='master_addresses', nodegroup_attr='node_addresses',
is_master=True
) )
def test_update_outputs_node_address(self): def test_update_outputs_node_address(self):
self._test_update_outputs_server_address( self._test_update_outputs_server_address(
public_ip_output_key='swarm_nodes', public_ip_output_key='swarm_nodes',
private_ip_output_key='swarm_nodes_private', private_ip_output_key='swarm_nodes_private',
cluster_attr='node_addresses', nodegroup_attr='node_addresses',
is_master=False
) )
def test_update_outputs_master_address_fip_disabled(self): def test_update_outputs_master_address_fip_disabled(self):
@ -1528,7 +1580,8 @@ class AtomicSwarmModeTemplateDefinitionTestCase(base.TestCase):
floating_ip_enabled=False, floating_ip_enabled=False,
public_ip_output_key='swarm_primary_master', public_ip_output_key='swarm_primary_master',
private_ip_output_key='swarm_primary_master_private', private_ip_output_key='swarm_primary_master_private',
cluster_attr='master_addresses', nodegroup_attr='node_addresses',
is_master=True
) )
def test_update_outputs_node_address_fip_disabled(self): def test_update_outputs_node_address_fip_disabled(self):
@ -1536,12 +1589,22 @@ class AtomicSwarmModeTemplateDefinitionTestCase(base.TestCase):
floating_ip_enabled=False, floating_ip_enabled=False,
public_ip_output_key='swarm_nodes', public_ip_output_key='swarm_nodes',
private_ip_output_key='swarm_nodes_private', private_ip_output_key='swarm_nodes_private',
cluster_attr='node_addresses', nodegroup_attr='node_addresses',
is_master=False
) )
class AtomicSwarmTemplateDefinitionTestCase(base.TestCase): class AtomicSwarmTemplateDefinitionTestCase(base.TestCase):
def setUp(self):
super(AtomicSwarmTemplateDefinitionTestCase, self).setUp()
self.master_ng = mock.MagicMock(uuid='master_ng', role='master')
self.worker_ng = mock.MagicMock(uuid='worker_ng', role='worker')
self.nodegroups = [self.master_ng, self.worker_ng]
self.mock_cluster = mock.MagicMock(nodegroups=self.nodegroups,
default_ng_worker=self.worker_ng,
default_ng_master=self.master_ng)
@mock.patch('magnum.common.clients.OpenStackClients') @mock.patch('magnum.common.clients.OpenStackClients')
@mock.patch('magnum.drivers.swarm_fedora_atomic_v1.template_def' @mock.patch('magnum.drivers.swarm_fedora_atomic_v1.template_def'
'.AtomicSwarmTemplateDefinition.get_discovery_url') '.AtomicSwarmTemplateDefinition.get_discovery_url')
@ -1757,7 +1820,9 @@ class AtomicSwarmTemplateDefinitionTestCase(base.TestCase):
def test_swarm_get_heat_param(self): def test_swarm_get_heat_param(self):
swarm_def = swarm_tdef.AtomicSwarmTemplateDefinition() swarm_def = swarm_tdef.AtomicSwarmTemplateDefinition()
heat_param = swarm_def.get_heat_param(cluster_attr='node_count') swarm_def.add_nodegroup_params(self.mock_cluster)
heat_param = swarm_def.get_heat_param(nodegroup_attr='node_count',
nodegroup_uuid='worker_ng')
self.assertEqual('number_of_nodes', heat_param) self.assertEqual('number_of_nodes', heat_param)
def test_update_outputs(self): def test_update_outputs(self):
@ -1785,18 +1850,27 @@ class AtomicSwarmTemplateDefinitionTestCase(base.TestCase):
] ]
mock_stack = mock.MagicMock() mock_stack = mock.MagicMock()
mock_stack.to_dict.return_value = {'outputs': outputs} mock_stack.to_dict.return_value = {'outputs': outputs}
mock_cluster = mock.MagicMock()
mock_cluster_template = mock.MagicMock() mock_cluster_template = mock.MagicMock()
swarm_def.update_outputs(mock_stack, mock_cluster_template, swarm_def.update_outputs(mock_stack, mock_cluster_template,
mock_cluster) self.mock_cluster)
expected_api_address = "tcp://%s:2376" % expected_api_address expected_api_address = "tcp://%s:2376" % expected_api_address
self.assertEqual(expected_api_address, mock_cluster.api_address) self.assertEqual(expected_api_address, self.mock_cluster.api_address)
self.assertEqual(expected_node_addresses, mock_cluster.node_addresses) self.assertEqual(expected_node_addresses,
self.worker_ng.node_addresses)
class UbuntuMesosTemplateDefinitionTestCase(base.TestCase): class UbuntuMesosTemplateDefinitionTestCase(base.TestCase):
def setUp(self):
super(UbuntuMesosTemplateDefinitionTestCase, self).setUp()
self.master_ng = mock.MagicMock(uuid='master_ng', role='master')
self.worker_ng = mock.MagicMock(uuid='worker_ng', role='worker')
self.nodegroups = [self.master_ng, self.worker_ng]
self.mock_cluster = mock.MagicMock(nodegroups=self.nodegroups,
default_ng_worker=self.worker_ng,
default_ng_master=self.master_ng)
@mock.patch('magnum.common.clients.OpenStackClients') @mock.patch('magnum.common.clients.OpenStackClients')
@mock.patch('magnum.drivers.heat.template_def.BaseTemplateDefinition' @mock.patch('magnum.drivers.heat.template_def.BaseTemplateDefinition'
'.get_params') '.get_params')
@ -1875,10 +1949,14 @@ class UbuntuMesosTemplateDefinitionTestCase(base.TestCase):
def test_mesos_get_heat_param(self): def test_mesos_get_heat_param(self):
mesos_def = mesos_tdef.UbuntuMesosTemplateDefinition() mesos_def = mesos_tdef.UbuntuMesosTemplateDefinition()
heat_param = mesos_def.get_heat_param(cluster_attr='node_count') mesos_def.add_nodegroup_params(self.mock_cluster)
heat_param = mesos_def.get_heat_param(nodegroup_attr='node_count',
nodegroup_uuid='worker_ng')
self.assertEqual('number_of_slaves', heat_param) self.assertEqual('number_of_slaves', heat_param)
heat_param = mesos_def.get_heat_param(cluster_attr='master_count') heat_param = mesos_def.get_heat_param(nodegroup_attr='node_count',
nodegroup_uuid='master_ng')
self.assertEqual('number_of_masters', heat_param) self.assertEqual('number_of_masters', heat_param)
def test_update_outputs(self): def test_update_outputs(self):
@ -1907,13 +1985,13 @@ class UbuntuMesosTemplateDefinitionTestCase(base.TestCase):
] ]
mock_stack = mock.MagicMock() mock_stack = mock.MagicMock()
mock_stack.to_dict.return_value = {'outputs': outputs} mock_stack.to_dict.return_value = {'outputs': outputs}
mock_cluster = mock.MagicMock()
mock_cluster_template = mock.MagicMock() mock_cluster_template = mock.MagicMock()
mesos_def.update_outputs(mock_stack, mock_cluster_template, mesos_def.update_outputs(mock_stack, mock_cluster_template,
mock_cluster) self.mock_cluster)
self.assertEqual(expected_api_address, mock_cluster.api_address) self.assertEqual(expected_api_address, self.mock_cluster.api_address)
self.assertEqual(expected_node_addresses, mock_cluster.node_addresses) self.assertEqual(expected_node_addresses,
self.mock_cluster.default_ng_worker.node_addresses)
self.assertEqual(expected_master_addresses, self.assertEqual(expected_master_addresses,
mock_cluster.master_addresses) self.mock_cluster.default_ng_master.node_addresses)