From 7b9144890f7277c71d717d0ea72f44d2c3e23469 Mon Sep 17 00:00:00 2001 From: Celestino Rey Date: Tue, 20 Aug 2024 08:14:27 +0200 Subject: [PATCH] =?UTF-8?q?Aplicaci=C3=B3n=20para=20ver=20el=20regsitry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- RegistryPy/db.sqlite3 | Bin 0 -> 131072 bytes RegistryPy/docker_registry_viewer/__init__.py | 0 RegistryPy/docker_registry_viewer/asgi.py | 16 +++ RegistryPy/docker_registry_viewer/settings.py | 124 ++++++++++++++++++ RegistryPy/docker_registry_viewer/urls.py | 23 ++++ RegistryPy/docker_registry_viewer/wsgi.py | 16 +++ RegistryPy/manage.py | 22 ++++ RegistryPy/registry/__init__.py | 0 RegistryPy/registry/admin.py | 3 + RegistryPy/registry/apps.py | 6 + RegistryPy/registry/migrations/__init__.py | 0 RegistryPy/registry/models.py | 3 + .../templates/registry/registry_list.html | 43 ++++++ .../templates/registry/repository_detail.html | 48 +++++++ RegistryPy/registry/tests.py | 3 + RegistryPy/registry/urls.py | 9 ++ RegistryPy/registry/views.py | 64 +++++++++ 17 files changed, 380 insertions(+) create mode 100644 RegistryPy/db.sqlite3 create mode 100644 RegistryPy/docker_registry_viewer/__init__.py create mode 100644 RegistryPy/docker_registry_viewer/asgi.py create mode 100644 RegistryPy/docker_registry_viewer/settings.py create mode 100644 RegistryPy/docker_registry_viewer/urls.py create mode 100644 RegistryPy/docker_registry_viewer/wsgi.py create mode 100755 RegistryPy/manage.py create mode 100644 RegistryPy/registry/__init__.py create mode 100644 RegistryPy/registry/admin.py create mode 100644 RegistryPy/registry/apps.py create mode 100644 RegistryPy/registry/migrations/__init__.py create mode 100644 RegistryPy/registry/models.py create mode 100644 RegistryPy/registry/templates/registry/registry_list.html create mode 100644 RegistryPy/registry/templates/registry/repository_detail.html create mode 100644 RegistryPy/registry/tests.py create mode 100644 RegistryPy/registry/urls.py create mode 100644 RegistryPy/registry/views.py diff --git a/RegistryPy/db.sqlite3 b/RegistryPy/db.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..8a4ee616c24a8829d87561a04059ab5ab6e4b79d GIT binary patch literal 131072 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 + + + Docker Registry Viewer + + + +

Docker Registry Viewer

+ + + + + + + + + {% for repo in data %} + + + + + {% endfor %} + +
RepositoryTags
{{ repo.repository }} + {% for tag in repo.tags %} + {{ tag }}{% if not forloop.last %}, {% endif %} + {% endfor %} +
+ + diff --git a/RegistryPy/registry/templates/registry/repository_detail.html b/RegistryPy/registry/templates/registry/repository_detail.html new file mode 100644 index 0000000..89ec019 --- /dev/null +++ b/RegistryPy/registry/templates/registry/repository_detail.html @@ -0,0 +1,48 @@ + + + + Repository Details - {{ repository }} + + + +

Tags for {{ repository }}

+ {% if error %} +

{{ error }}

+ {% endif %} + + + + + + + + + {% for tag in tags %} + + + + + {% endfor %} + +
TagsActions
{{ tag }}Delete
+

Back to Repository List

