Initial commit
This commit is contained in:
parent
fabf0319db
commit
7c4ad5104c
4 changed files with 181 additions and 0 deletions
41
api/__init__.py
Normal file
41
api/__init__.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
import requests
|
||||
import enum
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
class ApiAuthType(enum.Enum):
|
||||
NoAuth = 0
|
||||
Header = 1
|
||||
Cookie = 2
|
||||
|
||||
|
||||
class Api(object):
|
||||
base_url: str = None
|
||||
|
||||
def transform(self, data):
|
||||
return data
|
||||
|
||||
def apply_authentication(self) -> Tuple[ApiAuthType, dict]:
|
||||
raise NotImplementedError
|
||||
|
||||
def _get(self, endpoint, raw: bool = False):
|
||||
|
||||
url = self.base_url + endpoint
|
||||
|
||||
headers = {
|
||||
"Accept": "application/json"
|
||||
}
|
||||
|
||||
cookies = {}
|
||||
|
||||
ty, auth = self.apply_authentication()
|
||||
if ty == ApiAuthType.Header:
|
||||
headers.update(auth)
|
||||
elif ty == ApiAuthType.Cookie:
|
||||
cookies.update(auth)
|
||||
|
||||
response = requests.get(url, headers=headers, cookies=cookies)
|
||||
if raw:
|
||||
return response
|
||||
|
||||
return self.transform(response.json())
|
32
api/pelican.py
Normal file
32
api/pelican.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
from api import Api, ApiAuthType
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
class PelicanApi(Api):
|
||||
def __init__(self, base_url, auth_token):
|
||||
self.base_url = base_url
|
||||
self.auth_token = auth_token
|
||||
|
||||
def apply_authentication(self) -> Tuple[ApiAuthType, dict]:
|
||||
return ApiAuthType.Header, {
|
||||
"Authorization": "Bearer " + self.auth_token
|
||||
}
|
||||
|
||||
def transform(self, data):
|
||||
type = data["object"]
|
||||
if type == "list":
|
||||
return [self.transform(x) for x in data["data"]]
|
||||
|
||||
if type in ["allocation", "server", "node"]:
|
||||
return data["attributes"]
|
||||
|
||||
return data
|
||||
|
||||
def nodes(self):
|
||||
return self._get("/application/nodes")
|
||||
|
||||
def servers(self):
|
||||
return self._get("/application/servers")
|
||||
|
||||
def allocations(self, node_id: int):
|
||||
return self._get("/application/nodes/" + str(node_id) + "/allocations")
|
104
main.py
Normal file
104
main.py
Normal file
|
@ -0,0 +1,104 @@
|
|||
import os
|
||||
|
||||
import aiohttp
|
||||
import asyncio
|
||||
import socket
|
||||
|
||||
import configparser
|
||||
|
||||
cfg = configparser.ConfigParser()
|
||||
|
||||
import asusrouter.modules.port_forwarding
|
||||
from asusrouter import AsusRouter, AsusData
|
||||
from api.pelican import PelicanApi
|
||||
from flask import Flask, request
|
||||
|
||||
RULE_PREFIX = "[auto]::"
|
||||
|
||||
|
||||
def create_rule(label, address, port):
|
||||
return asusrouter.modules.port_forwarding.PortForwardingRule(RULE_PREFIX + label, address, None, "BOTH", None, port)
|
||||
|
||||
|
||||
def rule_to_string(rule: asusrouter.modules.port_forwarding.PortForwardingRule):
|
||||
return f"{rule.name}::{rule.port_external}->{rule.port if rule.port else rule.port_external}@{rule.ip_address}"
|
||||
|
||||
|
||||
def apply_port_changes():
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
session = aiohttp.ClientSession(loop=loop)
|
||||
|
||||
pelican_cfg = cfg["pelican"]
|
||||
router_cfg = cfg["router"]
|
||||
pelican = PelicanApi(pelican_cfg["baseurl"], pelican_cfg["auth"])
|
||||
router = AsusRouter(
|
||||
hostname=router_cfg["hostname"],
|
||||
username=router_cfg["username"],
|
||||
password=router_cfg["password"],
|
||||
use_ssl=False,
|
||||
session=session
|
||||
)
|
||||
|
||||
run = loop.run_until_complete
|
||||
|
||||
run(router.async_connect())
|
||||
|
||||
data = run(router.async_get_data(AsusData.PORT_FORWARDING))
|
||||
rules = data["rules"]
|
||||
x: asusrouter.modules.port_forwarding.PortForwardingRule
|
||||
# Remove auto-generated rules
|
||||
rules = [x for x in rules if not x.name.startswith(RULE_PREFIX)]
|
||||
|
||||
# Add new auto-generated rules
|
||||
allocation_server_lookup = {}
|
||||
for server in pelican.servers():
|
||||
allocation_server_lookup[server["allocation"]] = server
|
||||
|
||||
for node in pelican.nodes():
|
||||
node_id = node["id"]
|
||||
allocs = pelican.allocations(node_id)
|
||||
|
||||
node_internal_name = node["name"] + ".pve.local"
|
||||
node_internal_ip = socket.getaddrinfo(node_internal_name, 0)[0][4][0]
|
||||
|
||||
for alloc in allocs:
|
||||
if not alloc["assigned"]:
|
||||
continue
|
||||
|
||||
label = "Allocation " + str(alloc["id"]) + " for " + node_internal_name
|
||||
if alloc["id"] in allocation_server_lookup.keys():
|
||||
svr = allocation_server_lookup[alloc["id"]]
|
||||
label = svr["name"] + "(" + svr["identifier"] + ") allocation"
|
||||
|
||||
rules.append(create_rule(label, node_internal_ip, alloc["port"]))
|
||||
|
||||
run(router.async_apply_port_forwarding_rules(rules))
|
||||
|
||||
print("Currently open ports: ")
|
||||
for rule in rules:
|
||||
print("\t" + rule_to_string(rule))
|
||||
|
||||
run(router.async_disconnect())
|
||||
run(session.close())
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@app.route("/pelican-wh", methods=["GET", "POST"])
|
||||
def start():
|
||||
apply_port_changes()
|
||||
return "Hello, world!"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if os.path.exists("/config/config.ini"):
|
||||
cfg.read("/config/config.ini")
|
||||
else:
|
||||
print("No config file detected, exiting...")
|
||||
exit(1)
|
||||
|
||||
port = int(cfg["app"]["port"])
|
||||
|
||||
app.run(host="0.0.0.0", port=port)
|
4
requirements.txt
Normal file
4
requirements.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
requests~=2.32.3
|
||||
aiohttp~=3.11.13
|
||||
asusrouter~=1.13.1
|
||||
Flask~=3.1.0
|
Loading…
Reference in a new issue