add cloud-config-archive input type.

cloud-config-archive is a yaml formated document where the top
level should contain an array.  Each entry in the array can be one of
- dict { 'filename' : 'value' , 'content' : 'value', 'type' : 'value' }
   filename and type may not be present
- scalar(content)

if filename and type are not present, they are attempted to be guessed.
This commit is contained in:
Scott Moser
2011-01-19 17:32:52 -05:00
parent b31bf2cd2a
commit 778716f3eb
2 changed files with 61 additions and 6 deletions

View File

@@ -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'])

View File

@@ -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?