Custom Part Handler

This must be Python code that contains a list_types function and a handle_part function.

The list_types function takes no arguments and must return a list of content types that this part handler handles. These can include custom content types or built-in content types that this handler will override.

The handle_part function takes 4 arguments and returns nothing. See the example for how exactly each argument is used.

To use this part handler, it must be included in a MIME multipart file as part of the user data. Since MIME parts are processed in order, a part handler part must precede any parts with mime-types that it is expected to handle in the same user data.

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. These additional calls allow for initialisation or teardown before or after receiving any parts.

Example

 1#part-handler
 2
 3"""This is a trivial example part-handler that creates a file with the path
 4specified in the payload. It performs no input checking or error handling.
 5
 6To use it, first save the file you are currently viewing into your current
 7working directory. Then run the following:
 8```
 9$ echo '/var/tmp/my_path' > part
10$ cloud-init devel make-mime -a part-handler.py:part-handler -a part:x-my-path --force > user-data
11```
12
13This will create a mime file with the contents of 'part' and the
14part-handler. You can now pass 'user-data' to your cloud of choice.
15
16When run, cloud-init will have created an empty file at /var/tmp/my_path.
17"""
18
19import pathlib
20from typing import Any
21
22from cloudinit.cloud import Cloud
23
24
25def list_types():
26    """Return a list of mime-types that are handled by this module."""
27    return ["text/x-my-path"]
28
29
30def handle_part(data: Cloud, ctype: str, filename: str, payload: Any):
31    """Handle a part with the given mime-type.
32
33    This function will get called multiple times. The first time is
34    to allow any initial setup needed to handle parts. It will then get
35    called once for each part matching the mime-type returned by `list_types`.
36    Finally, it will get called one last time to allow for any final
37    teardown.
38
39    :data: A `Cloud` instance. This will be the same instance for each call
40        to handle_part.
41    :ctype: '__begin__', '__end__', or the mime-type
42        (for this example 'text/x-my-path') of the part
43    :filename: The filename for the part as defined in the MIME archive,
44        or dynamically generated part if no filename is given
45    :payload: The content of the part. This will be
46        `None` when `ctype` is '__begin__' or '__end__'.
47    """
48    if ctype == "__begin__":
49        # Any custom setup needed before handling payloads
50        return
51
52    if ctype == "__end__":
53        # Any custom teardown needed after handling payloads can happen here
54        return
55
56    # If we've made it here, we're dealing with a real payload, so handle
57    # it appropriately
58    pathlib.Path(payload.strip()).touch()