From 57777f3df521553a06cd01a3861b415d2905ceca Mon Sep 17 00:00:00 2001 From: spisarski Date: Wed, 15 Feb 2017 09:13:54 -0700 Subject: Initial patch with all code from CableLabs repository. Change-Id: I70a2778718c5e7f21fd14e4ad28c9269d3761cc7 Signed-off-by: spisarski --- snaps/openstack/utils/neutron_utils.py | 405 +++++++++++++++++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 snaps/openstack/utils/neutron_utils.py (limited to 'snaps/openstack/utils/neutron_utils.py') diff --git a/snaps/openstack/utils/neutron_utils.py b/snaps/openstack/utils/neutron_utils.py new file mode 100644 index 0000000..6c92d2e --- /dev/null +++ b/snaps/openstack/utils/neutron_utils.py @@ -0,0 +1,405 @@ +# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs") +# and others. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import logging + +from neutronclient.common.exceptions import NotFound +from neutronclient.neutron.client import Client +import keystone_utils + +__author__ = 'spisarski' + +logger = logging.getLogger('neutron_utils') + +""" +Utilities for basic neutron API calls +""" + + +def neutron_client(os_creds): + """ + Instantiates and returns a client for communications with OpenStack's Neutron server + :param os_creds: the credentials for connecting to the OpenStack remote API + :return: the client object + """ + return Client(api_version=os_creds.network_api_version, session=keystone_utils.keystone_session(os_creds)) + + +def create_network(neutron, os_creds, network_settings): + """ + Creates a network for OpenStack + :param neutron: the client + :param os_creds: the OpenStack credentials + :param network_settings: A dictionary containing the network configuration and is responsible for creating the + network request JSON body + :return: the network object + """ + if neutron and network_settings: + logger.info('Creating network with name ' + network_settings.name) + json_body = network_settings.dict_for_neutron(os_creds) + return neutron.create_network(body=json_body) + else: + logger.error("Failed to create network") + raise Exception + + +def delete_network(neutron, network): + """ + Deletes a network for OpenStack + :param neutron: the client + :param network: the network object + """ + if neutron and network: + logger.info('Deleting network with name ' + network['network']['name']) + neutron.delete_network(network['network']['id']) + + +def get_network(neutron, network_name, project_id=None): + """ + Returns an object (dictionary) of the first network found with a given name and project_id (if included) + :param neutron: the client + :param network_name: the name of the network to retrieve + :param project_id: the id of the network's project + :return: + """ + net_filter = dict() + if network_name: + net_filter['name'] = network_name + if project_id: + net_filter['project_id'] = project_id + + networks = neutron.list_networks(**net_filter) + for network, netInsts in networks.iteritems(): + for inst in netInsts: + if inst.get('name') == network_name: + if project_id and inst.get('project_id') == project_id: + return {'network': inst} + else: + return {'network': inst} + return None + + +def get_network_by_id(neutron, network_id): + """ + Returns the network object (dictionary) with the given ID + :param neutron: the client + :param network_id: the id of the network to retrieve + :return: + """ + networks = neutron.list_networks(**{'id': network_id}) + for network, netInsts in networks.iteritems(): + for inst in netInsts: + if inst.get('id') == network_id: + return {'network': inst} + return None + + +def create_subnet(neutron, subnet_settings, os_creds, network=None): + """ + Creates a network subnet for OpenStack + :param neutron: the client + :param network: the network object + :param subnet_settings: A dictionary containing the subnet configuration and is responsible for creating the subnet + request JSON body + :param os_creds: the OpenStack credentials + :return: the subnet object + """ + if neutron and network and subnet_settings: + json_body = {'subnets': [subnet_settings.dict_for_neutron(os_creds, network=network)]} + logger.info('Creating subnet with name ' + subnet_settings.name) + subnets = neutron.create_subnet(body=json_body) + return {'subnet': subnets['subnets'][0]} + else: + logger.error("Failed to create subnet.") + raise Exception + + +def delete_subnet(neutron, subnet): + """ + Deletes a network subnet for OpenStack + :param neutron: the client + :param subnet: the subnet object + """ + if neutron and subnet: + logger.info('Deleting subnet with name ' + subnet['subnet']['name']) + neutron.delete_subnet(subnet['subnet']['id']) + + +def get_subnet_by_name(neutron, subnet_name): + """ + Returns the first subnet object (dictionary) found with a given name + :param neutron: the client + :param subnet_name: the name of the network to retrieve + :return: + """ + subnets = neutron.list_subnets(**{'name': subnet_name}) + for subnet, subnetInst in subnets.iteritems(): + for inst in subnetInst: + if inst.get('name') == subnet_name: + return {'subnet': inst} + return None + + +def create_router(neutron, os_creds, router_settings): + """ + Creates a router for OpenStack + :param neutron: the client + :param os_creds: the OpenStack credentials + :param router_settings: A dictionary containing the router configuration and is responsible for creating the subnet + request JSON body + :return: the router object + """ + if neutron: + json_body = router_settings.dict_for_neutron(neutron, os_creds) + logger.info('Creating router with name - ' + router_settings.name) + return neutron.create_router(json_body) + else: + logger.error("Failed to create router.") + raise Exception + + +def delete_router(neutron, router): + """ + Deletes a router for OpenStack + :param neutron: the client + :param router: the router object + """ + if neutron and router: + logger.info('Deleting router with name - ' + router['router']['name']) + neutron.delete_router(router=router['router']['id']) + return True + + +def get_router_by_name(neutron, router_name): + """ + Returns the first router object (dictionary) found with a given name + :param neutron: the client + :param router_name: the name of the network to retrieve + :return: + """ + routers = neutron.list_routers(**{'name': router_name}) + for router, routerInst in routers.iteritems(): + for inst in routerInst: + if inst.get('name') == router_name: + return {'router': inst} + return None + + +def add_interface_router(neutron, router, subnet=None, port=None): + """ + Adds an interface router for OpenStack for either a subnet or port. Exception will be raised if requesting for both. + :param neutron: the client + :param router: the router object + :param subnet: the subnet object + :param port: the port object + :return: the interface router object + """ + if subnet and port: + raise Exception('Cannot add interface to the router. Both subnet and port were sent in. Either or please.') + + if neutron and router and (router or subnet): + logger.info('Adding interface to router with name ' + router['router']['name']) + return neutron.add_interface_router(router=router['router']['id'], body=__create_port_json_body(subnet, port)) + else: + raise Exception("Unable to create interface router as neutron client, router or subnet were not created") + + +def remove_interface_router(neutron, router, subnet=None, port=None): + """ + Removes an interface router for OpenStack + :param neutron: the client + :param router: the router object + :param subnet: the subnet object (either subnet or port, not both) + :param port: the port object + """ + if router: + try: + logger.info('Removing router interface from router named ' + router['router']['name']) + neutron.remove_interface_router(router=router['router']['id'], body=__create_port_json_body(subnet, port)) + except NotFound as e: + logger.warn('Could not remove router interface. NotFound - ' + e.message) + pass + else: + logger.warn('Could not remove router interface, No router object') + + +def __create_port_json_body(subnet=None, port=None): + """ + Returns the dictionary required for creating and deleting router interfaces. Will only work on a subnet or port + object. Will throw and exception if parameters contain both or neither + :param subnet: the subnet object + :param port: the port object + :return: the dict + """ + if subnet and port: + raise Exception('Cannot create JSON body with both subnet and port') + if not subnet and not port: + raise Exception('Cannot create JSON body without subnet or port') + + if subnet: + return {"subnet_id": subnet['subnet']['id']} + else: + return {"port_id": port['port']['id']} + + +def create_port(neutron, os_creds, port_settings): + """ + Creates a port for OpenStack + :param neutron: the client + :param os_creds: the OpenStack credentials + :param port_settings: the settings object for port configuration + :return: the port object + """ + json_body = port_settings.dict_for_neutron(neutron, os_creds) + logger.info('Creating port for network with name - ' + port_settings.network_name) + return neutron.create_port(body=json_body) + + +def delete_port(neutron, port): + """ + Removes an OpenStack port + :param neutron: the client + :param port: the port object + :return: + """ + logger.info('Deleting port with name ' + port['port']['name']) + neutron.delete_port(port['port']['id']) + + +def get_port_by_name(neutron, port_name): + """ + Returns the first port object (dictionary) found with a given name + :param neutron: the client + :param port_name: the name of the port to retrieve + :return: + """ + ports = neutron.list_ports(**{'name': port_name}) + for port in ports['ports']: + if port['name'] == port_name: + return {'port': port} + return None + + +def create_security_group(neutron, keystone, sec_grp_settings): + """ + Creates a security group object in OpenStack + :param neutron: the Neutron client + :param keystone: the Keystone client + :param sec_grp_settings: the security group settings + :return: the security group object + """ + logger.info('Creating security group with name - ' + sec_grp_settings.name) + return neutron.create_security_group(sec_grp_settings.dict_for_neutron(keystone)) + + +def delete_security_group(neutron, sec_grp): + """ + Deletes a security group object from OpenStack + :param neutron: the client + :param sec_grp: the security group object to delete + """ + logger.info('Deleting security group with name - ' + sec_grp['security_group']['name']) + return neutron.delete_security_group(sec_grp['security_group']['id']) + + +def get_security_group(neutron, name): + """ + Returns the first security group object of the given name else None + :param neutron: the client + :param name: the name of security group object to retrieve + """ + logger.info('Retrieving security group with name - ' + name) + + groups = neutron.list_security_groups(**{'name': name}) + for group in groups['security_groups']: + if group['name'] == name: + return {'security_group': group} + return None + + +def get_security_group_by_id(neutron, sec_grp_id): + """ + Returns the first security group object of the given name else None + :param neutron: the client + :param sec_grp_id: the id of the security group to retrieve + """ + logger.info('Retrieving security group with ID - ' + sec_grp_id) + + groups = neutron.list_security_groups(**{'sec_grp_id': sec_grp_id}) + for group in groups['security_groups']: + return {'security_group': group} + return None + + +def create_security_group_rule(neutron, sec_grp_rule_settings): + """ + Creates a security group object in OpenStack + :param neutron: the client + :param sec_grp_rule_settings: the security group rule settings + :return: the security group object + """ + logger.info('Creating security group to security group - ' + sec_grp_rule_settings.sec_grp_name) + return neutron.create_security_group_rule(sec_grp_rule_settings.dict_for_neutron(neutron)) + + +def delete_security_group_rule(neutron, sec_grp_rule): + """ + Deletes a security group object from OpenStack + :param neutron: the client + :param sec_grp_rule: the security group rule object to delete + """ + logger.info('Deleting security group rule with ID - ' + sec_grp_rule['security_group_rule']['id']) + neutron.delete_security_group_rule(sec_grp_rule['security_group_rule']['id']) + + +def get_rules_by_security_group(neutron, sec_grp): + """ + Retrieves all of the rules for a given security group + :param neutron: the client + :param sec_grp: the security group object + """ + logger.info('Retrieving security group rules associate with the security group - ' + + sec_grp['security_group']['name']) + out = list() + rules = neutron.list_security_group_rules(**{'security_group_id': sec_grp['security_group']['id']}) + for rule in rules['security_group_rules']: + if rule['security_group_id'] == sec_grp['security_group']['id']: + out.append({'security_group_rule': rule}) + return out + + +def get_rule_by_id(neutron, sec_grp, rule_id): + """ + Deletes a security group object from OpenStack + :param neutron: the client + :param sec_grp: the security group object + :param rule_id: the rule's ID + """ + rules = neutron.list_security_group_rules(**{'security_group_id': sec_grp['security_group']['id']}) + for rule in rules['security_group_rules']: + if rule['id'] == rule_id: + return {'security_group_rule': rule} + return None + + +def get_external_networks(neutron): + """ + Returns a list of external OpenStack network object/dict for all external networks + :param neutron: the client + :return: a list of external networks (empty list if none configured) + """ + out = list() + for network in neutron.list_networks(**{'router:external': True})['networks']: + out.append({'network': network}) + return out -- cgit 1.2.3-korg