Skip to content

Commit cabe716

Browse files
authored
Merge pull request #200 from thom311/th/simple-exec
[th/simple-exec] add "--exec" option to "simple" test to run arbitrary script instead
2 parents bfe3626 + 137a799 commit cabe716

File tree

2 files changed

+93
-1
lines changed

2 files changed

+93
-1
lines changed

scripts/build-container.sh

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
3+
TAG="${TAG:-quay.io/$USER/kubernetes-traffic-flow-tests:latest}"
4+
5+
set -ex
6+
7+
TAG="${1:-$TAG}"
8+
9+
buildah manifest rm kubernetes-traffic-flow-tests-manifest || true
10+
buildah manifest create kubernetes-traffic-flow-tests-manifest
11+
buildah build --manifest kubernetes-traffic-flow-tests-manifest --platform linux/amd64,linux/arm64 -t "$TAG" .
12+
buildah manifest push --all kubernetes-traffic-flow-tests-manifest "docker://$TAG"

scripts/simple-tcp-server-client.py

+81-1
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
import random
66
import socket
77
import sys
8+
import shlex
89
import time
910

1011
from collections.abc import Iterator
1112
from contextlib import contextmanager
13+
from typing import Any
1214
from typing import Callable
1315
from typing import Optional
1416

@@ -229,6 +231,41 @@ def done_msg() -> None:
229231
sleep_timeout("client", start_time, duration, sleep, done_msg=done_msg)
230232

231233

234+
def run_exec(
235+
exec_url: str,
236+
exec_args: list[str],
237+
server: bool,
238+
s_addr: str,
239+
port: int,
240+
duration: float,
241+
) -> None:
242+
log_prefix = "server:" if server else "client: "
243+
244+
import urllib.request
245+
import urllib.parse
246+
247+
path = urllib.parse.urlparse(exec_url).path
248+
basename = os.path.basename(path)
249+
250+
filename = f"/tmp/simple-exec{'.'+basename if basename else ''}"
251+
252+
print(f"{log_prefix}downloading exec URL {repr(exec_url)} to {filename}")
253+
urllib.request.urlretrieve(exec_url, filename)
254+
255+
os.chmod(filename, 0o755)
256+
257+
env = os.environ.copy()
258+
env["SERVER"] = "1" if server else "0"
259+
env["ADDR"] = s_addr
260+
env["PORT"] = str(port)
261+
env["DURATION"] = str(duration)
262+
env["ORIG_ARGS_N"] = str(len(sys.argv))
263+
for idx, a in enumerate(sys.argv):
264+
env[f"ORIG_ARGS_{idx}"] = sys.argv[idx]
265+
266+
os.execve(filename, [filename] + exec_args, env)
267+
268+
232269
def parse_args() -> argparse.Namespace:
233270
parser = argparse.ArgumentParser(description="Simple TCP echo server/client")
234271
parser.add_argument(
@@ -276,12 +313,55 @@ def parse_args() -> argparse.Namespace:
276313
help=f"For the server, how many clients are accepted (server can only handle one client at a time) (default: {DEFAULT_NUM_CLIENTS})",
277314
default=DEFAULT_NUM_CLIENTS, # noqa: E225
278315
)
316+
parser.add_argument(
317+
"--exec",
318+
default=None,
319+
help='A HTTP URL to a script. If set, this script is downloaded and executed (set a shebang!). Environment variables SERVER, ADDR, PORT, DURATION are set and "--exec-args" options are passed. This allows to easily hack the code that runs by injecting a script from the internet.',
320+
)
321+
322+
class AppendExecArgs(argparse.Action):
323+
def __call__(
324+
self,
325+
parser: argparse.ArgumentParser,
326+
namespace: argparse.Namespace,
327+
values: Any,
328+
option_string: Optional[str] = None,
329+
) -> None:
330+
if option_string == "--exec-args":
331+
namespace.exec_args.extend(shlex.split(values))
332+
else:
333+
namespace.exec_args.append(values)
334+
335+
parser.add_argument(
336+
"--exec-args",
337+
action=AppendExecArgs,
338+
dest="exec_args",
339+
default=[],
340+
help='If "--exec" is set, specify the command line argument passed to the script. The parameter is parsed with shlex.split() (use shlex.quote() to ensure it is not split or use "--exec-arg" option). Can be specified multiple times and combined with "--exec-arg", in which case all entries are concatenated.',
341+
)
342+
parser.add_argument(
343+
"-E",
344+
"--exec-arg",
345+
action=AppendExecArgs,
346+
dest="exec_args",
347+
help='If "--exec" is set, specify the command line argument passed to the script. Similar to "--exec-args", but this is a single command line argument used as-is. Can be specified multiple times and combined with "--exec-args", in which all case entries are concatenated.',
348+
)
349+
279350
return parser.parse_args()
280351

281352

282353
def main() -> None:
283354
args = parse_args()
284-
if args.server:
355+
if args.exec is not None:
356+
run_exec(
357+
exec_url=args.exec,
358+
exec_args=args.exec_args,
359+
server=args.server,
360+
s_addr=args.addr,
361+
port=args.port,
362+
duration=args.duration,
363+
)
364+
elif args.server:
285365
run_server(
286366
s_addr=args.addr,
287367
port=args.port,

0 commit comments

Comments
 (0)