diff --git a/contrib/rackspace/rackspace/resources/cloud_server.py b/contrib/rackspace/rackspace/resources/cloud_server.py index a1b467a079..731c934130 100644 --- a/contrib/rackspace/rackspace/resources/cloud_server.py +++ b/contrib/rackspace/rackspace/resources/cloud_server.py @@ -19,6 +19,7 @@ import paramiko from heat.common import exception from heat.db.sqlalchemy import api as db_api +from heat.engine import properties from heat.engine.resources import nova_utils from heat.engine.resources import server from heat.openstack.common.gettextutils import _ @@ -113,6 +114,20 @@ bash -x /var/lib/cloud/data/cfn-userdata > /root/cfn-userdata.log 2>&1 || RC_STATUS_FAILED = 'FAILED' RC_STATUS_UNPROCESSABLE = 'UNPROCESSABLE' + # Admin Pass Properties + SAVE_ADMIN_PASS = 'save_admin_pass' + + properties_schema = copy.deepcopy(server.Server.properties_schema) + properties_schema.update( + { + SAVE_ADMIN_PASS: properties.Schema( + properties.Schema.BOOLEAN, + _('True if the system should remember the admin password; ' + 'False otherwise.'), + default=False + ), + } + ) attributes_schema = copy.deepcopy(server.Server.attributes_schema) attributes_schema.update( { @@ -470,7 +485,8 @@ bash -x /var/lib/cloud/data/cfn-userdata > /root/cfn-userdata.log 2>&1 || # Server will not have an adminPass attribute if Nova's # "enable_instance_password" config option is turned off - if hasattr(server, 'adminPass') and server.adminPass: + if (self.properties.get(self.SAVE_ADMIN_PASS) and + hasattr(server, 'adminPass') and server.adminPass): db_api.resource_data_set(self, self.ADMIN_PASS, server.adminPass, redact=True) diff --git a/contrib/rackspace/rackspace/tests/test_rackspace_cloud_server.py b/contrib/rackspace/rackspace/tests/test_rackspace_cloud_server.py index 3d838610a0..31c1d12a71 100644 --- a/contrib/rackspace/rackspace/tests/test_rackspace_cloud_server.py +++ b/contrib/rackspace/rackspace/tests/test_rackspace_cloud_server.py @@ -959,6 +959,7 @@ class CloudServersTest(HeatTestCase): stack_name = 'admin_pass_s' (t, stack) = self._setup_test_stack(stack_name) + t['Resources']['WebServer']['Properties']['save_admin_pass'] = True server = cloud_server.CloudServer('WebServer', t['Resources']['WebServer'], stack) server._sftp_files = mock.Mock() @@ -973,6 +974,58 @@ class CloudServersTest(HeatTestCase): 'autogenerated', redact=True) self.assertIn(expected_call, mock_data_set.call_args_list) + @mock.patch.object(clients.OpenStackClients, 'nova') + @mock.patch.object(cloud_server.db_api, 'resource_data_set') + def test_create_save_admin_pass_is_false(self, + mock_data_set, + mock_nova): + self._mock_metadata_os_distro() + return_server = self.fc.servers.list()[1] + return_server.adminPass = 'autogenerated' + stack_name = 'admin_pass_s' + (t, stack) = self._setup_test_stack(stack_name) + + t['Resources']['WebServer']['Properties']['save_admin_pass'] = False + server = cloud_server.CloudServer('WebServer', + t['Resources']['WebServer'], stack) + server._sftp_files = mock.Mock() + server._run_ssh_command = mock.Mock(return_value=0) + + mock_nova.return_value = self.fc + server.t = server.stack.resolve_runtime_data(server.t) + self.fc.servers.create = mock.Mock(return_value=return_server) + + scheduler.TaskRunner(server.create)() + expected_call = mock.call(mock.ANY, server.ADMIN_PASS, + mock.ANY, mock.ANY) + self.assertNotIn(expected_call, mock_data_set.call_args_list) + + @mock.patch.object(clients.OpenStackClients, 'nova') + @mock.patch.object(cloud_server.db_api, 'resource_data_set') + def test_create_save_admin_pass_defaults_to_false(self, + mock_data_set, + mock_nova): + self._mock_metadata_os_distro() + return_server = self.fc.servers.list()[1] + return_server.adminPass = 'autogenerated' + stack_name = 'admin_pass_s' + (t, stack) = self._setup_test_stack(stack_name) + + t['Resources']['WebServer']['Properties']['save_admin_pass'] = None + server = cloud_server.CloudServer('WebServer', + t['Resources']['WebServer'], stack) + server._sftp_files = mock.Mock() + server._run_ssh_command = mock.Mock(return_value=0) + + mock_nova.return_value = self.fc + server.t = server.stack.resolve_runtime_data(server.t) + self.fc.servers.create = mock.Mock(return_value=return_server) + + scheduler.TaskRunner(server.create)() + expected_call = mock.call(mock.ANY, server.ADMIN_PASS, + mock.ANY, mock.ANY) + self.assertNotIn(expected_call, mock_data_set.call_args_list) + @mock.patch.object(clients.OpenStackClients, 'nova') @mock.patch.object(cloud_server.db_api, 'resource_data_set') def test_create_without_adminPass_attribute(self,