gowalk-cicd 1.0.195 → 1.0.196
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -50,7 +50,7 @@ def candidate(engine, old, body, name, staged, reservation):
|
|
|
50
50
|
current = engine.inspect(old['Id'])
|
|
51
51
|
unchanged(old, current)
|
|
52
52
|
if current['State']['Running']:
|
|
53
|
-
engine.
|
|
53
|
+
engine.stop(old['Id'])
|
|
54
54
|
replacement = engine.inspect(name, missing=True)
|
|
55
55
|
if replacement is None:
|
|
56
56
|
result = engine.request('POST', '/containers/create?name=' + quote(name, safe=''), body)
|
|
@@ -71,6 +71,8 @@ def confirmed(engine, method, path, proof):
|
|
|
71
71
|
|
|
72
72
|
|
|
73
73
|
def rollback(engine, old, name, reservation):
|
|
74
|
+
if engine.pending_stop is not None:
|
|
75
|
+
engine.stop(old['Id'])
|
|
74
76
|
replacement = engine.inspect(name, missing=True)
|
|
75
77
|
if replacement is not None and replacement['Id'] != old['Id']:
|
|
76
78
|
if (replacement['Config'].get('Labels', {}).get(MARKER) != old['Id']
|
|
@@ -13,14 +13,15 @@ SOCKET = '/var/run/docker.sock'
|
|
|
13
13
|
class Engine:
|
|
14
14
|
def __init__(self):
|
|
15
15
|
self.deadline = time.monotonic() + 90
|
|
16
|
+
self.pending_stop = None
|
|
16
17
|
|
|
17
|
-
def request(self, method, path, body=None, missing=False, raw=False):
|
|
18
|
+
def request(self, method, path, body=None, missing=False, raw=False, timeout=10):
|
|
18
19
|
remaining = self.deadline - time.monotonic()
|
|
19
20
|
if remaining <= 0:
|
|
20
21
|
raise ValueError('rollout_deadline')
|
|
21
|
-
connection = http.client.HTTPConnection('localhost', timeout=min(
|
|
22
|
+
connection = http.client.HTTPConnection('localhost', timeout=min(timeout, remaining))
|
|
22
23
|
connection.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
23
|
-
connection.sock.settimeout(min(
|
|
24
|
+
connection.sock.settimeout(min(timeout, remaining))
|
|
24
25
|
try:
|
|
25
26
|
connection.sock.connect(SOCKET)
|
|
26
27
|
data = None if body is None else json.dumps(body).encode()
|
|
@@ -38,6 +39,15 @@ class Engine:
|
|
|
38
39
|
def inspect(self, identifier, missing=False):
|
|
39
40
|
return self.request('GET', '/containers/' + quote(identifier, safe='') + '/json', missing=missing)
|
|
40
41
|
|
|
42
|
+
def stop(self, identifier):
|
|
43
|
+
# Docker continues an accepted stop after a lost HTTP reply. Keep that uncertainty
|
|
44
|
+
# until the same-ID stop completes and its stopped state is positively observed.
|
|
45
|
+
self.pending_stop = identifier
|
|
46
|
+
self.request('POST', '/containers/' + identifier + '/stop?t=10', timeout=20)
|
|
47
|
+
if self.inspect(identifier)['State']['Running']:
|
|
48
|
+
raise ValueError('container_stop_unconfirmed')
|
|
49
|
+
self.pending_stop = None
|
|
50
|
+
|
|
41
51
|
|
|
42
52
|
def unshared(engine, original):
|
|
43
53
|
identifiers = [row['Id'] for row in engine.request('GET', '/containers/json?all=1')]
|
|
@@ -67,9 +77,16 @@ def probe(engine, identifier, test):
|
|
|
67
77
|
created = engine.request('POST', '/containers/' + identifier + '/exec',
|
|
68
78
|
{'AttachStdout': False, 'AttachStderr': False, 'Cmd': command})
|
|
69
79
|
engine.request('POST', '/exec/' + created['Id'] + '/start', {'Detach': False, 'Tty': False}, raw=True)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
80
|
+
deadline = min(time.monotonic() + 5, engine.deadline)
|
|
81
|
+
while time.monotonic() < deadline:
|
|
82
|
+
result = engine.request('GET', '/exec/' + created['Id'] + '/json',
|
|
83
|
+
timeout=max(0.001, deadline - time.monotonic()))
|
|
84
|
+
if not result['Running']:
|
|
85
|
+
if result['ExitCode'] != 0:
|
|
86
|
+
raise ValueError('original_probe_failed')
|
|
87
|
+
return
|
|
88
|
+
time.sleep(min(0.1, max(0, deadline - time.monotonic())))
|
|
89
|
+
raise ValueError('original_probe_timeout')
|
|
73
90
|
|
|
74
91
|
|
|
75
92
|
def healthy(engine, identifier, deadline):
|
|
@@ -113,7 +113,12 @@ def unchanged(before, after, reservation_changes=False):
|
|
|
113
113
|
|
|
114
114
|
def verified(row, body, original):
|
|
115
115
|
config = {key: value for key, value in body.items() if key not in ('HostConfig', 'NetworkingConfig')}
|
|
116
|
-
|
|
116
|
+
hosts = [dict(value) for value in (row['HostConfig'], body['HostConfig'])]
|
|
117
|
+
# Docker reports the default OOM setting as null while running and false before start.
|
|
118
|
+
for host in hosts:
|
|
119
|
+
if host.get('OomKillDisable') is None:
|
|
120
|
+
host['OomKillDisable'] = False
|
|
121
|
+
if row['Config'] != config or row['Image'] != original['Image'] or hosts[0] != hosts[1]:
|
|
117
122
|
raise ValueError('replacement_config_changed')
|
|
118
123
|
actual = row['NetworkSettings']['Networks']
|
|
119
124
|
expected = body['NetworkingConfig']['EndpointsConfig']
|
|
@@ -81,6 +81,12 @@ marker-bound replacement, restore/start the original and verify its original hea
|
|
|
81
81
|
by identity/state readback. `rollback_unconfirmed` means recovery needs another exact readback/replay;
|
|
82
82
|
retained containers and records stay available, and unrelated containers are never removed to clear a name.
|
|
83
83
|
|
|
84
|
+
Docker may report the default `OomKillDisable` as either null or false; these alone compare equivalently,
|
|
85
|
+
while an enabled OOM-kill override must match exactly. Stop requests retain their ten-second grace with
|
|
86
|
+
a twenty-second transport allowance inside the transaction budget. An uncertain stop must settle on
|
|
87
|
+
that exact container before rollback can restart it or certify its health. Original-probe verification
|
|
88
|
+
waits for the exec's confirmed exit status, for at most five seconds within the remaining transaction.
|
|
89
|
+
|
|
84
90
|
Replay with the same original ID resumes an interrupted retained-container transaction. After successful
|
|
85
91
|
cleanup it finds the marker-bound healthy replacement and returns `already_applied`. It refuses absent,
|
|
86
92
|
ambiguous or changed runtime evidence. Start with one canary, verify application health externally and
|