summaryrefslogtreecommitdiffstats
path: root/snaps/openstack/create_router.py
diff options
context:
space:
mode:
Diffstat (limited to 'snaps/openstack/create_router.py')
-rw-r--r--snaps/openstack/create_router.py244
1 files changed, 244 insertions, 0 deletions
diff --git a/snaps/openstack/create_router.py b/snaps/openstack/create_router.py
new file mode 100644
index 0000000..70c6b76
--- /dev/null
+++ b/snaps/openstack/create_router.py
@@ -0,0 +1,244 @@
+# 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 snaps.openstack.create_network import PortSettings
+from snaps.openstack.utils import neutron_utils, keystone_utils
+
+__author__ = 'spisarski'
+
+logger = logging.getLogger('OpenStackNetwork')
+
+
+class OpenStackRouter:
+ """
+ Class responsible for creating a router in OpenStack
+ """
+
+ def __init__(self, os_creds, router_settings):
+ """
+ Constructor - all parameters are required
+ :param os_creds: The credentials to connect with OpenStack
+ :param router_settings: The settings used to create a router object (must be an instance of the
+ RouterSettings class)
+ """
+ self.__os_creds = os_creds
+
+ if not router_settings:
+ raise Exception('router_settings is required')
+
+ self.router_settings = router_settings
+ self.__neutron = neutron_utils.neutron_client(os_creds)
+
+ # Attributes instantiated on create()
+ self.__router = None
+ self.__internal_subnets = list()
+ self.__internal_router_interface = None
+
+ # Dict where the port object is the key and any newly created router interfaces are the value
+ self.__ports = list()
+
+ def create(self, cleanup=False):
+ """
+ Responsible for creating the router.
+ :param cleanup: When true, only perform lookups for OpenStack objects.
+ :return: the router object
+ """
+ logger.debug('Creating Router with name - ' + self.router_settings.name)
+ try:
+ existing = False
+ router_inst = neutron_utils.get_router_by_name(self.__neutron, self.router_settings.name)
+ if router_inst:
+ self.__router = router_inst
+ existing = True
+ else:
+ if not cleanup:
+ self.__router = neutron_utils.create_router(self.__neutron, self.__os_creds, self.router_settings)
+
+ for internal_subnet_name in self.router_settings.internal_subnets:
+ internal_subnet = neutron_utils.get_subnet_by_name(self.__neutron, internal_subnet_name)
+ if internal_subnet:
+ self.__internal_subnets.append(internal_subnet)
+ if internal_subnet and not cleanup and not existing:
+ logger.debug('Adding router to subnet...')
+ self.__internal_router_interface = neutron_utils.add_interface_router(
+ self.__neutron, self.__router, subnet=internal_subnet)
+ else:
+ raise Exception('Subnet not found with name ' + internal_subnet_name)
+
+ for port_setting in self.router_settings.port_settings:
+ port = neutron_utils.get_port_by_name(self.__neutron, port_setting.name)
+ logger.info('Retrieved port ' + port_setting.name + ' for router - ' + self.router_settings.name)
+ if port:
+ self.__ports.append(port)
+
+ if not port and not cleanup and not existing:
+ port = neutron_utils.create_port(self.__neutron, self.__os_creds, port_setting)
+ if port:
+ logger.info('Created port ' + port_setting.name + ' for router - ' + self.router_settings.name)
+ self.__ports.append(port)
+ neutron_utils.add_interface_router(self.__neutron, self.__router, port=port)
+ else:
+ raise Exception('Error creating port with name - ' + port_setting.name)
+
+ return self.__router
+ except Exception as e:
+ self.clean()
+ raise Exception(e.message)
+
+ def clean(self):
+ """
+ Removes and deletes all items created in reverse order.
+ """
+ for port in self.__ports:
+ logger.info('Removing router interface from router ' + self.router_settings.name +
+ ' and port ' + port['port']['name'])
+ try:
+ neutron_utils.remove_interface_router(self.__neutron, self.__router, port=port)
+ except NotFound:
+ pass
+ self.__ports = list()
+
+ for internal_subnet in self.__internal_subnets:
+ logger.info('Removing router interface from router ' + self.router_settings.name +
+ ' and subnet ' + internal_subnet['subnet']['name'])
+ try:
+ neutron_utils.remove_interface_router(self.__neutron, self.__router, subnet=internal_subnet)
+ except NotFound:
+ pass
+ self.__internal_subnets = list()
+
+ if self.__router:
+ logger.info('Removing router ' + self.router_settings.name)
+ try:
+ neutron_utils.delete_router(self.__neutron, self.__router)
+ except NotFound:
+ pass
+ self.__router = None
+
+ def get_router(self):
+ """
+ Returns the OpenStack router object
+ :return:
+ """
+ return self.__router
+
+ def get_internal_router_interface(self):
+ """
+ Returns the OpenStack internal router interface object
+ :return:
+ """
+ return self.__internal_router_interface
+
+
+class RouterSettings:
+ """
+ Class representing a router configuration
+ """
+
+ def __init__(self, config=None, name=None, project_name=None, external_gateway=None,
+ admin_state_up=True, external_fixed_ips=None, internal_subnets=list(),
+ port_settings=list()):
+ """
+ Constructor - all parameters are optional
+ :param config: Should be a dict object containing the configuration settings using the attribute names below
+ as each member's the key and overrides any of the other parameters.
+ :param name: The router name.
+ :param project_name: The name of the project who owns the network. Only administrative users can specify a
+ project ID other than their own. You cannot change this value through authorization
+ policies.
+ :param external_gateway: Name of the external network to which to route
+ :param admin_state_up: The administrative status of the router. True = up / False = down (default True)
+ :param enable_snat: Boolean value. Enable Source NAT (SNAT) attribute. Default is True. To persist this
+ attribute value, set the enable_snat_by_default option in the neutron.conf file.
+ :param external_fixed_ips: Dictionary containing the IP address parameters.
+ :param internal_subnets: List of subnet names to which to connect this router for Floating IP purposes
+ :param port_settings: List of PortSettings objects
+ :return:
+ """
+ if config:
+ self.name = config.get('name')
+ self.project_name = config.get('project_name')
+ self.external_gateway = config.get('external_gateway')
+
+ self.admin_state_up = config.get('admin_state_up')
+ self.enable_snat = config.get('enable_snat')
+ self.external_fixed_ips = config.get('external_fixed_ips')
+ if config.get('internal_subnets'):
+ self.internal_subnets = config['internal_subnets']
+ else:
+ self.internal_subnets = internal_subnets
+
+ self.port_settings = list()
+ if config.get('interfaces'):
+ interfaces = config['interfaces']
+ for interface in interfaces:
+ if interface.get('port'):
+ self.port_settings.append(PortSettings(config=interface['port']))
+ else:
+ self.name = name
+ self.project_name = project_name
+ self.external_gateway = external_gateway
+ self.admin_state_up = admin_state_up
+ self.external_fixed_ips = external_fixed_ips
+ self.internal_subnets = internal_subnets
+ self.port_settings = port_settings
+
+ if not self.name:
+ raise Exception('Name is required')
+
+ def dict_for_neutron(self, neutron, os_creds):
+ """
+ Returns a dictionary object representing this object.
+ This is meant to be converted into JSON designed for use by the Neutron API
+
+ TODO - expand automated testing to exercise all parameters
+ :param neutron: The neutron client to retrieve external network information if necessary
+ :param os_creds: The OpenStack credentials
+ :return: the dictionary object
+ """
+ out = dict()
+ ext_gw = dict()
+
+ project_id = None
+
+ if self.name:
+ out['name'] = self.name
+ if self.project_name:
+ keystone = keystone_utils.keystone_client(os_creds)
+ project = keystone_utils.get_project(keystone, self.project_name)
+ project_id = None
+ if project:
+ project_id = project.id
+ if project_id:
+ out['project_id'] = project_id
+ else:
+ raise Exception('Could not find project ID for project named - ' + self.project_name)
+ if self.admin_state_up is not None:
+ out['admin_state_up'] = self.admin_state_up
+ if self.external_gateway:
+ ext_net = neutron_utils.get_network(neutron, self.external_gateway, project_id)
+ if ext_net:
+ ext_gw['network_id'] = ext_net['network']['id']
+ out['external_gateway_info'] = ext_gw
+ else:
+ raise Exception('Could not find the external network named - ' + self.external_gateway)
+
+ #TODO: Enable SNAT option for Router
+ #TODO: Add external_fixed_ips Tests
+
+ return {'router': out}