0
# Container Operations
1
2
Operation classes that abstract the differences between running containers and executing commands in existing containers. These classes implement the Operation interface and handle the specific details of Docker API interactions.
3
4
## Capabilities
5
6
### Run Operation
7
8
Handles `docker run`-like commands where you start a new container with PTY support.
9
10
```python { .api }
11
class RunOperation:
12
def __init__(self, client, container, interactive=True, stdout=None, stderr=None, stdin=None, logs=None):
13
"""
14
Initialize the PTY for docker run-like operations.
15
16
Parameters:
17
- client: Docker client instance
18
- container: Container dict or ID
19
- interactive: bool, whether to enable interactive mode (default: True)
20
- stdout: file-like object for stdout (default: sys.stdout)
21
- stderr: file-like object for stderr (default: sys.stderr)
22
- stdin: file-like object for stdin (default: sys.stdin)
23
- logs: int, whether to include logs (default: None, shows deprecation warning)
24
"""
25
26
def start(self, sockets=None, **kwargs):
27
"""
28
Present the PTY of the container inside the current process.
29
30
This will take over the current process' TTY until the container's PTY is closed.
31
If the container is not running, it will be started.
32
33
Parameters:
34
- sockets: tuple of (stdin_socket, stdout_socket, stderr_socket), optional
35
- **kwargs: Additional arguments passed to client.start()
36
37
Returns:
38
List of Pump instances for stream management
39
"""
40
41
def israw(self, **kwargs):
42
"""
43
Returns True if the PTY should operate in raw mode.
44
45
If the container was not started with tty=True, this will return False.
46
47
Parameters:
48
- **kwargs: Additional arguments (unused)
49
50
Returns:
51
bool - True if PTY should use raw mode
52
"""
53
54
def sockets(self):
55
"""
56
Returns a tuple of sockets connected to the pty (stdin,stdout,stderr).
57
58
If any of the sockets are not attached in the container, None is
59
returned in the tuple.
60
61
Returns:
62
tuple - (stdin_socket, stdout_socket, stderr_socket) or None for missing sockets
63
"""
64
65
def resize(self, height, width, **kwargs):
66
"""
67
Resize pty within container.
68
69
Parameters:
70
- height: int, terminal height in rows
71
- width: int, terminal width in columns
72
- **kwargs: Additional arguments (unused)
73
74
Returns:
75
None
76
"""
77
```
78
79
Usage example:
80
81
```python
82
import docker
83
from dockerpty import RunOperation, PseudoTerminal
84
85
client = docker.Client()
86
container = client.create_container(
87
image='alpine:latest',
88
stdin_open=True,
89
tty=True,
90
command='/bin/sh',
91
)
92
93
# Create and start operation
94
operation = RunOperation(client, container, interactive=True)
95
pty = PseudoTerminal(client, operation)
96
pty.start()
97
```
98
99
### Exec Operation
100
101
Handles `docker exec`-like commands where you execute a command in an existing running container.
102
103
```python { .api }
104
class ExecOperation:
105
def __init__(self, client, exec_id, interactive=True, stdout=None, stderr=None, stdin=None):
106
"""
107
Initialize the PTY for docker exec-like operations.
108
109
Parameters:
110
- client: Docker client instance
111
- exec_id: Exec instance ID (from client.exec_create())
112
- interactive: bool, whether to enable interactive mode (default: True)
113
- stdout: file-like object for stdout (default: sys.stdout)
114
- stderr: file-like object for stderr (default: sys.stderr)
115
- stdin: file-like object for stdin (default: sys.stdin)
116
"""
117
118
def start(self, sockets=None, **kwargs):
119
"""
120
Start execution of the exec command.
121
122
Parameters:
123
- sockets: socket for exec I/O, optional
124
- **kwargs: Additional arguments (unused)
125
126
Returns:
127
List of Pump instances for stream management
128
"""
129
130
def israw(self, **kwargs):
131
"""
132
Returns True if the PTY should operate in raw mode.
133
134
If the exec was not started with tty=True, this will return False.
135
136
Parameters:
137
- **kwargs: Additional arguments (unused)
138
139
Returns:
140
bool - True if PTY should use raw mode
141
"""
142
143
def sockets(self):
144
"""
145
Return a single socket which is processing all I/O to exec.
146
147
Returns:
148
Stream or Demuxer instance for exec I/O
149
"""
150
151
def resize(self, height, width, **kwargs):
152
"""
153
Resize pty of an execed process.
154
155
Parameters:
156
- height: int, terminal height in rows
157
- width: int, terminal width in columns
158
- **kwargs: Additional arguments (unused)
159
160
Returns:
161
None
162
"""
163
164
def is_process_tty(self):
165
"""
166
Does execed process have allocated tty?
167
168
Returns:
169
bool - True if process has TTY allocated
170
"""
171
```
172
173
Usage example:
174
175
```python
176
import docker
177
from dockerpty import ExecOperation, PseudoTerminal
178
179
client = docker.Client()
180
container_id = 'running_container_id'
181
182
# Create exec instance
183
exec_id = client.exec_create(container_id, '/bin/bash', tty=True, stdin=True)
184
185
# Create and start operation
186
operation = ExecOperation(client, exec_id['Id'], interactive=True)
187
pty = PseudoTerminal(client, operation)
188
pty.start()
189
```
190
191
### Exec Creation Utility
192
193
Convenience function for creating exec instances.
194
195
```python { .api }
196
def exec_create(client, container, command, interactive=True):
197
"""
198
Create exec instance for container.
199
200
Parameters:
201
- client: Docker client instance
202
- container: Container dict or ID
203
- command: str or list, command to execute
204
- interactive: bool, whether to enable interactive mode (default: True)
205
206
Returns:
207
dict - Exec instance information with 'Id' key
208
"""
209
```
210
211
Usage example:
212
213
```python
214
import docker
215
from dockerpty import exec_create
216
217
client = docker.Client()
218
container_id = 'running_container_id'
219
220
# Create exec instance
221
exec_id = exec_create(client, container_id, ['/bin/bash', '-l'])
222
print(exec_id['Id']) # Exec instance ID
223
```
224
225
### Operation Base Class
226
227
Abstract base class defining the operation interface.
228
229
```python { .api }
230
class Operation:
231
def israw(self, **kwargs):
232
"""Are we dealing with a tty or not?"""
233
raise NotImplementedError()
234
235
def start(self, **kwargs):
236
"""Start execution."""
237
raise NotImplementedError()
238
239
def resize(self, height, width, **kwargs):
240
"""If we have terminal, resize it."""
241
raise NotImplementedError()
242
243
def sockets(self):
244
"""Return sockets for streams."""
245
raise NotImplementedError()
246
```
247
248
## Key Differences
249
250
### RunOperation vs ExecOperation
251
252
**RunOperation** (for new containers):
253
- Can start stopped containers
254
- Returns separate stdin, stdout, stderr sockets
255
- Handles container lifecycle management
256
- Supports logs parameter for including container logs
257
258
**ExecOperation** (for existing containers):
259
- Works only with running containers
260
- Returns single multiplexed socket for all I/O
261
- Cannot distinguish stderr from stdout in current implementation
262
- More lightweight for command execution
263
264
### Stream Handling
265
266
- **RunOperation**: Uses separate streams that may be demultiplexed if no TTY
267
- **ExecOperation**: Uses single stream, always demultiplexed if no TTY
268
- Both support TTY mode for raw terminal interaction
269
270
## Error Handling
271
272
- Handles container inspection failures
273
- Manages resize failures (container may have exited)
274
- Supports graceful degradation when TTY is not available
275
- Properly handles Docker API connectivity issues