Explorar el Código

Support service names/IDs

master
Ricardo Branco hace 5 años
padre
commit
d660b1a512
Se han modificado 1 ficheros con 58 adiciones y 24 borrados
  1. 58
    24
      clean_registry.py

+ 58
- 24
clean_registry.py Ver fichero

5
 The optional -x flag may be used to completely remove the specified repositories or tagged images.
5
 The optional -x flag may be used to completely remove the specified repositories or tagged images.
6
 
6
 
7
 NOTES:
7
 NOTES:
8
-  - This script stops the Registry container during cleanup to prevent corruption,
8
+  - This script pauses the Registry container during cleanup to prevent corruption,
9
     making it temporarily unavailable to clients.
9
     making it temporarily unavailable to clients.
10
   - This script assumes local storage (the filesystem storage driver).
10
   - This script assumes local storage (the filesystem storage driver).
11
   - This script may run stand-alone (on local setups) or dockerized (which supports remote Docker setups).
11
   - This script may run stand-alone (on local setups) or dockerized (which supports remote Docker setups).
12
   - This script is Python 3 only.
12
   - This script is Python 3 only.
13
 
13
 
14
-v1.3.2 by Ricardo Branco
14
+v1.4 by Ricardo Branco
15
 
15
 
16
 MIT License
16
 MIT License
17
 """
17
 """
34
 
34
 
35
 import yaml
35
 import yaml
36
 
36
 
37
-VERSION = "1.3.2"
37
+VERSION = "1.4"
38
 REGISTRY_DIR = "REGISTRY_STORAGE_FILESYSTEM_ROOTREGISTRY_DIR"
38
 REGISTRY_DIR = "REGISTRY_STORAGE_FILESYSTEM_ROOTREGISTRY_DIR"
39
 args = None
39
 args = None
40
 
40
 
151
 
151
 
152
 class RegistryCleaner():
152
 class RegistryCleaner():
153
     '''Simple callable class for Docker Registry cleaning duties'''
153
     '''Simple callable class for Docker Registry cleaning duties'''
154
-    def __init__(self, container=None, volume=None):
154
+    def __init__(self, container_or_service=None, volume=None):
155
         try:
155
         try:
156
             self.docker = docker.from_env()
156
             self.docker = docker.from_env()
157
         except TLSParameterError as err:
157
         except TLSParameterError as err:
158
             error(err)
158
             error(err)
159
 
159
 
160
-        if container is None:
161
-            self.container = None
160
+        if volume:
161
+            self.containers = None
162
             try:
162
             try:
163
                 self.volume = self.docker.volumes.get(volume)
163
                 self.volume = self.docker.volumes.get(volume)
164
                 self.registry_dir = self.volume.attrs['Mountpoint']
164
                 self.registry_dir = self.volume.attrs['Mountpoint']
171
                     self.registry_dir = "/var/lib/registry"
171
                     self.registry_dir = "/var/lib/registry"
172
             return
172
             return
173
 
173
 
174
-        try:
175
-            self.info = self.docker.api.inspect_container(container)
176
-            self.container = self.info['Id']
177
-        except (APIError, exceptions.ConnectionError) as err:
178
-            error(err)
174
+        self._get_info(container_or_service)
179
 
175
 
180
         if not re.match("registry:2(@sha256:[0-9a-f]{64})?$", self.info['Config']['Image']):
176
         if not re.match("registry:2(@sha256:[0-9a-f]{64})?$", self.info['Config']['Image']):
181
-            error("The container %s is not running the registry:2 image" % (container))
177
+            error("%s is not running the registry:2 image" % (container_or_service))
182
 
178
 
183
         if LooseVersion(self.get_image_version()) < LooseVersion("v2.4.0"):
179
         if LooseVersion(self.get_image_version()) < LooseVersion("v2.4.0"):
184
             error("You're not running Docker Registry 2.4.0+")
180
             error("You're not running Docker Registry 2.4.0+")
194
         except FileNotFoundError as err:
190
         except FileNotFoundError as err:
195
             error(err)
191
             error(err)
196
 
192
 
197
-        if self.container is not None:
198
-            self.docker.api.stop(self.container)
193
+        # We could use stop() but the orchestrator would start another container
194
+        if self.containers is not None:
195
+            for container in self.containers:
196
+                if self.info['State']['Running']:
197
+                    self.docker.api.pause(container)
199
 
198
 
200
         images = args.images or \
199
         images = args.images or \
201
             map(os.path.dirname, iglob("**/_manifests", recursive=True))
200
             map(os.path.dirname, iglob("**/_manifests", recursive=True))
208
         if not self.garbage_collect():
207
         if not self.garbage_collect():
209
             exit_status = 1
208
             exit_status = 1
210
 
209
 
211
-        if self.container is not None:
212
-            self.docker.api.start(self.container)
210
+        if self.containers is not None:
211
+            for container in self.containers:
212
+                if self.info['State']['Running']:
213
+                    self.docker.api.unpause(container)
213
 
214
 
214
         self.docker.close()
215
         self.docker.close()
215
         return exit_status
216
         return exit_status
216
 
217
 
