Skip to content

Commit 69a548d

Browse files
author
Neile Havens
committed
add support for the --user option to docker run
Username or UID to run commands as inside the container. https://docs.docker.com/engine/reference/run/#user Resolves tox-dev#135
1 parent 7b573c5 commit 69a548d

File tree

5 files changed

+43
-1
lines changed

5 files changed

+43
-1
lines changed

README.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ The ``[docker:container-name]`` section may contain the following directives:
121121
test run until the container reports healthy, and will fail the test
122122
run if it never does so (within the parameters specified).
123123

124+
``user``
125+
The `user<https://docs.docker.com/engine/reference/run/#user>`__ Username
126+
or UID to run commands as inside the container.
127+
124128
Command-Line Arguments
125129
----------------------
126130

@@ -182,6 +186,8 @@ Example
182186
# testing use cases, as this could persist data between test runs
183187
volumes =
184188
bind:rw:/my/own/datadir:/var/lib/postgresql/data
189+
# The uid (or username) to run commands as inside the container.
190+
user = 1234
185191
186192
[docker:appserv]
187193
# You can use any value that `docker run` would accept as the image

tox_docker/config.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
r"$"
2020
)
2121

22+
# uid or username. valid username regex from useradd(8)
23+
USER = re.compile(r"[a-z_][a-z0-9_-]*[$]?|[0-9]+")
24+
2225

2326
def runas_name(container_name: str, pid: Optional[int] = None) -> str:
2427
"""
@@ -103,6 +106,19 @@ def __init__(self, config_line: str) -> None:
103106
)
104107

105108

109+
class User:
110+
def __init__(self, config_line: str) -> None:
111+
match = USER.match(config_line)
112+
if not match:
113+
raise ValueError(f"{config_line!r} is not a valid user name")
114+
self.username = config_line
115+
self.uid = None
116+
try:
117+
self.uid = int(self.username)
118+
except ValueError:
119+
pass
120+
121+
106122
class ContainerConfig:
107123
def __init__(
108124
self,
@@ -118,6 +134,7 @@ def __init__(
118134
ports: Optional[Collection[Port]] = None,
119135
links: Optional[Collection[Link]] = None,
120136
volumes: Optional[Collection[Volume]] = None,
137+
user: Optional[User] = None,
121138
) -> None:
122139
self.name = name
123140
self.runas_name = runas_name(name)
@@ -139,3 +156,4 @@ def __init__(
139156
int(healthcheck_start_period) if healthcheck_start_period else None
140157
)
141158
self.healthcheck_retries = healthcheck_retries
159+
self.user = user

tox_docker/plugin.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ def docker_run(
9797
if not os.path.exists(source):
9898
raise ValueError(f"Volume source {source!r} does not exist")
9999

100+
user = None
101+
if container_config.user:
102+
user = container_config.user.uid or container_config.user.username
103+
100104
log(f"run {container_config.image!r} (from {container_config.name!r})")
101105
container = docker.containers.run(
102106
str(container_config.image),
@@ -108,6 +112,7 @@ def docker_run(
108112
ports=ports,
109113
publish_all_ports=len(ports) == 0,
110114
mounts=container_config.mounts,
115+
user=user,
111116
)
112117
container.reload() # TODO: why do we need this?
113118
return container

tox_docker/tox3/config.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
Link,
1212
Port,
1313
RunningContainers,
14+
User,
1415
Volume,
1516
)
1617

@@ -133,6 +134,10 @@ def parse_container_config(
133134
if reader.getstring("volumes"):
134135
volumes = [Volume(line) for line in reader.getlist("volumes")]
135136

137+
user = None
138+
if reader.getstring("user"):
139+
user = User(reader.getstring("user"))
140+
136141
return ContainerConfig(
137142
name=container_name,
138143
image=Image(reader.getstring("image")),
@@ -146,4 +151,5 @@ def parse_container_config(
146151
ports=ports,
147152
links=links,
148153
volumes=volumes,
154+
user=user,
149155
)

tox_docker/tox4/config.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from tox.config.sets import ConfigSet
44

5-
from tox_docker.config import ContainerConfig, Image, Link, Port, Volume
5+
from tox_docker.config import ContainerConfig, Image, Link, Port, User, Volume
66

77
# nanoseconds in a second; named "SECOND" so that "1.5 * SECOND" makes sense
88
SECOND = 1000000000
@@ -86,6 +86,12 @@ def register_config(self) -> None:
8686
default=0,
8787
desc="docker healthcheck retry count",
8888
)
89+
self.add_config(
90+
keys=["user"],
91+
of_type=User,
92+
default=None,
93+
desc="Username or UID to run commands as inside the container",
94+
)
8995

9096

9197
def parse_container_config(docker_config: DockerConfigSet) -> ContainerConfig:
@@ -102,4 +108,5 @@ def parse_container_config(docker_config: DockerConfigSet) -> ContainerConfig:
102108
ports=docker_config["ports"],
103109
links=docker_config["links"],
104110
volumes=docker_config["volumes"],
111+
user=docker_config["user"],
105112
)

0 commit comments

Comments
 (0)