Skip to content

Commit 4e04967

Browse files
committed
DevService
- changes to RealWorldRouting - replace pickle with jsonpickle -DevelopmentService for remote development with VSCode on the simulation nodes
1 parent 3aac138 commit 4e04967

File tree

11 files changed

+227
-98
lines changed

11 files changed

+227
-98
lines changed
+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Networking Application Development in SEED
2+
3+
4+
The DevelopmentService prepares a node for [Remote Development with VSCode](https://code.visualstudio.com/docs/remote/remote-overview).
5+
It installs the VSCode Remote Server on the Node during the docker image build, which allows to ssh into the running container later i.e. to debug software.
6+
7+
As of now the primary anticipated use of the seed-emulator has been the deployment of fully developed applications into an emulated szenario i.e. to observe its behaviour.
8+
9+
The DevService adapts the emulators primary paradigm of deploying fully develped applications into an emulated szenario,
10+
to meet the need of developing i.e. P2P software to maturity in a distributed environment.
11+
12+
The DevService allows for each individual node that it is installed on, to specify one or more Git repositories that shall be checked out
13+
(along with the desired filesystem path and branch) as well as the VSCode Extensions required for the projects software stack
14+
(i.e. golang.Go for the SCION-proto implementation which is written in Go)
15+
The DevService takes care to install the entirety of build and analysis tools that are needed for a given programming language at docker image build time (for Go this being i.e. the compiler, language server gopls, debugger delve) so that no annoying time delay arises once the emulator is running and you want to attach to a container.
16+
Any specified Git repositories are checked out on its own separate docker volume, for the changes to persist between runs of the simulator in case one forgets to push.
17+
18+
Software development requires a 'real Internet' connection of the container be it to git push/pull or fetch project dependencies for a build (i.e. go get, cargo build etc. )
19+
This is achieved by promoting the nodes default gateway ( router node ) in the simulation into a 'RealWorldRouter' (which has access to the `000_svc` service network)
20+
Use of a separate service network inhibits 'short-circuiting' the simulated network topology (i.e. any crosstalk past the intended network topo among nodes)
21+
22+
23+
24+
### Usage
25+
This example is meant to showcase how SEED can be made into a testbed for development of features for SCION.
26+
This is mainly achieved by two steps:
27+
- deploy your custom SCION stack inside the simulation
28+
This is achieved by setting the `SetupSpecification` option on the `ScionRouting`layer and
29+
make it point to the specific repo checkout you want to use.
30+
As a consequence a named docker volume containing the binary distributables is mounted into every node in the simulation
31+
under the `/bin/scion` path.
32+
33+
- install a GolangDevelopmentServer on every node in the emulation
34+
This turns every simulation node into a Golang development environment (with go, git, delve, gopls, vscode-server),
35+
by mounting a bunch of docker volumes into each container containing the installation.
36+
(they'll even share the module/build cache)
37+
For each repo that you check out a named docker volume will be generated that accommodates the code and is shared between all nodes.
38+
If you now set up your project build-task to output the distributables into `/bin/scion`, you just need to restart the simulation docker containers,
39+
to run and test a SCION stack with your latest changes in place.
40+
Moreover changes done to the code in one container, are visible to all others (if checkout mode is `AccessMode.shared` ),
41+
so it doesn't matter on which of the nodes you trigger a recompile. The changes will take effect on all simulation nodes.
42+
43+
44+
```
45+
spec = SetupSpecification.LOCAL_BUILD(
46+
CheckoutSpecification(
47+
mode = "build",
48+
git_repo_url = "https://github.com/johndoe/scion.git", # your SCION fork
49+
checkout = "v0.12.0" # could be tag, branch or commit-hash
50+
))
51+
routing = ScionRouting(setup_spec=OptionRegistry().scion_setup_spec(spec))
52+
```
53+
54+
55+
```
56+
devsvc = GolangDevService('jane.doe', '[email protected]')
57+
repo_url = 'https://github.com/scionproto/scion.git'
58+
repo_branch = 'v0.12.0'
59+
repo_path = '/home/root/repos/scion'
60+
61+
svc = devsvc.install(f'dev_152_cs1')
62+
svc.checkoutRepo(repo_url, repo_path, repo_branch, AccessMode.shared)
63+
emu.addBinding(Binding(f'dev_152_cs1', filter=Filter(nodeName=as152_cs1.getName(), asn=152)))
64+
65+
svc3 = devsvc.install(f'dev_153_cs1')
66+
svc3.checkoutRepo(repo_url, repo_path, repo_branch, AccessMode.shared)
67+
emu.addBinding(Binding(f'dev_153_cs1', filter=Filter(nodeName=as153_cs1.getName(), asn=153)))
68+
69+
```
70+
71+
72+
To do any development you first have to bring up the simulation `docker compose up` and then attach to one of the containers with DevServer installation
73+
(i.e. from within VSCode IDE via the [RemoteDevelopment Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) ).
74+
You can attach to multiple nodes at the same time and i.e. send a packet from the integrated terminal in one window,
75+
and hit a breakpoint set in the border router of any on-path AS once the packet eventually arrives there and step through to see if its correctly processed the way you intended.
76+
77+
![Attach to Emulator](media/attach_to_emu_container.png)
78+
79+
80+
![Develop your own SCION features in SEED](media/inside_dev_container.png)
Loading
Loading

examples/scion/S08_real_world/scion_dev_service.py renamed to examples/scion/S08_dev_service/scion_dev_service.py

+16-10
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
from seedemu.services import GolangDevService, AccessMode
66
from seedemu.core import Emulator, Binding, Filter
7-
7+
88
from seedemu.compiler import Docker
9-
from seedemu.core import Emulator
10-
from seedemu.layers import ScionBase, ScionRouting, ScionIsd, Scion
9+
from seedemu.core import Emulator, OptionRegistry
10+
from seedemu.layers import ScionBase, ScionRouting, ScionIsd, Scion, CheckoutSpecification, SetupSpecification
1111
from seedemu.layers.Scion import LinkType as ScLinkType
1212

1313
from seedemu.compiler import Docker, Platform
@@ -32,19 +32,25 @@ def run(dumpfile = None):
3232
else:
3333
print(f"Usage: {script_name} amd|arm")
3434
sys.exit(1)
35-
35+
3636
# Initialize
3737
emu = Emulator()
3838
base = ScionBase()
39-
routing = ScionRouting()
39+
spec = SetupSpecification.LOCAL_BUILD(
40+
CheckoutSpecification(
41+
mode = "build",
42+
git_repo_url = "https://github.com/scionproto/scion.git",
43+
checkout = "v0.12.0" # could be tag, branch or commit-hash
44+
))
45+
routing = ScionRouting(setup_spec=OptionRegistry().scion_setup_spec(spec))
4046
scion_isd = ScionIsd()
4147
scion = Scion()
4248

4349
devsvc = GolangDevService('jane.doe', '[email protected]')
4450
repo_url = 'https://github.com/scionproto/scion.git'
4551
repo_branch = 'v0.12.0'
4652
repo_path = '/home/root/repos/scion'
47-
53+
4854

4955

5056
# SCION ISDs
@@ -58,7 +64,7 @@ def run(dumpfile = None):
5864
scion_isd.addIsdAs(1, 150, is_core=True)
5965
as150.createNetwork('net0')
6066
as150.createControlService('cs1').joinNetwork('net0')
61-
as150_router = as150.createRealWorldRouter('br0', prefixes=['10.150.0.0/24'])# the 'auto' gen prefix of net0
67+
as150_router = as150.createRealWorldRouter('br0', prefixes=['0.0.0.0/1', '128.0.0.0/1'])
6268
# expectation: hosts from within AS150 can ping outside world i.e. 8.8.8.8
6369
# Hosts in the other ASes can't!!
6470
as150_router.joinNetwork('net0').joinNetwork('ix100')
@@ -83,8 +89,8 @@ def run(dumpfile = None):
8389
scion_isd.addIsdAs(1, 153, is_core=False)
8490
scion_isd.setCertIssuer((1, 153), issuer=150)
8591
as153.createNetwork('net0')
86-
as153_cs1 = as153.createControlService('cs1').joinNetwork('net0')
87-
92+
as153_cs1 = as153.createControlService('cs1').joinNetwork('net0')
93+
8894
as153_router = as153.createRouter('br0')
8995
as153_router.joinNetwork('net0')
9096
as153_router.crossConnect(150, 'br0', '10.50.0.3/29')
@@ -117,7 +123,7 @@ def run(dumpfile = None):
117123
emu.render()
118124

119125
###############################################################################
120-
# Compilation
126+
# Compilation
121127

122128
emu.compile(Docker(platform=platform), './output', override=True)
123129

examples/scion/S08_real_world/README.md

-50
This file was deleted.

seedemu/core/Emulator.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from typing import Dict, Set, Tuple, List
99
from sys import prefix, stderr
1010
from ipaddress import IPv4Network
11-
import pickle
11+
import jsonpickle
1212

1313
class BindingDatabase(Registrable, Printable):
1414
"""!
@@ -549,8 +549,9 @@ def dump(self, fileName: str) -> Emulator:
549549
"""
550550

551551
assert not self.__rendered, 'cannot dump emulation after render.'
552-
with open(fileName, 'wb') as f:
553-
pickle.dump(self.__registry, f)
552+
with open(fileName, 'w') as f:
553+
frozen = jsonpickle.encode(self.__registry, make_refs=False, keys=True)
554+
f.write(frozen)
554555

555556
return self
556557

@@ -563,10 +564,10 @@ def load(self, fileName: str) -> Emulator:
563564
@returns self, for chaining API calls.
564565
"""
565566

566-
with open(fileName, 'rb') as f:
567+
with open(fileName, 'r') as f:
567568
self.__rendered = False
568569
self.__dependencies_db = {}
569-
self.__registry = pickle.load(f)
570+
self.__registry = jsonpickle.decode(f.read(), keys=True)
570571
self.__layers = self.__registry.get('seedemu', 'dict', 'layersdb')
571572
self.__bindings = self.__registry.get('seedemu', 'list', 'bindingdb')
572573

seedemu/core/Network.py

+3
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,9 @@ def getRemoteAccessProvider(self) -> RemoteAccessProvider:
305305
def getExternalConnectivityProvider(self) -> ExternalConnectivityProvider:
306306
return self.__ecp
307307

308+
def getExternalConnectivityProvider(self) -> ExternalConnectivityProvider:
309+
return self.__ecp
310+
308311
def print(self, indent: int) -> str:
309312
out = ' ' * indent
310313
out += 'Network {} ({}):\n'.format(self.__name, self.__type)

0 commit comments

Comments
 (0)