]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Refactor compute resources to use nova_utils
authorRandall Burt <randall.burt@rackspace.com>
Wed, 7 Aug 2013 00:48:02 +0000 (19:48 -0500)
committerRandall Burt <randall.burt@rackspace.com>
Wed, 7 Aug 2013 22:34:56 +0000 (17:34 -0500)
Change-Id: I4a03a8062998c8f713ada47d0d86f2ace52cc253

heat/engine/resources/instance.py
heat/engine/resources/rackspace/cloud_server.py
heat/tests/test_engine_service.py
heat/tests/test_instance.py
heat/tests/test_instance_network.py
heat/tests/test_nokey.py
heat/tests/test_server_tags.py

index e505f086d21212908178cc86ac509757e096b986..54ee7d4b9c1a5567e408841e9e6ce45b60cf7d3f 100644 (file)
 #    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,
index 1e9911bdb66efc7d187b9cdc3d43ef15b8db77df..0faf64d4f20118e3f77b1e4440759ff3f68d94f5 100644 (file)
@@ -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}]
index 069ed1fe6b4ba03eca62f30ec2c7df98de019d37..a7510d56fa8eca1a4f42e9172a5ebddea8190627 100644 (file)
@@ -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'),
index b91552b007630fd6dea4b5884971bbf41d74d6e8..78ad46141ad0749433a6e572d09126f6e3c44b06 100644 (file)
@@ -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',
index 19f31405a7eb8b64943ad9170ffa7fc9c40b044d..41457eaf9fb7273f82c49ef78062d15be441d559 100644 (file)
@@ -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',
index a5d4419c45a31f3a905af3e4abde795ee496789d..6b7e9b926471be76c1f76ce13d0b720cc6c8eef2 100644 (file)
@@ -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,
index 091d53f98ac32d58f69852ddf290c984c70a710a..564bc587bb67d261dcbf87da6705f42b63656959 100644 (file)
@@ -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',