From 47cf2132a27f85cccf779f070badc3cebbc37a3c Mon Sep 17 00:00:00 2001 From: Tomas Sedovic Date: Thu, 3 May 2012 16:19:17 +0200 Subject: [PATCH] Connect cfn utils to the remote server The cfn_helper's `Metadata` class can now connect to the metadata server prodived it's URL is known and available. Engine will pass metadata server's URL via the User Data to the following file: /var/lib/cloud/data/cfn-metadata-server If the file doesn't exist or the server is unreachable, cfntools will read metadata from the `/var/lib/cloud/data/cfn-init-data` file as they did so far. Note that Engine dosen't currently know the metadata server's URL so it's not passing it to the instance yet. --- heat/cfntools/cfn_helper.py | 43 +++++++++++++++++++++++++++++++++---- heat/engine/instance.py | 10 +++++++-- heat/engine/parser.py | 3 ++- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/heat/cfntools/cfn_helper.py b/heat/cfntools/cfn_helper.py index 24bfbb9d..b35287ad 100644 --- a/heat/cfntools/cfn_helper.py +++ b/heat/cfntools/cfn_helper.py @@ -41,7 +41,8 @@ import rpmUtils.updates as rpmupdates import rpmUtils.miscutils as rpmutils import subprocess import sys - +from urllib2 import urlopen +from urlparse import urlparse, urlunparse def to_boolean(b): val = b.lower().strip() if isinstance(b, basestring) else b @@ -731,6 +732,8 @@ class ServicesHandler(object): else: self._monitor_services(handler, service_entries) +class MetadataServerConnectionError(Exception): + pass class Metadata(object): _metadata = None @@ -750,6 +753,35 @@ class Metadata(object): self._is_local_metadata = True self._metadata = None + + def metadata_server_url(self): + """ + Return the url to the metadata server. + """ + try: + f = open("/var/lib/cloud/data/cfn-metadata-server") + server_url = f.read() + f.close() + except IOError: + return None + + url_parts = list(urlparse(server_url)) + url_parts[2] = '/stacks/%s/resources/%s' % (self.stack, self.resource) + return urlunparse(url_parts) + + def remote_metadata(self): + """ + Connect to the metadata server and retreive the metadata from there. + """ + server_url = self.metadata_server_url() + if not server_url: + raise MetadataServerConnectionError() + + try: + return urlopen(server_url).read() + except: + raise MetadataServerConnectionError() + def retrieve(self, meta_str=None): """ Read the metadata from the given filename @@ -757,9 +789,12 @@ class Metadata(object): if meta_str: self._data = meta_str else: - f = open("/var/lib/cloud/data/cfn-init-data") - self._data = f.read() - f.close() + try: + self._data = self.remote_metadata() + except MetadataServerConnectionError: + f = open("/var/lib/cloud/data/cfn-init-data") + self._data = f.read() + f.close() if isinstance(self._data, str): self._metadata = json.loads(self._data) diff --git a/heat/engine/instance.py b/heat/engine/instance.py index bd3fc8db..951a38ed 100644 --- a/heat/engine/instance.py +++ b/heat/engine/instance.py @@ -108,13 +108,19 @@ class Instance(Resource): filename='cfn-init-data') mime_blob.attach(msg) + if self.stack.metadata_server: + msg = MIMEText(self.stack.metadata_server, + _subtype='x-cfninitdata') + msg.add_header('Content-Disposition', 'attachment', + filename='cfn-metadata-server') + mime_blob.attach(msg) + msg = MIMEText(userdata, _subtype='x-shellscript') msg.add_header('Content-Disposition', 'attachment', filename='startup') mime_blob.attach(msg) self.mime_string = mime_blob.as_string() - - return self.mime_string + return self.mime_string def create(self): def _null_callback(p, n, out): diff --git a/heat/engine/parser.py b/heat/engine/parser.py index 4f30c6c2..a1370317 100644 --- a/heat/engine/parser.py +++ b/heat/engine/parser.py @@ -48,7 +48,8 @@ class Stack(object): self.doc = None self.name = stack_name self.parsed_template_id = 0 - self.metadata_server = 'http://10.0.0.1' + # TODO(shadower) load this from a config file + #self.metadata_server = 'http://10.0.0.1' self.parms['AWS::StackName'] = {"Description": "AWS StackName", "Type": "String", -- 2.45.2