Change-Id: I775988fbb97070f3df4140acbaffa30b36196238changes/14/104814/1
parent
d915ab59c3
commit
a7b1f969fe
@ -1,163 +0,0 @@
|
||||
# Copyright (c) 2013 OpenStack Foundation.
|
||||
#
|
||||
# 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 abc
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.v2 import attributes as attr
|
||||
from neutron.api.v2 import base
|
||||
from neutron.common import exceptions
|
||||
from neutron import manager
|
||||
|
||||
|
||||
# Attribute Map
|
||||
RESOURCE_NAME = 'agent'
|
||||
RESOURCE_ATTRIBUTE_MAP = {
|
||||
RESOURCE_NAME + 's': {
|
||||
'id': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True},
|
||||
'agent_type': {'allow_post': False, 'allow_put': False,
|
||||
'is_visible': True},
|
||||
'binary': {'allow_post': False, 'allow_put': False,
|
||||
'is_visible': True},
|
||||
'topic': {'allow_post': False, 'allow_put': False,
|
||||
'is_visible': True},
|
||||
'host': {'allow_post': False, 'allow_put': False,
|
||||
'is_visible': True},
|
||||
'admin_state_up': {'allow_post': False, 'allow_put': True,
|
||||
'convert_to': attr.convert_to_boolean,
|
||||
'is_visible': True},
|
||||
'created_at': {'allow_post': False, 'allow_put': False,
|
||||
'is_visible': True},
|
||||
'started_at': {'allow_post': False, 'allow_put': False,
|
||||
'is_visible': True},
|
||||
'heartbeat_timestamp': {'allow_post': False, 'allow_put': False,
|
||||
'is_visible': True},
|
||||
'alive': {'allow_post': False, 'allow_put': False,
|
||||
'is_visible': True},
|
||||
'configurations': {'allow_post': False, 'allow_put': False,
|
||||
'is_visible': True},
|
||||
'description': {'allow_post': False, 'allow_put': True,
|
||||
'is_visible': True,
|
||||
'validate': {'type:string': None}},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class AgentNotFound(exceptions.NotFound):
|
||||
message = _("Agent %(id)s could not be found")
|
||||
|
||||
|
||||
class AgentNotFoundByTypeHost(exceptions.NotFound):
|
||||
message = _("Agent with agent_type=%(agent_type)s and host=%(host)s "
|
||||
"could not be found")
|
||||
|
||||
|
||||
class MultipleAgentFoundByTypeHost(exceptions.Conflict):
|
||||
message = _("Multiple agents with agent_type=%(agent_type)s and "
|
||||
"host=%(host)s found")
|
||||
|
||||
|
||||
class Agent(object):
|
||||
"""Agent management extension."""
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "agent"
|
||||
|
||||
@classmethod
|
||||
def get_alias(cls):
|
||||
return "agent"
|
||||
|
||||
@classmethod
|
||||
def get_description(cls):
|
||||
return "The agent management extension."
|
||||
|
||||
@classmethod
|
||||
def get_namespace(cls):
|
||||
return "http://docs.openstack.org/ext/agent/api/v2.0"
|
||||
|
||||
@classmethod
|
||||
def get_updated(cls):
|
||||
return "2013-02-03T10:00:00-00:00"
|
||||
|
||||
@classmethod
|
||||
def get_resources(cls):
|
||||
"""Returns Ext Resources."""
|
||||
my_plurals = [(key, key[:-1]) for key in RESOURCE_ATTRIBUTE_MAP.keys()]
|
||||
attr.PLURALS.update(dict(my_plurals))
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
params = RESOURCE_ATTRIBUTE_MAP.get(RESOURCE_NAME + 's')
|
||||
controller = base.create_resource(RESOURCE_NAME + 's',
|
||||
RESOURCE_NAME,
|
||||
plugin, params
|
||||
)
|
||||
|
||||
ex = extensions.ResourceExtension(RESOURCE_NAME + 's',
|
||||
controller)
|
||||
|
||||
return [ex]
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
return RESOURCE_ATTRIBUTE_MAP
|
||||
else:
|
||||
return {}
|
||||
|
||||
|
||||
class AgentPluginBase(object):
|
||||
"""REST API to operate the Agent.
|
||||
|
||||
All of method must be in an admin context.
|
||||
"""
|
||||
|
||||
def create_agent(self, context, agent):
|
||||
"""Create agent.
|
||||
|
||||
This operation is not allow in REST API.
|
||||
@raise exceptions.BadRequest:
|
||||
"""
|
||||
raise exceptions.BadRequest
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_agent(self, context, id):
|
||||
"""Delete agent.
|
||||
|
||||
Agents register themselves on reporting state.
|
||||
But if a agent does not report its status
|
||||
for a long time (for example, it is dead for ever. ),
|
||||
admin can remove it. Agents must be disabled before
|
||||
being removed.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_agent(self, context, agent):
|
||||
"""Disable or Enable the agent.
|
||||
|
||||
Discription also can be updated. Some agents cannot be disabled, such
|
||||
as plugins, services. An error code should be reported in this case.
|
||||
@raise exceptions.BadRequest:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_agents(self, context, filters=None, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_agent(self, context, id, fields=None):
|
||||
pass
|
@ -1,116 +0,0 @@
|
||||
# Copyright 2013 VMware, Inc. 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 webob.exc
|
||||
|
||||
from neutron.api.v2 import attributes as attr
|
||||
from neutron.common import exceptions as nexception
|
||||
|
||||
|
||||
class AllowedAddressPairsMissingIP(nexception.InvalidInput):
|
||||
message = _("AllowedAddressPair must contain ip_address")
|
||||
|
||||
|
||||
class AddressPairAndPortSecurityRequired(nexception.Conflict):
|
||||
message = _("Port Security must be enabled in order to have allowed "
|
||||
"address pairs on a port.")
|
||||
|
||||
|
||||
class DuplicateAddressPairInRequest(nexception.InvalidInput):
|
||||
message = _("Request contains duplicate address pair: "
|
||||
"mac_address %(mac_address)s ip_address %(ip_address)s.")
|
||||
|
||||
|
||||
def _validate_allowed_address_pairs(address_pairs, valid_values=None):
|
||||
unique_check = {}
|
||||
for address_pair in address_pairs:
|
||||
# mac_address is optional, if not set we use the mac on the port
|
||||
if 'mac_address' in address_pair:
|
||||
msg = attr._validate_mac_address(address_pair['mac_address'])
|
||||
if msg:
|
||||
raise webob.exc.HTTPBadRequest(msg)
|
||||
if 'ip_address' not in address_pair:
|
||||
raise AllowedAddressPairsMissingIP()
|
||||
|
||||
mac = address_pair.get('mac_address')
|
||||
ip_address = address_pair['ip_address']
|
||||
if (mac, ip_address) not in unique_check:
|
||||
unique_check[(mac, ip_address)] = None
|
||||
else:
|
||||
raise DuplicateAddressPairInRequest(mac_address=mac,
|
||||
ip_address=ip_address)
|
||||
|
||||
invalid_attrs = set(address_pair.keys()) - set(['mac_address',
|
||||
'ip_address'])
|
||||
if invalid_attrs:
|
||||
msg = (_("Unrecognized attribute(s) '%s'") %
|
||||
', '.join(set(address_pair.keys()) -
|
||||
set(['mac_address', 'ip_address'])))
|
||||
raise webob.exc.HTTPBadRequest(msg)
|
||||
|
||||
if '/' in ip_address:
|
||||
msg = attr._validate_subnet(ip_address)
|
||||
else:
|
||||
msg = attr._validate_ip_address(ip_address)
|
||||
if msg:
|
||||
raise webob.exc.HTTPBadRequest(msg)
|
||||
|
||||
attr.validators['type:validate_allowed_address_pairs'] = (
|
||||
_validate_allowed_address_pairs)
|
||||
|
||||
ADDRESS_PAIRS = 'allowed_address_pairs'
|
||||
EXTENDED_ATTRIBUTES_2_0 = {
|
||||
'ports': {
|
||||
ADDRESS_PAIRS: {'allow_post': True, 'allow_put': True,
|
||||
'convert_list_to':
|
||||
attr.convert_kvp_list_to_dict,
|
||||
'validate': {'type:validate_allowed_address_pairs':
|
||||
None},
|
||||
'enforce_policy': True,
|
||||
'default': attr.ATTR_NOT_SPECIFIED,
|
||||
'is_visible': True},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Allowedaddresspairs(object):
|
||||
"""Extension class supporting allowed address pairs."""
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "Allowed Address Pairs"
|
||||
|
||||
@classmethod
|
||||
def get_alias(cls):
|
||||
return "allowed-address-pairs"
|
||||
|
||||
@classmethod
|
||||
def get_description(cls):
|
||||
return "Provides allowed address pairs"
|
||||
|
||||
@classmethod
|
||||
def get_namespace(cls):
|
||||
return "http://docs.openstack.org/ext/allowedaddresspairs/api/v2.0"
|
||||
|
||||
@classmethod
|
||||
def get_updated(cls):
|
||||
return "2013-07-23T10:00:00-00:00"
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
attr.PLURALS.update({'allowed_address_pairs':
|
||||
'allowed_address_pair'})
|
||||
return EXTENDED_ATTRIBUTES_2_0
|
||||
else:
|
||||
return {}
|
@ -1,152 +0,0 @@
|
||||
# Copyright (c) 2013 OpenStack Foundation.
|
||||
# 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 abc
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.v2 import base
|
||||
from neutron.api.v2 import resource
|
||||
from neutron.common import constants
|
||||
from neutron.common import exceptions
|
||||
from neutron.extensions import agent
|
||||
from neutron import manager
|
||||
from neutron import policy
|
||||
from neutron import wsgi
|
||||
|
||||
DHCP_NET = 'dhcp-network'
|
||||
DHCP_NETS = DHCP_NET + 's'
|
||||
DHCP_AGENT = 'dhcp-agent'
|
||||
DHCP_AGENTS = DHCP_AGENT + 's'
|
||||
|
||||
|
||||
class NetworkSchedulerController(wsgi.Controller):
|
||||
def index(self, request, **kwargs):
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
policy.enforce(request.context,
|
||||
"get_%s" % DHCP_NETS,
|
||||
{})
|
||||
return plugin.list_networks_on_dhcp_agent(
|
||||
request.context, kwargs['agent_id'])
|
||||
|
||||
def create(self, request, body, **kwargs):
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
policy.enforce(request.context,
|
||||
"create_%s" % DHCP_NET,
|
||||
{})
|
||||
return plugin.add_network_to_dhcp_agent(
|
||||
request.context, kwargs['agent_id'], body['network_id'])
|
||||
|
||||
def delete(self, request, id, **kwargs):
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
policy.enforce(request.context,
|
||||
"delete_%s" % DHCP_NET,
|
||||
{})
|
||||
return plugin.remove_network_from_dhcp_agent(
|
||||
request.context, kwargs['agent_id'], id)
|
||||
|
||||
|
||||
class DhcpAgentsHostingNetworkController(wsgi.Controller):
|
||||
def index(self, request, **kwargs):
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
policy.enforce(request.context,
|
||||
"get_%s" % DHCP_AGENTS,
|
||||
{})
|
||||
return plugin.list_dhcp_agents_hosting_network(
|
||||
request.context, kwargs['network_id'])
|
||||
|
||||
|
||||
class Dhcpagentscheduler(extensions.ExtensionDescriptor):
|
||||
"""Extension class supporting dhcp agent scheduler.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "DHCP Agent Scheduler"
|
||||
|
||||
@classmethod
|
||||
def get_alias(cls):
|
||||
return constants.DHCP_AGENT_SCHEDULER_EXT_ALIAS
|
||||
|
||||
@classmethod
|
||||
def get_description(cls):
|
||||
return "Schedule networks among dhcp agents"
|
||||
|
||||
@classmethod
|
||||
def get_namespace(cls):
|
||||
return "http://docs.openstack.org/ext/dhcp_agent_scheduler/api/v1.0"
|
||||
|
||||
@classmethod
|
||||
def get_updated(cls):
|
||||
return "2013-02-07T10:00:00-00:00"
|
||||
|
||||
@classmethod
|
||||
def get_resources(cls):
|
||||
"""Returns Ext Resources."""
|
||||
exts = []
|
||||
parent = dict(member_name="agent",
|
||||
collection_name="agents")
|
||||
controller = resource.Resource(NetworkSchedulerController(),
|
||||
base.FAULT_MAP)
|
||||
exts.append(extensions.ResourceExtension(
|
||||
DHCP_NETS, controller, parent))
|
||||
|
||||
parent = dict(member_name="network",
|
||||
collection_name="networks")
|
||||
|
||||
controller = resource.Resource(DhcpAgentsHostingNetworkController(),
|
||||
base.FAULT_MAP)
|
||||
exts.append(extensions.ResourceExtension(
|
||||
DHCP_AGENTS, controller, parent))
|
||||
return exts
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
return {}
|
||||
|
||||
|
||||
class InvalidDHCPAgent(agent.AgentNotFound):
|
||||
message = _("Agent %(id)s is not a valid DHCP Agent or has been disabled")
|
||||
|
||||
|
||||
class NetworkHostedByDHCPAgent(exceptions.Conflict):
|
||||
message = _("The network %(network_id)s has been already hosted"
|
||||
" by the DHCP Agent %(agent_id)s.")
|
||||
|
||||
|
||||
class NetworkNotHostedByDhcpAgent(exceptions.Conflict):
|
||||
message = _("The network %(network_id)s is not hosted"
|
||||
" by the DHCP agent %(agent_id)s.")
|
||||
|
||||
|
||||
class DhcpAgentSchedulerPluginBase(object):
|
||||
"""REST API to operate the DHCP agent scheduler.
|
||||
|
||||
All of method must be in an admin context.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def add_network_to_dhcp_agent(self, context, id, network_id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def remove_network_from_dhcp_agent(self, context, id, network_id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def list_networks_on_dhcp_agent(self, context, id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def list_dhcp_agents_hosting_network(self, context, network_id):
|
||||
pass
|
@ -1,68 +0,0 @@
|
||||
# Copyright (c) 2013 OpenStack Foundation.
|
||||
# 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.
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.v2 import attributes as attr
|
||||
from neutron.common import exceptions as qexception
|
||||
from neutron.extensions import l3
|
||||
|
||||
|
||||
class ExternalNetworkInUse(qexception.InUse):
|
||||
message = _("External network %(net_id)s cannot be updated to be made "
|
||||
"non-external, since it has existing gateway ports")
|
||||
|
||||
|
||||
# For backward compatibility the 'router' prefix is kept.
|
||||
EXTERNAL = 'router:external'
|
||||
EXTENDED_ATTRIBUTES_2_0 = {
|
||||
'networks': {EXTERNAL: {'allow_post': True,
|
||||
'allow_put': True,
|
||||
'default': attr.ATTR_NOT_SPECIFIED,
|
||||
'is_visible': True,
|
||||
'convert_to': attr.convert_to_boolean,
|
||||
'enforce_policy': True,
|
||||
'required_by_policy': True}}}
|
||||
|
||||
|
||||
class External_net(extensions.ExtensionDescriptor):
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "Neutron external network"
|
||||
|
||||
@classmethod
|
||||
def get_alias(cls):
|
||||
return "external-net"
|
||||
|
||||
@classmethod
|
||||
def get_description(cls):
|
||||
return _("Adds external network attribute to network resource.")
|
||||
|
||||
@classmethod
|
||||
def get_namespace(cls):
|
||||
return "http://docs.openstack.org/ext/neutron/external_net/api/v1.0"
|
||||
|
||||
@classmethod
|
||||
def get_updated(cls):
|
||||
return "2013-01-14T10:00:00-00:00"
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
return EXTENDED_ATTRIBUTES_2_0
|
||||
else:
|
||||
return {}
|
||||
|
||||
def get_alias_namespace_compatibility_map(self):
|
||||
return {l3.L3.get_alias(): l3.L3.get_namespace()}
|
@ -1,91 +0,0 @@
|
||||
# Copyright (c) 2013 OpenStack Foundation.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# @Author Don Kehn, dekehn@gmail.com
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.v2 import attributes as attr
|
||||
from neutron.common import exceptions
|
||||
|
||||
|
||||
# ExtraDHcpOpts Exceptions
|
||||
class ExtraDhcpOptNotFound(exceptions.NotFound):
|
||||
message = _("ExtraDhcpOpt %(id)s could not be found")
|
||||
|
||||
|
||||
class ExtraDhcpOptBadData(exceptions.InvalidInput):
|
||||
message = _("Invalid data format for extra-dhcp-opt: %(data)s")
|
||||
|
||||
|
||||
def _validate_list_of_dict_or_none(data, key_specs=None):
|
||||
if data is not None:
|
||||
if not isinstance(data, list):
|
||||
raise ExtraDhcpOptBadData(data=data)
|
||||
for d in data:
|
||||
msg = attr._validate_dict(d, key_specs)
|
||||
if msg:
|
||||
raise ExtraDhcpOptBadData(data=msg)
|
||||
|
||||
|
||||
attr.validators['type:list_of_dict_or_none'] = _validate_list_of_dict_or_none
|
||||
|
||||
# Attribute Map
|
||||
EXTRADHCPOPTS = 'extra_dhcp_opts'
|
||||
|
||||
EXTENDED_ATTRIBUTES_2_0 = {
|
||||
'ports': {
|
||||
EXTRADHCPOPTS:
|
||||
{'allow_post': True,
|
||||
'allow_put': True,
|
||||
'is_visible': True,
|
||||
'default': None,
|
||||
'validate': {
|
||||
'type:list_of_dict_or_none': {
|
||||
'id': {'type:uuid': None, 'required': False},
|
||||
'opt_name': {'type:not_empty_string': None,
|
||||
'required': True},
|
||||
'opt_value': {'type:not_empty_string_or_none': None,
|
||||
'required': True}}}}}}
|
||||
|
||||
|
||||
class Extra_dhcp_opt(extensions.ExtensionDescriptor):
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "Neutron Extra DHCP opts"
|
||||
|
||||
@classmethod
|
||||
def get_alias(cls):
|
||||
return "extra_dhcp_opt"
|
||||
|
||||
@classmethod
|
||||
def get_description(cls):
|
||||
return ("Extra options configuration for DHCP. "
|
||||
"For example PXE boot options to DHCP clients can "
|
||||
"be specified (e.g. tftp-server, server-ip-address, "
|
||||
"bootfile-name)")
|
||||
|
||||
@classmethod
|
||||
def get_namespace(cls):
|
||||
return "http://docs.openstack.org/ext/neutron/extra_dhcp_opt/api/v1.0"
|
||||
|
||||
@classmethod
|
||||
def get_updated(cls):
|
||||
return "2013-03-17T12:00:00-00:00"
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
return EXTENDED_ATTRIBUTES_2_0
|
||||
else:
|
||||
return {}
|
@ -1,74 +0,0 @@
|
||||
# Copyright 2013, Nachi Ueno, NTT MCL, Inc.
|
||||
# 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.
|
||||
|
||||
|
||||
from neutron.api.v2 import attributes as attr
|
||||
from neutron.common import exceptions as qexception
|
||||
|
||||
|
||||
# Extra Routes Exceptions
|
||||
class InvalidRoutes(qexception.InvalidInput):
|
||||
message = _("Invalid format for routes: %(routes)s, %(reason)s")
|
||||
|
||||
|
||||
class RouterInterfaceInUseByRoute(qexception.InUse):
|
||||
message = _("Router interface for subnet %(subnet_id)s on router "
|
||||
"%(router_id)s cannot be deleted, as it is required "
|
||||
"by one or more routes.")
|
||||
|
||||
|
||||
class RoutesExhausted(qexception.BadRequest):
|
||||
message = _("Unable to complete operation for %(router_id)s. "
|
||||
"The number of routes exceeds the maximum %(quota)s.")
|
||||
|
||||
# Attribute Map
|
||||
EXTENDED_ATTRIBUTES_2_0 = {
|
||||
'routers': {
|
||||
'routes': {'allow_post': False, 'allow_put': True,
|
||||
'validate': {'type:hostroutes': None},
|
||||
'convert_to': attr.convert_none_to_empty_list,
|
||||
'is_visible': True, 'default': attr.ATTR_NOT_SPECIFIED},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Extraroute():
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "Neutron Extra Route"
|
||||
|
||||
@classmethod
|
||||
def get_alias(cls):
|
||||
return "extraroute"
|
||||
|
||||
@classmethod
|
||||
def get_description(cls):
|
||||
return "Extra routes configuration for L3 router"
|
||||
|
||||
@classmethod
|
||||
def get_namespace(cls):
|
||||
return "http://docs.openstack.org/ext/neutron/extraroutes/api/v1.0"
|
||||
|
||||
@classmethod
|
||||
def get_updated(cls):
|
||||
return "2013-02-01T10:00:00-00:00"
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
attr.PLURALS.update({'routes': 'route'})
|
||||
return EXTENDED_ATTRIBUTES_2_0
|
||||
else:
|
||||
return {}
|
@ -1,431 +0,0 @@
|
||||
# Copyright 2013 Big Switch Networks, Inc.
|
||||
# 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.
|
||||
#
|
||||
# @author: Sumit Naiksatam, sumitnaiksatam@gmail.com, Big Switch Networks, Inc.
|
||||
|
||||
import abc
|
||||
|
||||
from oslo.config import cfg
|
||||
import six
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.v2 import attributes as attr
|
||||
from neutron.api.v2 import resource_helper
|
||||
from neutron.common import exceptions as qexception
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.plugins.common import constants
|
||||
from neutron.services import service_base
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Firewall Exceptions
|
||||
class FirewallNotFound(qexception.NotFound):
|
||||
message = _("Firewall %(firewall_id)s could not be found.")
|
||||
|
||||
|
||||
class FirewallInUse(qexception.InUse):
|
||||
message = _("Firewall %(firewall_id)s is still active.")
|
||||
|
||||
|
||||
class FirewallInPendingState(qexception.Conflict):
|
||||
message = _("Operation cannot be performed since associated Firewall "
|
||||
"%(firewall_id)s is in %(pending_state)s.")
|
||||
|
||||
|
||||
class FirewallPolicyNotFound(qexception.NotFound):
|
||||
message = _("Firewall Policy %(firewall_policy_id)s could not be found.")
|
||||
|
||||
|
||||
class FirewallPolicyInUse(qexception.InUse):
|
||||
message = _("Firewall Policy %(firewall_policy_id)s is being used.")
|
||||
|
||||
|
||||
class FirewallRuleNotFound(qexception.NotFound):
|
||||
message = _("Firewall Rule %(firewall_rule_id)s could not be found.")
|
||||
|
||||
|
||||
class FirewallRuleInUse(qexception.InUse):
|
||||
message = _("Firewall Rule %(firewall_rule_id)s is being used.")
|
||||
|
||||
|
||||
class FirewallRuleNotAssociatedWithPolicy(qexception.InvalidInput):
|
||||
message = _("Firewall Rule %(firewall_rule_id)s is not associated "
|
||||
" with Firewall Policy %(firewall_policy_id)s.")
|
||||
|
||||
|
||||
class FirewallRuleInvalidProtocol(qexception.InvalidInput):
|
||||
message = _("Firewall Rule protocol %(protocol)s is not supported. "
|
||||
"Only protocol values %(values)s and their integer "
|
||||
"representation (0 to 255) are supported.")
|
||||
|
||||
|
||||
class FirewallRuleInvalidAction(qexception.InvalidInput):
|
||||
message = _("Firewall rule action %(action)s is not supported. "
|
||||
"Only action values %(values)s are supported.")
|
||||
|
||||
|
||||
class FirewallRuleInvalidICMPParameter(qexception.InvalidInput):
|
||||
message = _("%(param)s are not allowed when protocol "
|
||||
"is set to ICMP.")
|
||||
|
||||
|
||||
class FirewallInvalidPortValue(qexception.InvalidInput):
|
||||
message = _("Invalid value for port %(port)s.")
|
||||
|
||||
|
||||
class FirewallRuleInfoMissing(qexception.InvalidInput):
|
||||
message = _("Missing rule info argument for insert/remove "
|
||||
"rule operation.")
|
||||
|
||||
|
||||
class FirewallInternalDriverError(qexception.NeutronException):
|
||||
"""Fwaas exception for all driver errors.
|
||||
|
||||
On any failure or exception in the driver, driver should log it and
|
||||
raise this exception to the agent
|
||||
"""
|
||||
message = _("%(driver)s: Internal driver error.")
|
||||
|
||||
|
||||
fw_valid_protocol_values = [None, constants.TCP, constants.UDP, constants.ICMP]
|
||||
fw_valid_action_values = [constants.FWAAS_ALLOW, constants.FWAAS_DENY]
|
||||
|
||||
|
||||
def convert_protocol(value):
|
||||
if value is None:
|
||||
return
|
||||
if value.isdigit():
|
||||
val = int(value)
|
||||
if 0 <= val <= 255:
|
||||
return val
|
||||
else:
|
||||
raise FirewallRuleInvalidProtocol(protocol=value,
|
||||
values=
|
||||
fw_valid_protocol_values)
|
||||
elif value.lower() in fw_valid_protocol_values:
|
||||
return value.lower()
|
||||
else:
|
||||
raise FirewallRuleInvalidProtocol(protocol=value,
|
||||
values=
|
||||
fw_valid_protocol_values)
|
||||
|
||||
|
||||
def convert_action_to_case_insensitive(value):
|
||||
if value is None:
|
||||
return
|
||||
else:
|
||||
return value.lower()
|
||||
|
||||
|
||||
def convert_port_to_string(value):
|
||||
if value is None:
|
||||
return
|
||||
else:
|
||||
return str(value)
|
||||
|
||||
|
||||
def _validate_port_range(data, key_specs=None):
|
||||
if data is None:
|
||||
return
|
||||
data = str(data)
|
||||
ports = data.split(':')
|
||||
for p in ports:
|
||||
try:
|
||||
val = int(p)
|
||||
except (ValueError, TypeError):
|
||||
msg = _("Port '%s' is not a valid number") % p
|
||||
LOG.debug(msg)
|
||||
return msg
|
||||
if val <= 0 or val > 65535:
|
||||
msg = _("Invalid port '%s'") % p
|
||||
LOG.debug(msg)
|
||||
return msg
|
||||
|
||||
|
||||
def _validate_ip_or_subnet_or_none(data, valid_values=None):
|
||||
if data is None:
|
||||
return None
|
||||
msg_ip = attr._validate_ip_address(data, valid_values)
|
||||
if not msg_ip:
|
||||
return
|
||||
msg_subnet = attr._validate_subnet(data, valid_values)
|
||||
if not msg_subnet:
|
||||
return
|
||||
return _("%(msg_ip)s and %(msg_subnet)s") % {'msg_ip': msg_ip,
|
||||
'msg_subnet': msg_subnet}
|
||||
|
||||
|
||||
attr.validators['type:port_range'] = _validate_port_range
|
||||
attr.validators['type:ip_or_subnet_or_none'] = _validate_ip_or_subnet_or_none
|
||||
|
||||
|
||||
RESOURCE_ATTRIBUTE_MAP = {
|
||||
'firewall_rules': {
|
||||
'id': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True, 'primary_key': True},
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'required_by_policy': True,
|
||||
'is_visible': True},
|
||||
'name': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'description': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'firewall_policy_id': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid_or_none': None},
|
||||
'is_visible': True},
|
||||
'shared': {'allow_post': True, 'allow_put': True,
|
||||
'default': False, 'convert_to': attr.convert_to_boolean,
|
||||
'is_visible': True, 'required_by_policy': True,
|
||||
'enforce_policy': True},
|
||||
'protocol': {'allow_post': True, 'allow_put': True,
|
||||
'is_visible': True, 'default': None,
|
||||
'convert_to': convert_protocol,
|
||||
'validate': {'type:values': fw_valid_protocol_values}},
|
||||
'ip_version': {'allow_post': True, 'allow_put': True,
|
||||
'default': 4, 'convert_to': attr.convert_to_int,
|
||||
'validate': {'type:values': [4, 6]},
|
||||
'is_visible': True},
|
||||
'source_ip_address': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:ip_or_subnet_or_none': None},
|
||||
'is_visible': True, 'default': None},
|
||||
'destination_ip_address': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:ip_or_subnet_or_none':
|
||||
None},
|
||||
'is_visible': True, 'default': None},
|
||||
'source_port': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:port_range': None},
|
||||
'convert_to': convert_port_to_string,
|
||||
'default': None, 'is_visible': True},
|
||||
'destination_port': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:port_range': None},
|
||||
'convert_to': convert_port_to_string,
|
||||
'default': None, 'is_visible': True},
|
||||
'position': {'allow_post': False, 'allow_put': False,
|
||||
'default': None, 'is_visible': True},
|
||||
'action': {'allow_post': True, 'allow_put': True,
|
||||
'convert_to': convert_action_to_case_insensitive,
|
||||
'validate': {'type:values': fw_valid_action_values},
|
||||
'is_visible': True, 'default': 'deny'},
|
||||
'enabled': {'allow_post': True, 'allow_put': True,
|
||||
'default': True, 'convert_to': attr.convert_to_boolean,
|
||||
'is_visible': True},
|
||||
},
|
||||
'firewall_policies': {
|
||||
'id': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True,
|
||||
'primary_key': True},
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'required_by_policy': True,
|
||||
'is_visible': True},
|
||||
'name': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'description': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'shared': {'allow_post': True, 'allow_put': True,
|
||||
'default': False, 'convert_to': attr.convert_to_boolean,
|
||||
'is_visible': True, 'required_by_policy': True,
|
||||
'enforce_policy': True},
|
||||
'firewall_rules': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:uuid_list': None},
|
||||
'convert_to': attr.convert_none_to_empty_list,
|
||||
'default': None, 'is_visible': True},
|
||||
'audited': {'allow_post': True, 'allow_put': True,
|
||||
'default': False, 'convert_to': attr.convert_to_boolean,
|
||||
'is_visible': True},
|
||||
},
|
||||
'firewalls': {
|
||||
'id': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True,
|
||||
'primary_key': True},
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'required_by_policy': True,
|
||||
'is_visible': True},
|
||||
'name': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'description': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'admin_state_up': {'allow_post': True, 'allow_put': True,
|
||||
'default': True,
|
||||
'convert_to': attr.convert_to_boolean,
|
||||
'is_visible': True},
|
||||
'status': {'allow_post': False, 'allow_put': False,
|
||||
'is_visible': True},
|
||||
'shared': {'allow_post': True, 'allow_put': True,
|
||||
'default': False, 'convert_to': attr.convert_to_boolean,
|
||||
'is_visible': False, 'required_by_policy': True,
|
||||
'enforce_policy': True},
|
||||
'firewall_policy_id': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:uuid_or_none': None},
|
||||
'is_visible': True},
|
||||
},
|
||||
}
|
||||
|
||||
firewall_quota_opts = [
|
||||
cfg.IntOpt('quota_firewall',
|
||||
default=1,
|
||||
help=_('Number of firewalls allowed per tenant. '
|
||||
'A negative value means unlimited.')),
|
||||
cfg.IntOpt('quota_firewall_policy',
|
||||
default=1,
|
||||
help=_('Number of firewall policies allowed per tenant. '
|
||||
'A negative value means unlimited.')),
|
||||
cfg.IntOpt('quota_firewall_rule',
|
||||
default=-1,
|
||||
help=_('Number of firewall rules allowed per tenant. '
|
||||
'A negative value means unlimited.')),
|
||||
]
|
||||
cfg.CONF.register_opts(firewall_quota_opts, 'QUOTAS')
|
||||
|
||||
|
||||
class Firewall(extensions.ExtensionDescriptor):
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "Firewall service"
|
||||
|
||||
@classmethod
|
||||
def get_alias(cls):
|
||||
return "fwaas"
|
||||
|
||||
@classmethod
|
||||
def get_description(cls):
|
||||
return "Extension for Firewall service"
|
||||
|
||||
@classmethod
|
||||
def get_namespace(cls):
|
||||
return "http://wiki.openstack.org/Neutron/FWaaS/API_1.0"
|
||||
|
||||
@classmethod
|
||||
def get_updated(cls):
|
||||
return "2013-02-25T10:00:00-00:00"
|
||||
|
||||
@classmethod
|
||||
def get_resources(cls):
|
||||
special_mappings = {'firewall_policies': 'firewall_policy'}
|
||||
plural_mappings = resource_helper.build_plural_mappings(
|
||||
special_mappings, RESOURCE_ATTRIBUTE_MAP)
|
||||
attr.PLURALS.update(plural_mappings)
|
||||
action_map = {'firewall_policy': {'insert_rule': 'PUT',
|
||||
'remove_rule': 'PUT'}}
|
||||
return resource_helper.build_resource_info(plural_mappings,
|
||||
RESOURCE_ATTRIBUTE_MAP,
|
||||
constants.FIREWALL,
|
||||
action_map=action_map)
|
||||
|
||||
@classmethod
|
||||
def get_plugin_interface(cls):
|
||||
return FirewallPluginBase
|
||||
|
||||
def update_attributes_map(self, attributes):
|
||||
super(Firewall, self).update_attributes_map(
|
||||
attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP)
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
return RESOURCE_ATTRIBUTE_MAP
|
||||
else:
|
||||
return {}
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class FirewallPluginBase(service_base.ServicePluginBase):
|
||||
|
||||
def get_plugin_name(self):
|
||||
return constants.FIREWALL
|
||||
|
||||
def get_plugin_type(self):
|
||||
return constants.FIREWALL
|
||||
|
||||
def get_plugin_description(self):
|
||||
return 'Firewall service plugin'
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_firewalls(self, context, filters=None, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_firewall(self, context, id, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_firewall(self, context, firewall):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_firewall(self, context, id, firewall):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_firewall(self, context, id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_firewall_rules(self, context, filters=None, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_firewall_rule(self, context, id, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_firewall_rule(self, context, firewall_rule):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_firewall_rule(self, context, id, firewall_rule):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_firewall_rule(self, context, id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_firewall_policy(self, context, id, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_firewall_policies(self, context, filters=None, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_firewall_policy(self, context, firewall_policy):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_firewall_policy(self, context, id, firewall_policy):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_firewall_policy(self, context, id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def insert_rule(self, context, id, rule_info):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def remove_rule(self, context, id, rule_info):
|
||||
pass
|
@ -1,67 +0,0 @@
|
||||
# Copyright 2012 Nachi Ueno, NTT MCL, Inc.
|
||||
# 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.
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.v2 import attributes
|
||||
from neutron.openstack.common import log as logging
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
FLAVOR_NETWORK = 'flavor:network'
|
||||
FLAVOR_ROUTER = 'flavor:router'
|
||||
|
||||
FLAVOR_ATTRIBUTE = {
|
||||
'networks': {
|
||||
FLAVOR_NETWORK: {'allow_post': True,
|
||||
'allow_put': False,
|
||||
'is_visible': True,
|
||||
'default': attributes.ATTR_NOT_SPECIFIED}
|
||||
},
|
||||
'routers': {
|
||||
FLAVOR_ROUTER: {'allow_post': True,
|
||||
'allow_put': False,
|
||||
'is_visible': True,
|
||||
'default': attributes.ATTR_NOT_SPECIFIED}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Flavor(extensions.ExtensionDescriptor):
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "Flavor support for network and router"
|
||||
|
||||
@classmethod
|
||||
def get_alias(cls):
|
||||
return "flavor"
|
||||
|
||||
@classmethod
|
||||
def get_description(cls):
|
||||
return "Flavor"
|
||||
|
||||
@classmethod
|
||||
def get_namespace(cls):
|
||||
return "http://docs.openstack.org/ext/flavor/api/v1.0"
|
||||
|
||||
@classmethod
|
||||
def get_updated(cls):
|
||||
return "2012-07-20T10:00:00-00:00"
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
return FLAVOR_ATTRIBUTE
|
||||
else:
|
||||
return {}
|
@ -1,254 +0,0 @@
|
||||
# Copyright 2012 VMware, Inc.
|
||||
# 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 abc
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.v2 import attributes as attr
|
||||
from neutron.api.v2 import resource_helper
|
||||
from neutron.common import exceptions as qexception
|
||||
from neutron.plugins.common import constants
|
||||
|
||||
|
||||
# L3 Exceptions
|
||||
class RouterNotFound(qexception.NotFound):
|
||||
message = _("Router %(router_id)s could not be found")
|
||||
|
||||
|
||||
class RouterInUse(qexception.InUse):
|
||||
message = _("Router %(router_id)s still has ports")
|
||||
|
||||
|
||||
class RouterInterfaceNotFound(qexception.NotFound):
|
||||
message = _("Router %(router_id)s does not have "
|
||||
"an interface with id %(port_id)s")
|
||||
|
||||
|
||||
class RouterInterfaceNotFoundForSubnet(qexception.NotFound):
|
||||
message = _("Router %(router_id)s has no interface "
|
||||
"on subnet %(subnet_id)s")
|
||||
|
||||
|
||||
class RouterInterfaceInUseByFloatingIP(qexception.InUse):
|
||||
message = _("Router interface for subnet %(subnet_id)s on router "
|
||||
"%(router_id)s cannot be deleted, as it is required "
|
||||
"by one or more floating IPs.")
|
||||
|
||||
|
||||
class FloatingIPNotFound(qexception.NotFound):
|
||||
message = _("Floating IP %(floatingip_id)s could not be found")
|
||||
|
||||
|
||||
class ExternalGatewayForFloatingIPNotFound(qexception.NotFound):
|
||||
message = _("External network %(external_network_id)s is not reachable "
|
||||
"from subnet %(subnet_id)s. Therefore, cannot associate "
|
||||
"Port %(port_id)s with a Floating IP.")
|
||||
|
||||
|
||||
class FloatingIPPortAlreadyAssociated(qexception.InUse):
|
||||
message = _("Cannot associate floating IP %(floating_ip_address)s "
|
||||
"(%(fip_id)s) with port %(port_id)s "
|
||||
"using fixed IP %(fixed_ip)s, as that fixed IP already "
|
||||
"has a floating IP on external network %(net_id)s.")
|
||||
|
||||
|
||||
class L3PortInUse(qexception.InUse):
|
||||
message = _("Port %(port_id)s has owner %(device_owner)s and therefore"
|
||||
" cannot be deleted directly via the port API.")
|
||||
|
||||
|
||||
class RouterExternalGatewayInUseByFloatingIp(qexception.InUse):
|
||||
message = _("Gateway cannot be updated for router %(router_id)s, since a "
|
||||
"gateway to external network %(net_id)s is required by one or "
|
||||
"more floating IPs.")
|
||||
|
||||
ROUTERS = 'routers'
|
||||
EXTERNAL_GW_INFO = 'external_gateway_info'
|
||||
|
||||
RESOURCE_ATTRIBUTE_MAP = {
|
||||
ROUTERS: {
|
||||
'id': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True,
|
||||
'primary_key': True},
|
||||
'name': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'admin_state_up': {'allow_post': True, 'allow_put': True,
|
||||
'default': True,
|
||||
'convert_to': attr.convert_to_boolean,
|
||||
'is_visible': True},
|
||||
'status': {'allow_post': False, 'allow_put': False,
|
||||
'is_visible': True},
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'required_by_policy': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True},
|
||||
EXTERNAL_GW_INFO: {'allow_post': True, 'allow_put': True,
|
||||
'is_visible': True, 'default': None,
|
||||
'enforce_policy': True}
|
||||
},
|
||||
'floatingips': {
|
||||
'id': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True,
|
||||
'primary_key': True},
|
||||
'floating_ip_address': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:ip_address_or_none': None},
|
||||
'is_visible': True},
|
||||
'floating_network_id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True},
|
||||
'router_id': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid_or_none': None},
|
||||
'is_visible': True, 'default': None},
|
||||
'port_id': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:uuid_or_none': None},
|
||||
'is_visible': True, 'default': None,
|
||||
'required_by_policy': True},
|
||||
'fixed_ip_address': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:ip_address_or_none': None},
|
||||
'is_visible': True, 'default': None},
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'required_by_policy': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True},
|
||||
'status': {'allow_post': False, 'allow_put': False,
|
||||
'is_visible': True},
|
||||
},
|
||||
}
|
||||
|
||||
l3_quota_opts = [
|
||||
cfg.IntOpt('quota_router',
|
||||
default=10,
|
||||
help=_('Number of routers allowed per tenant. '
|
||||
'A negative value means unlimited.')),
|
||||
cfg.IntOpt('quota_floatingip',
|
||||
default=50,
|
||||
help=_('Number of floating IPs allowed per tenant. '
|
||||
'A negative value means unlimited.')),
|
||||
]
|
||||
cfg.CONF.register_opts(l3_quota_opts, 'QUOTAS')
|
||||
|
||||
|
||||
class L3(extensions.ExtensionDescriptor):
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "Neutron L3 Router"
|
||||
|
||||
@classmethod
|
||||
def get_alias(cls):
|
||||
return "router"
|
||||
|
||||
@classmethod
|
||||
def get_description(cls):
|
||||
return ("Router abstraction for basic L3 forwarding"
|
||||
" between L2 Neutron networks and access to external"
|
||||
" networks via a NAT gateway.")
|
||||
|
||||
@classmethod
|
||||
def get_namespace(cls):
|
||||
return "http://docs.openstack.org/ext/neutron/router/api/v1.0"
|
||||
|
||||
@classmethod
|
||||
def get_updated(cls):
|
||||
return "2012-07-20T10:00:00-00:00"
|
||||
|
||||
@classmethod
|
||||
def get_resources(cls):
|
||||
"""Returns Ext Resources."""
|
||||
plural_mappings = resource_helper.build_plural_mappings(
|
||||
{}, RESOURCE_ATTRIBUTE_MAP)
|
||||
attr.PLURALS.update(plural_mappings)
|
||||
action_map = {'router': {'add_router_interface': 'PUT',
|
||||
'remove_router_interface': 'PUT'}}
|
||||
return resource_helper.build_resource_info(plural_mappings,
|
||||
RESOURCE_ATTRIBUTE_MAP,
|
||||
constants.L3_ROUTER_NAT,
|
||||
action_map=action_map,
|
||||
register_quota=True)
|
||||
|
||||
def update_attributes_map(self, attributes):
|
||||
super(L3, self).update_attributes_map(
|
||||
attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP)
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
return RESOURCE_ATTRIBUTE_MAP
|
||||
else:
|
||||
return {}
|
||||
|
||||
|
||||
class RouterPluginBase(object):
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_router(self, context, router):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_router(self, context, id, router):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_router(self, context, id, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_router(self, context, id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_routers(self, context, filters=None, fields=None,
|
||||
sorts=None, limit=None, marker=None, page_reverse=False):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def add_router_interface(self, context, router_id, interface_info):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def remove_router_interface(self, context, router_id, interface_info):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_floatingip(self, context, floatingip):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_floatingip(self, context, id, floatingip):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_floatingip(self, context, id, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_floatingip(self, context, id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_floatingips(self, context, filters=None, fields=None,
|
||||
sorts=None, limit=None, marker=None,
|
||||
page_reverse=False):
|
||||
pass
|
||||
|
||||
def get_routers_count(self, context, filters=None):
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_floatingips_count(self, context, filters=None):
|
||||
raise NotImplementedError()
|
@ -1,66 +0,0 @@
|
||||
# Copyright 2013 VMware, Inc.
|
||||
# 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.
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.v2 import attributes as attrs
|
||||
from neutron.extensions import l3
|
||||
|
||||
|
||||
EXTENDED_ATTRIBUTES_2_0 = {
|
||||
'routers': {l3.EXTERNAL_GW_INFO:
|
||||
{'allow_post': True,
|
||||
'allow_put': True,
|
||||
'is_visible': True,
|
||||
'default': None,
|
||||
'enforce_policy': True,
|
||||
'validate':
|
||||
{'type:dict_or_nodata':
|
||||
{'network_id': {'type:uuid': None, 'required': True},
|
||||
'enable_snat': {'type:boolean': None, 'required': |