diff --git a/magnum/api/attr_validator.py b/magnum/api/attr_validator.py index 537bf76c5d..68b96d266a 100644 --- a/magnum/api/attr_validator.py +++ b/magnum/api/attr_validator.py @@ -28,6 +28,7 @@ SUPPORTED_ISOLATION = ['filesystem/posix', 'filesystem/linux', 'cgroups/mem', 'docker/runtime', 'namespaces/pid'] SUPPORTED_IMAGE_PROVIDERS = ['docker', 'appc'] +SUPPORTED_SWARM_STRATEGY = ['spread', 'binpack', 'random'] def validate_image(cli, image): @@ -166,6 +167,21 @@ def validate_labels_executor_env_variables(labels): raise exception.InvalidParameterValue(err) +def validate_labels_strategy(labels): + """Validate swarm_strategy""" + swarm_strategy = list(labels.get('swarm_strategy', "").split()) + unsupported_strategy = set(swarm_strategy) - set( + SUPPORTED_SWARM_STRATEGY) + if (len(unsupported_strategy) > 0): + raise exception.InvalidParameterValue(_( + 'property "labels/swarm_strategy" with value ' + '"%(strategy)s" is not supported, supported values are: ' + '%(supported_strategies)s') % { + 'strategy': ' '.join(list(unsupported_strategy)), + 'supported_strategies': ', '.join( + SUPPORTED_SWARM_STRATEGY + ['unspecified'])}) + + def validate_os_resources(context, cluster_template, cluster=None): """Validate ClusterTemplate's OpenStack Resources""" @@ -201,4 +217,5 @@ labels_validators = {'mesos_slave_isolation': validate_labels_isolation, 'mesos_slave_image_providers': validate_labels_image_providers, 'mesos_slave_executor_env_variables': - validate_labels_executor_env_variables} + validate_labels_executor_env_variables, + 'swarm_strategy': validate_labels_strategy} diff --git a/magnum/drivers/common/swarm_fedora_template_def.py b/magnum/drivers/common/swarm_fedora_template_def.py index 00373b7b04..c5c596ab0e 100644 --- a/magnum/drivers/common/swarm_fedora_template_def.py +++ b/magnum/drivers/common/swarm_fedora_template_def.py @@ -94,7 +94,8 @@ class SwarmFedoraTemplateDefinition(template_def.BaseTemplateDefinition): extra_params['magnum_url'] = osc.magnum_url() label_list = ['flannel_network_cidr', 'flannel_backend', - 'flannel_network_subnetlen', 'rexray_preempt'] + 'flannel_network_subnetlen', 'rexray_preempt', + 'swarm_strategy'] extra_params['auth_url'] = context.auth_url diff --git a/magnum/drivers/common/templates/swarm/fragments/write-swarm-master-service.sh b/magnum/drivers/common/templates/swarm/fragments/write-swarm-master-service.sh index 4f006b4f50..47626bac5b 100644 --- a/magnum/drivers/common/templates/swarm/fragments/write-swarm-master-service.sh +++ b/magnum/drivers/common/templates/swarm/fragments/write-swarm-master-service.sh @@ -20,6 +20,7 @@ ExecStart=/usr/bin/docker run --name swarm-manager \\ -e no_proxy=$NO_PROXY \\ swarm:$SWARM_VERSION \\ manage -H tcp://0.0.0.0:2375 \\ + --strategy $SWARM_STRATEGY \\ --replication \\ --advertise $NODE_IP:2376 \\ END_SERVICE_TOP diff --git a/magnum/drivers/swarm_fedora_atomic_v1/templates/cluster.yaml b/magnum/drivers/swarm_fedora_atomic_v1/templates/cluster.yaml index 0de667db3f..63885dffec 100644 --- a/magnum/drivers/swarm_fedora_atomic_v1/templates/cluster.yaml +++ b/magnum/drivers/swarm_fedora_atomic_v1/templates/cluster.yaml @@ -147,6 +147,12 @@ parameters: description: version of swarm used for swarm cluster default: 1.0.0 + swarm_strategy: + type: string + description: > + schedule strategy to be used by swarm manager + default: "spread" + trustee_domain_id: type: string description: domain id of the trustee @@ -414,6 +420,7 @@ resources: etcd_server_ip: {get_attr: [etcd_loadbalancer, vip_address]} api_ip_address: {get_attr: [api_pool_floating, floating_ip_address]} swarm_version: {get_param: swarm_version} + swarm_strategy: {get_param: swarm_strategy} trustee_user_id: {get_param: trustee_user_id} trustee_password: {get_param: trustee_password} trust_id: {get_param: trust_id} diff --git a/magnum/drivers/swarm_fedora_atomic_v1/templates/swarmmaster.yaml b/magnum/drivers/swarm_fedora_atomic_v1/templates/swarmmaster.yaml index dacaa65d05..72d2900a6a 100644 --- a/magnum/drivers/swarm_fedora_atomic_v1/templates/swarmmaster.yaml +++ b/magnum/drivers/swarm_fedora_atomic_v1/templates/swarmmaster.yaml @@ -103,6 +103,13 @@ parameters: type: string description: version of swarm used for swarm cluster + swarm_strategy: + type: string + description: > + schedule strategy to be used by swarm manager + constraints: + - allowed_values: ["spread", "binpack", "random"] + secgroup_swarm_master_id: type: string description: ID of the security group for swarm master. @@ -315,6 +322,7 @@ resources: "$NO_PROXY": {get_param: no_proxy} "$TLS_DISABLED": {get_param: tls_disabled} "$SWARM_VERSION": {get_param: swarm_version} + "$SWARM_STRATEGY": {get_param: swarm_strategy} enable_services: type: "OS::Heat::SoftwareConfig" diff --git a/magnum/tests/unit/api/test_attr_validator.py b/magnum/tests/unit/api/test_attr_validator.py index 04d7778f33..01294113ce 100644 --- a/magnum/tests/unit/api/test_attr_validator.py +++ b/magnum/tests/unit/api/test_attr_validator.py @@ -186,6 +186,20 @@ class TestAttrValidator(base.BaseTestCase): attr_validator.validate_labels_isolation, fake_labels) + def test_validate_labels_strategy_valid(self): + fake_labels = {'swarm_strategy': 'spread'} + attr_validator.validate_labels_strategy(fake_labels) + + def test_validate_labels_strategy_missing(self): + fake_labels = {'strategy': 'spread'} + attr_validator.validate_labels_strategy(fake_labels) + + def test_validate_labels_strategy_invalid(self): + fake_labels = {'swarm_strategy': 'invalid'} + self.assertRaises(exception.InvalidParameterValue, + attr_validator.validate_labels_strategy, + fake_labels) + @mock.patch('magnum.api.utils.get_openstack_resource') def test_validate_image_with_valid_image_by_name(self, mock_os_res): mock_image = {'name': 'fedora-21-atomic-5', diff --git a/magnum/tests/unit/conductor/handlers/test_swarm_cluster_conductor.py b/magnum/tests/unit/conductor/handlers/test_swarm_cluster_conductor.py index 42c955d079..c20868d379 100644 --- a/magnum/tests/unit/conductor/handlers/test_swarm_cluster_conductor.py +++ b/magnum/tests/unit/conductor/handlers/test_swarm_cluster_conductor.py @@ -51,7 +51,8 @@ class TestClusterConductorWithSwarm(base.TestCase): 'labels': {'flannel_network_cidr': '10.101.0.0/16', 'flannel_network_subnetlen': '26', 'flannel_backend': 'vxlan', - 'rexray_preempt': 'False'}, + 'rexray_preempt': 'False', + 'swarm_strategy': 'spread'}, 'master_lb_enabled': False, 'volume_driver': 'rexray' } @@ -139,6 +140,7 @@ class TestClusterConductorWithSwarm(base.TestCase): 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de', 'auth_url': 'http://192.168.10.10:5000/v3', 'swarm_version': 'fake-version', + 'swarm_strategy': u'spread', 'volume_driver': 'rexray', 'rexray_preempt': 'False' } @@ -209,6 +211,7 @@ class TestClusterConductorWithSwarm(base.TestCase): 'auth_url': 'http://192.168.10.10:5000/v3', 'docker_storage_driver': 'devicemapper', 'swarm_version': 'fake-version', + 'swarm_strategy': u'spread', 'volume_driver': 'rexray', 'rexray_preempt': 'False' } @@ -272,6 +275,7 @@ class TestClusterConductorWithSwarm(base.TestCase): 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de', 'auth_url': 'http://192.168.10.10:5000/v3', 'swarm_version': 'fake-version', + 'swarm_strategy': u'spread', 'rexray_preempt': 'False' } self.assertEqual(expected, definition) @@ -335,6 +339,7 @@ class TestClusterConductorWithSwarm(base.TestCase): 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de', 'auth_url': 'http://192.168.10.10:5000/v3', 'swarm_version': 'fake-version', + 'swarm_strategy': u'spread', 'volume_driver': 'rexray', 'rexray_preempt': 'False' } @@ -400,6 +405,7 @@ class TestClusterConductorWithSwarm(base.TestCase): 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de', 'auth_url': 'http://192.168.10.10:5000/v3', 'swarm_version': 'fake-version', + 'swarm_strategy': u'spread', 'volume_driver': 'rexray', 'rexray_preempt': 'False' } diff --git a/magnum/tests/unit/drivers/test_template_definition.py b/magnum/tests/unit/drivers/test_template_definition.py index 598d7b6ebd..d800f171f0 100644 --- a/magnum/tests/unit/drivers/test_template_definition.py +++ b/magnum/tests/unit/drivers/test_template_definition.py @@ -718,6 +718,7 @@ class AtomicSwarmTemplateDefinitionTestCase(base.TestCase): 'flannel_network_subnetlen') flannel_backend = mock_cluster_template.labels.get('flannel_backend') rexray_preempt = mock_cluster_template.labels.get('rexray_preempt') + swarm_strategy = mock_cluster_template.labels.get('swarm_strategy') swarm_def = swarm_tdef.AtomicSwarmTemplateDefinition() @@ -730,7 +731,8 @@ class AtomicSwarmTemplateDefinitionTestCase(base.TestCase): 'flannel_backend': flannel_backend, 'flannel_network_subnetlen': flannel_subnet, 'auth_url': 'http://192.168.10.10:5000/v3', - 'rexray_preempt': rexray_preempt}} + 'rexray_preempt': rexray_preempt, + 'swarm_strategy': swarm_strategy}} mock_get_params.assert_called_once_with(mock_context, mock_cluster_template, mock_cluster,