|
#! /usr/bin/env python |
|
|
|
# Copy of https://github.com/Red5d/docker-autocompose dirty hacked with some fixes for dates and |
|
# possiblity to create docker command lines from the existing containers by using the -o2 parameter |
|
|
|
import sys, argparse, pyaml, docker |
|
from collections import OrderedDict |
|
|
|
def main(): |
|
parser = argparse.ArgumentParser(description='Generate docker-compose yaml definition from running container.') |
|
parser.add_argument('-v', '--version', type=int, default=3, help='Compose file version (1 or 3)') |
|
parser.add_argument('-o', '--output', type=int, default=0, help='Type of output (0 or 1,2)') |
|
parser.add_argument('cnames', nargs='*', type=str, help='The name of the container to process.') |
|
args = parser.parse_args() |
|
|
|
struct = {} |
|
networks = [] |
|
for cname in args.cnames: |
|
cfile, networks,cmdline = generate(cname) |
|
struct.update(cfile) |
|
|
|
if args.output >0: |
|
print ("\r\n"+ cmdline + "\r\n") |
|
if args.output <2: |
|
render(struct, args, networks) |
|
|
|
|
|
def render(struct, args, networks): |
|
# Render yaml file |
|
if args.version == 1: |
|
pyaml.p(OrderedDict(struct)) |
|
else: |
|
pyaml.p(OrderedDict({'version': '"3"', 'services': struct, 'networks': networks})) |
|
|
|
def generate(cname): |
|
c = docker.from_env() |
|
|
|
try: |
|
cid = [x.short_id for x in c.containers.list(all=True) if cname == x.name or x.short_id in cname][0] |
|
except IndexError: |
|
print("That container is not available.") |
|
sys.exit(1) |
|
|
|
cattrs = c.containers.get(cid).attrs |
|
|
|
|
|
# Build yaml dict structure |
|
|
|
cfile = {} |
|
cfile[cattrs['Name'][1:]] = {} |
|
ct = cfile[cattrs['Name'][1:]] |
|
cmdLine ="docker run --name " + str( cattrs['Name'][1:]) |
|
|
|
values = { |
|
'cap_add': cattrs['HostConfig']['CapAdd'], |
|
'cap_drop': cattrs['HostConfig']['CapDrop'], |
|
'cgroup_parent': cattrs['HostConfig']['CgroupParent'], |
|
'container_name': cattrs['Name'][1:], |
|
'devices': [], |
|
'dns': cattrs['HostConfig']['Dns'], |
|
'dns_search': cattrs['HostConfig']['DnsSearch'], |
|
'environment': cattrs['Config']['Env'], |
|
'extra_hosts': cattrs['HostConfig']['ExtraHosts'], |
|
'image': cattrs['Config']['Image'], |
|
'labels': cattrs['Config']['Labels'], |
|
'links': cattrs['HostConfig']['Links'], |
|
#'log_driver': cattrs['HostConfig']['LogConfig']['Type'], |
|
#'log_opt': cattrs['HostConfig']['LogConfig']['Config'], |
|
#'logging': {'driver': cattrs['HostConfig']['LogConfig']['Type'], 'options': cattrs['HostConfig']['LogConfig']['Config']}, |
|
'networks': {x for x in cattrs['NetworkSettings']['Networks'].keys() if x != 'bridge'}, |
|
'security_opt': cattrs['HostConfig']['SecurityOpt'], |
|
'ulimits': cattrs['HostConfig']['Ulimits'], |
|
'volumes': cattrs['HostConfig']['Binds'], |
|
'volume_driver': cattrs['HostConfig']['VolumeDriver'], |
|
'volumes_from': cattrs['HostConfig']['VolumesFrom'], |
|
'entrypoint': cattrs['Config']['Entrypoint'], |
|
'user': cattrs['Config']['User'], |
|
'working_dir': cattrs['Config']['WorkingDir'], |
|
'domainname': cattrs['Config']['Domainname'], |
|
'hostname': cattrs['Config']['Hostname'], |
|
'ipc': cattrs['HostConfig']['IpcMode'], |
|
'mac_address': cattrs['NetworkSettings']['MacAddress'], |
|
'privileged': cattrs['HostConfig']['Privileged'], |
|
'restart': cattrs['HostConfig']['RestartPolicy']['Name'], |
|
'read_only': cattrs['HostConfig']['ReadonlyRootfs'], |
|
'stdin_open': cattrs['Config']['OpenStdin'], |
|
'tty': cattrs['Config']['Tty'] |
|
} |
|
|
|
# Populate devices key if device values are present |
|
if cattrs['HostConfig']['Devices']: |
|
values['devices'] = [x['PathOnHost']+':'+x['PathInContainer'] for x in cattrs['HostConfig']['Devices']] |
|
|
|
networks = {} |
|
if values['networks'] == set(): |
|
del values['networks'] |
|
values['network_mode'] = 'bridge' |
|
else: |
|
networklist = c.networks.list() |
|
for network in networklist: |
|
if network.attrs['Name'] in values['networks']: |
|
networks[network.attrs['Name']] = {'external': (not network.attrs['Internal'])} |
|
|
|
# Check for command and add it if present. |
|
if cattrs['Config']['Cmd'] != None: |
|
values['command'] = " ".join(cattrs['Config']['Cmd']), |
|
|
|
# Check for exposed/bound ports and add them if needed. |
|
try: |
|
expose_value = list(cattrs['Config']['ExposedPorts'].keys()) |
|
ports_value = [cattrs['HostConfig']['PortBindings'][key][0]['HostIp']+':'+cattrs['HostConfig']['PortBindings'][key][0]['HostPort']+':'+key for key in cattrs['HostConfig']['PortBindings']] |
|
|
|
# If bound ports found, don't use the 'expose' value. |
|
if (ports_value != None) and (ports_value != "") and (ports_value != []) and (ports_value != 'null') and (ports_value != {}) and (ports_value != "default") and (ports_value != 0) and (ports_value !=$ |
|
for index, port in enumerate(ports_value): |
|
if port[0] == ':': |
|
ports_value[index] = port[1:] |
|
# print ( "-p " , str (ports_value[index])) |
|
cmdLine = cmdLine + " -p " + str (ports_value[index]) |
|
values['ports'] = ports_value |
|
else: |
|
values['expose'] = expose_value |
|
|
|
except (KeyError, TypeError): |
|
# No ports exposed/bound. Continue without them. |
|
ports = None |
|
|
|
# fix some dates from causing errors. |
|
try: |
|
if values['labels']['org.label-schema.build-date'] != None: |
|
d = values['labels']['org.label-schema.build-date'] |
|
values['labels']['org.label-schema.build-date'] = "'" + str( d ) + "'" |
|
except KeyError as ke: |
|
pass |
|
|
|
# Iterate through values to finish building yaml dict. |
|
for key in values: |
|
value = values[key] |
|
if (value != None) and (value != "") and (value != []) and (value != 'null') and (value != {}) and (value != "default") and (value != 0) and (value != ",") and (value != "no"): |
|
ct[key] = value |
|
|
|
if cattrs['HostConfig']['Binds']: |
|
for key in cattrs['HostConfig']['Binds']: |
|
cmdLine = cmdLine + ' -v ' + str(key) |
|
|
|
if cattrs['Config']['Env']: |
|
for key in values['environment']: |
|
cmdLine = cmdLine + ' -e ' + str(key.split('=')[0]) |
|
if len(key.split('='))>1: |
|
cmdLine = cmdLine + '="' + str(key.split('=')[1]) + '"' |
|
cmdLine = cmdLine + " " + str ( cattrs['Config']['Image']) |
|
return cfile, networks, cmdLine |
|
|
|
|
|
if __name__ == "__main__": |
|
main() |
|
|
|
|
|
|
|
|
I really appreciate having access to this gist! Thank you.
I'm still working through a couple of issues, and would appreciate any help/expertise.
grep -v ""
from the command to create the tag file. I do not understand what that was supposed to do?tag
to then add the tags and repo sources to the images. No issue once I figured out that, but maybe this note will help someone else out. Or, does this mean something else isn't correct?docker-compose
. For those, is it necessary to use the the createddocker-compose.yml
files on the first run? I did, but then had one container not start (turned out I was out of space again) and so I nuked them. All but one of our containers starts with a single compose file, so I just used that and the generated file to kick start the one app. It seems to be working, but not sure if I'm misunderstanding something here?BTW, this process took a LOT of storage space. I had to attach a second volume for holding the images, backup and other files.