+ + diff --git a/RegistryPy/registry/tests.py b/RegistryPy/registry/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/RegistryPy/registry/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/RegistryPy/registry/urls.py b/RegistryPy/registry/urls.py new file mode 100644 index 0000000..5af8725 --- /dev/null +++ b/RegistryPy/registry/urls.py @@ -0,0 +1,9 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path('', views.registry_list, name='registry_list'), + path('/', views.repository_detail, name='repository_detail'), + path('/delete//', views.delete_tag, name='delete_tag'), +] + diff --git a/RegistryPy/registry/views.py b/RegistryPy/registry/views.py new file mode 100644 index 0000000..2cb6ee8 --- /dev/null +++ b/RegistryPy/registry/views.py @@ -0,0 +1,64 @@ +import requests +from django.shortcuts import render, redirect +from django.urls import reverse + +DOCKER_REGISTRY_URL = "https://registry.reymota.es/v2" +REGISTRY_USERNAME = "creylopez" +REGISTRY_PASSWORD = "Rey-1176" + +def get_docker_registry_data(): + # Autenticarse en el registro Docker + response = requests.get(f"{DOCKER_REGISTRY_URL}/_catalog", auth=(REGISTRY_USERNAME, REGISTRY_PASSWORD)) + + if response.status_code == 200: + repositories = response.json().get('repositories', []) + registry_data = [] + + for repo in repositories: + tags_response = requests.get(f"{DOCKER_REGISTRY_URL}/{repo}/tags/list", auth=(REGISTRY_USERNAME, REGISTRY_PASSWORD)) + if tags_response.status_code == 200: + tags = tags_response.json().get('tags', []) + registry_data.append({'repository': repo, 'tags': tags}) + + return registry_data + else: + return [] + +def registry_list(request): + data = get_docker_registry_data() + return render(request, 'registry/registry_list.html', {'data': data}) + +# Nueva vista para mostrar los detalles de un repositorio especĂ­fico +def repository_detail(request, repository_name): + tags_response = requests.get(f"{DOCKER_REGISTRY_URL}/{repository_name}/tags/list", auth=(REGISTRY_USERNAME, REGISTRY_PASSWORD)) + + if tags_response.status_code == 200: + tags = tags_response.json().get('tags', []) + else: + tags = [] + + return render(request, 'registry/repository_detail.html', {'repository': repository_name, 'tags': tags}) + +# Vista para eliminar un tag especĂ­fico +def delete_tag(request, repository_name, tag): + manifest_url = f"{DOCKER_REGISTRY_URL}/{repository_name}/manifests/{tag}" + + # Obtener el digest del tag + manifest_response = requests.head(manifest_url, auth=(REGISTRY_USERNAME, REGISTRY_PASSWORD), headers={"Accept": "application/vnd.docker.distribution.manifest.v2+json"}) + print("delete_tag: manifest_url ", manifest_url) + if manifest_response.status_code == 200: + digest = manifest_response.headers.get('Docker-Content-Digest') + delete_response = requests.delete(f"{DOCKER_REGISTRY_URL}/{repository_name}/manifests/{digest}", auth=(REGISTRY_USERNAME, REGISTRY_PASSWORD)) + print("delete_tag: digest->",digest) + if delete_response.status_code == 202: + return redirect(reverse('repository_detail', args=[repository_name])) + else: + # Obtener las etiquetas nuevamente para renderizar la plantilla + tags_response = requests.get(f"{DOCKER_REGISTRY_URL}/{repository_name}/tags/list", auth=(REGISTRY_USERNAME, REGISTRY_PASSWORD)) + tags = tags_response.json().get('tags', []) if tags_response.status_code == 200 else [] + return render(request, 'registry/repository_detail.html', {'repository': repository_name, 'tags': tags, 'error': 'Error deleting the tag.'}) + else: + # Obtener las etiquetas nuevamente para renderizar la plantilla + tags_response = requests.get(f"{DOCKER_REGISTRY_URL}/{repository_name}/tags/list", auth=(REGISTRY_USERNAME, REGISTRY_PASSWORD)) + tags = tags_response.json().get('tags', []) if tags_response.status_code == 200 else [] + return render(request, 'registry/repository_detail.html', {'repository': repository_name, 'tags': tags, 'error': 'Tag not found.'}) \ No newline at end of file