1 # Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
2 # and others. All rights reserved.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
17 from neutronclient.common.exceptions import NotFound
18 from neutronclient.neutron.client import Client
19 from snaps.openstack.utils import keystone_utils
21 __author__ = 'spisarski'
23 logger = logging.getLogger('neutron_utils')
26 Utilities for basic neutron API calls
30 def neutron_client(os_creds):
32 Instantiates and returns a client for communications with OpenStack's Neutron server
33 :param os_creds: the credentials for connecting to the OpenStack remote API
34 :return: the client object
36 return Client(api_version=os_creds.network_api_version, session=keystone_utils.keystone_session(os_creds))
39 def create_network(neutron, os_creds, network_settings):
41 Creates a network for OpenStack
42 :param neutron: the client
43 :param os_creds: the OpenStack credentials
44 :param network_settings: A dictionary containing the network configuration and is responsible for creating the
45 network request JSON body
46 :return: the network object
48 if neutron and network_settings:
49 logger.info('Creating network with name ' + network_settings.name)
50 json_body = network_settings.dict_for_neutron(os_creds)
51 return neutron.create_network(body=json_body)
53 logger.error("Failed to create network")
57 def delete_network(neutron, network):
59 Deletes a network for OpenStack
60 :param neutron: the client
61 :param network: the network object
63 if neutron and network:
64 logger.info('Deleting network with name ' + network['network']['name'])
65 neutron.delete_network(network['network']['id'])
68 def get_network(neutron, network_name, project_id=None):
70 Returns an object (dictionary) of the first network found with a given name and project_id (if included)
71 :param neutron: the client
72 :param network_name: the name of the network to retrieve
73 :param project_id: the id of the network's project
78 net_filter['name'] = network_name
80 net_filter['project_id'] = project_id
82 networks = neutron.list_networks(**net_filter)
83 for network, netInsts in networks.items():
85 if inst.get('name') == network_name:
86 if project_id and inst.get('project_id') == project_id:
87 return {'network': inst}
89 return {'network': inst}
93 def get_network_by_id(neutron, network_id):
95 Returns the network object (dictionary) with the given ID
96 :param neutron: the client
97 :param network_id: the id of the network to retrieve
100 networks = neutron.list_networks(**{'id': network_id})
101 for network, netInsts in networks.items():
102 for inst in netInsts:
103 if inst.get('id') == network_id:
104 return {'network': inst}
108 def create_subnet(neutron, subnet_settings, os_creds, network=None):
110 Creates a network subnet for OpenStack
111 :param neutron: the client
112 :param network: the network object
113 :param subnet_settings: A dictionary containing the subnet configuration and is responsible for creating the subnet
115 :param os_creds: the OpenStack credentials
116 :return: the subnet object
118 if neutron and network and subnet_settings:
119 json_body = {'subnets': [subnet_settings.dict_for_neutron(os_creds, network=network)]}
120 logger.info('Creating subnet with name ' + subnet_settings.name)
121 subnets = neutron.create_subnet(body=json_body)
122 return {'subnet': subnets['subnets'][0]}
124 logger.error("Failed to create subnet.")
128 def delete_subnet(neutron, subnet):
130 Deletes a network subnet for OpenStack
131 :param neutron: the client
132 :param subnet: the subnet object
134 if neutron and subnet:
135 logger.info('Deleting subnet with name ' + subnet['subnet']['name'])
136 neutron.delete_subnet(subnet['subnet']['id'])
139 def get_subnet_by_name(neutron, subnet_name):
141 Returns the first subnet object (dictionary) found with a given name
142 :param neutron: the client
143 :param subnet_name: the name of the network to retrieve
146 subnets = neutron.list_subnets(**{'name': subnet_name})
147 for subnet, subnetInst in subnets.items():
148 for inst in subnetInst:
149 if inst.get('name') == subnet_name:
150 return {'subnet': inst}
154 def create_router(neutron, os_creds, router_settings):
156 Creates a router for OpenStack
157 :param neutron: the client
158 :param os_creds: the OpenStack credentials
159 :param router_settings: A dictionary containing the router configuration and is responsible for creating the subnet
161 :return: the router object
164 json_body = router_settings.dict_for_neutron(neutron, os_creds)
165 logger.info('Creating router with name - ' + router_settings.name)
166 return neutron.create_router(json_body)
168 logger.error("Failed to create router.")
172 def delete_router(neutron, router):
174 Deletes a router for OpenStack
175 :param neutron: the client
176 :param router: the router object
178 if neutron and router:
179 logger.info('Deleting router with name - ' + router['router']['name'])
180 neutron.delete_router(router=router['router']['id'])
184 def get_router_by_name(neutron, router_name):
186 Returns the first router object (dictionary) found with a given name
187 :param neutron: the client
188 :param router_name: the name of the network to retrieve
191 routers = neutron.list_routers(**{'name': router_name})
192 for router, routerInst in routers.items():
193 for inst in routerInst:
194 if inst.get('name') == router_name:
195 return {'router': inst}
199 def add_interface_router(neutron, router, subnet=None, port=None):
201 Adds an interface router for OpenStack for either a subnet or port. Exception will be raised if requesting for both.
202 :param neutron: the client
203 :param router: the router object
204 :param subnet: the subnet object
205 :param port: the port object
206 :return: the interface router object
209 raise Exception('Cannot add interface to the router. Both subnet and port were sent in. Either or please.')
211 if neutron and router and (router or subnet):
212 logger.info('Adding interface to router with name ' + router['router']['name'])
213 return neutron.add_interface_router(router=router['router']['id'], body=__create_port_json_body(subnet, port))
215 raise Exception("Unable to create interface router as neutron client, router or subnet were not created")
218 def remove_interface_router(neutron, router, subnet=None, port=None):
220 Removes an interface router for OpenStack
221 :param neutron: the client
222 :param router: the router object
223 :param subnet: the subnet object (either subnet or port, not both)
224 :param port: the port object
228 logger.info('Removing router interface from router named ' + router['router']['name'])
229 neutron.remove_interface_router(router=router['router']['id'], body=__create_port_json_body(subnet, port))
230 except NotFound as e:
231 logger.warning('Could not remove router interface. NotFound - ' + str(e))
234 logger.warning('Could not remove router interface, No router object')
237 def __create_port_json_body(subnet=None, port=None):
239 Returns the dictionary required for creating and deleting router interfaces. Will only work on a subnet or port
240 object. Will throw and exception if parameters contain both or neither
241 :param subnet: the subnet object
242 :param port: the port object
246 raise Exception('Cannot create JSON body with both subnet and port')
247 if not subnet and not port:
248 raise Exception('Cannot create JSON body without subnet or port')
251 return {"subnet_id": subnet['subnet']['id']}
253 return {"port_id": port['port']['id']}
256 def create_port(neutron, os_creds, port_settings):
258 Creates a port for OpenStack
259 :param neutron: the client
260 :param os_creds: the OpenStack credentials
261 :param port_settings: the settings object for port configuration
262 :return: the port object
264 json_body = port_settings.dict_for_neutron(neutron, os_creds)
265 logger.info('Creating port for network with name - ' + port_settings.network_name)
266 return neutron.create_port(body=json_body)
269 def delete_port(neutron, port):
271 Removes an OpenStack port
272 :param neutron: the client
273 :param port: the port object
276 logger.info('Deleting port with name ' + port['port']['name'])
277 neutron.delete_port(port['port']['id'])
280 def get_port_by_name(neutron, port_name):
282 Returns the first port object (dictionary) found with a given name
283 :param neutron: the client
284 :param port_name: the name of the port to retrieve
287 ports = neutron.list_ports(**{'name': port_name})
288 for port in ports['ports']:
289 if port['name'] == port_name:
290 return {'port': port}
294 def create_security_group(neutron, keystone, sec_grp_settings):
296 Creates a security group object in OpenStack
297 :param neutron: the Neutron client
298 :param keystone: the Keystone client
299 :param sec_grp_settings: the security group settings
300 :return: the security group object
302 logger.info('Creating security group with name - ' + sec_grp_settings.name)
303 return neutron.create_security_group(sec_grp_settings.dict_for_neutron(keystone))
306 def delete_security_group(neutron, sec_grp):
308 Deletes a security group object from OpenStack
309 :param neutron: the client
310 :param sec_grp: the security group object to delete
312 logger.info('Deleting security group with name - ' + sec_grp['security_group']['name'])
313 return neutron.delete_security_group(sec_grp['security_group']['id'])
316 def get_security_group(neutron, name):
318 Returns the first security group object of the given name else None
319 :param neutron: the client
320 :param name: the name of security group object to retrieve
322 logger.info('Retrieving security group with name - ' + name)
324 groups = neutron.list_security_groups(**{'name': name})
325 for group in groups['security_groups']:
326 if group['name'] == name:
327 return {'security_group': group}
331 def get_security_group_by_id(neutron, sec_grp_id):
333 Returns the first security group object of the given name else None
334 :param neutron: the client
335 :param sec_grp_id: the id of the security group to retrieve
337 logger.info('Retrieving security group with ID - ' + sec_grp_id)
339 groups = neutron.list_security_groups(**{'sec_grp_id': sec_grp_id})
340 for group in groups['security_groups']:
341 return {'security_group': group}
345 def create_security_group_rule(neutron, sec_grp_rule_settings):
347 Creates a security group object in OpenStack
348 :param neutron: the client
349 :param sec_grp_rule_settings: the security group rule settings
350 :return: the security group object
352 logger.info('Creating security group to security group - ' + sec_grp_rule_settings.sec_grp_name)
353 return neutron.create_security_group_rule(sec_grp_rule_settings.dict_for_neutron(neutron))
356 def delete_security_group_rule(neutron, sec_grp_rule):
358 Deletes a security group object from OpenStack
359 :param neutron: the client
360 :param sec_grp_rule: the security group rule object to delete
362 logger.info('Deleting security group rule with ID - ' + sec_grp_rule['security_group_rule']['id'])
363 neutron.delete_security_group_rule(sec_grp_rule['security_group_rule']['id'])
366 def get_rules_by_security_group(neutron, sec_grp):
368 Retrieves all of the rules for a given security group
369 :param neutron: the client
370 :param sec_grp: the security group object
372 logger.info('Retrieving security group rules associate with the security group - ' +
373 sec_grp['security_group']['name'])
375 rules = neutron.list_security_group_rules(**{'security_group_id': sec_grp['security_group']['id']})
376 for rule in rules['security_group_rules']:
377 if rule['security_group_id'] == sec_grp['security_group']['id']:
378 out.append({'security_group_rule': rule})
382 def get_rule_by_id(neutron, sec_grp, rule_id):
384 Deletes a security group object from OpenStack
385 :param neutron: the client
386 :param sec_grp: the security group object
387 :param rule_id: the rule's ID
389 rules = neutron.list_security_group_rules(**{'security_group_id': sec_grp['security_group']['id']})
390 for rule in rules['security_group_rules']:
391 if rule['id'] == rule_id:
392 return {'security_group_rule': rule}
396 def get_external_networks(neutron):
398 Returns a list of external OpenStack network object/dict for all external networks
399 :param neutron: the client
400 :return: a list of external networks (empty list if none configured)
403 for network in neutron.list_networks(**{'router:external': True})['networks']:
404 out.append({'network': network})