1
- #! /usr/bin/env python
1
+ #! /usr/bin/env python3
2
2
import datetime
3
3
import sys , argparse , pyaml , docker
4
4
from collections import OrderedDict
@@ -14,6 +14,7 @@ def main():
14
14
parser .add_argument ('-a' , '--all' , action = 'store_true' , help = 'Include all active containers' )
15
15
parser .add_argument ('-v' , '--version' , type = int , default = 3 , help = 'Compose file version (1 or 3)' )
16
16
parser .add_argument ('cnames' , nargs = '*' , type = str , help = 'The name of the container to process.' )
17
+ parser .add_argument ('-c' , '--createvolumes' , action = 'store_true' , help = 'Create new volumes instead of reusing existing ones' )
17
18
args = parser .parse_args ()
18
19
19
20
container_names = args .cnames
@@ -23,24 +24,24 @@ def main():
23
24
struct = {}
24
25
networks = {}
25
26
volumes = {}
27
+ containers = {}
26
28
for cname in container_names :
27
- cfile , c_networks , c_volumes = generate (cname )
29
+ cfile , c_networks , c_volumes = generate (cname , createvolumes = args . createvolumes )
28
30
29
31
struct .update (cfile )
30
32
31
- if c_networks is None :
32
- networks = None
33
- else :
33
+ if not c_networks == None :
34
34
networks .update (c_networks )
35
-
36
- if c_volumes is None :
37
- volumes = None
38
- else :
35
+ if not c_volumes == None :
39
36
volumes .update (c_volumes )
40
-
37
+
38
+ # moving the networks = None statemens outside of the for loop. Otherwise any container could reset it.
39
+ if len (networks ) == 0 :
40
+ networks = None
41
+ if len (volumes ) == 0 :
42
+ volumes = None
41
43
render (struct , args , networks , volumes )
42
44
43
-
44
45
def render (struct , args , networks , volumes ):
45
46
# Render yaml file
46
47
if args .version == 1 :
@@ -71,7 +72,7 @@ def fix_label(label: str):
71
72
return f"'{ label } '" if is_date_or_time (label ) else label
72
73
73
74
74
- def generate (cname ):
75
+ def generate (cname , createvolumes = False ):
75
76
c = docker .from_env ()
76
77
77
78
try :
@@ -110,7 +111,9 @@ def generate(cname):
110
111
'networks' : {x for x in cattrs ['NetworkSettings' ]['Networks' ].keys () if x not in default_networks },
111
112
'security_opt' : cattrs ['HostConfig' ]['SecurityOpt' ],
112
113
'ulimits' : cattrs ['HostConfig' ]['Ulimits' ],
113
- 'volumes' : [f'{ m ["Name" ]} :{ m ["Destination" ]} ' for m in cattrs ['Mounts' ] if m ['Type' ] == 'volume' ],
114
+ # the line below would not handle type bind
115
+ # 'volumes': [f'{m["Name"]}:{m["Destination"]}' for m in cattrs['Mounts'] if m['Type'] == 'volume'],
116
+ 'mounts' : cattrs ['Mounts' ], #this could be moved outside of the dict. will only use it for generate
114
117
'volume_driver' : cattrs ['HostConfig' ]['VolumeDriver' ],
115
118
'volumes_from' : cattrs ['HostConfig' ]['VolumesFrom' ],
116
119
'entrypoint' : cattrs ['Config' ]['Entrypoint' ],
@@ -143,14 +146,34 @@ def generate(cname):
143
146
if network .attrs ['Name' ] in values ['networks' ]:
144
147
networks [network .attrs ['Name' ]] = {'external' : (not network .attrs ['Internal' ]),
145
148
'name' : network .attrs ['Name' ]}
146
-
149
+ # volumes = {}
150
+ # if values['volumes'] is not None:
151
+ # for volume in values['volumes']:
152
+ # volume_name = volume.split(':')[0]
153
+ # volumes[volume_name] = {'external': True}
154
+ # else:
155
+ # volumes = None
156
+
157
+ # handles both the returned values['volumes'] (in c_file) and volumes for both, the bind and volume types
158
+ # also includes the read only option
147
159
volumes = {}
148
- if values ['volumes' ] is not None :
149
- for volume in values ['volumes' ]:
150
- volume_name = volume .split (':' )[0 ]
151
- volumes [volume_name ] = {'external' : True }
152
- else :
160
+ mountpoints = []
161
+ if values ['mounts' ] is not None :
162
+ for mount in values ['mounts' ]:
163
+ destination = mount ['Destination' ]
164
+ if not mount ['RW' ]:
165
+ destination = destination + ':ro'
166
+ if mount ['Type' ] == 'volume' :
167
+ mountpoints .append (mount ['Name' ] + ':' + destination )
168
+ if not createvolumes :
169
+ volumes [mount ['Name' ]] = {'external' : True } #to reuse an existing volume ... better to make that a choice? (cli argument)
170
+ elif mount ['Type' ] == 'bind' :
171
+ mountpoints .append (mount ['Source' ] + ':' + destination )
172
+ values ['volumes' ] = mountpoints
173
+ if len (volumes ) == 0 :
153
174
volumes = None
175
+ values ['mounts' ] = None #remove this temporary data from the returned data
176
+
154
177
155
178
# Check for command and add it if present.
156
179
if cattrs ['Config' ]['Cmd' ] is not None :
@@ -186,4 +209,3 @@ def generate(cname):
186
209
187
210
if __name__ == "__main__" :
188
211
main ()
189
-
0 commit comments