From 85619842be6a5c1d5a8068aeb28e158ec32c41ca Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Mon, 18 Jan 2016 14:02:25 -0500 Subject: [PATCH] Add migration script. Signed-off-by: Daniel Nephin --- .../migrate-compose-file-v1-to-v2.py | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100755 contrib/migration/migrate-compose-file-v1-to-v2.py diff --git a/contrib/migration/migrate-compose-file-v1-to-v2.py b/contrib/migration/migrate-compose-file-v1-to-v2.py new file mode 100755 index 000000000..a961b0bd7 --- /dev/null +++ b/contrib/migration/migrate-compose-file-v1-to-v2.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python +""" +Migrate a Compose file from the V1 format in Compose 1.5 to the V2 format +supported by Compose 1.6+ +""" +from __future__ import absolute_import +from __future__ import unicode_literals + +import argparse +import logging +import sys + +import ruamel.yaml + + +log = logging.getLogger('migrate') + + +def migrate(content): + data = ruamel.yaml.load(content, ruamel.yaml.RoundTripLoader) + + service_names = data.keys() + for name, service in data.items(): + # remove links and external links + service.pop('links', None) + external_links = service.pop('external_links', None) + if external_links: + log.warn( + "Service {name} has external_links: {ext}, which are no longer " + "supported. See https://docs.docker.com/compose/networking/ " + "for options on how to connect external containers to the " + "compose network.".format(name=name, ext=external_links)) + + # net is now networks + if 'net' in service: + service['networks'] = [service.pop('net')] + + # create build section + if 'dockerfile' in service: + service['build'] = { + 'context': service.pop('build'), + 'dockerfile': service.pop('dockerfile'), + } + + # create logging section + if 'log_driver' in service: + service['logging'] = {'driver': service.pop('log_driver')} + if 'log_opt' in service: + service['logging']['options'] = service.pop('log_opt') + + # volumes_from prefix with 'container:' + for idx, volume_from in enumerate(service.get('volumes_from', [])): + if volume_from.split(':', 1)[0] not in service_names: + service['volumes_from'][idx] = 'container:%s' % volume_from + + data['services'] = {name: data.pop(name) for name in data.keys()} + data['version'] = 2 + return data + + +def write(stream, new_format, indent, width): + ruamel.yaml.dump( + new_format, + stream, + Dumper=ruamel.yaml.RoundTripDumper, + indent=indent, + width=width) + + +def parse_opts(args): + parser = argparse.ArgumentParser() + parser.add_argument("filename", help="Compose file filename.") + parser.add_argument("-i", "--in-place", action='store_true') + parser.add_argument( + "--indent", type=int, default=2, + help="Number of spaces used to indent the output yaml.") + parser.add_argument( + "--width", type=int, default=80, + help="Number of spaces used as the output width.") + return parser.parse_args() + + +def main(args): + logging.basicConfig() + + opts = parse_opts(args) + + with open(opts.filename, 'r') as fh: + new_format = migrate(fh.read()) + + if opts.in_place: + output = open(opts.filename, 'w') + else: + output = sys.stdout + write(output, new_format, opts.indent, opts.width) + + +if __name__ == "__main__": + main(sys.argv)