diff --git a/heat/engine/resources/server.py b/heat/engine/resources/server.py index d281fd424..632c5dbc4 100644 --- a/heat/engine/resources/server.py +++ b/heat/engine/resources/server.py @@ -20,6 +20,7 @@ from heat.common import exception from heat.engine import clients from heat.engine import scheduler from heat.engine.resources import nova_utils +from heat.engine.resources.software_config import software_config as sc from heat.engine import constraints from heat.engine import properties from heat.engine import resource @@ -67,6 +68,12 @@ class Server(resource.Resource): 'uuid', 'network', 'fixed_ip', 'port', ) + _SOFTWARE_CONFIG_FORMATS = ( + HEAT_CFNTOOLS, RAW + ) = ( + 'HEAT_CFNTOOLS', 'RAW' + ) + properties_schema = { NAME: properties.Schema( properties.Schema.STRING, @@ -217,9 +224,9 @@ class Server(resource.Resource): 'HEAT_CFNTOOLS, the user_data is bundled as part of the ' 'heat-cfntools cloud-init boot configuration data. For RAW, ' 'the user_data is passed to Nova unmodified.'), - default='HEAT_CFNTOOLS', + default=HEAT_CFNTOOLS, constraints=[ - constraints.AllowedValues(['HEAT_CFNTOOLS', 'RAW']), + constraints.AllowedValues(_SOFTWARE_CONFIG_FORMATS), ] ), USER_DATA: properties.Schema( @@ -300,13 +307,26 @@ class Server(resource.Resource): # This method is overridden by the derived CloudServer resource return self.properties.get(self.KEY_NAME) + def user_data_raw(self): + return self.properties.get(self.USER_DATA_FORMAT) == 'RAW' + def handle_create(self): security_groups = self.properties.get(self.SECURITY_GROUPS) user_data_format = self.properties.get(self.USER_DATA_FORMAT) + ud_content = self.properties.get(self.USER_DATA) + if self.user_data_raw() and uuidutils.is_uuid_like(ud_content): + # attempt to load the userdata from software config + try: + ud_content = sc.SoftwareConfig.get_software_config( + self.heat(), ud_content) + except exception.SoftwareConfigMissing: + # no config was found, so do not modify the user_data + pass + userdata = nova_utils.build_userdata( self, - self.properties.get(self.USER_DATA), + ud_content, instance_user=self.properties[self.ADMIN_USER], user_data_format=user_data_format) diff --git a/heat/tests/test_server.py b/heat/tests/test_server.py index a4a1ef2f9..13439f8a5 100644 --- a/heat/tests/test_server.py +++ b/heat/tests/test_server.py @@ -28,6 +28,7 @@ from heat.engine import scheduler from heat.engine.resources import image from heat.engine.resources import nova_utils from heat.engine.resources import server as servers +from heat.engine.resources.software_config import software_config as sc from heat.openstack.common import uuidutils from heat.openstack.common.gettextutils import _ from heat.tests.common import HeatTestCase @@ -357,6 +358,93 @@ class ServersTest(HeatTestCase): meta=None, nics=None, availability_zone=None, block_device_mapping=None, config_drive=None, disk_config=None, reservation_id=None, files={}, + admin_pass=None).AndReturn( + return_server) + + self.m.ReplayAll() + scheduler.TaskRunner(server.create)() + self.m.VerifyAll() + + def test_server_create_raw_config_userdata(self): + return_server = self.fc.servers.list()[1] + stack_name = 'raw_userdata_s' + (t, stack) = self._setup_test_stack(stack_name) + + t['Resources']['WebServer']['Properties']['user_data_format'] = \ + 'RAW' + t['Resources']['WebServer']['Properties']['user_data'] = \ + '8c813873-f6ee-4809-8eec-959ef39acb55' + + server = servers.Server('WebServer', + t['Resources']['WebServer'], stack) + + self.m.StubOutWithMock(server, 'nova') + self.m.StubOutWithMock(server, 'heat') + self.m.StubOutWithMock(sc.SoftwareConfig, 'get_software_config') + server.heat().AndReturn(None) + sc.SoftwareConfig.get_software_config( + None, '8c813873-f6ee-4809-8eec-959ef39acb55').AndReturn( + 'wordpress from config') + + server.nova().MultipleTimes().AndReturn(self.fc) + self.m.StubOutWithMock(clients.OpenStackClients, 'nova') + clients.OpenStackClients.nova().MultipleTimes().AndReturn(self.fc) + + server.t = server.stack.resolve_runtime_data(server.t) + + self.m.StubOutWithMock(self.fc.servers, 'create') + self.fc.servers.create( + image=744, flavor=3, key_name='test', + name=utils.PhysName(stack_name, server.name), + security_groups=[], + userdata='wordpress from config', scheduler_hints=None, + meta=None, nics=None, availability_zone=None, + block_device_mapping=None, config_drive=None, + disk_config=None, reservation_id=None, files={}, + admin_pass=None).AndReturn( + return_server) + + self.m.ReplayAll() + scheduler.TaskRunner(server.create)() + self.m.VerifyAll() + + def test_server_create_raw_config_userdata_None(self): + return_server = self.fc.servers.list()[1] + stack_name = 'raw_userdata_s' + (t, stack) = self._setup_test_stack(stack_name) + + sc_id = '8c813873-f6ee-4809-8eec-959ef39acb55' + t['Resources']['WebServer']['Properties']['user_data_format'] = \ + 'RAW' + t['Resources']['WebServer']['Properties']['user_data'] = sc_id + + server = servers.Server('WebServer', + t['Resources']['WebServer'], stack) + + self.m.StubOutWithMock(server, 'nova') + self.m.StubOutWithMock(server, 'heat') + self.m.StubOutWithMock(sc.SoftwareConfig, 'get_software_config') + server.heat().AndReturn(None) + sc.SoftwareConfig.get_software_config( + None, sc_id).AndRaise(exception.SoftwareConfigMissing( + software_config_id=sc_id)) + + server.nova().MultipleTimes().AndReturn(self.fc) + self.m.StubOutWithMock(clients.OpenStackClients, 'nova') + clients.OpenStackClients.nova().MultipleTimes().AndReturn(self.fc) + + server.t = server.stack.resolve_runtime_data(server.t) + + self.m.StubOutWithMock(self.fc.servers, 'create') + self.fc.servers.create( + image=744, flavor=3, key_name='test', + name=utils.PhysName(stack_name, server.name), + security_groups=[], + userdata=sc_id, + scheduler_hints=None, meta=None, + nics=None, availability_zone=None, + block_device_mapping=None, config_drive=None, + disk_config=None, reservation_id=None, files={}, admin_pass=None).AndReturn(return_server) self.m.ReplayAll()