docker-artifact/repobot/replication.py

77 lines
2.6 KiB
Python

from urllib.parse import urlparse, urlunsplit, urlencode
from time import sleep
from threading import Thread
from repobot.provider import providers
import logging
import os
from requests import post
log = logging.getLogger("replication")
class RepoReplicator(object):
def __init__(self, db, data_root, neighbors):
"""
:param neighbors: list of replication neighbor uris like 'http://1.2.3.4:8080'
"""
self.db = db
self.data_root = data_root
self.neighbors = [urlparse(i) for i in neighbors]
self.worker = None
def start(self):
if not self.neighbors:
return
self.worker = ReplicationWorker(self)
self.worker.start()
class ReplicationWorker(Thread):
def __init__(self, master):
super().__init__()
self.daemon = True
self.master = master
def run(self):
while True:
with self.master.db.db.transaction() as c:
# for item in c.root.sendqueue:
log.info("items in queue: %s", len(c.root.sendqueue))
if len(c.root.sendqueue) > 0:
item = c.root.sendqueue[0]
if self.replicate(item):
c.root.sendqueue.pop(0)
log.info("Replication successful")
sleep(5)
def replicate(self, item):
item_type, item = item
if item_type == "package":
return self.replicate_package(item)
def replicate_package(self, item):
repo, pkg, fname, params = item
datadir = os.path.join(self.master.data_root, repo.provider, repo.name)
provider = providers[repo.provider](self.master.db, repo, datadir)
fpath = provider.get_path(pkg, fname)
for neighbor in self.master.neighbors:
q_params = {"provider": repo.provider,
"reponame": repo.name,
"name": pkg.name,
"version": pkg.version}
q_params.update(**params)
url = urlunsplit(["http", neighbor.netloc, "/addpkg", urlencode(q_params), None])
with open(fpath, 'rb') as fitem:
try:
r = post(url, files={'f': (fname, fitem)}, timeout=(10, 30))
if r.status_code not in (200, 409):
r.raise_for_status()
except Exception as e:
log.warning("Failed replication of %s to %s: %s", pkg, neighbor.geturl(), str(e))
return False
log.info("Replicated %s to %s", pkg, neighbor.geturl())
return True