Skip to content

Commit 79a7885

Browse files
emaicusbmcutler
authored andcommitted
[Example] Overriding the Default Submitty Router (#22)
1 parent 79300a7 commit 79a7885

File tree

2 files changed

+125
-30
lines changed

2 files changed

+125
-30
lines changed

examples/16_docker_network_python/config/config.json

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,15 @@
33
// your assignment should fail to build.
44
"autograding_method" : "docker",
55
"container_options" : {
6-
//States that a given testcase uses a router by default. (Default value is true)
7-
"use_router" : true
6+
//States that a given testcase uses a router by default. (Default value is true)
7+
"use_router" : true
88
},
99

1010
"autograding" : {
11-
"work_to_details" : [ "**/*.csv", "**/*.txt" ]
11+
"work_to_details" : [ "**/*.txt" ]
1212
},
1313
// Each testcase creates a new, unique set of docker containers and networks.
1414
"testcases" : [
15-
16-
// *************** TEST CASES *****************
1715
{
1816
//Despite the default being true, this testcase will not use a router.
1917
"use_router" : false,
@@ -28,7 +26,7 @@
2826
//outgoing_connections list the containers that this container is allowed to network to.
2927
"outgoing_connections" : ["client"]
3028
// You can specify a docker image here, and if it is built on submitty, this container
31-
// will use it. At the moment, this field defaults to ubuntu:custom if unset -- the default
29+
// will use it. If unset, this field defaults to ubuntu:custom -- the default
3230
// submitty image.
3331
//container_image : <image_name>
3432
},
@@ -38,19 +36,12 @@
3836
// In this example, we want the server to start before the client, so we add a sleep command.
3937
"commands" : ["sleep 2", "python3 client.py client 0"],
4038
"outgoing_connections" : ["server"]
41-
},
42-
{
43-
// At the moment, a router should always be specified, which relays student messages.
44-
// The router should have the unique name "router."
45-
"container_name" : "router",
46-
"commands" : ["python3 router.py"]
4739
}
4840
],
4941
"points" : 5,
5042
"validation": [
5143
{
5244
"method" : "diff",
53-
//output files are stored in a directory that matches the container_name specified above.
5445
"actual_file" : "server/STDOUT.txt",
5546
"expected_file" : "expected_server_output_0.txt",
5647
"failure_message" : "ERROR: Your code did not match the expected output.",
@@ -70,19 +61,16 @@
7061
{
7162
"title" : "Ping Pong, Ping Pong",
7263
"containers" : [
64+
//This testcase is using a router, which will be injected into the network.
7365
{
7466
"container_name" : "server",
75-
"commands" : ["python3 server.py server"], //string or array of strings.
67+
"commands" : ["python3 server.py server"],
7668
"outgoing_connections" : ["client"]
7769
},
7870
{
7971
"container_name" : "client",
8072
"commands" : ["sleep 2", "python3 client.py client 1"],
8173
"outgoing_connections" : ["server"]
82-
},
83-
{
84-
"container_name" : "router",
85-
"commands" : ["python3 router.py"]
8674
}
8775
],
8876
"points" : 5,
@@ -102,6 +90,15 @@
10290
"failure_message" : "ERROR: Your code did not match the expected output.",
10391
"show_message" : "on_failure",
10492
"deduction" : 0.5
93+
},
94+
//Adding this "sequence_diagram" filecheck will display a sequence diagram
95+
// of messages passed to the student.
96+
{
97+
"sequence_diagram" : true,
98+
"type" : "FileCheck",
99+
"title" : "Sequence Diagram Text File",
100+
"actual_file" : "router/sequence_diagram.txt",
101+
"points" : 0
105102
}
106103
]
107104
},
@@ -110,17 +107,13 @@
110107
"containers" : [
111108
{
112109
"container_name" : "server",
113-
"commands" : ["python3 server.py server"], //string or array of strings.
110+
"commands" : ["python3 server.py server"],
114111
"outgoing_connections" : ["client"]
115112
},
116113
{
117114
"container_name" : "client",
118115
"commands" : ["sleep 2", "python3 client.py client 2"],
119116
"outgoing_connections" : ["server"]
120-
},
121-
{
122-
"container_name" : "router",
123-
"commands" : ["python3 router.py"]
124117
}
125118
],
126119
"points" : 5,
@@ -140,6 +133,15 @@
140133
"failure_message" : "ERROR: Your code did not match the expected output.",
141134
"show_message" : "on_failure",
142135
"deduction" : 0.5
136+
},
137+
//Adding this "sequence_diagram" filecheck will display a sequence diagram
138+
// of messages passed to the student.
139+
{
140+
"sequence_diagram" : true,
141+
"type" : "FileCheck",
142+
"title" : "Sequence Diagram Text File",
143+
"actual_file" : "router/sequence_diagram.txt",
144+
"points" : 0
143145
}
144146
]
145147
},
@@ -148,17 +150,13 @@
148150
"containers" : [
149151
{
150152
"container_name" : "server",
151-
"commands" : ["python3 server.py server"], //string or array of strings.
153+
"commands" : ["python3 server.py server"],
152154
"outgoing_connections" : ["client"]
153155
},
154156
{
155157
"container_name" : "client",
156158
"commands" : ["sleep 2", "python3 client.py client 3"],
157159
"outgoing_connections" : ["server"]
158-
},
159-
{
160-
"container_name" : "router",
161-
"commands" : ["python3 router.py"]
162160
}
163161
],
164162
"points" : 5,
@@ -178,6 +176,15 @@
178176
"failure_message" : "ERROR: Your code did not match the expected output.",
179177
"show_message" : "on_failure",
180178
"deduction" : 0.5
179+
},
180+
//Adding this "sequence_diagram" filecheck will display a sequence diagram
181+
// of messages passed to the student.
182+
{
183+
"sequence_diagram" : true,
184+
"type" : "FileCheck",
185+
"title" : "Sequence Diagram Text File",
186+
"actual_file" : "router/sequence_diagram.txt",
187+
"points" : 0
181188
}
182189
]
183190
},
@@ -187,17 +194,19 @@
187194
"containers" : [
188195
{
189196
"container_name" : "server",
190-
"commands" : ["python3 server.py server udp_enabled"], //string or array of strings.
197+
"commands" : ["python3 server.py server udp_enabled"],
191198
"outgoing_connections" : ["client"]
192199
},
193200
{
194201
"container_name" : "client",
195202
"commands" : ["sleep 2", "python3 client.py client 4 udp_enabled"],
196203
"outgoing_connections" : ["server"]
197204
},
205+
//This testcase uses a custom router. This container must be named router
206+
// and will automatically be connected up correctly.
198207
{
199208
"container_name" : "router",
200-
"commands" : ["python3 router.py"]
209+
"commands" : ["python3 custom_router.py"]
201210
}
202211
],
203212
"points" : 5,
@@ -209,6 +218,15 @@
209218
"failure_message" : "ERROR: Your code did not match the expected output.",
210219
"show_message" : "on_failure",
211220
"deduction" : 1.0
221+
},
222+
//Adding this "sequence_diagram" filecheck will display a sequence diagram
223+
// of messages passed to the student.
224+
{
225+
"sequence_diagram" : true,
226+
"type" : "FileCheck",
227+
"title" : "Sequence Diagram Text File",
228+
"actual_file" : "router/sequence_diagram.txt",
229+
"points" : 0
212230
}
213231
]
214232
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import socket
2+
import sys
3+
import csv
4+
import traceback
5+
import queue
6+
import errno
7+
from time import sleep
8+
import os
9+
import datetime
10+
import random
11+
from datetime import timedelta
12+
13+
from submitty_router import submitty_router
14+
15+
#Custom router extends submitty_router
16+
class custom_router(submitty_router):
17+
# The constructor for our custom router
18+
def __init__(self, seed=None, log_file='router_log.txt'):
19+
super().__init__(seed=seed, log_file=log_file)
20+
21+
'''
22+
Override this function to manipuate student messages.
23+
'''
24+
def manipulate_recieved_message(self, sender, recipient, port, message, message_number):
25+
now = datetime.datetime.now()
26+
# The total time the program has been running as of right now.
27+
elapsed_time = now - self.execution_start_time
28+
# Use the time at which this message will be processed. Set to now initially.
29+
process_time = now
30+
# Leave blank to avoid outputting a message to the student on their sequence diagram
31+
message_to_student = None
32+
#If true, this message is entirely discarded.
33+
drop_me = False
34+
35+
#EXAMPLE: modify one bit of the student's message in 1/10 messages before 2 seconds
36+
if random.randint(1,10) == 10 and elapsed_time.total_seconds() <= 2:
37+
# Convert the message int an array of bytes
38+
m_array = bytearray(message)
39+
# Determine which bit will be flipped
40+
flipbit = random.randint(0,len(m_array)-1 )
41+
# Flip the bit
42+
m_array[flipbit] = m_array[flipbit] + 1
43+
# Update the message
44+
message = bytes(m_array)
45+
# OPTIONAL: Tell the student that their message was corrupted via a message in their sequence diagram.
46+
message_to_student = "Corrupted"
47+
#EXAMPLE: delay the student message by up to 1 second in 1/10 messages
48+
elif random.randint(1,10) == 10:
49+
# Choose an amount of delay (in ms) between .1 and 1 second.
50+
milliseconds_dela = random.randint(100,1000)
51+
# Extend the processing time that far into the future
52+
process_time = process_time + timedelta(milliseconds=milliseconds_dela)
53+
# OPTIONAL: add a message to the student's sequence diagram that lets them know about the delay
54+
message_to_student = "Delayed {0} ms".format(milliseconds_dela)
55+
#We drop 1/10th of packets
56+
elif random.randint(1,10) == 10:
57+
drop_me = True
58+
59+
data = {
60+
'sender' : sender,
61+
'recipient' : recipient,
62+
'port' : port,
63+
'message' : message,
64+
'message_to_student' : message_to_student,
65+
'drop_message' : drop_me
66+
}
67+
return (process_time, data)
68+
69+
70+
#You must provide a main which is capable of running your router.
71+
if __name__ == '__main__':
72+
router = custom_router()
73+
router.log("This is the custom router!")
74+
# submitty_router provides init and run functions for you to call.
75+
router.init()
76+
router.run()
77+

0 commit comments

Comments
 (0)