DevOps/GitLab

GitLab API를 활용한 마이그레이션

yscho03 2022. 5. 9. 13:18
728x90
반응형

개요

BACKUP & RESTORE를 사용하여 파일을 활용하는 방법이 가장 간단한 방법이긴 하다. 하지만 회사 보안상이나 서버에 접근이 불가하거나 여러 가지 이슈들로 인하여 API를 활용하여 마이그레이션을 활용해야 하는 경우가 있다.

 

시나리오

  1. GitLab (구서버 - old-gitlab.com) 에서 git clone 하여 로컬에 임의 디렉토리에 저장
  2. localhost에서 GitLab (새로운 서버 - new-gitlab.com)로 push

 

준비사항

  • GitLab Group Acesss Token 
  • Python 3.x

 

마이그레이션 방법

1. GitLab Server Group Acess Token 발급

GitLab API를 활용하여 마이그레이션 하기 위해서는 Group에 접근할 Token을 발급한다.

Group에 대한 권한이 없을 경우 개인 계정에 대하여 Token을 발급하여 활용한다.

  • 기존 GitLab 서버 - Group Access Token 발급
  • 새로운 GitLab 서버 - Group Access Token 발급 

2. Python 스크립트 작성

migration.py를 임의의 공간에 작성한다.

import argparse
import json
import shlex
import subprocess
import time
from urllib.parse import urlparse
from urllib.request import urlopen
import os
import tqdm

# 로컬에 저장받을 디렉토리
PROJECT_DIR = "D:\\gitlab"

# 기존 GitLab Acess Token 정보
SRC_USERNAME = "yscho03"
SRC_GITLAB_SERVER = "old-gitlab.com"
SRC_ACCESS_TOKEN = "xxxxxxxxxx"
SRC_GITLAB_GROUP = "test"

DEST_USERNAME = "yscho03"
DEST_GITLAB_SERVER = "new-gitlab.com"
DEST_ACCESS_TOKEN = "xxxxxxxxxx"


def clone_to_local():
    project_info = urlopen(
        "https://{}/api/v4/projects?private_token={}&per_page=10000".format(SRC_GITLAB_SERVER, SRC_ACCESS_TOKEN))
    projects = json.loads(project_info.read().decode())
    pbar = tqdm.trange(len(projects))

    for i, v in enumerate(pbar):
        try:
            project = projects[i]
            if project['namespace']['name'] != SRC_GITLAB_GROUP:
                continue
            project_url = project['http_url_to_repo']
            parsed_url = urlparse(project_url)

            clone_url = "{}://{}:{}@{}{}".format(parsed_url.scheme, SRC_USERNAME, SRC_ACCESS_TOKEN,
                                                 parsed_url.netloc, parsed_url.path)
            command = 'cd {} && git clone {}'.format(PROJECT_DIR, clone_url)
            subprocess.call(command, shell=True, stdout=subprocess.PIPE)
        except Exception as e:
            print("error {}:{}".format(project_url, e))


def push_to_new_origin():
    for project_name in os.listdir(PROJECT_DIR):
        try:
            full_path = os.path.join(PROJECT_DIR, project_name)
            if not os.path.isdir(full_path):
                continue
            command = "cd {} && git remote get-url origin".format(full_path)
            pipe = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
            origin_url = pipe.communicate()[0].decode('utf-8')
            parsed_url = urlparse(origin_url)
            new_origin_url = "{}://{}:{}@{}{}".format(parsed_url.scheme, DEST_USERNAME, DEST_ACCESS_TOKEN,
                                                      DEST_GITLAB_SERVER,
                                                      parsed_url.path)
            command = 'cd {} && git pull && git remote set-url --push origin {} && git push'.format(full_path, new_origin_url)
            subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
        except Exception as e:
            print("error {}:{}".format(project_url, e))

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='GitLab Migration')
    parser.add_argument('--mode', type=str, help="clone or push", required=True)
    args = parser.parse_args()
    if args.mode == "clone":
        clone_to_local()
    elif args.mode == "push":
        push_to_new_origin()
    else:
        raise Exception("not found mode")

3. 기존 GitLab 서버에서 로컬로 Clone

D:\> python migration.py --mode clone
...
Delta compression using up to 4 threads
Compressing objects: 100% (8890/8890), done.114/518), 27.82 MiB | 11.11 MiB/s
Enumerating objects: 523, done., 27.82 MiB | 11.11 MiB/s
Counting objects: 100% (523/523), done.
...

4. 로컬에서 새로운 GitLab 서버로 Push

D:\> python migration.py --mode push
...
To https://new-gitlab.com/test/project.git
 * [new branch]      master -> master
Writing objects: 100% (10217/10217), 120.74 MiB | 1.44 MiB/s, done.
Total 10217 (delta 1158), reused 10197 (delta 1142)
remote: Resolving deltas: 100% (1158/1158), done.
...
728x90
반응형