summaryrefslogtreecommitdiff
path: root/buildstream/_artifactcache/pushreceive.py
diff options
context:
space:
mode:
authorSam Thursfield <sam.thursfield@codethink.co.uk>2017-11-16 12:50:31 +0000
committerSam Thursfield <sam.thursfield@codethink.co.uk>2017-11-22 15:03:53 +0000
commit5b7d0420bcdaa32cc8083edeb7d905fbe8caa1d4 (patch)
tree83244057659acbc5b7f9ceebf81c71cfa146d3c8 /buildstream/_artifactcache/pushreceive.py
parent4eb33736e1171734a8f4ed93976c0399aa8d85b3 (diff)
downloadbuildstream-5b7d0420bcdaa32cc8083edeb7d905fbe8caa1d4.tar.gz
Artifact push URLs must redirect to the corresponding pull URL
This change is part of issue #112 ("Artifact configuration is confusing and fragile, need canonical push/pull urls.") It updates the bst-artifact-receive program to send a pull URL to clients who access it over SSH. This requires extra configuration in the artifact cache server, so that it knows the correct pull URL. Versions of BuildStream which contain this commit will not be able to communicate over SSH with artifact caches that have not been updated to the same version. Currently this is just used to double-check user configuration, but we can now simplify the user facing configuration for artifact caches completely.
Diffstat (limited to 'buildstream/_artifactcache/pushreceive.py')
-rw-r--r--buildstream/_artifactcache/pushreceive.py60
1 files changed, 49 insertions, 11 deletions
diff --git a/buildstream/_artifactcache/pushreceive.py b/buildstream/_artifactcache/pushreceive.py
index 9aef842a8..18905fed3 100644
--- a/buildstream/_artifactcache/pushreceive.py
+++ b/buildstream/_artifactcache/pushreceive.py
@@ -136,8 +136,8 @@ class PushMessageWriter(object):
self.file.flush()
def send_hello(self):
- # The 'hello' message is used to check connectivity, and is actually
- # an empty info request in order to keep the receiver code simple.
+ # The 'hello' message is used to check connectivity and discover the
+ # cache's pull URL. It's actually transmitted as an empty info request.
args = {
'mode': GLib.Variant('i', 0),
'refs': GLib.Variant('a{ss}', {})
@@ -145,7 +145,7 @@ class PushMessageWriter(object):
command = PushCommand(PushCommandType.info, args)
self.write(command)
- def send_info(self, repo, refs):
+ def send_info(self, repo, refs, pull_url=None):
cmdtype = PushCommandType.info
mode = repo.get_mode()
@@ -161,6 +161,12 @@ class PushMessageWriter(object):
'mode': GLib.Variant('i', mode),
'refs': GLib.Variant('a{ss}', ref_map)
}
+
+ # The server sends this so clients can discover the correct pull URL
+ # for this cache without requiring end-users to specify it.
+ if pull_url:
+ args['pull_url'] = GLib.Variant('s', pull_url)
+
command = PushCommand(cmdtype, args)
self.write(command)
@@ -511,9 +517,16 @@ class OSTreePusher(object):
return self.close()
+# OSTreeReceiver is on the receiving end of an OSTree push.
+#
+# Args:
+# repopath (str): On-disk location of the receiving repository.
+# pull_url (str): Redirection for clients who want to pull, not push.
+#
class OSTreeReceiver(object):
- def __init__(self, repopath):
+ def __init__(self, repopath, pull_url):
self.repopath = repopath
+ self.pull_url = pull_url
if self.repopath is None:
self.repo = OSTree.Repo.new_default()
@@ -552,7 +565,8 @@ class OSTreeReceiver(object):
remote_refs = args['refs']
# Send info back
- self.writer.send_info(self.repo, list(remote_refs.keys()))
+ self.writer.send_info(self.repo, list(remote_refs.keys()),
+ pull_url=self.pull_url)
# Wait for update or done command
cmdtype, args = self.reader.receive([PushCommandType.update,
@@ -606,19 +620,28 @@ class OSTreeReceiver(object):
return 0
-# check_push_connection()
+# initialize_push_connection()
+#
+# Test that we can connect to the remote bst-artifact-receive program, and
+# receive the pull URL for this artifact cache.
#
-# Test that we can connect to the remote bst-artifact-receive program.
# We don't want to make the user wait until the first artifact has been built
-# to discover that they actually cannot push.
+# to discover that they actually cannot push, so this should be called early.
+#
+# The SSH push protocol doesn't allow pulling artifacts. We don't want to
+# require users to specify two URLs for a single cache, so we have the push
+# protocol return the corresponding pull URL as part of the 'hello' response.
#
# Args:
# remote: The ssh remote url to push to
# remote_port: The ssh port at the remote url
#
+# Returns:
+# (str): The URL that should be used for pushing to this cache.
+#
# Raises:
# PushException if there was an issue connecting to the remote.
-def check_push_connection(remote, remote_port):
+def initialize_push_connection(remote, remote_port):
remote_host, remote_user, remote_repo, remote_port = parse_remote_location(remote, remote_port)
ssh_cmd = ssh_commandline(remote_host, remote_user, remote_port)
@@ -632,7 +655,18 @@ def check_push_connection(remote, remote_port):
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
writer = PushMessageWriter(ssh.stdin)
+ reader = PushMessageReader(ssh.stdout)
+
writer.send_hello()
+ args = reader.receive_info()
+
+ if 'pull_url' in args:
+ pull_url = args['pull_url']
+ else:
+ raise PushException(
+ "Remote cache did not tell us its pull URL. This cache probably "
+ "requires updating to a newer version of `bst-artifact-receive`.")
+
writer.send_done()
ssh.wait()
@@ -640,6 +674,8 @@ def check_push_connection(remote, remote_port):
error = ssh.stderr.read().decode('unicode-escape')
raise PushException(error)
+ return pull_url
+
# push()
#
@@ -691,8 +727,10 @@ def push(repo, remote, remote_port, branches, output):
@click.command(short_help="Receive pushed artifacts over ssh")
@click.option('--verbose', '-v', is_flag=True, default=False, help="Verbose mode")
@click.option('--debug', '-d', is_flag=True, default=False, help="Debug mode")
+@click.option('--pull-url', type=str, required=True,
+ help="Clients who try to pull over SSH will be redirected here")
@click.argument('repo')
-def receive_main(verbose, debug, repo):
+def receive_main(verbose, debug, pull_url, repo):
"""A BuildStream sister program for receiving artifacts send to a shared artifact cache
"""
loglevel = logging.WARNING
@@ -703,5 +741,5 @@ def receive_main(verbose, debug, repo):
logging.basicConfig(format='%(module)s: %(levelname)s: %(message)s',
level=loglevel, stream=sys.stderr)
- receiver = OSTreeReceiver(repo)
+ receiver = OSTreeReceiver(repo, pull_url)
return receiver.run()