User data that will be acted upon by cloud-init must be in one of the following types.
Gzip Compressed Content¶
Content found to be gzip compressed will be uncompressed. The uncompressed data will then be used as if it were not compressed. This is typically useful because user-data is limited to ~16384  bytes.
Mime Multi Part Archive¶
This list of rules is applied to each part of this multi-part file. Using a mime-multi part file, the user can specify more than one type of data.
For example, both a user data script and a cloud-config type could be specified.
Helper script to generate mime messages¶
#!/usr/bin/python import sys from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText if len(sys.argv) == 1: print("%s input-file:type ..." % (sys.argv)) sys.exit(1) combined_message = MIMEMultipart() for i in sys.argv[1:]: (filename, format_type) = i.split(":", 1) with open(filename) as fh: contents = fh.read() sub_message = MIMEText(contents, format_type, sys.getdefaultencoding()) sub_message.add_header('Content-Disposition', 'attachment; filename="%s"' % (filename)) combined_message.attach(sub_message) print(combined_message)
Typically used by those who just want to execute a shell script.
Content-Type: text/x-shellscript when using a MIME
New in cloud-init v. 18.4: User-data scripts can also render cloud instance metadata variables using jinja templating. See Instance Metadata for more information.
$ cat myscript.sh #!/bin/sh echo "Hello World. The time is now $(date -R)!" | tee /root/output.txt $ euca-run-instances --key mykey --user-data-file myscript.sh ami-a07d95c9
This content is a
The file contains a list of urls, one per line. Each of the URLs will be read, and their content will be passed through this same set of rules. Ie, the content read from the URL can be gzipped, mime-multi-part, or plain text. If an error occurs reading a file the remaining files will not be read.
Content-Type: text/x-include-url when using
a MIME archive.
Cloud Config Data¶
Cloud-config is the simplest way to accomplish some things via user-data. Using cloud-config syntax, the user can specify certain things in a human friendly format.
These things include:
- apt upgrade should be run on first boot
- a different apt mirror should be used
- additional apt sources should be added
- certain ssh keys should be imported
- and many more…
This file must be valid yaml syntax.
See the Cloud config examples section for a commented set of examples of supported cloud config formats.
Content-Type: text/cloud-config when
using a MIME archive.
New in cloud-init v. 18.4: Cloud config dta can also render cloud instance metadata variables using jinja templating. See Instance Metadata for more information.
Content is placed into a file in
/etc/init, and will be consumed by upstart
as any other upstart job.
Content-Type: text/upstart-job when using
a MIME archive.
This content is
boothook data. It is stored in a file under
/var/lib/cloud and then executed immediately. This is the earliest
available. Note, that there is no mechanism provided for running only once. The
boothook must take care of this itself.
It is provided with the instance id in the environment variable
INSTANCE_ID. This could be made use of to provide a ‘once-per-instance’
type of functionality.
Content-Type: text/cloud-boothook when
using a MIME archive.
This is a
part-handler: It contains custom code for either supporting new
mime-types in multi-part user data, or overriding the existing handlers for
supported mime-types. It will be written to a file in
based on its filename (which is generated).
This must be python code that contains a
list_types function and a
handle_part function. Once the section is read the
will be called. It must return a list of mime-types that this part-handler
handles. Because mime parts are processed in order, a
must precede any parts with mime-types it is expected to handle in the same
handle_part function must be defined like:
def handle_part(data, ctype, filename, payload): # data = the cloudinit object # ctype = "__begin__", "__end__", or the mime-type of the part that is being handled. # filename = the filename of the part (or a generated filename if none is present in mime data) # payload = the parts' content
Cloud-init will then call the
handle_part function once before it handles
any parts, once per part received, and once after all parts have been handled.
'__end__' sentinels allow the part handler to do
initialization or teardown before or after receiving any parts.
Content-Type: text/part-handler when
using a MIME archive.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
#part-handler # vi: syntax=python ts=4 def list_types(): # return a list of mime-types that are handled by this module return(["text/plain", "text/go-cubs-go"]) def handle_part(data,ctype,filename,payload): # data: the cloudinit object # ctype: '__begin__', '__end__', or the specific mime-type of the part # filename: the filename for the part, or dynamically generated part if # no filename is given attribute is present # payload: the content of the part (empty for begin or end) if ctype == "__begin__": print "my handler is beginning" return if ctype == "__end__": print "my handler is ending" return print "==== received ctype=%s filename=%s ====" % (ctype,filename) print payload print "==== end ctype=%s filename=%s" % (ctype, filename)
Also this blog post offers another example for more advanced usage.
Cloud-init can be configured to ignore any user-data provided to instance.
This allows custom images to prevent users from accidentally breaking closed
allow_userdata: false in the configuration will disable
cloud-init from processing user-data.
|||See your cloud provider for applicable user-data size limitations…|