Files
api_internal/utils_v2/mikrotik/controllers/async_mikrotik.py
T

2657 lines
97 KiB
Python

"""
AUTHOR:
Khushal P Soonderji
DATE:
Monday, 10th Feb., 2025.
OBJECTIVE:
To handle all MikroTik configuration from one place.
REFERENCES:
N/A
DOWNLOADS:
N/A
"""
# *****************************************************************************************************************
# ***** ****
# *** IMPORT ***
# ***** ****
# *****************************************************************************************************************
# To make sibling directories accessible for imports:
import sys
sys.path.append(".")
sys.path.append("..")
# System-level activities:
import distro
import socket
import platform
# My async utils:
from utils_v2.string import json
from utils_v2.date_time import date_time
from utils_v2.database.async_mongo_v2 import AsyncMongo
from utils_v2.api.async_quart import describe_exception
# To make very controlled API calls:
from utils_v2.rest.controllers.async_base import AsyncREST
from utils_v2.rest.controllers.auth import BasicAuth
from utils_v2.rest.models.api_call import ApiResponse
# To work with IP Addresses:
import ipaddress
# To work with datatypes:
from typing import List, Any
# To make HTTP requests:
import httpx
# To work with date and time:
import datetime
# For asynchronous activities:
import asyncio
# Misc:
import math
import random
import string
# *****************************************************************************************************************
# ***** ****
# *** MACROS / ONE-TIME INIT ***
# ***** ****
# *****************************************************************************************************************
# Info for logging that will stay constant during runtime:
SERVER_HOSTNAME = str(socket.gethostname())
PLATFORM_INFO = platform.uname()
HOST_OS = str(distro.name(True))
HOST_CPU = f"{PLATFORM_INFO.processor} ({PLATFORM_INFO.machine})"
# *****************************************************************************************************************
# ***** ****
# *** VARIABLES ***
# ***** ****
# *****************************************************************************************************************
# --- Nothing Yet
# *****************************************************************************************************************
# ***** ****
# *** FUNCTIONS ***
# ***** ****
# *****************************************************************************************************************
# --- Nothing Yet
# *****************************************************************************************************************
# ***** ****
# *** CLASSES ***
# ***** ****
# *****************************************************************************************************************
class AsyncMikroTik:
# ┏┓┓ ┓┏
# ┃ ┃┏┓┏┏ ┃┃┏┓┏┓┏
# ┗┛┗┗┻┛┛ ┗┛┗┻┛ ┛
ACTION_LOG_COLLECTION = "_mikrotikActions"
# ┏┓
# ┃ ┏┓┏┓┏╋┏┓┓┏┏╋┏┓┏┓
# ┗┛┗┛┛┗┛┗┛ ┗┻┗┗┗┛┛
def __init__(
self,
config_by: str,
mikrotik_ip: str,
username: str,
password: str,
port: int = None,
use_https: bool = True,
http_client: httpx.AsyncClient = None,
action_log_conn: AsyncMongo = None,
debug: bool = True,
debug_prefix: str = "MikroTik (C) | ",
debug_only_errors: bool = True
):
"""
To control MikroTik devices in an async manner.
:param http_client: The HTTP client to use to make REST-ful API calls.
:param debug: Whether, or not, you would like to print debugging messages:
:param debug_prefix: The prefix to print with the debugging messages.
:param debug_only_errors: Whether you would like to print only error messages or all messages.
:return: None.
"""
# Save the input values:
self._config_by = config_by
self._mikrotik_ip = mikrotik_ip
self._username = username
self._password = password
self._port = port
self._use_https = use_https
# For logging actions to Mongo:
self._action_log_conn = action_log_conn
self._action_log_chain = None
self.new_action_chain()
# For controlled REST-ful calls:
self._rest = AsyncREST(
http_client = http_client,
debug = debug,
debug_prefix = debug_prefix,
debug_only_errors = debug_only_errors
)
self._basic_auth = BasicAuth(
username = self._username,
password = self._password
)
# ┏┓ •
# ┃┃┏┓┏┓┏┓┏┓┏┓╋┓┏┓┏
# ┣┛┛ ┗┛┣┛┗ ┛ ┗┗┗ ┛
# ┛
@property
def action_chain(self):
return self._action_log_chain
# ┓┏ ┓
# ┣┫┏┓┃┏┓┏┓┏┓┏
# ┛┗┗ ┗┣┛┗ ┛ ┛
# ┛
def get_mikrotik_url(
self,
path: str,
use_https: bool = None
) -> str:
"""
Simply creates the base URL for hitting the MikroTik server.
:param path: The path of the REST API to hit.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: The Base URL string.
"""
use_https = self._use_https if use_https is None else use_https
base_url = r"https://" if use_https else r"http://"
base_url += self._mikrotik_ip
if self._port is not None: base_url += f":{self._port}"
base_url += "/rest"
if not path.startswith("/"): path = "/" + path
return base_url + path
@staticmethod
def split_ipv4_range_equally(
start_ip: ipaddress.IPv4Address | str,
end_ip: ipaddress.IPv4Address | str,
targets: List
) -> List[dict]:
"""
Divides the IPv4 range over the list of targets (like VLAN ids) in a simple fashion
:param start_ip: The first IP in the full pool (range).
:param end_ip: The last IP in the full pool (range).
:param targets: The list of targets (need not be sequential or ordered) like VLAN ids.
:return: A list of dicts that describes the subnet for each target.
"""
# Parse the inputs:
start_ip_obj = start_ip if isinstance(start_ip, ipaddress.IPv4Address) else ipaddress.IPv4Address(start_ip)
end_ip_obj = end_ip if isinstance(end_ip, ipaddress.IPv4Address) else ipaddress.IPv4Address(end_ip)
target_count = len(targets)
# Calculate the total number of IPs in the range:
total_ips = int(end_ip_obj) - int(start_ip_obj) + 1
# Figure out the no. of IPs in each block:
ips_per_target = math.ceil(total_ips / target_count)
# Iterate through the list of targets, and give them the IPs:
subnets = []
current_ip = start_ip_obj
for index, target in enumerate(targets):
# Figure out the first and last IPs for this object:
subnet_start_ip_obj = current_ip
if index == target_count - 1: subnet_end_ip_obj = end_ip_obj
else: subnet_end_ip_obj = subnet_start_ip_obj + ips_per_target - 1
# Add the calculated subnet to the list:
subnets.append({
"target": target,
"network": str(subnet_start_ip_obj) + "-" + str(subnet_end_ip_obj),
"size": int(subnet_end_ip_obj) - int(subnet_start_ip_obj) + 1,
"startIp": str(subnet_start_ip_obj),
"endIp": str(subnet_end_ip_obj)
})
# Update the current IP for the next subnet:
current_ip += ips_per_target
# Done here:
return subnets
@staticmethod
def split_ipv4_range_in_powers_of_two(
start_ip: ipaddress.IPv4Address | str,
end_ip: ipaddress.IPv4Address | str,
targets: List,
consider_reserved_ips: bool = True,
strict: bool = False
) -> List[dict]:
"""
Divides the IPv4 range over the list of targets (like VLAN ids) in blocks whose sizes are in powers of 2. This
means that you won't have a block which has an unusual size like 7.
:param start_ip: The first IP in the full pool (range).
:param end_ip: The last IP in the full pool (range).
:param targets: The list of targets (need not be sequential or ordered) like VLAN ids.
:param consider_reserved_ips: Whether, or not, to add 3 IPs per block (network, gateway, and broadcast) when
splitting the range.
:param strict: Whether, or not, you want strict dvision of blocks such that the network address is always
x.x.x.0 and the broadcast address is always x.x.x.255.
:return: A list of dicts that describes the subnet for each target.
"""
# Parse the inputs:
start_ip_obj = start_ip if isinstance(start_ip, ipaddress.IPv4Address) else ipaddress.IPv4Address(start_ip)
end_ip_obj = end_ip if isinstance(end_ip, ipaddress.IPv4Address) else ipaddress.IPv4Address(end_ip)
target_count = len(targets)
# Calculate the total number of IPs in the range:
total_ips = int(end_ip_obj) - int(start_ip_obj) + 1
# Calculate the no. of IPs each VLAN gets (subtract one because counting starts from 0),
# and add three (if asked) because we need IPs for network, gateway and broadcast:
ips_per_target = math.ceil(total_ips / target_count) - 1
if consider_reserved_ips: ips_per_target += 3
# Generate subnets for each VLAN:
subnets = []
current_ip = start_ip_obj
for target in targets:
# Calculate the network address for the current VLAN:
subnet_network = ipaddress.IPv4Network(f"{current_ip}/{32 - ips_per_target.bit_length()}", strict = strict)
# Check for overlap with the parent network:
subnet_start_ip_obj = subnet_network.network_address
subnet_end_ip_obj = subnet_network.broadcast_address
if subnet_start_ip_obj <= end_ip_obj:
# Add the calculated subnet to the list:
subnets.append({
"target": target,
"network": str(subnet_network),
"size": int(2 ** (32 - subnet_network.prefixlen)),
"startIp": str(subnet_start_ip_obj),
"endIp": str(subnet_end_ip_obj)
})
# Update the current IP for the next subnet:
current_ip = ipaddress.IPv4Address(int(subnet_network.broadcast_address) + 1)
# Done here:
return subnets
def create_comment_json(
self,
config_ts: datetime.datetime = None,
roll_back_config: dict = None
) -> str:
"""
To create a JSON string that can be put as a comment in any step to later identify the work that was done and
have some hint about how to roll it back if needed.
:param config_ts: The datetime (preferably UTC) when this comment was created.
:param roll_back_config: The original config that can be used when rolling back.
:return: The comment string to be used.
"""
# Create the JSON:
comment_json = {
"configBy": self._config_by,
"configTs": (config_ts or date_time.get_current_utc_date_time(as_string = False)).timestamp(),
"rollbackConfig": roll_back_config
}
# Return a string:
return json.to_string(comment_json, no_space = True)
@staticmethod
def parse_comment_json(comment: str) -> dict | list | None:
"""
Tries to parse a comment as if it were a JSON string.
:param comment: The comment string.
:return: The dict/list parsed form the JSON, or a null value of the input was not a valid JSON string.
"""
# Start with a null value:
parsed = None
# Try to parse the comment as if it were a JSON string:
try: parsed = json.from_string(comment)
except: parsed = None
# Done here:
return parsed
@staticmethod
def get_original_config(comment_json: dict) -> dict | None:
"""
Once you have the comment's JSON unpacked successfully, pass that dict here to get the original config back.
:param comment_json: The dict received from parsing the comment's JSON string.
:return: The dict that describes the previous config, or None if no previous config was found.
"""
return comment_json.get("rollbackConfig") if isinstance(comment_json, dict) else None
def is_my_config(
self,
config_json: dict,
name_substring: str = None
) -> bool:
"""
Looks at a particular resource's JSON and tells if it was created by this class.
:param config_json: The JSON of the resource whose config needs to be checked.
:param name_substring: A substring (case-sensitive) to look for in the 'name' field.
:return: True if the config was created by this class, else False.
"""
# Extract needed values:
name = config_json.get("name", "???")
comment_json = self.parse_comment_json(config_json.get("comment")) or {}
# Perform needed checks:
if (
name.find(name_substring or "bhopli-muchhi-cookie") >= 0 or
comment_json.get("configBy", "???") == self._config_by
): return True
else: return False
def new_action_chain(self, action_chain: str | int = None) -> None:
"""
Generates a new random string to mark a new action chain and saves it in the local variable.
:param action_chain: A custom action chain to start using. A random string will be created if not provided.
:return: None
"""
if action_chain: self._action_log_chain = action_chain
else: self._action_log_chain = "".join(random.choices(string.ascii_letters + string.digits, k = 8))
async def log_action(
self,
api_response: ApiResponse,
) -> None:
"""
Invoke this to record actions automatically.
:param api_response: The response received from invoking an API provided by MikroTik.
:return: None.
"""
# Proceed only if we have a logging connection:
if self._action_log_conn is not None:
# Prepare the final log:
action_log_json = {
"hostname": SERVER_HOSTNAME,
"hostOs": HOST_OS,
"hostCpu": HOST_CPU,
"actionChain": self._action_log_chain,
"configBy": self._config_by,
"mikrotikIp": self._mikrotik_ip,
"url": api_response.url,
"method": api_response.method,
"action": api_response.action,
"config": api_response.requestJson,
"httpCode": api_response.httpCode,
"success": api_response.success,
"message": api_response.message,
"exception": describe_exception(api_response.exception),
"ts": date_time.get_current_utc_date_time(as_string = False)
}
# Record the action:
asyncio.create_task(self._action_log_conn.insert_one(
collection = self.ACTION_LOG_COLLECTION,
document = action_log_json
))
@staticmethod
async def get_failure_message(api_response: ApiResponse) -> str:
# On successful API calls, MikroTik doesn't give messages:
if api_response.success: message = "Success"
# On failure, the message is available in the JSON payload:
else:
response_json = await api_response.get_json()
message = f"{response_json.get('message')} ({response_json.get('detail')})"
# Done here:
return message
# ┏┓
# ┗┓┓┏┏╋┏┓┏┳┓
# ┗┛┗┫┛┗┗ ┛┗┗
# ┛
async def list_system_resources(
self,
use_https: bool = None
) -> ApiResponse:
"""
To get a summary of the hardware resources available in the MikroTik device. This also becomes a great way to
quickly check if any given device is valid, and up and running.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.get(
url = self.get_mikrotik_url(path = r"/system/resource", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
# Done here:
await self.log_action(api_response)
return api_response
# ┳ ┏
# ┃┏┓╋┏┓┏┓╋┏┓┏┏┓┏
# ┻┛┗┗┗ ┛ ┛┗┻┗┗ ┛
async def list_interfaces(
self,
use_https: bool = None
) -> ApiResponse:
"""
To enlist all the physical connectivity interfaces available on the MikroTik device.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.get(
url = self.get_mikrotik_url(path = r"/interface", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def update_interface(
self,
dot_id: str,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To update an interface's configuration.
:param dot_id: The value of the '.id' field in the list.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:param json_payload: The JSON to send in the body of the request.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.patch(
url = self.get_mikrotik_url(
path = f"/interface/{dot_id}",
use_https = use_https
),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# ┳┏┓ ┏┓ ┓ ┓ ┳┓• ┓•
# ┃┃┃ ┣┫┏┫┏┫┏┓┏┓┏┏ ┣┫┓┏┓┏┫┓┏┓┏┓┏
# ┻┣┛ ┛┗┗┻┗┻┛ ┗ ┛┛ ┻┛┗┛┗┗┻┗┛┗┗┫┛
# ┛
async def list_ip_address_bindings(
self,
use_https: bool = None
) -> ApiResponse:
"""
To enlist all the IP Address bindings to Interfaces that have been configured.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.get(
url = self.get_mikrotik_url(path = r"/ip/address", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def add_ip_address_binding(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To add a new IP Address binding to an Interface to the MikroTik's configuration.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.put(
url = self.get_mikrotik_url(path = r"/ip/address", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def update_ip_address_binding(
self,
dot_id: str,
json_payload: dict,
use_https: bool = None,
) -> ApiResponse:
"""
To update an existing IP Address binding to an Interface in the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.patch(
url = self.get_mikrotik_url(path = f"/ip/address/{dot_id}", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def remove_ip_address_binding(
self,
dot_id: str,
use_https: bool = None,
):
"""
To delete an existing IP Address to an Interface from the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.delete(
url = self.get_mikrotik_url(path = f"/ip/address/{dot_id}", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# ┓┏┓ ┏┓┳┓
# ┃┃┃ ┣┫┃┃┏
# ┗┛┗┛┛┗┛┗┛
async def list_vlans(
self,
use_https: bool = None
) -> ApiResponse:
"""
To enlist all the physical connectivity interfaces available on the MikroTik device.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.get(
url = self.get_mikrotik_url(path = r"/interface/vlan", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def add_vlan(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To add a new VLAN to the MikroTik's configuration.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.put(
url = self.get_mikrotik_url(path = r"/interface/vlan", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def update_vlan(
self,
dot_id: str,
json_payload: dict,
use_https: bool = None,
) -> ApiResponse:
"""
To update an existing VLAN in the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.patch(
url = self.get_mikrotik_url(path = f"/interface/vlan/{dot_id}", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def remove_vlan(
self,
dot_id: str,
use_https: bool = None,
):
"""
To delete an existing VLAN from the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.delete(
url = self.get_mikrotik_url(path = f"/interface/vlan/{dot_id}", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# ┳┏┓ ┏┓ ┓
# ┃┃┃ ┃┃┏┓┏┓┃┏
# ┻┣┛ ┣┛┗┛┗┛┗┛
async def list_ip_pools(
self,
use_https: bool = None
) -> ApiResponse:
"""
To enlist all the IP Pools that have been configured.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.get(
url = self.get_mikrotik_url(path = r"/ip/pool", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def add_ip_pool(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To add a new IP Pool to the MikroTik's configuration.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.put(
url = self.get_mikrotik_url(path = r"/ip/pool", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def update_ip_pool(
self,
dot_id: str,
json_payload: dict,
use_https: bool = None,
) -> ApiResponse:
"""
To update an existing IP Pool in the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.patch(
url = self.get_mikrotik_url(path = f"/ip/pool/{dot_id}", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def remove_ip_pool(
self,
dot_id: str,
use_https: bool = None,
):
"""
To delete an existing IP Pool from the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.delete(
url = self.get_mikrotik_url(path = f"/ip/pool/{dot_id}", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# ┏┓┏┓┏┓ ┏┓ ┏•┓
# ┃┃┃┃┃┃ ┃┃┏┓┏┓╋┓┃┏┓
# ┣┛┣┛┣┛ ┣┛┛ ┗┛┛┗┗┗
async def list_ppp_profiles(
self,
use_https: bool = None
) -> ApiResponse:
"""
To enlist all the PPP Profiles that have been configured.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.get(
url = self.get_mikrotik_url(path = r"/ppp/profile", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def add_ppp_profile(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To add a new PPP Profile to the MikroTik's configuration.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.put(
url = self.get_mikrotik_url(path = r"/ppp/profile", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def update_ppp_profile(
self,
dot_id: str,
json_payload: dict,
use_https: bool = None,
) -> ApiResponse:
"""
To update an existing PPP Profile in the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.patch(
url = self.get_mikrotik_url(path = f"/ppp/profile/{dot_id}", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def remove_ppp_profile(
self,
dot_id: str,
use_https: bool = None,
):
"""
To delete an existing PPP Profile from the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.delete(
url = self.get_mikrotik_url(path = f"/ppp/profile/{dot_id}", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# ┏┓┏┓┏┓ ┏┓
# ┃┃┃┃┃┃ ┗┓┏┓┏┓┓┏┏┓┏┓
# ┣┛┣┛┣┛ ┗┛┗ ┛ ┗┛┗ ┛
async def list_ppp_servers(
self,
use_https: bool = None
) -> ApiResponse:
"""
To enlist all the PPP Servers that have been configured.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.get(
url = self.get_mikrotik_url(path = r"/interface/pppoe-server/server", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def add_ppp_server(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To add a new PPP Server to the MikroTik's configuration.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.put(
url = self.get_mikrotik_url(path = r"/interface/pppoe-server/server", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def update_ppp_server(
self,
dot_id: str,
json_payload: dict,
use_https: bool = None,
) -> ApiResponse:
"""
To update an existing PPP Server in the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.patch(
url = self.get_mikrotik_url(path = f"/interface/pppoe-server/server/{dot_id}", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def remove_ppp_server(
self,
dot_id: str,
use_https: bool = None,
):
"""
To delete an existing PPP Server from the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.delete(
url = self.get_mikrotik_url(path = f"/interface/pppoe-server/server/{dot_id}", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# ┏┓┏┓┏┓ ┏┓┏┓┏┓
# ┃┃┃┃┃┃ ┣┫┣┫┣┫
# ┣┛┣┛┣┛ ┛┗┛┗┛┗
async def set_ppp_aaa(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To set the configuration for AAA in PPP.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.post(
url = self.get_mikrotik_url(path = r"/ppp/aaa/set", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# ┓┏ ┏┓ ┏•┓
# ┣┫┏┓╋┏┏┓┏┓╋ ┃┃┏┓┏┓╋┓┃┏┓
# ┛┗┗┛┗┛┣┛┗┛┗ ┣┛┛ ┗┛┛┗┗┗
# ┛
async def list_hotspot_profiles(
self,
use_https: bool = None
) -> ApiResponse:
"""
To enlist all the Hotspot Profiles that have been configured.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.get(
url = self.get_mikrotik_url(path = r"/ip/hotspot/profile", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def add_hotspot_profile(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To add a new Hotspot Profile to the MikroTik's configuration.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.put(
url = self.get_mikrotik_url(path = r"/ip/hotspot/profile", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def update_hotspot_profile(
self,
dot_id: str,
json_payload: dict,
use_https: bool = None,
) -> ApiResponse:
"""
To update an existing Hotspot Profile in the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.patch(
url = self.get_mikrotik_url(path = f"/ip/hotspot/profile/{dot_id}", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def remove_hotspot_profile(
self,
dot_id: str,
use_https: bool = None,
):
"""
To delete an existing Hotspot Profile from the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.delete(
url = self.get_mikrotik_url(path = f"/ip/hotspot/profile/{dot_id}", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# ┓┏ ┏┓
# ┣┫┏┓╋┏┏┓┏┓╋ ┗┓┏┓┏┓┓┏┏┓┏┓
# ┛┗┗┛┗┛┣┛┗┛┗ ┗┛┗ ┛ ┗┛┗ ┛
# ┛
async def list_hotspot_servers(
self,
use_https: bool = None
) -> ApiResponse:
"""
To enlist all the Hotspot Servers that have been configured.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.get(
url = self.get_mikrotik_url(path = r"/ip/hotspot", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def add_hotspot_server(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To add a new Hotspot Server to the MikroTik's configuration.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.put(
url = self.get_mikrotik_url(path = r"/ip/hotspot", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def update_hotspot_server(
self,
dot_id: str,
json_payload: dict,
use_https: bool = None,
) -> ApiResponse:
"""
To update an existing Hotspot Server in the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.patch(
url = self.get_mikrotik_url(path = f"/ip/hotspot/{dot_id}", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def remove_hotspot_server(
self,
dot_id: str,
use_https: bool = None,
):
"""
To delete an existing Hotspot Server from the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.delete(
url = self.get_mikrotik_url(path = f"/ip/hotspot/{dot_id}", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# ┓┏ ┓ ┏ ┓┓ ┓ ┏┓ ┓
# ┣┫┏┓╋┏┏┓┏┓╋ ┃┃┃┏┓┃┃┏┓┏┫━━┃┓┏┓┏┓┏┫┏┓┏┓
# ┛┗┗┛┗┛┣┛┗┛┗ ┗┻┛┗┻┗┗┗ ┗┻ ┗┛┗┻┛ ┗┻┗ ┛┗
# ┛
async def list_hotspot_walled_gardens(
self,
use_https: bool = None
) -> ApiResponse:
"""
To enlist all the Hotspot Walled-Gardens that have been configured.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.get(
url = self.get_mikrotik_url(path = r"/ip/hotspot/walled-garden", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def add_hotspot_walled_garden(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To add a new Hotspot Walled-Garden to the MikroTik's configuration.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.put(
url = self.get_mikrotik_url(path = r"/ip/hotspot/walled-garden", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def update_hotspot_walled_garden(
self,
dot_id: str,
json_payload: dict,
use_https: bool = None,
) -> ApiResponse:
"""
To update an existing Hotspot Walled-Garden in the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.patch(
url = self.get_mikrotik_url(path = f"/ip/hotspot/walled-garden/{dot_id}", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def remove_hotspot_walled_garden(
self,
dot_id: str,
use_https: bool = None,
):
"""
To delete an existing Hotspot Walled-Garden from the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.delete(
url = self.get_mikrotik_url(path = f"/ip/hotspot/walled-garden/{dot_id}", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# ┓┏ ┓ ┏ ┓┓ ┓ ┏┓ ┓ ┳┏┓
# ┣┫┏┓╋┏┏┓┏┓╋ ┃┃┃┏┓┃┃┏┓┏┫━━┃┓┏┓┏┓┏┫┏┓┏┓ ┃┃┃
# ┛┗┗┛┗┛┣┛┗┛┗ ┗┻┛┗┻┗┗┗ ┗┻ ┗┛┗┻┛ ┗┻┗ ┛┗ ┻┣┛
# ┛
async def list_hotspot_walled_garden_ips(
self,
use_https: bool = None
) -> ApiResponse:
"""
To enlist all the Hotspot Walled-Garden IPs that have been configured.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.get(
url = self.get_mikrotik_url(path = r"/ip/hotspot/walled-garden/ip", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def add_hotspot_walled_garden_ip(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To add a new Hotspot Walled-Garden IP to the MikroTik's configuration.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.put(
url = self.get_mikrotik_url(path = r"/ip/hotspot/walled-garden/ip", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def update_hotspot_walled_garden_ip(
self,
dot_id: str,
json_payload: dict,
use_https: bool = None,
) -> ApiResponse:
"""
To update an existing Hotspot Walled-Garden IP in the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.patch(
url = self.get_mikrotik_url(path = f"/ip/hotspot/walled-garden/ip/{dot_id}", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def remove_hotspot_walled_garden_ip(
self,
dot_id: str,
use_https: bool = None,
):
"""
To delete an existing Hotspot Walled-Garden IP from the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.delete(
url = self.get_mikrotik_url(path = f"/ip/hotspot/walled-garden/ip/{dot_id}", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# ┳┓┏┓┳┓┳┳┳┏┓
# ┣┫┣┫┃┃┃┃┃┗┓
# ┛┗┛┗┻┛┻┗┛┗┛
async def set_radius_incoming(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To set the parameters for the way the MikroTik devices receive incoming hits from RADIUS.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.post(
url = self.get_mikrotik_url(path = r"/radius/incoming/set", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def list_radius_servers(
self,
use_https: bool = None
) -> ApiResponse:
"""
To enlist all the RADIUS Servers that have been configured.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.get(
url = self.get_mikrotik_url(path = r"/radius", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def add_radius_server(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To add a new RADIUS Server to the MikroTik's configuration.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.put(
url = self.get_mikrotik_url(path = r"/radius", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def update_radius_server(
self,
dot_id: str,
json_payload: dict,
use_https: bool = None,
) -> ApiResponse:
"""
To update an existing RADIUS Server in the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.patch(
url = self.get_mikrotik_url(path = f"/radius/{dot_id}", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def remove_radius_server(
self,
dot_id: str,
use_https: bool = None,
):
"""
To delete an existing RADIUS Server from the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.delete(
url = self.get_mikrotik_url(path = f"/radius/{dot_id}", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# ┳┓┓┏┏┓┏┓ ┏┓
# ┃┃┣┫┃ ┃┃ ┗┓┏┓┏┓┓┏┏┓┏┓
# ┻┛┛┗┗┛┣┛ ┗┛┗ ┛ ┗┛┗ ┛
async def list_dhcp_servers(
self,
use_https: bool = None
) -> ApiResponse:
"""
To enlist all the DHCP Servers that have been configured.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.get(
url = self.get_mikrotik_url(path = r"/ip/dhcp-server", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def add_dhcp_server(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To add a new DHCP Server to the MikroTik's configuration.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.put(
url = self.get_mikrotik_url(path = r"/ip/dhcp-server", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def update_dhcp_server(
self,
dot_id: str,
json_payload: dict,
use_https: bool = None,
) -> ApiResponse:
"""
To update an existing DHCP Server in the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.patch(
url = self.get_mikrotik_url(path = f"/ip/dhcp-server/{dot_id}", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def remove_dhcp_server(
self,
dot_id: str,
use_https: bool = None,
):
"""
To delete an existing DHCP Server from the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.delete(
url = self.get_mikrotik_url(path = f"/ip/dhcp-server/{dot_id}", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# ┳┓┓┏┏┓┏┓ ┳┓ ┓
# ┃┃┣┫┃ ┃┃ ┃┃┏┓╋┓┏┏┏┓┏┓┃┏
# ┻┛┛┗┗┛┣┛ ┛┗┗ ┗┗┻┛┗┛┛ ┛┗
async def list_dhcp_networks(
self,
use_https: bool = None
) -> ApiResponse:
"""
To enlist all the DHCP Networks that have been configured.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.get(
url = self.get_mikrotik_url(path = r"/ip/dhcp-server/network", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def add_dhcp_network(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To add a new DHCP Network to the MikroTik's configuration.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.put(
url = self.get_mikrotik_url(path = r"/ip/dhcp-server/network", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def update_dhcp_network(
self,
dot_id: str,
json_payload: dict,
use_https: bool = None,
) -> ApiResponse:
"""
To update an existing DHCP Network in the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.patch(
url = self.get_mikrotik_url(path = f"/ip/dhcp-server/network/{dot_id}", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def remove_dhcp_network(
self,
dot_id: str,
use_https: bool = None,
):
"""
To delete an existing DHCP Network from the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.delete(
url = self.get_mikrotik_url(path = f"/ip/dhcp-server/network/{dot_id}", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# ┏┓┳┓┳┳┓┏┓ ┏┓ •
# ┗┓┃┃┃┃┃┃┃ ┃ ┏┓┏┳┓┏┳┓┓┏┏┓┓╋┓┏
# ┗┛┛┗┛ ┗┣┛ ┗┛┗┛┛┗┗┛┗┗┗┻┛┗┗┗┗┫
# ┛
async def list_snmp_communities(
self,
use_https: bool = None
) -> ApiResponse:
"""
To enlist all the SNMP Communities that have been configured.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.get(
url = self.get_mikrotik_url(path = r"/snmp/community", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def add_snmp_community(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To add a new SNMP Community to the MikroTik's configuration.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.put(
url = self.get_mikrotik_url(path = r"/snmp/community", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def update_snmp_community(
self,
dot_id: str,
json_payload: dict,
use_https: bool = None,
) -> ApiResponse:
"""
To update an existing SNMP Community in the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.patch(
url = self.get_mikrotik_url(path = f"/snmp/community/{dot_id}", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def remove_snmp_community(
self,
dot_id: str,
use_https: bool = None,
):
"""
To delete an existing SNMP Community from the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.delete(
url = self.get_mikrotik_url(path = f"/snmp/community/{dot_id}", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# ┳┓┏┓┏┳┓ •
# ┃┃┣┫ ┃ ━━┓┏┓┏┓
# ┛┗┛┗ ┻ ┗┛┗┗┫
# ┛
async def list_firewall_nat(
self,
use_https: bool = None
) -> ApiResponse:
"""
To enlist all the Firewall NAT that have been configured.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.get(
url = self.get_mikrotik_url(path = r"/ip/firewall/nat", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def add_firewall_nat(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To add a new Firewall NAT to the MikroTik's configuration.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.put(
url = self.get_mikrotik_url(path = r"/ip/firewall/nat", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def update_firewall_nat(
self,
dot_id: str,
json_payload: dict,
use_https: bool = None,
) -> ApiResponse:
"""
To update an existing Firewall NAT in the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.patch(
url = self.get_mikrotik_url(path = f"/ip/firewall/nat/{dot_id}", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
async def remove_firewall_nat(
self,
dot_id: str,
use_https: bool = None,
):
"""
To delete an existing Firewall NAT from the MikroTik's configuration.
:param dot_id: The value of the '.id' field in the list.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.delete(
url = self.get_mikrotik_url(path = f"/ip/firewall/nat/{dot_id}", use_https = use_https),
auth = self._basic_auth
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# ┳┓┳┓┏┓
# ┃┃┃┃┗┓
# ┻┛┛┗┗┛
async def set_dns(
self,
json_payload: dict,
use_https: bool = None
) -> ApiResponse:
"""
To set the DNS parameters for the MikroTik.
:param json_payload: The JSON to send in the body of the request.
:param use_https: Whether to use HTTPS, or HTTP. Leave it as null to use the class's default setting.
:return: A structured API response.
"""
# Make the API call:
api_response = await self._rest.post(
url = self.get_mikrotik_url(path = r"/ip/dns/set", use_https = use_https),
auth = self._basic_auth,
json = json_payload
)
# Extract the needed values:
if api_response.success: api_response.data = await api_response.get_json()
else: api_response.message = await self.get_failure_message(api_response)
# Done here:
await self.log_action(api_response)
return api_response
# *****************************************************************************************************************
# ***** ****
# *** MAIN PROGRAM ***
# ***** ****
# *****************************************************************************************************************
if __name__ == "__main__":
# Make an instance of an HTTP client to use to make API calls:
my_http_client = httpx.AsyncClient(
limits = httpx.Limits(
max_connections = 100, # ............ Maximum number of connections allowed in the pool.
max_keepalive_connections = 50, # ... Maximum number of connections that can be kept alive.
),
timeout = httpx.Timeout(
pool = 120.0, # .... Time to wait for a free connection from the pool.
connect = 2.5, # ... Time to wait for establishing a connection to the server.
write = 10.0, # .... Time to wait for sending data.
read = 9.9 # ....... Time to wait for receiving data.
)
)
# Create an instance of a Mongo conn. to write action logs:
logs_mongo = AsyncMongo(
connection_string = r"mongodb://del.ditscentre.in:27017,wtt.ditscentre.in:27017,mum.arh.001.ditscentre.in:27017/admin?tls=true&tlsCAFile=%2Fetc%2Fssl%2Fdbu%2Fmongo_data_ca.pem&tlsCertificateKeyFile=%2Fetc%2Fssl%2Fdbu%2Fmongo_data_cert.pem&replicaSet=dits_mongod_rep&readPreference=primary&authMechanism=MONGODB-X509&authSource=%24external",
database_name = "converse",
max_connections = 10,
)
# Create an instance of a MikroTik client:
my_mikrotik = AsyncMikroTik(
http_client = my_http_client,
mikrotik_ip = "102.210.173.150",
username = "easyfi",
password = "easyfi",
use_https = False,
config_by = "easyfi",
action_log_conn = logs_mongo
)
async def main():
await logs_mongo.connect()
# api_response = await my_mikrotik.list_system_resources()
# print("SYS RESOURCES:", json.to_string(api_response.data))
#
# api_response = await my_mikrotik.list_interfaces()
# print(f"INTERFACES ({len(api_response.data)}):", json.to_string(api_response.data))
#
# api_response = await my_mikrotik.list_vlans()
# print(f"VLANS ({len(api_response.data)}):", json.to_string(api_response.data))
#
# api_response = await my_mikrotik.list_ip_pools()
# print(f"IP POOLS ({len(api_response.data)}):", json.to_string(api_response.data))
#
# api_response = await my_mikrotik.list_ppp_profiles()
# print(f"PPP PROFILES ({len(api_response.data)}):", json.to_string(api_response.data))
#
# api_response = await my_mikrotik.list_ppp_servers()
# print(f"PPP SERVERS ({len(api_response.data)}):", json.to_string(api_response.data))
#
# api_response = await my_mikrotik.list_hotspot_profiles()
# print(f"HOTSPOT PROFILES ({len(api_response.data)}):", json.to_string(api_response.data))
#
# api_response = await my_mikrotik.list_hotspot_servers()
# print(f"HOTSPOT SERVERS ({len(api_response.data)}):", json.to_string(api_response.data))
#
api_response = await my_mikrotik.list_hotspot_walled_gardens()
print(f"HOTSPOT WALLED GARDENS ({len(api_response.data)}):", json.to_string(api_response.data))
#
# api_response = await my_mikrotik.list_hotspot_walled_garden_ips()
# print(f"HOTSPOT WALLED GARDEN IPS ({len(api_response.data)}):", json.to_string(api_response.data))
#
# api_response = await my_mikrotik.list_radius_servers()
# print(f"RADIUS SERVERS ({len(api_response.data)}):", json.to_string(api_response.data))
#
# api_response = await my_mikrotik.list_firewall_nat()
# print(f"FIREWALL NAT ({len(api_response.data)}):")
async def hotspot_steps():
HS_VLAN_ID = "2001"
HS_INTERFACE_NAME = "easyfi-hs-if"
HS_VLAN_NAME = "easyfi-hs-vlan-" + HS_VLAN_ID
HS_IP_POOL_NAME = "easyfi-hs-pool-" + HS_VLAN_ID
HS_PROFILE_NAME = "easyfi-hs-prf-" + HS_VLAN_ID
HS_SERVER_NAME = "easyfi-hs-srv-" + HS_VLAN_ID
HS_DHCP_SERVER_NAME = "easyfi-hs-dhcp-" + HS_VLAN_ID
HS_SNMP_COMMUNITY_NAME = "lkjhgfdsa1234567"
HS_PUBLIC_IP_SUBNET = "102.210.173.150/26"
HS_FIRST_PUBLIC_IP = "102.210.173.128"
HS_LAST_PUBLIC_IP = "102.210.173.191"
HS_PRIVATE_IP_SUBNET = "100.65.0.0/22"
HS_FIRST_PRIVATE_IP = "100.65.0.0"
HS_LAST_PRIVATE_IP = "100.65.3.255"
HS_GATEWAY_PRIVATE_IP = "100.65.0.1"
HS_RADIUS_SERVER_IP = "154.84.218.42"
HS_RADIUS_SERVER_SECRET = "asdfghjkl"
HS_COMMENT = my_mikrotik.create_comment_json()
# # STEP 1:
# # Set up the interface:
# api_response = await my_mikrotik.update_interface(
# dot_id = "*3",
# json_payload = {
# "name": HS_INTERFACE_NAME,
# "comment": HS_COMMENT
# }
# )
# print("STEP 1:", api_response.success, f"({api_response.action})")
# print("MESSAGE:", api_response.message)
# print("JSON:", api_response.data)
# print("\n\n")
# # STEP 2:
# # Create the VLAN:
# api_response = await my_mikrotik.add_vlan(
# json_payload = {
# "name": HS_VLAN_NAME,
# "interface": HS_INTERFACE_NAME,
# "vlan-id": HS_VLAN_ID,
# "disabled": "false",
# "comment": HS_COMMENT
# }
# )
# print("STEP 2:", api_response.success, f"({api_response.action})")
# print("MESSAGE:", api_response.message)
# print("JSON:", api_response.data)
# print("\n\n")
# # STEP 3:
# # Bind a new IP address/network to the VLAN:
# api_response = await my_mikrotik.add_ip_address_binding(
# json_payload = {
# "address": HS_PRIVATE_IP_SUBNET,
# "interface": HS_VLAN_NAME,
# "disabled": "false",
# "comment": HS_COMMENT
# }
# )
# print("STEP 3:", api_response.success, f"({api_response.action})")
# print("MESSAGE:", api_response.message)
# print("JSON:", api_response.data)
# print("\n\n")
# # STEP 4:
# # Add a new IP Pool for the Hotspot users:
# api_response = await my_mikrotik.add_ip_pool(
# json_payload = {
# "name": HS_IP_POOL_NAME,
# "ranges": HS_PRIVATE_IP_SUBNET,
# "comment": HS_COMMENT
# }
# )
# print("STEP 4:", api_response.success, f"({api_response.action})")
# print("MESSAGE:", api_response.message)
# print("JSON:", api_response.data)
# print("\n\n")
# # STEP 5:
# # Add a new Hotspot Profile:
# api_response = await my_mikrotik.add_hotspot_profile(
# json_payload = {
# "dns-name": "hs01.easyfi.net.in",
# "hotspot-address": HS_GATEWAY_PRIVATE_IP,
# "html-directory": "hotspot",
# "html-directory-override": "",
# "http-cookie-lifetime": "3d",
# "http-proxy": "0.0.0.0:0",
# "install-hotspot-queue": "false",
# "login-by": "cookie,http-chap",
# # "name": "hs01.easyfi.net.in",
# "name": HS_PROFILE_NAME,
# "split-user-domain": "false",
# "use-radius": "true",
# "nas-port-type": "wireless-802.11",
# "radius-accounting": "true",
# "radius-default-domain": "",
# "radius-interim-update": "received",
# "radius-location-id": "",
# "radius-location-name": "",
# "radius-mac-format": "XX:XX:XX:XX:XX:XX",
# # "comment": HS_COMMENT
# }
# )
# print("STEP 5:", api_response.success, f"({api_response.action})")
# print("MESSAGE:", api_response.message)
# print("JSON:", api_response.data)
# print("\n\n")
# # STEP 6:
# # Add a new Hotspot Server:
# api_response = await my_mikrotik.add_hotspot_server(
# json_payload = {
# "address-pool": HS_IP_POOL_NAME,
# "addresses-per-mac": "2",
# "idle-timeout": "5m",
# "interface": HS_VLAN_NAME,
# "keepalive-timeout": "none",
# "login-timeout": "none",
# # "name": "hs01.easyfi.net.in",
# "name": HS_SERVER_NAME,
# # "profile": "hs01.easyfi.net.in",
# "profile": HS_PROFILE_NAME,
# "disabled": "false",
# # "comment": HS_COMMENT
# }
# )
# print("STEP 6:", api_response.success, f"({api_response.action})")
# print("MESSAGE:", api_response.message)
# print("JSON:", api_response.data)
# print("\n\n")
# # STEP 7:
# # Add a new DHCP Server:
# api_response = await my_mikrotik.add_dhcp_server(
# json_payload = {
# "address-pool": HS_IP_POOL_NAME,
# "authoritative": "yes",
# "disabled": "false",
# "interface": HS_VLAN_NAME,
# "lease-time": "30m",
# "name": HS_DHCP_SERVER_NAME,
# "use-radius": "no",
# "comment": HS_COMMENT
# }
# )
# print("STEP 7:", api_response.success, f"({api_response.action})")
# print("MESSAGE:", api_response.message)
# print("JSON:", api_response.data)
# print("\n\n")
# # STEP 8:
# # Add a new DHCP Network:
# api_response = await my_mikrotik.add_dhcp_network(
# json_payload = {
# "address": HS_PRIVATE_IP_SUBNET,
# "gateway": HS_GATEWAY_PRIVATE_IP,
# "netmask": HS_PRIVATE_IP_SUBNET.split("/")[-1],
# "dns-server": HS_GATEWAY_PRIVATE_IP,
# "comment": HS_COMMENT
# }
# )
# print("STEP 8:", api_response.success, f"({api_response.action})")
# print("MESSAGE:", api_response.message)
# print("JSON:", api_response.data)
# print("\n\n")
# STEP 9-A
# Set up the Walled-Garden:
for index, url in enumerate([
"api.thecaoffice.com",
"cdn.jsdelivr.net"
]):
api_response = await my_mikrotik.add_hotspot_walled_garden(
json_payload = {
"action": "allow",
"dst-host": url,
"comment": HS_COMMENT
}
)
print(f"STEP 9-A.{index}:", api_response.success, f"({api_response.action})")
print("MESSAGE:", api_response.message)
print("JSON:", api_response.data)
print("\n\n")
# # STEP 9-B:
# # Set up the Walled-Garden IP:
# api_response = await my_mikrotik.add_hotspot_walled_garden_ip(
# json_payload = {
# "action": "accept",
# "dst-address": HS_RADIUS_SERVER_IP,
# "comment": HS_COMMENT
# }
# )
# print("STEP 9-B:", api_response.success, f"({api_response.action})")
# print("MESSAGE:", api_response.message)
# print("JSON:", api_response.data)
# print("\n\n")
# # STEP 10:
# # Add a new RADIUS Server:
# api_response = await my_mikrotik.add_radius_server(
# json_payload = {
# "accounting-port": "1813",
# "address": HS_RADIUS_SERVER_IP,
# "authentication-port": "1812",
# "disabled": "false",
# "protocol": "udp",
# "secret": HS_RADIUS_SERVER_SECRET,
# "service": "ppp,login,hotspot,dhcp",
# "timeout": "300ms",
# "comment": HS_COMMENT
# }
# )
# print("STEP 10:", api_response.success, f"({api_response.action})")
# print("MESSAGE:", api_response.message)
# print("JSON:", api_response.data)
# print("\n\n")
# # STEP 11:
# # Allow incoming traffic from RADIUS:
# api_response = await my_mikrotik.set_radius_incoming(
# json_payload = {
# "accept": "yes",
# "port": "3799",
# # "comment": HS_COMMENT
# }
# )
# print("STEP 11:", api_response.success, f"({api_response.action})")
# print("MESSAGE:", api_response.message)
# print("JSON:", api_response.data)
# print("\n\n")
# # STEP 12:
# # Set up the DNS:
# api_response = await my_mikrotik.set_dns(
# json_payload = {
# "allow-remote-requests": "true",
# "servers": "8.8.8.8,8.8.4.4",
# # "comment": HS_COMMENT
# }
# )
# print("STEP 12:", api_response.success, f"({api_response.action})")
# print("MESSAGE:", api_response.message)
# print("JSON:", api_response.data)
# print("\n\n")
# # STEP 13:
# # Map the private IPs to the public IPs for NAT-ing:
# private_ips = [
# str(ipaddress.IPv4Address(_))
# for _ in range(
# int(ipaddress.IPv4Address(HS_FIRST_PRIVATE_IP)),
# int(ipaddress.IPv4Address(HS_LAST_PRIVATE_IP)) + 1
# )
# ]
# public_ips = [
# str(ipaddress.IPv4Address(_))
# for _ in range(
# int(ipaddress.IPv4Address(HS_FIRST_PUBLIC_IP)),
# int(ipaddress.IPv4Address(HS_LAST_PUBLIC_IP)) + 1
# )
# ]
# nat_map = my_mikrotik.split_ipv4_range_in_powers_of_two(
# start_ip = HS_FIRST_PRIVATE_IP,
# end_ip = HS_LAST_PRIVATE_IP,
# targets = public_ips,
# consider_reserved_ips = False
# )
# print("NAT MAP:", json.to_string(nat_map, default=str))
# print("PRIVATE IP COUNT:", len(private_ips))
# print("PUBLIC IP COUNT:", len(public_ips))
# print("RULE COUNT:", len(nat_map))
# for index, nat_rule in enumerate(nat_map):
# api_response = await my_mikrotik.add_firewall_nat(
# json_payload = {
# "action": "src-nat",
# "chain": "srcnat",
# "disabled": "false",
# "src-address": nat_rule["network"],
# "to-addresses": nat_rule["target"],
# "comment": HS_COMMENT
# }
# )
# print(f"STEP 13 ({index+1}/{len(nat_map)}):", api_response.success, f"({api_response.action})")
# print("MESSAGE:", api_response.message)
# print("JSON:", api_response.data)
# print("\n\n")
# # STEP 14:
# # Set up the SNMP Community:
# api_response = await my_mikrotik.add_snmp_community(
# json_payload = {
# "addresses": "::/0",
# "authentication-password": "",
# "authentication-protocol": "MD5",
# "disabled": "false",
# "encryption-password": "",
# "encryption-protocol": "DES",
# "name": HS_SNMP_COMMUNITY_NAME,
# "read-access": "true",
# "security": "none",
# "write-access": "false",
# "comment": HS_COMMENT
# }
# )
# print("STEP 14:", api_response.success, f"({api_response.action})")
# print("MESSAGE:", api_response.message)
# print("JSON:", api_response.data)
# print("\n\n")
asyncio.run(hotspot_steps())