Skip to content

Commit

Permalink
Wrappers implemented and docs updated
Browse files Browse the repository at this point in the history
  • Loading branch information
tommaso-ascani committed Sep 19, 2024
1 parent 8782b3c commit ce19e38
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 42 deletions.
52 changes: 52 additions & 0 deletions core/imageroot/usr/local/agent/pypkg/agent/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -607,3 +607,55 @@ def get_bound_domain_list(rdb, module_id=None):
return rval.split()
else:
return []

def allocate_ports(ports_number: int, module_id: str, protocol: str):
"""
Allocate a range of ports for a given module,
if it is already allocated it is deallocated first.
:param ports_number: Number of consecutive ports required.
:param module_id: Name of the module requesting the ports.
:param protocol: Protocol type ('tcp' or 'udp').
:return: A tuple (start_port, end_port) if allocation is successful, None otherwise.
"""

node_id = os.environ['NODE_ID']
response = agent.tasks.run(
agent_id=f'node/{node_id}',
action='allocate-ports',
data={
'ports': ports_number,
'module_id': module_id,
'protocol': protocol
}
)

if response['exit_code'] != 0:
raise Exception(f"{response['error']}")

return response['output']


def deallocate_ports(module_id: str, protocol: str):
"""
Deallocate the ports for a given module.
:param module_id: Name of the module whose ports are to be deallocated.
:param protocol: Protocol type ('tcp' or 'udp').
:return: A tuple (start_port, end_port) if deallocation is successful, None otherwise.
"""

node_id = os.environ['NODE_ID']
response = agent.tasks.run(
agent_id=f'node/{node_id}',
action='deallocate-ports',
data={
'module_id': module_id,
'protocol': protocol
}
)

if response['exit_code'] != 0:
raise Exception(f"{response['error']}")

return response['output']
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ request = json.load(sys.stdin)
module_env = os.getenv("AGENT_TASK_USER")

if module_env != "" and module_env != f"module/{request['module_id']}":
print(agent.SD_ERR + f"Agent {module_env} does not have permission to change the port allocation for {request['module_id']}.")
print(agent.SD_ERR + f" Agent {module_env} does not have permission to change the port allocation for {request['module_id']}.", file=sys.stderr)
sys.exit(1)

range = node.ports_manager.allocate_ports(int(request['ports']), request['module_id'], request['protocol'])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ request = json.load(sys.stdin)
module_env = os.getenv("AGENT_TASK_USER")

if module_env != "" and module_env != f"module/{request['module_id']}":
print(agent.SD_ERR + f"Agent {module_env} does not have permission to change the port allocation for {request['module_id']}.")
print(agent.SD_ERR + f"Agent {module_env} does not have permission to change the port allocation for {request['module_id']}.", file=sys.stderr)
sys.exit(1)

range = node.ports_manager.deallocate_ports(request['module_id'], request['protocol'])
Expand Down
53 changes: 53 additions & 0 deletions docs/core/port_allocation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
layout: default
title: Port allocation
nav_order: 17
parent: Core
---

## Importing the Library

To use the `ports_manager` library, you need to import it into your Python script as follows:

```python
import node.ports_manager
```

## Available Functions

### `allocate_ports`

This function allows you to allocate a specific number of ports for a given module and protocol.

- **Parameters**:
- `required_ports` (*int*): The number of ports required.
- `module_name` (*str*): The name of the module requesting the ports.
- `protocol` (*str*): The protocol for which the ports are required (e.g. "tcp" or "udp").

- **Usage Example**:

```python
allocated_ports = node.ports_manager.allocate_ports(5, "my_module", "tcp")
print(f"my_module ports allocated: {allocated_ports}")
```

### `deallocate_ports`

This function allows you to deallocate all ports previously assigned to a specific module for a given protocol.

- **Parameters**:
- `module_name` (*str*): The name of the module for which ports should be deallocated.
- `protocol` (*str*): The protocol for which the ports were allocated (e.g., "tcp" or "udp").

- **Usage Example**:

```python
deallocated_ports = node.ports_manager.deallocate_ports("my_module", "udp")
print(f"my_module ports deallocated: {deallocated_ports}")
```

## Additional Notes

- Ensure to handle exceptions that may be raised during the allocation or deallocation of ports.
- Ports allocated will remain reserved for the specified module until they are explicitly deallocated.
- When using the `allocate_ports` function, if the module already has allocated ports, they will first be deallocated and then reallocated.
1 change: 1 addition & 0 deletions docs/core/subscription.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
layout: default
title: Subscription
nav_order: 16
parent: Core
---

