diff options
Diffstat (limited to 'aria/multivim-plugin/neutron_plugin/router.py')
-rw-r--r-- | aria/multivim-plugin/neutron_plugin/router.py | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/aria/multivim-plugin/neutron_plugin/router.py b/aria/multivim-plugin/neutron_plugin/router.py new file mode 100644 index 0000000000..1a2851e4bc --- /dev/null +++ b/aria/multivim-plugin/neutron_plugin/router.py @@ -0,0 +1,215 @@ +######### +# Copyright (c) 2014 GigaSpaces Technologies Ltd. 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 warnings + +from cloudify import ctx +from cloudify.decorators import operation +from cloudify.exceptions import NonRecoverableError + +from openstack_plugin_common import ( + provider, + transform_resource_name, + get_resource_id, + with_neutron_client, + use_external_resource, + is_external_relationship, + is_external_relationship_not_conditionally_created, + delete_runtime_properties, + get_openstack_ids_of_connected_nodes_by_openstack_type, + delete_resource_and_runtime_properties, + get_resource_by_name_or_id, + validate_resource, + COMMON_RUNTIME_PROPERTIES_KEYS, + OPENSTACK_ID_PROPERTY, + OPENSTACK_TYPE_PROPERTY, + OPENSTACK_NAME_PROPERTY +) + +from neutron_plugin.network import NETWORK_OPENSTACK_TYPE + + +ROUTER_OPENSTACK_TYPE = 'router' + +# Runtime properties +RUNTIME_PROPERTIES_KEYS = COMMON_RUNTIME_PROPERTIES_KEYS + + +@operation +@with_neutron_client +def create(neutron_client, args, **kwargs): + + if use_external_resource(ctx, neutron_client, ROUTER_OPENSTACK_TYPE): + try: + ext_net_id_by_rel = _get_connected_ext_net_id(neutron_client) + + if ext_net_id_by_rel: + router_id = \ + ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] + + router = neutron_client.show_router(router_id)['router'] + if not (router['external_gateway_info'] and 'network_id' in + router['external_gateway_info'] and + router['external_gateway_info']['network_id'] == + ext_net_id_by_rel): + raise NonRecoverableError( + 'Expected external resources router {0} and ' + 'external network {1} to be connected'.format( + router_id, ext_net_id_by_rel)) + return + except Exception: + delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS) + raise + + router = { + 'name': get_resource_id(ctx, ROUTER_OPENSTACK_TYPE), + } + router.update(ctx.node.properties['router'], **args) + transform_resource_name(ctx, router) + + _handle_external_network_config(router, neutron_client) + + r = neutron_client.create_router({'router': router})['router'] + + ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = r['id'] + ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] =\ + ROUTER_OPENSTACK_TYPE + ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = r['name'] + + +@operation +@with_neutron_client +def connect_subnet(neutron_client, **kwargs): + router_id = ctx.target.instance.runtime_properties[OPENSTACK_ID_PROPERTY] + subnet_id = ctx.source.instance.runtime_properties[OPENSTACK_ID_PROPERTY] + + if is_external_relationship_not_conditionally_created(ctx): + ctx.logger.info('Validating external subnet and router ' + 'are associated') + for port in neutron_client.list_ports(device_id=router_id)['ports']: + for fixed_ip in port.get('fixed_ips', []): + if fixed_ip.get('subnet_id') == subnet_id: + return + raise NonRecoverableError( + 'Expected external resources router {0} and subnet {1} to be ' + 'connected'.format(router_id, subnet_id)) + + neutron_client.add_interface_router(router_id, {'subnet_id': subnet_id}) + + +@operation +@with_neutron_client +def disconnect_subnet(neutron_client, **kwargs): + if is_external_relationship(ctx): + ctx.logger.info('Not connecting subnet and router since external ' + 'subnet and router are being used') + return + + neutron_client.remove_interface_router( + ctx.target.instance.runtime_properties[OPENSTACK_ID_PROPERTY], { + 'subnet_id': ctx.source.instance.runtime_properties[ + OPENSTACK_ID_PROPERTY] + } + ) + + +@operation +@with_neutron_client +def delete(neutron_client, **kwargs): + delete_resource_and_runtime_properties(ctx, neutron_client, + RUNTIME_PROPERTIES_KEYS) + + +@operation +@with_neutron_client +def creation_validation(neutron_client, **kwargs): + validate_resource(ctx, neutron_client, ROUTER_OPENSTACK_TYPE) + + +def _insert_ext_net_id_to_router_config(ext_net_id, router): + router['external_gateway_info'] = router.get( + 'external_gateway_info', {}) + router['external_gateway_info']['network_id'] = ext_net_id + + +def _handle_external_network_config(router, neutron_client): + # attempting to find an external network for the router to connect to - + # first by either a network name or id passed in explicitly; then by a + # network connected by a relationship; with a final optional fallback to an + # external network set in the Provider-context. Otherwise the router will + # simply not get connected to an external network + + provider_context = provider(ctx) + + ext_net_id_by_rel = _get_connected_ext_net_id(neutron_client) + ext_net_by_property = ctx.node.properties['external_network'] + + # the following is meant for backwards compatibility with the + # 'network_name' sugaring + if 'external_gateway_info' in router and 'network_name' in \ + router['external_gateway_info']: + warnings.warn( + 'Passing external "network_name" inside the ' + 'external_gateway_info key of the "router" property is now ' + 'deprecated; Use the "external_network" property instead', + DeprecationWarning) + + ext_net_by_property = router['external_gateway_info']['network_name'] + del (router['external_gateway_info']['network_name']) + + # need to check if the user explicitly passed network_id in the external + # gateway configuration as it affects external network behavior by + # relationship and/or provider context + if 'external_gateway_info' in router and 'network_id' in \ + router['external_gateway_info']: + ext_net_by_property = router['external_gateway_info']['network_name'] + + if ext_net_by_property and ext_net_id_by_rel: + raise RuntimeError( + "Router can't have an external network connected by both a " + 'relationship and by a network name/id') + + if ext_net_by_property: + ext_net_id = get_resource_by_name_or_id( + ext_net_by_property, NETWORK_OPENSTACK_TYPE, neutron_client)['id'] + _insert_ext_net_id_to_router_config(ext_net_id, router) + elif ext_net_id_by_rel: + _insert_ext_net_id_to_router_config(ext_net_id_by_rel, router) + elif ctx.node.properties['default_to_managers_external_network'] and \ + provider_context.ext_network: + _insert_ext_net_id_to_router_config(provider_context.ext_network['id'], + router) + + +def _check_if_network_is_external(neutron_client, network_id): + return neutron_client.show_network( + network_id)['network']['router:external'] + + +def _get_connected_ext_net_id(neutron_client): + ext_net_ids = \ + [net_id + for net_id in + get_openstack_ids_of_connected_nodes_by_openstack_type( + ctx, NETWORK_OPENSTACK_TYPE) if + _check_if_network_is_external(neutron_client, net_id)] + + if len(ext_net_ids) > 1: + raise NonRecoverableError( + 'More than one external network is connected to router {0}' + ' by a relationship; External network IDs: {0}'.format( + ext_net_ids)) + + return ext_net_ids[0] if ext_net_ids else None |