remove unnecessary neutron files under neutron/extensions
Change-Id: I775988fbb97070f3df4140acbaffa30b36196238
This commit is contained in:
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': False,
|
|
||||||
'convert_to': attrs.convert_to_boolean}}
|
|
||||||
}}}}
|
|
||||||
|
|
||||||
|
|
||||||
class L3_ext_gw_mode(extensions.ExtensionDescriptor):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "Neutron L3 Configurable external gateway mode"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_alias(cls):
|
|
||||||
return "ext-gw-mode"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_description(cls):
|
|
||||||
return ("Extension of the router abstraction for specifying whether "
|
|
||||||
"SNAT should occur on the external gateway")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_namespace(cls):
|
|
||||||
return "http://docs.openstack.org/ext/neutron/ext-gw-mode/api/v1.0"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_updated(cls):
|
|
||||||
return "2013-03-28T10:00:00-00:00"
|
|
||||||
|
|
||||||
def get_required_extensions(self):
|
|
||||||
return ["router"]
|
|
||||||
|
|
||||||
def get_extended_resources(self, version):
|
|
||||||
if version == "2.0":
|
|
||||||
return dict(EXTENDED_ATTRIBUTES_2_0.items())
|
|
||||||
else:
|
|
||||||
return {}
|
|
|
@ -1,194 +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
|
|
||||||
|
|
||||||
import webob.exc
|
|
||||||
|
|
||||||
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.openstack.common import log as logging
|
|
||||||
from neutron.plugins.common import constants as service_constants
|
|
||||||
from neutron import policy
|
|
||||||
from neutron import wsgi
|
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
L3_ROUTER = 'l3-router'
|
|
||||||
L3_ROUTERS = L3_ROUTER + 's'
|
|
||||||
L3_AGENT = 'l3-agent'
|
|
||||||
L3_AGENTS = L3_AGENT + 's'
|
|
||||||
|
|
||||||
|
|
||||||
class RouterSchedulerController(wsgi.Controller):
|
|
||||||
def get_plugin(self):
|
|
||||||
plugin = manager.NeutronManager.get_service_plugins().get(
|
|
||||||
service_constants.L3_ROUTER_NAT)
|
|
||||||
if not plugin:
|
|
||||||
LOG.error(_('No plugin for L3 routing registered to handle '
|
|
||||||
'router scheduling'))
|
|
||||||
msg = _('The resource could not be found.')
|
|
||||||
raise webob.exc.HTTPNotFound(msg)
|
|
||||||
return plugin
|
|
||||||
|
|
||||||
def index(self, request, **kwargs):
|
|
||||||
plugin = self.get_plugin()
|
|
||||||
policy.enforce(request.context,
|
|
||||||
"get_%s" % L3_ROUTERS,
|
|
||||||
{})
|
|
||||||
return plugin.list_routers_on_l3_agent(
|
|
||||||
request.context, kwargs['agent_id'])
|
|
||||||
|
|
||||||
def create(self, request, body, **kwargs):
|
|
||||||
plugin = self.get_plugin()
|
|
||||||
policy.enforce(request.context,
|
|
||||||
"create_%s" % L3_ROUTER,
|
|
||||||
{})
|
|
||||||
return plugin.add_router_to_l3_agent(
|
|
||||||
request.context,
|
|
||||||
kwargs['agent_id'],
|
|
||||||
body['router_id'])
|
|
||||||
|
|
||||||
def delete(self, request, id, **kwargs):
|
|
||||||
plugin = self.get_plugin()
|
|
||||||
policy.enforce(request.context,
|
|
||||||
"delete_%s" % L3_ROUTER,
|
|
||||||
{})
|
|
||||||
return plugin.remove_router_from_l3_agent(
|
|
||||||
request.context, kwargs['agent_id'], id)
|
|
||||||
|
|
||||||
|
|
||||||
class L3AgentsHostingRouterController(wsgi.Controller):
|
|
||||||
def get_plugin(self):
|
|
||||||
plugin = manager.NeutronManager.get_service_plugins().get(
|
|
||||||
service_constants.L3_ROUTER_NAT)
|
|
||||||
if not plugin:
|
|
||||||
LOG.error(_('No plugin for L3 routing registered to handle '
|
|
||||||
'router scheduling'))
|
|
||||||
msg = _('The resource could not be found.')
|
|
||||||
raise webob.exc.HTTPNotFound(msg)
|
|
||||||
return plugin
|
|
||||||
|
|
||||||
def index(self, request, **kwargs):
|
|
||||||
plugin = manager.NeutronManager.get_service_plugins().get(
|
|
||||||
service_constants.L3_ROUTER_NAT)
|
|
||||||
policy.enforce(request.context,
|
|
||||||
"get_%s" % L3_AGENTS,
|
|
||||||
{})
|
|
||||||
return plugin.list_l3_agents_hosting_router(
|
|
||||||
request.context, kwargs['router_id'])
|
|
||||||
|
|
||||||
|
|
||||||
class L3agentscheduler(extensions.ExtensionDescriptor):
|
|
||||||
"""Extension class supporting l3 agent scheduler.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "L3 Agent Scheduler"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_alias(cls):
|
|
||||||
return constants.L3_AGENT_SCHEDULER_EXT_ALIAS
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_description(cls):
|
|
||||||
return "Schedule routers among l3 agents"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_namespace(cls):
|
|
||||||
return "http://docs.openstack.org/ext/l3_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(RouterSchedulerController(),
|
|
||||||
base.FAULT_MAP)
|
|
||||||
exts.append(extensions.ResourceExtension(
|
|
||||||
L3_ROUTERS, controller, parent))
|
|
||||||
|
|
||||||
parent = dict(member_name="router",
|
|
||||||
collection_name="routers")
|
|
||||||
|
|
||||||
controller = resource.Resource(L3AgentsHostingRouterController(),
|
|
||||||
base.FAULT_MAP)
|
|
||||||
exts.append(extensions.ResourceExtension(
|
|
||||||
L3_AGENTS, controller, parent))
|
|
||||||
return exts
|
|
||||||
|
|
||||||
def get_extended_resources(self, version):
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
class InvalidL3Agent(agent.AgentNotFound):
|
|
||||||
message = _("Agent %(id)s is not a L3 Agent or has been disabled")
|
|
||||||
|
|
||||||
|
|
||||||
class RouterHostedByL3Agent(exceptions.Conflict):
|
|
||||||
message = _("The router %(router_id)s has been already hosted"
|
|
||||||
" by the L3 Agent %(agent_id)s.")
|
|
||||||
|
|
||||||
|
|
||||||
class RouterSchedulingFailed(exceptions.Conflict):
|
|
||||||
message = _("Failed scheduling router %(router_id)s to"
|
|
||||||
" the L3 Agent %(agent_id)s.")
|
|
||||||
|
|
||||||
|
|
||||||
class RouterReschedulingFailed(exceptions.Conflict):
|
|
||||||
message = _("Failed rescheduling router %(router_id)s: "
|
|
||||||
"no eligible l3 agent found.")
|
|
||||||
|
|
||||||
|
|
||||||
class RouterNotHostedByL3Agent(exceptions.Conflict):
|
|
||||||
message = _("The router %(router_id)s is not hosted"
|
|
||||||
" by L3 agent %(agent_id)s.")
|
|
||||||
|
|
||||||
|
|
||||||
class L3AgentSchedulerPluginBase(object):
|
|
||||||
"""REST API to operate the l3 agent scheduler.
|
|
||||||
|
|
||||||
All of method must be in an admin context.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def add_router_to_l3_agent(self, context, id, router_id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def remove_router_from_l3_agent(self, context, id, router_id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def list_routers_on_l3_agent(self, context, id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def list_l3_agents_hosting_router(self, context, router_id):
|
|
||||||
pass
|
|
|
@ -1,137 +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.extensions import agent
|
|
||||||
from neutron.extensions import loadbalancer
|
|
||||||
from neutron import manager
|
|
||||||
from neutron.plugins.common import constants as plugin_const
|
|
||||||
from neutron import policy
|
|
||||||
from neutron import wsgi
|
|
||||||
|
|
||||||
LOADBALANCER_POOL = 'loadbalancer-pool'
|
|
||||||
LOADBALANCER_POOLS = LOADBALANCER_POOL + 's'
|
|
||||||
LOADBALANCER_AGENT = 'loadbalancer-agent'
|
|
||||||
|
|
||||||
|
|
||||||
class PoolSchedulerController(wsgi.Controller):
|
|
||||||
def index(self, request, **kwargs):
|
|
||||||
lbaas_plugin = manager.NeutronManager.get_service_plugins().get(
|
|
||||||
plugin_const.LOADBALANCER)
|
|
||||||
if not lbaas_plugin:
|
|
||||||
return {'pools': []}
|
|
||||||
|
|
||||||
policy.enforce(request.context,
|
|
||||||
"get_%s" % LOADBALANCER_POOLS,
|
|
||||||
{},
|
|
||||||
plugin=lbaas_plugin)
|
|
||||||
return lbaas_plugin.list_pools_on_lbaas_agent(
|
|
||||||
request.context, kwargs['agent_id'])
|
|
||||||
|
|
||||||
|
|
||||||
class LbaasAgentHostingPoolController(wsgi.Controller):
|
|
||||||
def index(self, request, **kwargs):
|
|
||||||
lbaas_plugin = manager.NeutronManager.get_service_plugins().get(
|
|
||||||
plugin_const.LOADBALANCER)
|
|
||||||
if not lbaas_plugin:
|
|
||||||
return
|
|
||||||
|
|
||||||
policy.enforce(request.context,
|
|
||||||
"get_%s" % LOADBALANCER_AGENT,
|
|
||||||
{},
|
|
||||||
plugin=lbaas_plugin)
|
|
||||||
return lbaas_plugin.get_lbaas_agent_hosting_pool(
|
|
||||||
request.context, kwargs['pool_id'])
|
|
||||||
|
|
||||||
|
|
||||||
class Lbaas_agentscheduler(extensions.ExtensionDescriptor):
|
|
||||||
"""Extension class supporting LBaaS agent scheduler.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "Loadbalancer Agent Scheduler"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_alias(cls):
|
|
||||||
return constants.LBAAS_AGENT_SCHEDULER_EXT_ALIAS
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_description(cls):
|
|
||||||
return "Schedule pools among lbaas agents"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_namespace(cls):
|
|
||||||
return "http://docs.openstack.org/ext/lbaas_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(PoolSchedulerController(),
|
|
||||||
base.FAULT_MAP)
|
|
||||||
exts.append(extensions.ResourceExtension(
|
|
||||||
LOADBALANCER_POOLS, controller, parent))
|
|
||||||
|
|
||||||
parent = dict(member_name="pool",
|
|
||||||
collection_name="pools")
|
|
||||||
|
|
||||||
controller = resource.Resource(LbaasAgentHostingPoolController(),
|
|
||||||
base.FAULT_MAP)
|
|
||||||
exts.append(extensions.ResourceExtension(
|
|
||||||
LOADBALANCER_AGENT, controller, parent,
|
|
||||||
path_prefix=plugin_const.
|
|
||||||
COMMON_PREFIXES[plugin_const.LOADBALANCER]))
|
|
||||||
return exts
|
|
||||||
|
|
||||||
def get_extended_resources(self, version):
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
class NoEligibleLbaasAgent(loadbalancer.NoEligibleBackend):
|
|
||||||
message = _("No eligible loadbalancer agent found "
|
|
||||||
"for pool %(pool_id)s.")
|
|
||||||
|
|
||||||
|
|
||||||
class NoActiveLbaasAgent(agent.AgentNotFound):
|
|
||||||
message = _("No active loadbalancer agent found "
|
|
||||||
"for pool %(pool_id)s.")
|
|
||||||
|
|
||||||
|
|
||||||
class LbaasAgentSchedulerPluginBase(object):
|
|
||||||
"""REST API to operate the lbaas agent scheduler.
|
|
||||||
|
|
||||||
All of method must be in an admin context.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def list_pools_on_lbaas_agent(self, context, id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_lbaas_agent_hosting_pool(self, context, pool_id):
|
|
||||||
pass
|
|
|
@ -1,506 +0,0 @@
|
||||||
# Copyright 2012 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 oslo.config import cfg
|
|
||||||
import six
|
|
||||||
|
|
||||||
from neutron.api import extensions
|
|
||||||
from neutron.api.v2 import attributes as attr
|
|
||||||
from neutron.api.v2 import base
|
|
||||||
from neutron.api.v2 import resource_helper
|
|
||||||
from neutron.common import exceptions as qexception
|
|
||||||
from neutron import manager
|
|
||||||
from neutron.plugins.common import constants
|
|
||||||
from neutron.services import service_base
|
|
||||||
|
|
||||||
|
|
||||||
# Loadbalancer Exceptions
|
|
||||||
class DelayOrTimeoutInvalid(qexception.BadRequest):
|
|
||||||
message = _("Delay must be greater than or equal to timeout")
|
|
||||||
|
|
||||||
|
|
||||||
class NoEligibleBackend(qexception.NotFound):
|
|
||||||
message = _("No eligible backend for pool %(pool_id)s")
|
|
||||||
|
|
||||||
|
|
||||||
class VipNotFound(qexception.NotFound):
|
|
||||||
message = _("Vip %(vip_id)s could not be found")
|
|
||||||
|
|
||||||
|
|
||||||
class VipExists(qexception.NeutronException):
|
|
||||||
message = _("Another Vip already exists for pool %(pool_id)s")
|
|
||||||
|
|
||||||
|
|
||||||
class PoolNotFound(qexception.NotFound):
|
|
||||||
message = _("Pool %(pool_id)s could not be found")
|
|
||||||
|
|
||||||
|
|
||||||
class MemberNotFound(qexception.NotFound):
|
|
||||||
message = _("Member %(member_id)s could not be found")
|
|
||||||
|
|
||||||
|
|
||||||
class HealthMonitorNotFound(qexception.NotFound):
|
|
||||||
message = _("Health_monitor %(monitor_id)s could not be found")
|
|
||||||
|
|
||||||
|
|
||||||
class PoolMonitorAssociationNotFound(qexception.NotFound):
|
|
||||||
message = _("Monitor %(monitor_id)s is not associated "
|
|
||||||
"with Pool %(pool_id)s")
|
|
||||||
|
|
||||||
|
|
||||||
class PoolMonitorAssociationExists(qexception.Conflict):
|
|
||||||
message = _('health_monitor %(monitor_id)s is already associated '
|
|
||||||
'with pool %(pool_id)s')
|
|
||||||
|
|
||||||
|
|
||||||
class StateInvalid(qexception.NeutronException):
|
|
||||||
message = _("Invalid state %(state)s of Loadbalancer resource %(id)s")
|
|
||||||
|
|
||||||
|
|
||||||
class PoolInUse(qexception.InUse):
|
|
||||||
message = _("Pool %(pool_id)s is still in use")
|
|
||||||
|
|
||||||
|
|
||||||
class HealthMonitorInUse(qexception.InUse):
|
|
||||||
message = _("Health monitor %(monitor_id)s still has associations with "
|
|
||||||
"pools")
|
|
||||||
|
|
||||||
|
|
||||||
class PoolStatsNotFound(qexception.NotFound):
|
|
||||||
message = _("Statistics of Pool %(pool_id)s could not be found")
|
|
||||||
|
|
||||||
|
|
||||||
class ProtocolMismatch(qexception.BadRequest):
|
|
||||||
message = _("Protocol %(vip_proto)s does not match "
|
|
||||||
"pool protocol %(pool_proto)s")
|
|
||||||
|
|
||||||
|
|
||||||
class MemberExists(qexception.NeutronException):
|
|
||||||
message = _("Member with address %(address)s and port %(port)s "
|
|
||||||
"already present in pool %(pool)s")
|
|
||||||
|
|
||||||
|
|
||||||
RESOURCE_ATTRIBUTE_MAP = {
|
|
||||||
'vips': {
|
|
||||||
'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,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'required_by_policy': True,
|
|
||||||
'is_visible': True},
|
|
||||||
'name': {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'default': '',
|
|
||||||
'is_visible': True},
|
|
||||||
'description': {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'is_visible': True, 'default': ''},
|
|
||||||
'subnet_id': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'address': {'allow_post': True, 'allow_put': False,
|
|
||||||
'default': attr.ATTR_NOT_SPECIFIED,
|
|
||||||
'validate': {'type:ip_address_or_none': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'port_id': {'allow_post': False, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'protocol_port': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:range': [0, 65535]},
|
|
||||||
'convert_to': attr.convert_to_int,
|
|
||||||
'is_visible': True},
|
|
||||||
'protocol': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:values': ['TCP', 'HTTP', 'HTTPS']},
|
|
||||||
'is_visible': True},
|
|
||||||
'pool_id': {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:uuid': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'session_persistence': {'allow_post': True, 'allow_put': True,
|
|
||||||
'convert_to': attr.convert_none_to_empty_dict,
|
|
||||||
'default': {},
|
|
||||||
'validate': {
|
|
||||||
'type:dict_or_empty': {
|
|
||||||
'type': {'type:values': ['APP_COOKIE',
|
|
||||||
'HTTP_COOKIE',
|
|
||||||
'SOURCE_IP'],
|
|
||||||
'required': True},
|
|
||||||
'cookie_name': {'type:string': None,
|
|
||||||
'required': False}}},
|
|
||||||
'is_visible': True},
|
|
||||||
'connection_limit': {'allow_post': True, 'allow_put': True,
|
|
||||||
'default': -1,
|
|
||||||
'convert_to': attr.convert_to_int,
|
|
||||||
'is_visible': True},
|
|
||||||
'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},
|
|
||||||
'status_description': {'allow_post': False, 'allow_put': False,
|
|
||||||
'is_visible': True}
|
|
||||||
},
|
|
||||||
'pools': {
|
|
||||||
'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,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'required_by_policy': True,
|
|
||||||
'is_visible': True},
|
|
||||||
'vip_id': {'allow_post': False, 'allow_put': False,
|
|
||||||
'is_visible': True},
|
|
||||||
'name': {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'default': '',
|
|
||||||
'is_visible': True},
|
|
||||||
'description': {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'is_visible': True, 'default': ''},
|
|
||||||
'subnet_id': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'protocol': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:values': ['TCP', 'HTTP', 'HTTPS']},
|
|
||||||
'is_visible': True},
|
|
||||||
'provider': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'is_visible': True, 'default': attr.ATTR_NOT_SPECIFIED},
|
|
||||||
'lb_method': {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'members': {'allow_post': False, 'allow_put': False,
|
|
||||||
'is_visible': True},
|
|
||||||
'health_monitors': {'allow_post': True, 'allow_put': True,
|
|
||||||
'default': None,
|
|
||||||
'validate': {'type:uuid_list': None},
|
|
||||||
'convert_to': attr.convert_to_list,
|
|
||||||
'is_visible': True},
|
|
||||||
'health_monitors_status': {'allow_post': False, 'allow_put': False,
|
|
||||||
'is_visible': True},
|
|
||||||
'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},
|
|
||||||
'status_description': {'allow_post': False, 'allow_put': False,
|
|
||||||
'is_visible': True}
|
|
||||||
},
|
|
||||||
'members': {
|
|
||||||
'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,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'required_by_policy': True,
|
|
||||||
'is_visible': True},
|
|
||||||
'pool_id': {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:uuid': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'address': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:ip_address': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'protocol_port': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:range': [0, 65535]},
|
|
||||||
'convert_to': attr.convert_to_int,
|
|
||||||
'is_visible': True},
|
|
||||||
'weight': {'allow_post': True, 'allow_put': True,
|
|
||||||
'default': 1,
|
|
||||||
'validate': {'type:range': [0, 256]},
|
|
||||||
'convert_to': attr.convert_to_int,
|
|
||||||
'is_visible': True},
|
|
||||||
'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},
|
|
||||||
'status_description': {'allow_post': False, 'allow_put': False,
|
|
||||||
'is_visible': True}
|
|
||||||
},
|
|
||||||
'health_monitors': {
|
|
||||||
'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,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'required_by_policy': True,
|
|
||||||
'is_visible': True},
|
|
||||||
'type': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:values': ['PING', 'TCP', 'HTTP', 'HTTPS']},
|
|
||||||
'is_visible': True},
|
|
||||||
'delay': {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:non_negative': None},
|
|
||||||
'convert_to': attr.convert_to_int,
|
|
||||||
'is_visible': True},
|
|
||||||
'timeout': {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:non_negative': None},
|
|
||||||
'convert_to': attr.convert_to_int,
|
|
||||||
'is_visible': True},
|
|
||||||
'max_retries': {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:range': [1, 10]},
|
|
||||||
'convert_to': attr.convert_to_int,
|
|
||||||
'is_visible': True},
|
|
||||||
'http_method': {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'default': 'GET',
|
|
||||||
'is_visible': True},
|
|
||||||
'url_path': {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'default': '/',
|
|
||||||
'is_visible': True},
|
|
||||||
'expected_codes': {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {
|
|
||||||
'type:regex':
|
|
||||||
'^(\d{3}(\s*,\s*\d{3})*)$|^(\d{3}-\d{3})$'},
|
|
||||||
'default': '200',
|
|
||||||
'is_visible': True},
|
|
||||||
'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},
|
|
||||||
'status_description': {'allow_post': False, 'allow_put': False,
|
|
||||||
'is_visible': True},
|
|
||||||
'pools': {'allow_post': False, 'allow_put': False,
|
|
||||||
'is_visible': True}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SUB_RESOURCE_ATTRIBUTE_MAP = {
|
|
||||||
'health_monitors': {
|
|
||||||
'parent': {'collection_name': 'pools',
|
|
||||||
'member_name': 'pool'},
|
|
||||||
'parameters': {'id': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'required_by_policy': True,
|
|
||||||
'is_visible': True},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lbaas_quota_opts = [
|
|
||||||
cfg.IntOpt('quota_vip',
|
|
||||||
default=10,
|
|
||||||
help=_('Number of vips allowed per tenant. '
|
|
||||||
'A negative value means unlimited.')),
|
|
||||||
cfg.IntOpt('quota_pool',
|
|
||||||
default=10,
|
|
||||||
help=_('Number of pools allowed per tenant. '
|
|
||||||
'A negative value means unlimited.')),
|
|
||||||
cfg.IntOpt('quota_member',
|
|
||||||
default=-1,
|
|
||||||
help=_('Number of pool members allowed per tenant. '
|
|
||||||
'A negative value means unlimited.')),
|
|
||||||
cfg.IntOpt('quota_health_monitor',
|
|
||||||
default=-1,
|
|
||||||
help=_('Number of health monitors allowed per tenant. '
|
|
||||||
'A negative value means unlimited.'))
|
|
||||||
]
|
|
||||||
cfg.CONF.register_opts(lbaas_quota_opts, 'QUOTAS')
|
|
||||||
|
|
||||||
|
|
||||||
class Loadbalancer(extensions.ExtensionDescriptor):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "LoadBalancing service"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_alias(cls):
|
|
||||||
return "lbaas"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_description(cls):
|
|
||||||
return "Extension for LoadBalancing service"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_namespace(cls):
|
|
||||||
return "http://wiki.openstack.org/neutron/LBaaS/API_1.0"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_updated(cls):
|
|
||||||
return "2012-10-07T10:00:00-00:00"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_resources(cls):
|
|
||||||
plural_mappings = resource_helper.build_plural_mappings(
|
|
||||||
{}, RESOURCE_ATTRIBUTE_MAP)
|
|
||||||
plural_mappings['health_monitors_status'] = 'health_monitor_status'
|
|
||||||
attr.PLURALS.update(plural_mappings)
|
|
||||||
action_map = {'pool': {'stats': 'GET'}}
|
|
||||||
resources = resource_helper.build_resource_info(plural_mappings,
|
|
||||||
RESOURCE_ATTRIBUTE_MAP,
|
|
||||||
constants.LOADBALANCER,
|
|
||||||
action_map=action_map,
|
|
||||||
register_quota=True)
|
|
||||||
plugin = manager.NeutronManager.get_service_plugins()[
|
|
||||||
constants.LOADBALANCER]
|
|
||||||
for collection_name in SUB_RESOURCE_ATTRIBUTE_MAP:
|
|
||||||
# Special handling needed for sub-resources with 'y' ending
|
|
||||||
# (e.g. proxies -> proxy)
|
|
||||||
resource_name = collection_name[:-1]
|
|
||||||
parent = SUB_RESOURCE_ATTRIBUTE_MAP[collection_name].get('parent')
|
|
||||||
params = SUB_RESOURCE_ATTRIBUTE_MAP[collection_name].get(
|
|
||||||
'parameters')
|
|
||||||
|
|
||||||
controller = base.create_resource(collection_name, resource_name,
|
|
||||||
plugin, params,
|
|
||||||
allow_bulk=True,
|
|
||||||
parent=parent)
|
|
||||||
|
|
||||||
resource = extensions.ResourceExtension(
|
|
||||||
collection_name,
|
|
||||||
controller, parent,
|
|
||||||
path_prefix=constants.COMMON_PREFIXES[constants.LOADBALANCER],
|
|
||||||
attr_map=params)
|
|
||||||
resources.append(resource)
|
|
||||||
|
|
||||||
return resources
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_plugin_interface(cls):
|
|
||||||
return LoadBalancerPluginBase
|
|
||||||
|
|
||||||
def update_attributes_map(self, attributes):
|
|
||||||
super(Loadbalancer, 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 LoadBalancerPluginBase(service_base.ServicePluginBase):
|
|
||||||
|
|
||||||
def get_plugin_name(self):
|
|
||||||
return constants.LOADBALANCER
|
|
||||||
|
|
||||||
def get_plugin_type(self):
|
|
||||||
return constants.LOADBALANCER
|
|
||||||
|
|
||||||
def get_plugin_description(self):
|
|
||||||
return 'LoadBalancer service plugin'
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_vips(self, context, filters=None, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_vip(self, context, id, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def create_vip(self, context, vip):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def update_vip(self, context, id, vip):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def delete_vip(self, context, id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_pools(self, context, filters=None, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_pool(self, context, id, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def create_pool(self, context, pool):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def update_pool(self, context, id, pool):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def delete_pool(self, context, id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def stats(self, context, pool_id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def create_pool_health_monitor(self, context, health_monitor, pool_id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_pool_health_monitor(self, context, id, pool_id, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def delete_pool_health_monitor(self, context, id, pool_id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_members(self, context, filters=None, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_member(self, context, id, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def create_member(self, context, member):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def update_member(self, context, id, member):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def delete_member(self, context, id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_health_monitors(self, context, filters=None, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_health_monitor(self, context, id, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def create_health_monitor(self, context, health_monitor):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def update_health_monitor(self, context, id, health_monitor):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def delete_health_monitor(self, context, id):
|
|
||||||
pass
|
|
|
@ -1,190 +0,0 @@
|
||||||
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
|
|
||||||
#
|
|
||||||
# Author: Sylvain Afchain <sylvain.afchain@enovance.com>
|
|
||||||
#
|
|
||||||
# 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
|
|
||||||
|
|
||||||
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__)
|
|
||||||
|
|
||||||
|
|
||||||
class MeteringLabelNotFound(qexception.NotFound):
|
|
||||||
message = _("Metering label %(label_id)s does not exist")
|
|
||||||
|
|
||||||
|
|
||||||
class DuplicateMeteringRuleInPost(qexception.InUse):
|
|
||||||
message = _("Duplicate Metering Rule in POST.")
|
|
||||||
|
|
||||||
|
|
||||||
class MeteringLabelRuleNotFound(qexception.NotFound):
|
|
||||||
message = _("Metering label rule %(rule_id)s does not exist")
|
|
||||||
|
|
||||||
|
|
||||||
class MeteringLabelRuleOverlaps(qexception.NotFound):
|
|
||||||
message = _("Metering label rule with remote_ip_prefix "
|
|
||||||
"%(remote_ip_prefix)s overlaps another")
|
|
||||||
|
|
||||||
|
|
||||||
RESOURCE_ATTRIBUTE_MAP = {
|
|
||||||
'metering_labels': {
|
|
||||||
'id': {'allow_post': False, 'allow_put': False,
|
|
||||||
'is_visible': True,
|
|
||||||
'primary_key': True},
|
|
||||||
'name': {'allow_post': True, 'allow_put': True,
|
|
||||||
'is_visible': True, 'default': ''},
|
|
||||||
'description': {'allow_post': True, 'allow_put': True,
|
|
||||||
'is_visible': True, 'default': ''},
|
|
||||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
|
||||||
'required_by_policy': True,
|
|
||||||
'is_visible': True}
|
|
||||||
},
|
|
||||||
'metering_label_rules': {
|
|
||||||
'id': {'allow_post': False, 'allow_put': False,
|
|
||||||
'is_visible': True,
|
|
||||||
'primary_key': True},
|
|
||||||
'metering_label_id': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid': None},
|
|
||||||
'is_visible': True, 'required_by_policy': True},
|
|
||||||
'direction': {'allow_post': True, 'allow_put': True,
|
|
||||||
'is_visible': True,
|
|
||||||
'validate': {'type:values': ['ingress', 'egress']}},
|
|
||||||
'excluded': {'allow_post': True, 'allow_put': True,
|
|
||||||
'is_visible': True, 'default': False,
|
|
||||||
'convert_to': attr.convert_to_boolean},
|
|
||||||
'remote_ip_prefix': {'allow_post': True, 'allow_put': False,
|
|
||||||
'is_visible': True, 'required_by_policy': True,
|
|
||||||
'validate': {'type:subnet': None}},
|
|
||||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
|
||||||
'required_by_policy': True,
|
|
||||||
'is_visible': True}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class Metering(extensions.ExtensionDescriptor):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "Neutron Metering"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_alias(cls):
|
|
||||||
return "metering"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_description(cls):
|
|
||||||
return "Neutron Metering extension."
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_namespace(cls):
|
|
||||||
return "http://wiki.openstack.org/wiki/Neutron/Metering/Bandwidth#API"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_updated(cls):
|
|
||||||
return "2013-06-12T10:00:00-00:00"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_plugin_interface(cls):
|
|
||||||
return MeteringPluginBase
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_resources(cls):
|
|
||||||
"""Returns Ext Resources."""
|
|
||||||
plural_mappings = resource_helper.build_plural_mappings(
|
|
||||||
{}, RESOURCE_ATTRIBUTE_MAP)
|
|
||||||
attr.PLURALS.update(plural_mappings)
|
|
||||||
# PCM: Metering sets pagination and sorting to True. Do we have cfg
|
|
||||||
# entries for these so can be read? Else, must pass in.
|
|
||||||
return resource_helper.build_resource_info(plural_mappings,
|
|
||||||
RESOURCE_ATTRIBUTE_MAP,
|
|
||||||
constants.METERING,
|
|
||||||
translate_name=True,
|
|
||||||
allow_bulk=True)
|
|
||||||
|
|
||||||
def update_attributes_map(self, attributes):
|
|
||||||
super(Metering, 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 MeteringPluginBase(service_base.ServicePluginBase):
|
|
||||||
|
|
||||||
def get_plugin_name(self):
|
|
||||||
return constants.METERING
|
|
||||||
|
|
||||||
def get_plugin_description(self):
|
|
||||||
return constants.METERING
|
|
||||||
|
|
||||||
def get_plugin_type(self):
|
|
||||||
return constants.METERING
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def create_metering_label(self, context, metering_label):
|
|
||||||
"""Create a metering label."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def delete_metering_label(self, context, label_id):
|
|
||||||
"""Delete a metering label."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_metering_label(self, context, label_id, fields=None):
|
|
||||||
"""Get a metering label."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_metering_labels(self, context, filters=None, fields=None,
|
|
||||||
sorts=None, limit=None, marker=None,
|
|
||||||
page_reverse=False):
|
|
||||||
"""List all metering labels."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def create_metering_label_rule(self, context, metering_label_rule):
|
|
||||||
"""Create a metering label rule."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_metering_label_rule(self, context, rule_id, fields=None):
|
|
||||||
"""Get a metering label rule."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def delete_metering_label_rule(self, context, rule_id):
|
|
||||||
"""Delete a metering label rule."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_metering_label_rules(self, context, filters=None, fields=None,
|
|
||||||
sorts=None, limit=None, marker=None,
|
|
||||||
page_reverse=False):
|
|
||||||
"""List all metering label rules."""
|
|
||||||
pass
|
|
|
@ -1,114 +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 webob.exc
|
|
||||||
|
|
||||||
from neutron.api import extensions
|
|
||||||
from neutron.api.v2 import attributes as attr
|
|
||||||
from neutron.common import exceptions as qexception
|
|
||||||
from neutron.extensions import providernet as pnet
|
|
||||||
|
|
||||||
SEGMENTS = 'segments'
|
|
||||||
|
|
||||||
|
|
||||||
class SegmentsSetInConjunctionWithProviders(qexception.InvalidInput):
|
|
||||||
message = _("Segments and provider values cannot both be set.")
|
|
||||||
|
|
||||||
|
|
||||||
class SegmentsContainDuplicateEntry(qexception.InvalidInput):
|
|
||||||
message = _("Duplicate segment entry in request.")
|
|
||||||
|
|
||||||
|
|
||||||
def _convert_and_validate_segments(segments, valid_values=None):
|
|
||||||
unique = set()
|
|
||||||
for segment in segments:
|
|
||||||
unique.add(tuple(segment.iteritems()))
|
|
||||||
network_type = segment.get(pnet.NETWORK_TYPE,
|
|
||||||
attr.ATTR_NOT_SPECIFIED)
|
|
||||||
segment[pnet.NETWORK_TYPE] = network_type
|
|
||||||
physical_network = segment.get(pnet.PHYSICAL_NETWORK,
|
|
||||||
attr.ATTR_NOT_SPECIFIED)
|
|
||||||
segment[pnet.PHYSICAL_NETWORK] = physical_network
|
|
||||||
segmentation_id = segment.get(pnet.SEGMENTATION_ID)
|
|
||||||
if segmentation_id:
|
|
||||||
segment[pnet.SEGMENTATION_ID] = attr.convert_to_int(
|
|
||||||
segmentation_id)
|
|
||||||
else:
|
|
||||||
segment[pnet.SEGMENTATION_ID] = attr.ATTR_NOT_SPECIFIED
|
|
||||||
if len(segment.keys()) != 3:
|
|
||||||
msg = (_("Unrecognized attribute(s) '%s'") %
|
|
||||||
', '.join(set(segment.keys()) -
|
|
||||||
set([pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK,
|
|
||||||
pnet.SEGMENTATION_ID])))
|
|
||||||
raise webob.exc.HTTPBadRequest(msg)
|
|
||||||
if len(unique) != len(segments):
|
|
||||||
raise SegmentsContainDuplicateEntry()
|
|
||||||
|
|
||||||
|
|
||||||
attr.validators['type:convert_segments'] = (
|
|
||||||
_convert_and_validate_segments)
|
|
||||||
|
|
||||||
|
|
||||||
EXTENDED_ATTRIBUTES_2_0 = {
|
|
||||||
'networks': {
|
|
||||||
SEGMENTS: {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:convert_segments': None},
|
|
||||||
'convert_list_to': attr.convert_kvp_list_to_dict,
|
|
||||||
'default': attr.ATTR_NOT_SPECIFIED,
|
|
||||||
'enforce_policy': True,
|
|
||||||
'is_visible': True},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class Multiprovidernet(extensions.ExtensionDescriptor):
|
|
||||||
"""Extension class supporting multiple provider networks.
|
|
||||||
|
|
||||||
This class is used by neutron's extension framework to make
|
|
||||||
metadata about the multiple provider network extension available to
|
|
||||||
clients. No new resources are defined by this extension. Instead,
|
|
||||||
the existing network resource's request and response messages are
|
|
||||||
extended with 'segments' attribute.
|
|
||||||
|
|
||||||
With admin rights, network dictionaries returned will also include
|
|
||||||
'segments' attribute.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "Multi Provider Network"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_alias(cls):
|
|
||||||
return "multi-provider"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_description(cls):
|
|
||||||
return ("Expose mapping of virtual networks to multiple physical "
|
|
||||||
"networks")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_namespace(cls):
|
|
||||||
return "http://docs.openstack.org/ext/multi-provider/api/v1.0"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_updated(cls):
|
|
||||||
return "2013-06-27T10:00:00-00:00"
|
|
||||||
|
|
||||||
def get_extended_resources(self, version):
|
|
||||||
if version == "2.0":
|
|
||||||
return EXTENDED_ATTRIBUTES_2_0
|
|
||||||
else:
|
|
||||||
return {}
|
|
|
@ -1,133 +0,0 @@
|
||||||
# Copyright (c) 2012 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
|
|
||||||
|
|
||||||
# The type of vnic that this port should be attached to
|
|
||||||
VNIC_TYPE = 'binding:vnic_type'
|
|
||||||
# The service will return the vif type for the specific port.
|
|
||||||
VIF_TYPE = 'binding:vif_type'
|
|
||||||
# The service may return a dictionary containing additional
|
|
||||||
# information needed by the interface driver. The set of items
|
|
||||||
# returned may depend on the value of VIF_TYPE.
|
|
||||||
VIF_DETAILS = 'binding:vif_details'
|
|
||||||
# In some cases different implementations may be run on different hosts.
|
|
||||||
# The host on which the port will be allocated.
|
|
||||||
HOST_ID = 'binding:host_id'
|
|
||||||
# The profile will be a dictionary that enables the application running
|
|
||||||
# on the specific host to pass and receive vif port specific information to
|
|
||||||
# the plugin.
|
|
||||||
PROFILE = 'binding:profile'
|
|
||||||
|
|
||||||
# The keys below are used in the VIF_DETAILS attribute to convey
|
|
||||||
# information to the VIF driver.
|
|
||||||
|
|
||||||
# TODO(rkukura): Replace CAP_PORT_FILTER, which nova no longer
|
|
||||||
# understands, with the new set of VIF security details to be used in
|
|
||||||
# the VIF_DETAILS attribute.
|
|
||||||
#
|
|
||||||
# - port_filter : Boolean value indicating Neutron provides port filtering
|
|
||||||
# features such as security group and anti MAC/IP spoofing
|
|
||||||
# - ovs_hybrid_plug: Boolean used to inform Nova that the hybrid plugging
|
|
||||||
# strategy for OVS should be used
|
|
||||||
CAP_PORT_FILTER = 'port_filter'
|
|
||||||
OVS_HYBRID_PLUG = 'ovs_hybrid_plug'
|
|
||||||
|
|
||||||
VIF_TYPE_UNBOUND = 'unbound'
|
|
||||||
VIF_TYPE_BINDING_FAILED = 'binding_failed'
|
|
||||||
VIF_TYPE_IOVISOR = 'iovisor'
|
|
||||||
VIF_TYPE_OVS = 'ovs'
|
|
||||||
VIF_TYPE_IVS = 'ivs'
|
|
||||||
VIF_TYPE_BRIDGE = 'bridge'
|
|
||||||
VIF_TYPE_802_QBG = '802.1qbg'
|
|
||||||
VIF_TYPE_802_QBH = '802.1qbh'
|
|
||||||
VIF_TYPE_HYPERV = 'hyperv'
|
|
||||||
VIF_TYPE_MIDONET = 'midonet'
|
|
||||||
VIF_TYPE_MLNX_DIRECT = 'mlnx_direct'
|
|
||||||
VIF_TYPE_MLNX_HOSTDEV = 'hostdev'
|
|
||||||
VIF_TYPE_OTHER = 'other'
|
|
||||||
VIF_TYPES = [VIF_TYPE_UNBOUND, VIF_TYPE_BINDING_FAILED, VIF_TYPE_OVS,
|
|
||||||
VIF_TYPE_IVS, VIF_TYPE_BRIDGE, VIF_TYPE_802_QBG,
|
|
||||||
VIF_TYPE_802_QBH, VIF_TYPE_HYPERV, VIF_TYPE_MIDONET,
|
|
||||||
VIF_TYPE_MLNX_DIRECT, VIF_TYPE_MLNX_HOSTDEV, VIF_TYPE_OTHER]
|
|
||||||
|
|
||||||
VNIC_NORMAL = 'normal'
|
|
||||||
VNIC_DIRECT = 'direct'
|
|
||||||
VNIC_MACVTAP = 'macvtap'
|
|
||||||
VNIC_TYPES = [VNIC_NORMAL, VNIC_DIRECT, VNIC_MACVTAP]
|
|
||||||
|
|
||||||
EXTENDED_ATTRIBUTES_2_0 = {
|
|
||||||
'ports': {
|
|
||||||
VIF_TYPE: {'allow_post': False, 'allow_put': False,
|
|
||||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
|
||||||
'enforce_policy': True,
|
|
||||||
'is_visible': True},
|
|
||||||
VIF_DETAILS: {'allow_post': False, 'allow_put': False,
|
|
||||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
|
||||||
'enforce_policy': True,
|
|
||||||
'is_visible': True},
|
|
||||||
VNIC_TYPE: {'allow_post': True, 'allow_put': True,
|
|
||||||
'default': VNIC_NORMAL,
|
|
||||||
'is_visible': True,
|
|
||||||
'validate': {'type:values': VNIC_TYPES},
|
|
||||||
'enforce_policy': True},
|
|
||||||
HOST_ID: {'allow_post': True, 'allow_put': True,
|
|
||||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
|
||||||
'is_visible': True,
|
|
||||||
'enforce_policy': True},
|
|
||||||
PROFILE: {'allow_post': True, 'allow_put': True,
|
|
||||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
|
||||||
'enforce_policy': True,
|
|
||||||
'validate': {'type:dict_or_none': None},
|
|
||||||
'is_visible': True},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class Portbindings(extensions.ExtensionDescriptor):
|
|
||||||
"""Extension class supporting port bindings.
|
|
||||||
|
|
||||||
This class is used by neutron's extension framework to make
|
|
||||||
metadata about the port bindings available to external applications.
|
|
||||||
|
|
||||||
With admin rights one will be able to update and read the values.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "Port Binding"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_alias(cls):
|
|
||||||
return "binding"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_description(cls):
|
|
||||||
return "Expose port bindings of a virtual port to external application"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_namespace(cls):
|
|
||||||
return "http://docs.openstack.org/ext/binding/api/v1.0"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_updated(cls):
|
|
||||||
return "2014-02-03T10:00:00-00:00"
|
|
||||||
|
|
||||||
def get_extended_resources(self, version):
|
|
||||||
if version == "2.0":
|
|
||||||
return EXTENDED_ATTRIBUTES_2_0
|
|
||||||
else:
|
|
||||||
return {}
|
|
|
@ -1,78 +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.v2 import attributes
|
|
||||||
from neutron.common import exceptions as qexception
|
|
||||||
|
|
||||||
|
|
||||||
class PortSecurityPortHasSecurityGroup(qexception.InUse):
|
|
||||||
message = _("Port has security group associated. Cannot disable port "
|
|
||||||
"security or ip address until security group is removed")
|
|
||||||
|
|
||||||
|
|
||||||
class PortSecurityAndIPRequiredForSecurityGroups(qexception.InvalidInput):
|
|
||||||
message = _("Port security must be enabled and port must have an IP"
|
|
||||||
" address in order to use security groups.")
|
|
||||||
|
|
||||||
|
|
||||||
class PortSecurityBindingNotFound(qexception.InvalidExtensionEnv):
|
|
||||||
message = _("Port does not have port security binding.")
|
|
||||||
|
|
||||||
PORTSECURITY = 'port_security_enabled'
|
|
||||||
EXTENDED_ATTRIBUTES_2_0 = {
|
|
||||||
'networks': {
|
|
||||||
PORTSECURITY: {'allow_post': True, 'allow_put': True,
|
|
||||||
'convert_to': attributes.convert_to_boolean,
|
|
||||||
'enforce_policy': True,
|
|
||||||
'default': True,
|
|
||||||
'is_visible': True},
|
|
||||||
},
|
|
||||||
'ports': {
|
|
||||||
PORTSECURITY: {'allow_post': True, 'allow_put': True,
|
|
||||||
'convert_to': attributes.convert_to_boolean,
|
|
||||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
|
||||||
'enforce_policy': True,
|
|
||||||
'is_visible': True},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class Portsecurity(object):
|
|
||||||
"""Extension class supporting port security."""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "Port Security"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_alias(cls):
|
|
||||||
return "port-security"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_description(cls):
|
|
||||||
return "Provides port security"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_namespace(cls):
|
|
||||||
return "http://docs.openstack.org/ext/portsecurity/api/v1.0"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_updated(cls):
|
|
||||||
return "2012-07-23T10:00:00-00:00"
|
|
||||||
|
|
||||||
def get_extended_resources(self, version):
|
|
||||||
if version == "2.0":
|
|
||||||
return EXTENDED_ATTRIBUTES_2_0
|
|
||||||
else:
|
|
||||||
return {}
|
|
|
@ -1,95 +0,0 @@
|
||||||
# Copyright (c) 2012 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
|
|
||||||
from neutron.common import exceptions as n_exc
|
|
||||||
|
|
||||||
|
|
||||||
NETWORK_TYPE = 'provider:network_type'
|
|
||||||
PHYSICAL_NETWORK = 'provider:physical_network'
|
|
||||||
SEGMENTATION_ID = 'provider:segmentation_id'
|
|
||||||
|
|
||||||
EXTENDED_ATTRIBUTES_2_0 = {
|
|
||||||
'networks': {
|
|
||||||
NETWORK_TYPE: {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
|
||||||
'enforce_policy': True,
|
|
||||||
'is_visible': True},
|
|
||||||
PHYSICAL_NETWORK: {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
|
||||||
'enforce_policy': True,
|
|
||||||
'is_visible': True},
|
|
||||||
SEGMENTATION_ID: {'allow_post': True, 'allow_put': True,
|
|
||||||
'convert_to': int,
|
|
||||||
'enforce_policy': True,
|
|
||||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
|
||||||
'is_visible': True},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def _raise_if_updates_provider_attributes(attrs):
|
|
||||||
"""Raise exception if provider attributes are present.
|
|
||||||
|
|
||||||
This method is used for plugins that do not support
|
|
||||||
updating provider networks.
|
|
||||||
"""
|
|
||||||
immutable = (NETWORK_TYPE, PHYSICAL_NETWORK, SEGMENTATION_ID)
|
|
||||||
if any(attributes.is_attr_set(attrs.get(a)) for a in immutable):
|
|
||||||
msg = _("Plugin does not support updating provider attributes")
|
|
||||||
raise n_exc.InvalidInput(error_message=msg)
|
|
||||||
|
|
||||||
|
|
||||||
class Providernet(extensions.ExtensionDescriptor):
|
|
||||||
"""Extension class supporting provider networks.
|
|
||||||
|
|
||||||
This class is used by neutron's extension framework to make
|
|
||||||
metadata about the provider network extension available to
|
|
||||||
clients. No new resources are defined by this extension. Instead,
|
|
||||||
the existing network resource's request and response messages are
|
|
||||||
extended with attributes in the provider namespace.
|
|
||||||
|
|
||||||
With admin rights, network dictionaries returned will also include
|
|
||||||
provider attributes.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "Provider Network"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_alias(cls):
|
|
||||||
return "provider"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_description(cls):
|
|
||||||
return "Expose mapping of virtual networks to physical networks"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_namespace(cls):
|
|
||||||
return "http://docs.openstack.org/ext/provider/api/v1.0"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_updated(cls):
|
|
||||||
return "2012-09-07T10:00:00-00:00"
|
|
||||||
|
|
||||||
def get_extended_resources(self, version):
|
|
||||||
if version == "2.0":
|
|
||||||
return EXTENDED_ATTRIBUTES_2_0
|
|
||||||
else:
|
|
||||||
return {}
|
|
|
@ -1,152 +0,0 @@
|
||||||
# Copyright 2011 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 sys
|
|
||||||
|
|
||||||
from oslo.config import cfg
|
|
||||||
import webob
|
|
||||||
|
|
||||||
from neutron.api import extensions
|
|
||||||
from neutron.api.v2 import attributes
|
|
||||||
from neutron.api.v2 import base
|
|
||||||
from neutron.api.v2 import resource
|
|
||||||
from neutron.common import exceptions as n_exc
|
|
||||||
from neutron import manager
|
|
||||||
from neutron.openstack.common import importutils
|
|
||||||
from neutron import quota
|
|
||||||
from neutron import wsgi
|
|
||||||
|
|
||||||
|
|
||||||
RESOURCE_NAME = 'quota'
|
|
||||||
RESOURCE_COLLECTION = RESOURCE_NAME + "s"
|
|
||||||
QUOTAS = quota.QUOTAS
|
|
||||||
DB_QUOTA_DRIVER = 'neutron.db.quota_db.DbQuotaDriver'
|
|
||||||
EXTENDED_ATTRIBUTES_2_0 = {
|
|
||||||
RESOURCE_COLLECTION: {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class QuotaSetsController(wsgi.Controller):
|
|
||||||
|
|
||||||
def __init__(self, plugin):
|
|
||||||
self._resource_name = RESOURCE_NAME
|
|
||||||
self._plugin = plugin
|
|
||||||
self._driver = importutils.import_class(
|
|
||||||
cfg.CONF.QUOTAS.quota_driver
|
|
||||||
)
|
|
||||||
self._update_extended_attributes = True
|
|
||||||
|
|
||||||
def _update_attributes(self):
|
|
||||||
for quota_resource in QUOTAS.resources.iterkeys():
|
|
||||||
attr_dict = EXTENDED_ATTRIBUTES_2_0[RESOURCE_COLLECTION]
|
|
||||||
attr_dict[quota_resource] = {
|
|
||||||
'allow_post': False,
|
|
||||||
'allow_put': True,
|
|
||||||
'convert_to': attributes.convert_to_int,
|
|
||||||
'validate': {'type:range': [-1, sys.maxsize]},
|
|
||||||
'is_visible': True}
|
|
||||||
self._update_extended_attributes = False
|
|
||||||
|
|
||||||
def _get_quotas(self, request, tenant_id):
|
|
||||||
return self._driver.get_tenant_quotas(
|
|
||||||
request.context, QUOTAS.resources, tenant_id)
|
|
||||||
|
|
||||||
def create(self, request, body=None):
|
|
||||||
msg = _('POST requests are not supported on this resource.')
|
|
||||||
raise webob.exc.HTTPNotImplemented(msg)
|
|
||||||
|
|
||||||
def index(self, request):
|
|
||||||
context = request.context
|
|
||||||
self._check_admin(context)
|
|
||||||
return {self._resource_name + "s":
|
|
||||||
self._driver.get_all_quotas(context, QUOTAS.resources)}
|
|
||||||
|
|
||||||
def tenant(self, request):
|
|
||||||
"""Retrieve the tenant info in context."""
|
|
||||||
context = request.context
|
|
||||||
if not context.tenant_id:
|
|
||||||
raise n_exc.QuotaMissingTenant()
|
|
||||||
return {'tenant': {'tenant_id': context.tenant_id}}
|
|
||||||
|
|
||||||
def show(self, request, id):
|
|
||||||
if id != request.context.tenant_id:
|
|
||||||
self._check_admin(request.context,
|
|
||||||
reason=_("Only admin is authorized "
|
|
||||||
"to access quotas for another tenant"))
|
|
||||||
return {self._resource_name: self._get_quotas(request, id)}
|
|
||||||
|
|
||||||
def _check_admin(self, context,
|
|
||||||
reason=_("Only admin can view or configure quota")):
|
|
||||||
if not context.is_admin:
|
|
||||||
raise n_exc.AdminRequired(reason=reason)
|
|
||||||
|
|
||||||
def delete(self, request, id):
|
|
||||||
self._check_admin(request.context)
|
|
||||||
self._driver.delete_tenant_quota(request.context, id)
|
|
||||||
|
|
||||||
def update(self, request, id, body=None):
|
|
||||||
self._check_admin(request.context)
|
|
||||||
if self._update_extended_attributes:
|
|
||||||
self._update_attributes()
|
|
||||||
body = base.Controller.prepare_request_body(
|
|
||||||
request.context, body, False, self._resource_name,
|
|
||||||
EXTENDED_ATTRIBUTES_2_0[RESOURCE_COLLECTION])
|
|
||||||
for key, value in body[self._resource_name].items():
|
|
||||||
self._driver.update_quota_limit(request.context, id, key, value)
|
|
||||||
return {self._resource_name: self._get_quotas(request, id)}
|
|
||||||
|
|
||||||
|
|
||||||
class Quotasv2(extensions.ExtensionDescriptor):
|
|
||||||
"""Quotas management support."""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "Quota management support"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_alias(cls):
|
|
||||||
return RESOURCE_COLLECTION
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_description(cls):
|
|
||||||
description = 'Expose functions for quotas management'
|
|
||||||
if cfg.CONF.QUOTAS.quota_driver == DB_QUOTA_DRIVER:
|
|
||||||
description += ' per tenant'
|
|
||||||
return description
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_namespace(cls):
|
|
||||||
return "http://docs.openstack.org/network/ext/quotas-sets/api/v2.0"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_updated(cls):
|
|
||||||
return "2012-07-29T10:00:00-00:00"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_resources(cls):
|
|
||||||
"""Returns Ext Resources."""
|
|
||||||
controller = resource.Resource(
|
|
||||||
QuotaSetsController(manager.NeutronManager.get_plugin()),
|
|
||||||
faults=base.FAULT_MAP)
|
|
||||||
return [extensions.ResourceExtension(
|
|
||||||
Quotasv2.get_alias(),
|
|
||||||
controller,
|
|
||||||
collection_actions={'tenant': 'GET'})]
|
|
||||||
|
|
||||||
def get_extended_resources(self, version):
|
|
||||||
if version == "2.0":
|
|
||||||
return EXTENDED_ATTRIBUTES_2_0
|
|
||||||
else:
|
|
||||||
return {}
|
|
|
@ -1,71 +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.
|
|
||||||
#
|
|
||||||
# @author: Kaiwei Fan, VMware, Inc
|
|
||||||
|
|
||||||
|
|
||||||
ROUTER_ID = 'router_id'
|
|
||||||
EXTENDED_ATTRIBUTES_2_0 = {
|
|
||||||
'vips': {
|
|
||||||
ROUTER_ID: {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid_or_none': None},
|
|
||||||
'default': None, 'is_visible': True},
|
|
||||||
},
|
|
||||||
'pools': {
|
|
||||||
ROUTER_ID: {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid_or_none': None},
|
|
||||||
'default': None, 'is_visible': True},
|
|
||||||
},
|
|
||||||
'health_monitors': {
|
|
||||||
ROUTER_ID: {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid_or_none': None},
|
|
||||||
'default': None, 'is_visible': True},
|
|
||||||
},
|
|
||||||
|
|
||||||
'firewalls': {
|
|
||||||
ROUTER_ID: {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid_or_none': None},
|
|
||||||
'default': None, 'is_visible': True},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class Routedserviceinsertion(object):
|
|
||||||
"""Extension class supporting routed service type."""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "Routed Service Insertion"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_alias(cls):
|
|
||||||
return "routed-service-insertion"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_description(cls):
|
|
||||||
return "Provides routed service type"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_namespace(cls):
|
|
||||||
return ""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_updated(cls):
|
|
||||||
return "2013-01-29T00:00:00-00:00"
|
|
||||||
|
|
||||||
def get_extended_resources(self, version):
|
|
||||||
if version == "2.0":
|
|
||||||
return EXTENDED_ATTRIBUTES_2_0
|
|
||||||
else:
|
|
||||||
return {}
|
|
|
@ -1,55 +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.
|
|
||||||
#
|
|
||||||
# @author: Kaiwei Fan, VMware, Inc
|
|
||||||
|
|
||||||
|
|
||||||
SERVICE_TYPE_ID = 'service_type_id'
|
|
||||||
EXTENDED_ATTRIBUTES_2_0 = {
|
|
||||||
'routers': {
|
|
||||||
SERVICE_TYPE_ID: {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid_or_none': None},
|
|
||||||
'default': None, 'is_visible': True},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class Routerservicetype(object):
|
|
||||||
"""Extension class supporting router service type."""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "Router Service Type"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_alias(cls):
|
|
||||||
return "router-service-type"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_description(cls):
|
|
||||||
return "Provides router service type"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_namespace(cls):
|
|
||||||
return ""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_updated(cls):
|
|
||||||
return "2013-01-29T00:00:00-00:00"
|
|
||||||
|
|
||||||
def get_extended_resources(self, version):
|
|
||||||
if version == "2.0":
|
|
||||||
return EXTENDED_ATTRIBUTES_2_0
|
|
||||||
else:
|
|
||||||
return {}
|
|
|
@ -1,354 +0,0 @@
|
||||||
# Copyright (c) 2012 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
|
|
||||||
import netaddr
|
|
||||||
|
|
||||||
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 base
|
|
||||||
from neutron.common import constants as const
|
|
||||||
from neutron.common import exceptions as qexception
|
|
||||||
from neutron import manager
|
|
||||||
from neutron.openstack.common import uuidutils
|
|
||||||
from neutron import quota
|
|
||||||
|
|
||||||
|
|
||||||
# Security group Exceptions
|
|
||||||
class SecurityGroupInvalidPortRange(qexception.InvalidInput):
|
|
||||||
message = _("For TCP/UDP protocols, port_range_min must be "
|
|
||||||
"<= port_range_max")
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupInvalidPortValue(qexception.InvalidInput):
|
|
||||||
message = _("Invalid value for port %(port)s")
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupInvalidIcmpValue(qexception.InvalidInput):
|
|
||||||
message = _("Invalid value for ICMP %(field)s (%(attr)s) "
|
|
||||||
"%(value)s. It must be 0 to 255.")
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupMissingIcmpType(qexception.InvalidInput):
|
|
||||||
message = _("ICMP code (port-range-max) %(value)s is provided"
|
|
||||||
" but ICMP type (port-range-min) is missing.")
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupInUse(qexception.InUse):
|
|
||||||
message = _("Security Group %(id)s in use.")
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupCannotRemoveDefault(qexception.InUse):
|
|
||||||
message = _("Removing default security group not allowed.")
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupCannotUpdateDefault(qexception.InUse):
|
|
||||||
message = _("Updating default security group not allowed.")
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupDefaultAlreadyExists(qexception.InUse):
|
|
||||||
message = _("Default security group already exists.")
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupRuleInvalidProtocol(qexception.InvalidInput):
|
|
||||||
message = _("Security group rule protocol %(protocol)s not supported. "
|
|
||||||
"Only protocol values %(values)s and their integer "
|
|
||||||
"representation (0 to 255) are supported.")
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupRulesNotSingleTenant(qexception.InvalidInput):
|
|
||||||
message = _("Multiple tenant_ids in bulk security group rule create"
|
|
||||||
" not allowed")
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupRemoteGroupAndRemoteIpPrefix(qexception.InvalidInput):
|
|
||||||
message = _("Only remote_ip_prefix or remote_group_id may "
|
|
||||||
"be provided.")
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupProtocolRequiredWithPorts(qexception.InvalidInput):
|
|
||||||
message = _("Must also specifiy protocol if port range is given.")
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupNotSingleGroupRules(qexception.InvalidInput):
|
|
||||||
message = _("Only allowed to update rules for "
|
|
||||||
"one security profile at a time")
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupNotFound(qexception.NotFound):
|
|
||||||
message = _("Security group %(id)s does not exist")
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupRuleNotFound(qexception.NotFound):
|
|
||||||
message = _("Security group rule %(id)s does not exist")
|
|
||||||
|
|
||||||
|
|
||||||
class DuplicateSecurityGroupRuleInPost(qexception.InUse):
|
|
||||||
message = _("Duplicate Security Group Rule in POST.")
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupRuleExists(qexception.InUse):
|
|
||||||
message = _("Security group rule already exists. Group id is %(id)s.")
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupRuleParameterConflict(qexception.InvalidInput):
|
|
||||||
message = _("Conflicting value ethertype %(ethertype)s for CIDR %(cidr)s")
|
|
||||||
|
|
||||||
|
|
||||||
def convert_protocol(value):
|
|
||||||
if value is None:
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
val = int(value)
|
|
||||||
if val >= 0 and val <= 255:
|
|
||||||
return val
|
|
||||||
raise SecurityGroupRuleInvalidProtocol(
|
|
||||||
protocol=value, values=sg_supported_protocols)
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
if value.lower() in sg_supported_protocols:
|
|
||||||
return value.lower()
|
|
||||||
raise SecurityGroupRuleInvalidProtocol(
|
|
||||||
protocol=value, values=sg_supported_protocols)
|
|
||||||
except AttributeError:
|
|
||||||
raise SecurityGroupRuleInvalidProtocol(
|
|
||||||
protocol=value, values=sg_supported_protocols)
|
|
||||||
|
|
||||||
|
|
||||||
def convert_ethertype_to_case_insensitive(value):
|
|
||||||
if isinstance(value, basestring):
|
|
||||||
for ethertype in sg_supported_ethertypes:
|
|
||||||
if ethertype.lower() == value.lower():
|
|
||||||
return ethertype
|
|
||||||
|
|
||||||
|
|
||||||
def convert_validate_port_value(port):
|
|
||||||
if port is None:
|
|
||||||
return port
|
|
||||||
try:
|
|
||||||
val = int(port)
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
raise SecurityGroupInvalidPortValue(port=port)
|
|
||||||
|
|
||||||
if val >= 0 and val <= 65535:
|
|
||||||
return val
|
|
||||||
else:
|
|
||||||
raise SecurityGroupInvalidPortValue(port=port)
|
|
||||||
|
|
||||||
|
|
||||||
def convert_to_uuid_list_or_none(value_list):
|
|
||||||
if value_list is None:
|
|
||||||
return
|
|
||||||
for sg_id in value_list:
|
|
||||||
if not uuidutils.is_uuid_like(sg_id):
|
|
||||||
msg = _("'%s' is not an integer or uuid") % sg_id
|
|
||||||
raise qexception.InvalidInput(error_message=msg)
|
|
||||||
return value_list
|
|
||||||
|
|
||||||
|
|
||||||
def convert_ip_prefix_to_cidr(ip_prefix):
|
|
||||||
if not ip_prefix:
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
cidr = netaddr.IPNetwork(ip_prefix)
|
|
||||||
return str(cidr)
|
|
||||||
except (ValueError, TypeError, netaddr.AddrFormatError):
|
|
||||||
raise qexception.InvalidCIDR(input=ip_prefix)
|
|
||||||
|
|
||||||
|
|
||||||
def _validate_name_not_default(data, valid_values=None):
|
|
||||||
if data == "default":
|
|
||||||
raise SecurityGroupDefaultAlreadyExists()
|
|
||||||
|
|
||||||
|
|
||||||
attr.validators['type:name_not_default'] = _validate_name_not_default
|
|
||||||
|
|
||||||
sg_supported_protocols = [None, const.PROTO_NAME_TCP,
|
|
||||||
const.PROTO_NAME_UDP, const.PROTO_NAME_ICMP]
|
|
||||||
sg_supported_ethertypes = ['IPv4', 'IPv6']
|
|
||||||
|
|
||||||
# Attribute Map
|
|
||||||
RESOURCE_ATTRIBUTE_MAP = {
|
|
||||||
'security_groups': {
|
|
||||||
'id': {'allow_post': False, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid': None},
|
|
||||||
'is_visible': True,
|
|
||||||
'primary_key': True},
|
|
||||||
'name': {'allow_post': True, 'allow_put': True,
|
|
||||||
'is_visible': True, 'default': '',
|
|
||||||
'validate': {'type:name_not_default': None}},
|
|
||||||
'description': {'allow_post': True, 'allow_put': True,
|
|
||||||
'is_visible': True, 'default': ''},
|
|
||||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
|
||||||
'required_by_policy': True,
|
|
||||||
'is_visible': True},
|
|
||||||
'security_group_rules': {'allow_post': False, 'allow_put': False,
|
|
||||||
'is_visible': True},
|
|
||||||
},
|
|
||||||
'security_group_rules': {
|
|
||||||
'id': {'allow_post': False, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid': None},
|
|
||||||
'is_visible': True,
|
|
||||||
'primary_key': True},
|
|
||||||
'security_group_id': {'allow_post': True, 'allow_put': False,
|
|
||||||
'is_visible': True, 'required_by_policy': True},
|
|
||||||
'remote_group_id': {'allow_post': True, 'allow_put': False,
|
|
||||||
'default': None, 'is_visible': True},
|
|
||||||
'direction': {'allow_post': True, 'allow_put': True,
|
|
||||||
'is_visible': True,
|
|
||||||
'validate': {'type:values': ['ingress', 'egress']}},
|
|
||||||
'protocol': {'allow_post': True, 'allow_put': False,
|
|
||||||
'is_visible': True, 'default': None,
|
|
||||||
'convert_to': convert_protocol},
|
|
||||||
'port_range_min': {'allow_post': True, 'allow_put': False,
|
|
||||||
'convert_to': convert_validate_port_value,
|
|
||||||
'default': None, 'is_visible': True},
|
|
||||||
'port_range_max': {'allow_post': True, 'allow_put': False,
|
|
||||||
'convert_to': convert_validate_port_value,
|
|
||||||
'default': None, 'is_visible': True},
|
|
||||||
'ethertype': {'allow_post': True, 'allow_put': False,
|
|
||||||
'is_visible': True, 'default': 'IPv4',
|
|
||||||
'convert_to': convert_ethertype_to_case_insensitive,
|
|
||||||
'validate': {'type:values': sg_supported_ethertypes}},
|
|
||||||
'remote_ip_prefix': {'allow_post': True, 'allow_put': False,
|
|
||||||
'default': None, 'is_visible': True,
|
|
||||||
'convert_to': convert_ip_prefix_to_cidr},
|
|
||||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
|
||||||
'required_by_policy': True,
|
|
||||||
'is_visible': True},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SECURITYGROUPS = 'security_groups'
|
|
||||||
EXTENDED_ATTRIBUTES_2_0 = {
|
|
||||||
'ports': {SECURITYGROUPS: {'allow_post': True,
|
|
||||||
'allow_put': True,
|
|
||||||
'is_visible': True,
|
|
||||||
'convert_to': convert_to_uuid_list_or_none,
|
|
||||||
'default': attr.ATTR_NOT_SPECIFIED}}}
|
|
||||||
security_group_quota_opts = [
|
|
||||||
cfg.IntOpt('quota_security_group',
|
|
||||||
default=10,
|
|
||||||
help=_('Number of security groups allowed per tenant. '
|
|
||||||
'A negative value means unlimited.')),
|
|
||||||
cfg.IntOpt('quota_security_group_rule',
|
|
||||||
default=100,
|
|
||||||
help=_('Number of security rules allowed per tenant. '
|
|
||||||
'A negative value means unlimited.')),
|
|
||||||
]
|
|
||||||
cfg.CONF.register_opts(security_group_quota_opts, 'QUOTAS')
|
|
||||||
|
|
||||||
|
|
||||||
class Securitygroup(extensions.ExtensionDescriptor):
|
|
||||||
"""Security group extension."""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "security-group"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_alias(cls):
|
|
||||||
return "security-group"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_description(cls):
|
|
||||||
return "The security groups extension."
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_namespace(cls):
|
|
||||||
# todo
|
|
||||||
return "http://docs.openstack.org/ext/securitygroups/api/v2.0"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_updated(cls):
|
|
||||||
return "2012-10-05T10: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))
|
|
||||||
exts = []
|
|
||||||
plugin = manager.NeutronManager.get_plugin()
|
|
||||||
for resource_name in ['security_group', 'security_group_rule']:
|
|
||||||
collection_name = resource_name.replace('_', '-') + "s"
|
|
||||||
params = RESOURCE_ATTRIBUTE_MAP.get(resource_name + "s", dict())
|
|
||||||
quota.QUOTAS.register_resource_by_name(resource_name)
|
|
||||||
controller = base.create_resource(collection_name,
|
|
||||||
resource_name,
|
|
||||||
plugin, params, allow_bulk=True,
|
|
||||||
allow_pagination=True,
|
|
||||||
allow_sorting=True)
|
|
||||||
|
|
||||||
ex = extensions.ResourceExtension(collection_name,
|
|
||||||
controller,
|
|
||||||
attr_map=params)
|
|
||||||
exts.append(ex)
|
|
||||||
|
|
||||||
return exts
|
|
||||||
|
|
||||||
def get_extended_resources(self, version):
|
|
||||||
if version == "2.0":
|
|
||||||
return dict(EXTENDED_ATTRIBUTES_2_0.items() +
|
|
||||||
RESOURCE_ATTRIBUTE_MAP.items())
|
|
||||||
else:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
|
||||||
class SecurityGroupPluginBase(object):
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def create_security_group(self, context, security_group):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def update_security_group(self, context, id, security_group):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def delete_security_group(self, context, id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_security_groups(self, context, filters=None, fields=None,
|
|
||||||
sorts=None, limit=None, marker=None,
|
|
||||||
page_reverse=False):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_security_group(self, context, id, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def create_security_group_rule(self, context, security_group_rule):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def delete_security_group_rule(self, context, id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_security_group_rules(self, context, filters=None, fields=None,
|
|
||||||
sorts=None, limit=None, marker=None,
|
|
||||||
page_reverse=False):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_security_group_rule(self, context, id, fields=None):
|
|
||||||
pass
|
|
|
@ -1,91 +0,0 @@
|
||||||
# Copyright 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.
|
|
||||||
#
|
|
||||||
# @author: Salvatore Orlando, VMware
|
|
||||||
#
|
|
||||||
|
|
||||||
from neutron.api import extensions
|
|
||||||
from neutron.api.v2 import attributes
|
|
||||||
from neutron.api.v2 import base
|
|
||||||
from neutron.db import servicetype_db
|
|
||||||
from neutron.openstack.common import log as logging
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
RESOURCE_NAME = "service_provider"
|
|
||||||
COLLECTION_NAME = "%ss" % RESOURCE_NAME
|
|
||||||
SERVICE_ATTR = 'service_type'
|
|
||||||
PLUGIN_ATTR = 'plugin'
|
|
||||||
DRIVER_ATTR = 'driver'
|
|
||||||
EXT_ALIAS = 'service-type'
|
|
||||||
|
|
||||||
# Attribute Map for Service Provider Resource
|
|
||||||
# Allow read-only access
|
|
||||||
RESOURCE_ATTRIBUTE_MAP = {
|
|
||||||
COLLECTION_NAME: {
|
|
||||||
'service_type': {'allow_post': False, 'allow_put': False,
|
|
||||||
'is_visible': True},
|
|
||||||
'name': {'allow_post': False, 'allow_put': False,
|
|
||||||
'is_visible': True},
|
|
||||||
'default': {'allow_post': False, 'allow_put': False,
|
|
||||||
'is_visible': True},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class Servicetype(extensions.ExtensionDescriptor):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return _("Neutron Service Type Management")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_alias(cls):
|
|
||||||
return EXT_ALIAS
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_description(cls):
|
|
||||||
return _("API for retrieving service providers for "
|
|
||||||
"Neutron advanced services")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_namespace(cls):
|
|
||||||
return "http://docs.openstack.org/ext/neutron/service-type/api/v1.0"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_updated(cls):
|
|
||||||
return "2013-01-20T00:00:00-00:00"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_resources(cls):
|
|
||||||
"""Returns Extended Resource for service type management."""
|
|
||||||
my_plurals = [(key, key[:-1]) for key in RESOURCE_ATTRIBUTE_MAP.keys()]
|
|
||||||
attributes.PLURALS.update(dict(my_plurals))
|
|
||||||
attr_map = RESOURCE_ATTRIBUTE_MAP[COLLECTION_NAME]
|
|
||||||
collection_name = COLLECTION_NAME.replace('_', '-')
|
|
||||||
controller = base.create_resource(
|
|
||||||
collection_name,
|
|
||||||
RESOURCE_NAME,
|
|
||||||
servicetype_db.ServiceTypeManager.get_instance(),
|
|
||||||
attr_map)
|
|
||||||
return [extensions.ResourceExtension(collection_name,
|
|
||||||
controller,
|
|
||||||
attr_map=attr_map)]
|
|
||||||
|
|
||||||
def get_extended_resources(self, version):
|
|
||||||
if version == "2.0":
|
|
||||||
return RESOURCE_ATTRIBUTE_MAP
|
|
||||||
else:
|
|
||||||
return {}
|
|
|
@ -1,482 +0,0 @@
|
||||||
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
|
|
||||||
# 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: Swaminathan Vasudevan, Hewlett-Packard.
|
|
||||||
|
|
||||||
import abc
|
|
||||||
|
|
||||||
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.plugins.common import constants
|
|
||||||
from neutron.services import service_base
|
|
||||||
|
|
||||||
|
|
||||||
class VPNServiceNotFound(qexception.NotFound):
|
|
||||||
message = _("VPNService %(vpnservice_id)s could not be found")
|
|
||||||
|
|
||||||
|
|
||||||
class IPsecSiteConnectionNotFound(qexception.NotFound):
|
|
||||||
message = _("ipsec_site_connection %(ipsecsite_conn_id)s not found")
|
|
||||||
|
|
||||||
|
|
||||||
class IPsecSiteConnectionDpdIntervalValueError(qexception.InvalidInput):
|
|
||||||
message = _("ipsec_site_connection %(attr)s is "
|
|
||||||
"equal to or less than dpd_interval")
|
|
||||||
|
|
||||||
|
|
||||||
class IPsecSiteConnectionMtuError(qexception.InvalidInput):
|
|
||||||
message = _("ipsec_site_connection MTU %(mtu)d is too small "
|
|
||||||
"for ipv%(version)s")
|
|
||||||
|
|
||||||
|
|
||||||
class IKEPolicyNotFound(qexception.NotFound):
|
|
||||||
message = _("IKEPolicy %(ikepolicy_id)s could not be found")
|
|
||||||
|
|
||||||
|
|
||||||
class IPsecPolicyNotFound(qexception.NotFound):
|
|
||||||
message = _("IPsecPolicy %(ipsecpolicy_id)s could not be found")
|
|
||||||
|
|
||||||
|
|
||||||
class IKEPolicyInUse(qexception.InUse):
|
|
||||||
message = _("IKEPolicy %(ikepolicy_id)s is in use by existing "
|
|
||||||
"IPsecSiteConnection and can't be updated or deleted")
|
|
||||||
|
|
||||||
|
|
||||||
class VPNServiceInUse(qexception.InUse):
|
|
||||||
message = _("VPNService %(vpnservice_id)s is still in use")
|
|
||||||
|
|
||||||
|
|
||||||
class RouterInUseByVPNService(qexception.InUse):
|
|
||||||
message = _("Router %(router_id)s is used by VPNService %(vpnservice_id)s")
|
|
||||||
|
|
||||||
|
|
||||||
class VPNStateInvalidToUpdate(qexception.BadRequest):
|
|
||||||
message = _("Invalid state %(state)s of vpnaas resource %(id)s"
|
|
||||||
" for updating")
|
|
||||||
|
|
||||||
|
|
||||||
class IPsecPolicyInUse(qexception.InUse):
|
|
||||||
message = _("IPsecPolicy %(ipsecpolicy_id)s is in use by existing "
|
|
||||||
"IPsecSiteConnection and can't be updated or deleted")
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceDriverImportError(qexception.NeutronException):
|
|
||||||
message = _("Can not load driver :%(device_driver)s")
|
|
||||||
|
|
||||||
|
|
||||||
class SubnetIsNotConnectedToRouter(qexception.BadRequest):
|
|
||||||
message = _("Subnet %(subnet_id)s is not "
|
|
||||||
"connected to Router %(router_id)s")
|
|
||||||
|
|
||||||
|
|
||||||
class RouterIsNotExternal(qexception.BadRequest):
|
|
||||||
message = _("Router %(router_id)s has no external network gateway set")
|
|
||||||
|
|
||||||
|
|
||||||
vpn_supported_initiators = ['bi-directional', 'response-only']
|
|
||||||
vpn_supported_encryption_algorithms = ['3des', 'aes-128',
|
|
||||||
'aes-192', 'aes-256']
|
|
||||||
vpn_dpd_supported_actions = [
|
|
||||||
'hold', 'clear', 'restart', 'restart-by-peer', 'disabled'
|
|
||||||
]
|
|
||||||
vpn_supported_transform_protocols = ['esp', 'ah', 'ah-esp']
|
|
||||||
vpn_supported_encapsulation_mode = ['tunnel', 'transport']
|
|
||||||
#TODO(nati) add kilobytes when we support it
|
|
||||||
vpn_supported_lifetime_units = ['seconds']
|
|
||||||
vpn_supported_pfs = ['group2', 'group5', 'group14']
|
|
||||||
vpn_supported_ike_versions = ['v1', 'v2']
|
|
||||||
vpn_supported_auth_mode = ['psk']
|
|
||||||
vpn_supported_auth_algorithms = ['sha1']
|
|
||||||
vpn_supported_phase1_negotiation_mode = ['main']
|
|
||||||
|
|
||||||
vpn_lifetime_limits = (60, attr.UNLIMITED)
|
|
||||||
positive_int = (0, attr.UNLIMITED)
|
|
||||||
|
|
||||||
RESOURCE_ATTRIBUTE_MAP = {
|
|
||||||
|
|
||||||
'vpnservices': {
|
|
||||||
'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,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'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': ''},
|
|
||||||
'subnet_id': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'router_id': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'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}
|
|
||||||
},
|
|
||||||
|
|
||||||
'ipsec_site_connections': {
|
|
||||||
'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,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'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': ''},
|
|
||||||
'peer_address': {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'peer_id': {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'peer_cidrs': {'allow_post': True, 'allow_put': True,
|
|
||||||
'convert_to': attr.convert_to_list,
|
|
||||||
'validate': {'type:subnet_list': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'route_mode': {'allow_post': False, 'allow_put': False,
|
|
||||||
'default': 'static',
|
|
||||||
'is_visible': True},
|
|
||||||
'mtu': {'allow_post': True, 'allow_put': True,
|
|
||||||
'default': '1500',
|
|
||||||
'validate': {'type:range': positive_int},
|
|
||||||
'convert_to': attr.convert_to_int,
|
|
||||||
'is_visible': True},
|
|
||||||
'initiator': {'allow_post': True, 'allow_put': True,
|
|
||||||
'default': 'bi-directional',
|
|
||||||
'validate': {'type:values': vpn_supported_initiators},
|
|
||||||
'is_visible': True},
|
|
||||||
'auth_mode': {'allow_post': False, 'allow_put': False,
|
|
||||||
'default': 'psk',
|
|
||||||
'validate': {'type:values': vpn_supported_auth_mode},
|
|
||||||
'is_visible': True},
|
|
||||||
'psk': {'allow_post': True, 'allow_put': True,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'dpd': {'allow_post': True, 'allow_put': True,
|
|
||||||
'convert_to': attr.convert_none_to_empty_dict,
|
|
||||||
'is_visible': True,
|
|
||||||
'default': {},
|
|
||||||
'validate': {
|
|
||||||
'type:dict_or_empty': {
|
|
||||||
'actions': {
|
|
||||||
'type:values': vpn_dpd_supported_actions,
|
|
||||||
},
|
|
||||||
'interval': {
|
|
||||||
'type:range': positive_int
|
|
||||||
},
|
|
||||||
'timeout': {
|
|
||||||
'type:range': positive_int
|
|
||||||
}}}},
|
|
||||||
'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},
|
|
||||||
'vpnservice_id': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'ikepolicy_id': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid': None},
|
|
||||||
'is_visible': True},
|
|
||||||
'ipsecpolicy_id': {'allow_post': True, 'allow_put': False,
|
|
||||||
'validate': {'type:uuid': None},
|
|
||||||
'is_visible': True}
|
|
||||||
},
|
|
||||||
|
|
||||||
'ipsecpolicies': {
|
|
||||||
'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,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'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': ''},
|
|
||||||
'transform_protocol': {
|
|
||||||
'allow_post': True,
|
|
||||||
'allow_put': True,
|
|
||||||
'default': 'esp',
|
|
||||||
'validate': {
|
|
||||||
'type:values': vpn_supported_transform_protocols},
|
|
||||||
'is_visible': True},
|
|
||||||
'auth_algorithm': {
|
|
||||||
'allow_post': True,
|
|
||||||
'allow_put': True,
|
|
||||||
'default': 'sha1',
|
|
||||||
'validate': {
|
|
||||||
'type:values': vpn_supported_auth_algorithms
|
|
||||||
},
|
|
||||||
'is_visible': True},
|
|
||||||
'encryption_algorithm': {
|
|
||||||
'allow_post': True,
|
|
||||||
'allow_put': True,
|
|
||||||
'default': 'aes-128',
|
|
||||||
'validate': {
|
|
||||||
'type:values': vpn_supported_encryption_algorithms
|
|
||||||
},
|
|
||||||
'is_visible': True},
|
|
||||||
'encapsulation_mode': {
|
|
||||||
'allow_post': True,
|
|
||||||
'allow_put': True,
|
|
||||||
'default': 'tunnel',
|
|
||||||
'validate': {
|
|
||||||
'type:values': vpn_supported_encapsulation_mode
|
|
||||||
},
|
|
||||||
'is_visible': True},
|
|
||||||
'lifetime': {'allow_post': True, 'allow_put': True,
|
|
||||||
'convert_to': attr.convert_none_to_empty_dict,
|
|
||||||
'default': {},
|
|
||||||
'validate': {
|
|
||||||
'type:dict_or_empty': {
|
|
||||||
'units': {
|
|
||||||
'type:values': vpn_supported_lifetime_units,
|
|
||||||
},
|
|
||||||
'value': {
|
|
||||||
'type:range': vpn_lifetime_limits
|
|
||||||
}}},
|
|
||||||
'is_visible': True},
|
|
||||||
'pfs': {'allow_post': True, 'allow_put': True,
|
|
||||||
'default': 'group5',
|
|
||||||
'validate': {'type:values': vpn_supported_pfs},
|
|
||||||
'is_visible': True}
|
|
||||||
},
|
|
||||||
|
|
||||||
'ikepolicies': {
|
|
||||||
'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,
|
|
||||||
'validate': {'type:string': None},
|
|
||||||
'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': ''},
|
|
||||||
'auth_algorithm': {'allow_post': True, 'allow_put': True,
|
|
||||||
'default': 'sha1',
|
|
||||||
'validate': {
|
|
||||||
'type:values': vpn_supported_auth_algorithms},
|
|
||||||
'is_visible': True},
|
|
||||||
'encryption_algorithm': {
|
|
||||||
'allow_post': True, 'allow_put': True,
|
|
||||||
'default': 'aes-128',
|
|
||||||
'validate': {'type:values': vpn_supported_encryption_algorithms},
|
|
||||||
'is_visible': True},
|
|
||||||
'phase1_negotiation_mode': {
|
|
||||||
'allow_post': True, 'allow_put': True,
|
|
||||||
'default': 'main',
|
|
||||||
'validate': {
|
|
||||||
'type:values': vpn_supported_phase1_negotiation_mode
|
|
||||||
},
|
|
||||||
'is_visible': True},
|
|
||||||
'lifetime': {'allow_post': True, 'allow_put': True,
|
|
||||||
'convert_to': attr.convert_none_to_empty_dict,
|
|
||||||
'default': {},
|
|
||||||
'validate': {
|
|
||||||
'type:dict_or_empty': {
|
|
||||||
'units': {
|
|
||||||
'type:values': vpn_supported_lifetime_units,
|
|
||||||
},
|
|
||||||
'value': {
|
|
||||||
'type:range': vpn_lifetime_limits,
|
|
||||||
}}},
|
|
||||||
'is_visible': True},
|
|
||||||
'ike_version': {'allow_post': True, 'allow_put': True,
|
|
||||||
'default': 'v1',
|
|
||||||
'validate': {
|
|
||||||
'type:values': vpn_supported_ike_versions},
|
|
||||||
'is_visible': True},
|
|
||||||
'pfs': {'allow_post': True, 'allow_put': True,
|
|
||||||
'default': 'group5',
|
|
||||||
'validate': {'type:values': vpn_supported_pfs},
|
|
||||||
'is_visible': True}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class Vpnaas(extensions.ExtensionDescriptor):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "VPN service"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_alias(cls):
|
|
||||||
return "vpnaas"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_description(cls):
|
|
||||||
return "Extension for VPN service"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_namespace(cls):
|
|
||||||
return "https://wiki.openstack.org/Neutron/VPNaaS"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_updated(cls):
|
|
||||||
return "2013-05-29T10:00:00-00:00"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_resources(cls):
|
|
||||||
special_mappings = {'ikepolicies': 'ikepolicy',
|
|
||||||
'ipsecpolicies': 'ipsecpolicy'}
|
|
||||||
plural_mappings = resource_helper.build_plural_mappings(
|
|
||||||
special_mappings, RESOURCE_ATTRIBUTE_MAP)
|
|
||||||
plural_mappings['peer_cidrs'] = 'peer_cidr'
|
|
||||||
attr.PLURALS.update(plural_mappings)
|
|
||||||
return resource_helper.build_resource_info(plural_mappings,
|
|
||||||
RESOURCE_ATTRIBUTE_MAP,
|
|
||||||
constants.VPN,
|
|
||||||
register_quota=True,
|
|
||||||
translate_name=True)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_plugin_interface(cls):
|
|
||||||
return VPNPluginBase
|
|
||||||
|
|
||||||
def update_attributes_map(self, attributes):
|
|
||||||
super(Vpnaas, 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 VPNPluginBase(service_base.ServicePluginBase):
|
|
||||||
|
|
||||||
def get_plugin_name(self):
|
|
||||||
return constants.VPN
|
|
||||||
|
|
||||||
def get_plugin_type(self):
|
|
||||||
return constants.VPN
|
|
||||||
|
|
||||||
def get_plugin_description(self):
|
|
||||||
return 'VPN service plugin'
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_vpnservices(self, context, filters=None, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_vpnservice(self, context, vpnservice_id, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def create_vpnservice(self, context, vpnservice):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def update_vpnservice(self, context, vpnservice_id, vpnservice):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def delete_vpnservice(self, context, vpnservice_id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_ipsec_site_connections(self, context, filters=None, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_ipsec_site_connection(self, context,
|
|
||||||
ipsecsite_conn_id, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def create_ipsec_site_connection(self, context, ipsec_site_connection):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def update_ipsec_site_connection(self, context,
|
|
||||||
ipsecsite_conn_id, ipsec_site_connection):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def delete_ipsec_site_connection(self, context, ipsecsite_conn_id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_ikepolicy(self, context, ikepolicy_id, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_ikepolicies(self, context, filters=None, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def create_ikepolicy(self, context, ikepolicy):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def update_ikepolicy(self, context, ikepolicy_id, ikepolicy):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def delete_ikepolicy(self, context, ikepolicy_id):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_ipsecpolicies(self, context, filters=None, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_ipsecpolicy(self, context, ipsecpolicy_id, fields=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def create_ipsecpolicy(self, context, ipsecpolicy):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def update_ipsecpolicy(self, context, ipsecpolicy_id, ipsecpolicy):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def delete_ipsecpolicy(self, context, ipsecpolicy_id):
|
|
||||||
pass
|
|
Loading…
Reference in New Issue