Daniel Playle pushed to branch dp0/casserver-tests at BuildStream / buildstream
Commits:
5 changed files:
- buildstream/_artifactcache/casserver.py
- + tests/frontend/creds/server_cert.pem
- + tests/frontend/creds/server_key.pem
- tests/frontend/push.py
- tests/testutils/artifactshare.py
Changes:
| ... | ... | @@ -42,6 +42,11 @@ from .cascache import CASCache |
| 42 | 42 |
class ArtifactTooLargeException(Exception):
|
| 43 | 43 |
pass
|
| 44 | 44 |
|
| 45 |
+class RequiresServerKeyPairException(Exception):
|
|
| 46 |
+ pass
|
|
| 47 |
+ |
|
| 48 |
+class RequiresServerKeyForClientAuthException(Exception):
|
|
| 49 |
+ pass
|
|
| 45 | 50 |
|
| 46 | 51 |
# create_server():
|
| 47 | 52 |
#
|
| ... | ... | @@ -72,27 +77,37 @@ def create_server(repo, *, enable_push): |
| 72 | 77 |
|
| 73 | 78 |
return server
|
| 74 | 79 |
|
| 75 |
- |
|
| 76 |
-@click.command(short_help="CAS Artifact Server")
|
|
| 77 |
-@click.option('--port', '-p', type=click.INT, required=True, help="Port number")
|
|
| 78 |
-@click.option('--server-key', help="Private server key for TLS (PEM-encoded)")
|
|
| 79 |
-@click.option('--server-cert', help="Public server certificate for TLS (PEM-encoded)")
|
|
| 80 |
-@click.option('--client-certs', help="Public client certificates for TLS (PEM-encoded)")
|
|
| 81 |
-@click.option('--enable-push', default=False, is_flag=True,
|
|
| 82 |
- help="Allow clients to upload blobs and update artifact cache")
|
|
| 83 |
-@click.argument('repo')
|
|
| 84 |
-def server_main(repo, port, server_key, server_cert, client_certs, enable_push):
|
|
| 85 |
- server = create_server(repo, enable_push=enable_push)
|
|
| 86 |
- |
|
| 80 |
+# setup_server():
|
|
| 81 |
+#
|
|
| 82 |
+# Creates a port on the given server. This port either be secured or unsecured.
|
|
| 83 |
+# This is dependent on the optional credential arguments.
|
|
| 84 |
+#
|
|
| 85 |
+# Either none or both of server_key and server_cert must be specified. If
|
|
| 86 |
+# client_certs is specified, then both server_key and server_cert must be
|
|
| 87 |
+# specified.
|
|
| 88 |
+#
|
|
| 89 |
+# If the caller of this function does not care what port is used, this decision
|
|
| 90 |
+# can be made by the gRPC runtime by specifying port 0. The port that is
|
|
| 91 |
+# actually used is returned.
|
|
| 92 |
+#
|
|
| 93 |
+# Args:
|
|
| 94 |
+# server (grpc.server): The server to open a port on
|
|
| 95 |
+# address (str): The address to bind the port on
|
|
| 96 |
+# port (int): The port number to bind on. 0 if the gRPC runtime should pick
|
|
| 97 |
+# server_key (str): The filename of the server private key file
|
|
| 98 |
+# server_cert (str): The filename of the server public cert file
|
|
| 99 |
+# client_certs (str): The filename of the client public certs file
|
|
| 100 |
+#
|
|
| 101 |
+# Returns:
|
|
| 102 |
+# int: The actual port that was opened for this server
|
|
| 103 |
+def setup_server(server, address, port, server_key=None, server_cert=None, client_certs=None):
|
|
| 87 | 104 |
use_tls = bool(server_key)
|
| 88 | 105 |
|
| 89 | 106 |
if bool(server_cert) != use_tls:
|
| 90 |
- click.echo("ERROR: --server-key and --server-cert are both required for TLS", err=True)
|
|
| 91 |
- sys.exit(-1)
|
|
| 107 |
+ raise RequiresServerKeyPairException()
|
|
| 92 | 108 |
|
| 93 | 109 |
if client_certs and not use_tls:
|
| 94 |
- click.echo("ERROR: --client-certs can only be used with --server-key", err=True)
|
|
| 95 |
- sys.exit(-1)
|
|
| 110 |
+ raise RequiresServerKeyForClientAuthException()
|
|
| 96 | 111 |
|
| 97 | 112 |
if use_tls:
|
| 98 | 113 |
# Read public/private key pair
|
| ... | ... | @@ -110,9 +125,30 @@ def server_main(repo, port, server_key, server_cert, client_certs, enable_push): |
| 110 | 125 |
credentials = grpc.ssl_server_credentials([(server_key_bytes, server_cert_bytes)],
|
| 111 | 126 |
root_certificates=client_certs_bytes,
|
| 112 | 127 |
require_client_auth=bool(client_certs))
|
| 113 |
- server.add_secure_port('[::]:{}'.format(port), credentials)
|
|
| 128 |
+ return server.add_secure_port('{}:{}'.format(address, port), credentials)
|
|
| 114 | 129 |
else:
|
| 115 |
- server.add_insecure_port('[::]:{}'.format(port))
|
|
| 130 |
+ return server.add_insecure_port('{}:{}'.format(address, port))
|
|
| 131 |
+ |
|
| 132 |
+ |
|
| 133 |
+@click.command(short_help="CAS Artifact Server")
|
|
| 134 |
+@click.option('--port', '-p', type=click.INT, required=True, help="Port number")
|
|
| 135 |
+@click.option('--server-key', help="Private server key for TLS (PEM-encoded)")
|
|
| 136 |
+@click.option('--server-cert', help="Public server certificate for TLS (PEM-encoded)")
|
|
| 137 |
+@click.option('--client-certs', help="Public client certificates for TLS (PEM-encoded)")
|
|
| 138 |
+@click.option('--enable-push', default=False, is_flag=True,
|
|
| 139 |
+ help="Allow clients to upload blobs and update artifact cache")
|
|
| 140 |
+@click.argument('repo')
|
|
| 141 |
+def server_main(repo, port, server_key, server_cert, client_certs, enable_push):
|
|
| 142 |
+ server = create_server(repo, enable_push=enable_push)
|
|
| 143 |
+ |
|
| 144 |
+ try:
|
|
| 145 |
+ setup_server(server, '[::]', port, server_key, server_cert, client_certs)
|
|
| 146 |
+ except RequiresServerKeyPairException:
|
|
| 147 |
+ click.echo("ERROR: --server-key and --server-cert are both required for TLS", err=True)
|
|
| 148 |
+ sys.exit(-1)
|
|
| 149 |
+ except RequiresServerKeyForClientAuthException:
|
|
| 150 |
+ click.echo("ERROR: --client-certs can only be used with --server-key", err=True)
|
|
| 151 |
+ sys.exit(-1)
|
|
| 116 | 152 |
|
| 117 | 153 |
# Run artifact server
|
| 118 | 154 |
server.start()
|
| 1 |
+-----BEGIN CERTIFICATE-----
|
|
| 2 |
+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
|
|
| 29 |
+-----END CERTIFICATE-----
|
| 1 |
+-----BEGIN PRIVATE KEY-----
|
|
| 2 |
+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
|
|
| 51 |
+e+XVdfiURwWj6Q7/y/Rujtp7K6z2dA==
|
|
| 52 |
+-----END PRIVATE KEY-----
|
| ... | ... | @@ -35,6 +35,22 @@ DATA_DIR = os.path.join( |
| 35 | 35 |
"project",
|
| 36 | 36 |
)
|
| 37 | 37 |
|
| 38 |
+# Credential directory
|
|
| 39 |
+CRED_DIR = os.path.join(
|
|
| 40 |
+ os.path.dirname(os.path.realpath(__file__)),
|
|
| 41 |
+ "creds",
|
|
| 42 |
+)
|
|
| 43 |
+ |
|
| 44 |
+# Parameters for credentials
|
|
| 45 |
+CREDENTIAL_FILENAMES = {
|
|
| 46 |
+ 'unsecured': {},
|
|
| 47 |
+ |
|
| 48 |
+ 'server_secured': {
|
|
| 49 |
+ 'server_key': 'server_key.pem',
|
|
| 50 |
+ 'server_cert': 'server_cert.pem',
|
|
| 51 |
+ },
|
|
| 52 |
+}
|
|
| 53 |
+ |
|
| 38 | 54 |
|
| 39 | 55 |
# Assert that a given artifact is in the share
|
| 40 | 56 |
#
|
| ... | ... | @@ -60,14 +76,41 @@ def assert_not_shared(cli, share, project, element_name): |
| 60 | 76 |
.format(share.repo, element_name))
|
| 61 | 77 |
|
| 62 | 78 |
|
| 79 |
+# Taking a dictionary of filenames, this returns a dictionary of qualified
|
|
| 80 |
+# fielnames
|
|
| 81 |
+def join_credentials_path(credential_filenames, credential_files):
|
|
| 82 |
+ return {
|
|
| 83 |
+ key: os.path.join(credential_files, filename)
|
|
| 84 |
+ for key, filename in credential_filenames.items()
|
|
| 85 |
+ }
|
|
| 86 |
+ |
|
| 87 |
+ |
|
| 88 |
+# Adds the server certificate to the configuration if it exists and returns
|
|
| 89 |
+# this for ease of use
|
|
| 90 |
+def add_client_config_creds(configuration, credentials):
|
|
| 91 |
+ if 'server_cert' in credentials:
|
|
| 92 |
+ artifacts = configuration['artifacts']
|
|
| 93 |
+ if isinstance(artifacts, (list,)):
|
|
| 94 |
+ for subconfig in artifacts:
|
|
| 95 |
+ subconfig['server-cert'] = credentials['server_cert']
|
|
| 96 |
+ else:
|
|
| 97 |
+ artifacts['server-cert'] = credentials['server_cert']
|
|
| 98 |
+ return configuration
|
|
| 99 |
+ |
|
| 100 |
+ |
|
| 63 | 101 |
# Tests that:
|
| 64 | 102 |
#
|
| 65 | 103 |
# * `bst push` fails if there are no remotes configured for pushing
|
| 66 | 104 |
# * `bst push` successfully pushes to any remote that is configured for pushing
|
| 67 | 105 |
#
|
| 68 |
-@pytest.mark.datafiles(DATA_DIR)
|
|
| 69 |
-def test_push(cli, tmpdir, datafiles):
|
|
| 70 |
- project = str(datafiles)
|
|
| 106 |
+@pytest.mark.parametrize(
|
|
| 107 |
+ 'credential_filenames', CREDENTIAL_FILENAMES.values(), ids=list(CREDENTIAL_FILENAMES))
|
|
| 108 |
+@pytest.mark.datafiles(DATA_DIR, CRED_DIR, keep_top_dir=True)
|
|
| 109 |
+def test_push(cli, tmpdir, datafiles, credential_filenames):
|
|
| 110 |
+ project = os.path.join(datafiles, 'project')
|
|
| 111 |
+ credfiles = os.path.join(datafiles, 'creds')
|
|
| 112 |
+ |
|
| 113 |
+ credentials = join_credentials_path(credential_filenames, credfiles)
|
|
| 71 | 114 |
|
| 72 | 115 |
# First build the project without the artifact cache configured
|
| 73 | 116 |
result = cli.run(project=project, args=['build', 'target.bst'])
|
| ... | ... | @@ -77,9 +120,11 @@ def test_push(cli, tmpdir, datafiles): |
| 77 | 120 |
assert cli.get_element_state(project, 'target.bst') == 'cached'
|
| 78 | 121 |
|
| 79 | 122 |
# Set up two artifact shares.
|
| 80 |
- with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare1')) as share1:
|
|
| 123 |
+ with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare1'),
|
|
| 124 |
+ credentials=credentials) as share1:
|
|
| 81 | 125 |
|
| 82 |
- with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare2')) as share2:
|
|
| 126 |
+ with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare2'),
|
|
| 127 |
+ credentials=credentials) as share2:
|
|
| 83 | 128 |
|
| 84 | 129 |
# Try pushing with no remotes configured. This should fail.
|
| 85 | 130 |
result = cli.run(project=project, args=['push', 'target.bst'])
|
| ... | ... | @@ -87,19 +132,19 @@ def test_push(cli, tmpdir, datafiles): |
| 87 | 132 |
|
| 88 | 133 |
# Configure bst to pull but not push from a cache and run `bst push`.
|
| 89 | 134 |
# This should also fail.
|
| 90 |
- cli.configure({
|
|
| 135 |
+ cli.configure(add_client_config_creds({
|
|
| 91 | 136 |
'artifacts': {'url': share1.repo, 'push': False},
|
| 92 |
- })
|
|
| 137 |
+ }, credentials))
|
|
| 93 | 138 |
result = cli.run(project=project, args=['push', 'target.bst'])
|
| 94 | 139 |
result.assert_main_error(ErrorDomain.STREAM, None)
|
| 95 | 140 |
|
| 96 | 141 |
# Configure bst to push to one of the caches and run `bst push`. This works.
|
| 97 |
- cli.configure({
|
|
| 142 |
+ cli.configure(add_client_config_creds({
|
|
| 98 | 143 |
'artifacts': [
|
| 99 | 144 |
{'url': share1.repo, 'push': False},
|
| 100 | 145 |
{'url': share2.repo, 'push': True},
|
| 101 | 146 |
]
|
| 102 |
- })
|
|
| 147 |
+ }, credentials))
|
|
| 103 | 148 |
result = cli.run(project=project, args=['push', 'target.bst'])
|
| 104 | 149 |
|
| 105 | 150 |
assert_not_shared(cli, share1, project, 'target.bst')
|
| ... | ... | @@ -108,12 +153,12 @@ def test_push(cli, tmpdir, datafiles): |
| 108 | 153 |
# Now try pushing to both
|
| 109 | 154 |
|
| 110 | 155 |
with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare2')) as share2:
|
| 111 |
- cli.configure({
|
|
| 156 |
+ cli.configure(add_client_config_creds({
|
|
| 112 | 157 |
'artifacts': [
|
| 113 | 158 |
{'url': share1.repo, 'push': True},
|
| 114 | 159 |
{'url': share2.repo, 'push': True},
|
| 115 | 160 |
]
|
| 116 |
- })
|
|
| 161 |
+ }, credentials))
|
|
| 117 | 162 |
result = cli.run(project=project, args=['push', 'target.bst'])
|
| 118 | 163 |
|
| 119 | 164 |
assert_shared(cli, share1, project, 'target.bst')
|
| ... | ... | @@ -122,11 +167,16 @@ def test_push(cli, tmpdir, datafiles): |
| 122 | 167 |
|
| 123 | 168 |
# Tests that `bst push --deps all` pushes all dependencies of the given element.
|
| 124 | 169 |
#
|
| 125 |
-@pytest.mark.datafiles(DATA_DIR)
|
|
| 126 |
-def test_push_all(cli, tmpdir, datafiles):
|
|
| 127 |
- project = os.path.join(datafiles.dirname, datafiles.basename)
|
|
| 170 |
+@pytest.mark.parametrize(
|
|
| 171 |
+ 'credential_filenames', CREDENTIAL_FILENAMES.values(), ids=list(CREDENTIAL_FILENAMES))
|
|
| 172 |
+@pytest.mark.datafiles(DATA_DIR, CRED_DIR, keep_top_dir=True)
|
|
| 173 |
+def test_push_all(cli, tmpdir, datafiles, credential_filenames):
|
|
| 174 |
+ project = os.path.join(datafiles, 'project')
|
|
| 175 |
+ credfiles = os.path.join(datafiles, 'creds')
|
|
| 128 | 176 |
|
| 129 |
- with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare')) as share:
|
|
| 177 |
+ credentials = join_credentials_path(credential_filenames, credfiles)
|
|
| 178 |
+ |
|
| 179 |
+ with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare'), credentials=credentials) as share:
|
|
| 130 | 180 |
|
| 131 | 181 |
# First build it without the artifact cache configured
|
| 132 | 182 |
result = cli.run(project=project, args=['build', 'target.bst'])
|
| ... | ... | @@ -136,7 +186,7 @@ def test_push_all(cli, tmpdir, datafiles): |
| 136 | 186 |
assert cli.get_element_state(project, 'target.bst') == 'cached'
|
| 137 | 187 |
|
| 138 | 188 |
# Configure artifact share
|
| 139 |
- cli.configure({
|
|
| 189 |
+ cli.configure(add_client_config_creds({
|
|
| 140 | 190 |
#
|
| 141 | 191 |
# FIXME: This test hangs "sometimes" if we allow
|
| 142 | 192 |
# concurrent push.
|
| ... | ... | @@ -152,7 +202,7 @@ def test_push_all(cli, tmpdir, datafiles): |
| 152 | 202 |
'url': share.repo,
|
| 153 | 203 |
'push': True,
|
| 154 | 204 |
}
|
| 155 |
- })
|
|
| 205 |
+ }, credentials))
|
|
| 156 | 206 |
|
| 157 | 207 |
# Now try bst push all the deps
|
| 158 | 208 |
result = cli.run(project=project, args=[
|
| ... | ... | @@ -12,7 +12,7 @@ import pytest_cov |
| 12 | 12 |
|
| 13 | 13 |
from buildstream import _yaml
|
| 14 | 14 |
from buildstream._artifactcache.cascache import CASCache
|
| 15 |
-from buildstream._artifactcache.casserver import create_server
|
|
| 15 |
+from buildstream._artifactcache.casserver import create_server, setup_server
|
|
| 16 | 16 |
from buildstream._context import Context
|
| 17 | 17 |
from buildstream._exceptions import ArtifactError
|
| 18 | 18 |
|
| ... | ... | @@ -29,7 +29,7 @@ from buildstream._exceptions import ArtifactError |
| 29 | 29 |
#
|
| 30 | 30 |
class ArtifactShare():
|
| 31 | 31 |
|
| 32 |
- def __init__(self, directory, *, total_space=None, free_space=None):
|
|
| 32 |
+ def __init__(self, directory, *, total_space=None, free_space=None, credentials={}):
|
|
| 33 | 33 |
|
| 34 | 34 |
# The working directory for the artifact share (in case it
|
| 35 | 35 |
# needs to do something outside of it's backend's storage folder).
|
| ... | ... | @@ -55,19 +55,24 @@ class ArtifactShare(): |
| 55 | 55 |
|
| 56 | 56 |
q = Queue()
|
| 57 | 57 |
|
| 58 |
- self.process = Process(target=self.run, args=(q,))
|
|
| 58 |
+ self.process = Process(target=self.run, args=(q, credentials))
|
|
| 59 | 59 |
self.process.start()
|
| 60 | 60 |
|
| 61 | 61 |
# Retrieve port from server subprocess
|
| 62 | 62 |
port = q.get()
|
| 63 | 63 |
|
| 64 |
- self.repo = 'http://localhost:{}'.format(port)
|
|
| 64 |
+ if credentials:
|
|
| 65 |
+ protocol = 'https'
|
|
| 66 |
+ else:
|
|
| 67 |
+ protocol = 'http'
|
|
| 68 |
+ |
|
| 69 |
+ self.repo = '{}://localhost:{}'.format(protocol, port)
|
|
| 65 | 70 |
|
| 66 | 71 |
# run():
|
| 67 | 72 |
#
|
| 68 | 73 |
# Run the artifact server.
|
| 69 | 74 |
#
|
| 70 |
- def run(self, q):
|
|
| 75 |
+ def run(self, q, credentials):
|
|
| 71 | 76 |
pytest_cov.embed.cleanup_on_sigterm()
|
| 72 | 77 |
|
| 73 | 78 |
# Optionally mock statvfs
|
| ... | ... | @@ -77,7 +82,7 @@ class ArtifactShare(): |
| 77 | 82 |
os.statvfs = self._mock_statvfs
|
| 78 | 83 |
|
| 79 | 84 |
server = create_server(self.repodir, enable_push=True)
|
| 80 |
- port = server.add_insecure_port('localhost:0')
|
|
| 85 |
+ port = setup_server(server, 'localhost', 0, **credentials)
|
|
| 81 | 86 |
|
| 82 | 87 |
server.start()
|
| 83 | 88 |
|
| ... | ... | @@ -149,8 +154,8 @@ class ArtifactShare(): |
| 149 | 154 |
# Create an ArtifactShare for use in a test case
|
| 150 | 155 |
#
|
| 151 | 156 |
@contextmanager
|
| 152 |
-def create_artifact_share(directory, *, total_space=None, free_space=None):
|
|
| 153 |
- share = ArtifactShare(directory, total_space=total_space, free_space=free_space)
|
|
| 157 |
+def create_artifact_share(directory, *, total_space=None, free_space=None, credentials={}):
|
|
| 158 |
+ share = ArtifactShare(directory, total_space=total_space, free_space=free_space, credentials=credentials)
|
|
| 154 | 159 |
try:
|
| 155 | 160 |
yield share
|
| 156 | 161 |
finally:
|
