diff --git a/docs/static/tutorial5/VM-network-settings.png b/docs/static/tutorial5/VM-network-settings.png new file mode 100644 index 00000000..5d47738e Binary files /dev/null and b/docs/static/tutorial5/VM-network-settings.png differ diff --git a/docs/static/tutorial5/configure-the-rj45.png b/docs/static/tutorial5/configure-the-rj45.png new file mode 100644 index 00000000..0e2b8f8b Binary files /dev/null and b/docs/static/tutorial5/configure-the-rj45.png differ diff --git a/docs/static/tutorial5/rj45-connector.png b/docs/static/tutorial5/rj45-connector.png new file mode 100644 index 00000000..8c8e86ef Binary files /dev/null and b/docs/static/tutorial5/rj45-connector.png differ diff --git a/docs/static/tutorial5/rj45-unassigned.png b/docs/static/tutorial5/rj45-unassigned.png new file mode 100644 index 00000000..eda4a3b6 Binary files /dev/null and b/docs/static/tutorial5/rj45-unassigned.png differ diff --git a/docs/tutorials/overview.md b/docs/tutorials/overview.md index 733157bd..6ec0d275 100644 --- a/docs/tutorials/overview.md +++ b/docs/tutorials/overview.md @@ -21,7 +21,7 @@ These are the items you should become familiar with for running all the tutorial * Covers mobility interactions when using a simple 3 node wireless network * [Tutorial 4 - Tests](tutorial4.md) * Covers automating scenarios as tests to validate software -* [Tutorial 5 - Access Windows](tutorial5.md) +* [Tutorial 5 - RJ45 Node](tutorial5.md) * Covers using the RJ45 node to connect a Windows OS * [Tutorial 6 - Improve Visuals](tutorial6.md) * Covers changing the look of a scenario within the CORE GUI diff --git a/docs/tutorials/tutorial5.md b/docs/tutorials/tutorial5.md new file mode 100644 index 00000000..4724544f --- /dev/null +++ b/docs/tutorials/tutorial5.md @@ -0,0 +1,166 @@ +# Tutorial 5 - RJ45 Node + +## Overview + +This tutorial will cover connecting CORE VM to a Windows host machine using a RJ45 node. + +## Files + +Below is the list of files used for this tutorial. + +* scenario.xml - the scenario with RJ45 unassigned +* scenario.py- grpc script to create the RJ45 in simple CORE scenario +* client_for_windows.py - chat app client modified for windows + +## Running with the Saved XML File + +This section covers using the saved **scenario.xml** file to get and up and running. + +* Configure the Windows host VM to have a bridged network adapter +
+ +
+* Make sure the **core-daemon** is running in a terminal + ```shell + sudop core-daemon + ``` +* In another terminal run the GUI + ```shell + core-gui + ``` +* Open the **scenario.xml** with the unassigned RJ45 node ++ +
+* Configure the RJ45 node name to use the bridged interface ++ +
+* After configuring the RJ45, run the scenario: ++ +
+* Double click node **n1** to open a terminal and add a route to the Windows host + ```shell + ip route add 192.168.0.0/24 via 10.0.0.20 + ``` +* On the Windows host using Windows command prompt with administrator privilege, add a route that uses the interface connected to the associated interface assigned to the RJ45 node + ```shell + # if enp0s3 is ssigned 192.168.0.6/24 + route add 10.0.0.0 mask 255.255.255.0 192.168.0.6 + ``` +* Now you should be able to ping from the Windows host to **n1** + ```shell + C:\WINDOWS\system32>ping 10.0.0.20 + + Pinging 10.0.0.20 with 32 bytes of data: + Reply from 10.0.0.20: bytes=32 time<1ms TTL=64 + Reply from 10.0.0.20: bytes=32 time<1ms TTL=64 + Reply from 10.0.0.20: bytes=32 time<1ms TTL=64 + Reply from 10.0.0.20: bytes=32 time<1ms TTL=64 + + Ping statistics for 10.0.0.20: + Packets: Sent = 4, Received = 4, Lost = 0 (0% loss) + Approximate round trip times in milli-seconds: + Minimum = 0ms, Maximum = 0ms, Average = 0ms + ``` +* After pinging successfully, run the following in the **n1** terminal to start the chatapp server + ```shell + export PATH=$PATH:/usr/local/bin + chatapp-server + ``` +* On the Windows host, run the **client_for_windows.py** + ```shell + python3 client_for_windows.py -a 10.0.0.20 + connected to server(10.0.0.20:9001) as client(192.168.0.6:49960) + >> .Hello WORLD + .Hello WORLD Again + . + ``` +* Observe output on **n1** + ```shell + chat server listening on: :9001 + [server] 192.168.0.6:49960 joining + [192.168.0.6:49960] Hello WORLD + [192.168.0.6:49960] Hello WORLD Again + ``` +* When finished, you can stop the CORE scenario and cleanup +* On the Windows host remove the added route + ```shell + route delete 10.0.0.0 + ``` + +## Running with the gRPC Script + +This section covers leveraging the gRPC script to get up and running. + +* Configure the Windows host VM to have a bridged network adapter ++ +
+* Make sure the **core-daemon** is running in a terminal + ```shell + sudop core-daemon + ``` +* In another terminal run the GUI + ```shell + core-gui + ``` +* Run the gRPC script in the VM + ```shell + # use the desired interface name, in this case enp0s3 + /opt/core/venv/bin/python scenario.py enp0s3 + ``` +* In the **core-gui** connect to the running session that was created ++ +
+* Double click node **n1** to open a terminal and add a route to the Windows host + ```shell + ip route add 192.168.0.0/24 via 10.0.0.20 + ``` +* On the Windows host using Windows command prompt with administrator privilege, add a route that uses the interface connected to the associated interface assigned to the RJ45 node + ```shell + # if enp0s3 is ssigned 192.168.0.6/24 + route add 10.0.0.0 mask 255.255.255.0 192.168.0.6 + ``` +* Now you should be able to ping from the Windows host to **n1** + ```shell + C:\WINDOWS\system32>ping 10.0.0.20 + + Pinging 10.0.0.20 with 32 bytes of data: + Reply from 10.0.0.20: bytes=32 time<1ms TTL=64 + Reply from 10.0.0.20: bytes=32 time<1ms TTL=64 + Reply from 10.0.0.20: bytes=32 time<1ms TTL=64 + Reply from 10.0.0.20: bytes=32 time<1ms TTL=64 + + Ping statistics for 10.0.0.20: + Packets: Sent = 4, Received = 4, Lost = 0 (0% loss) + Approximate round trip times in milli-seconds: + Minimum = 0ms, Maximum = 0ms, Average = 0ms + ``` +* After pinging successfully, run the following in the **n1** terminal to start the chatapp server + ```shell + export PATH=$PATH:/usr/local/bin + chatapp-server + ``` +* On the Windows host, run the **client_for_windows.py** + ```shell + python3 client_for_windows.py -a 10.0.0.20 + connected to server(10.0.0.20:9001) as client(192.168.0.6:49960) + >> .Hello WORLD + .Hello WORLD Again + . + ``` +* Observe output on **n1** + ```shell + chat server listening on: :9001 + [server] 192.168.0.6:49960 joining + [192.168.0.6:49960] Hello WORLD + [192.168.0.6:49960] Hello WORLD Again + ``` +* When finished, you can stop the CORE scenario and cleanup +* On the Windows host remove the added route + ```shell + route delete 10.0.0.0 + ``` diff --git a/mkdocs.yml b/mkdocs.yml index b71a89bb..8f48bef1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -43,6 +43,7 @@ nav: - Setup: tutorials/setup.md - Tutorial 1: tutorials/tutorial1.md - Tutorial 4: tutorials/tutorial4.md + - Tutorial 5: tutorials/tutorial5.md - Tutorial 6: tutorials/tutorial6.md - Tutorial 7: tutorials/tutorial7.md - Detailed Topics: diff --git a/package/examples/tutorials/tutorial5/client_for_windows.py b/package/examples/tutorials/tutorial5/client_for_windows.py new file mode 100644 index 00000000..5f55680a --- /dev/null +++ b/package/examples/tutorials/tutorial5/client_for_windows.py @@ -0,0 +1,60 @@ +import argparse +import select +import socket +import sys + +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 = [server] + prompt() + try: + while True: + read_sockets, write_socket, error_socket = select.select(sockets, [], [], 10) + for sock in read_sockets: + if sock == server: + message = server.recv(READ_SIZE) + if not message: + print("server closed") + sys.exit(1) + else: + print("\x1b[2K\r", end="") + print(message.decode().strip()) + prompt() + # waiting for input + message = input(".") + server.sendall(f"{message}\n".encode()) + 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() diff --git a/package/examples/tutorials/tutorial5/scenario.py b/package/examples/tutorials/tutorial5/scenario.py new file mode 100644 index 00000000..472208ab --- /dev/null +++ b/package/examples/tutorials/tutorial5/scenario.py @@ -0,0 +1,40 @@ +import sys + +from core.api.grpc import client, wrappers +from core.api.grpc.wrappers import NodeType, Position + + +def main(): + if (len(sys.argv) != 2): + print("usage core-python scenario.py