|
@@ -11,7 +11,7 @@
|
11
|
11
|
# - This script may run stand-alone (on local setups) or dockerized (which supports remote Docker setups).
|
12
|
12
|
# - This script is Python 3 only.
|
13
|
13
|
#
|
14
|
|
-# v1.0.2 by Ricardo Branco
|
|
14
|
+# v1.1 by Ricardo Branco
|
15
|
15
|
#
|
16
|
16
|
# MIT License
|
17
|
17
|
#
|
|
@@ -40,7 +40,7 @@ try:
|
40
|
40
|
except ImportError:
|
41
|
41
|
error("Please install PyYaml with: pip3 install pyyaml")
|
42
|
42
|
|
43
|
|
-VERSION = "1.0.2"
|
|
43
|
+VERSION = "1.1"
|
44
|
44
|
|
45
|
45
|
|
46
|
46
|
def dockerized():
|
|
@@ -144,35 +144,50 @@ def check_name(image):
|
144
|
144
|
|
145
|
145
|
class RegistryCleaner():
|
146
|
146
|
'''Simple callable class for Docker Registry cleaning duties'''
|
147
|
|
- def __init__(self, container_name):
|
|
147
|
+ def __init__(self, container=None, volume=None):
|
148
|
148
|
try:
|
149
|
149
|
self.docker = docker.from_env()
|
150
|
150
|
except TLSParameterError as err:
|
151
|
151
|
error(err)
|
152
|
152
|
|
|
153
|
+ if container is None:
|
|
154
|
+ self.container = None
|
|
155
|
+ try:
|
|
156
|
+ self.volume = self.docker.volumes.get(volume)
|
|
157
|
+ self.registry_dir = self.volume.attrs['Mountpoint']
|
|
158
|
+ except (APIError, exceptions.ConnectionError) as err:
|
|
159
|
+ error(err)
|
|
160
|
+ if dockerized():
|
|
161
|
+ if not os.getenv("REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY"):
|
|
162
|
+ os.environ['REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY'] = "/var/lib/registry"
|
|
163
|
+ self.registry_dir = os.environ['REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY']
|
|
164
|
+ return
|
|
165
|
+
|
153
|
166
|
try:
|
154
|
|
- self.info = self.docker.api.inspect_container(container_name)
|
|
167
|
+ self.info = self.docker.api.inspect_container(container)
|
155
|
168
|
self.container = self.info['Id']
|
156
|
169
|
except (APIError, exceptions.ConnectionError) as err:
|
157
|
170
|
error(err)
|
158
|
171
|
|
159
|
172
|
if self.info['Config']['Image'] != "registry:2":
|
160
|
|
- error("The container %s is not running the registry:2 image" % (container_name))
|
|
173
|
+ error("The container %s is not running the registry:2 image" % (container))
|
161
|
174
|
|
162
|
175
|
if LooseVersion(self.get_image_version()) < LooseVersion("v2.4.0"):
|
163
|
176
|
error("You're not running Docker Registry 2.4.0+")
|
164
|
177
|
|
165
|
178
|
self.registry_dir = self.get_registry_dir()
|
166
|
|
- try:
|
167
|
|
- os.chdir(self.registry_dir + "/docker/registry/v2/repositories")
|
168
|
|
- except FileNotFoundError as err:
|
169
|
|
- error(err)
|
170
|
179
|
|
171
|
180
|
if dockerized() and not os.getenv("REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY"):
|
172
|
181
|
os.environ['REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY'] = self.registry_dir
|
173
|
182
|
|
174
|
183
|
def __call__(self):
|
175
|
|
- self.docker.api.stop(self.container)
|
|
184
|
+ try:
|
|
185
|
+ os.chdir(self.registry_dir + "/docker/registry/v2/repositories")
|
|
186
|
+ except FileNotFoundError as err:
|
|
187
|
+ error(err)
|
|
188
|
+
|
|
189
|
+ if self.container is not None:
|
|
190
|
+ self.docker.api.stop(self.container)
|
176
|
191
|
|
177
|
192
|
images = args.images if args.images else os.listdir(".")
|
178
|
193
|
|
|
@@ -184,7 +199,8 @@ class RegistryCleaner():
|
184
|
199
|
if not self.garbage_collect():
|
185
|
200
|
rc = 1
|
186
|
201
|
|
187
|
|
- self.docker.api.start(self.container)
|
|
202
|
+ if self.container is not None:
|
|
203
|
+ self.docker.api.start(self.container)
|
188
|
204
|
return rc
|
189
|
205
|
|
190
|
206
|
def get_file(self, filename):
|
|
@@ -258,9 +274,10 @@ class RegistryCleaner():
|
258
|
274
|
def main():
|
259
|
275
|
'''Main function'''
|
260
|
276
|
progname = os.path.basename(sys.argv[0])
|
261
|
|
- usage = "\rUsage: " + progname + " [OPTIONS] CONTAINER [REPOSITORY[:TAG]]..." + """
|
|
277
|
+ usage = "\rUsage: " + progname + " [OPTIONS] VOLUME|CONTAINER [REPOSITORY[:TAG]]..." + """
|
262
|
278
|
Options:
|
263
|
279
|
-x, --remove Remove the specified images or repositories.
|
|
280
|
+ -v, --volume Specify a volume instead of container.
|
264
|
281
|
-q, --quiet Supress non-error messages.
|
265
|
282
|
-V, --version Show version and exit."""
|
266
|
283
|
|
|
@@ -268,8 +285,9 @@ Options:
|
268
|
285
|
parser.add_argument('-h', '--help', action='store_true')
|
269
|
286
|
parser.add_argument('-q', '--quiet', action='store_true')
|
270
|
287
|
parser.add_argument('-x', '--remove', action='store_true')
|
|
288
|
+ parser.add_argument('-v', '--volume', action='store_true')
|
271
|
289
|
parser.add_argument('-V', '--version', action='store_true')
|
272
|
|
- parser.add_argument('container')
|
|
290
|
+ parser.add_argument('container_or_volume')
|
273
|
291
|
parser.add_argument('images', nargs='*')
|
274
|
292
|
global args
|
275
|
293
|
args = parser.parse_args()
|
|
@@ -288,7 +306,11 @@ Options:
|
288
|
306
|
if args.remove and not args.images:
|
289
|
307
|
error("The -x option requires that you specify at least one repository...")
|
290
|
308
|
|
291
|
|
- rc = RegistryCleaner(args.container)
|
|
309
|
+ if args.volume:
|
|
310
|
+ rc = RegistryCleaner(volume=args.container_or_volume)
|
|
311
|
+ else:
|
|
312
|
+ rc = RegistryCleaner(container=args.container_or_volume)
|
|
313
|
+
|
292
|
314
|
sys.exit(rc())
|
293
|
315
|
|
294
|
316
|
if __name__ == "__main__":
|