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