"small changes"
- remove http only in login.html - extract PeeringManager into separate file - add "progress meter" for "used" to "available" peerings
This commit is contained in:
parent
d6509ef6fe
commit
1fda3c11a4
8 changed files with 307 additions and 166 deletions
19
.vscode/launch.json
vendored
19
.vscode/launch.json
vendored
|
@ -1,5 +1,16 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Python: Flask-backend",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"module": "flask",
|
||||
"cwd": "${workspaceFolder}/web/",
|
||||
"env": { "FLASK_APP": "backend/main.py", "FLASK_DEBUG": "1", "FLASK_RUN_HOST": "0.0.0.0", "FLASK_RUN_PORT": "8042" },
|
||||
"args": ["run", "--no-debugger"],
|
||||
"jinja": true,
|
||||
"justMyCode": true
|
||||
},
|
||||
{
|
||||
"name": "Python: Current File",
|
||||
"type": "python",
|
||||
|
@ -8,6 +19,14 @@
|
|||
"cwd": "${workspaceFolder}/web/",
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": true
|
||||
},
|
||||
{
|
||||
"name": "Python: backend",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "backend/main.py",
|
||||
"cwd": "${workspaceFolder}/web/",
|
||||
"justMyCode": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
"ASN": "424242000", //Your ASN (used to generate default peer ListenPorts)
|
||||
"listen": "0.0.0.0",
|
||||
"port": 8042,
|
||||
"domain": "example.org", // domain to use for kioubit verification service
|
||||
"domain": "example.org", // domain to use for kioubit verification service (with protocol)
|
||||
"base-dir": "/", //optional:directury for which it is reachable (if behind some sort of reverse proxy) default "/"
|
||||
"peerings": "/path/to/peering-config.json", // optional; default "$PWD/peerings", directory to save existing peerings to
|
||||
"production": true, //optional, default true;
|
|
@ -10,6 +10,7 @@ import random
|
|||
from functools import wraps
|
||||
from ipaddress import ip_address, ip_network, IPv4Network, IPv6Network
|
||||
import kioubit_verify
|
||||
from peering_manager import PeeringManager
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
@ -22,7 +23,7 @@ class Config (dict):
|
|||
if os.path.exists("./config.json"):
|
||||
self.configfile = "./config.json"
|
||||
elif os.path.exists("/etc/dn42-autopeer/config.json"):
|
||||
self.configfile = "/etc/dn42-autopeer/config,json"
|
||||
self.configfile = "/etc/dn42-autopeer/config.json"
|
||||
else:
|
||||
raise FileNotFoundError(
|
||||
"no config file found in ./config.json or /etc/dn42-autopeer/config.json")
|
||||
|
@ -58,152 +59,19 @@ class Config (dict):
|
|||
|
||||
if not "peerings-data" in self._config:
|
||||
self._config["peering-data"] = "./peerings"
|
||||
|
||||
if not "nodes" in self._config:
|
||||
self,_config = {}
|
||||
for node in self._config["nodes"]:
|
||||
if not "capacity" in self._config["nodes"][node]:
|
||||
self._config["nodes"][node]["capacity"] = -1
|
||||
|
||||
logging.info(self._config)
|
||||
|
||||
|
||||
class PeeringManager:
|
||||
|
||||
def __init__(self, peerings_file):
|
||||
self._peering_file = peerings_file
|
||||
|
||||
self._load_peerings()
|
||||
|
||||
def _load_peerings(self):
|
||||
if not os.path.exists(self._peering_file):
|
||||
with open(self._peering_file, "x") as p:
|
||||
json.dump({"mnter": {}, "asn": {}}, p)
|
||||
try:
|
||||
with open(self._peering_file, "r") as p:
|
||||
self.peerings = json.load(p)
|
||||
except json.decoder.JSONDecodeError:
|
||||
with open(self._peering_file, "w") as p:
|
||||
json.dump({"mnter": {}, "asn": {}}, p)
|
||||
with open(self._peering_file, "r") as p:
|
||||
self.peerings = json.load(p)
|
||||
|
||||
# self.peerings = {}
|
||||
# missing_peerings = False
|
||||
# for peering in self._peerings:
|
||||
# if os.path.exists(f"{self._peering_dir}/{peering}.json"):
|
||||
# with open(f"{self._peering_dir}/{peering}.json") as peer_cfg:
|
||||
# self.peerings[peering] = json.load(peer_cfg)
|
||||
# else:
|
||||
# logging.warning(f"peering with id {peering} doesn't exist. removing reference in `{self._peering_dir}/peerings.json`")
|
||||
# self._peerings.remove(peering)
|
||||
# missing_peerings = True
|
||||
# if missing_peerings:
|
||||
# with open(f"{self._peering_dir}/peerings.json","w") as p:
|
||||
# json.dump(self._peerings, p, indent=4)
|
||||
def _save_peerings(self):
|
||||
with open(self._peering_file, "w") as p:
|
||||
json.dump(self.peerings, p, indent=4)
|
||||
|
||||
def _update_nodes(mode, peering, new_peering=None):
|
||||
"""mode: "add","update","delete
|
||||
peering: peering to send to node (included in peering)
|
||||
new_peering: if mode=="update" the new peering to update to
|
||||
"""
|
||||
pass
|
||||
|
||||
def exists(self, asn, node, mnt=None, wg_key=None, endpoint=None, ipv6ll=None, ipv4=None, ipv6=None, bgp_mp=True, bgp_enh=True):
|
||||
"""checks if a peerings with specific data already exists"""
|
||||
# check if mnt is specified, already exists in the database and if that mnt has the specified ASn -> if not: return False
|
||||
if mnt and not (mnt in self.peerings["mnter"] and asn in self.peerings["mnter"][mnt]):
|
||||
return False
|
||||
selected_peerings = self.peerings["asn"][asn]
|
||||
# check if the ASn even has peerings
|
||||
if len(selected_peerings) == 0:
|
||||
return False
|
||||
for p in selected_peerings:
|
||||
if p["node"] == node:
|
||||
if (not wg_key or p["wg_key"] == wg_key) and (not endpoint or p["endpoint"] == endpoint) \
|
||||
and (not ipv6ll or p["ipv6ll"] == ipv6ll) and (not ipv4 or p["ipv4"] == ipv4) and (not ipv6 or p["ipv6"] == ipv6)\
|
||||
and (not bgp_mp or p["bgp_mp"] == bgp_mp) and (not bgp_enh or p["bgp_enh"] == bgp_enh):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_peerings_by_mnt(self, mnt):
|
||||
# print(self.peerings)
|
||||
try:
|
||||
out = []
|
||||
for asn in self.peerings["mnter"][mnt]:
|
||||
try:
|
||||
for peering in self.peerings["asn"][asn]:
|
||||
out.append(peering)
|
||||
except KeyError as e:
|
||||
pass
|
||||
return out
|
||||
except KeyError:
|
||||
return {}
|
||||
|
||||
def add_peering(self, asn, node, mnt, wg_key, endpoint=None, ipv6ll=None, ipv4=None, ipv6=None, bgp_mp=True, bgp_enh=True):
|
||||
# check if this MNT already has a/this asn
|
||||
try:
|
||||
if not asn in self.peerings["mnter"][mnt]:
|
||||
# ... and add it if it hasn't
|
||||
self.peerings[mnt].append(asn)
|
||||
except KeyError:
|
||||
# ... and cerate it if it doesn't have any yet
|
||||
self.peerings["mnter"][mnt] = [asn]
|
||||
try:
|
||||
if not asn in self.peerings["asn"]:
|
||||
self.peerings["asn"][asn] = []
|
||||
except KeyError:
|
||||
self.peerings["asn"][asn] = []
|
||||
|
||||
# deny more than one peering per ASN to one node
|
||||
for peering in self.peerings["asn"][asn]:
|
||||
if peering["node"] == node:
|
||||
return False
|
||||
|
||||
self.peerings["asn"][asn].append({"MNT": mnt, "ASN": asn, "node": node, "wg_key": wg_key, "endpoint": endpoint,
|
||||
"ipv6ll": ipv6ll, "ipv4": ipv4, "ipv6": ipv6, "bgp_mp": bgp_mp, "bgp_enh": bgp_enh})
|
||||
|
||||
self._save_peerings()
|
||||
return True
|
||||
|
||||
def update_peering(self, asn, node, mnt, wg_key, endpoint=None, ipv6ll=None, ipv4=None, ipv6=None, bgp_mp=True, bgp_enh=True):
|
||||
# check if this MNT already has a/this asn
|
||||
try:
|
||||
if not asn in self.peerings["mnter"][mnt]:
|
||||
# ... and add it if it hasn't
|
||||
self.peerings[mnt].append(asn)
|
||||
except KeyError:
|
||||
# ... and cerate it if it doesn't have any yet
|
||||
self.peerings["mnter"][mnt] = [asn]
|
||||
try:
|
||||
if not asn in self.peerings["asn"]:
|
||||
return False
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
success = False
|
||||
for pNr in range(len(self.peerings["asn"][asn])):
|
||||
if self.peerings["asn"][asn][pNr]["node"] == node:
|
||||
self.peerings["asn"][asn][pNr] = {"MNT": mnt, "ASN": asn, "node": node, "wg_key": wg_key,
|
||||
"endpoint": endpoint, "ipv6ll": ipv6ll, "ipv4": ipv4, "ipv6": ipv6, "bgp_mp": bgp_mp, "bgp_enh": bgp_enh}
|
||||
success = True
|
||||
if not success:
|
||||
return False
|
||||
self._save_peerings()
|
||||
return True
|
||||
|
||||
def delete_peering(self, asn, node, mnt, wg_key=None):
|
||||
if not self.exists(asn, node, mnt=mnt, wg_key=wg_key):
|
||||
return False
|
||||
for p in self.peerings["asn"][asn]:
|
||||
if p["node"] == node:
|
||||
if wg_key and p["wg_key"] != wg_key:
|
||||
continue
|
||||
self.peerings["asn"][asn].remove(p)
|
||||
self._save_peerings()
|
||||
return True
|
||||
# if nothing got found (should have been catched by self.exists)
|
||||
return False
|
||||
|
||||
|
||||
config = Config()
|
||||
peerings = PeeringManager(config["peerings"])
|
||||
peerings = PeeringManager(config)
|
||||
kverifyer = kioubit_verify.AuthVerifyer(config["domain"])
|
||||
|
||||
|
||||
|
@ -241,9 +109,9 @@ def check_peering_data(form):
|
|||
else:
|
||||
new_peering["peer-v6"] = None
|
||||
new_peering["bgp-mp"] = form["bgp-multi-protocol"] if "bgp-multi-protocol" in form else "off"
|
||||
new_peering["bgp-mp"] = True if new_peering["bgp-mp"] else False
|
||||
new_peering["bgp-mp"] = True if new_peering["bgp-mp"] == "on" else False
|
||||
new_peering["bgp-enh"] = form["bgp-extended-next-hop"] if "bgp-extended-next-hop" in form else "off"
|
||||
new_peering["bgp-enh"] = True if new_peering["bgp-enh"] else False
|
||||
new_peering["bgp-enh"] = True if new_peering["bgp-enh"] == "on" else False
|
||||
#new_peering[""] = form["peer-wgkey"]
|
||||
except ValueError as e:
|
||||
print(f"error: {e.args}")
|
||||
|
@ -322,13 +190,13 @@ def check_peering_data(form):
|
|||
|
||||
# check bgp options
|
||||
try:
|
||||
if new_peering["bgp-mp"] == "off" and new_peering["bgp-enh"] == "on":
|
||||
if new_peering["bgp-mp"] == False and new_peering["bgp-enh"] == True:
|
||||
return False, "extended next hop requires multiprotocol bgp"
|
||||
if new_peering["bgp-mp"] == "off":
|
||||
if new_peering["bgp-mp"] == False:
|
||||
if not (new_peering["peer-v4"] and (new_peering["peer-v6"] or new_peering["peer-v6ll"])):
|
||||
return False, "ipv4 and ipv6 addresses required when not having MP-BGP"
|
||||
except ValueError:
|
||||
...
|
||||
pass
|
||||
return True, new_peering
|
||||
|
||||
|
||||
|
@ -537,13 +405,13 @@ def index():
|
|||
# print(config._config["nodes"])
|
||||
# for node in config["nodes"].values():
|
||||
# print (node)
|
||||
return render_template("index.html", session=session, config=config._config)
|
||||
return render_template("index.html", session=session, config=config, peerings = peerings)
|
||||
|
||||
|
||||
app.static_folder = config["flask-template-dir"]+"/static/"
|
||||
app.template_folder = config["flask-template-dir"]
|
||||
app.secret_key = config["flask-secret-key"]
|
||||
def main():
|
||||
app.static_folder = config["flask-template-dir"]+"/static/"
|
||||
app.template_folder = config["flask-template-dir"]
|
||||
app.secret_key = config["flask-secret-key"]
|
||||
if "production" in config and config["production"] == False:
|
||||
logging.getLogger(__name__).setLevel(0)
|
||||
app.run(host=config["listen"], port=config["port"],
|
||||
|
|
176
web/backend/peering_manager.py
Normal file
176
web/backend/peering_manager.py
Normal file
|
@ -0,0 +1,176 @@
|
|||
import json
|
||||
import os
|
||||
import base64
|
||||
import logging
|
||||
import random
|
||||
|
||||
class NodeCommunicator:
|
||||
|
||||
def __init__(self, name:str, config):
|
||||
self.name = name
|
||||
self.__config = config
|
||||
self.__api_addr = config["api-con"]
|
||||
|
||||
class PeeringManager:
|
||||
|
||||
def __init__(self, config):
|
||||
self.__config = config
|
||||
self.__peering_file = config["peerings"]
|
||||
|
||||
self.__load_peerings()
|
||||
|
||||
self._nodes = {}
|
||||
for node in self.__config["nodes"]:
|
||||
self._nodes[node] = NodeCommunicator(name=node, config=self.__config["nodes"][node])
|
||||
|
||||
self._amounts = None
|
||||
|
||||
def __load_peerings(self):
|
||||
if not os.path.exists(self.__peering_file):
|
||||
with open(self.__peering_file, "x") as p:
|
||||
json.dump({"mnter": {}, "asn": {}}, p)
|
||||
try:
|
||||
with open(self.__peering_file, "r") as p:
|
||||
self.peerings = json.load(p)
|
||||
except json.decoder.JSONDecodeError:
|
||||
with open(self.__peering_file, "w") as p:
|
||||
json.dump({"mnter": {}, "asn": {}}, p)
|
||||
with open(self.__peering_file, "r") as p:
|
||||
self.peerings = json.load(p)
|
||||
|
||||
# self.peerings = {}
|
||||
# missing_peerings = False
|
||||
# for peering in self._peerings:
|
||||
# if os.path.exists(f"{self._peering_dir}/{peering}.json"):
|
||||
# with open(f"{self._peering_dir}/{peering}.json") as peer_cfg:
|
||||
# self.peerings[peering] = json.load(peer_cfg)
|
||||
# else:
|
||||
# logging.warning(f"peering with id {peering} doesn't exist. removing reference in `{self._peering_dir}/peerings.json`")
|
||||
# self._peerings.remove(peering)
|
||||
# missing_peerings = True
|
||||
# if missing_peerings:
|
||||
# with open(f"{self._peering_dir}/peerings.json","w") as p:
|
||||
# json.dump(self._peerings, p, indent=4)
|
||||
def _save_peerings(self):
|
||||
with open(self.__peering_file, "w") as p:
|
||||
json.dump(self.peerings, p, indent=4)
|
||||
self._amounts = None
|
||||
|
||||
def _update_nodes(self, mode, peering, new_peering=None):
|
||||
"""mode: "add","update","delete
|
||||
peering: peering to send to node (included in peering)
|
||||
new_peering: if mode=="update" the new peering to update to
|
||||
"""
|
||||
pass
|
||||
def _update_amounts(self):
|
||||
__new = {}
|
||||
for asn in self.peerings["asn"]:
|
||||
for peering in self.peerings["asn"][asn]:
|
||||
if not peering["node"] in __new:
|
||||
__new[peering["node"]] = 0
|
||||
__new[peering["node"]] += 1
|
||||
self._amounts = __new
|
||||
|
||||
|
||||
def amount_by_node(self, node_name: str):
|
||||
if self._amounts ==None:
|
||||
self._update_amounts()
|
||||
try:
|
||||
return self._amounts[node_name]
|
||||
except KeyError:
|
||||
return 0
|
||||
def exists(self, asn, node, mnt=None, wg_key=None, endpoint=None, ipv6ll=None, ipv4=None, ipv6=None, bgp_mp=True, bgp_enh=True):
|
||||
"""checks if a peerings with specific data already exists"""
|
||||
# check if mnt is specified, already exists in the database and if that mnt has the specified ASn -> if not: return False
|
||||
if mnt and not (mnt in self.peerings["mnter"] and asn in self.peerings["mnter"][mnt]):
|
||||
return False
|
||||
selected_peerings = self.peerings["asn"][asn]
|
||||
# check if the ASn even has peerings
|
||||
if len(selected_peerings) == 0:
|
||||
return False
|
||||
for p in selected_peerings:
|
||||
if p["node"] == node:
|
||||
if (not wg_key or p["wg_key"] == wg_key) and (not endpoint or p["endpoint"] == endpoint) \
|
||||
and (not ipv6ll or p["ipv6ll"] == ipv6ll) and (not ipv4 or p["ipv4"] == ipv4) and (not ipv6 or p["ipv6"] == ipv6)\
|
||||
and (not bgp_mp or p["bgp_mp"] == bgp_mp) and (not bgp_enh or p["bgp_enh"] == bgp_enh):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_peerings_by_mnt(self, mnt):
|
||||
# print(self.peerings)
|
||||
try:
|
||||
out = []
|
||||
for asn in self.peerings["mnter"][mnt]:
|
||||
try:
|
||||
for peering in self.peerings["asn"][asn]:
|
||||
out.append(peering)
|
||||
except KeyError as e:
|
||||
pass
|
||||
return out
|
||||
except KeyError:
|
||||
return {}
|
||||
|
||||
def add_peering(self, asn, node, mnt, wg_key, endpoint=None, ipv6ll=None, ipv4=None, ipv6=None, bgp_mp=True, bgp_enh=True):
|
||||
# check if this MNT already has a/this asn
|
||||
try:
|
||||
if not asn in self.peerings["mnter"][mnt]:
|
||||
# ... and add it if it hasn't
|
||||
self.peerings[mnt].append(asn)
|
||||
except KeyError:
|
||||
# ... and cerate it if it doesn't have any yet
|
||||
self.peerings["mnter"][mnt] = [asn]
|
||||
try:
|
||||
if not asn in self.peerings["asn"]:
|
||||
self.peerings["asn"][asn] = []
|
||||
except KeyError:
|
||||
self.peerings["asn"][asn] = []
|
||||
|
||||
# deny more than one peering per ASN to one node
|
||||
for peering in self.peerings["asn"][asn]:
|
||||
if peering["node"] == node:
|
||||
return False
|
||||
|
||||
self.peerings["asn"][asn].append({"MNT": mnt, "ASN": asn, "node": node, "wg_key": wg_key, "endpoint": endpoint,
|
||||
"ipv6ll": ipv6ll, "ipv4": ipv4, "ipv6": ipv6, "bgp_mp": bgp_mp, "bgp_enh": bgp_enh})
|
||||
|
||||
self._save_peerings()
|
||||
return True
|
||||
|
||||
def update_peering(self, asn, node, mnt, wg_key, endpoint=None, ipv6ll=None, ipv4=None, ipv6=None, bgp_mp=True, bgp_enh=True):
|
||||
# check if this MNT already has a/this asn
|
||||
try:
|
||||
if not asn in self.peerings["mnter"][mnt]:
|
||||
# ... and add it if it hasn't
|
||||
self.peerings[mnt].append(asn)
|
||||
except KeyError:
|
||||
# ... and cerate it if it doesn't have any yet
|
||||
self.peerings["mnter"][mnt] = [asn]
|
||||
try:
|
||||
if not asn in self.peerings["asn"]:
|
||||
return False
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
success = False
|
||||
for pNr in range(len(self.peerings["asn"][asn])):
|
||||
if self.peerings["asn"][asn][pNr]["node"] == node:
|
||||
self.peerings["asn"][asn][pNr] = {"MNT": mnt, "ASN": asn, "node": node, "wg_key": wg_key,
|
||||
"endpoint": endpoint, "ipv6ll": ipv6ll, "ipv4": ipv4, "ipv6": ipv6, "bgp_mp": bgp_mp, "bgp_enh": bgp_enh}
|
||||
success = True
|
||||
if not success:
|
||||
return False
|
||||
self._save_peerings()
|
||||
return True
|
||||
|
||||
def delete_peering(self, asn, node, mnt, wg_key=None):
|
||||
if not self.exists(asn, node, mnt=mnt, wg_key=wg_key):
|
||||
return False
|
||||
for p in self.peerings["asn"][asn]:
|
||||
if p["node"] == node:
|
||||
if wg_key and p["wg_key"] != wg_key:
|
||||
continue
|
||||
self.peerings["asn"][asn].remove(p)
|
||||
self._save_peerings()
|
||||
return True
|
||||
# if nothing got found (should have been catched by self.exists)
|
||||
return False
|
|
@ -16,7 +16,17 @@
|
|||
<td>{{node}}</td>
|
||||
<td>{{config["nodes"][node]["country"]}}</td>
|
||||
<td>{{config["nodes"][node]["city"]}}</td>
|
||||
<td></td>
|
||||
<td>
|
||||
{% set peerings_percentage =
|
||||
(peerings.amount_by_node(node)/config['nodes'][node]['capacity']*100) %}
|
||||
<div class="progress progress-bar" title="{{peerings.amount_by_node(node)}}/{{config['nodes'][node]['capacity']}}">
|
||||
<div
|
||||
class="progress progress-value"
|
||||
style="width:'{{peerings_percentage}}px'; background-color: {% if (peerings_percentage<80) %}green{% elif (peerings_percentage < 90) %}orange{%else%}red{%endif%};"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td><a href="peerings/new?node={{node}}">peer</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
type="hidden"
|
||||
id="return"
|
||||
name="return"
|
||||
value='{{"http://"+config["domain"]+"/api/auth/kverify"}}'
|
||||
value='{{config["domain"]+"/api/auth/kverify"}}'
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
|
|
|
@ -214,13 +214,13 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td><label for="peer-v4">your ipv4</label></td>
|
||||
<td><input type="checkbox" name="peer-v4-enabled" id="peer-v4-enabled"onchange="return update_from_v4()" {% if selected_peering["ipv4"] %} checked {% endif %}></td>
|
||||
<td><input type="text" name="peer-v4" id="peer-v4"onchange="return update_from_v4()" {% if selected_peering["ipv4"] %}value="{{selected_peering['ipv4']}}" {% endif %}></td>
|
||||
<td><input type="checkbox" name="peer-v4-enabled" id="peer-v4-enabled" onchange="return update_from_v4()" {% if selected_peering["ipv4"] %} checked {% endif %}></td>
|
||||
<td><input type="text" name="peer-v4" id="peer-v4" onchange="return update_from_v4()" {% if selected_peering["ipv4"] %}value="{{selected_peering['ipv4']}}" {% endif %}></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="peer-v6">your ipv6</label></td>
|
||||
<td><input type="checkbox" name="peer-v6-enabled" id="peer-v6-enabled"onchange="return update_from_v6()"{% if selected_peering["ipv6"] %} checked {% endif %}></td>
|
||||
<td><input type="text" name="peer-v6" id="peer-v6"onchange="return update_from_v6()" {% if selected_peering["ipv6"] %}value="{{selected_peering['ipv6']}}" {% endif %}></td>
|
||||
<td><input type="checkbox" name="peer-v6-enabled" id="peer-v6-enabled" onchange="return update_from_v6()"{% if selected_peering["ipv6"] %} checked {% endif %}></td>
|
||||
<td><input type="text" name="peer-v6" id="peer-v6" onchange="return update_from_v6()" {% if selected_peering["ipv6"] %}value="{{selected_peering['ipv6']}}" {% endif %}></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><h4>BGP</h4></td>
|
||||
|
@ -228,13 +228,13 @@
|
|||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MultiProtocol</td>
|
||||
<td><input type="checkbox" name="bgp-multi-protocol" id="bgp-multi-protocol" onchange="return update_from_mpbgp()" {% if selected_peering["bgp-mp"] %} checked {% endif %}></td>
|
||||
<td><label for="bgp-multi-protocol">MultiProtocol</label></td>
|
||||
<td><input type="checkbox" name="bgp-multi-protocol" id="bgp-multi-protocol" onchange="return update_from_mpbgp()" {% if selected_peering["bgp_mp"] == True %} checked {% endif %}></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>extended next hop</td>
|
||||
<td><input type="checkbox" name="bgp-extended-next-hop" id="bgp-extended-next-hop" onchange="return update_from_enh()" {% if selected_peering["bgp-enh"] %} checked {% endif %}></td>
|
||||
<td><label for="bgp-extended-next-hop">extended next hop</label></td>
|
||||
<td><input type="checkbox" name="bgp-extended-next-hop" id="bgp-extended-next-hop" onchange="return update_from_enh()" {% if selected_peering["bgp_enh"] == True%} checked {% endif %}></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -62,6 +62,72 @@ footer.flex {
|
|||
flex-direction: row;
|
||||
}
|
||||
|
||||
/* # index.html */
|
||||
|
||||
/* based on https://codepen.io/t_afif/pen/RwQZLYb */
|
||||
.progress-bar {
|
||||
--w: 100px; /* the width*/
|
||||
|
||||
--background: lightgrey; /* the background color */
|
||||
width: var(--w);
|
||||
margin: 0 10px;
|
||||
}
|
||||
.progress {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
border: none;
|
||||
height: 10px;
|
||||
border-radius: 10em;
|
||||
background: var(--background);
|
||||
}
|
||||
|
||||
.progress-value[value]{
|
||||
--color: /* the progress color */
|
||||
/* linear-gradient(#fff8,#fff0), */
|
||||
/* repeating-linear-gradient(135deg,#0003 0 10px,#0000 0 20px), */
|
||||
/* if < 30% "red" */
|
||||
linear-gradient(green 0 0) 0 /calc(var(--w)*.8 - 100%) 1px,
|
||||
/* if < 60% "orange" */
|
||||
linear-gradient(orange 0 0) 0 /calc(var(--w)*.9 - 100%) 1px,
|
||||
/* else "green" */
|
||||
red;
|
||||
background-color: var(--color);
|
||||
align-self: left;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.progress[value]::-webkit-progress-bar {
|
||||
border-radius: 10em;
|
||||
background: var(--background);
|
||||
}
|
||||
|
||||
.progress[value]::-webkit-progress-value {
|
||||
border-radius: 10em;
|
||||
background: var(--color);
|
||||
}
|
||||
.progress[value]::-moz-progress-bar {
|
||||
border-radius: 10em;
|
||||
background-color: var(--color);
|
||||
}
|
||||
|
||||
/* .progress:before { */
|
||||
/* position:absolute; */
|
||||
/* height:30px; */
|
||||
/* background:green; */
|
||||
/* content:'50%'; hrere you should add the text */
|
||||
/* top:0; */
|
||||
/* left:0; */
|
||||
/* width:50%; */
|
||||
/* display:flex; */
|
||||
/* color:white; */
|
||||
/* align-items:center; */
|
||||
/* justify-content:flex-end; */
|
||||
/* padding-right:10px; */
|
||||
/* } */
|
||||
|
||||
|
||||
/* for peerings-{edit,new}.html */
|
||||
.example-config {
|
||||
background-color: white;
|
||||
padding: 1%;
|
||||
|
@ -78,6 +144,7 @@ form>div>* {
|
|||
margin: 10px;
|
||||
}
|
||||
|
||||
/* for peerings.html */
|
||||
.peering {
|
||||
border-color: var(--other-background);
|
||||
border-radius: 10px;
|
||||
|
@ -99,6 +166,11 @@ form>div>* {
|
|||
padding: 10px;
|
||||
}
|
||||
|
||||
.peering>* {
|
||||
width: auto;
|
||||
align-items: center;
|
||||
}
|
||||
/* button def */
|
||||
button,
|
||||
input[type=button] {
|
||||
background-color: #00000020;
|
||||
|
@ -113,10 +185,6 @@ input[type=button].button-selected {
|
|||
color: var(--text-color-dark);
|
||||
}
|
||||
|
||||
.peering>* {
|
||||
width: auto;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.button-blue {
|
||||
border-color: lightblue;
|
||||
|
|
Loading…
Add table
Reference in a new issue