8d8a5d360ab628f9493f4d79ffd1dfc23a707f49
[osm/vim-emu.git] / src / emuvim / api / openstack / resources / net.py
1 import re
2
3
4 class Net:
5 def __init__(self, name):
6 self.name = name
7 self.id = None
8 self.subnet_name = None
9 self.subnet_id = None
10 self.subnet_creation_time = None
11 self.subnet_update_time = None
12 self.gateway_ip = None
13 self.segmentation_id = None # not set
14 self._cidr = None
15 self.start_end_dict = None
16 self._issued_ip_addresses = dict()
17
18 def get_short_id(self):
19 """
20 Returns a shortened UUID, with only the first 6 characters.
21
22 :return: First 6 characters of the UUID
23 :rtype: ``str``
24 """
25 return str(self.id)[:6]
26
27 def get_new_ip_address(self, port_name):
28 """
29 Calculates the next unused IP Address which belongs to the subnet.
30
31 :param port_name: Specifies the port.
32 :type port_name: ``str``
33 :return: Returns a unused IP Address or none if all are in use.
34 :rtype: ``str``
35 """
36 if self.start_end_dict is None:
37 return None
38
39 int_start_ip = Net.ip_2_int(self.start_end_dict['start']) + 2 # First address as network address not usable
40 # Second one is for gateways only
41 int_end_ip = Net.ip_2_int(self.start_end_dict['end']) - 1 # Last address for broadcasts
42 while int_start_ip in self._issued_ip_addresses and int_start_ip <= int_end_ip:
43 int_start_ip += 1
44
45 if int_start_ip > int_end_ip:
46 return None
47
48 self._issued_ip_addresses[int_start_ip] = port_name
49 return Net.int_2_ip(int_start_ip) + '/' + self._cidr.rsplit('/', 1)[1]
50
51 def assign_ip_address(self, cidr, port_name):
52 """
53 Assigns the IP address to the port if it is currently NOT used.
54
55 :param cidr: The cidr used by the port - e.g. 10.0.0.1/24
56 :type cidr: ``str``
57 :param port_name: The port name
58 :type port_name: ``str``
59 :return: * *False*: If the IP address is already issued or if it is not within this subnet mask.
60 * *True*: Else
61 """
62 int_ip = Net.cidr_2_int(cidr)
63 if int_ip in self._issued_ip_addresses:
64 return False
65
66 int_start_ip = Net.ip_2_int(self.start_end_dict['start']) + 1 # First address as network address not usable
67 int_end_ip = Net.ip_2_int(self.start_end_dict['end']) - 1 # Last address for broadcasts
68 if int_ip < int_start_ip or int_ip > int_end_ip:
69 return False
70
71 self._issued_ip_addresses[int_ip] = port_name
72 return True
73
74 def is_my_ip(self, cidr, port_name):
75 """
76 Checks if the IP is registered for this port name.
77
78 :param cidr: The cidr used by the port - e.g. 10.0.0.1/24
79 :type cidr: ``str``
80 :param port_name: The port name
81 :type port_name: ``str``
82 :return: Returns true if the IP address belongs to the port name. Else it returns false.
83 """
84 int_ip = Net.cidr_2_int(cidr)
85
86 if not int_ip in self._issued_ip_addresses:
87 return False
88
89 if self._issued_ip_addresses[int_ip] == port_name:
90 return True
91 return False
92
93 def withdraw_ip_address(self, ip_address):
94 """
95 Removes the IP address from the list of issued addresses, thus other ports can use it.
96
97 :param ip_address: The issued IP address.
98 :type ip_address: ``str``
99 """
100 if ip_address is None:
101 return
102
103 if "/" in ip_address:
104 address, suffix = ip_address.rsplit('/', 1)
105 else:
106 address = ip_address
107 int_ip_address = Net.ip_2_int(address)
108 if int_ip_address in self._issued_ip_addresses.keys():
109 del self._issued_ip_addresses[int_ip_address]
110
111 def reset_issued_ip_addresses(self):
112 """
113 Resets all issued IP addresses.
114 """
115 self._issued_ip_addresses = dict()
116
117 def update_port_name_for_ip_address(self, ip_address, port_name):
118 """
119 Updates the port name of the issued IP address.
120
121 :param ip_address: The already issued IP address.
122 :type ip_address: ``str``
123 :param port_name: The new port name
124 :type port_name: ``str``
125 """
126 address, suffix = ip_address.rsplit('/', 1)
127 int_ip_address = Net.ip_2_int(address)
128 self._issued_ip_addresses[int_ip_address] = port_name
129
130 def set_cidr(self, cidr):
131 """
132 Sets the CIDR for the subnet. It previously checks for the correct CIDR format.
133
134 :param cidr: The new CIDR for the subnet.
135 :type cidr: ``str``
136 :return: * *True*: When the new CIDR was set successfully.
137 * *False*: If the CIDR format was wrong.
138 :rtype: ``bool``
139 """
140 if cidr is None:
141 if self._cidr is not None:
142 import emuvim.api.openstack.ip_handler as IP
143 IP.free_cidr(self._cidr, self.subnet_id)
144 self._cidr = None
145 self.reset_issued_ip_addresses()
146 self.start_end_dict = dict()
147 return True
148 if not Net.check_cidr_format(cidr):
149 return False
150
151 self.reset_issued_ip_addresses()
152 self.start_end_dict = Net.calculate_start_and_end_dict(cidr)
153 self._cidr = cidr
154 return True
155
156 def get_cidr(self):
157 """
158 Gets the CIDR.
159
160 :return: The CIDR
161 :rtype: ``str``
162 """
163 return self._cidr
164
165 def clear_cidr(self):
166 self._cidr = None
167 self.start_end_dict = dict()
168 self.reset_issued_ip_addresses()
169
170 def delete_subnet(self):
171 self.subnet_id = None
172 self.subnet_name = None
173 self.subnet_creation_time = None
174 self.subnet_update_time = None
175 self.set_cidr(None)
176
177 @staticmethod
178 def calculate_start_and_end_dict(cidr):
179 """
180 Calculates the start and end IP address for the subnet.
181
182 :param cidr: The CIDR for the subnet.
183 :type cidr: ``str``
184 :return: Dict with start and end ip address
185 :rtype: ``dict``
186 """
187 address, suffix = cidr.rsplit('/', 1)
188 int_suffix = int(suffix)
189 int_address = Net.ip_2_int(address)
190 address_space = 2 ** 32 - 1
191
192 for x in range(0, 31 - int_suffix):
193 address_space = ~(~address_space | (1 << x))
194
195 start = int_address & address_space
196 end = start + (2 ** (32 - int_suffix) - 1)
197
198 return {'start': Net.int_2_ip(start), 'end': Net.int_2_ip(end)}
199
200 @staticmethod
201 def cidr_2_int(cidr):
202 if cidr is None:
203 return None
204 ip = cidr.rsplit('/', 1)[0]
205 return Net.ip_2_int(ip)
206
207 @staticmethod
208 def ip_2_int(ip):
209 """
210 Converts a IP address to int.
211
212 :param ip: IP address
213 :type ip: ``str``
214 :return: IP address as int.
215 :rtype: ``int``
216 """
217 o = map(int, ip.split('.'))
218 res = (16777216 * o[0]) + (65536 * o[1]) + (256 * o[2]) + o[3]
219 return res
220
221 @staticmethod
222 def int_2_ip(int_ip):
223 """
224 Converts a int IP address to string.
225
226 :param int_ip: Int IP address.
227 :type int_ip: ``int``
228 :return: IP address
229 :rtype: ``str``
230 """
231 o1 = int(int_ip / 16777216) % 256
232 o2 = int(int_ip / 65536) % 256
233 o3 = int(int_ip / 256) % 256
234 o4 = int(int_ip) % 256
235 return '%(o1)s.%(o2)s.%(o3)s.%(o4)s' % locals()
236
237 @staticmethod
238 def check_cidr_format(cidr):
239 """
240 Checks the CIDR format. An valid example is: 192.168.0.0/29
241
242 :param cidr: CIDR to be checked.
243 :type cidr: ``str``
244 :return: * *True*: If the Format is correct.
245 * *False*: If it is not correct.
246 :rtype: ``bool``
247 """
248 r = re.compile('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{2}')
249 if r.match(cidr):
250 return True
251 return False
252
253 def create_network_dict(self):
254 """
255 Creates the network description dictionary.
256
257 :return: Network description.
258 :rtype: ``dict``
259 """
260 network_dict = dict()
261 network_dict["status"] = "ACTIVE" # TODO do we support inactive networks?
262 if self.subnet_id == None:
263 network_dict["subnets"] = []
264 else:
265 network_dict["subnets"] = [self.subnet_id]
266 network_dict["name"] = self.name
267 network_dict["admin_state_up"] = True # TODO is it always true?
268 network_dict["tenant_id"] = "abcdefghijklmnopqrstuvwxyz123456" # TODO what should go in here
269 network_dict["id"] = self.id
270 network_dict["shared"] = False # TODO is it always false?
271 return network_dict
272
273 def create_subnet_dict(self):
274 """
275 Creates the subnet description dictionary.
276
277 :return: Subnet description.
278 :rtype: ``dict``
279 """
280 subnet_dict = dict()
281 subnet_dict["name"] = self.subnet_name
282 subnet_dict["network_id"] = self.id
283 subnet_dict["tenant_id"] = "abcdefghijklmnopqrstuvwxyz123456" # TODO what should go in here?
284 subnet_dict["created_at"] = self.subnet_creation_time
285 subnet_dict["dns_nameservers"] = []
286 subnet_dict["allocation_pools"] = [self.start_end_dict]
287 subnet_dict["host_routers"] = []
288 subnet_dict["gateway_ip"] = self.gateway_ip
289 subnet_dict["ip_version"] = "4"
290 subnet_dict["cidr"] = self.get_cidr()
291 subnet_dict["updated_at"] = self.subnet_update_time
292 subnet_dict["id"] = self.subnet_id
293 subnet_dict["enable_dhcp"] = False # TODO do we support DHCP?
294 return subnet_dict
295
296 def __eq__(self, other):
297 if self.name == other.name and self.subnet_name == other.subnet_name and \
298 self.gateway_ip == other.gateway_ip and \
299 self.segmentation_id == other.segmentation_id and \
300 self._cidr == other._cidr and \
301 self.start_end_dict == other.start_end_dict:
302 return True
303 return False
304
305 def __hash__(self):
306 return hash((self.name,
307 self.subnet_name,
308 self.gateway_ip,
309 self.segmentation_id,
310 self._cidr,
311 self.start_end_dict))