(20250213) Many things added to the mikrotik util. Even added a sample hotspot config. code to it.

This commit is contained in:
2025-02-13 16:59:00 +05:30
parent 519aff21ca
commit b913f91fbd
2 changed files with 2137 additions and 78 deletions
@@ -322,8 +322,8 @@ class MikroTikPPPoE1000Controller(MikroTikController):
async def set_up_one_vlan( async def set_up_one_vlan(
self, self,
mikrotik_client: AsyncMikroTik, mikrotik_client: AsyncMikroTik,
vlan_id: int, new_resource: int,
vlan_list: List[dict], existing_resources: List[dict],
use_https: bool = True use_https: bool = True
) -> MikroTikConfigAttemptResponse: ) -> MikroTikConfigAttemptResponse:
@@ -331,8 +331,8 @@ class MikroTikPPPoE1000Controller(MikroTikController):
To set up just one of the needed VLANs. If the VLAN id is not taken, a new VLAN will be created, otherwise the To set up just one of the needed VLANs. If the VLAN id is not taken, a new VLAN will be created, otherwise the
existing one will be updated. existing one will be updated.
:param mikrotik_client: The client to use. :param mikrotik_client: The client to use.
:param vlan_id: The id of the VLAN you want to create. :param new_resource: The id of the VLAN you want to create.
:param vlan_list: The list of existing VLANs already configured in the MikroTik device. Helps us decide between :param existing_resources: The list of existing VLANs already configured in the MikroTik device. Helps us decide between
the use of PUT and PATCH methods. the use of PUT and PATCH methods.
:param use_https: Whether to use HTTPS, or HTTP. :param use_https: Whether to use HTTPS, or HTTP.
:return: A structured response to indicate what happened during the process. :return: A structured response to indicate what happened during the process.
@@ -341,15 +341,13 @@ class MikroTikPPPoE1000Controller(MikroTikController):
# Start by assuming failure: # Start by assuming failure:
step_response = MikroTikConfigAttemptResponse() step_response = MikroTikConfigAttemptResponse()
# Check if you can find the VLAN id in the existing VLANs list: # Check if the configuration already exists:
existing_dot_id = None existing_dot_id = None
existing_vlan_id = None existing_resource = None
existing_vlan_json = None for _ in existing_resources:
for vlan_json in vlan_list: if _.get("vlan-id", "???") == str(new_resource):
if vlan_json.get("vlan-id") == str(vlan_id): existing_dot_id = _.get(".id")
existing_dot_id = vlan_json.get(".id") existing_resource = _
existing_vlan_id = vlan_json.get("vlan-id")
existing_vlan_json = vlan_json
break break
# If the VLAN id is unused: # If the VLAN id is unused:
@@ -358,11 +356,11 @@ class MikroTikPPPoE1000Controller(MikroTikController):
# We add the VLAN: # We add the VLAN:
api_response = await mikrotik_client.add_vlan( api_response = await mikrotik_client.add_vlan(
json_payload = { json_payload = {
"name": self.VLAN_NAME.format(vlan_id), "name": self.VLAN_NAME.format(new_resource),
"vlan-id": str(vlan_id), "vlan-id": str(new_resource),
"interface": self.HW_INTERFACE_NAME, "interface": self.HW_INTERFACE_NAME,
"disabled": "false", "disabled": "false",
"comment": mikrotik_client.create_comment_json(roll_back_config = existing_vlan_json) "comment": mikrotik_client.create_comment_json(roll_back_config = existing_resource)
}, },
use_https = use_https use_https = use_https
) )
@@ -370,11 +368,11 @@ class MikroTikPPPoE1000Controller(MikroTikController):
# And assess the result: # And assess the result:
if api_response.success: if api_response.success:
step_response.success = True step_response.success = True
step_response.message = f"Added new VLAN with id {vlan_id}." step_response.message = f"Added new VLAN with id {new_resource}."
step_response.exception = None step_response.exception = None
else: else:
step_response.success = False step_response.success = False
step_response.message = f"Failed to add new VLAN with id {vlan_id}." step_response.message = f"Failed to add new VLAN with id {new_resource}."
step_response.exception = api_response.exception step_response.exception = api_response.exception
# If the VLAN id is already used: # If the VLAN id is already used:
@@ -384,10 +382,10 @@ class MikroTikPPPoE1000Controller(MikroTikController):
api_response = await mikrotik_client.update_vlan( api_response = await mikrotik_client.update_vlan(
dot_id = existing_dot_id, dot_id = existing_dot_id,
json_payload = { json_payload = {
"name": self.VLAN_NAME.format(vlan_id), "name": self.VLAN_NAME.format(new_resource),
"interface": self.HW_INTERFACE_NAME, "interface": self.HW_INTERFACE_NAME,
"disabled": "false", "disabled": "false",
"comment": mikrotik_client.create_comment_json(roll_back_config = existing_vlan_json) "comment": mikrotik_client.create_comment_json(roll_back_config = existing_resource)
}, },
use_https = use_https use_https = use_https
) )
@@ -395,11 +393,11 @@ class MikroTikPPPoE1000Controller(MikroTikController):
# And assess the result: # And assess the result:
if api_response.success: if api_response.success:
step_response.success = True step_response.success = True
step_response.message = f"Updated existing VLAN ({existing_vlan_id}) to id {vlan_id}." step_response.message = f"Updated existing VLAN ({existing_dot_id}) to id {new_resource}."
step_response.exception = None step_response.exception = None
else: else:
step_response.success = False step_response.success = False
step_response.message = f"Failed to update existing VLAN ({existing_vlan_id}) to id {vlan_id}." step_response.message = f"Failed to update existing VLAN ({existing_dot_id}) to id {new_resource}."
step_response.exception = api_response.exception step_response.exception = api_response.exception
# Done here: # Done here:
@@ -434,15 +432,15 @@ class MikroTikPPPoE1000Controller(MikroTikController):
return step_response return step_response
# Extract the list here: # Extract the list here:
vlan_list = api_response.data existing_resources = api_response.data
# Create a task for each VLAN that you need to set up, # Create a task for each VLAN that you need to set up,
# then fire them all asynchronously: # then fire them all asynchronously:
tasks = [ tasks = [
self.set_up_one_vlan( self.set_up_one_vlan(
mikrotik_client = mikrotik_client, mikrotik_client = mikrotik_client,
vlan_id = vlan_id, new_resource = vlan_id,
vlan_list = vlan_list, existing_resources = existing_resources,
use_https = use_https use_https = use_https
) for vlan_id in mikrotik_auth.vlanIds ) for vlan_id in mikrotik_auth.vlanIds
] ]
@@ -554,16 +552,16 @@ class MikroTikPPPoE1000Controller(MikroTikController):
async def set_up_one_ip_pool( async def set_up_one_ip_pool(
self, self,
mikrotik_client: AsyncMikroTik, mikrotik_client: AsyncMikroTik,
ip_pool: dict, new_resource: dict,
existing_ip_pools: List[dict], existing_resources: List[dict],
use_https: bool = True use_https: bool = True
) -> MikroTikConfigAttemptResponse: ) -> MikroTikConfigAttemptResponse:
""" """
To set up one of the needed IP pools. To set up one of the needed IP pools.
:param mikrotik_client: The client to use. :param mikrotik_client: The client to use.
:param ip_pool: The IP pool you want configured by the end of the process. :param new_resource: The IP pool you want configured by the end of the process.
:param existing_ip_pools: A list of the existing IP pools. Helps to decide between 'PUT' and 'PATCH' methods. :param existing_resources: A list of the existing IP pools. Helps to decide between 'PUT' and 'PATCH' methods.
:param use_https: Whether to use HTTPS, or HTTP. :param use_https: Whether to use HTTPS, or HTTP.
:return: A structured response to indicate what happened during the process. :return: A structured response to indicate what happened during the process.
""" """
@@ -573,11 +571,11 @@ class MikroTikPPPoE1000Controller(MikroTikController):
# Check if the configuration already exists: # Check if the configuration already exists:
existing_dot_id = None existing_dot_id = None
existing_ip_pool_json = None existing_resource = None
for existing_ip_pool in existing_ip_pools: for _ in existing_resources:
if existing_ip_pool.get("name", "???") == ip_pool["name"]: if _.get("name", "???") == new_resource["name"]:
existing_dot_id = existing_ip_pool[".id"] existing_dot_id = _.get(".id")
existing_ip_pool_json = existing_ip_pool existing_resource = _
break break
# If the IP pool doesn't already exist: # If the IP pool doesn't already exist:
@@ -586,8 +584,8 @@ class MikroTikPPPoE1000Controller(MikroTikController):
# Add the configuration: # Add the configuration:
api_response = await mikrotik_client.add_ip_pool( api_response = await mikrotik_client.add_ip_pool(
json_payload = { json_payload = {
"name": ip_pool["name"], "name": new_resource["name"],
"ranges": ip_pool["network"], "ranges": new_resource["network"],
"comment": mikrotik_client.create_comment_json() "comment": mikrotik_client.create_comment_json()
}, },
use_https = use_https use_https = use_https
@@ -596,11 +594,11 @@ class MikroTikPPPoE1000Controller(MikroTikController):
# And assess the result: # And assess the result:
if api_response.success: if api_response.success:
step_response.success = True step_response.success = True
step_response.message = f"Added new IP pool '{ip_pool['name']}'." step_response.message = f"Added new IP Pool '{new_resource['name']}'."
step_response.exception = None step_response.exception = None
else: else:
step_response.success = False step_response.success = False
step_response.message = f"Failed to add new IP pool '{ip_pool['name']}'." step_response.message = f"Failed to add new IP Pool '{new_resource['name']}'."
step_response.exception = api_response.exception step_response.exception = api_response.exception
# If the IP pool already exists: # If the IP pool already exists:
@@ -610,9 +608,9 @@ class MikroTikPPPoE1000Controller(MikroTikController):
api_response = await mikrotik_client.update_ip_pool( api_response = await mikrotik_client.update_ip_pool(
dot_id = existing_dot_id, dot_id = existing_dot_id,
json_payload = { json_payload = {
"name": ip_pool["name"], "name": new_resource["name"],
"ranges": ip_pool["network"], "ranges": new_resource["network"],
"comment": mikrotik_client.create_comment_json(roll_back_config = existing_ip_pool_json) "comment": mikrotik_client.create_comment_json(roll_back_config = existing_resource)
}, },
use_https = use_https use_https = use_https
) )
@@ -620,11 +618,11 @@ class MikroTikPPPoE1000Controller(MikroTikController):
# And assess the result: # And assess the result:
if api_response.success: if api_response.success:
step_response.success = True step_response.success = True
step_response.message = f"Updated existing IP pool '{ip_pool['name']}'." step_response.message = f"Updated existing IP pool '{new_resource['name']}'."
step_response.exception = None step_response.exception = None
else: else:
step_response.success = False step_response.success = False
step_response.message = f"Failed to update existing IP pool '{ip_pool['name']}'." step_response.message = f"Failed to update existing IP pool '{new_resource['name']}'."
step_response.exception = api_response.exception step_response.exception = api_response.exception
# Done here: # Done here:
@@ -654,16 +652,16 @@ class MikroTikPPPoE1000Controller(MikroTikController):
# If the listing failed: # If the listing failed:
if not api_response.success: if not api_response.success:
step_response.success = False step_response.success = False
step_response.message = "Failed to enlist existing IP pools during configuration." step_response.message = "Failed to enlist existing IP Pools during configuration."
step_response.exception = step_response.exception step_response.exception = step_response.exception
return step_response return step_response
# Extract the list here: # Extract the list here:
existing_ip_pools = api_response.data existing_resources = api_response.data
# First we split the whole private IP range # First we split the whole private IP range
# into the no. of VLANs we had been asked to make: # into the no. of VLANs we had been asked to make:
ip_pools = mikrotik_client.split_ipv4_range_equally( new_resources = mikrotik_client.split_ipv4_range_equally(
start_ip = mikrotik_auth.firstPrivateIp, start_ip = mikrotik_auth.firstPrivateIp,
end_ip = mikrotik_auth.lastPrivateIp, end_ip = mikrotik_auth.lastPrivateIp,
targets = mikrotik_auth.vlanIds targets = mikrotik_auth.vlanIds
@@ -674,13 +672,13 @@ class MikroTikPPPoE1000Controller(MikroTikController):
tasks = [ tasks = [
self.set_up_one_ip_pool( self.set_up_one_ip_pool(
mikrotik_client = mikrotik_client, mikrotik_client = mikrotik_client,
ip_pool = { new_resource = {
"name": self.PRIVATE_IP_POOL_NAME.format(ip_pool["target"]), "name": self.PRIVATE_IP_POOL_NAME.format(new_resource["target"]),
"network": ip_pool["network"], "network": new_resource["network"],
}, },
existing_ip_pools = existing_ip_pools, existing_resources = existing_resources,
use_https = use_https use_https = use_https
) for ip_pool in ip_pools ) for new_resource in new_resources
] ]
results = await asyncio.gather(*tasks) results = await asyncio.gather(*tasks)
@@ -689,7 +687,7 @@ class MikroTikPPPoE1000Controller(MikroTikController):
success_count = 0 success_count = 0
for result in results: for result in results:
if result.success: success_count += 1 if result.success: success_count += 1
step_response.message = f"{success_count}/{total_count} IP pool(s) configured." step_response.message = f"{success_count}/{total_count} IP Pool(s) configured."
step_response.success = True if success_count == total_count else False step_response.success = True if success_count == total_count else False
# Done here: # Done here:
@@ -719,7 +717,7 @@ class MikroTikPPPoE1000Controller(MikroTikController):
# If the listing failed: # If the listing failed:
if not api_response.success: if not api_response.success:
step_response.success = False step_response.success = False
step_response.message = "Failed to enlist existing IP pools during rollback." step_response.message = "Failed to enlist existing IP Pools during rollback."
step_response.exception = step_response.exception step_response.exception = step_response.exception
return step_response return step_response
@@ -769,11 +767,520 @@ class MikroTikPPPoE1000Controller(MikroTikController):
# Assess the overall results: # Assess the overall results:
if success_count == total_count: step_response.success = True if success_count == total_count: step_response.success = True
step_response.message = f"Removed/rolled-back {success_count}/{total_count} IP pool(s)." step_response.message = f"Removed/rolled-back {success_count}/{total_count} IP Pool(s)."
# Done here: # Done here:
return step_response return step_response
# ┏┓┏┓┏┓ ┏┓ ┏┓ ┏•┓
# ┃┃┃┃┃┃┏┓┣ ┃┃┏┓┏┓╋┓┃┏┓┏
# ┣┛┣┛┣┛┗┛┗┛ ┣┛┛ ┗┛┛┗┗┗ ┛
async def set_up_one_ppp_profile(
self,
mikrotik_client: AsyncMikroTik,
new_resource: dict,
existing_resources: List[dict],
use_https: bool = True
) -> MikroTikConfigAttemptResponse:
"""
To set up one of the needed PPPoE Profiles.
:param mikrotik_client: The client to use.
:param new_resource: The PPPoE Profile you want configured by the end of the process.
:param existing_resources: A list of the existing PPPoE Profiles. Helps to decide between 'PUT' and 'PATCH'
methods.
:param use_https: Whether to use HTTPS, or HTTP.
:return: A structured response to indicate what happened during the process.
"""
# Start by assuming failure:
step_response = MikroTikConfigAttemptResponse()
# Check if the configuration already exists:
existing_dot_id = None
existing_resource = None
for _ in existing_resources:
if _.get("name", "???") == new_resource["name"]:
existing_dot_id = _.get(".id")
existing_resource = _
break
# If the IP pool doesn't already exist:
if existing_dot_id is None:
# Add the configuration:
api_response = await mikrotik_client.add_ppp_profile(
json_payload = {
"name": new_resource["name"],
"address-list": "",
"bridge-learning": "default",
"change-tcp-mss": "yes",
"dns-server": "8.8.8.8",
"local-address": new_resource["local-address"],
"only-one": "yes",
"remote-address": new_resource["remote-address"],
"use-compression": "default",
"use-encryption": "default",
"use-ipv6": "yes",
"use-mpls": "default",
"use-upnp": "default",
"comment": mikrotik_client.create_comment_json()
},
use_https = use_https
)
# And assess the result:
if api_response.success:
step_response.success = True
step_response.message = f"Added new PPPoE Profile '{new_resource['name']}'."
step_response.exception = None
else:
step_response.success = False
step_response.message = f"Failed to add new PPPoE Profile '{new_resource['name']}'."
step_response.exception = api_response.exception
# If the IP pool already exists:
else:
# Update the configuration:
api_response = await mikrotik_client.update_ppp_profile(
dot_id = existing_dot_id,
json_payload = {
"name": new_resource["name"],
"address-list": "",
"bridge-learning": "default",
"change-tcp-mss": "yes",
"dns-server": "8.8.8.8",
"local-address": new_resource["local-address"],
"only-one": "yes",
"remote-address": new_resource["remote-address"],
"use-compression": "default",
"use-encryption": "default",
"use-ipv6": "yes",
"use-mpls": "default",
"use-upnp": "default",
"comment": mikrotik_client.create_comment_json(roll_back_config = existing_resource)
},
use_https = use_https
)
# And assess the result:
if api_response.success:
step_response.success = True
step_response.message = f"Updated existing PPPoE Profile '{new_resource['name']}'."
step_response.exception = None
else:
step_response.success = False
step_response.message = f"Failed to update existing PPPoE Profile '{new_resource['name']}'."
step_response.exception = api_response.exception
# Done here:
return step_response
async def set_up_ppp_profiles(
self,
mikrotik_client: AsyncMikroTik,
mikrotik_auth: MikroTikPPPoE1000Auth,
use_https: bool = True
) -> MikroTikConfigAttemptResponse:
"""
To set up ALL the needed PPPoE Profiles.
:param mikrotik_client: The client to use.
:param mikrotik_auth: The set of credentials as received from the UI/API.
:param use_https: Whether to use HTTPS, or HTTP.
:return: A structured response to indicate what happened during the process.
"""
# Start by assuming failure:
step_response = MikroTikConfigAttemptResponse()
# Enlist all the existing VLANs:
api_response = await mikrotik_client.list_ppp_profiles(use_https = use_https)
# If the listing failed:
if not api_response.success:
step_response.success = False
step_response.message = "Failed to enlist existing PPPoE Profiles during configuration."
step_response.exception = step_response.exception
return step_response
# Extract the list here:
existing_resources = api_response.data
# First we split the whole private IP range
# into the no. of VLANs we had been asked to make:
new_resources = mikrotik_client.split_ipv4_range_equally(
start_ip = mikrotik_auth.firstPrivateIp,
end_ip = mikrotik_auth.lastPrivateIp,
targets = mikrotik_auth.vlanIds
)
# Create tasks to create new PPPoE Profiles,
# and fire them asynchronously:
tasks = [
self.set_up_one_ppp_profile(
mikrotik_client = mikrotik_client,
new_resource = {
"name": self.PPP_PROFILE_NAME.format(new_resource["target"]),
"local-address": mikrotik_auth.nasIp,
"remote-address": self.PRIVATE_IP_POOL_NAME.format(new_resource["target"]),
},
existing_resources = existing_resources,
use_https = use_https
) for new_resource in new_resources
]
results = await asyncio.gather(*tasks)
# Assess the results:
total_count = len(results)
success_count = 0
for result in results:
if result.success: success_count += 1
step_response.message = f"{success_count}/{total_count} PPPoE Profile(s) configured."
step_response.success = True if success_count == total_count else False
# Done here:
return step_response
async def roll_back_ppp_profiles(
self,
mikrotik_client: AsyncMikroTik,
use_https: bool = True
) -> MikroTikConfigAttemptResponse:
"""
To reset PPPoE Profiles to their original state (if they already existed) or remove them if this class added
them.
:param mikrotik_client: The client to use.
:param use_https: Whether to use HTTPS, or HTTP.
:return: A structured response to indicate what happened during the process.
"""
# Start by assuming failure:
total_count = 0
success_count = 0
step_response = MikroTikConfigAttemptResponse()
# Enlist all the existing VLANs:
api_response = await mikrotik_client.list_ppp_profiles(use_https = use_https)
# If the listing failed:
if not api_response.success:
step_response.success = False
step_response.message = "Failed to enlist existing PPPoE Profiles during rollback."
step_response.exception = step_response.exception
return step_response
# Loop through all the VLANs,
# and either reset them to their original state (if they already existed),
# or remove them entirely if they didn't exist before we came:
for resource_json in api_response.data:
# Check if the VLAN was created by this class:
if not mikrotik_client.is_my_config(
config_json = resource_json,
name_substring = self.NAME_PREFIX
): continue
# Extract the rollback information:
dot_id = resource_json.get(".id")
# We delete the resource:
api_response = await mikrotik_client.remove_ppp_profile(dot_id = dot_id, use_https = use_https)
# Assess the result:
total_count += 1
if api_response.success: success_count += 1
# Assess the overall results:
if success_count == total_count: step_response.success = True
step_response.message = f"Removed/rolled-back {success_count}/{total_count} PPPoE Profile(s)."
# Done here:
return step_response
# ┏┓┏┓┏┓ ┏┓ ┏┓
# ┃┃┃┃┃┃┏┓┣ ┗┓┏┓┏┓┓┏┏┓┏┓┏
# ┣┛┣┛┣┛┗┛┗┛ ┗┛┗ ┛ ┗┛┗ ┛ ┛
async def set_up_one_ppp_server(
self,
mikrotik_client: AsyncMikroTik,
new_resource: dict,
existing_resources: List[dict],
use_https: bool = True
) -> MikroTikConfigAttemptResponse:
"""
To set up one of the needed PPPoE Servers.
:param mikrotik_client: The client to use.
:param new_resource: The PPPoE Server you want configured by the end of the process.
:param existing_resources: A list of the existing PPPoE Server. Helps to decide between 'PUT' and 'PATCH'
methods.
:param use_https: Whether to use HTTPS, or HTTP.
:return: A structured response to indicate what happened during the process.
"""
# Start by assuming failure:
step_response = MikroTikConfigAttemptResponse()
# Check if the configuration already exists:
existing_dot_id = None
existing_resource = None
for _ in existing_resources:
if _.get("name", "???") == new_resource["name"]:
existing_dot_id = _.get(".id")
existing_resource = _
break
# If the IP pool doesn't already exist:
if existing_dot_id is None:
# Add the configuration:
api_response = await mikrotik_client.add_ppp_server(
json_payload = {
"service-name": new_resource["service-name"],
"interface": new_resource["interface"],
"default-profile": new_resource["default-profile"],
"authentication": "pap,chap",
"disabled": "false",
"keepalive-timeout": "900",
"max-mru": "1500",
"max-mtu": "1500",
"max-sessions": "unlimited",
"mrru": "1500",
"one-session-per-host": "true",
"pado-delay": "0",
"comment": mikrotik_client.create_comment_json()
},
use_https = use_https
)
# And assess the result:
if api_response.success:
step_response.success = True
step_response.message = f"Added new PPPoE Server '{new_resource['service-name']}'."
step_response.exception = None
else:
step_response.success = False
step_response.message = f"Failed to add new PPPoE Server '{new_resource['service-name']}'."
step_response.exception = api_response.exception
# If the IP pool already exists:
else:
# Update the configuration:
api_response = await mikrotik_client.update_ppp_server(
dot_id = existing_dot_id,
json_payload = {
"service-name": new_resource["service-name"],
"interface": new_resource["interface"],
"default-profile": new_resource["default-profile"],
"authentication": "pap,chap",
"disabled": "false",
"keepalive-timeout": "900",
"max-mru": "1500",
"max-mtu": "1500",
"max-sessions": "unlimited",
"mrru": "1500",
"one-session-per-host": "true",
"pado-delay": "0",
"comment": mikrotik_client.create_comment_json(roll_back_config = existing_resource)
},
use_https = use_https
)
# And assess the result:
if api_response.success:
step_response.success = True
step_response.message = f"Updated existing PPPoE Server '{new_resource['service-name']}'."
step_response.exception = None
else:
step_response.success = False
step_response.message = f"Failed to update existing PPPoE Server '{new_resource['service-name']}'."
step_response.exception = api_response.exception
# Done here:
return step_response
async def set_up_ppp_servers(
self,
mikrotik_client: AsyncMikroTik,
mikrotik_auth: MikroTikPPPoE1000Auth,
use_https: bool = True
) -> MikroTikConfigAttemptResponse:
"""
To set up ALL the needed PPPoE Servers.
:param mikrotik_client: The client to use.
:param mikrotik_auth: The set of credentials as received from the UI/API.
:param use_https: Whether to use HTTPS, or HTTP.
:return: A structured response to indicate what happened during the process.
"""
# Start by assuming failure:
step_response = MikroTikConfigAttemptResponse()
# Enlist all the existing VLANs:
api_response = await mikrotik_client.list_ppp_servers(use_https = use_https)
# If the listing failed:
if not api_response.success:
step_response.success = False
step_response.message = "Failed to enlist existing PPPoE Servers during configuration."
step_response.exception = step_response.exception
return step_response
# Extract the list here:
existing_resources = api_response.data
# First we split the whole private IP range
# into the no. of VLANs we had been asked to make:
new_resources = mikrotik_client.split_ipv4_range_equally(
start_ip = mikrotik_auth.firstPrivateIp,
end_ip = mikrotik_auth.lastPrivateIp,
targets = mikrotik_auth.vlanIds
)
# Create tasks to create new PPPoE Profiles,
# and fire them asynchronously:
tasks = [
self.set_up_one_ppp_server(
mikrotik_client = mikrotik_client,
new_resource = {
"service-name": self.PPP_SERVER_NAME.format(new_resource["target"]),
"interface": self.VLAN_NAME.format(new_resource["target"]),
"default-profile": self.PPP_PROFILE_NAME.format(new_resource["target"])
},
existing_resources = existing_resources,
use_https = use_https
) for new_resource in new_resources
]
results = await asyncio.gather(*tasks)
# Assess the results:
total_count = len(results)
success_count = 0
for result in results:
if result.success: success_count += 1
step_response.message = f"{success_count}/{total_count} PPPoE Server(s) configured."
step_response.success = True if success_count == total_count else False
# Done here:
return step_response
async def roll_back_ppp_servers(
self,
mikrotik_client: AsyncMikroTik,
use_https: bool = True
) -> MikroTikConfigAttemptResponse:
"""
To reset PPPoE Servers to their original state (if they already existed) or remove them if this class added
them.
:param mikrotik_client: The client to use.
:param use_https: Whether to use HTTPS, or HTTP.
:return: A structured response to indicate what happened during the process.
"""
# Start by assuming failure:
total_count = 0
success_count = 0
step_response = MikroTikConfigAttemptResponse()
# Enlist all the existing VLANs:
api_response = await mikrotik_client.list_ppp_servers(use_https = use_https)
# If the listing failed:
if not api_response.success:
step_response.success = False
step_response.message = "Failed to enlist existing PPPoE Servers during rollback."
step_response.exception = step_response.exception
return step_response
# Loop through all the VLANs,
# and either reset them to their original state (if they already existed),
# or remove them entirely if they didn't exist before we came:
for resource_json in api_response.data:
# Check if the VLAN was created by this class:
if not mikrotik_client.is_my_config(
config_json = resource_json,
name_substring = self.NAME_PREFIX
): continue
# Extract the rollback information:
dot_id = resource_json.get(".id")
# We delete the resource:
await mikrotik_client.remove_ppp_server(dot_id = dot_id, use_https = use_https)
# Assess the result:
total_count += 1
if api_response.success: success_count += 1
# Assess the overall results:
if success_count == total_count: step_response.success = True
step_response.message = f"Removed/rolled-back {success_count}/{total_count} PPPoE Server(s)."
# Done here:
return step_response
# ┳┓┏┓┳┓┳┳┳┏┓
# ┣┫┣┫┃┃┃┃┃┗┓
# ┛┗┛┗┻┛┻┗┛┗┛
async def enable_radius(
self,
mikrotik_client: AsyncMikroTik,
mikrotik_auth: MikroTikPPPoE1000Auth,
use_https: bool = True
) -> MikroTikConfigAttemptResponse:
"""
To set up AAA such that it uses RADIUS.
:param mikrotik_client: The client to use.
:param mikrotik_auth: The set of credentials as received from the UI/API.
:param use_https: Whether to use HTTPS, or HTTP.
:return: A structured response to indicate what happened during the process.
"""
# Start by assuming failure:
step_response = MikroTikConfigAttemptResponse()
# We hit the API:
api_response = await mikrotik_client.set_ppp_aaa(
json_payload = {
"accounting": "true",
"interim-update": "3m",
"use-circuit-id-in-nas-port-id": "false",
"use-radius": "true"
},
use_https = use_https
)
# Assess the results:
if api_response.success:
step_response.success = True
step_response.message = f"Enabled RADIUS."
step_response.exception = None
else:
step_response.success = False
step_response.message = f"Failed to enable RADIUS."
step_response.exception = api_response.exception
# Done here:
return step_response
async def add_radius_server(
self,
mikrotik_client: AsyncMikroTik,
mikrotik_auth: MikroTikPPPoE1000Auth,
use_https: bool = True
): pass
# ┏┓ ┓ # ┏┓ ┓
# ┣┫┓┏╋┣┓ # ┣┫┓┏╋┣┓
# ┛┗┗┻┗┛┗ # ┛┗┗┻┗┛┗
@@ -813,7 +1320,8 @@ class MikroTikPPPoE1000Controller(MikroTikController):
config_response = await self.configure(mikrotik_client, mikrotik_auth) config_response = await self.configure(mikrotik_client, mikrotik_auth)
print("CONFIG RESPONSE:", config_response) print("CONFIG RESPONSE:", config_response)
await asyncio.sleep(2.0) print("Waiting...")
await asyncio.sleep(10.0)
# Try to roll all configuration back: # Try to roll all configuration back:
roll_back_response = await self.roll_back(mikrotik_client, mikrotik_auth) roll_back_response = await self.roll_back(mikrotik_client, mikrotik_auth)
@@ -848,6 +1356,18 @@ class MikroTikPPPoE1000Controller(MikroTikController):
all_messages = ["STARTING ROLLBACK."] all_messages = ["STARTING ROLLBACK."]
roll_back_response = MikroTikConfigAttemptResponse() roll_back_response = MikroTikConfigAttemptResponse()
# Next, we roll back all the PPPoE Servers:
if keep_going:
step_response = await self.roll_back_ppp_servers(mikrotik_client, use_https = False)
all_messages.append(step_response.message)
keep_going = step_response.success
# Next, we roll back all the PPPoE Profiles:
if keep_going:
step_response = await self.roll_back_ppp_profiles(mikrotik_client, use_https = False)
all_messages.append(step_response.message)
keep_going = step_response.success
# Next, we roll back all the IP pools: # Next, we roll back all the IP pools:
if keep_going: if keep_going:
step_response = await self.roll_back_ip_pools(mikrotik_client, use_https = False) step_response = await self.roll_back_ip_pools(mikrotik_client, use_https = False)
@@ -909,6 +1429,20 @@ class MikroTikPPPoE1000Controller(MikroTikController):
all_messages.append(step_response.message) all_messages.append(step_response.message)
keep_going = step_response.success keep_going = step_response.success
# Next, we create the PPPoE Profiles:
if keep_going:
await asyncio.sleep(0.25)
step_response = await self.set_up_ppp_profiles(mikrotik_client, mikrotik_auth, use_https = False)
all_messages.append(step_response.message)
keep_going = step_response.success
# Next, we create the PPPoE Servers:
if keep_going:
await asyncio.sleep(0.25)
step_response = await self.set_up_ppp_servers(mikrotik_client, mikrotik_auth, use_https = False)
all_messages.append(step_response.message)
keep_going = step_response.success
# Done here: # Done here:
config_response.success = keep_going config_response.success = keep_going
config_response.message = " -> ".join(all_messages) config_response.message = " -> ".join(all_messages)
File diff suppressed because it is too large Load Diff