User data formats#
User data that will be acted upon by cloud-init
must be in one of the
following types.
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 boota different
apt
mirror should be usedadditional
apt
sources should be addedcertain SSH keys should be imported
and many more…
Note
This file must be valid YAML syntax.
See the Cloud config examples section for a commented set of examples of supported cloud config formats.
Begins with: #cloud-config
or Content-Type: text/cloud-config
when
using a MIME archive.
Note
New in cloud-init
v. 18.4: Cloud config data can also render cloud
instance metadata variables using jinja templating. See
Instance metadata for more information.
User data script#
Typically used by those who just want to execute a shell script.
Begins with: #!
or Content-Type: text/x-shellscript
when using a MIME
archive.
User data scripts can optionally render cloud instance metadata variables using jinja templating. See Instance metadata for more information.
Example script#
Create a script file myscript.sh
that contains the following:
#!/bin/sh
echo "Hello World. The time is now $(date -R)!" | tee /root/output.txt
Now run:
$ euca-run-instances --key mykey --user-data-file myscript.sh ami-a07d95c9
Kernel command line#
When using the NoCloud datasource, users can pass user data via the kernel command line parameters. See the NoCloud datasource and Kernel command line documentation for more details.
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 [1] 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.
Supported content-types are listed from the cloud-init
subcommand
make-mime:
$ cloud-init devel make-mime --list-types
Example output:
cloud-boothook
cloud-config
cloud-config-archive
cloud-config-jsonp
jinja2
part-handler
x-include-once-url
x-include-url
x-shellscript
x-shellscript-per-boot
x-shellscript-per-instance
x-shellscript-per-once
Helper subcommand to generate MIME messages#
The cloud-init
make-mime subcommand can also generate MIME multi-part
files.
The make-mime subcommand takes pairs of (filename, “text/” mime
subtype) separated by a colon (e.g., config.yaml:cloud-config
) and emits a
MIME multipart message to stdout
.
Examples#
Create user data containing both a cloud-config (config.yaml
)
and a shell script (script.sh
)
$ cloud-init devel make-mime -a config.yaml:cloud-config -a script.sh:x-shellscript > userdata
Create user data containing 3 shell scripts:
always.sh
- run every bootinstance.sh
- run once per instanceonce.sh
- run once
$ cloud-init devel make-mime -a always.sh:x-shellscript-per-boot -a instance.sh:x-shellscript-per-instance -a once.sh:x-shellscript-per-once
include
file#
This content is an include
file.
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, i.e., 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.
Begins with: #include
or Content-Type: text/x-include-url
when using
a MIME archive.
cloud-boothook
#
This content is boothook data. It is stored in a file under
/var/lib/cloud
and executed immediately. This is the earliest hook
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.
Begins with: #cloud-boothook
or Content-Type: text/cloud-boothook
when
using a MIME archive.
Part-handler#
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
/var/lib/cloud/data
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 list_types
method
will be called. It must return a list of mime-types that this part-handler
handles. Since MIME parts are processed in order, a part-handler part
must precede any parts with mime-types it is expected to handle in the same
user data.
The 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. The '__begin__'
and '__end__'
sentinels allow the part
handler to do initialisation or teardown before or after receiving any parts.
Begins with: #part-handler
or Content-Type: text/part-handler
when
using a MIME archive.
Example#
1#part-handler
2
3def list_types():
4 # return a list of mime-types that are handled by this module
5 return(["text/plain", "text/go-cubs-go"])
6
7def handle_part(data, ctype, filename, payload):
8 # data: the cloudinit object
9 # ctype: '__begin__', '__end__', or the specific mime-type of the part
10 # filename: the filename for the part, or dynamically generated part if
11 # no filename is given attribute is present
12 # payload: the content of the part (empty for begin or end)
13 if ctype == "__begin__":
14 print("my handler is beginning")
15 return
16 if ctype == "__end__":
17 print("my handler is ending")
18 return
19
20 print(f"==== received ctype={ctype} filename={filename} ====")
21 print(payload)
22 print(f"==== end ctype={ctype} filename={filename}")
Also, this blog post offers another example for more advanced usage.
Disabling user data#
Cloud-init
can be configured to ignore any user data provided to instance.
This allows custom images to prevent users from accidentally breaking closed
appliances. Setting allow_userdata: false
in the configuration will disable
cloud-init
from processing user data.