summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cloudinit/UserDataHandler.py51
-rw-r--r--doc/examples/cloud-config-archive.txt16
2 files changed, 61 insertions, 6 deletions
diff --git a/cloudinit/UserDataHandler.py b/cloudinit/UserDataHandler.py
index feb67149..fbb000fc 100644
--- a/cloudinit/UserDataHandler.py
+++ b/cloudinit/UserDataHandler.py
@@ -19,7 +19,9 @@ import email
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
-
+from email.mime.base import MIMEBase
+from email import encoders
+import yaml
starts_with_mappings={
'#include' : 'text/x-include-url',
@@ -27,7 +29,8 @@ starts_with_mappings={
'#cloud-config' : 'text/cloud-config',
'#upstart-job' : 'text/upstart-job',
'#part-handler' : 'text/part-handler',
- '#cloud-boothook' : 'text/cloud-boothook'
+ '#cloud-boothook' : 'text/cloud-boothook',
+ '#cloud-config-archive' : 'text/cloud-config-archive',
}
# if 'str' is compressed return decompressed otherwise return it
@@ -43,12 +46,47 @@ def decomp_str(str):
def do_include(str,parts):
import urllib
# is just a list of urls, one per line
+ # also support '#include <url here>'
for line in str.splitlines():
if line == "#include": continue
+ if line.startswith("#include"):
+ line = line[len("#include"):].lstrip()
if line.startswith("#"): continue
content = urllib.urlopen(line).read()
process_includes(email.message_from_string(decomp_str(content)),parts)
+def explode_cc_archive(archive,parts):
+ for ent in yaml.load(archive):
+ # ent can be one of:
+ # dict { 'filename' : 'value' , 'content' : 'value', 'type' : 'value' }
+ # filename and type not be present
+ # or
+ # scalar(payload)
+ filename = 'part-%03d' % len(parts['content'])
+ def_type = "text/cloud-config"
+ if isinstance(ent,str):
+ content = ent
+ mtype = type_from_startswith(content,def_type)
+ else:
+ content = ent.get('content', '')
+ filename = ent.get('filename', filename)
+ mtype = ent.get('type', None)
+ if mtype == None:
+ mtype = type_from_startswith(payload,def_type)
+
+ print "adding %s,%s" % (filename, mtype)
+ parts['content'].append(content)
+ parts['names'].append(filename)
+ parts['types'].append(mtype)
+
+def type_from_startswith(payload, default=None):
+ # slist is sorted longest first
+ slist = sorted(starts_with_mappings.keys(), key=lambda e: 0-len(e))
+ for sstr in slist:
+ if payload.startswith(sstr):
+ return(starts_with_mappings[sstr])
+ return default
+
def process_includes(msg,parts):
# parts is a dictionary of arrays
# parts['content']
@@ -67,10 +105,7 @@ def process_includes(msg,parts):
ctype = None
ctype_orig = part.get_content_type()
if ctype_orig == "text/plain":
- for sstr, gtype in starts_with_mappings.items():
- if payload.startswith(sstr):
- ctype = gtype
- break
+ ctype = type_from_startswith(payload)
if ctype is None:
ctype = ctype_orig
@@ -79,6 +114,10 @@ def process_includes(msg,parts):
do_include(payload,parts)
continue
+ if ctype == "text/cloud-config-archive":
+ explode_cc_archive(payload,parts)
+ continue
+
filename = part.get_filename()
if not filename:
filename = 'part-%03d' % len(parts['content'])
diff --git a/doc/examples/cloud-config-archive.txt b/doc/examples/cloud-config-archive.txt
new file mode 100644
index 00000000..23b1024c
--- /dev/null
+++ b/doc/examples/cloud-config-archive.txt
@@ -0,0 +1,16 @@
+#cloud-config-archive
+- type: foo/wark
+ filename: bar
+ content: |
+ This is my payload
+ hello
+- this is also payload
+- |
+ multi line payload
+ here
+-
+ type: text/upstart-job
+ filename: my-upstart.conf
+ content: |
+ whats this, yo?
+