Fix vfc-lcm/pub/nfvi pep8 issue
[vfc/nfvo/lcm.git] / lcm / pub / nfvi / vim / api / openstack / network.py
1 # Copyright 2016 ZTE Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #         http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import logging
16 import sys
17 import traceback
18
19 from neutronclient.common.exceptions import NeutronClientException
20 from neutronclient.common.exceptions import NetworkNotFoundClient
21 from neutronclient.common.exceptions import NotFound as SubnetNotFound
22
23 from lcm.pub.nfvi.vim.api.openstack import neutronbase
24 from lcm.pub.nfvi.vim.lib.syscomm import fun_name
25 from lcm.pub.nfvi.vim.api.openstack import project
26 from lcm.pub.nfvi.vim import const
27 from lcm.pub.nfvi.vim.lib.vimexception import VimException
28
29 logger = logging.getLogger(__name__)
30
31
32 def query_net(auth_info, net_id):
33     neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
34     net = None
35     try:
36         net = neutron.show_network(net_id)["network"]
37         keystone = auth_info["keystone"]
38         tenant = keystone.tenants.get(tenant_id=net["tenant_id"])
39     except NetworkNotFoundClient as e:
40         logger.warn("NetworkNotFoundClient: %s", e.message)
41         return [2, e.message]
42     return [0, {
43         "id": net["id"],
44         "name": net["name"],
45         "status": net["status"],
46         "admin_state_up": net["admin_state_up"],
47         "network_type": net["provider:network_type"],
48         "physical_network": net["provider:physical_network"],
49         "segmentation_id": net["provider:segmentation_id"],
50         "tenant_id": net["tenant_id"],
51         "tenant_name": tenant.name,
52         "subnets": net["subnets"],
53         "shared": net["shared"],
54         "router_external": net["router:external"]}
55     ]
56
57
58 def query_nets(auth_info):
59     neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
60     keystone = auth_info["keystone"]
61     tenants_map = {}
62     tenants = keystone.tenants.list()
63     for tenant in tenants:
64         tenants_map[tenant.id] = tenant.name
65
66     nets = neutron.list_networks()
67     return [0, {"networks": [{
68         "id": net["id"],
69         "name": net["name"],
70         "status": net["status"],
71         "admin_state_up": net["admin_state_up"],
72         "network_type": net["provider:network_type"],
73         "physical_network": net["provider:physical_network"],
74         "segmentation_id": net["provider:segmentation_id"],
75         "tenant_id": net["tenant_id"],
76         "tenant_name": tenants_map[net["tenant_id"]] if net["tenant_id"] in tenants_map else "unknown",
77         "subnets": net["subnets"],
78         "shared": net["shared"],
79         "router_external": net["router:external"]
80     } for net in nets["networks"]]}]
81
82
83 def query_subnet(auth_info, subnet_id):
84     neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
85     subnet_info = None
86     try:
87         subnet_info = neutron.show_subnet(subnet_id)["subnet"]
88     except SubnetNotFound as e:
89         logger.warn("SubnetNotFound: %s", e.message)
90         return [2, e.message]
91     ret = [0, {}]
92     ret[1]["id"] = subnet_id
93     ret[1]["name"] = subnet_info["name"]
94     ret[1]["status"] = ""
95     ret[1]["ip_version"] = subnet_info["ip_version"]
96     ret[1]["cidr"] = subnet_info["cidr"]
97     ret[1]["allocation_pools"] = subnet_info["allocation_pools"]
98     ret[1]["enable_dhcp"] = subnet_info["enable_dhcp"]
99     ret[1]["gateway_ip"] = subnet_info["gateway_ip"]
100     ret[1]["host_routes"] = subnet_info["host_routes"]
101     ret[1]["dns_nameservers"] = subnet_info["dns_nameservers"]
102     return ret
103
104
105 def query_port(auth_info, port_id):
106     neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
107     port_info = None
108     try:
109         port_info = neutron.show_port(port_id)["port"]
110     except NeutronClientException as e:
111         logger.warn("NeutronClientException: %s", e.message)
112         return [2, e.message]
113     ret = [0, {}]
114     ret[1]["id"] = port_id
115     ret[1]["name"] = port_info["name"]
116     ret[1]["network_id"] = port_info["network_id"]
117     ret[1]["tenant_id"] = port_info["tenant_id"]
118     if "fixed_ips" in port_info and port_info["fixed_ips"]:
119         ret[1]["ip"] = port_info["fixed_ips"][0]["ip_address"]
120         ret[1]["subnet_id"] = port_info["fixed_ips"][0]["subnet_id"]
121     else:
122         ret[1]["ip"] = ""
123         ret[1]["subnet_id"] = ""
124     ret[1]["mac_address"] = port_info["mac_address"]
125     ret[1]["status"] = port_info["status"]
126     ret[1]["admin_state_up"] = port_info["admin_state_up"]
127     ret[1]["device_id"] = port_info["device_id"]
128     return ret
129
130
131 def get_subnet_id(neutron, data, network_id):
132     subnet_id = None
133     if "subnet_name" in data and data["subnet_name"]:
134         all_subnets = neutron.list_subnets()
135         filter_subnets = [subnet for subnet in all_subnets["subnets"] if subnet["name"] == data["subnet_name"] and
136                           subnet["network_id"] == network_id]
137         count_filter_subnets = len(filter_subnets)
138         if 1 > count_filter_subnets:
139             logger.error("Subnet name(%s) does not exist" % data["subnet_name"])
140             raise VimException("Subnet name(%s) does not exist" % data["subnet_name"])
141         if 1 < count_filter_subnets:
142             for subnet in filter_subnets:
143                 logger.error("subnet_id=%s", subnet["id"])
144             raise VimException("%d subnet(%s) exist in network(%s)"
145                                % (count_filter_subnets, data["subnet_name"], data["network_name"]))
146         subnet_id = filter_subnets[0]['id']
147     else:
148         subnets = neutron.list_subnets()
149         filter_subnets = [subnet for subnet in subnets["subnets"] if subnet["network_id"] == network_id]
150         if filter_subnets:
151             subnet_id = filter_subnets[0]["id"]
152     return subnet_id
153
154
155 def create_port(auth_info, data):
156     tenant_id = project.get_tenant_id(fun_name(), auth_info, data["tenant_name"])
157
158     neutron_admin = neutronbase.get_neutron_default(fun_name(), auth_info)
159     all_nets = neutron_admin.list_networks()
160     filter_nets = [net for net in all_nets['networks'] if net['name'] == data["network_name"]]
161     sel_nets = [net for net in filter_nets if net['tenant_id'] == tenant_id or
162                 (net['tenant_id'] != tenant_id and net['shared'])]
163     count_sel_nets = len(sel_nets)
164     if 1 > count_sel_nets:
165         logger.error("Network(%s) does not exist" % data["network_name"])
166         raise VimException("Network(%s) does not exist" % data["network_name"])
167     if 1 < count_sel_nets:
168         for net in sel_nets:
169             logger.error("net_id=%s", net["id"])
170         raise VimException("%d networks(%s) exist in tenant(%s)"
171                            % (count_sel_nets, data["network_name"], data["tenant_name"]))
172     network_id = sel_nets[0]['id']
173     if tenant_id != sel_nets[0]['tenant_id']:
174         neutron = neutronbase.get_neutron_by_tenant_id(fun_name(), auth_info, sel_nets[0]['tenant_id'])
175     else:
176         neutron = neutronbase.get_neutron(fun_name(), auth_info, data["tenant_name"])
177
178     # get subnet id
179     subnet_id = get_subnet_id(neutron_admin, data, network_id)
180
181     # check port
182     port_data = None
183     ports = neutron.list_ports()
184     sel_ports = [port for port in ports['ports'] if port['tenant_id'] == tenant_id and
185                  port['network_id'] == network_id]
186     filter_ports = []
187     for port in sel_ports:
188         if port['name'] == data["port_name"] and port['fixed_ips']:
189             for fixed_ip in port['fixed_ips']:
190                 if fixed_ip['subnet_id'] == subnet_id:
191                     filter_ports.append(port)
192                     break
193     count_filter_ports = len(filter_ports)
194     if 1 < count_filter_ports:
195         for port in filter_ports:
196             logger.error("port_id=%s", port["id"])
197         raise VimException("%d port(%s) exist in subnet(%s)"
198                            % (count_filter_ports, data["port_name"], data["subnet_name"]))
199     if 1 == len(filter_ports):
200         logger.debug("Port(%s) is exist!" % data["port_name"])
201         port_data = {'status': filter_ports[0]['status'],
202                      'id': filter_ports[0]['id'],
203                      'name': filter_ports[0]['name'],
204                      'network_id': filter_ports[0]['network_id'],
205                      const.RES_TYPE_KEY: const.RES_TYPE_EXIST}
206         return [0, port_data]
207
208     # create port
209     create_param = {
210         'port': {
211             'name': data["port_name"],
212             'admin_state_up': True,
213             'network_id': network_id,
214             'security_groups': [],
215             'tenant_id': tenant_id
216         }
217     }
218     if "mac_address" in data and data["mac_address"]:
219         create_param['port']['mac_address'] = data["mac_address"]
220     if "vnic_type" in data and data["vnic_type"]:
221         create_param['port']['binding:vnic_type'] = data["vnic_type"]
222     if "bandwidth" in data and data["bandwidth"]:
223         create_param['port']['bandwidth'] = int(data["bandwidth"])
224     if "bond" in data and data["bond"]:
225         create_param['port']['bond'] = int(data["bond"])
226     if "macbond" in data and data["macbond"]:
227         if 'mac_address' in create_param['port']:
228             create_param['port']['mac_address'] += (',' + data["macbond"])
229         else:
230             create_param['port']['mac_address'] = data["macbond"]
231     if "ip" in data and data["ip"]:
232         if subnet_id:
233             create_param['port']['fixed_ips'] = [{"subnet_id": subnet_id, "ip_address": data["ip"]}]
234
235     if "allowed_address_pairs" in data and data["allowed_address_pairs"]:
236         create_param['port']['allowed_address_pairs'] = data["allowed_address_pairs"]
237     logger.info("[%s]call neutron.create_port(%s)" % (fun_name(), str(create_param)))
238     port_created = None
239     try:
240         port_created = neutron.create_port(create_param)
241     except NeutronClientException as ex:
242         logger.info("create_port exception: %s, %s", str(sys.exc_info()), ex.message)
243         create_param['port'].pop('security_groups')
244         if 'allowed_address_pairs' in create_param['port']:
245             create_param['port'].pop('allowed_address_pairs')
246         logger.info("[%s]recall neutron.create_port(%s)" % (fun_name(), str(create_param)))
247         port_created = neutron.create_port(create_param)
248     if port_created:
249         port_data = {'status': port_created['port']['status'],
250                      'id': port_created['port']['id'],
251                      'name': port_created['port']['name'],
252                      'network_id': port_created['port']['network_id'],
253                      const.RES_TYPE_KEY: const.RES_TYPE_NEW}
254     return [0, port_data]
255
256
257 def create_network(auth_info, data):
258     neutron = neutronbase.get_neutron(fun_name(), auth_info, data["tenant"])
259     tenant_id = project.get_tenant_id(fun_name(), auth_info, data["tenant"])
260
261     neutron_admin = neutronbase.get_neutron_default(fun_name(), auth_info)
262     all_nets = neutron_admin.list_networks()
263     filter_nets = [net for net in all_nets['networks'] if net['name'] == data["network_name"]]
264     sel_nets = [net for net in filter_nets if net['tenant_id'] == tenant_id or
265                 (net['tenant_id'] != tenant_id and net['shared'])]
266     count_sel_nets = len(sel_nets)
267     if 1 < count_sel_nets:
268         for sel_net in sel_nets:
269             logger.info("net_id=%s, net_tenant_id=%s", sel_net["id"], sel_net['tenant_id'])
270         raise VimException("Already %d networks are found with name %s" % (count_sel_nets, data["network_name"]))
271
272     network_data = None
273     if sel_nets:
274         if sel_nets[0]['tenant_id'] != tenant_id:
275             neutron = neutronbase.get_neutron_by_tenant_id(fun_name(), auth_info, sel_nets[0]['tenant_id'])
276         all_subnets = neutron_admin.list_subnets()
277         filter_subnets = [subnet for subnet in all_subnets["subnets"] if subnet["network_id"] == sel_nets[0]["id"]]
278         network_data = {
279             "status": sel_nets[0]["status"],
280             "id": sel_nets[0]["id"],
281             "name": data["network_name"],
282             "provider:segmentation_id": sel_nets[0]["provider:segmentation_id"],
283             "provider:network_type": sel_nets[0]["provider:network_type"],
284             const.RES_TYPE_KEY: const.RES_TYPE_EXIST,
285             "subnet_list": [
286                 {
287                     "id": subnet["id"],
288                     "name": subnet["name"],
289                     const.RES_TYPE_KEY: const.RES_TYPE_EXIST
290                 }for subnet in filter_subnets
291             ]
292         }
293     else:
294         create_params = {
295             'network': {
296                 'name': data["network_name"],
297                 'admin_state_up': True,
298                 'tenant_id': tenant_id,
299                 'shared': "shared" in data and int(data["shared"]) == const.SHARED_NET}}
300         if "mtu" in data and int(data["mtu"]) != const.DEFAULT_MTU:
301             create_params['network']['mtu'] = int(data["mtu"])
302         if "vlan_transparent" in data and int(data["vlan_transparent"]) == const.SUPPORT_VLAN_TRANSPARENT:
303             create_params['network']['vlan-transparent'] = True
304         if "network_type" in data and data['network_type']:
305             create_params['network']['provider:network_type'] = data['network_type']
306         if "segmentation_id" in data and data['segmentation_id']:
307             create_params['network']['provider:segmentation_id'] = int(data['segmentation_id'])
308         if "physical_network" in data and data['physical_network']:
309             create_params['network']['provider:physical_network'] = data['physical_network']
310
311         logger.info("[%s]call neutron.create_network(%s)" % (fun_name(), str(create_params)))
312         network_created = neutron.create_network(create_params)
313         network_data = {"status": network_created['network']['status'],
314                         "id": network_created['network']['id'],
315                         "name": data["network_name"],
316                         "provider:segmentation_id": network_created['network']['provider:segmentation_id'],
317                         "provider:network_type": network_created['network']['provider:network_type'],
318                         const.RES_TYPE_KEY: const.RES_TYPE_NEW,
319                         "subnet_list": []}
320
321     # subnet create
322     exist_subnet_names = [subnet["name"] for subnet in network_data["subnet_list"]]
323     need_rollback, ret_error = False, None
324     if "subnet_list" in data and data["subnet_list"]:
325         for subnet_data in data["subnet_list"]:
326             if subnet_data["subnet_name"] in exist_subnet_names:
327                 continue
328             ret = create_subnet(neutron, network_data["id"], subnet_data)
329             if ret[0] != 0:
330                 need_rollback, ret_error = True, ret
331                 break
332             network_data["subnet_list"].append(ret[1])
333
334     # rollback when failed to create subnet
335     if need_rollback:
336         rollback(neutron_admin, network_data)
337         return ret_error
338
339     return [0, network_data]
340
341
342 def create_subnet(neutron, network_id, data):
343     all_subnets = neutron.list_subnets()
344     filter_subnets = [subnet for subnet in all_subnets["subnets"]
345                       if subnet["network_id"] == network_id and subnet["name"] == data["subnet_name"]]
346     if filter_subnets:
347         return [0, {
348             "id": filter_subnets[0]["id"],
349             "name": data["subnet_name"],
350             const.RES_TYPE_KEY: const.RES_TYPE_EXIST
351         }]
352     try:
353         create_params = {
354             'subnet': {
355                 'network_id': network_id,
356                 'name': data["subnet_name"],
357                 'cidr': data["cidr"],
358                 'ip_version': int(data["ip_version"]) if "ip_version" in data else const.IPV4, }}
359         create_params["subnet"]["enable_dhcp"] = ("enable_dhcp" in data and
360                                                   int(data["enable_dhcp"]) == const.ENABLE_DHCP)
361         if "gateway_ip" in data and data["gateway_ip"]:
362             create_params["subnet"]["gateway_ip"] = data["gateway_ip"]
363         else:
364             create_params["subnet"]["gateway_ip"] = None
365         if "dns_nameservers" in data and data["dns_nameservers"]:
366             create_params["subnet"]["dns_nameservers"] = data["dns_nameservers"]
367         if "allocation_pools" in data and data["allocation_pools"]:
368             create_params["subnet"]["allocation_pools"] = data["allocation_pools"]
369         if "host_routes" in data and data["host_routes"]:
370             create_params["subnet"]["host_routes"] = data["host_routes"]
371
372         logger.info("[%s]call neutron.create_subnet(%s)" % (fun_name(), str(create_params)))
373         subnet_created = neutron.create_subnet(create_params)
374         return [0, {"id": subnet_created["subnet"]["id"],
375                     "name": data["subnet_name"],
376                     const.RES_TYPE_KEY: const.RES_TYPE_NEW}]
377     except Exception as ex:
378         logger.error(traceback.format_exc())
379         logger.error(str(sys.exc_info()))
380         return [1, ex.message if ex.message else str(sys.exc_info())]
381
382
383 def rollback(neutron, network_data):
384     for subnet_data in network_data["subnet_list"]:
385         if subnet_data[const.RES_TYPE_KEY] == const.RES_TYPE_NEW:
386             try:
387                 logger.info("[%s]call neutron.delete_subnet(%s)" % (fun_name(), subnet_data["id"]))
388                 neutron.delete_subnet(subnet_data["subnet_id"])
389             except:
390                 logger.error("[%s]%s", fun_name(), str(sys.exc_info()))
391
392     if network_data and network_data[const.RES_TYPE_KEY] == const.RES_TYPE_NEW:
393         try:
394             logger.info("[%s]call neutron.delete_network(%s)" % (fun_name(), network_data["id"]))
395             neutron.delete_network(network_data["id"])
396         except:
397             logger.error("[%s]%s", fun_name(), str(sys.exc_info()))
398
399
400 def delete_network(auth_info, network_id):
401     neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
402     try:
403         neutron.delete_network(network_id)
404     except Exception as ex:
405         logger.error(traceback.format_exc())
406         msg = ex.message if ex.message else str(sys.exc_info())
407         logger.error(msg)
408         if 404 == ex.status_code:
409             return [0, ex.message]
410         return [1, "Vim exception."]
411     return [0, "Network(%s) is deleted" % network_id]
412
413
414 def delete_subnet(auth_info, subnet_id):
415     neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
416     try:
417         neutron.delete_subnet(subnet_id)
418     except NeutronClientException as e:
419         logger.warn("[%s]NetworkNotFoundClient: %s", fun_name(), e.message)
420         return [0, e.message]
421     return [0, "Subnet(%s) is deleted" % subnet_id]
422
423
424 def delete_port(auth_info, port_id):
425     neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
426     try:
427         neutron.delete_port(port_id)
428     except NeutronClientException as e:
429         logger.warn("[%s]NeutronClientException: %s", fun_name(), e.message)
430         return [0, e.message]
431     return [0, "Port(%s) is deleted" % port_id]