Manually added OpenStack API code
[osm/vim-emu.git] / src / emuvim / api / openstack / resources / port.py
1 import logging
2 import threading
3 import uuid
4
5 lock = threading.Lock()
6 intf_names = dict()
7
8
9 class Port:
10 def __init__(self, name, ip_address=None, mac_address=None, floating_ip=None):
11 self.name = name
12 self.intf_name = None
13 self.id = str(uuid.uuid4())
14 self.template_name = name
15 """
16 ip_address is structured like 10.0.0.1/24
17 """
18 self.ip_address = ip_address
19 self.mac_address = mac_address
20 self.floating_ip = floating_ip
21 self.net_name = None
22
23 def set_name(self, name):
24 """
25 Sets the port name.
26
27 :param name: New port name.
28 :type name: ``str``
29 """
30 if self.name == name:
31 return
32
33 # Delete old interface name
34 global lock
35 lock.acquire()
36 if intf_names[self.intf_name][0] == self.id and intf_names[self.intf_name][1] is False:
37 del intf_names[self.intf_name]
38 lock.release()
39
40 self.name = name
41 # Create new interface name
42 self.create_intf_name()
43
44 def create_intf_name(self):
45 """
46 Creates the interface name, while using the first 4 letters of the port name, the specification, if it is an
47 'in' / 'out' port or something else, and a counter value if the name is already used. The counter starts
48 for each name at 0 and can go up to 999. After creating the name each port will post its interface name
49 into the global dictionary and adding his full name. Thus each port can determine if his desired interface
50 name is already used and choose the next one.
51 """
52 split_name = self.name.split(':')
53 if len(split_name) >= 3:
54 if split_name[2] == 'input' or split_name[2] == 'in':
55 self.intf_name = split_name[0][:4] + '-' + \
56 'in'
57 elif split_name[2] == 'output' or split_name[2] == 'out':
58 self.intf_name = split_name[0][:4] + '-' + \
59 'out'
60 else:
61 self.intf_name = split_name[0][:4] + '-' + \
62 split_name[2][:4]
63 else:
64 self.intf_name = self.name[:9]
65
66 global lock
67 lock.acquire()
68 counter = 0
69 global intf_names
70 intf_len = len(self.intf_name)
71 self.intf_name = self.intf_name + '-' + str(counter)[:4]
72 while self.intf_name in intf_names and counter < 999 and not intf_names[self.intf_name][0] == self.id:
73 counter += 1
74 self.intf_name = self.intf_name[:intf_len] + '-' + str(counter)[:4]
75
76 if counter >= 1000:
77 logging.ERROR("Port %s could not create unique interface name (%s)", self.name, self.intf_name)
78 lock.release()
79 return
80
81 updated = False
82 if self.intf_name in intf_names and intf_names[self.intf_name][0] == self.id:
83 updated = True
84
85 intf_names[self.intf_name] = [self.id, updated]
86 lock.release()
87
88 def get_short_id(self):
89 """
90 Gets a shortened ID which only contains first 6 characters.
91
92 :return: The first 6 characters of the UUID.
93 :rtype: ``str``
94 """
95 return str(self.id)[:6]
96
97 def create_port_dict(self, compute):
98 """
99 Creates the port description dictionary.
100
101 :param compute: Requires the compute resource to determine the used network.
102 :type compute: :class:`heat.compute`
103 :return: Returns the description dictionary.
104 :rtype: ``dict``
105 """
106 port_dict = dict()
107 port_dict["admin_state_up"] = True # TODO is it always true?
108 port_dict["device_id"] = "257614cc-e178-4c92-9c61-3b28d40eca44" # TODO find real values
109 port_dict["device_owner"] = "" # TODO do we have such things?
110 net = compute.find_network_by_name_or_id(self.net_name)
111 port_dict["fixed_ips"] = [
112 {
113 "ip_address": self.ip_address.rsplit('/', 1)[0] if self.ip_address is not None else "",
114 "subnet_id": net.subnet_id if net is not None else ""
115 }
116 ]
117 port_dict["id"] = self.id
118 port_dict["mac_address"] = self.mac_address
119 port_dict["name"] = self.name
120 port_dict["network_id"] = net.id if net is not None else ""
121 port_dict["status"] = "ACTIVE" # TODO do we support inactive port?
122 port_dict["tenant_id"] = "abcdefghijklmnopqrstuvwxyz123456" # TODO find real tenant_id
123 return port_dict
124
125 def compare_attributes(self, other):
126 """
127 Does NOT compare ip_address because this function only exists to check if we can
128 update the IP address without any changes
129
130 :param other: The port to compare with
131 :type other: :class:`heat.resources.port`
132 :return: True if the attributes are the same, else False.
133 :rtype: ``bool``
134 """
135 if other is None:
136 return False
137
138 if self.name == other.name and self.floating_ip == other.floating_ip and \
139 self.net_name == other.net_name:
140 return True
141 return False
142
143 def __eq__(self, other):
144 if other is None:
145 return False
146
147 if self.name == other.name and self.ip_address == other.ip_address and \
148 self.mac_address == other.mac_address and \
149 self.floating_ip == other.floating_ip and \
150 self.net_name == other.net_name:
151 return True
152 return False
153
154 def __hash__(self):
155 return hash((self.name,
156 self.ip_address,
157 self.mac_address,
158 self.floating_ip,
159 self.net_name))
160
161 def __del__(self):
162 global lock
163 lock.acquire()
164 global intf_names
165 if self.intf_name in intf_names and intf_names[self.intf_name][0] == self.id:
166 if intf_names[self.intf_name][1] is False:
167 del intf_names[self.intf_name]
168 else:
169 intf_names[self.intf_name][1] = False
170 lock.release()