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 |
+MIIFADCCAuigAwIBAgIJAMrnbCKz2am/MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
|
|
3 |
+BAMMCWxvY2FsaG9zdDAgFw0xODA4MzExNTEzMThaGA8zMDE4MDEwMTE1MTMxOFow
|
|
4 |
+FDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
|
|
5 |
+CgKCAgEAtOF+EmfIIQVz4eox6lZLcQcsf089r65XB5su8SzDXvC2kYIn8Crqs67Q
|
|
6 |
+x4s10YfYAOWS0Bj0Jx5GS7NQB+vUQtHWNTAO+19edAsrH204OD3QTrU0rt1rpJGb
|
|
7 |
+P36tIgZk+zgWj9MquHibacg2u/sz+4OlfxsDg2FDt1zhgamY9AQ2BRlxDza9/lcU
|
|
8 |
+/yBD2hSw3LyLQLJAL0TbTARqUkCHWZRcy1KPQ47SV4aWC2WhUwimDK44UZs1Ub50
|
|
9 |
+GcaB7s/ZRm6mREGV5mBzW63GLthOGlTps5YzE45GsLrmRiQ9aJgr8I6BZoNggLl9
|
|
10 |
+WomvGvd4PBzsXxyu3d+ZVdoudxeQbMKlyr7i5yVDO5S26xohUbpQg8wAl4YZ7tG7
|
|
11 |
+K2ihEphSgeCh3owWPkptXSxX+dXnA7W2/uJ4HwHjRLf7/MRL3GccJsviL7qtg9fO
|
|
12 |
+PF5av/psRkfR5tq/qtFrWAor4E1/nLKJbtEzHP8XoSJglSIXL2g1Q6ofNmbHvghg
|
|
13 |
+hR0pT6oEf6hc5R+qXVT7TTSxdVQkyLnrR+nUWMzaMUrD990kdhY+eJu15sJXsHyJ
|
|
14 |
+OThkuqiGbiTlTUEyhbTsFCK1UVi9P8cLGndyeB9LtQynWVqBFXPkT/qVyjOINUHZ
|
|
15 |
+2wu2U0OhjMpZ3dtQC58ME/Q0xDbJoyr+HwsMFV97TXT/WoLiN48CAwEAAaNTMFEw
|
|
16 |
+HQYDVR0OBBYEFFWfm5e2tS2Ask/QRNP8Y10yM3S4MB8GA1UdIwQYMBaAFFWfm5e2
|
|
17 |
+tS2Ask/QRNP8Y10yM3S4MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD
|
|
18 |
+ggIBACGpGGhliKiwAu1TjxMoQfI9rpO7uVyEYeBIYJ/eK3beJqCs3FmirgYdmGtK
|
|
19 |
+2KHcPnMG27c1m9EEsJf9sVOjkd43OB7fdWw38i0TaPxSgmPh0v6b+jhR4tqxwIRi
|
|
20 |
+jSQUxNklurKroyMWL9QFFLufwd43g3XTm449EOzrLB2jxUd10u+OXwzraQRRgTeM
|
|
21 |
+9U9PMoTfp6dICKKcV7XJdDR2hUH7SRrk96ucgYhztLx4x9R+mTZzgeCw5euY7a/t
|
|
22 |
+02uijT4tIrtCryOTukHrtfWdy5+ng4mcsdlWvZgJiRy+vwdWFx8k5t/MJ6f1xqxs
|
|
23 |
+RHl/99LAh/d9scdkVXPEB57vQRuHeybPH2i4cM/0VyFDfCrCG9AeXeVeB/pbanzB
|
|
24 |
+ex6MHttnhopTWtFHuMDquCeLP5P5cnKNLB676bZvKhgNoYZAXIrFGJtJNLMFBXD6
|
|
25 |
+v9kXrCIpDdUFHd3GLi8U9GTiwSmfz6HQVCvQZ+feVBpZLxaFrLpbRszKIE1lYFVS
|
|
26 |
+eJd3StxS/BGm3jzbWGgG9kq7kuF3cuJmtfKoAzOYYNz3/eipfQl6giOitJx5MWW5
|
|
27 |
+mevCq9mCNBIKvRNdxR0kJ4rJ5eTlDJ6xfFs2aKGXHFKS1+21RM/S58El+XosWXov
|
|
28 |
+4jZCTLS7wmk2/MrABGmbCgK4YfrQnt6eY2nElJXEBPX0jeHu
|
|
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:
|