Created
December 18, 2023 10:11
-
-
Save b0tting/0e3658b53f3270c599be45fc061c48b7 to your computer and use it in GitHub Desktop.
Script used to move all container images from one Gitlab registry to another, including every tag. This script first pulls all containers with all tags to the system running the script, then retags with the new registry and pushes the images to the target repository.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import sys | |
import requests | |
from docker.errors import DockerException | |
try: | |
import docker | |
except ImportError: | |
sys.exit("Please run 'pip install docker' first") | |
class GitlabContainerRegistry: | |
def __init__(self, gitlab_project, gitlab_token): | |
self.gitlab_project = gitlab_project | |
self.gitlab_token = gitlab_token | |
self.gitlab_url = ( | |
"https://gitlab.com/api/v4/projects/" | |
+ gitlab_project | |
+ "/registry/repositories" | |
) | |
def pretty_print_repositories(self, repositories_dict): | |
repositories = json.dumps(repositories_dict, indent=4) | |
print(repositories) | |
def get_repositories(self): | |
response = requests.get( | |
self.gitlab_url, headers={"PRIVATE-TOKEN": self.gitlab_token} | |
) | |
if response.status_code != 200: | |
raise Exception(response.text) | |
repositories = response.json() | |
self.enrich_repositories_with_tags(repositories) | |
return repositories | |
def enrich_repositories_with_tags(self, repositories): | |
for repository in repositories: | |
repository["tags"] = self.get_repository_tags(repository["id"]) | |
def get_repository_tags(self, repository_id): | |
response = requests.get( | |
self.gitlab_url + "/" + str(repository_id) + "/tags", | |
headers={"PRIVATE-TOKEN": self.gitlab_token}, | |
) | |
if response.status_code != 200: | |
raise Exception(response.text) | |
return response.json() | |
class DockerPuller: | |
def __init__(self, username, password): | |
try: | |
self.client = docker.from_env() | |
self.auth = { | |
"username": username, | |
"password": password, | |
} | |
except DockerException as e: | |
print("Is Docker running?") | |
sys.exit("Could not connect to docker daemon: " + str(e)) | |
def pull_image(self, image_name, all_tags=True): | |
print("Pulling " + image_name) | |
self.client.images.pull(image_name, all_tags=all_tags, auth_config=self.auth) | |
print("Done") | |
class DockerPusher: | |
def __init__(self, username, password): | |
try: | |
self.client = docker.from_env() | |
self.auth = { | |
"username": username, | |
"password": password, | |
} | |
except DockerException as e: | |
print("Is Docker running?") | |
sys.exit("Could not connect to docker daemon: " + str(e)) | |
def push_images_to_registry(self, source_registry, target_registry): | |
images = self.client.images.list() | |
for image in images: | |
for tag in image.tags: | |
if tag.startswith(source_registry): | |
print("Pushing " + tag) | |
new_tag = self.retag_image( | |
image, tag, target_registry | |
) # Retag does not remove original tags | |
self.client.images.push(new_tag, auth_config=self.auth) | |
print("Pushed " + new_tag) | |
else: | |
print( | |
"Skipping " + tag + " as it does not match " + source_registry | |
) | |
def retag_image(self, image, tag, registry_path): | |
image_name_clean = tag.split("/")[-1] | |
new_tag = registry_path + image_name_clean | |
image.tag(new_tag) | |
return new_tag | |
# Most of the wisdom comes from https://docs.gitlab.com/ee/api/container_registry.html | |
# To get your project ID, go to the project page and open "Project settings" | |
# It's the number shown next to the project name | |
# Step 0: | |
# Decide on either 2 project tokens or a single personal token | |
# You need the "developer" role and read_registry permission scope | |
source_project_id = "12345678" | |
source_project_token = "glpat-sometoken" | |
source_registry_url = "registry.gitlab.com/groupname/projectname/" | |
target_project_token = "glpat-someothertoken" | |
target_registry_url = "registry.gitlab.com/newgroupname/newprojectname/" | |
# Step 1: Gather required docker image names | |
gitlab_container = GitlabContainerRegistry(source_project_id, source_project_token) | |
repositories = gitlab_container.get_repositories() | |
# This just gets all tag information | |
# gitlab_container.pretty_print_repositories(repositories) | |
# Step 2: Pull all image names to local | |
docker_puller = DockerPuller("gitlab-ci-token", source_project_token) | |
for repository in repositories: | |
docker_puller.pull_image(repository["location"], all_tags=True) | |
# Step 3: Retag and push all images to new registry | |
# Source registry is mentioned here as it is in the container tags | |
# This step will not contact the source registry | |
docker_pusher = DockerPusher("gitlab-ci-token", target_project_token) | |
docker_pusher.push_images_to_registry( | |
source_registry=source_registry_url, | |
target_registry=target_registry_url, | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment