forked from beluga-php/docker-php-api
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathContainerAttach.php
More file actions
204 lines (191 loc) · 7.32 KB
/
Copy pathContainerAttach.php
File metadata and controls
204 lines (191 loc) · 7.32 KB
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
<?php
declare(strict_types=1);
namespace Docker\API\Endpoint;
class ContainerAttach extends \Docker\API\Runtime\Client\BaseEndpoint implements \Docker\API\Runtime\Client\Endpoint
{
use \Docker\API\Runtime\Client\EndpointTrait;
protected $id;
protected $accept;
/**
* Attach to a container to read its output or send it input. You can attach
* to the same container multiple times and you can reattach to containers
* that have been detached.
*
* Either the `stream` or `logs` parameter must be `true` for this endpoint
* to do anything.
*
* See the [documentation for the `docker attach` command](https://docs.docker.com/engine/reference/commandline/attach/)
* for more details.
*
* ### Hijacking
*
* This endpoint hijacks the HTTP connection to transport `stdin`, `stdout`,
* and `stderr` on the same socket.
*
* This is the response from the daemon for an attach request:
*
* ```
* HTTP/1.1 200 OK
* Content-Type: application/vnd.docker.raw-stream
*
* [STREAM]
* ```
*
* After the headers and two new lines, the TCP connection can now be used
* for raw, bidirectional communication between the client and server.
*
* To hint potential proxies about connection hijacking, the Docker client
* can also optionally send connection upgrade headers.
*
* For example, the client sends this request to upgrade the connection:
*
* ```
* POST /containers/16253994b7c4/attach?stream=1&stdout=1 HTTP/1.1
* Upgrade: tcp
* Connection: Upgrade
* ```
*
* The Docker daemon will respond with a `101 UPGRADED` response, and will
* similarly follow with the raw stream:
*
* ```
* HTTP/1.1 101 UPGRADED
* Content-Type: application/vnd.docker.raw-stream
* Connection: Upgrade
* Upgrade: tcp
*
* [STREAM]
* ```
*
* ### Stream format
*
* When the TTY setting is disabled in [`POST /containers/create`](#operation/ContainerCreate),
* the HTTP Content-Type header is set to application/vnd.docker.multiplexed-stream
* and the stream over the hijacked connected is multiplexed to separate out
* `stdout` and `stderr`. The stream consists of a series of frames, each
* containing a header and a payload.
*
* The header contains the information which the stream writes (`stdout` or
* `stderr`). It also contains the size of the associated frame encoded in
* the last four bytes (`uint32`).
*
* It is encoded on the first eight bytes like this:
*
* ```go
* header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}
* ```
*
* `STREAM_TYPE` can be:
*
* - 0: `stdin` (is written on `stdout`)
* - 1: `stdout`
* - 2: `stderr`
*
* `SIZE1, SIZE2, SIZE3, SIZE4` are the four bytes of the `uint32` size
* encoded as big endian.
*
* Following the header is the payload, which is the specified number of
* bytes of `STREAM_TYPE`.
*
* The simplest way to implement this protocol is the following:
*
* 1. Read 8 bytes.
* 2. Choose `stdout` or `stderr` depending on the first byte.
* 3. Extract the frame size from the last four bytes.
* 4. Read the extracted size and output it on the correct output.
* 5. Goto 1.
*
* ### Stream format when using a TTY
*
* When the TTY setting is enabled in [`POST /containers/create`](#operation/ContainerCreate),
* the stream is not multiplexed. The data exchanged over the hijacked
* connection is simply the raw data from the process PTY and client's
* `stdin`.
*
* @param string $id ID or name of the container
* @param array $queryParameters {
*
* @var string $detachKeys Override the key sequence for detaching a container.Format is a single
* character `[a-Z]` or `ctrl-<value>` where `<value>` is one of: `a-z`,
* `@`, `^`, `[`, `,` or `_`.
* @var bool $logs Replay previous logs from the container.
*
* This is useful for attaching to a container that has started and you
* want to output everything since the container started.
*
* If `stream` is also enabled, once all the previous output has been
* returned, it will seamlessly transition into streaming current
* output.
* @var bool $stream stream attached streams from the time the request was made onwards
* @var bool $stdin Attach to `stdin`
* @var bool $stdout Attach to `stdout`
* @var bool $stderr Attach to `stderr`
* }
*
* @param array $accept Accept content header application/vnd.docker.raw-stream|application/vnd.docker.multiplexed-stream|application/json
*/
public function __construct(string $id, array $queryParameters = [], array $accept = [])
{
$this->id = $id;
$this->queryParameters = $queryParameters;
$this->accept = $accept;
}
public function getMethod(): string
{
return 'POST';
}
public function getUri(): string
{
return str_replace(['{id}'], [$this->id], '/containers/{id}/attach');
}
public function getBody(\Symfony\Component\Serializer\SerializerInterface $serializer, $streamFactory = null): array
{
return [[], null];
}
public function getExtraHeaders(): array
{
if (empty($this->accept)) {
return ['Accept' => ['application/vnd.docker.raw-stream', 'application/vnd.docker.multiplexed-stream', 'application/json']];
}
return $this->accept;
}
protected function getQueryOptionsResolver(): \Symfony\Component\OptionsResolver\OptionsResolver
{
$optionsResolver = parent::getQueryOptionsResolver();
$optionsResolver->setDefined(['detachKeys', 'logs', 'stream', 'stdin', 'stdout', 'stderr']);
$optionsResolver->setRequired([]);
$optionsResolver->setDefaults(['logs' => false, 'stream' => false, 'stdin' => false, 'stdout' => false, 'stderr' => false]);
$optionsResolver->addAllowedTypes('detachKeys', ['string']);
$optionsResolver->addAllowedTypes('logs', ['bool']);
$optionsResolver->addAllowedTypes('stream', ['bool']);
$optionsResolver->addAllowedTypes('stdin', ['bool']);
$optionsResolver->addAllowedTypes('stdout', ['bool']);
$optionsResolver->addAllowedTypes('stderr', ['bool']);
return $optionsResolver;
}
/**
* @throws \Docker\API\Exception\ContainerAttachNotFoundException
*
* @return null
*/
protected function transformResponseBody(\Psr\Http\Message\ResponseInterface $response, \Symfony\Component\Serializer\SerializerInterface $serializer, ?string $contentType = null)
{
$status = $response->getStatusCode();
$body = (string) $response->getBody();
if (101 === $status) {
}
if (200 === $status) {
}
if (400 === $status) {
}
if ((null === $contentType) === false && (404 === $status && false !== mb_strpos($contentType, 'application/json'))) {
throw new \Docker\API\Exception\ContainerAttachNotFoundException($response);
}
if (500 === $status) {
}
}
public function getAuthenticationScopes(): array
{
return [];
}
}