22
22
from email.mime.base import MIMEBase
23
23
from email import encoders
26
import cloudinit.util as util
26
29
starts_with_mappings={
27
30
'#include' : 'text/x-include-url',
31
'#include-once' : 'text/x-include-once-url',
28
32
'#!' : 'text/x-shellscript',
29
33
'#cloud-config' : 'text/cloud-config',
30
34
'#upstart-job' : 'text/upstart-job',
46
50
def do_include(str,parts):
48
53
# is just a list of urls, one per line
49
54
# also support '#include <url here>'
50
56
for line in str.splitlines():
51
57
if line == "#include": continue
52
if line.startswith("#include"):
58
if line == "#include-once":
61
if line.startswith("#include-once"):
62
line = line[len("#include-once"):].lstrip()
64
elif line.startswith("#include"):
53
65
line = line[len("#include"):].lstrip()
54
66
if line.startswith("#"): continue
55
content = urllib.urlopen(line).read()
68
# urls cannot not have leading or trailing white space
70
msum.update(line.strip())
71
includeonce_filename = "%s/urlcache/%s" % (
72
cloudinit.get_ipath_cur("data"), msum.hexdigest())
74
if includeonce and os.path.isfile(includeonce_filename):
75
with open(includeonce_filename, "r") as fp:
78
content = urllib.urlopen(line).read()
80
util.write_file(includeonce_filename, content, mode=0600)
81
except Exception as e:
56
84
process_includes(email.message_from_string(decomp_str(content)),parts)
58
87
def explode_cc_archive(archive,parts):
59
88
for ent in yaml.load(archive):
60
89
# ent can be one of:
75
104
mtype = type_from_startswith(payload,def_type)
77
print "adding %s,%s" % (filename, mtype)
78
106
parts['content'].append(content)
79
107
parts['names'].append(filename)
80
108
parts['types'].append(mtype)
114
142
do_include(payload,parts)
145
if ctype == 'text/x-include-once-url':
146
do_include(payload,parts)
117
149
if ctype == "text/cloud-config-archive":
118
150
explode_cc_archive(payload,parts)
158
190
process_includes(email.message_from_string(decomp_str(data)),parts)
159
191
return(parts2mime(parts))
161
# callbacks is a dictionary with:
162
# { 'content-type': handler(data,content_type,filename,payload) }
163
def walk_userdata(str, callbacks, data = None):
193
# callback is a function that will be called with (data, content_type, filename, payload)
194
def walk_userdata(istr, callback, data = None):
165
for part in email.message_from_string(str).walk():
196
for part in email.message_from_string(istr).walk():
166
197
# multipart/* are just containers
167
198
if part.get_content_maintype() == 'multipart':
176
207
filename = 'part-%03d' % partnum
178
if callbacks.has_key(ctype):
179
callbacks[ctype](data,ctype,filename,part.get_payload())
209
callback(data, ctype, filename, part.get_payload())
181
211
partnum = partnum+1