Adjust the decoding of the files that are given so that a canonicalize

happens first, which will examine the incoming encoding, and decide the
neccasary decoding types needed to get the final resultant string and
then use these normalized decoding types to actually do the final decode.

Also change the name of the config key that is looked up to 'write_files'
since 'files' is pretty generic and could have clashes with other modules.

Add an example that shows how to use this in the different encoding formats
that are supported.
This commit is contained in:
Joshua Harlow
2012-07-11 11:20:24 -07:00
parent 04a4817dc8
commit 3fdc05b28a
2 changed files with 73 additions and 8 deletions

View File

@@ -25,10 +25,11 @@ from cloudinit.settings import PER_INSTANCE
frequency = PER_INSTANCE
DEFAULT_PERMS = 0644
UNKNOWN_ENC = 'text/plain'
def handle(name, cfg, _cloud, log, _args):
files = cfg.get('files')
files = cfg.get('write_files')
if not files:
log.debug(("Skipping module named %s,"
" no/empty 'files' key in configuration"), name)
@@ -36,6 +37,29 @@ def handle(name, cfg, _cloud, log, _args):
write_files(name, files, log)
def canonicalize_decoding(enc):
if not enc:
enc = ''
enc = enc.lower().strip()
# Translate to a mime-type (or set of) that will be understood
# when decoding (for now we only support a limited set of known mime-types)
# See: http://tiny.cc/m4kahw
# See: http://www.iana.org/assignments/media-types/index.html
if enc in ['gz', 'gzip']:
# Should we assume that this is 'always' base64?
# Someone might of got lucky and not had to encode it?
return ['application/x-gzip']
if enc in ['gz+base64', 'gzip+base64', 'gz+b64', 'gzip+b64']:
return ['application/base64', 'application/x-gzip']
if enc in ['base64', 'b64']:
return ['application/base64']
if enc in ['base32', 'b32']:
return ['application/base32']
if enc in ['base16', 'b16']:
return ['application/base16']
return [UNKNOWN_ENC]
def write_files(name, files, log):
if not files:
return
@@ -47,8 +71,8 @@ def write_files(name, files, log):
i + 1, name)
continue
path = os.path.abspath(path)
contents = decode_string(f_info.get('content', ''),
f_info.get('compression'))
decodings = canonicalize_decoding(f_info.get('encoding'))
contents = decode_contents(f_info.get('content', ''), decodings)
(u, g) = util.extract_usergroup(f_info.get('owner'))
perms = safe_int(f_info.get('permissions'), DEFAULT_PERMS)
util.write_file(path, contents, mode=perms)
@@ -62,8 +86,17 @@ def safe_int(text, default):
return default
def decode_string(contents, content_type):
if util.is_true(content_type, addons=['gzip', 'gz']):
contents_dec = base64.b64decode(contents)
contents = util.decomp_gzip(contents_dec, quiet=False)
return contents
def decode_contents(contents, decodings):
result = str(contents)
for enc in decodings:
if enc == 'application/x-gzip':
result = util.decomp_gzip(result, quiet=False)
elif enc == 'application/base64':
result = base64.b64decode(result)
elif enc == 'application/base32':
result = base64.b32decode(result)
elif enc == 'application/base16':
result = base64.b16decode(result)
elif enc == UNKNOWN_ENC:
pass
return result

View File

@@ -0,0 +1,32 @@
#cloud-config
# vim: syntax=yaml
#
# This is the configuration syntax that the write_files module
# will know how to understand, it can be given b64, b32, b16, or
# gz (or gz+b64) encoded strings which will be decoded accordingly
# and then written to the path that is provided.
#
# Note: Content strings here are truncated for example purposes.
#
write_files:
- content: CiMgVGhpcyBmaWxlIGNvbnRyb2xzIHRoZSBzdGF0ZSBvZiBTRUxpbnV4IG9u.....
encoding: b64
path: /etc/sysconfig/selinux
- content: '
# My new /etc/sysconfig/samba file
SMBDOPTIONS="-D"
'
path: /etc/sysconfig/samba
- content: H4sIADXC/U8C/+1Yf2wbVx1/d7YT122TQEMpadS6kgOZqL30J+.....
encoding: gz+b64
path: /usr/bin/uptime
- content: BIRSAU3FOR2GS3THOMQGM33SEB2GQZJAINJE6TRAMRQWK3LPNYXAU===
encoding: b32
path: /etc/sysconfig/crond
- content: 0A232053657474696E677320666F7220746865204E4653206461656D6F6E2E0A
encoding: b16
path: /etc/sysconfig/nfs