-
Notifications
You must be signed in to change notification settings - Fork 0
/
data.py
159 lines (122 loc) · 4.13 KB
/
data.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import json
from dataclasses import dataclass
from dataclasses import dataclass
from ipaddress import IPv4Address
from typing import List, Union
import yaml
from gns3fy import Node
from jsonschema import validate
@dataclass
class Router:
name: str
x: int
y: int
uid: str
router_id: str
asn: int
console_host: str
console_port: int
# type: List[Interface]
interfaces: list
@staticmethod
def from_node(node: Node, ri, asn):
return Router(name=node.name,
x=node.x, y=node.y, uid=node.node_id,
console_host=node.console_host, console_port=node.console,
router_id=ri, interfaces=[], asn=asn)
class Routers(dict):
# type: List[Router]
def get_by_uid(self, uid: str) -> Router:
for router in self.values():
if router.uid == uid:
return router
def add(self, router: Router):
self[router.name] = router
def __getitem__(self, item) -> Router:
return super().__getitem__(item)
@dataclass
class Lien:
uid: str
network4: IPv4Address # 10.2.0
network6: str # 2201:beef
side_a: Router
side_b: Router
int_a: str
int_b: str
network4_display: str = "10/8"
@property
def interface_a(self):
# type: () -> Interface
return list(filter(lambda i: i.name == self.int_a, self.side_a.interfaces))[0]
@property
def interface_b(self):
# type: () -> Interface
return list(filter(lambda i: i.name == self.int_b, self.side_b.interfaces))[0]
def __str__(self):
return f"({self.side_a.name}) {self.int_a} <--> {self.int_b} ({self.side_b.name})"
@property
def name(self):
return f"{self.side_a.name}<-->{self.side_b.name}"
SIDE_A = 'a'
SIDE_B = 'b'
@dataclass
class Interface:
name: str
lien: Union[Lien, None] = None # si None, le lien n'est pas branché à un routeur
side: str = 'u' # 'a' ou 'b' ou 'u' si lien==None
@property
def peer(self) -> Router:
if self.lien is not None:
if self.side == 'a':
return self.lien.side_b
elif self.side == 'b':
return self.lien.side_a
return None
@property
def peer_int(self) -> str:
if self.lien is not None:
if self.side == 'a':
return self.lien.int_b
elif self.side == 'b':
return self.lien.int_a
return None
@property
def peer_interface(self):
# type: () -> Interface
if self.lien is not None:
if self.side == 'a':
return self.lien.interface_b
elif self.side == 'b':
return self.lien.interface_a
return None
@property
def router(self) -> Router:
if self.lien is not None:
if self.side == 'b':
return self.lien.side_b
elif self.side == 'a':
return self.lien.side_a
return None
def __str__(self):
if self.lien is not None:
return str(self.lien)
return self.name
def get_ip6(self):
return f"{self.lien.network6}::{ord(self.side) - 96}"
def get_ip_end(self) -> int:
# 1 pour side_a, 2 pour side_b
return ord(self.side) - 96
def get_ip4(self):
# on fait de la magie avec les IPv4 pour utiliser des sous-réseaux de 2 hôtes
return f"{IPv4Address(int(self.lien.network4) + ord(self.side) - 96)}"
# https://stackoverflow.com/questions/8640959/how-can-i-control-what-scalar-form-pyyaml-uses-for-my-data
def str_presenter(dumper, data):
if len(data.splitlines()) > 1: # check for multiline string
return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|')
return dumper.represent_scalar('tag:yaml.org,2002:str', data)
yaml.add_representer(str, str_presenter)
def load_user_conf(filename='user_conf.yaml') -> dict:
user_conf = yaml.load(open(filename, 'r'), Loader=yaml.FullLoader)
user_conf_schema = json.load(open('user-conf-schema.json', 'r'))
validate(instance=user_conf, schema=user_conf_schema)
return user_conf