Skip to content

Commit 0fe3acf

Browse files
committed
Enable passing a docker container ID directly.
This makes it possible to target an existing docker container from the command line without using the `docker_container_id` host data variable. Additionally this changes the disconnect behaviour to only commit and stop the container when starting with an image. When executing against a container we leave it as-is.
1 parent a7fe8bf commit 0fe3acf

File tree

2 files changed

+43
-11
lines changed

2 files changed

+43
-11
lines changed

docs/connectors.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,27 @@ pyinfra @local ...
4141

4242
## `@docker`
4343

44+
The `@docker` connector allows you to build Docker images, or modify running Docker containers, using ``pyinfra``. You can pass either an image name or existing container ID:
4445

45-
The `@docker` connector allows you to build Docker containers using pyinfra.
46+
+ Image - will create a container from the image, execute operations and save into a new image
47+
+ Existing container ID - will simply execute operations against the container, leaving it up afterwards
4648

4749
```sh
4850
# A Docker base image must be provided
4951
pyinfra @docker/alpine:3.8 ...
5052

5153
# pyinfra can run on multiple Docker images in parallel
5254
pyinfra @docker/alpine:3.8,@docker/ubuntu:bionic ...
55+
56+
# Execute against a running container
57+
pyinfra @docker/2beb8c15a1b1 ...
5358
```
5459

5560
**Available Data**:
5661

5762
```py
5863
# Provide a specific container ID - prevents pyinfra starting a new container and will instead use
59-
# whatever is provided in the name.
64+
# whatever is provided in the name. This is the same as passing container ID via the CLI above.
6065
docker_container_id = 'abc'
6166
```
6267

pyinfra/api/connectors/docker.py

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
import os
23

34
from tempfile import mkstemp
@@ -23,25 +24,51 @@ def make_names_data(image=None):
2324
yield '@docker/{0}'.format(image), {'docker_image': image}, ['@docker']
2425

2526

26-
def connect(state, host):
27-
if 'docker_container_id' in host.host_data: # user can provide a docker_container_id
28-
return True
27+
def _find_start_docker_container(container_id):
28+
docker_info = local.shell('docker container inspect {0}'.format(container_id))
29+
docker_info = json.loads(docker_info)[0]
30+
if docker_info['State']['Running'] is False:
31+
logger.info('Starting stopped container: {0}'.format(container_id))
32+
local.shell('docker container start {0}'.format(container_id))
33+
2934

35+
def _start_docker_image(image_name):
3036
try:
31-
with progress_spinner({'docker run'}):
32-
container_id = local.shell(
33-
'docker run -d {0} tail -f /dev/null'.format(host.data.docker_image),
34-
splitlines=True,
35-
)[-1] # last line is the container ID
37+
return local.shell(
38+
'docker run -d {0} tail -f /dev/null'.format(image_name),
39+
splitlines=True,
40+
)[-1] # last line is the container ID
3641
except PyinfraError as e:
3742
raise ConnectError(e.args[0])
3843

44+
45+
def connect(state, host):
46+
if 'docker_container_id' in host.host_data: # user can provide a docker_container_id
47+
host.host_data['docker_container_no_disconnect'] = True
48+
return True
49+
50+
with progress_spinner({'prepare docker container'}):
51+
try:
52+
# Check if the provided @docker/X is an existing container ID
53+
_find_start_docker_container(host.data.docker_image)
54+
except PyinfraError:
55+
container_id = _start_docker_image(host.data.docker_image)
56+
else:
57+
container_id = host.data.docker_image
58+
host.host_data['docker_container_no_disconnect'] = True
59+
3960
host.host_data['docker_container_id'] = container_id
4061
return True
4162

4263

4364
def disconnect(state, host):
44-
container_id = host.host_data['docker_container_id'][:12]
65+
container_id = host.host_data['docker_container_id']
66+
67+
if host.host_data.get('docker_container_no_disconnect'):
68+
logger.info('{0}docker build complete, container left running: {1}'.format(
69+
host.print_prefix, click.style(container_id, bold=True),
70+
))
71+
return
4572

4673
with progress_spinner({'docker commit'}):
4774
image_id = local.shell(

0 commit comments

Comments
 (0)