Skip to content

Instantly share code, notes, and snippets.

@b0tting
Created December 18, 2023 10:11
Show Gist options
  • Save b0tting/0e3658b53f3270c599be45fc061c48b7 to your computer and use it in GitHub Desktop.
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.
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