Зачем и как мы бэкапим github

от автора

Позвольте мне для начала немного пофилософствовать на тему технологий. Технологии позволяют нам концентрироваться на результате, на конечной цели, дают ощущение контроля. Вот вы в белоснежном кителе на мостике своего технологичного лайнера выходите в очередной плавание. Ваш лайнер снаряжен всем необходимым, чтобы противостоять любой проблеме. Вам не страшны волны, айсберги и даже пьяные боцманы.

Вообще лирическое вступление было навеяно вполне конкретной историей про сломанный гитхаб. Сделанная на заре одного из проектов синхронизация домашнего репо в гитхаб решила проблему переезда. Потом про костыль забыли. Древнее зло уснуло и терпеливо ждало своего часа. В один прекрасный день скайнет новый сотрудник решил привести в порядок тот самый домашний репозиторий. И самым популярным вопросом среди программистов в тот день было «коллега, а вы не видели мою ветку 0022? ну такая, с багфиксами». Руководство опс-тим было спокойно как никогда: гит — это распределенная система, версия кода хранится на персональном компьютере каждого разработчика. Давайте уже как-нибудь разберитесь между собой и не отвлекайте нас от сборки наших ядер и тюнингов сетевых стеков.

И все же зачем..?

Действительно, можно нафантазировать большое количество количество возможных проблем, например:

  • Недоступность удаленного репозитория и отсутсвие актуальной локальной копии
  • Злоумышленники с помощью украденного пароля испортили/удалили репозитории
  • Ошибки в манипуляциях с репозиториями
Итак, что и как бэкапить…


Итак, вот вкратце наш хитрый план действий:

  1. Получаем список репозиториев для организации
  2. Клонируем репозитории поз полученного списка
  3. Архивируем
  4. Кладем в AWS S3
Немного больше конкретики в случае использования github.com

Разумно завести для процедуры бэкапа отдельного readonly-пользователя. Так же необходимо сгенерировать для него token(Settings -> Personal Access Tokens -> Generate new token).

Для начала с помощью pygithub3 получаем репозитории, которые мы впоследствии собираемся бэкапить:

from pygithub3 import Github  def get_repos(args):     config = {'token': args.token}     gh = Github(**config)      return gh.repos.list_by_org(args.organization).all() 

Для клонирования будем использовать консольный git:

def clone_repo(repo_list,args):      if os.path.isdir(args.directory):         shutil.rmtree(args.directory)      os.mkdir(args.directory)      if args.mirror is True:         args.git += " --mirror"      for repo in repo_list:         repo_url = "https://%(token)s:x-oauth-basic@github.com/%(organization)s/%(repo)s.git" % {'token': args.token,                                                                                                  'organization': args.organization,                                                                                                  'repo': repo.name}          os.system('git clone %(arguments)s %(repo_url)s %(directory)s/%(repo)s' % {'arguments': args.git,                                                                                    'repo_url': repo_url,                                                                                    'directory': args.directory, 'repo': repo.name}) 

Обратите внимание на опцию "—mirror" — с помощью нее создается зеркальная копия удаленного репозитория.

Кстати, в случае использования bitbucket.org…

Получаем список репозиториев:

def _get_repositories(owner, username, password):     auth_value = ('%s:%s' % (username, password)).encode('base64').strip()     headers = {'Authorization': 'Basic %s' % auth_value}     url = 'https://bitbucket.org/api/2.0/repositories/%s?role=member' % owner     values = []      while url is not None:         request = urllib2.Request(url, None, headers)         data = json.loads(urllib2.urlopen(request).read())         values = values + data['values']         url = data.get('next')      return values 

И клонируем:

def _git_clone(username, password, directory, sub_dir_name, owner, slug, verbose=False):     os.chdir(directory)     cmd = 'git clone --mirror https://%s:%s@bitbucket.org/%s/%s.git %s' % (username, password,                                                                   owner, slug, sub_dir_name)     proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)     ret_value = proc.wait()     msg = proc.stdout.read()     sys.stdout.write('%s%s%s%s' % (sub_dir_name, os.linesep,                                    '=' * len(sub_dir_name), os.linesep))     sys.stdout.write("%s%s" % (msg, os.linesep))     return ret_value 

Кстати, slug — это url-friendly название вашего репо в bitbucket.

Готовый скрипт для github можно найти тут.

ссылка на оригинал статьи http://habrahabr.ru/post/273513/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *