From 9f77fda680836dc4226bf8b2b1ad21a7c1b89169 Mon Sep 17 00:00:00 2001 From: Andriy Popovych Date: Tue, 12 May 2015 21:41:37 +0300 Subject: [PATCH] Replace all occurrences of $ with $$ in vCenter Backport from 6.1 OpenStack services may reference to previously defined variable in configuration files using $ (dollar sign), e.g. 'metadata_host = $my_ip'. Interpolation can be avoided by using $$. Passwords often contain metachars and $ is one of them. We must replace all $ occurrences with $$, otherwise service will fail to start because it cannot interpolate non-existing variable. Change-Id: I0d7d9f2d7f0ccaa3310c865a7f467c377c067442 Closes-bug: #1436083 --- .../orchestrator/deployment_serializers.py | 39 +++++++++ .../test_orchestrator_serializer.py | 85 +++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/nailgun/nailgun/orchestrator/deployment_serializers.py b/nailgun/nailgun/orchestrator/deployment_serializers.py index aabe9ddf43..5a3e253f2b 100644 --- a/nailgun/nailgun/orchestrator/deployment_serializers.py +++ b/nailgun/nailgun/orchestrator/deployment_serializers.py @@ -1143,12 +1143,51 @@ class DeploymentMultinodeSerializer60(DeploymentMultinodeSerializer): nova_network_serializer = NovaNetworkDeploymentSerializer neutron_network_serializer = NeutronNetworkDeploymentSerializer60 + def get_common_attrs(self, cluster): + attrs = super(DeploymentMultinodeSerializer60, self).\ + get_common_attrs(cluster) + + if attrs['libvirt_type'] == 'vcenter': + data_to_replace = [ + ('vcenter', 'vc_user'), + ('vcenter', 'vc_password'), + ('vcenter', 'datastore_regex'), + ('storage', 'vc_user'), + ('storage', 'vc_password') + ] + + # In order to disable variable interpolation in values + # that we write to configuration files during deployment + # we must replace all $ (dollar sign) occurrences. + for group, key in data_to_replace: + attrs[group][key] = str(attrs[group][key]).replace('$', '$$') + + return attrs + class DeploymentHASerializer60(DeploymentHASerializer): nova_network_serializer = NovaNetworkDeploymentSerializer neutron_network_serializer = NeutronNetworkDeploymentSerializer60 + def get_common_attrs(self, cluster): + attrs = super(DeploymentHASerializer60, self).\ + get_common_attrs(cluster) + + if attrs['libvirt_type'] == 'vcenter': + data_to_replace = [ + ('vcenter', 'vc_user'), + ('vcenter', 'vc_password'), + ('vcenter', 'datastore_regex'), + ('storage', 'vc_user'), + ('storage', 'vc_password') + ] + + for group, key in data_to_replace: + attrs[group][key] = str(attrs[group][key]).replace('$', '$$') + + return attrs + def create_serializer(cluster): """Returns a serializer depends on a given `cluster`. diff --git a/nailgun/nailgun/test/integration/test_orchestrator_serializer.py b/nailgun/nailgun/test/integration/test_orchestrator_serializer.py index 091dc44b46..21afc494b8 100644 --- a/nailgun/nailgun/test/integration/test_orchestrator_serializer.py +++ b/nailgun/nailgun/test/integration/test_orchestrator_serializer.py @@ -34,17 +34,25 @@ from nailgun.orchestrator.deployment_serializers import\ DeploymentHASerializer from nailgun.orchestrator.deployment_serializers import\ DeploymentHASerializer51 +from nailgun.orchestrator.deployment_serializers import\ + DeploymentHASerializer60 from nailgun.orchestrator.deployment_serializers import\ DeploymentMultinodeSerializer +from nailgun.orchestrator.deployment_serializers import\ + DeploymentMultinodeSerializer60 from nailgun.orchestrator.priority_serializers import\ PriorityHASerializer50 from nailgun.orchestrator.priority_serializers import\ PriorityHASerializer51 +from nailgun.orchestrator.priority_serializers import\ + PriorityHASerializer60 from nailgun.orchestrator.priority_serializers import\ PriorityHASerializerPatching from nailgun.orchestrator.priority_serializers import\ PriorityMultinodeSerializer50 +from nailgun.orchestrator.priority_serializers import\ + PriorityMultinodeSerializer60 from nailgun.db.sqlalchemy import models from nailgun import objects @@ -58,6 +66,22 @@ from nailgun.volumes import manager class OrchestratorSerializerTestBase(BaseIntegrationTest): """Class containts helpers.""" + def create_env(self, mode): + cluster = self.env.create( + cluster_kwargs={ + 'mode': mode, + 'net_provider': 'neutron'}, + nodes_kwargs=[{ + 'roles': ['controller'], + 'pending_addition': True}]) + + cluster_db = self.db.query(Cluster).get(cluster['id']) + objects.NodeCollection.prepare_for_deployment( + cluster_db.nodes) + self.db.flush() + + return cluster_db + def filter_by_role(self, nodes, role): return filter(lambda node: role in node['role'], nodes) @@ -90,6 +114,37 @@ class OrchestratorSerializerTestBase(BaseIntegrationTest): ''' return copy.deepcopy(data_to_copy) + def check_vmware_escaped_dollar_sign(self): + cluster_attrs = objects.Cluster.get_attributes( + self.cluster_db).editable + + cluster_attrs['common']['libvirt_type']['value'] = 'vcenter' + cluster_attrs['vcenter']['vc_user']['value'] = 'user$' + cluster_attrs['vcenter']['vc_password']['value'] = 'pass$word' + cluster_attrs['vcenter']['datastore_regex']['value'] = '^stack-[0-9]$' + cluster_attrs['storage']['vc_user']['value'] = 'user$' + cluster_attrs['storage']['vc_password']['value'] = 'pass$word' + + objects.Cluster.update_attributes( + self.cluster_db, {'editable': cluster_attrs}) + + result = self.serializer.get_common_attrs(self.cluster_db) + self.assertEqual( + result['vcenter']['vc_user'], + "user$$") + self.assertEqual( + result['vcenter']['vc_password'], + "pass$$word") + self.assertEqual( + result['vcenter']['datastore_regex'], + "^stack-[0-9]$$") + self.assertEqual( + result['storage']['vc_user'], + "user$$") + self.assertEqual( + result['storage']['vc_password'], + "pass$$word") + # TODO(awoodward): multinode deprecation: probably has duplicates class TestNovaOrchestratorSerializer(OrchestratorSerializerTestBase): @@ -1643,3 +1698,33 @@ class TestNSXOrchestratorSerializer(OrchestratorSerializerTestBase): self.assertIn('enable_metadata_network', l3_settings['dhcp_agent']) self.assertEqual(l3_settings['dhcp_agent']['enable_metadata_network'], True) + + +class TestDeploymentHASerializer60(OrchestratorSerializerTestBase): + + def setUp(self): + super(TestDeploymentHASerializer60, self).setUp() + self.cluster_db = self.create_env('ha_compact') + + @property + def serializer(self): + return DeploymentHASerializer60( + PriorityHASerializer60) + + def test_vmware_escaped_dollar_sign(self): + self.check_vmware_escaped_dollar_sign() + + +class TestDeploymentMultinodeSerializer60(OrchestratorSerializerTestBase): + + def setUp(self): + super(TestDeploymentMultinodeSerializer60, self).setUp() + self.cluster_db = self.create_env('multinode') + + @property + def serializer(self): + return DeploymentMultinodeSerializer60( + PriorityMultinodeSerializer60) + + def test_vmware_escaped_dollar_sign(self): + self.check_vmware_escaped_dollar_sign()