Expand Down
73 changes: 33 additions & 40 deletions docs/modules/port_allocation.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,63 +24,56 @@ The available environment variables will be:
- `TCP_PORTS`, `UDP_PORTS`: only if value is greater than 1 and less or equal than 8, it contains a comma separated list of
ports like, i.e. `20001,20002,20003`

Currently, allocated ports are saved in an SQLite database file located in the node working directory.
Currently, allocated ports are saved in an SQLite database file managed by the local node agent.

The module requires an additional role to manage its port allocation, which is assigned by setting the `org.nethserver.authorizations` label on the module image, as shown in the following example:
```
org.nethserver.authorizations = node:portsadm
```

The module will be granted execution permissions for the following actions on the local node:
- `allocate-ports`
- `deallocate-ports`
## Agent library

The `ports_manager` library provides functions for managing network ports used by different modules within an application. You can dynamically allocate and deallocate ports based on the module's requirements.
The Python `agent` library provides a convenient interface for managing port allocation and deallocation, based on the node actions `allocate_ports` and `deallocate_ports`.

## Importing the Library
It is recommended to use `os.environ['MODULE_ID']` to ensure the correct module name is used, as calling the function with a name that does not correspond to the invoking module will result in an exception.

To use the `ports_manager` library, you need to import it into your Python script as follows:
### Allocate ports

```python
import node.ports_manager
```
Imagine an application module that initially requires only one TCP port. Later, a new feature is added, and it needs four TCP ports to handle more connections.

## Available Functions
If ports are already allocated for this module, the previous allocation will be deallocated, and the new requested range of ports will be allocated. Here’s how this can be done:

### `allocate_ports`
```python
import agent
import os

This function allows you to allocate a specific number of ports for a given module and protocol.
# Allocate 4 TCP ports for the "my_module" module
allocated_ports = agent.allocate_ports(4, os.environ['MODULE_ID'], "tcp")
print(f"Allocated TCP ports: {allocated_ports}")
```

- **Parameters**:
- `required_ports` (*int*): The number of ports required.
- `module_name` (*str*): The name of the module requesting the ports.
- `protocol` (*str*): The protocol for which the ports are required (e.g. "tcp" or "udp").
### Deallocate ports

- **Usage Example**:
If the module no longer needs the allocated ports, such as when a feature is removed or disabled, the ports can be easily deallocated:

```python
allocated_ports = node.ports_manager.allocate_ports(5, "my_module", "tcp")
print(f"my_module ports allocated: {allocated_ports}")
import agent
import os

# Deallocate UDP ports for the "my_module" module
deallocated_ports = agent.deallocate_ports(os.environ['MODULE_ID'], "udp")
print(f"Deallocated UDP ports: {deallocated_ports}")
```
By deallocating the ports, the module frees up the resources, allowing other modules to use those ports.

### `deallocate_ports`
For more information about functions, see [Port allocation](../../core/port_allocation)

This function allows you to deallocate all ports previously assigned to a specific module for a given protocol.
These functions dynamically allocate and deallocate ports based on the module's needs without requiring direct interaction with the node's APIs.

- **Parameters**:
- `module_name` (*str*): The name of the module for which ports should be deallocated.
- `protocol` (*str*): The protocol for which the ports were allocated (e.g., "tcp" or "udp").
## Authorizations

- **Usage Example**:
The module requires an additional role to manage port allocation, which is assigned by setting the `org.nethserver.authorizations` label on the module image, as shown in the following example:

```python
deallocated_ports = node.ports_manager.deallocate_ports("my_module", "udp")
print(f"my_module ports deallocated: {deallocated_ports}")
```
org.nethserver.authorizations = node:portsadm
```
The module will be granted execution permissions for the following actions on the local node:
- `allocate-ports`
- `deallocate-ports`

## Additional Notes

- Ensure to handle exceptions that may be raised during the allocation or deallocation of ports.
- Ports allocated will remain reserved for the specified module until they are explicitly deallocated.
- When using the `allocate_ports` function, if the module already has allocated ports, they will first be deallocated and then reallocated.

However, as mentioned above, these actions can be carried out using the agent library without making direct node API calls.

0 comments on commit ce19e38

Please sign in to comment.