218
+    def _get_info(self, container_or_service):
219
+        self.containers = []
220
+
221
+        # Is a service?
222
+        try:
223
+            service = self.docker.services.get(container_or_service)
224
+        except NotFound:
225
+            pass
226
+        except (APIError, exceptions.ConnectionError) as err:
227
+            error(err)
228
+        else:
229
+            # Get list of containers to pause them all
230
+            try:
231
+                tasks = service.tasks(filters={'desired-state': "running"})
232
+            except (APIError, NotFound, exceptions.ConnectionError) as err:
233
+                error(err)
234
+            self.containers = [
235
+                item['Status']['ContainerStatus']['ContainerID']
236
+                for _, item in enumerate(tasks)
237
+            ]
238
+
239
+        # Get information from the first container in list.
240
+        # We can't get the source of /var/lib/registry from inspect_service()
241
+        #   if a bind mount was not specified.
242
+        try:
243
+            self.info = self.docker.api.inspect_container(
244
+                self.containers[0] if self.containers else container_or_service
245
+            )
246
+        except (APIError, NotFound, exceptions.ConnectionError) as err:
247
+            error(err)
248
+        if not self.containers:
249
+            self.containers = [self.info['Id']]
250
+
217
     def get_file(self, path):
251
     def get_file(self, path):
218
         '''Returns the contents of the specified file from the container'''
252
         '''Returns the contents of the specified file from the container'''
219
         try:
253
         try:
220
             with BytesIO(b"".join(
254
             with BytesIO(b"".join(
221
-                    _ for _ in self.docker.api.get_archive(self.container, path)[0]
255
+                    _ for _ in self.docker.api.get_archive(self.containers[0], path)[0]
222
             )) as buf, tarfile.open(fileobj=buf) \
256
             )) as buf, tarfile.open(fileobj=buf) \
223
                     as tar, tar.extractfile(os.path.basename(path)) \
257
                     as tar, tar.extractfile(os.path.basename(path)) \
224
                     as infile:
258
                     as infile:
263
         '''Gets the Docker distribution version running on the container'''
297
         '''Gets the Docker distribution version running on the container'''
264
         if self.info['State']['Running']:
298
         if self.info['State']['Running']:
265
             data = self.docker.containers.get(
299
             data = self.docker.containers.get(
266
-                self.container
300
+                self.containers[0]
267
             ).exec_run("/bin/registry --version").output
301
             ).exec_run("/bin/registry --version").output
268
         else:
302
         else:
269
             data = self.docker.containers.run(
303
             data = self.docker.containers.run(
270
-                self.info["Image"], command="--version", remove=True
304
+                self.info['Config']['Image'], command="--version", remove=True
271
             )
305
             )
272
         return data.decode('utf-8').split()[2]
306
         return data.decode('utf-8').split()[2]
273
 
307
 
308
 def main():
342
 def main():
309
     '''Main function'''
343
     '''Main function'''
310
     progname = os.path.basename(sys.argv[0])
344
     progname = os.path.basename(sys.argv[0])
311
-    usage = "\rUsage: " + progname + " [OPTIONS] VOLUME|CONTAINER [REPOSITORY[:TAG]]..." + """
345
+    usage = "\rUsage: " + progname + " [OPTIONS] SERVICE|CONTAINER|VOLUME [REPOSITORY[:TAG]]..." + """
312
 Options:
346
 Options:
313
         -x, --remove    Remove the specified images or repositories.
347
         -x, --remove    Remove the specified images or repositories.
314
         -v, --volume    Specify a volume instead of container.
348
         -v, --volume    Specify a volume instead of container.
321
     parser.add_argument('-x', '--remove', action='store_true')
355
     parser.add_argument('-x', '--remove', action='store_true')
322
     parser.add_argument('-v', '--volume', action='store_true')
356
     parser.add_argument('-v', '--volume', action='store_true')
323
     parser.add_argument('-V', '--version', action='store_true')
357
     parser.add_argument('-V', '--version', action='store_true')
324
-    parser.add_argument('container_or_volume', nargs='?')
358
+    parser.add_argument('foobar', nargs='?')
325
     parser.add_argument('images', nargs='*')
359
     parser.add_argument('images', nargs='*')
326
     global args
360
     global args
327
     args = parser.parse_args()
361
     args = parser.parse_args()
332
     elif args.version:
366
     elif args.version:
333
         print(progname + " " + VERSION)
367
         print(progname + " " + VERSION)
334
         sys.exit(0)
368
         sys.exit(0)
335
-    elif not args.container_or_volume:
369
+    elif not args.foobar:
336
         print('usage: ' + usage)
370
         print('usage: ' + usage)
337
         sys.exit(1)
371
         sys.exit(1)
338
 
372
 
344
         error("The -x option requires that you specify at least one repository...")
378
         error("The -x option requires that you specify at least one repository...")
345
 
379
 
346
     if args.volume:
380
     if args.volume:
347
-        cleaner = RegistryCleaner(volume=args.container_or_volume)
381
+        cleaner = RegistryCleaner(volume=args.foobar)
348
     else:
382
     else:
349
-        cleaner = RegistryCleaner(container=args.container_or_volume)
383
+        cleaner = RegistryCleaner(container_or_service=args.foobar)
350
 
384
 
351
     sys.exit(cleaner())
385
     sys.exit(cleaner())
352
 
386
 

Loading…
Cancelar
Guardar