From: Randall Burt Date: Wed, 7 Aug 2013 00:48:02 +0000 (-0500) Subject: Refactor compute resources to use nova_utils X-Git-Tag: 2014.1~251^2 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=ac1e0a030d5abd7c69a1f79f35aab36c31fa4b6d;p=openstack-build%2Fheat-build.git Refactor compute resources to use nova_utils Change-Id: I4a03a8062998c8f713ada47d0d86f2ace52cc253 --- diff --git a/heat/engine/resources/instance.py b/heat/engine/resources/instance.py index e505f086..54ee7d4b 100644 --- a/heat/engine/resources/instance.py +++ b/heat/engine/resources/instance.py @@ -13,19 +13,11 @@ # License for the specific language governing permissions and limitations # under the License. -from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText -import json -import os -import pkgutil -from urlparse import urlparse - -from oslo.config import cfg - from heat.engine import signal_responder from heat.engine import clients from heat.engine import resource from heat.engine import scheduler +from heat.engine.resources import nova_utils from heat.engine.resources import volume from heat.common import exception @@ -33,7 +25,6 @@ from heat.engine.resources.network_interface import NetworkInterface from heat.openstack.common.gettextutils import _ from heat.openstack.common import log as logging -from heat.openstack.common import uuidutils logger = logging.getLogger(__name__) @@ -198,69 +189,6 @@ class Instance(resource.Resource): logger.info('%s._resolve_attribute(%s) == %s' % (self.name, name, res)) return unicode(res) if res else None - def _build_userdata(self, userdata): - if not self.mime_string: - # Build mime multipart data blob for cloudinit userdata - - def make_subpart(content, filename, subtype=None): - if subtype is None: - subtype = os.path.splitext(filename)[0] - msg = MIMEText(content, _subtype=subtype) - msg.add_header('Content-Disposition', 'attachment', - filename=filename) - return msg - - def read_cloudinit_file(fn): - data = pkgutil.get_data('heat', 'cloudinit/%s' % fn) - data = data.replace('@INSTANCE_USER@', - cfg.CONF.instance_user) - return data - - attachments = [(read_cloudinit_file('config'), 'cloud-config'), - (read_cloudinit_file('boothook.sh'), 'boothook.sh', - 'cloud-boothook'), - (read_cloudinit_file('part_handler.py'), - 'part-handler.py'), - (userdata, 'cfn-userdata', 'x-cfninitdata'), - (read_cloudinit_file('loguserdata.py'), - 'loguserdata.py', 'x-shellscript')] - - if 'Metadata' in self.t: - attachments.append((json.dumps(self.metadata), - 'cfn-init-data', 'x-cfninitdata')) - - attachments.append((cfg.CONF.heat_watch_server_url, - 'cfn-watch-server', 'x-cfninitdata')) - - attachments.append((cfg.CONF.heat_metadata_server_url, - 'cfn-metadata-server', 'x-cfninitdata')) - - # Create a boto config which the cfntools on the host use to know - # where the cfn and cw API's are to be accessed - cfn_url = urlparse(cfg.CONF.heat_metadata_server_url) - cw_url = urlparse(cfg.CONF.heat_watch_server_url) - is_secure = cfg.CONF.instance_connection_is_secure - vcerts = cfg.CONF.instance_connection_https_validate_certificates - boto_cfg = "\n".join(["[Boto]", - "debug = 0", - "is_secure = %s" % is_secure, - "https_validate_certificates = %s" % vcerts, - "cfn_region_name = heat", - "cfn_region_endpoint = %s" % - cfn_url.hostname, - "cloudwatch_region_name = heat", - "cloudwatch_region_endpoint = %s" % - cw_url.hostname]) - attachments.append((boto_cfg, - 'cfn-boto-cfg', 'x-cfninitdata')) - - subparts = [make_subpart(*args) for args in attachments] - mime_blob = MIMEMultipart(_subparts=subparts) - - self.mime_string = mime_blob.as_string() - - return self.mime_string - def _build_nics(self, network_interfaces, subnet_id=None): nics = None @@ -308,22 +236,10 @@ class Instance(resource.Resource): security_groups = None return security_groups - def _get_flavor_id(self, flavor): - flavor_id = None - flavor_list = self.nova().flavors.list() - for o in flavor_list: - if o.name == flavor: - flavor_id = o.id - break - if flavor_id is None: - raise exception.FlavorMissing(flavor_id=flavor) - return flavor_id - - def _get_keypair(self, key_name): - for keypair in self.nova().keypairs.list(): - if keypair.name == key_name: - return keypair - raise exception.UserKeyPairMissing(key_name=key_name) + def get_mime_string(self, userdata): + if not self.mime_string: + self.mime_string = nova_utils.build_userdata(self, userdata) + return self.mime_string def handle_create(self): security_groups = self._get_security_groups() @@ -335,13 +251,13 @@ class Instance(resource.Resource): key_name = self.properties['KeyName'] if key_name: # confirm keypair exists - self._get_keypair(key_name) + nova_utils.get_keypair(self.nova(), key_name) image_name = self.properties['ImageId'] - image_id = self._get_image_id(image_name) + image_id = nova_utils.get_image_id(self.nova(), image_name) - flavor_id = self._get_flavor_id(flavor) + flavor_id = nova_utils.get_flavor_id(self.nova(), flavor) tags = {} if self.properties['Tags']: @@ -359,8 +275,6 @@ class Instance(resource.Resource): nics = self._build_nics(self.properties['NetworkInterfaces'], subnet_id=self.properties['SubnetId']) - - server_userdata = self._build_userdata(userdata) server = None try: server = self.nova().servers.create( @@ -369,7 +283,7 @@ class Instance(resource.Resource): flavor=flavor_id, key_name=key_name, security_groups=security_groups, - userdata=server_userdata, + userdata=self.get_mime_string(userdata), meta=tags, scheduler_hints=scheduler_hints, nics=nics, @@ -438,7 +352,7 @@ class Instance(resource.Resource): self.metadata = tmpl_diff['Metadata'] if 'InstanceType' in prop_diff: flavor = prop_diff['InstanceType'] - flavor_id = self._get_flavor_id(flavor) + flavor_id = nova_utils.get_flavor_id(self.nova(), flavor) server = self.nova().servers.get(self.resource_id) server.resize(flavor_id) scheduler.TaskRunner(self._check_resize, server, flavor)() @@ -490,10 +404,7 @@ class Instance(resource.Resource): 'NetworkInterfaces') # make sure the image exists. - image_identifier = self.properties['ImageId'] - self._get_image_id(image_identifier) - - return + nova_utils.get_image_id(self.nova(), self.properties['ImageId']) def _delete_server(self, server): ''' @@ -539,34 +450,6 @@ class Instance(resource.Resource): self.resource_id = None - def _get_image_id(self, image_identifier): - image_id = None - if uuidutils.is_uuid_like(image_identifier): - try: - image_id = self.nova().images.get(image_identifier).id - except clients.novaclient.exceptions.NotFound: - logger.info("Image %s was not found in glance" - % image_identifier) - raise exception.ImageNotFound(image_name=image_identifier) - else: - try: - image_list = self.nova().images.list() - except clients.novaclient.exceptions.ClientException as ex: - raise exception.ServerError(message=str(ex)) - image_names = dict( - (o.id, o.name) - for o in image_list if o.name == image_identifier) - if len(image_names) == 0: - logger.info("Image %s was not found in glance" % - image_identifier) - raise exception.ImageNotFound(image_name=image_identifier) - elif len(image_names) > 1: - logger.info("Mulitple images %s were found in glance with name" - % image_identifier) - raise exception.NoUniqueImageFound(image_name=image_identifier) - image_id = image_names.popitem()[0] - return image_id - def handle_suspend(self): ''' Suspend an instance - note we do not wait for the SUSPENDED state, diff --git a/heat/engine/resources/rackspace/cloud_server.py b/heat/engine/resources/rackspace/cloud_server.py index 1e9911bd..0faf64d4 100644 --- a/heat/engine/resources/rackspace/cloud_server.py +++ b/heat/engine/resources/rackspace/cloud_server.py @@ -21,6 +21,7 @@ from heat.common import exception from heat.openstack.common import log as logging from heat.engine import scheduler from heat.engine.resources import instance +from heat.engine.resources import nova_utils from heat.engine.resources.rackspace import rackspace_resource from heat.db.sqlalchemy import api as db_api @@ -306,7 +307,8 @@ zypper --non-interactive in cloud-init python-boto python-pip gcc python-devel public_keys = [rsa.publickey().exportKey('OpenSSH')] if self.properties.get('key_name'): key_name = self.properties['key_name'] - public_keys.append(self._get_keypair(key_name).public_key) + public_keys.append(nova_utils.get_keypair(self.nova(), + key_name).public_key) personality_files = { "/root/.ssh/authorized_keys": '\n'.join(public_keys)} @@ -366,7 +368,7 @@ zypper --non-interactive in cloud-init python-boto python-pip gcc python-devel if self.has_userdata: # Create heat-script and userdata files on server raw_userdata = self.properties['user_data'] or '' - userdata = self._build_userdata(raw_userdata) + userdata = nova_utils.build_userdata(self, raw_userdata) files = [{'path': "/tmp/userdata", 'data': userdata}, {'path': "/root/heat-script.sh", 'data': self.script}] diff --git a/heat/tests/test_engine_service.py b/heat/tests/test_engine_service.py index 069ed1fe..a7510d56 100644 --- a/heat/tests/test_engine_service.py +++ b/heat/tests/test_engine_service.py @@ -33,6 +33,7 @@ from heat.engine import parser from heat.engine import service from heat.engine.properties import Properties from heat.engine.resources import instance as instances +from heat.engine.resources import nova_utils from heat.engine import resource as rsrs from heat.engine import watchrule from heat.openstack.common import threadgroup @@ -142,7 +143,9 @@ def setup_mocks(mocks, stack): instances.Instance.nova().MultipleTimes().AndReturn(fc) instance = stack.resources['WebServer'] - server_userdata = instance._build_userdata(instance.properties['UserData']) + user_data = instance.properties['UserData'] + server_userdata = nova_utils.build_userdata(instance, user_data) + instance.mime_string = server_userdata mocks.StubOutWithMock(fc.servers, 'create') fc.servers.create(image=744, flavor=3, key_name='test', name=utils.PhysName(stack.name, 'WebServer'), diff --git a/heat/tests/test_instance.py b/heat/tests/test_instance.py index b91552b0..78ad4614 100644 --- a/heat/tests/test_instance.py +++ b/heat/tests/test_instance.py @@ -18,12 +18,13 @@ import mox from heat.engine import environment from heat.tests.v1_1 import fakes -from heat.engine.resources import instance as instances from heat.common import exception from heat.common import template_format from heat.engine import parser from heat.engine import resource from heat.engine import scheduler +from heat.engine.resources import instance as instances +from heat.engine.resources import nova_utils from heat.openstack.common import uuidutils from heat.tests.common import HeatTestCase from heat.tests import utils @@ -88,8 +89,10 @@ class InstancesTest(HeatTestCase): instance.t = instance.stack.resolve_runtime_data(instance.t) # need to resolve the template functions - server_userdata = instance._build_userdata( + server_userdata = nova_utils.build_userdata( + instance, instance.t['Properties']['UserData']) + instance.mime_string = server_userdata self.m.StubOutWithMock(self.fc.servers, 'create') self.fc.servers.create( image=1, flavor=1, key_name='test', diff --git a/heat/tests/test_instance_network.py b/heat/tests/test_instance_network.py index 19f31405..41457eaf 100644 --- a/heat/tests/test_instance_network.py +++ b/heat/tests/test_instance_network.py @@ -17,6 +17,7 @@ from heat.engine import environment from heat.tests.v1_1 import fakes from heat.engine.resources import instance as instances from heat.engine.resources import network_interface as network_interfaces +from heat.engine.resources import nova_utils from heat.common import template_format from heat.engine import parser from heat.engine import scheduler @@ -175,9 +176,10 @@ class instancesTest(HeatTestCase): instance.t = instance.stack.resolve_runtime_data(instance.t) # need to resolve the template functions - server_userdata = instance._build_userdata( + server_userdata = nova_utils.build_userdata( + instance, instance.t['Properties']['UserData']) - + instance.mime_string = server_userdata self.m.StubOutWithMock(self.fc.servers, 'create') self.fc.servers.create( image=1, flavor=3, key_name='test', @@ -222,8 +224,10 @@ class instancesTest(HeatTestCase): instance.t = instance.stack.resolve_runtime_data(instance.t) # need to resolve the template functions - server_userdata = instance._build_userdata( + server_userdata = nova_utils.build_userdata( + instance, instance.t['Properties']['UserData']) + instance.mime_string = server_userdata self.m.StubOutWithMock(self.fc.servers, 'create') self.fc.servers.create( image=1, flavor=3, key_name='test', diff --git a/heat/tests/test_nokey.py b/heat/tests/test_nokey.py index a5d4419c..6b7e9b92 100644 --- a/heat/tests/test_nokey.py +++ b/heat/tests/test_nokey.py @@ -14,6 +14,7 @@ from heat.tests.v1_1 import fakes from heat.engine.resources import instance as instances +from heat.engine.resources import nova_utils from heat.common import template_format from heat.engine import scheduler from heat.tests.common import HeatTestCase @@ -65,8 +66,10 @@ class nokeyTest(HeatTestCase): instance.t = instance.stack.resolve_runtime_data(instance.t) # need to resolve the template functions - server_userdata = instance._build_userdata( + server_userdata = nova_utils.build_userdata( + instance, instance.t['Properties']['UserData']) + instance.mime_string = server_userdata self.m.StubOutWithMock(self.fc.servers, 'create') self.fc.servers.create( image=1, flavor=1, key_name=None, diff --git a/heat/tests/test_server_tags.py b/heat/tests/test_server_tags.py index 091d53f9..564bc587 100644 --- a/heat/tests/test_server_tags.py +++ b/heat/tests/test_server_tags.py @@ -15,8 +15,9 @@ import mox from heat.engine import environment from heat.tests.v1_1 import fakes -from heat.engine.resources import instance as instances from heat.engine.resources import autoscaling +from heat.engine.resources import instance as instances +from heat.engine.resources import nova_utils from heat.common import template_format from heat.engine import parser from heat.engine import scheduler @@ -111,8 +112,10 @@ class ServerTagsTest(HeatTestCase): instance.t = instance.stack.resolve_runtime_data(instance.t) # need to resolve the template functions - server_userdata = instance._build_userdata( + server_userdata = nova_utils.build_userdata( + instance, instance.t['Properties']['UserData']) + instance.mime_string = server_userdata self.m.StubOutWithMock(self.fc.servers, 'create') self.fc.servers.create( image=1, flavor=1, key_name='test',