summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--buildstream/_artifactcache/ostreecache.py10
-rw-r--r--buildstream/_artifactcache/pushreceive.py60
-rw-r--r--doc/source/artifacts.rst4
3 files changed, 58 insertions, 16 deletions
diff --git a/buildstream/_artifactcache/ostreecache.py b/buildstream/_artifactcache/ostreecache.py
index e2e623e78..6b2411e7f 100644
--- a/buildstream/_artifactcache/ostreecache.py
+++ b/buildstream/_artifactcache/ostreecache.py
@@ -29,7 +29,7 @@ from ..element import _KeyStrength
from .._ostree import OSTreeError
from . import ArtifactCache
-from .pushreceive import check_push_connection
+from .pushreceive import initialize_push_connection
from .pushreceive import push as push_artifact
from .pushreceive import PushException
@@ -82,8 +82,12 @@ class OSTreeCache(ArtifactCache):
def preflight(self):
if self.can_push() and not self.artifact_push.startswith("/"):
try:
- check_push_connection(self.artifact_push,
- self.artifact_push_port)
+ pull_url = initialize_push_connection(self.artifact_push,
+ self.artifact_push_port)
+ if pull_url != self.artifact_pull:
+ raise ArtifactError(
+ "This cache reports its pull URL as {}, but user "
+ "configuration specifies {}.".format(pull_url, self.artifact_pull))
except PushException as e:
raise ArtifactError("BuildStream will be unable to push artifacts "
"to the shared cache: {}".format(e))
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()
diff --git a/doc/source/artifacts.rst b/doc/source/artifacts.rst
index 8ad2f600c..575f51a51 100644
--- a/doc/source/artifacts.rst
+++ b/doc/source/artifacts.rst
@@ -122,8 +122,8 @@ For this you will want something like the following in your ``/etc/ssh/sshd_conf
# bst-artifact-receive program, note that the full
# command must be specified here; 'artifacts' is
# the HOME relative path to the artifact cache.
- #
- ForceCommand bst-artifact-receive --verbose artifacts
+ # The exact pull URL must also be specified.
+ ForceCommand bst-artifact-receive --pull-url https://example.com/artifacts --verbose artifacts
Summary file updates