You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildstream.apache.org by no...@apache.org on 2020/12/29 12:27:59 UTC
[buildstream] branch dp0/casserver-tests created (now e9ffd7e)
This is an automated email from the ASF dual-hosted git repository.
not-in-ldap pushed a change to branch dp0/casserver-tests
in repository https://gitbox.apache.org/repos/asf/buildstream.git.
at e9ffd7e Adapt tests to use secured CAS server
This branch includes the following new commits:
new 5b476dd Refactor casserver for better coverage
new e9ffd7e Adapt tests to use secured CAS server
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[buildstream] 02/02: Adapt tests to use secured CAS server
Posted by no...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
not-in-ldap pushed a commit to branch dp0/casserver-tests
in repository https://gitbox.apache.org/repos/asf/buildstream.git
commit e9ffd7eab8608d6a400182e2f1af8a8f97e3a7f9
Author: Daniel Playle <dp...@bloomberg.net>
AuthorDate: Fri Aug 31 16:55:24 2018 +0100
Adapt tests to use secured CAS server
Previously, we had been only testing an unsecured CAS server. As such,
no authentication mechanisms were tested. This commit adapts existing
tests to ensure that a secured CAS server is also tested alongside
unsecured configurations.
This commit introduces two data files which are used in part of the
testing process: a server private key, and a server certificate. The
server private key is of size 4096 bytes. The server certificate is for
the name "localhost" and has an expiration set to 1000 years in the
future, so there should be little concern of the expiration of this
testing artifact.
---
tests/frontend/creds/server_cert.pem | 29 +++++++++++++
tests/frontend/creds/server_key.pem | 52 ++++++++++++++++++++++
tests/frontend/push.py | 84 ++++++++++++++++++++++++++++--------
tests/testutils/artifactshare.py | 19 +++++---
4 files changed, 160 insertions(+), 24 deletions(-)
diff --git a/tests/frontend/creds/server_cert.pem b/tests/frontend/creds/server_cert.pem
new file mode 100644
index 0000000..b1c6dc2
--- /dev/null
+++ b/tests/frontend/creds/server_cert.pem
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIFADCCAuigAwIBAgIJAMrnbCKz2am/MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
+BAMMCWxvY2FsaG9zdDAgFw0xODA4MzExNTEzMThaGA8zMDE4MDEwMTE1MTMxOFow
+FDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEAtOF+EmfIIQVz4eox6lZLcQcsf089r65XB5su8SzDXvC2kYIn8Crqs67Q
+x4s10YfYAOWS0Bj0Jx5GS7NQB+vUQtHWNTAO+19edAsrH204OD3QTrU0rt1rpJGb
+P36tIgZk+zgWj9MquHibacg2u/sz+4OlfxsDg2FDt1zhgamY9AQ2BRlxDza9/lcU
+/yBD2hSw3LyLQLJAL0TbTARqUkCHWZRcy1KPQ47SV4aWC2WhUwimDK44UZs1Ub50
+GcaB7s/ZRm6mREGV5mBzW63GLthOGlTps5YzE45GsLrmRiQ9aJgr8I6BZoNggLl9
+WomvGvd4PBzsXxyu3d+ZVdoudxeQbMKlyr7i5yVDO5S26xohUbpQg8wAl4YZ7tG7
+K2ihEphSgeCh3owWPkptXSxX+dXnA7W2/uJ4HwHjRLf7/MRL3GccJsviL7qtg9fO
+PF5av/psRkfR5tq/qtFrWAor4E1/nLKJbtEzHP8XoSJglSIXL2g1Q6ofNmbHvghg
+hR0pT6oEf6hc5R+qXVT7TTSxdVQkyLnrR+nUWMzaMUrD990kdhY+eJu15sJXsHyJ
+OThkuqiGbiTlTUEyhbTsFCK1UVi9P8cLGndyeB9LtQynWVqBFXPkT/qVyjOINUHZ
+2wu2U0OhjMpZ3dtQC58ME/Q0xDbJoyr+HwsMFV97TXT/WoLiN48CAwEAAaNTMFEw
+HQYDVR0OBBYEFFWfm5e2tS2Ask/QRNP8Y10yM3S4MB8GA1UdIwQYMBaAFFWfm5e2
+tS2Ask/QRNP8Y10yM3S4MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD
+ggIBACGpGGhliKiwAu1TjxMoQfI9rpO7uVyEYeBIYJ/eK3beJqCs3FmirgYdmGtK
+2KHcPnMG27c1m9EEsJf9sVOjkd43OB7fdWw38i0TaPxSgmPh0v6b+jhR4tqxwIRi
+jSQUxNklurKroyMWL9QFFLufwd43g3XTm449EOzrLB2jxUd10u+OXwzraQRRgTeM
+9U9PMoTfp6dICKKcV7XJdDR2hUH7SRrk96ucgYhztLx4x9R+mTZzgeCw5euY7a/t
+02uijT4tIrtCryOTukHrtfWdy5+ng4mcsdlWvZgJiRy+vwdWFx8k5t/MJ6f1xqxs
+RHl/99LAh/d9scdkVXPEB57vQRuHeybPH2i4cM/0VyFDfCrCG9AeXeVeB/pbanzB
+ex6MHttnhopTWtFHuMDquCeLP5P5cnKNLB676bZvKhgNoYZAXIrFGJtJNLMFBXD6
+v9kXrCIpDdUFHd3GLi8U9GTiwSmfz6HQVCvQZ+feVBpZLxaFrLpbRszKIE1lYFVS
+eJd3StxS/BGm3jzbWGgG9kq7kuF3cuJmtfKoAzOYYNz3/eipfQl6giOitJx5MWW5
+mevCq9mCNBIKvRNdxR0kJ4rJ5eTlDJ6xfFs2aKGXHFKS1+21RM/S58El+XosWXov
+4jZCTLS7wmk2/MrABGmbCgK4YfrQnt6eY2nElJXEBPX0jeHu
+-----END CERTIFICATE-----
diff --git a/tests/frontend/creds/server_key.pem b/tests/frontend/creds/server_key.pem
new file mode 100644
index 0000000..ba546dc
--- /dev/null
+++ b/tests/frontend/creds/server_key.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+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
+e+XVdfiURwWj6Q7/y/Rujtp7K6z2dA==
+-----END PRIVATE KEY-----
diff --git a/tests/frontend/push.py b/tests/frontend/push.py
index f351e33..74f0623 100644
--- a/tests/frontend/push.py
+++ b/tests/frontend/push.py
@@ -35,6 +35,22 @@ DATA_DIR = os.path.join(
"project",
)
+# Credential directory
+CRED_DIR = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ "creds",
+)
+
+# Parameters for credentials
+CREDENTIAL_FILENAMES = {
+ 'unsecured': {},
+
+ 'server_secured': {
+ 'server_key': 'server_key.pem',
+ 'server_cert': 'server_cert.pem',
+ },
+}
+
# Assert that a given artifact is in the share
#
@@ -60,14 +76,41 @@ def assert_not_shared(cli, share, project, element_name):
.format(share.repo, element_name))
+# Taking a dictionary of filenames, this returns a dictionary of qualified
+# fielnames
+def join_credentials_path(credential_filenames, credential_files):
+ return {
+ key: os.path.join(credential_files, filename)
+ for key, filename in credential_filenames.items()
+ }
+
+
+# Adds the server certificate to the configuration if it exists and returns
+# this for ease of use
+def add_client_config_creds(configuration, credentials):
+ if 'server_cert' in credentials:
+ artifacts = configuration['artifacts']
+ if isinstance(artifacts, (list,)):
+ for subconfig in artifacts:
+ subconfig['server-cert'] = credentials['server_cert']
+ else:
+ artifacts['server-cert'] = credentials['server_cert']
+ return configuration
+
+
# Tests that:
#
# * `bst push` fails if there are no remotes configured for pushing
# * `bst push` successfully pushes to any remote that is configured for pushing
#
-@pytest.mark.datafiles(DATA_DIR)
-def test_push(cli, tmpdir, datafiles):
- project = str(datafiles)
+@pytest.mark.parametrize(
+ 'credential_filenames', CREDENTIAL_FILENAMES.values(), ids=list(CREDENTIAL_FILENAMES))
+@pytest.mark.datafiles(DATA_DIR, CRED_DIR, keep_top_dir=True)
+def test_push(cli, tmpdir, datafiles, credential_filenames):
+ project = os.path.join(datafiles, 'project')
+ credfiles = os.path.join(datafiles, 'creds')
+
+ credentials = join_credentials_path(credential_filenames, credfiles)
# First build the project without the artifact cache configured
result = cli.run(project=project, args=['build', 'target.bst'])
@@ -77,9 +120,11 @@ def test_push(cli, tmpdir, datafiles):
assert cli.get_element_state(project, 'target.bst') == 'cached'
# Set up two artifact shares.
- with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare1')) as share1:
+ with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare1'),
+ credentials=credentials) as share1:
- with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare2')) as share2:
+ with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare2'),
+ credentials=credentials) as share2:
# Try pushing with no remotes configured. This should fail.
result = cli.run(project=project, args=['push', 'target.bst'])
@@ -87,19 +132,19 @@ def test_push(cli, tmpdir, datafiles):
# Configure bst to pull but not push from a cache and run `bst push`.
# This should also fail.
- cli.configure({
+ cli.configure(add_client_config_creds({
'artifacts': {'url': share1.repo, 'push': False},
- })
+ }, credentials))
result = cli.run(project=project, args=['push', 'target.bst'])
result.assert_main_error(ErrorDomain.STREAM, None)
# Configure bst to push to one of the caches and run `bst push`. This works.
- cli.configure({
+ cli.configure(add_client_config_creds({
'artifacts': [
{'url': share1.repo, 'push': False},
{'url': share2.repo, 'push': True},
]
- })
+ }, credentials))
result = cli.run(project=project, args=['push', 'target.bst'])
assert_not_shared(cli, share1, project, 'target.bst')
@@ -108,12 +153,12 @@ def test_push(cli, tmpdir, datafiles):
# Now try pushing to both
with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare2')) as share2:
- cli.configure({
+ cli.configure(add_client_config_creds({
'artifacts': [
{'url': share1.repo, 'push': True},
{'url': share2.repo, 'push': True},
]
- })
+ }, credentials))
result = cli.run(project=project, args=['push', 'target.bst'])
assert_shared(cli, share1, project, 'target.bst')
@@ -122,11 +167,16 @@ def test_push(cli, tmpdir, datafiles):
# Tests that `bst push --deps all` pushes all dependencies of the given element.
#
-@pytest.mark.datafiles(DATA_DIR)
-def test_push_all(cli, tmpdir, datafiles):
- project = os.path.join(datafiles.dirname, datafiles.basename)
+@pytest.mark.parametrize(
+ 'credential_filenames', CREDENTIAL_FILENAMES.values(), ids=list(CREDENTIAL_FILENAMES))
+@pytest.mark.datafiles(DATA_DIR, CRED_DIR, keep_top_dir=True)
+def test_push_all(cli, tmpdir, datafiles, credential_filenames):
+ project = os.path.join(datafiles, 'project')
+ credfiles = os.path.join(datafiles, 'creds')
- with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare')) as share:
+ credentials = join_credentials_path(credential_filenames, credfiles)
+
+ with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare'), credentials=credentials) as share:
# First build it without the artifact cache configured
result = cli.run(project=project, args=['build', 'target.bst'])
@@ -136,7 +186,7 @@ def test_push_all(cli, tmpdir, datafiles):
assert cli.get_element_state(project, 'target.bst') == 'cached'
# Configure artifact share
- cli.configure({
+ cli.configure(add_client_config_creds({
#
# FIXME: This test hangs "sometimes" if we allow
# concurrent push.
@@ -152,7 +202,7 @@ def test_push_all(cli, tmpdir, datafiles):
'url': share.repo,
'push': True,
}
- })
+ }, credentials))
# Now try bst push all the deps
result = cli.run(project=project, args=[
diff --git a/tests/testutils/artifactshare.py b/tests/testutils/artifactshare.py
index d7575e5..a486ca1 100644
--- a/tests/testutils/artifactshare.py
+++ b/tests/testutils/artifactshare.py
@@ -29,7 +29,7 @@ from buildstream._exceptions import ArtifactError
#
class ArtifactShare():
- def __init__(self, directory, *, total_space=None, free_space=None):
+ def __init__(self, directory, *, total_space=None, free_space=None, credentials={}):
# The working directory for the artifact share (in case it
# needs to do something outside of it's backend's storage folder).
@@ -55,19 +55,24 @@ class ArtifactShare():
q = Queue()
- self.process = Process(target=self.run, args=(q,))
+ self.process = Process(target=self.run, args=(q, credentials))
self.process.start()
# Retrieve port from server subprocess
port = q.get()
- self.repo = 'http://localhost:{}'.format(port)
+ if credentials:
+ protocol = 'https'
+ else:
+ protocol = 'http'
+
+ self.repo = '{}://localhost:{}'.format(protocol, port)
# run():
#
# Run the artifact server.
#
- def run(self, q):
+ def run(self, q, credentials):
pytest_cov.embed.cleanup_on_sigterm()
# Optionally mock statvfs
@@ -77,7 +82,7 @@ class ArtifactShare():
os.statvfs = self._mock_statvfs
server = create_server(self.repodir, enable_push=True)
- port = setup_server(server, 'localhost', 0)
+ port = setup_server(server, 'localhost', 0, **credentials)
server.start()
@@ -149,8 +154,8 @@ class ArtifactShare():
# Create an ArtifactShare for use in a test case
#
@contextmanager
-def create_artifact_share(directory, *, total_space=None, free_space=None):
- share = ArtifactShare(directory, total_space=total_space, free_space=free_space)
+def create_artifact_share(directory, *, total_space=None, free_space=None, credentials={}):
+ share = ArtifactShare(directory, total_space=total_space, free_space=free_space, credentials=credentials)
try:
yield share
finally:
[buildstream] 01/02: Refactor casserver for better coverage
Posted by no...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
not-in-ldap pushed a commit to branch dp0/casserver-tests
in repository https://gitbox.apache.org/repos/asf/buildstream.git
commit 5b476ddd57382c06d8fdb190c7e3fa687e88b4eb
Author: Daniel Playle <dp...@bloomberg.net>
AuthorDate: Fri Aug 31 11:25:31 2018 +0100
Refactor casserver for better coverage
Previously we had the logic for setting up the ports on the server in
server_main. This makes for messy testing of this functionality. As
such, this setup logic has been moved to a public function which can be
tested easily.
This commit does not change any exists test, but modifies the testutil
for creating a cache server.
---
buildstream/_artifactcache/casserver.py | 72 ++++++++++++++++++++++++---------
tests/testutils/artifactshare.py | 4 +-
2 files changed, 56 insertions(+), 20 deletions(-)
diff --git a/buildstream/_artifactcache/casserver.py b/buildstream/_artifactcache/casserver.py
index 0af6572..1baaec4 100644
--- a/buildstream/_artifactcache/casserver.py
+++ b/buildstream/_artifactcache/casserver.py
@@ -42,6 +42,11 @@ from .cascache import CASCache
class ArtifactTooLargeException(Exception):
pass
+class RequiresServerKeyPairException(Exception):
+ pass
+
+class RequiresServerKeyForClientAuthException(Exception):
+ pass
# create_server():
#
@@ -72,27 +77,37 @@ def create_server(repo, *, enable_push):
return server
-
-@click.command(short_help="CAS Artifact Server")
-@click.option('--port', '-p', type=click.INT, required=True, help="Port number")
-@click.option('--server-key', help="Private server key for TLS (PEM-encoded)")
-@click.option('--server-cert', help="Public server certificate for TLS (PEM-encoded)")
-@click.option('--client-certs', help="Public client certificates for TLS (PEM-encoded)")
-@click.option('--enable-push', default=False, is_flag=True,
- help="Allow clients to upload blobs and update artifact cache")
-@click.argument('repo')
-def server_main(repo, port, server_key, server_cert, client_certs, enable_push):
- server = create_server(repo, enable_push=enable_push)
-
+# setup_server():
+#
+# Creates a port on the given server. This port either be secured or unsecured.
+# This is dependent on the optional credential arguments.
+#
+# Either none or both of server_key and server_cert must be specified. If
+# client_certs is specified, then both server_key and server_cert must be
+# specified.
+#
+# If the caller of this function does not care what port is used, this decision
+# can be made by the gRPC runtime by specifying port 0. The port that is
+# actually used is returned.
+#
+# Args:
+# server (grpc.server): The server to open a port on
+# address (str): The address to bind the port on
+# port (int): The port number to bind on. 0 if the gRPC runtime should pick
+# server_key (str): The filename of the server private key file
+# server_cert (str): The filename of the server public cert file
+# client_certs (str): The filename of the client public certs file
+#
+# Returns:
+# int: The actual port that was opened for this server
+def setup_server(server, address, port, server_key=None, server_cert=None, client_certs=None):
use_tls = bool(server_key)
if bool(server_cert) != use_tls:
- click.echo("ERROR: --server-key and --server-cert are both required for TLS", err=True)
- sys.exit(-1)
+ raise RequiresServerKeyPairException()
if client_certs and not use_tls:
- click.echo("ERROR: --client-certs can only be used with --server-key", err=True)
- sys.exit(-1)
+ raise RequiresServerKeyForClientAuthException()
if use_tls:
# Read public/private key pair
@@ -110,9 +125,30 @@ def server_main(repo, port, server_key, server_cert, client_certs, enable_push):
credentials = grpc.ssl_server_credentials([(server_key_bytes, server_cert_bytes)],
root_certificates=client_certs_bytes,
require_client_auth=bool(client_certs))
- server.add_secure_port('[::]:{}'.format(port), credentials)
+ return server.add_secure_port('{}:{}'.format(address, port), credentials)
else:
- server.add_insecure_port('[::]:{}'.format(port))
+ return server.add_insecure_port('{}:{}'.format(address, port))
+
+
+@click.command(short_help="CAS Artifact Server")
+@click.option('--port', '-p', type=click.INT, required=True, help="Port number")
+@click.option('--server-key', help="Private server key for TLS (PEM-encoded)")
+@click.option('--server-cert', help="Public server certificate for TLS (PEM-encoded)")
+@click.option('--client-certs', help="Public client certificates for TLS (PEM-encoded)")
+@click.option('--enable-push', default=False, is_flag=True,
+ help="Allow clients to upload blobs and update artifact cache")
+@click.argument('repo')
+def server_main(repo, port, server_key, server_cert, client_certs, enable_push):
+ server = create_server(repo, enable_push=enable_push)
+
+ try:
+ setup_server(server, '[::]', port, server_key, server_cert, client_certs)
+ except RequiresServerKeyPairException:
+ click.echo("ERROR: --server-key and --server-cert are both required for TLS", err=True)
+ sys.exit(-1)
+ except RequiresServerKeyForClientAuthException:
+ click.echo("ERROR: --client-certs can only be used with --server-key", err=True)
+ sys.exit(-1)
# Run artifact server
server.start()
diff --git a/tests/testutils/artifactshare.py b/tests/testutils/artifactshare.py
index 05e87a4..d7575e5 100644
--- a/tests/testutils/artifactshare.py
+++ b/tests/testutils/artifactshare.py
@@ -12,7 +12,7 @@ import pytest_cov
from buildstream import _yaml
from buildstream._artifactcache.cascache import CASCache
-from buildstream._artifactcache.casserver import create_server
+from buildstream._artifactcache.casserver import create_server, setup_server
from buildstream._context import Context
from buildstream._exceptions import ArtifactError
@@ -77,7 +77,7 @@ class ArtifactShare():
os.statvfs = self._mock_statvfs
server = create_server(self.repodir, enable_push=True)
- port = server.add_insecure_port('localhost:0')
+ port = setup_server(server, 'localhost', 0)
server.start()