Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
40290dc
fixes
rafael-direito Jan 22, 2024
9c6245e
cleanup done
rafael-direito Jan 22, 2024
3ae67a3
minor fix
rafael-direito Jan 22, 2024
ca4df6b
Merge branch 'main' into enhancement/#17
rafael-direito Jan 22, 2024
b8efee5
Minor Update
rafael-direito Jan 22, 2024
2445920
Merge pull request #18 from 5gasp/enhancement/#17
rafael-direito Jan 22, 2024
e105510
Added the needed business logic for the MiniAPI to get a specific UE…
rafael-direito Jan 22, 2024
ccec4f4
Merge pull request #20 from 5gasp/enhancement/#19
rafael-direito Jan 22, 2024
0c7a739
Added documentation on how to run the miniAPI + minor fix
eduardosantoshf Feb 4, 2024
219697f
Updated README
rafael-direito Feb 4, 2024
a71b2ec
Updated the docker-compose file to expose port 5201 - the port used b…
rafael-direito Feb 4, 2024
7465ff7
Merge pull request #22 from 5gasp/documentation/#21
rafael-direito Feb 5, 2024
c1d993a
updated results files location
rafael-direito Feb 15, 2024
ed62cef
updated results files location
rafael-direito Feb 15, 2024
61a54de
removed results file
rafael-direito Feb 15, 2024
ff41b2e
Merge pull request #24 from 5gasp/bug/#23
rafael-direito Feb 15, 2024
e5a3c17
added __init.py__ to performance_operations/
Jan 4, 2024
8cb3b97
created miniapi/ and populated it with main.py, static/ and variable.…
Jan 4, 2024
d9fc16f
__init__.py for miniapi module
Jan 5, 2024
e024096
added setup.py
Jan 5, 2024
c3921a1
added debian/ with minimal content
Jan 5, 2024
7f0a29e
.pybuild/ in .gitignore
Jan 5, 2024
94345db
changelog for v0.0.2 (upstream c775644)
Jan 8, 2024
f128f55
added README-Debian-packaging.md
Jan 15, 2024
11bba46
deb package v0.0.3 (main: 7465ff7)
Feb 16, 2024
db685d3
deb package v0.0.4 (main: ff41b2e)
Feb 16, 2024
92f6e64
Merge branch 'debian/latest' into debian/latest
whaou Feb 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile.api
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM --platform=linux/amd64 python:3.9-slim

RUN apt-get update && \
apt-get install iperf3 hping3 iputils-ping net-tools -y
apt-get install iperf3 hping3 iputils-ping net-tools nmap -y

COPY ./src /app/src
COPY requirements.txt /app
Expand Down
56 changes: 51 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,57 @@

## How to run

1. Requirements
- docker
- docker-compose
1. To run the miniAPI and make it fully operational, we first need to install some OS-level dependencies:

2. Run
```bash
docker-compose up
sudo apt update

# Install dependencies - iperf3, ss, ping, netstat, and nmap
sudo apt install iperf3 iproute2 iputils-ping net-tools nmap -y
```

2. Then, clone the repository:

```bash
cd ~
git clone https://github.com/5gasp/NetworkAppControl-MiniAPI.git
cd ~/NetworkAppControl-MiniAPI/
```

3. Now, you need to install the miniAPI requirements. This can be done on the host or using a virtual environment.
The following commands may be used to install the miniAPI requirements in an Ubuntu 22.04. If you use a different OS, you may need to follow an alternative approach.

* On host:
```bash
sudo apt install python3-pip -y
pip3 install --upgrade pip
pip3 install -r requirements.txt
```

* Using venv:

```bash
sudo apt install python3.10-venv -y # Depending on your Ubuntu version, you may have to update this command
cd ~/NetworkAppControl-MiniAPI/
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
```

4. Finally, run the miniAPI:

```bash
cd ~/NetworkAppControl-MiniAPI/src
python3 -m uvicorn main:app --host=0.0.0.0 --port=3001
```

### Run using Docker

