Blame cloudinit/cmd/devel/make_mime.py

Packit Service 9bfd13
# This file is part of cloud-init. See LICENSE file for license information.
Packit Service 9bfd13
Packit Service 9bfd13
"""Generate multi-part mime messages for user-data """
Packit Service 9bfd13
Packit Service 9bfd13
import argparse
Packit Service 9bfd13
import sys
Packit Service 9bfd13
from email.mime.multipart import MIMEMultipart
Packit Service 9bfd13
from email.mime.text import MIMEText
Packit Service 9bfd13
Packit Service 9bfd13
from cloudinit import log
Packit Service 9bfd13
from cloudinit.handlers import INCLUSION_TYPES_MAP
Packit Service 9bfd13
from . import addLogHandlerCLI
Packit Service 9bfd13
Packit Service 9bfd13
NAME = 'make-mime'
Packit Service 9bfd13
LOG = log.getLogger(NAME)
Packit Service 9bfd13
EPILOG = ("Example: make-mime -a config.yaml:cloud-config "
Packit Service 9bfd13
          "-a script.sh:x-shellscript > user-data")
Packit Service 9bfd13
Packit Service 9bfd13
Packit Service 9bfd13
def file_content_type(text):
Packit Service 9bfd13
    """ Return file content type by reading the first line of the input. """
Packit Service 9bfd13
    try:
Packit Service 9bfd13
        filename, content_type = text.split(":", 1)
Packit Service 9bfd13
        return (open(filename, 'r'), filename, content_type.strip())
Packit Service 9bfd13
    except ValueError as e:
Packit Service 9bfd13
        raise argparse.ArgumentError(
Packit Service 9bfd13
            text, "Invalid value for %r" % (text)
Packit Service 9bfd13
        ) from e
Packit Service 9bfd13
Packit Service 9bfd13
Packit Service 9bfd13
def get_parser(parser=None):
Packit Service 9bfd13
    """Build or extend and arg parser for make-mime utility.
Packit Service 9bfd13
Packit Service 9bfd13
    @param parser: Optional existing ArgumentParser instance representing the
Packit Service 9bfd13
        subcommand which will be extended to support the args of this utility.
Packit Service 9bfd13
Packit Service 9bfd13
    @returns: ArgumentParser with proper argument configuration.
Packit Service 9bfd13
    """
Packit Service 9bfd13
    if not parser:
Packit Service 9bfd13
        parser = argparse.ArgumentParser()
Packit Service 9bfd13
    # update the parser's doc and add an epilog to show an example
Packit Service 9bfd13
    parser.description = __doc__
Packit Service 9bfd13
    parser.epilog = EPILOG
Packit Service 9bfd13
    parser.add_argument("-a", "--attach", dest="files", type=file_content_type,
Packit Service 9bfd13
                        action='append', default=[],
Packit Service 9bfd13
                        metavar="<file>:<content-type>",
Packit Service 9bfd13
                        help=("attach the given file as the specified "
Packit Service 9bfd13
                              "content-type"))
Packit Service 9bfd13
    parser.add_argument('-l', '--list-types', action='store_true',
Packit Service 9bfd13
                        default=False,
Packit Service 9bfd13
                        help='List support cloud-init content types.')
Packit Service 9bfd13
    parser.add_argument('-f', '--force', action='store_true',
Packit Service 9bfd13
                        default=False,
Packit Service 9bfd13
                        help='Ignore unknown content-type warnings')
Packit Service 9bfd13
    return parser
Packit Service 9bfd13
Packit Service 9bfd13
Packit Service 9bfd13
def get_content_types(strip_prefix=False):
Packit Service 9bfd13
    """ Return a list of cloud-init supported content types.  Optionally
Packit Service 9bfd13
        strip out the leading 'text/' of the type if strip_prefix=True.
Packit Service 9bfd13
    """
Packit Service 9bfd13
    return sorted([ctype.replace("text/", "") if strip_prefix else ctype
Packit Service 9bfd13
                   for ctype in INCLUSION_TYPES_MAP.values()])
Packit Service 9bfd13
Packit Service 9bfd13
Packit Service 9bfd13
def handle_args(name, args):
Packit Service 9bfd13
    """Create a multi-part MIME archive for use as user-data.  Optionally
Packit Service 9bfd13
       print out the list of supported content types of cloud-init.
Packit Service 9bfd13
Packit Service 9bfd13
    Also setup CLI log handlers to report to stderr since this is a development
Packit Service 9bfd13
    utility which should be run by a human on the CLI.
Packit Service 9bfd13
Packit Service 9bfd13
    @return 0 on success, 1 on failure.
Packit Service 9bfd13
    """
Packit Service 9bfd13
    addLogHandlerCLI(LOG, log.DEBUG if args.debug else log.WARNING)
Packit Service 9bfd13
    if args.list_types:
Packit Service 9bfd13
        print("\n".join(get_content_types(strip_prefix=True)))
Packit Service 9bfd13
        return 0
Packit Service 9bfd13
Packit Service 9bfd13
    sub_messages = []
Packit Service 9bfd13
    errors = []
Packit Service 9bfd13
    for i, (fh, filename, format_type) in enumerate(args.files):
Packit Service 9bfd13
        contents = fh.read()
Packit Service 9bfd13
        sub_message = MIMEText(contents, format_type, sys.getdefaultencoding())
Packit Service 9bfd13
        sub_message.add_header('Content-Disposition',
Packit Service 9bfd13
                               'attachment; filename="%s"' % (filename))
Packit Service 9bfd13
        content_type = sub_message.get_content_type().lower()
Packit Service 9bfd13
        if content_type not in get_content_types():
Packit Service 9bfd13
            level = "WARNING" if args.force else "ERROR"
Packit Service 9bfd13
            msg = (level + ": content type %r for attachment %s "
Packit Service 9bfd13
                   "may be incorrect!") % (content_type, i + 1)
Packit Service 9bfd13
            sys.stderr.write(msg + '\n')
Packit Service 9bfd13
            errors.append(msg)
Packit Service 9bfd13
        sub_messages.append(sub_message)
Packit Service 9bfd13
    if len(errors) and not args.force:
Packit Service 9bfd13
        sys.stderr.write("Invalid content-types, override with --force\n")
Packit Service 9bfd13
        return 1
Packit Service 9bfd13
    combined_message = MIMEMultipart()
Packit Service 9bfd13
    for msg in sub_messages:
Packit Service 9bfd13
        combined_message.attach(msg)
Packit Service 9bfd13
    print(combined_message)
Packit Service 9bfd13
    return 0
Packit Service 9bfd13
Packit Service 9bfd13
Packit Service 9bfd13
def main():
Packit Service 9bfd13
    args = get_parser().parse_args()
Packit Service 9bfd13
    return(handle_args(NAME, args))
Packit Service 9bfd13
Packit Service 9bfd13
Packit Service 9bfd13
if __name__ == '__main__':
Packit Service 9bfd13
    sys.exit(main())
Packit Service 9bfd13
Packit Service 9bfd13
Packit Service 9bfd13
# vi: ts=4 expandtab