docs: adding tutorial 1
This commit is contained in:
parent
01585b6ec5
commit
a5727e3355
12 changed files with 764 additions and 0 deletions
22
docs/tutorials/common/grpc.md
Normal file
22
docs/tutorials/common/grpc.md
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
## gRPC Python Scripts
|
||||||
|
|
||||||
|
You can also run the same steps above, using the provided gRPC script versions of scenarios.
|
||||||
|
Below are the steps to run and join one of these scenario, then you can continue with
|
||||||
|
the remaining steps of a given section.
|
||||||
|
|
||||||
|
1. Make sure the CORE daemon is running a terminal, if not already
|
||||||
|
``` shell
|
||||||
|
sudop core-daemon
|
||||||
|
```
|
||||||
|
2. From another terminal run the tutorial python script, which will create a session to join
|
||||||
|
``` shell
|
||||||
|
/opt/core/venv/bin/python scenario.py
|
||||||
|
```
|
||||||
|
3. In another terminal run the CORE GUI
|
||||||
|
``` shell
|
||||||
|
core-gui
|
||||||
|
```
|
||||||
|
4. You will be presented with sessions to join, select the one created by the script
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/tutorial-common/running-join.png" width="75%">
|
||||||
|
</p>
|
82
docs/tutorials/setup.md
Normal file
82
docs/tutorials/setup.md
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
# Tutorial Setup
|
||||||
|
|
||||||
|
## Setup for CORE
|
||||||
|
|
||||||
|
We assume the prior installation of CORE, using a virtual environment. You can
|
||||||
|
then adjust your PATH and add an alias to help more conveniently run CORE
|
||||||
|
commands.
|
||||||
|
|
||||||
|
This can be setup in your **.bashrc**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
export PATH=$PATH:/opt/core/venv/bin
|
||||||
|
alias sudop='sudo env PATH=$PATH'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Setup for Chat App
|
||||||
|
|
||||||
|
There is a simple TCP chat app provided as example software to use and run within
|
||||||
|
the tutorials provided.
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
The following will install chatapp and its scripts into **/usr/local**, which you
|
||||||
|
may need to add to PATH within node to be able to use command directly.
|
||||||
|
|
||||||
|
``` shell
|
||||||
|
sudo python3 -m pip install .
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
|
||||||
|
Some Linux distros will not have **/usr/local** in their PATH and you
|
||||||
|
will need to compensate.
|
||||||
|
|
||||||
|
``` shell
|
||||||
|
export PATH=$PATH:/usr/local
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running the Server
|
||||||
|
|
||||||
|
The server will print and log connected clients and their messages.
|
||||||
|
|
||||||
|
``` shell
|
||||||
|
usage: chatapp-server [-h] [-a ADDRESS] [-p PORT]
|
||||||
|
|
||||||
|
chat app server
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-a ADDRESS, --address ADDRESS
|
||||||
|
address to listen on (default: )
|
||||||
|
-p PORT, --port PORT port to listen on (default: 9001)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running the Client
|
||||||
|
|
||||||
|
The client will print and log messages from other clients and their join/leave status.
|
||||||
|
|
||||||
|
``` shell
|
||||||
|
usage: chatapp-client [-h] -a ADDRESS [-p PORT]
|
||||||
|
|
||||||
|
chat app client
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-a ADDRESS, --address ADDRESS
|
||||||
|
address to listen on (default: None)
|
||||||
|
-p PORT, --port PORT port to listen on (default: 9001)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Installing the Chat App Service
|
||||||
|
|
||||||
|
1. You will first need to edit **/etc/core/core.conf** to update the config
|
||||||
|
service path to pick up your service
|
||||||
|
``` shell
|
||||||
|
custom_config_services_dir = <path for service>
|
||||||
|
```
|
||||||
|
2. Then you will need to copy/move **chatapp/chatapp_service.py** to the directory
|
||||||
|
configured above
|
||||||
|
3. Then you will need to restart the **core-daemon** to pick up this new service
|
||||||
|
4. Now the service will be an available option under the group **ChatApp** with
|
||||||
|
the name **ChatApp Server**
|
250
docs/tutorials/tutorial1.md
Normal file
250
docs/tutorials/tutorial1.md
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
# Tutorial 1 - Wired Network
|
||||||
|
|
||||||
|
This tutorial will cover some use cases when using a wired 2 node
|
||||||
|
scenario in CORE.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/tutorial1/scenario.png" width="75%">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
Below is the list of files used for this tutorial.
|
||||||
|
|
||||||
|
* 2 node wired scenario
|
||||||
|
* scenario.xml
|
||||||
|
* scenario.py
|
||||||
|
* 2 node wired scenario, with **n1** running the "Chat App Server" service
|
||||||
|
* scenario_service.xml
|
||||||
|
* scenario_service.py
|
||||||
|
|
||||||
|
## Running this Tutorial
|
||||||
|
|
||||||
|
This section covers interactions that can be carried out for this scenario.
|
||||||
|
|
||||||
|
Our scenario has the following nodes and addresses:
|
||||||
|
|
||||||
|
* n1 - 10.0.0.20
|
||||||
|
* n2 - 10.0.0.21
|
||||||
|
|
||||||
|
All usages below assume a clean scenario start.
|
||||||
|
|
||||||
|
### Using Ping
|
||||||
|
|
||||||
|
Using the command line utility **ping** can be a good way to verify connectivity
|
||||||
|
between nodes in CORE.
|
||||||
|
|
||||||
|
* Make sure the CORE daemon is running a terminal, if not already
|
||||||
|
``` shell
|
||||||
|
sudop core-daemon
|
||||||
|
```
|
||||||
|
* In another terminal run the GUI
|
||||||
|
``` shell
|
||||||
|
core-gui
|
||||||
|
```
|
||||||
|
* In the GUI menu bar select **File->Open...**, then navigate to and select **scenario.xml**
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/tutorial-common/running-open.png" width="75%">
|
||||||
|
</p>
|
||||||
|
* You can now click on the **Start Session** button to run the scenario
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/tutorial1/scenario.png" width="75%">
|
||||||
|
</p>
|
||||||
|
* Open a terminal on **n1** by double clicking it in the GUI
|
||||||
|
* Run the following in **n1** terminal
|
||||||
|
``` shell
|
||||||
|
ping -c 3 10.0.0.21
|
||||||
|
```
|
||||||
|
* You should see the following output
|
||||||
|
``` shell
|
||||||
|
PING 10.0.0.21 (10.0.0.21) 56(84) bytes of data.
|
||||||
|
64 bytes from 10.0.0.21: icmp_seq=1 ttl=64 time=0.085 ms
|
||||||
|
64 bytes from 10.0.0.21: icmp_seq=2 ttl=64 time=0.079 ms
|
||||||
|
64 bytes from 10.0.0.21: icmp_seq=3 ttl=64 time=0.072 ms
|
||||||
|
|
||||||
|
--- 10.0.0.21 ping statistics ---
|
||||||
|
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
|
||||||
|
rtt min/avg/max/mdev = 0.072/0.078/0.085/0.011 ms
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using Tcpdump
|
||||||
|
|
||||||
|
Using **tcpdump** can be very beneficial for examining a network. You can verify
|
||||||
|
traffic being sent/received among many other uses.
|
||||||
|
|
||||||
|
* Make sure the CORE daemon is running a terminal, if not already
|
||||||
|
``` shell
|
||||||
|
sudop core-daemon
|
||||||
|
```
|
||||||
|
* In another terminal run the GUI
|
||||||
|
``` shell
|
||||||
|
core-gui
|
||||||
|
```
|
||||||
|
* In the GUI menu bar select **File->Open...**, then navigate to and select **scenario.xml**
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/tutorial-common/running-open.png" width="75%">
|
||||||
|
</p>
|
||||||
|
* You can now click on the **Start Session** button to run the scenario
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/tutorial1/scenario.png" width="75%">
|
||||||
|
</p>
|
||||||
|
* Open a terminal on **n1** by double clicking it in the GUI
|
||||||
|
* Open a terminal on **n2** by double clicking it in the GUI
|
||||||
|
* Run the following in **n2** terminal
|
||||||
|
``` shell
|
||||||
|
tcpdump -lenni eth0
|
||||||
|
```
|
||||||
|
* Run the following in **n1** terminal
|
||||||
|
``` shell
|
||||||
|
ping -c 1 10.0.0.21
|
||||||
|
```
|
||||||
|
* You should see the following in **n2** terminal
|
||||||
|
``` shell
|
||||||
|
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
|
||||||
|
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
|
||||||
|
10:23:04.685292 00:00:00:aa:00:00 > 00:00:00:aa:00:01, ethertype IPv4 (0x0800), length 98: 10.0.0.20 > 10.0.0.21: ICMP echo request, id 67, seq 1, length 64
|
||||||
|
10:23:04.685329 00:00:00:aa:00:01 > 00:00:00:aa:00:00, ethertype IPv4 (0x0800), length 98: 10.0.0.21 > 10.0.0.20: ICMP echo reply, id 67, seq 1, length 64
|
||||||
|
```
|
||||||
|
|
||||||
|
### Editing a Link
|
||||||
|
|
||||||
|
You can edit links between nodes in CORE to modify loss, delay, bandwidth, and more. This can be
|
||||||
|
beneficial for understanding how software will behave in adverse conditions.
|
||||||
|
|
||||||
|
* Make sure the CORE daemon is running a terminal, if not already
|
||||||
|
``` shell
|
||||||
|
sudop core-daemon
|
||||||
|
```
|
||||||
|
* In another terminal run the GUI
|
||||||
|
``` shell
|
||||||
|
core-gui
|
||||||
|
```
|
||||||
|
* In the GUI menu bar select **File->Open...**, then navigate to and select **scenario.xml**
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/tutorial-common/running-open.png" width="75%">
|
||||||
|
</p>
|
||||||
|
* You can now click on the **Start Session** button to run the scenario
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/tutorial1/scenario.png" width="75%">
|
||||||
|
</p>
|
||||||
|
* Right click the link between **n1** and **n2**
|
||||||
|
* Select **Configure**
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/tutorial1/link-config.png" width="75%">
|
||||||
|
</p>
|
||||||
|
* Update the loss to **25**
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/tutorial1/link-config-dialog.png" width="50%">
|
||||||
|
</p>
|
||||||
|
* Open a terminal on **n1** by double clicking it in the GUI
|
||||||
|
* Run the following in **n1** terminal
|
||||||
|
``` shell
|
||||||
|
ping -c 10 10.0.0.21
|
||||||
|
```
|
||||||
|
* You should see something similar for the summary output, reflecting the change in loss
|
||||||
|
``` shell
|
||||||
|
--- 10.0.0.21 ping statistics ---
|
||||||
|
10 packets transmitted, 6 received, 40% packet loss, time 9000ms
|
||||||
|
rtt min/avg/max/mdev = 0.077/0.093/0.108/0.016 ms
|
||||||
|
```
|
||||||
|
* Remember that the loss above is compounded, since a ping and the loss applied occurs in both directions
|
||||||
|
|
||||||
|
### Running Software
|
||||||
|
|
||||||
|
We will now leverage the installed Chat App software to stand up a server and client
|
||||||
|
within the nodes of our scenario.
|
||||||
|
|
||||||
|
* Make sure the CORE daemon is running a terminal, if not already
|
||||||
|
``` shell
|
||||||
|
sudop core-daemon
|
||||||
|
```
|
||||||
|
* In another terminal run the GUI
|
||||||
|
``` shell
|
||||||
|
core-gui
|
||||||
|
```
|
||||||
|
* In the GUI menu bar select **File->Open...**, then navigate to and select **scenario.xml**
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/tutorial-common/running-open.png" width="75%">
|
||||||
|
</p>
|
||||||
|
* You can now click on the **Start Session** button to run the scenario
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/tutorial1/scenario.png" width="75%">
|
||||||
|
</p>
|
||||||
|
* Open a terminal on **n1** by double clicking it in the GUI
|
||||||
|
* Run the following in **n1** terminal
|
||||||
|
``` shell
|
||||||
|
export PATH=$PATH:/usr/local/bin
|
||||||
|
chatapp-server
|
||||||
|
```
|
||||||
|
* Open a terminal on **n2** by double clicking it in the GUI
|
||||||
|
* Run the following in **n2** terminal
|
||||||
|
``` shell
|
||||||
|
export PATH=$PATH:/usr/local/bin
|
||||||
|
chatapp-client -a 10.0.0.20
|
||||||
|
```
|
||||||
|
* You will see the following output in **n1** terminal
|
||||||
|
``` shell
|
||||||
|
chat server listening on: :9001
|
||||||
|
[server] 10.0.0.21:44362 joining
|
||||||
|
```
|
||||||
|
* Type the following in **n2** terminal and hit enter
|
||||||
|
``` shell
|
||||||
|
hello world
|
||||||
|
```
|
||||||
|
* You will see the following output in **n1** terminal
|
||||||
|
``` shell
|
||||||
|
chat server listening on: :9001
|
||||||
|
[server] 10.0.0.21:44362 joining
|
||||||
|
[10.0.0.21:44362] hello world
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tailing a Log
|
||||||
|
|
||||||
|
In this case we are using the service based scenario. This will automatically start
|
||||||
|
and run the Chat App Server on **n1** and log to a file. This case will demonstrate
|
||||||
|
using `tail -f` to observe the output of running software.
|
||||||
|
|
||||||
|
* Make sure the CORE daemon is running a terminal, if not already
|
||||||
|
``` shell
|
||||||
|
sudop core-daemon
|
||||||
|
```
|
||||||
|
* In another terminal run the GUI
|
||||||
|
``` shell
|
||||||
|
core-gui
|
||||||
|
```
|
||||||
|
* In the GUI menu bar select **File->Open...**, then navigate to and select **scenario_service.xml**
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/tutorial-common/running-open.png" width="75%">
|
||||||
|
</p>
|
||||||
|
* You can now click on the **Start Session** button to run the scenario
|
||||||
|
<p align="center">
|
||||||
|
<img src="images/tutorial1/scenario.png" width="75%">
|
||||||
|
</p>
|
||||||
|
* Open a terminal on **n1** by double clicking it in the GUI
|
||||||
|
* Run the following in **n1** terminal
|
||||||
|
``` shell
|
||||||
|
tail -f chatapp.log
|
||||||
|
```
|
||||||
|
* Open a terminal on **n2** by double clicking it in the GUI
|
||||||
|
* Run the following in **n2** terminal
|
||||||
|
``` shell
|
||||||
|
export PATH=$PATH:/usr/local/bin
|
||||||
|
chatapp-client -a 10.0.0.20
|
||||||
|
```
|
||||||
|
* You will see the following output in **n1** terminal
|
||||||
|
``` shell
|
||||||
|
chat server listening on: :9001
|
||||||
|
[server] 10.0.0.21:44362 joining
|
||||||
|
```
|
||||||
|
* Type the following in **n2** terminal and hit enter
|
||||||
|
``` shell
|
||||||
|
hello world
|
||||||
|
```
|
||||||
|
* You will see the following output in **n1** terminal
|
||||||
|
``` shell
|
||||||
|
chat server listening on: :9001
|
||||||
|
[server] 10.0.0.21:44362 joining
|
||||||
|
[10.0.0.21:44362] hello world
|
||||||
|
```
|
||||||
|
|
||||||
|
--8<-- "common/grpc.md"
|
0
package/examples/tutorials/chatapp/chatapp/__init__.py
Normal file
0
package/examples/tutorials/chatapp/chatapp/__init__.py
Normal file
63
package/examples/tutorials/chatapp/chatapp/client.py
Normal file
63
package/examples/tutorials/chatapp/chatapp/client.py
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import argparse
|
||||||
|
import select
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
import termios
|
||||||
|
|
||||||
|
DEFAULT_PORT: int = 9001
|
||||||
|
READ_SIZE: int = 4096
|
||||||
|
|
||||||
|
|
||||||
|
def prompt():
|
||||||
|
sys.stdout.write(">> ")
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
|
class ChatClient:
|
||||||
|
def __init__(self, address, port):
|
||||||
|
self.address = address
|
||||||
|
self.port = port
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
server = socket.create_connection((self.address, self.port))
|
||||||
|
sockname = server.getsockname()
|
||||||
|
print(f"connected to server({self.address}:{self.port}) as client({sockname[0]}:{sockname[1]})")
|
||||||
|
sockets = [sys.stdin, server]
|
||||||
|
prompt()
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
read_sockets, write_socket, error_socket = select.select(sockets, [], [])
|
||||||
|
for sock in read_sockets:
|
||||||
|
if sock == server:
|
||||||
|
message = server.recv(READ_SIZE)
|
||||||
|
if not message:
|
||||||
|
print("server closed")
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
termios.tcflush(sys.stdin, termios.TCIOFLUSH)
|
||||||
|
print("\x1b[2K\r", end="")
|
||||||
|
print(message.decode().strip())
|
||||||
|
prompt()
|
||||||
|
else:
|
||||||
|
message = sys.stdin.readline().strip()
|
||||||
|
server.sendall(f"{message}\n".encode())
|
||||||
|
prompt()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("client exiting")
|
||||||
|
server.close()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="chat app client",
|
||||||
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||||
|
)
|
||||||
|
parser.add_argument("-a", "--address", help="address to listen on", required=True)
|
||||||
|
parser.add_argument("-p", "--port", type=int, help="port to listen on", default=DEFAULT_PORT)
|
||||||
|
args = parser.parse_args()
|
||||||
|
client = ChatClient(args.address, args.port)
|
||||||
|
client.run()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
73
package/examples/tutorials/chatapp/chatapp/server.py
Normal file
73
package/examples/tutorials/chatapp/chatapp/server.py
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import argparse
|
||||||
|
import select
|
||||||
|
import socket
|
||||||
|
|
||||||
|
DEFAULT_ADDRESS: str = ""
|
||||||
|
DEFAULT_PORT: int = 9001
|
||||||
|
READ_SIZE: int = 4096
|
||||||
|
|
||||||
|
|
||||||
|
class ChatServer:
|
||||||
|
def __init__(self, address, port):
|
||||||
|
self.address = address
|
||||||
|
self.port = port
|
||||||
|
self.sockets = []
|
||||||
|
|
||||||
|
def broadcast(self, ignore, message):
|
||||||
|
for sock in self.sockets:
|
||||||
|
if sock not in ignore:
|
||||||
|
sock.sendall(message.encode())
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
print(f"chat server listening on: {self.address}:{self.port}")
|
||||||
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
|
||||||
|
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
server.bind((self.address, self.port))
|
||||||
|
server.listen()
|
||||||
|
self.sockets.append(server)
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
read_sockets, write_sockets, error_sockets = select.select(self.sockets, [], [])
|
||||||
|
for sock in read_sockets:
|
||||||
|
if sock == server:
|
||||||
|
client_sock, addr = server.accept()
|
||||||
|
self.sockets.append(client_sock)
|
||||||
|
name = f"{addr[0]}:{addr[1]}"
|
||||||
|
print(f"[server] {name} joining")
|
||||||
|
self.broadcast({server, client_sock}, f"[server] {name} entered room\n")
|
||||||
|
else:
|
||||||
|
peer = sock.getpeername()
|
||||||
|
name = f"{peer[0]}:{peer[1]}"
|
||||||
|
try:
|
||||||
|
data = sock.recv(READ_SIZE).decode().strip()
|
||||||
|
if data:
|
||||||
|
print(f"[{name}] {data}")
|
||||||
|
self.broadcast({server, sock}, f"[{name}] {data}\n")
|
||||||
|
else:
|
||||||
|
print(f"[server] {name} leaving")
|
||||||
|
self.broadcast({server, sock}, f"[server] {name} leaving\n")
|
||||||
|
sock.close()
|
||||||
|
self.sockets.remove(sock)
|
||||||
|
except socket.error:
|
||||||
|
print(f"[server] {name} leaving")
|
||||||
|
self.broadcast({server, sock}, f"[server] {name} leaving\n")
|
||||||
|
sock.close()
|
||||||
|
self.sockets.remove(sock)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("closing server")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="chat app server",
|
||||||
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||||
|
)
|
||||||
|
parser.add_argument("-a", "--address", help="address to listen on", default=DEFAULT_ADDRESS)
|
||||||
|
parser.add_argument("-p", "--port", type=int, help="port to listen on", default=DEFAULT_PORT)
|
||||||
|
args = parser.parse_args()
|
||||||
|
server = ChatServer(args.address, args.port)
|
||||||
|
server.run()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
26
package/examples/tutorials/chatapp/chatapp_service.py
Normal file
26
package/examples/tutorials/chatapp/chatapp_service.py
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
from typing import Dict, List
|
||||||
|
|
||||||
|
from core.config import Configuration
|
||||||
|
from core.configservice.base import ConfigService, ConfigServiceMode, ShadowDir
|
||||||
|
|
||||||
|
|
||||||
|
class ChatAppService(ConfigService):
|
||||||
|
name: str = "ChatApp Server"
|
||||||
|
group: str = "ChatApp"
|
||||||
|
directories: List[str] = []
|
||||||
|
files: List[str] = ["chatapp.sh"]
|
||||||
|
executables: List[str] = []
|
||||||
|
dependencies: List[str] = []
|
||||||
|
startup: List[str] = [f"bash {files[0]}"]
|
||||||
|
validate: List[str] = []
|
||||||
|
shutdown: List[str] = []
|
||||||
|
validation_mode: ConfigServiceMode = ConfigServiceMode.BLOCKING
|
||||||
|
default_configs: List[Configuration] = []
|
||||||
|
modes: Dict[str, Dict[str, str]] = {}
|
||||||
|
shadow_directories: List[ShadowDir] = []
|
||||||
|
|
||||||
|
def get_text_template(self, _name: str) -> str:
|
||||||
|
return """
|
||||||
|
export PATH=$PATH:/usr/local/bin
|
||||||
|
PYTHONUNBUFFERED=1 chatapp-server > chatapp.log 2>&1 &
|
||||||
|
"""
|
17
package/examples/tutorials/chatapp/setup.py
Normal file
17
package/examples/tutorials/chatapp/setup.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="chatapp",
|
||||||
|
version="0.1.0",
|
||||||
|
packages=find_packages(),
|
||||||
|
description="Chat App",
|
||||||
|
entry_points={
|
||||||
|
"console_scripts": [
|
||||||
|
"chatapp-client = chatapp.client:main",
|
||||||
|
"chatapp-server = chatapp.server:main",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
include_package_data=True,
|
||||||
|
zip_safe=False,
|
||||||
|
python_requires=">=3.6",
|
||||||
|
)
|
36
package/examples/tutorials/tutorial1/scenario.py
Normal file
36
package/examples/tutorials/tutorial1/scenario.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
from core.api.grpc import client
|
||||||
|
from core.api.grpc.wrappers import Position
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# interface helper
|
||||||
|
iface_helper = client.InterfaceHelper(ip4_prefix="10.0.0.0/24", ip6_prefix="2001::/64")
|
||||||
|
|
||||||
|
# create grpc client and connect
|
||||||
|
core = client.CoreGrpcClient()
|
||||||
|
core.connect()
|
||||||
|
|
||||||
|
# create session
|
||||||
|
session = core.create_session()
|
||||||
|
|
||||||
|
# create nodes
|
||||||
|
position = Position(x=250, y=250)
|
||||||
|
node1 = session.add_node(_id=1, name="n1", position=position)
|
||||||
|
position = Position(x=500, y=250)
|
||||||
|
node2 = session.add_node(_id=2, name="n2", position=position)
|
||||||
|
|
||||||
|
# create link
|
||||||
|
node1_iface = iface_helper.create_iface(node_id=node1.id, iface_id=0)
|
||||||
|
node1_iface.ip4 = "10.0.0.20"
|
||||||
|
node1_iface.ip6 = "2001::14"
|
||||||
|
node2_iface = iface_helper.create_iface(node_id=node2.id, iface_id=0)
|
||||||
|
node2_iface.ip4 = "10.0.0.21"
|
||||||
|
node2_iface.ip6 = "2001::15"
|
||||||
|
session.add_link(node1=node1, node2=node2, iface1=node1_iface, iface2=node2_iface)
|
||||||
|
|
||||||
|
# start session
|
||||||
|
core.start_session(session=session)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
77
package/examples/tutorials/tutorial1/scenario.xml
Normal file
77
package/examples/tutorials/tutorial1/scenario.xml
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<scenario name="/tmp/tmpa_gpqzdf">
|
||||||
|
<networks/>
|
||||||
|
<devices>
|
||||||
|
<device id="1" name="n1" icon="" canvas="1" type="PC" class="" image="">
|
||||||
|
<position x="250.0" y="250.0" lat="47.57679395743362" lon="-122.12891511224676" alt="2.0"/>
|
||||||
|
<configservices>
|
||||||
|
<service name="DefaultRoute"/>
|
||||||
|
</configservices>
|
||||||
|
</device>
|
||||||
|
<device id="2" name="n2" icon="" canvas="1" type="PC" class="" image="">
|
||||||
|
<position x="500.0" y="250.0" lat="47.576775777287395" lon="-122.12534430899237" alt="2.0"/>
|
||||||
|
<configservices>
|
||||||
|
<service name="DefaultRoute"/>
|
||||||
|
</configservices>
|
||||||
|
</device>
|
||||||
|
</devices>
|
||||||
|
<links>
|
||||||
|
<link node1="1" node2="2">
|
||||||
|
<iface1 id="0" name="eth0" mac="00:00:00:aa:00:00" ip4="10.0.0.20" ip4_mask="24" ip6="2001::14" ip6_mask="64"/>
|
||||||
|
<iface2 id="0" name="eth0" mac="00:00:00:aa:00:01" ip4="10.0.0.21" ip4_mask="24" ip6="2001::15" ip6_mask="64"/>
|
||||||
|
<options delay="0" bandwidth="0" loss="0.0" dup="0" jitter="0" unidirectional="0" buffer="0"/>
|
||||||
|
</link>
|
||||||
|
</links>
|
||||||
|
<emane_global_configuration>
|
||||||
|
<emulator/>
|
||||||
|
<core>
|
||||||
|
<configuration name="platform_id_start" value="1"/>
|
||||||
|
<configuration name="nem_id_start" value="1"/>
|
||||||
|
<configuration name="link_enabled" value="1"/>
|
||||||
|
<configuration name="loss_threshold" value="30"/>
|
||||||
|
<configuration name="link_interval" value="1"/>
|
||||||
|
<configuration name="link_timeout" value="4"/>
|
||||||
|
</core>
|
||||||
|
</emane_global_configuration>
|
||||||
|
<session_origin lat="47.579166412353516" lon="-122.13232421875" alt="2.0" scale="150.0"/>
|
||||||
|
<session_options>
|
||||||
|
<configuration name="controlnet" value=""/>
|
||||||
|
<configuration name="controlnet0" value=""/>
|
||||||
|
<configuration name="controlnet1" value=""/>
|
||||||
|
<configuration name="controlnet2" value=""/>
|
||||||
|
<configuration name="controlnet3" value=""/>
|
||||||
|
<configuration name="controlnet_updown_script" value=""/>
|
||||||
|
<configuration name="enablerj45" value="1"/>
|
||||||
|
<configuration name="preservedir" value="0"/>
|
||||||
|
<configuration name="enablesdt" value="0"/>
|
||||||
|
<configuration name="sdturl" value="tcp://127.0.0.1:50000/"/>
|
||||||
|
<configuration name="ovs" value="0"/>
|
||||||
|
</session_options>
|
||||||
|
<session_metadata>
|
||||||
|
<configuration name="shapes" value="[]"/>
|
||||||
|
<configuration name="hidden" value="[]"/>
|
||||||
|
<configuration name="canvas" value="{"gridlines": true, "dimensions": [1000, 750], "canvases": [{"id": 1, "wallpaper": null, "wallpaper_style": 1, "fit_image": false}]}"/>
|
||||||
|
<configuration name="edges" value="[]"/>
|
||||||
|
</session_metadata>
|
||||||
|
<default_services>
|
||||||
|
<node type="mdr">
|
||||||
|
<service name="zebra"/>
|
||||||
|
<service name="OSPFv3MDR"/>
|
||||||
|
<service name="IPForward"/>
|
||||||
|
</node>
|
||||||
|
<node type="PC">
|
||||||
|
<service name="DefaultRoute"/>
|
||||||
|
</node>
|
||||||
|
<node type="prouter"/>
|
||||||
|
<node type="router">
|
||||||
|
<service name="zebra"/>
|
||||||
|
<service name="OSPFv2"/>
|
||||||
|
<service name="OSPFv3"/>
|
||||||
|
<service name="IPForward"/>
|
||||||
|
</node>
|
||||||
|
<node type="host">
|
||||||
|
<service name="DefaultRoute"/>
|
||||||
|
<service name="SSH"/>
|
||||||
|
</node>
|
||||||
|
</default_services>
|
||||||
|
</scenario>
|
37
package/examples/tutorials/tutorial1/scenario_service.py
Normal file
37
package/examples/tutorials/tutorial1/scenario_service.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
from core.api.grpc import client
|
||||||
|
from core.api.grpc.wrappers import Position
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# interface helper
|
||||||
|
iface_helper = client.InterfaceHelper(ip4_prefix="10.0.0.0/24", ip6_prefix="2001::/64")
|
||||||
|
|
||||||
|
# create grpc client and connect
|
||||||
|
core = client.CoreGrpcClient()
|
||||||
|
core.connect()
|
||||||
|
|
||||||
|
# create session
|
||||||
|
session = core.create_session()
|
||||||
|
|
||||||
|
# create nodes
|
||||||
|
position = Position(x=250, y=250)
|
||||||
|
node1 = session.add_node(_id=1, name="n1", position=position)
|
||||||
|
node1.config_services.add("ChatApp Server")
|
||||||
|
position = Position(x=500, y=250)
|
||||||
|
node2 = session.add_node(_id=2, name="n2", position=position)
|
||||||
|
|
||||||
|
# create link
|
||||||
|
node1_iface = iface_helper.create_iface(node_id=node1.id, iface_id=0)
|
||||||
|
node1_iface.ip4 = "10.0.0.20"
|
||||||
|
node1_iface.ip6 = "2001::14"
|
||||||
|
node2_iface = iface_helper.create_iface(node_id=node2.id, iface_id=0)
|
||||||
|
node2_iface.ip4 = "10.0.0.21"
|
||||||
|
node2_iface.ip6 = "2001::15"
|
||||||
|
session.add_link(node1=node1, node2=node2, iface1=node1_iface, iface2=node2_iface)
|
||||||
|
|
||||||
|
# start session
|
||||||
|
core.start_session(session=session)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
81
package/examples/tutorials/tutorial1/scenario_service.xml
Normal file
81
package/examples/tutorials/tutorial1/scenario_service.xml
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<scenario name="/tmp/tmp2exmy1y9">
|
||||||
|
<networks/>
|
||||||
|
<devices>
|
||||||
|
<device id="1" name="n1" icon="" canvas="0" type="PC" class="" image="">
|
||||||
|
<position x="250.0" y="250.0" lat="47.576893948125004" lon="-122.12895553643455" alt="2.0"/>
|
||||||
|
<configservices>
|
||||||
|
<service name="ChatApp Server"/>
|
||||||
|
<service name="DefaultRoute"/>
|
||||||
|
</configservices>
|
||||||
|
</device>
|
||||||
|
<device id="2" name="n2" icon="" canvas="0" type="PC" class="" image="">
|
||||||
|
<position x="500.0" y="250.0" lat="47.576893948125004" lon="-122.12558685411909" alt="2.0"/>
|
||||||
|
<configservices>
|
||||||
|
<service name="DefaultRoute"/>
|
||||||
|
</configservices>
|
||||||
|
</device>
|
||||||
|
</devices>
|
||||||
|
<links>
|
||||||
|
<link node1="1" node2="2">
|
||||||
|
<iface1 id="0" name="eth0" mac="00:00:00:aa:00:00" ip4="10.0.0.20" ip4_mask="24" ip6="2001::14" ip6_mask="64"/>
|
||||||
|
<iface2 id="0" name="eth0" mac="00:00:00:aa:00:01" ip4="10.0.0.21" ip4_mask="24" ip6="2001::15" ip6_mask="64"/>
|
||||||
|
<options delay="0" bandwidth="0" loss="0.0" dup="0" jitter="0" unidirectional="0" buffer="0"/>
|
||||||
|
</link>
|
||||||
|
</links>
|
||||||
|
<emane_global_configuration>
|
||||||
|
<emulator/>
|
||||||
|
<core>
|
||||||
|
<configuration name="platform_id_start" value="1"/>
|
||||||
|
<configuration name="nem_id_start" value="1"/>
|
||||||
|
<configuration name="link_enabled" value="1"/>
|
||||||
|
<configuration name="loss_threshold" value="30"/>
|
||||||
|
<configuration name="link_interval" value="1"/>
|
||||||
|
<configuration name="link_timeout" value="4"/>
|
||||||
|
</core>
|
||||||
|
</emane_global_configuration>
|
||||||
|
<configservice_configurations>
|
||||||
|
<service name="ChatApp Server" node="1"/>
|
||||||
|
</configservice_configurations>
|
||||||
|
<session_origin lat="47.579166412353516" lon="-122.13232421875" alt="2.0" scale="150.0"/>
|
||||||
|
<session_options>
|
||||||
|
<configuration name="controlnet" value=""/>
|
||||||
|
<configuration name="controlnet0" value=""/>
|
||||||
|
<configuration name="controlnet1" value=""/>
|
||||||
|
<configuration name="controlnet2" value=""/>
|
||||||
|
<configuration name="controlnet3" value=""/>
|
||||||
|
<configuration name="controlnet_updown_script" value=""/>
|
||||||
|
<configuration name="enablerj45" value="1"/>
|
||||||
|
<configuration name="preservedir" value="0"/>
|
||||||
|
<configuration name="enablesdt" value="0"/>
|
||||||
|
<configuration name="sdturl" value="tcp://127.0.0.1:50000/"/>
|
||||||
|
<configuration name="ovs" value="0"/>
|
||||||
|
</session_options>
|
||||||
|
<session_metadata>
|
||||||
|
<configuration name="shapes" value="[]"/>
|
||||||
|
<configuration name="hidden" value="[]"/>
|
||||||
|
<configuration name="canvas" value="{"gridlines": true, "dimensions": [1000, 750], "canvases": [{"id": 1, "wallpaper": null, "wallpaper_style": 1, "fit_image": false}]}"/>
|
||||||
|
<configuration name="edges" value="[]"/>
|
||||||
|
</session_metadata>
|
||||||
|
<default_services>
|
||||||
|
<node type="mdr">
|
||||||
|
<service name="zebra"/>
|
||||||
|
<service name="OSPFv3MDR"/>
|
||||||
|
<service name="IPForward"/>
|
||||||
|
</node>
|
||||||
|
<node type="PC">
|
||||||
|
<service name="DefaultRoute"/>
|
||||||
|
</node>
|
||||||
|
<node type="prouter"/>
|
||||||
|
<node type="router">
|
||||||
|
<service name="zebra"/>
|
||||||
|
<service name="OSPFv2"/>
|
||||||
|
<service name="OSPFv3"/>
|
||||||
|
<service name="IPForward"/>
|
||||||
|
</node>
|
||||||
|
<node type="host">
|
||||||
|
<service name="DefaultRoute"/>
|
||||||
|
<service name="SSH"/>
|
||||||
|
</node>
|
||||||
|
</default_services>
|
||||||
|
</scenario>
|
Loading…
Reference in a new issue