1. Docker must be installed on the OS. You can find the official tutorial on how to install Docker [here](https://docs.docker.com/desktop/install/linux-install/).

2. Run:
```bash
cd ~/NetworkAppControl-MiniAPI/
docker compose up
```
13 changes: 13 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
miniapi (0.0.4) unstable; urgency=low

* Integration of upstream version ff41b2e (Thu Feb 15 16:40:27 2024)

-- Christophe COUTURIER <couturier.christophe@gmail.com> Thu, 15 Feb 2024 20:54:00 +0100

miniapi (0.0.3) unstable; urgency=low

* Integration of upstream version 7465ff7 (Mon Feb 5 09:00:04 2024)
* Added dependencies: iperf3, iproute2, iputils-ping, net-tools, nmap

-- Christophe COUTURIER <couturier.christophe@gmail.com> Wed, 14 Feb 2024 14:58:09 +0100

miniapi (0.0.2) unstable; urgency=low

* Integration of upstream version c775644 (Sat Jan 6 12:05:14 2024)
Expand Down
2 changes: 1 addition & 1 deletion debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ Standards-Version: 3.9.5
Package: miniapi
Architecture: any
Pre-Depends: dpkg (>= 1.16.1), python3-minimal, ${misc:Pre-Depends}
Depends: ${python3:Depends}, ${misc:Depends}, python3-pip
Depends: ${python3:Depends}, ${misc:Depends}, python3-pip, iperf3, iproute2, iputils-ping, net-tools, nmap
Description: API to trigger the NEF tests of the 5GASP Project
API to trigger the NEF tests of the 5GASP Project
3 changes: 2 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ services:
context: .
dockerfile: Dockerfile.api
ports:
- "3001:3001"
- "3001:3001"
- "5201:5201"
18 changes: 10 additions & 8 deletions src/aux/operations_ids.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,21 @@

class OPERATION(Enum):
### NEF
LOGIN = '1'
NEF_AUTHENTICATION = 'Def19Sec9'
AUTHENTICATION_WITH_5GS = 'Def115G1'
CREATE_UE = '2'
GET_UES = '3'
SUBSCRIPTION = '4'
UE_PATH_LOSS = '5'
SERVING_CELL_INFO = '6'
HANDOVER = '9'
SUBSCRIBE_QOS_EVENT = "def115G7"
NEF_LOCATION_SUBSCRIPTION = 'Def115G2'
UE_PATH_LOSS = 'Def115G5'
SERVING_CELL_INFO = 'Def115G6'
HANDOVER = 'Def115G3'
SUBSCRIBE_QOS_EVENT = "Def115G7"
E2E_SINGLE_UE_LATENCY_AND_THROUGHPUT = "Def14Perf1"
E2E_MULTIPLE_UE_LATENCY_AND_THROUGHPUT = "Def14Perf2"
ACQUISITION_OF_RSRP = "Def115G4"
### AVAILABILITY
E2E_UE_PERFORMANCE = '7'
E2E_UE_RTT_PERFORMANCE = '8'
# E2E_UE_PERFORMANCE = '7'
# E2E_UE_RTT_PERFORMANCE = '8'
MAX_HOPS = "Def14Perf13"
MAX_CONNECTIONS = "Def14Perf11"
NEF_CALLBACK_MAX_CONNECTIONS = "Def14Perf7"
4 changes: 2 additions & 2 deletions src/aux/ping_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def run(self):
self.transmitter.count = PING_TIMEOUT
res = self.transmitter.ping()
res = self.parser.parse(res).as_dict()
with open(f'./static/{variables.E2E_RTT_RESULTS}', 'w') as json_file:
with open(f'/tmp/{variables.E2E_RTT_RESULTS}', 'w') as json_file:
json.dump(res, json_file)


Expand All @@ -39,7 +39,7 @@ def run_hping(self):

# Parse the output
parsed_output = parse_hping_output(output)
with open(f'./static/{variables.E2E_RTT_RESULTS}', 'w') as json_file:
with open(f'/tmp/{variables.E2E_RTT_RESULTS}', 'w') as json_file:
json.dump(parsed_output, json_file)
except subprocess.CalledProcessError as e:
print(f"Error running hping3: {e}")
Expand Down
71 changes: 42 additions & 29 deletions src/miniapi/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,10 @@
from aux.operations_ids import OPERATION
from nef_operations import operations as nef_operations
from performance_operations import operations as perf_operations
from fastapi.staticfiles import StaticFiles

models.Base.metadata.create_all(bind=engine)

app = FastAPI()
#app.mount("/static", StaticFiles(directory="static"), name="static")
app.mount("/static", StaticFiles(directory="/tmp"), name="static")

RUNNING_PROCESSES = {
OPERATION.MAX_CONNECTIONS.value: [],
Expand Down Expand Up @@ -89,7 +86,8 @@ async def start_test(
ue_count: int = None,
target: str = None):
try:
if operation_id == OPERATION.LOGIN.value:
if operation_id == OPERATION.NEF_AUTHENTICATION.value or\
operation_id == OPERATION.AUTHENTICATION_WITH_5GS:
token = nef_operations.login(
ip=variables.VARIABLES["NEF_IP"],
port=variables.VARIABLES["NEF_PORT"],
Expand Down Expand Up @@ -121,32 +119,47 @@ async def start_test(
)
return JSONResponse(content="Got UEs", status_code=200)

if operation_id == OPERATION.SUBSCRIPTION.value:
if operation_id == OPERATION.NEF_LOCATION_SUBSCRIPTION.value:
nef_operations.subscribe_event(
ip=variables.VARIABLES["NEF_IP"],
port=variables.VARIABLES["NEF_PORT"],
callback_url=variables.VARIABLES["SUBS1_CALLBACK_URL"],
monitoring_type=variables.VARIABLES["SUBS1_MONITORING_TYPE"],
monitoring_expire_time=variables.VARIABLES["SUBS1_MONITORING_EXPIRE_TIME"],
callback_url=variables.VARIABLES["SUBS_CALLBACK_URL"],
monitoring_type=variables.VARIABLES["SUBS_MONITORING_TYPE"],
monitoring_expire_time=variables.VARIABLES[
"SUBS_MONITORING_EXPIRE_TIME"
],
external_id=variables.VARIABLES["SUBS_EXTERNAL_ID"],
token = variables.VARIABLES["AUTH_TOKEN"]
)
return JSONResponse(content="Subscription Done", status_code=200)
if operation_id == OPERATION.UE_PATH_LOSS.value:
nef_operations.get_ue_path_loss(
ip=variables.VARIABLES["NEF_IP"],
port=variables.VARIABLES["NEF_PORT"],
ue_supi=variables.VARIABLES["UE1_SUPI"],

ue_supi=variables.VARIABLES["UE1_SUPI"],
token = variables.VARIABLES["AUTH_TOKEN"]
)
return JSONResponse(content="Got UE Path Loss Information", status_code=200)

if operation_id == OPERATION.ACQUISITION_OF_RSRP.value:
nef_operations.get_ue_path_loss(
ip=variables.VARIABLES["NEF_IP"],
port=variables.VARIABLES["NEF_PORT"],
ue_supi=variables.VARIABLES["UE1_SUPI"],
token = variables.VARIABLES["AUTH_TOKEN"]
)
return JSONResponse(content="Got UE Path Loss Information", status_code=200)

if operation_id == OPERATION.SERVING_CELL_INFO.value:
nef_operations.get_serving_cell_info(
nef_operations.get_rsrp_info(
ip=variables.VARIABLES["NEF_IP"],
port=variables.VARIABLES["NEF_PORT"],
ue_supi=variables.VARIABLES["UE1_SUPI"],
token = variables.VARIABLES["AUTH_TOKEN"]
)
return JSONResponse(content="Got UE Serving Cell Information", status_code=200)
return JSONResponse(content="Got UE RSRP Information", status_code=200)


if operation_id == OPERATION.HANDOVER.value:
nef_operations.get_ue_handover_event(
Expand All @@ -160,10 +173,10 @@ async def start_test(
if operation_id == OPERATION.E2E_SINGLE_UE_LATENCY_AND_THROUGHPUT.value:
# Delete old results file
if os.path.exists(
f'./static/{variables.E2E_SINGLE_UE_THROUGHPUT_AND_LATENCY}'
f'/tmp/{variables.E2E_SINGLE_UE_THROUGHPUT_AND_LATENCY}'
):
os.remove(
f'./static/{variables.E2E_SINGLE_UE_THROUGHPUT_AND_LATENCY}'
f'/tmp/{variables.E2E_SINGLE_UE_THROUGHPUT_AND_LATENCY}'
)

error_message = None
Expand Down Expand Up @@ -208,10 +221,10 @@ async def start_test(
if operation_id == OPERATION.E2E_MULTIPLE_UE_LATENCY_AND_THROUGHPUT.value:
# Delete old results file
if os.path.exists(
f'./static/{variables.E2E_SINGLE_UE_THROUGHPUT_AND_LATENCY}'
f'/tmp/{variables.E2E_SINGLE_UE_THROUGHPUT_AND_LATENCY}'
):
os.remove(
f'./static/{variables.E2E_SINGLE_UE_THROUGHPUT_AND_LATENCY}'
f'/tmp/{variables.E2E_SINGLE_UE_THROUGHPUT_AND_LATENCY}'
)

error_message = None
Expand Down Expand Up @@ -262,8 +275,8 @@ async def start_test(

if operation_id == OPERATION.MAX_HOPS.value:
# Delete old results file
if os.path.exists(f'./static/{variables.MAX_HOPS_RESULTS}'):
os.remove(f'./static/{variables.MAX_HOPS_RESULTS}')
if os.path.exists(f'/tmp/{variables.MAX_HOPS_RESULTS}'):
os.remove(f'/tmp/{variables.MAX_HOPS_RESULTS}')

# Start the number of hops until target process
max_hops_process = perf_operations.start_max_hops_computing(
Expand All @@ -281,11 +294,11 @@ async def start_test(

if operation_id == OPERATION.MAX_CONNECTIONS.value:
# Delete old results file
if os.path.exists(f'./static/{variables.MAX_CONNECTIONS_RESULTS}'):
os.remove(f'./static/{variables.MAX_CONNECTIONS_RESULTS}')
if os.path.exists(f'/tmp/{variables.MAX_CONNECTIONS_RESULTS}'):
os.remove(f'/tmp/{variables.MAX_CONNECTIONS_RESULTS}')
# Start the netstat loop
netstat_process = perf_operations.start_netstat_command(
output_file=f'./static/{variables.MAX_CONNECTIONS_RESULTS}'
output_file=f'/tmp/{variables.MAX_CONNECTIONS_RESULTS}'
)

# If we can start a monitoring process everything is ok
Expand All @@ -312,7 +325,7 @@ async def start_test(
nef_operations.subscribe_qos_event(
ip=variables.VARIABLES["NEF_IP"],
port=variables.VARIABLES["NEF_PORT"],
callback_url=variables.VARIABLES["SUBS1_CALLBACK_URL"],
callback_url=variables.VARIABLES["SUBS_CALLBACK_URL"],
token = variables.VARIABLES["AUTH_TOKEN"],
monitoring_payload = monitoring_payload
)
Expand All @@ -322,15 +335,15 @@ async def start_test(
if operation_id == OPERATION.NEF_CALLBACK_MAX_CONNECTIONS.value:
# Delete old results file
if os.path.exists(
f'./static/{variables.NEF_CALLBACK_MAX_CONNECTIONS_RESULTS}'
f'/tmp/{variables.NEF_CALLBACK_MAX_CONNECTIONS_RESULTS}'
):
os.remove(
f'./static/{variables.NEF_CALLBACK_MAX_CONNECTIONS_RESULTS}'
f'/tmp/{variables.NEF_CALLBACK_MAX_CONNECTIONS_RESULTS}'
)

# Start the netstat loop
netstat_process = perf_operations.start_netstat_command(
output_file=f'./static/{variables.NEF_CALLBACK_MAX_CONNECTIONS_RESULTS}'
output_file=f'/tmp/{variables.NEF_CALLBACK_MAX_CONNECTIONS_RESULTS}'
)

# If we can start a monitoring process everything is ok
Expand Down Expand Up @@ -372,12 +385,12 @@ async def get_report(operation_id: str):

if operation_id == OPERATION.MAX_CONNECTIONS.value:
return FileResponse(
path=f'./static/{variables.MAX_CONNECTIONS_RESULTS}'
path=f'/tmp/{variables.MAX_CONNECTIONS_RESULTS}'
)

if operation_id == OPERATION.NEF_CALLBACK_MAX_CONNECTIONS.value:
return FileResponse(
path=f'./static/{variables.NEF_CALLBACK_MAX_CONNECTIONS_RESULTS}'
path=f'/tmp/{variables.NEF_CALLBACK_MAX_CONNECTIONS_RESULTS}'
)

if operation_id in [
Expand All @@ -387,7 +400,7 @@ async def get_report(operation_id: str):
# The test may still be running when the user requests its results
try:
with open(
f'./static/{variables.E2E_SINGLE_UE_THROUGHPUT_AND_LATENCY}',
f'/tmp/{variables.E2E_SINGLE_UE_THROUGHPUT_AND_LATENCY}',
"r"
) as file:
data = json.load(file)
Expand All @@ -412,13 +425,13 @@ async def get_report(operation_id: str):

if operation_id == OPERATION.MAX_HOPS.value:
# The test may still be running when the user requests its results
if not os.path.exists(f'./static/{variables.MAX_HOPS_RESULTS}'):
if not os.path.exists(f'/tmp/{variables.MAX_HOPS_RESULTS}'):
return JSONResponse(
content=f"The Max Hops Performance Test is not finished yet!",
status_code=404
)

with open(f'./static/{variables.MAX_HOPS_RESULTS}', "r") as file:
with open(f'/tmp/{variables.MAX_HOPS_RESULTS}', "r") as file:
data = json.load(file)
return JSONResponse(
content=data,
Expand Down
Loading