1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
import asyncio
import binascii
import hashlib
import os
import base36
import grpclib.server
from docker.utils import version_gte
from docker.utils.config import config_dir
HEADER_SESSION_ID = "X-Docker-Expose-Session-Uuid"
HEADER_SESSION_NAME = "X-Docker-Expose-Session-Name"
HEADER_SESSION_SHAREDKEY = "X-Docker-Expose-Session-Sharedkey"
HEADER_SESSION_METHOD = "X-Docker-Expose-Session-Grpc-Method"
def is_session_supported(client, for_stream):
if not for_stream and version_gte(client._version, '1.39'):
return True
servinfo = client.ping2()
return servinfo['experimental'] and version_gte(client._version, '1.31')
def try_session(client, context_dir, for_stream):
if is_session_supported(client, for_stream):
shared_key = get_build_shared_key(context_dir)
session = Session(context_dir, shared_key)
return session
return None
def get_build_shared_key(folder):
k = '{}:{}'.format(node_identifier(), folder)
h = hashlib.sha256()
h.update(k)
return h.hexdigest()
def node_identifier():
cfgdir = config_dir()
session_file = os.path.join(cfgdir, '.buildNodeID')
try:
if not os.path.isfile(session_file):
with open(session_file, 'w') as sess_fp:
b = os.urandom(32)
sess_fp.write(binascii.hexlify(b).decode('ascii'))
with open(session_file, 'r') as sess_fp:
return sess_fp.read()
except OSError:
pass
return cfgdir
def generate_session_id():
b = os.urandom(17)
b[0] |= 0x80
return base36.dumps(int.from_bytes(b, 'big'))[:25]
class Session(object):
def __init__(self, name, shared_key):
self.id = generate_session_id()
self.name = name
self.shared_key = shared_key
self.grpc_server = grpclib.server.Server(
[], asyncio.get_event_loop()
)
self.sock = None
def allow(self, attachable):
attachable.register(self.grpc_server)
def run(self, sock):
meta = {
HEADER_SESSION_ID: self.id,
HEADER_SESSION_NAME: self.name,
HEADER_SESSION_SHAREDKEY: self.shared_key,
}
# FIXME: some loop for headerSessionMethod
self.sock = sock
await self.serve(meta)
async def serve(self, metadata):
# FIXME: Figure out what to do with metadata
await self.grpc_server.start(sock=self.sock)
print('Serving on socket {}'.format(self.sock))
try:
await self.grpc_server.wait_closed()
except asyncio.CancelledError:
self.grpc_server.close()
await self.grpc_server.wait_closed()
def close(self):
if self.sock:
self.sock.close()
self.grpc_server.close()
self.closed = True
|