Martin Blanchard pushed to branch mablanch/68-bots-multi-endpoints at BuildGrid / buildgrid
Commits:
-
94c7a77e
by Martin Blanchard at 2018-08-29T13:53:50Z
4 changed files:
- buildgrid/_app/bots/buildbox.py
- buildgrid/_app/bots/temp_directory.py
- buildgrid/_app/cli.py
- buildgrid/_app/commands/cmd_bot.py
Changes:
... | ... | @@ -16,13 +16,12 @@ |
16 | 16 |
import os
|
17 | 17 |
import subprocess
|
18 | 18 |
import tempfile
|
19 |
-import grpc
|
|
20 | 19 |
|
21 | 20 |
from google.protobuf import any_pb2
|
22 | 21 |
|
23 | 22 |
from buildgrid._protos.build.bazel.remote.execution.v2 import remote_execution_pb2
|
24 | 23 |
from buildgrid._protos.google.bytestream import bytestream_pb2_grpc
|
25 |
-from buildgrid.utils import read_file, parse_to_pb2_from_fetch
|
|
24 |
+from buildgrid.utils import parse_to_pb2_from_fetch
|
|
26 | 25 |
|
27 | 26 |
|
28 | 27 |
def work_buildbox(context, lease):
|
... | ... | @@ -32,18 +31,7 @@ def work_buildbox(context, lease): |
32 | 31 |
action_digest = remote_execution_pb2.Digest()
|
33 | 32 |
action_digest_any.Unpack(action_digest)
|
34 | 33 |
|
35 |
- cert_server = read_file(context.server_cert)
|
|
36 |
- cert_client = read_file(context.client_cert)
|
|
37 |
- key_client = read_file(context.client_key)
|
|
38 |
- |
|
39 |
- # create server credentials
|
|
40 |
- credentials = grpc.ssl_channel_credentials(root_certificates=cert_server,
|
|
41 |
- private_key=key_client,
|
|
42 |
- certificate_chain=cert_client)
|
|
43 |
- |
|
44 |
- channel = grpc.secure_channel('{}:{}'.format(context.remote, context.port), credentials)
|
|
45 |
- |
|
46 |
- stub = bytestream_pb2_grpc.ByteStreamStub(channel)
|
|
34 |
+ stub = bytestream_pb2_grpc.ByteStreamStub(context.cas_channel)
|
|
47 | 35 |
|
48 | 36 |
action = remote_execution_pb2.Action()
|
49 | 37 |
parse_to_pb2_from_fetch(action, stub, action_digest)
|
... | ... | @@ -66,13 +54,18 @@ def work_buildbox(context, lease): |
66 | 54 |
|
67 | 55 |
with tempfile.NamedTemporaryFile(dir=os.path.join(casdir, 'tmp')) as output_digest_file:
|
68 | 56 |
command = ['buildbox',
|
69 |
- '--remote={}'.format('https://{}:{}'.format(context.remote, context.port)),
|
|
70 |
- '--server-cert={}'.format(context.server_cert),
|
|
71 |
- '--client-key={}'.format(context.client_key),
|
|
72 |
- '--client-cert={}'.format(context.client_cert),
|
|
57 |
+ '--remote={}'.format(context.remote_cas_url),
|
|
73 | 58 |
'--input-digest={}'.format(input_digest_file.name),
|
74 | 59 |
'--output-digest={}'.format(output_digest_file.name),
|
75 | 60 |
'--local={}'.format(casdir)]
|
61 |
+ |
|
62 |
+ if context.cas_client_key:
|
|
63 |
+ command.append('--client-key={}'.format(context.cas_client_key))
|
|
64 |
+ if context.cas_client_cert:
|
|
65 |
+ command.append('--client-cert={}'.format(context.cas_client_cert))
|
|
66 |
+ if context.cas_server_cert:
|
|
67 |
+ command.append('--server-cert={}'.format(context.cas_server_cert))
|
|
68 |
+ |
|
76 | 69 |
if 'PWD' in environment and environment['PWD']:
|
77 | 70 |
command.append('--chdir={}'.format(environment['PWD']))
|
78 | 71 |
|
... | ... | @@ -30,7 +30,7 @@ def work_temp_directory(context, lease): |
30 | 30 |
"""
|
31 | 31 |
|
32 | 32 |
parent = context.parent
|
33 |
- stub_bytestream = bytestream_pb2_grpc.ByteStreamStub(context.channel)
|
|
33 |
+ stub_bytestream = bytestream_pb2_grpc.ByteStreamStub(context.cas_channel)
|
|
34 | 34 |
|
35 | 35 |
action_digest = remote_execution_pb2.Digest()
|
36 | 36 |
lease.payload.Unpack(action_digest)
|
... | ... | @@ -78,7 +78,7 @@ def work_temp_directory(context, lease): |
78 | 78 |
request = remote_execution_pb2.BatchUpdateBlobsRequest(instance_name=parent,
|
79 | 79 |
requests=requests)
|
80 | 80 |
|
81 |
- stub_cas = remote_execution_pb2_grpc.ContentAddressableStorageStub(context.channel)
|
|
81 |
+ stub_cas = remote_execution_pb2_grpc.ContentAddressableStorageStub(context.cas_channel)
|
|
82 | 82 |
stub_cas.BatchUpdateBlobs(request)
|
83 | 83 |
|
84 | 84 |
result_any = any_pb2.Any()
|
... | ... | @@ -83,14 +83,22 @@ class Context: |
83 | 83 |
client_key_pem = read_file(client_key)
|
84 | 84 |
else:
|
85 | 85 |
client_key_pem = None
|
86 |
+ client_key = None
|
|
86 | 87 |
if client_key_pem and client_cert and os.path.exists(client_cert):
|
87 | 88 |
client_cert_pem = read_file(client_cert)
|
88 | 89 |
else:
|
89 | 90 |
client_cert_pem = None
|
91 |
+ client_cert = None
|
|
90 | 92 |
|
91 |
- return grpc.ssl_channel_credentials(root_certificates=server_cert_pem,
|
|
92 |
- private_key=client_key_pem,
|
|
93 |
- certificate_chain=client_cert_pem)
|
|
93 |
+ credentials = grpc.ssl_channel_credentials(root_certificates=server_cert_pem,
|
|
94 |
+ private_key=client_key_pem,
|
|
95 |
+ certificate_chain=client_cert_pem)
|
|
96 |
+ |
|
97 |
+ credentials.client_key = client_key
|
|
98 |
+ credentials.client_cert = client_cert
|
|
99 |
+ credentials.server_cert = server_cert
|
|
100 |
+ |
|
101 |
+ return credentials
|
|
94 | 102 |
|
95 | 103 |
def load_server_credentials(self, server_key=None, server_cert=None,
|
96 | 104 |
client_certs=None, use_default_client_certs=False):
|
... | ... | @@ -132,10 +140,17 @@ class Context: |
132 | 140 |
client_certs_pem = read_file(client_certs)
|
133 | 141 |
else:
|
134 | 142 |
client_certs_pem = None
|
143 |
+ client_certs = None
|
|
144 |
+ |
|
145 |
+ credentials = grpc.ssl_server_credentials([(server_key_pem, server_cert_pem)],
|
|
146 |
+ root_certificates=client_certs_pem,
|
|
147 |
+ require_client_auth=bool(client_certs))
|
|
148 |
+ |
|
149 |
+ credentials.server_key = server_key
|
|
150 |
+ credentials.server_cert = server_cert
|
|
151 |
+ credentials.client_certs = client_certs
|
|
135 | 152 |
|
136 |
- return grpc.ssl_server_credentials([(server_key_pem, server_cert_pem)],
|
|
137 |
- root_certificates=client_certs_pem,
|
|
138 |
- require_client_auth=bool(client_certs))
|
|
153 |
+ return credentials
|
|
139 | 154 |
|
140 | 155 |
|
141 | 156 |
pass_context = click.make_pass_decorator(Context, ensure=True)
|
... | ... | @@ -44,26 +44,79 @@ from ..cli import pass_context |
44 | 44 |
help="Public client certificate for TLS (PEM-encoded)")
|
45 | 45 |
@click.option('--server-cert', type=click.Path(exists=True, dir_okay=False), default=None,
|
46 | 46 |
help="Public server certificate for TLS (PEM-encoded)")
|
47 |
+@click.option('--remote-cas', type=click.STRING, default=None, show_default=True,
|
|
48 |
+ help="Remote CAS server's URL (port defaults to 11001 if not specified).")
|
|
49 |
+@click.option('--cas-client-key', type=click.Path(exists=True, dir_okay=False), default=None,
|
|
50 |
+ help="Private CAS client key for TLS (PEM-encoded)")
|
|
51 |
+@click.option('--cas-client-cert', type=click.Path(exists=True, dir_okay=False), default=None,
|
|
52 |
+ help="Public CAS client certificate for TLS (PEM-encoded)")
|
|
53 |
+@click.option('--cas-server-cert', type=click.Path(exists=True, dir_okay=False), default=None,
|
|
54 |
+ help="Public CAS server certificate for TLS (PEM-encoded)")
|
|
47 | 55 |
@click.option('--parent', type=click.STRING, default='main', show_default=True,
|
48 | 56 |
help="Targeted farm resource.")
|
49 | 57 |
@pass_context
|
50 |
-def cli(context, remote, parent, client_key, client_cert, server_cert):
|
|
58 |
+def cli(context, parent, remote, client_key, client_cert, server_cert,
|
|
59 |
+ remote_cas, cas_client_key, cas_client_cert, cas_server_cert):
|
|
60 |
+ # Setup the remote execution server channel:
|
|
51 | 61 |
url = urlparse(remote)
|
52 | 62 |
|
53 | 63 |
context.remote = '{}:{}'.format(url.hostname, url.port or 50051)
|
64 |
+ context.remote_url = remote
|
|
54 | 65 |
context.parent = parent
|
55 | 66 |
|
56 | 67 |
if url.scheme == 'http':
|
57 | 68 |
context.channel = grpc.insecure_channel(context.remote)
|
69 |
+ |
|
70 |
+ context.client_key = None
|
|
71 |
+ context.client_cert = None
|
|
72 |
+ context.server_cert = None
|
|
58 | 73 |
else:
|
59 | 74 |
credentials = context.load_client_credentials(client_key, client_cert, server_cert)
|
60 | 75 |
if not credentials:
|
61 |
- click.echo("ERROR: no TLS keys were specified and no defaults could be found.\n" +
|
|
62 |
- "Use --allow-insecure in order to deactivate TLS encryption.\n", err=True)
|
|
76 |
+ click.echo("ERROR: no TLS keys were specified and no defaults could be found.", err=True)
|
|
63 | 77 |
sys.exit(-1)
|
64 | 78 |
|
65 | 79 |
context.channel = grpc.secure_channel(context.remote, credentials)
|
66 | 80 |
|
81 |
+ context.client_key = credentials.client_key
|
|
82 |
+ context.client_cert = credentials.client_cert
|
|
83 |
+ context.server_cert = credentials.server_cert
|
|
84 |
+ |
|
85 |
+ # Setup the remote CAS server channel, if separated:
|
|
86 |
+ if remote_cas is not None and remote_cas != remote:
|
|
87 |
+ cas_url = urlparse(remote_cas)
|
|
88 |
+ |
|
89 |
+ context.remote_cas = '{}:{}'.format(cas_url.hostname, cas_url.port or 11001)
|
|
90 |
+ context.remote_cas_url = remote_cas
|
|
91 |
+ |
|
92 |
+ if cas_url.scheme == 'http':
|
|
93 |
+ context.cas_channel = grpc.insecure_channel(context.remote_cas)
|
|
94 |
+ |
|
95 |
+ context.cas_client_key = None
|
|
96 |
+ context.cas_client_cert = None
|
|
97 |
+ context.cas_server_cert = None
|
|
98 |
+ else:
|
|
99 |
+ cas_credentials = context.load_client_credentials(cas_client_key, cas_client_cert, cas_server_cert)
|
|
100 |
+ if not cas_credentials:
|
|
101 |
+ click.echo("ERROR: no TLS keys were specified and no defaults could be found.", err=True)
|
|
102 |
+ sys.exit(-1)
|
|
103 |
+ |
|
104 |
+ context.cas_channel = grpc.secure_channel(context.remote_cas, cas_credentials)
|
|
105 |
+ |
|
106 |
+ context.cas_client_key = cas_credentials.client_key
|
|
107 |
+ context.cas_client_cert = cas_credentials.client_cert
|
|
108 |
+ context.cas_server_cert = cas_credentials.server_cert
|
|
109 |
+ |
|
110 |
+ else:
|
|
111 |
+ context.remote_cas = context.remote
|
|
112 |
+ context.remote_cas_url = remote
|
|
113 |
+ |
|
114 |
+ context.cas_channel = context.channel
|
|
115 |
+ |
|
116 |
+ context.cas_client_key = context.client_key
|
|
117 |
+ context.cas_client_cert = context.client_cert
|
|
118 |
+ context.cas_server_cert = context.server_cert
|
|
119 |
+ |
|
67 | 120 |
context.logger = logging.getLogger(__name__)
|
68 | 121 |
context.logger.debug("Starting for remote {}".format(context.remote))
|
69 | 122 |
|
... | ... | @@ -112,35 +165,17 @@ def run_temp_directory(context): |
112 | 165 |
help="Main mount-point location.")
|
113 | 166 |
@click.option('--local-cas', type=click.Path(readable=False), default=str(PurePath(Path.home(), 'cas')),
|
114 | 167 |
help="Local CAS cache directory.")
|
115 |
-@click.option('--client-cert', type=click.Path(readable=False), default=str(PurePath(Path.home(), 'client.crt')),
|
|
116 |
- help="Public client certificate for TLS (PEM-encoded).")
|
|
117 |
-@click.option('--client-key', type=click.Path(readable=False), default=str(PurePath(Path.home(), 'client.key')),
|
|
118 |
- help="Private client key for TLS (PEM-encoded).")
|
|
119 |
-@click.option('--server-cert', type=click.Path(readable=False), default=str(PurePath(Path.home(), 'server.crt')),
|
|
120 |
- help="Public server certificate for TLS (PEM-encoded).")
|
|
121 |
-@click.option('--port', type=click.INT, default=11001, show_default=True,
|
|
122 |
- help="Remote CAS server port.")
|
|
123 |
-@click.option('--remote', type=click.STRING, default='localhost', show_default=True,
|
|
124 |
- help="Remote CAS server hostname.")
|
|
125 | 168 |
@pass_context
|
126 |
-def run_buildbox(context, remote, port, server_cert, client_key, client_cert, local_cas, fuse_dir):
|
|
169 |
+def run_buildbox(context, local_cas, fuse_dir):
|
|
127 | 170 |
"""
|
128 | 171 |
Uses BuildBox to run commands.
|
129 | 172 |
"""
|
130 |
- |
|
131 |
- context.logger.info("Creating a bot session")
|
|
132 |
- |
|
133 |
- context.remote = remote
|
|
134 |
- context.port = port
|
|
135 |
- context.server_cert = server_cert
|
|
136 |
- context.client_key = client_key
|
|
137 |
- context.client_cert = client_cert
|
|
138 | 173 |
context.local_cas = local_cas
|
139 | 174 |
context.fuse_dir = fuse_dir
|
140 | 175 |
|
141 | 176 |
try:
|
142 | 177 |
b = bot.Bot(context.bot_session)
|
143 |
- b.session(work=buildbox.work_buildbox,
|
|
144 |
- context=context)
|
|
178 |
+ b.session(buildbox.work_buildbox,
|
|
179 |
+ context)
|
|
145 | 180 |
except KeyboardInterrupt:
|
146 | 181 |
pass
|