aboutsummaryrefslogtreecommitdiffstats
path: root/aria/multivim-plugin/neutron_plugin/router.py
diff options
context:
space:
mode:
Diffstat (limited to 'aria/multivim-plugin/neutron_plugin/router.py')
-rw-r--r--aria/multivim-plugin/neutron_plugin/router.py215
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