From c932d5fab967b2e4a3b215e5cf1172a10186d238 Mon Sep 17 00:00:00 2001 From: wangqun Date: Sat, 20 Feb 2016 03:04:48 +0000 Subject: [PATCH] Add Container Volume Model into Mesos Heat Templates Previously,the mesos bay type did not support the Magnum Container Volume Model. This patch adds support for volume through the following: 1. Add username, tenant_name, preempt, region_name, domain_name to mesos bay type. 2. Add get_parameter to mesos. 3. Update mesos unit tests to support container volume. 4. Update mesos heat templates for container volume model Change-Id: Icf7cb9fc38c7facb2d49904b6e52bbce974948f7 Partially-Implements: blueprint magnum-integrate-with-cinder --- devstack/lib/magnum | 1 + magnum/conductor/template_definition.py | 24 +++++++ .../mesos/fragments/volume-service.sh | 39 ++++++++++++ .../mesos/fragments/write-heat-params.yaml | 8 +++ magnum/templates/mesos/mesoscluster.yaml | 53 ++++++++++++++++ magnum/templates/mesos/mesosslave.yaml | 62 ++++++++++++++++++- .../handlers/test_mesos_bay_conductor.py | 33 ++++++++-- .../conductor/test_template_definition.py | 36 +++++++++++ 8 files changed, 251 insertions(+), 5 deletions(-) create mode 100644 magnum/templates/mesos/fragments/volume-service.sh diff --git a/devstack/lib/magnum b/devstack/lib/magnum index 5f0bc2a60a..94ae0a587c 100644 --- a/devstack/lib/magnum +++ b/devstack/lib/magnum @@ -203,6 +203,7 @@ function create_magnum_conf { iniset $MAGNUM_CONF trust trustee_domain_id $trustee_domain_id iniset $MAGNUM_CONF trust trustee_domain_admin_id $trustee_domain_admin_id iniset $MAGNUM_CONF trust trustee_domain_admin_password $MAGNUM_TRUSTEE_DOMAIN_ADMIN_PASSWORD + iniset $MAGNUM_CONF cinder_client region_name $REGION_NAME } function update_heat_policy { diff --git a/magnum/conductor/template_definition.py b/magnum/conductor/template_definition.py index 4d8c9ab18b..094aa2ba8c 100644 --- a/magnum/conductor/template_definition.py +++ b/magnum/conductor/template_definition.py @@ -634,6 +634,8 @@ class UbuntuMesosTemplateDefinition(BaseTemplateDefinition): baymodel_attr='flavor_id') self.add_parameter('cluster_name', bay_attr='name') + self.add_parameter('volume_driver', + baymodel_attr='volume_driver') self.add_output('api_address', bay_attr='api_address') @@ -646,6 +648,28 @@ class UbuntuMesosTemplateDefinition(BaseTemplateDefinition): self.add_output('mesos_slaves', bay_attr='node_addresses') + def get_params(self, context, baymodel, bay, **kwargs): + extra_params = kwargs.pop('extra_params', {}) + # HACK(apmelton) - This uses the user's bearer token, ideally + # it should be replaced with an actual trust token with only + # access to do what the template needs it to do. + osc = clients.OpenStackClients(context) + extra_params['auth_url'] = context.auth_url + extra_params['username'] = context.user_name + extra_params['tenant_name'] = context.tenant + extra_params['domain_name'] = context.domain_name + extra_params['region_name'] = osc.cinder_region_name() + + label_list = ['rexray_preempt'] + + for label in label_list: + extra_params[label] = baymodel.labels.get(label) + + return super(UbuntuMesosTemplateDefinition, + self).get_params(context, baymodel, bay, + extra_params=extra_params, + **kwargs) + @property def template_path(self): return cfg.CONF.bay.mesos_ubuntu_template_path diff --git a/magnum/templates/mesos/fragments/volume-service.sh b/magnum/templates/mesos/fragments/volume-service.sh new file mode 100644 index 0000000000..ed8a95a49f --- /dev/null +++ b/magnum/templates/mesos/fragments/volume-service.sh @@ -0,0 +1,39 @@ +#!/bin/sh +. /etc/sysconfig/heat-params + +# Judge whether to install the rexray driver +if [ "$VOLUME_DRIVER" != "rexray" ]; then + exit 0 +fi + +curl -sSL https://dl.bintray.com/emccode/rexray/install | sh - + +CLOUD_CONFIG=/etc/rexray/config.yml +CLOUD=/etc/rexray + +if [ ! -d ${CLOUD_CONFIG} -o ! -d ${CLOUD} ]; then + mkdir -p $CLOUD +fi + +if [ ${AUTH_URL##*/}=="v3" ]; then + extra_configs="domainName: $DOMAIN_NAME" +fi + +cat > $CLOUD_CONFIG < + url for mesos to authenticate before sending request + + username: + type: string + description: user name + + password: + type: string + description: > + user password, not set in current implementation, only used to + fill in for Mesos config file + default: + password + hidden: true + + tenant_name: + type: string + description: > + tenant_name is used to isolate access to Compute resources + + volume_driver: + type: string + description: volume driver to use for container storage + default: "" + + domain_name: + type: string + description: > + domain is to define the administrative boundaries for management + of Keystone entities + + rexray_preempt: + type: string + description: > + enables any host to take control of a volume irrespective of whether + other hosts are using the volume + default: "false" + resources: ###################################################################### @@ -336,6 +381,14 @@ resources: http_proxy: {get_param: http_proxy} https_proxy: {get_param: https_proxy} no_proxy: {get_param: no_proxy} + auth_url: {get_param: auth_url} + username: {get_param: username} + password: {get_param: password} + tenant_name: {get_param: tenant_name} + volume_driver: {get_param: volume_driver} + region_name: {get_param: region_name} + domain_name: {get_param: domain_name} + rexray_preempt: {get_param: rexray_preempt} outputs: diff --git a/magnum/templates/mesos/mesosslave.yaml b/magnum/templates/mesos/mesosslave.yaml index da32aff491..c050f1d430 100644 --- a/magnum/templates/mesos/mesosslave.yaml +++ b/magnum/templates/mesos/mesosslave.yaml @@ -54,6 +54,51 @@ parameters: description: no proxies for docker default: "" + auth_url: + type: string + description: > + url for mesos to authenticate before sending request + + username: + type: string + description: user name + + password: + type: string + description: > + user password, not set in current implementation, only used to + fill in for Kubernetes config file + default: + password + hidden: true + + tenant_name: + type: string + description: > + tenant_name is used to isolate access to Compute resources + + volume_driver: + type: string + description: volume driver to use for container storage + default: "" + + region_name: + type: string + description: A logically separate section of the cluster + + domain_name: + type: string + description: > + domain is to define the administrative boundaries for management + of Keystone entities + + rexray_preempt: + type: string + description: > + enables any host to take control of a volume irrespective of whether + other hosts are using the volume + default: "false" + # The following are all generated in the parent template. mesos_masters_ips: type: string @@ -107,6 +152,14 @@ resources: "$HTTP_PROXY": {get_param: http_proxy} "$HTTPS_PROXY": {get_param: https_proxy} "$NO_PROXY": {get_param: no_proxy} + "$AUTH_URL": {get_param: auth_url} + "$USERNAME": {get_param: username} + "$PASSWORD": {get_param: password} + "$TENANT_NAME": {get_param: tenant_name} + "$VOLUME_DRIVER": {get_param: volume_driver} + "$REGION_NAME": {get_param: region_name} + "$DOMAIN_NAME": {get_param: domain_name} + "$REXRAY_PREEMPT": {get_param: rexray_preempt} configure_mesos_slave: type: OS::Heat::SoftwareConfig @@ -131,13 +184,19 @@ resources: wc_notify --data-binary '{"status": "SUCCESS"}' params: wc_notify: {get_attr: [slave_wait_handle, curl_cli]} - + add_proxy: type: OS::Heat::SoftwareConfig properties: group: ungrouped config: {get_file: fragments/add-proxy.sh} + volume_service: + type: OS::Heat::SoftwareConfig + properties: + group: ungrouped + config: {get_file: fragments/volume-service.sh} + mesos_slave_init: type: OS::Heat::MultipartMime properties: @@ -145,6 +204,7 @@ resources: - config: {get_resource: write_heat_params} - config: {get_resource: configure_mesos_slave} - config: {get_resource: add_proxy} + - config: {get_resource: volume_service} - config: {get_resource: start_services} - config: {get_resource: slave_wc_notify} diff --git a/magnum/tests/unit/conductor/handlers/test_mesos_bay_conductor.py b/magnum/tests/unit/conductor/handlers/test_mesos_bay_conductor.py index daa26c0701..3840c14837 100644 --- a/magnum/tests/unit/conductor/handlers/test_mesos_bay_conductor.py +++ b/magnum/tests/unit/conductor/handlers/test_mesos_bay_conductor.py @@ -38,7 +38,9 @@ class TestBayConductorWithMesos(base.TestCase): 'http_proxy': 'http_proxy', 'https_proxy': 'https_proxy', 'no_proxy': 'no_proxy', - 'server_type': 'vm' + 'server_type': 'vm', + 'volume_driver': 'volume_driver', + 'labels': {'rexray_preempt': 'False'} } self.bay_dict = { 'id': 1, @@ -58,6 +60,16 @@ class TestBayConductorWithMesos(base.TestCase): cfg.CONF.set_override('trustee_domain_id', '3527620c-b220-4f37-9ebc-6e63a81a9b2f', group='trust') + self.context.auth_url = 'http://192.168.10.10:5000/v3' + self.context.user_name = 'mesos_user' + self.context.tenant = 'admin' + self.context.domain_name = 'domainname' + osc_patcher = mock.patch('magnum.common.clients.OpenStackClients') + self.mock_osc_class = osc_patcher.start() + self.addCleanup(osc_patcher.stop) + self.mock_osc = mock.MagicMock() + self.mock_osc.cinder_region_name.return_value = 'RegionOne' + self.mock_osc_class.return_value = self.mock_osc @patch('magnum.objects.BayModel.get_by_uuid') def test_extract_template_definition_all_values( @@ -88,7 +100,14 @@ class TestBayConductorWithMesos(base.TestCase): 'trustee_username': 'fake_trustee', 'trustee_password': 'fake_trustee_password', 'trustee_user_id': '7b489f04-b458-4541-8179-6a48a553e656', - 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de' + 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de', + 'volume_driver': 'volume_driver', + 'auth_url': 'http://192.168.10.10:5000/v3', + 'region_name': self.mock_osc.cinder_region_name.return_value, + 'username': 'mesos_user', + 'tenant_name': 'admin', + 'domain_name': 'domainname', + 'rexray_preempt': 'False' } self.assertEqual(expected, definition) @@ -98,7 +117,7 @@ class TestBayConductorWithMesos(base.TestCase): mock_objects_baymodel_get_by_uuid): not_required = ['image_id', 'master_flavor_id', 'flavor_id', 'dns_nameserver', 'fixed_network', 'http_proxy', - 'https_proxy', 'no_proxy'] + 'https_proxy', 'no_proxy', 'volume_driver'] for key in not_required: self.baymodel_dict[key] = None @@ -120,7 +139,13 @@ class TestBayConductorWithMesos(base.TestCase): 'trustee_username': 'fake_trustee', 'trustee_password': 'fake_trustee_password', 'trustee_user_id': '7b489f04-b458-4541-8179-6a48a553e656', - 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de' + 'trust_id': 'bd11efc5-d4e2-4dac-bbce-25e348ddf7de', + 'auth_url': 'http://192.168.10.10:5000/v3', + 'region_name': self.mock_osc.cinder_region_name.return_value, + 'username': 'mesos_user', + 'tenant_name': 'admin', + 'domain_name': 'domainname', + 'rexray_preempt': 'False' } self.assertEqual(expected, definition) diff --git a/magnum/tests/unit/conductor/test_template_definition.py b/magnum/tests/unit/conductor/test_template_definition.py index c7a93917a9..9b3033d02d 100644 --- a/magnum/tests/unit/conductor/test_template_definition.py +++ b/magnum/tests/unit/conductor/test_template_definition.py @@ -510,6 +510,42 @@ class AtomicSwarmTemplateDefinitionTestCase(base.TestCase): class UbuntuMesosTemplateDefinitionTestCase(base.TestCase): + @mock.patch('magnum.common.clients.OpenStackClients') + @mock.patch('magnum.conductor.template_definition.BaseTemplateDefinition' + '.get_params') + @mock.patch('magnum.conductor.template_definition.TemplateDefinition' + '.get_output') + def test_mesos_get_params(self, mock_get_output, mock_get_params, + mock_osc_class): + mock_context = mock.MagicMock() + mock_context.auth_url = 'http://192.168.10.10:5000/v3' + mock_context.user_name = 'mesos_user' + mock_context.tenant = 'admin' + mock_context.domain_name = 'domainname' + mock_baymodel = mock.MagicMock() + mock_baymodel.tls_disabled = False + rexray_preempt = mock_baymodel.labels.get('rexray_preempt') + mock_bay = mock.MagicMock() + mock_bay.uuid = 'bay-xx-xx-xx-xx' + del mock_bay.stack_id + mock_osc = mock.MagicMock() + mock_osc.cinder_region_name.return_value = 'RegionOne' + mock_osc_class.return_value = mock_osc + + mesos_def = tdef.UbuntuMesosTemplateDefinition() + + mesos_def.get_params(mock_context, mock_baymodel, mock_bay) + + expected_kwargs = {'extra_params': { + 'region_name': mock_osc.cinder_region_name.return_value, + 'auth_url': 'http://192.168.10.10:5000/v3', + 'username': 'mesos_user', + 'tenant_name': 'admin', + 'domain_name': 'domainname', + 'rexray_preempt': rexray_preempt}} + mock_get_params.assert_called_once_with(mock_context, mock_baymodel, + mock_bay, **expected_kwargs) + def test_mesos_get_heat_param(self): mesos_def = tdef.UbuntuMesosTemplateDefinition()