Search code examples
cloud-init

cloud-init: Can write_files be merged?


Can write_files be merged? I can't seem to get the merge_how syntax correct. Only files in the last write_files are being created.

Thanks


Solution

  • The answer is yes.

    When working with multi-part MIME, you must add the following to the header of each part.

    Merge-Type: list(append)+dict(no_replace,recurse_list)+str()

    Below is a modified version of the helper script provided in the cloud-init documentation.

    #!/usr/bin/env python3
    
    import click
    import sys
    import gzip as gz
    
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    
    
    @click.command()
    @click.option('--gzip', is_flag=True,
                  help='gzip MIME message to current directory')
    @click.argument('message', nargs=-1)
    def main(message: str, gzip: bool) -> None:
        """This script creates a multi part MIME suitable for cloud-init
    
        A MESSAGE has following format <filename>:<type> where <filename> is the
        file that contains the data to add to the MIME message. <type> is the 
        MIME content-type.
    
        MIME content-type may be on of the following:
        text/cloud-boothook
        text/cloud-config
        text/cloud-config-archive
        text/jinja2
        text/part-handler
        text/upstart-job
        text/x-include-once-url
        text/x-include-url
        text/x-shellscript
    
        EXAMPLE:
        write-mime-multipart afile.cfg:cloud-config bfile.sh:x-shellscript
        """
        combined_message = MIMEMultipart()
        for message_part in message:
            (filename, format_type) = message_part.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="{}"'.format(filename))
            sub_message.add_header('Merge-Type',
                                   'list(append)+dict(no_replace,recurse_list)+str()')
            combined_message.attach(sub_message)
    
        if gzip:
            with gz.open('combined-userdata.txt.gz', 'wb') as fd:
                fd.write(bytes(combined_message))
        else:
            print(combined_message)
    
    
    if __name__ == '__main__':
        main()