Skip to content

Commit 9c49df7

Browse files
author
Danny Sauer
committed
convert to object model
1 parent 1301a29 commit 9c49df7

File tree

1 file changed

+116
-57
lines changed

1 file changed

+116
-57
lines changed

misc/dockerstress.py

Lines changed: 116 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,63 +3,122 @@
33
import argparse
44
import docker
55
import requests
6+
import threading
67
from time import sleep
78

8-
def main(target_instances):
9-
client = docker.from_env()
10-
containers = []
11-
12-
for i in range(1, target_instances + 1):
13-
containers.append(create_container(client, i))
14-
15-
for cont in containers:
16-
verify_container(cont)
17-
18-
for cont in containers:
19-
print(f"Cleaning up {cont.name}")
20-
cont.kill()
21-
#cont.remove()
22-
23-
def create_container(client, i):
24-
host = f"stresshost_{i}"
25-
print(f"creating {host}")
26-
cont = client.containers.run(
27-
"busybox",
28-
["/bin/httpd", "-fh", "/etc"],
29-
hostname=host,
30-
name=host,
31-
remove=True,
32-
detach=True,
33-
ports={"80/tcp": None}, # picks a random port
34-
publish_all_ports=True,
9+
# seems like this is something that should be built-in :/
10+
class Atomic_counter:
11+
def __init__(self, value=0):
12+
self._val = value
13+
self._lock = threading.Lock()
14+
15+
def increment(self):
16+
with self._lock:
17+
self._val += 1
18+
return self._val
19+
def inc(self):
20+
return self.increment()
21+
22+
# instance is the instance of this class, owner is the parent class
23+
def __get__(self, instance, owner):
24+
with self._lock:
25+
return self._val
26+
def __set__(self, instance, value):
27+
with self._lock:
28+
self._val = value
29+
return self._val
30+
31+
def __add__(self, other):
32+
with self._lock:
33+
self._val += other
34+
return self._val
35+
36+
def __str__(self):
37+
return self._val.__str__()
38+
39+
40+
class Dockerstress:
41+
def __init__(self, target_instances=1, threads=1):
42+
self.target_instances = target_instances
43+
self.thread_count = threads
44+
45+
self.client = docker.from_env()
46+
self.containers = []
47+
self.index = Atomic_counter()
48+
49+
def runall(self):
50+
self.create_containers()
51+
self.verify_containers()
52+
self.cleanup()
53+
54+
def create_containers(self):
55+
for i in range(1, self.target_instances + 1):
56+
self._create_container()
57+
58+
def _create_container(self):
59+
i = self.index.increment()
60+
host = f"stresshost_{i}"
61+
print(f"creating {host}")
62+
cont = self.client.containers.run(
63+
"busybox",
64+
["/bin/httpd", "-fh", "/etc"],
65+
hostname=host,
66+
name=host,
67+
remove=True,
68+
detach=True,
69+
ports={"80/tcp": None}, # picks a random port
70+
publish_all_ports=True,
71+
)
72+
# have to get the container after it's started so things like
73+
# "assigned ports" are fully populated. Otherwise we just get
74+
# the configuration value, which is None :/
75+
self.containers.append(
76+
self.client.containers.get(cont.name)
77+
)
78+
79+
def verify_containers(self):
80+
for cont in self.containers:
81+
self._verify_container(cont)
82+
83+
def _verify_container(self, cont):
84+
print(f"Verifying {cont.name}")
85+
eport = cont.attrs['NetworkSettings']['Ports']['80/tcp'][0]['HostPort']
86+
#print(f"Container {cont.name} exposes port {eport}")
87+
url=f"http://localhost:{eport}/hostname"
88+
r = requests.get(url)
89+
print(f"{url} -> '{r.text.rstrip()}'")
90+
91+
def cleanup(self):
92+
for cont in self.containers:
93+
print(f"Cleaning up {cont.name}")
94+
cont.kill()
95+
#cont.remove()
96+
97+
98+
def main(args):
99+
d = Dockerstress(target_instances=args.number, threads=args.threads)
100+
d.runall()
101+
102+
if __name__ == '__main__':
103+
parser = argparse.ArgumentParser()
104+
parser.add_argument(
105+
"number",
106+
help="number of instances (defaults to 1)",
107+
type=int,
108+
default=1,
109+
nargs='?', # make this optional
110+
)
111+
parser.add_argument(
112+
"-t", "--threads",
113+
help="Number of creation/verification threads to use",
114+
type=int,
115+
default="1",
116+
)
117+
parser.add_argument(
118+
"-v", "--verbose",
119+
help="Print more debug output",
120+
action="count",
121+
default="0",
35122
)
36-
# have to get the container after it's started so things like
37-
# "assigned ports" are fully populated. Otherwise we just get
38-
# the configuration value, which is None :/
39-
return client.containers.get(cont.name)
40-
41-
def verify_container(cont):
42-
print(f"Verifying {cont.name}")
43-
eport = cont.attrs['NetworkSettings']['Ports']['80/tcp'][0]['HostPort']
44-
#print(f"Container {cont.name} exposes port {eport}")
45-
url=f"http://localhost:{eport}/hostname"
46-
r = requests.get(url)
47-
print(f"{url} -> '{r.text.rstrip()}'")
48-
49-
parser = argparse.ArgumentParser()
50-
parser.add_argument(
51-
"number",
52-
help="number of instances (defaults to 1)",
53-
type=int,
54-
default=1,
55-
nargs='?', # make this optional
56-
)
57-
parser.add_argument(
58-
"-v", "--verbose",
59-
help="Print more debug output",
60-
action="count",
61-
default="0",
62-
)
63-
args = parser.parse_args()
64-
65-
main(args.number)
123+
args = parser.parse_args()
124+
main(args)

0 commit comments

Comments
 (0)