Merge remote-tracking branch 'origin' into merge-branch
This commit merges the master neutron branch into the feature/lbaasv2 branch. This is needed to get the feature/lbaasv2 branch building again. Change-Id: Iba59aa20adc6b369b4b9d250afee406159287ba1
This commit is contained in:
commit
d969131246
124
.pylintrc
124
.pylintrc
|
@ -2,17 +2,97 @@
|
|||
[MASTER]
|
||||
# Add <file or directory> to the black list. It should be a base name, not a
|
||||
# path. You may set this option multiple times.
|
||||
ignore=test
|
||||
#
|
||||
# Note the 'openstack' below is intended to match only
|
||||
# neutron.openstack.common. If we ever have another 'openstack'
|
||||
# dirname, then we'll need to expand the ignore features in pylint :/
|
||||
ignore=.git,tests,openstack
|
||||
|
||||
[Messages Control]
|
||||
# NOTE(justinsb): We might want to have a 2nd strict pylintrc in future
|
||||
# C0111: Don't require docstrings on every method
|
||||
# W0511: TODOs in code comments are fine.
|
||||
# W0142: *args and **kwargs are fine.
|
||||
# W0622: Redefining id is fine.
|
||||
disable=C0111,W0511,W0142,W0622
|
||||
[MESSAGES CONTROL]
|
||||
# NOTE(gus): This is a long list. A number of these are important and
|
||||
# should be re-enabled once the offending code is fixed (or marked
|
||||
# with a local disable)
|
||||
disable=
|
||||
# "F" Fatal errors that prevent further processing
|
||||
import-error,
|
||||
# "I" Informational noise
|
||||
locally-disabled,
|
||||
# "E" Error for important programming issues (likely bugs)
|
||||
access-member-before-definition,
|
||||
assignment-from-no-return,
|
||||
bad-except-order,
|
||||
bad-super-call,
|
||||
maybe-no-member,
|
||||
no-member,
|
||||
no-method-argument,
|
||||
no-name-in-module,
|
||||
no-self-argument,
|
||||
not-callable,
|
||||
no-value-for-parameter,
|
||||
super-on-old-class,
|
||||
too-few-format-args,
|
||||
# "W" Warnings for stylistic problems or minor programming issues
|
||||
abstract-method,
|
||||
anomalous-backslash-in-string,
|
||||
anomalous-unicode-escape-in-string,
|
||||
arguments-differ,
|
||||
attribute-defined-outside-init,
|
||||
bad-builtin,
|
||||
bad-indentation,
|
||||
broad-except,
|
||||
dangerous-default-value,
|
||||
deprecated-lambda,
|
||||
duplicate-key,
|
||||
expression-not-assigned,
|
||||
fixme,
|
||||
global-statement,
|
||||
global-variable-not-assigned,
|
||||
logging-not-lazy,
|
||||
lost-exception,
|
||||
no-init,
|
||||
non-parent-init-called,
|
||||
pointless-string-statement,
|
||||
protected-access,
|
||||
redefined-builtin,
|
||||
redefined-outer-name,
|
||||
redefine-in-handler,
|
||||
signature-differs,
|
||||
star-args,
|
||||
super-init-not-called,
|
||||
undefined-loop-variable,
|
||||
unnecessary-lambda,
|
||||
unnecessary-pass,
|
||||
unpacking-non-sequence,
|
||||
unreachable,
|
||||
unused-argument,
|
||||
unused-import,
|
||||
unused-variable,
|
||||
useless-else-on-loop,
|
||||
# "C" Coding convention violations
|
||||
bad-continuation,
|
||||
invalid-name,
|
||||
missing-docstring,
|
||||
old-style-class,
|
||||
superfluous-parens,
|
||||
# "R" Refactor recommendations
|
||||
abstract-class-little-used,
|
||||
abstract-class-not-used,
|
||||
cyclic-import,
|
||||
duplicate-code,
|
||||
interface-not-implemented,
|
||||
no-self-use,
|
||||
too-few-public-methods,
|
||||
too-many-ancestors,
|
||||
too-many-arguments,
|
||||
too-many-branches,
|
||||
too-many-instance-attributes,
|
||||
too-many-lines,
|
||||
too-many-locals,
|
||||
too-many-public-methods,
|
||||
too-many-return-statements,
|
||||
too-many-statements
|
||||
|
||||
[Basic]
|
||||
[BASIC]
|
||||
# Variable names can be 1 to 31 characters long, with lowercase and underscores
|
||||
variable-rgx=[a-z_][a-z0-9_]{0,30}$
|
||||
|
||||
|
@ -21,7 +101,7 @@ argument-rgx=[a-z_][a-z0-9_]{1,30}$
|
|||
|
||||
# Method names should be at least 3 characters long
|
||||
# and be lowecased with underscores
|
||||
method-rgx=([a-z_][a-z0-9_]{2,50}|setUp|tearDown)$
|
||||
method-rgx=([a-z_][a-z0-9_]{2,}|setUp|tearDown)$
|
||||
|
||||
# Module names matching neutron-* are ok (files in bin/)
|
||||
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+)|(neutron-[a-z0-9_-]+))$
|
||||
|
@ -29,14 +109,26 @@ module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+)|(neutron-[a-z0-9_-]+))$
|
|||
# Don't require docstrings on tests.
|
||||
no-docstring-rgx=((__.*__)|([tT]est.*)|setUp|tearDown)$
|
||||
|
||||
[Design]
|
||||
max-public-methods=100
|
||||
min-public-methods=0
|
||||
max-args=6
|
||||
|
||||
[Variables]
|
||||
[FORMAT]
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=79
|
||||
|
||||
[VARIABLES]
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid to define new builtins when possible.
|
||||
# _ is used by our localization
|
||||
additional-builtins=_
|
||||
|
||||
[CLASSES]
|
||||
# List of interface methods to ignore, separated by a comma.
|
||||
ignore-iface-methods=
|
||||
|
||||
[IMPORTS]
|
||||
# Deprecated modules which should not be used, separated by a comma
|
||||
deprecated-modules=
|
||||
# should use openstack.common.jsonutils
|
||||
json
|
||||
|
||||
[REPORTS]
|
||||
# Tells whether to display a full report or only the messages
|
||||
reports=no
|
||||
|
|
|
@ -12,6 +12,7 @@ Neutron Specific Commandments
|
|||
- [N321] Validate that jsonutils module is used instead of json
|
||||
- [N322] We do not use @authors tags in source files. We have git to track
|
||||
authorship.
|
||||
- [N323] assert_called_once() is not a valid method
|
||||
|
||||
Creating Unit Tests
|
||||
-------------------
|
||||
|
|
|
@ -1,14 +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.
|
|
@ -28,6 +28,7 @@ from neutron.db.vpn import vpn_validator
|
|||
from neutron.extensions import vpnaas
|
||||
from neutron import manager
|
||||
from neutron.openstack.common import excutils
|
||||
from neutron.openstack.common.gettextutils import _LW
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.openstack.common import uuidutils
|
||||
from neutron.plugins.common import constants
|
||||
|
@ -601,6 +602,16 @@ class VPNPluginDb(vpnaas.VPNPluginBase, base_db.CommonDbMixin):
|
|||
router_id=router_id,
|
||||
vpnservice_id=vpnservices[0]['id'])
|
||||
|
||||
def check_subnet_in_use(self, context, subnet_id):
|
||||
with context.session.begin(subtransactions=True):
|
||||
vpnservices = context.session.query(VPNService).filter_by(
|
||||
subnet_id=subnet_id
|
||||
).first()
|
||||
if vpnservices:
|
||||
raise vpnaas.SubnetInUseByVPNService(
|
||||
subnet_id=subnet_id,
|
||||
vpnservice_id=vpnservices['id'])
|
||||
|
||||
|
||||
class VPNPluginRpcDbMixin():
|
||||
def _get_agent_hosting_vpn_services(self, context, host):
|
||||
|
@ -646,7 +657,7 @@ class VPNPluginRpcDbMixin():
|
|||
vpnservice_db = self._get_vpnservice(
|
||||
context, vpnservice['id'])
|
||||
except vpnaas.VPNServiceNotFound:
|
||||
LOG.warn(_('vpnservice %s in db is already deleted'),
|
||||
LOG.warn(_LW('vpnservice %s in db is already deleted'),
|
||||
vpnservice['id'])
|
||||
continue
|
||||
|
||||
|
|
|
@ -1,14 +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.
|
|
@ -1,14 +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.
|
|
@ -130,15 +130,15 @@ class VPNAgent(l3_agent.L3NATAgentWithStateReport):
|
|||
for device in self.devices:
|
||||
device.destroy_router(router_id)
|
||||
|
||||
def _process_routers(self, routers, all_routers=False):
|
||||
def _process_router_if_compatible(self, router):
|
||||
"""Router sync event.
|
||||
|
||||
This method overwrites parent class method.
|
||||
:param routers: list of routers
|
||||
:param router: a router
|
||||
"""
|
||||
super(VPNAgent, self)._process_routers(routers, all_routers)
|
||||
super(VPNAgent, self)._process_router_if_compatible(router)
|
||||
for device in self.devices:
|
||||
device.sync(self.context, routers)
|
||||
device.sync(self.context, [router])
|
||||
|
||||
|
||||
def main():
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
# Copyright 2013, Nachi Ueno, NTT I3, 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.
|
|
@ -19,6 +19,7 @@ import requests
|
|||
from requests import exceptions as r_exc
|
||||
|
||||
from neutron.openstack.common import jsonutils
|
||||
from neutron.openstack.common.gettextutils import _LE, _LW
|
||||
from neutron.openstack.common import log as logging
|
||||
|
||||
|
||||
|
@ -84,7 +85,7 @@ class CsrRestClient(object):
|
|||
and 'detail' fields).
|
||||
"""
|
||||
if method in ('POST', 'GET') and self.status == requests.codes.OK:
|
||||
LOG.debug(_('RESPONSE: %s'), response.json())
|
||||
LOG.debug('RESPONSE: %s', response.json())
|
||||
return response.json()
|
||||
if method == 'POST' and self.status == requests.codes.CREATED:
|
||||
return response.headers.get('location', '')
|
||||
|
@ -97,21 +98,21 @@ class CsrRestClient(object):
|
|||
def _request(self, method, url, **kwargs):
|
||||
"""Perform REST request and save response info."""
|
||||
try:
|
||||
LOG.debug(_("%(method)s: Request for %(resource)s payload: "
|
||||
"%(payload)s"),
|
||||
LOG.debug("%(method)s: Request for %(resource)s payload: "
|
||||
"%(payload)s",
|
||||
{'method': method.upper(), 'resource': url,
|
||||
'payload': kwargs.get('data')})
|
||||
start_time = time.time()
|
||||
response = self.session.request(method, url, verify=False,
|
||||
timeout=self.timeout, **kwargs)
|
||||
LOG.debug(_("%(method)s Took %(time).2f seconds to process"),
|
||||
LOG.debug("%(method)s Took %(time).2f seconds to process",
|
||||
{'method': method.upper(),
|
||||
'time': time.time() - start_time})
|
||||
except (r_exc.Timeout, r_exc.SSLError) as te:
|
||||
# Should never see SSLError, unless requests package is old (<2.0)
|
||||
timeout_val = 0.0 if self.timeout is None else self.timeout
|
||||
LOG.warning(_("%(method)s: Request timeout%(ssl)s "
|
||||
"(%(timeout).3f sec) for CSR(%(host)s)"),
|
||||
LOG.warning(_LW("%(method)s: Request timeout%(ssl)s "
|
||||
"(%(timeout).3f sec) for CSR(%(host)s)"),
|
||||
{'method': method,
|
||||
'timeout': timeout_val,
|
||||
'ssl': '(SSLError)'
|
||||
|
@ -119,17 +120,18 @@ class CsrRestClient(object):
|
|||
'host': self.host})
|
||||
self.status = requests.codes.REQUEST_TIMEOUT
|
||||
except r_exc.ConnectionError:
|
||||
LOG.exception(_("%(method)s: Unable to connect to CSR(%(host)s)"),
|
||||
LOG.exception(_LE("%(method)s: Unable to connect to "
|
||||
"CSR(%(host)s)"),
|
||||
{'method': method, 'host': self.host})
|
||||
self.status = requests.codes.NOT_FOUND
|
||||
except Exception as e:
|
||||
LOG.error(_("%(method)s: Unexpected error for CSR (%(host)s): "
|
||||
"%(error)s"),
|
||||
LOG.error(_LE("%(method)s: Unexpected error for CSR (%(host)s): "
|
||||
"%(error)s"),
|
||||
{'method': method, 'host': self.host, 'error': e})
|
||||
self.status = requests.codes.INTERNAL_SERVER_ERROR
|
||||
else:
|
||||
self.status = response.status_code
|
||||
LOG.debug(_("%(method)s: Completed [%(status)s]"),
|
||||
LOG.debug("%(method)s: Completed [%(status)s]",
|
||||
{'method': method, 'status': self.status})
|
||||
return self._response_info_for(response, method)
|
||||
|
||||
|
@ -144,16 +146,16 @@ class CsrRestClient(object):
|
|||
headers = {'Content-Length': '0',
|
||||
'Accept': 'application/json'}
|
||||
headers.update(HEADER_CONTENT_TYPE_JSON)
|
||||
LOG.debug(_("%(auth)s with CSR %(host)s"),
|
||||
LOG.debug("%(auth)s with CSR %(host)s",
|
||||
{'auth': 'Authenticating' if self.token is None
|
||||
else 'Reauthenticating', 'host': self.host})
|
||||
self.token = None
|
||||
response = self._request("POST", url, headers=headers, auth=self.auth)
|
||||
if response:
|
||||
self.token = response['token-id']
|
||||
LOG.debug(_("Successfully authenticated with CSR %s"), self.host)
|
||||
LOG.debug("Successfully authenticated with CSR %s", self.host)
|
||||
return True
|
||||
LOG.error(_("Failed authentication with CSR %(host)s [%(status)s]"),
|
||||
LOG.error(_LE("Failed authentication with CSR %(host)s [%(status)s]"),
|
||||
{'host': self.host, 'status': self.status})
|
||||
|
||||
def _do_request(self, method, resource, payload=None, more_headers=None,
|
||||
|
@ -188,7 +190,7 @@ class CsrRestClient(object):
|
|||
headers=headers)
|
||||
if self.status != requests.codes.REQUEST_TIMEOUT:
|
||||
return response
|
||||
LOG.error(_("%(method)s: Request timeout for CSR(%(host)s)"),
|
||||
LOG.error(_LE("%(method)s: Request timeout for CSR(%(host)s)"),
|
||||
{'method': method, 'host': self.host})
|
||||
|
||||
def get_request(self, resource, full_url=False):
|
||||
|
|
|
@ -23,6 +23,7 @@ import six
|
|||
from neutron.common import exceptions
|
||||
from neutron.common import rpc as n_rpc
|
||||
from neutron import context as ctx
|
||||
from neutron.openstack.common.gettextutils import _LE, _LI, _LW
|
||||
from neutron.openstack.common import lockutils
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.openstack.common import loopingcall
|
||||
|
@ -125,7 +126,7 @@ class CiscoCsrIPsecDriver(device_drivers.DeviceDriver):
|
|||
|
||||
def vpnservice_updated(self, context, **kwargs):
|
||||
"""Handle VPNaaS service driver change notifications."""
|
||||
LOG.debug(_("Handling VPN service update notification '%s'"),
|
||||
LOG.debug("Handling VPN service update notification '%s'",
|
||||
kwargs.get('reason', ''))
|
||||
self.sync(context, [])
|
||||
|
||||
|
@ -147,20 +148,20 @@ class CiscoCsrIPsecDriver(device_drivers.DeviceDriver):
|
|||
ipsec_conn = vpn_service.conn_state[conn_id]
|
||||
config_changed = ipsec_conn.check_for_changes(conn_data)
|
||||
if config_changed:
|
||||
LOG.debug(_("Update: Existing connection %s changed"), conn_id)
|
||||
LOG.debug("Update: Existing connection %s changed", conn_id)
|
||||
ipsec_conn.delete_ipsec_site_connection(context, conn_id)
|
||||
ipsec_conn.create_ipsec_site_connection(context, conn_data)
|
||||
ipsec_conn.conn_info = conn_data
|
||||
|
||||
if ipsec_conn.forced_down:
|
||||
if vpn_service.is_admin_up and conn_is_admin_up:
|
||||
LOG.debug(_("Update: Connection %s no longer admin down"),
|
||||
LOG.debug("Update: Connection %s no longer admin down",
|
||||
conn_id)
|
||||
ipsec_conn.set_admin_state(is_up=True)
|
||||
ipsec_conn.forced_down = False
|
||||
else:
|
||||
if not vpn_service.is_admin_up or not conn_is_admin_up:
|
||||
LOG.debug(_("Update: Connection %s forced to admin down"),
|
||||
LOG.debug("Update: Connection %s forced to admin down",
|
||||
conn_id)
|
||||
ipsec_conn.set_admin_state(is_up=False)
|
||||
ipsec_conn.forced_down = True
|
||||
|
@ -168,12 +169,12 @@ class CiscoCsrIPsecDriver(device_drivers.DeviceDriver):
|
|||
ipsec_conn = vpn_service.create_connection(conn_data)
|
||||
ipsec_conn.create_ipsec_site_connection(context, conn_data)
|
||||
if not vpn_service.is_admin_up or not conn_is_admin_up:
|
||||
LOG.debug(_("Update: Created new connection %s in admin down "
|
||||
"state"), conn_id)
|
||||
LOG.debug("Update: Created new connection %s in admin down "
|
||||
"state", conn_id)
|
||||
ipsec_conn.set_admin_state(is_up=False)
|
||||
ipsec_conn.forced_down = True
|
||||
else:
|
||||
LOG.debug(_("Update: Created new connection %s"), conn_id)
|
||||
LOG.debug("Update: Created new connection %s", conn_id)
|
||||
|
||||
ipsec_conn.is_dirty = False
|
||||
ipsec_conn.last_status = conn_data['status']
|
||||
|
@ -184,11 +185,11 @@ class CiscoCsrIPsecDriver(device_drivers.DeviceDriver):
|
|||
"""Handle notification for a single VPN Service and its connections."""
|
||||
vpn_service_id = service_data['id']
|
||||
if vpn_service_id in self.service_state:
|
||||
LOG.debug(_("Update: Existing VPN service %s detected"),
|
||||
LOG.debug("Update: Existing VPN service %s detected",
|
||||
vpn_service_id)
|
||||
vpn_service = self.service_state[vpn_service_id]
|
||||
else:
|
||||
LOG.debug(_("Update: New VPN service %s detected"), vpn_service_id)
|
||||
LOG.debug("Update: New VPN service %s detected", vpn_service_id)
|
||||
vpn_service = self.create_vpn_service(service_data)
|
||||
if not vpn_service:
|
||||
return
|
||||
|
@ -199,7 +200,7 @@ class CiscoCsrIPsecDriver(device_drivers.DeviceDriver):
|
|||
vpn_service.is_admin_up = service_data[u'admin_state_up']
|
||||
for conn_data in service_data['ipsec_conns']:
|
||||
self.update_connection(context, vpn_service_id, conn_data)
|
||||
LOG.debug(_("Update: Completed update processing"))
|
||||
LOG.debug("Update: Completed update processing")
|
||||
return vpn_service
|
||||
|
||||
def update_all_services_and_connections(self, context):
|
||||
|
@ -229,9 +230,9 @@ class CiscoCsrIPsecDriver(device_drivers.DeviceDriver):
|
|||
for conn_id in service_state.conn_state:
|
||||
service_state.conn_state[conn_id].is_dirty = True
|
||||
connection_count += 1
|
||||
LOG.debug(_("Mark: %(service)d VPN services and %(conn)d IPSec "
|
||||
"connections marked dirty"), {'service': service_count,
|
||||
'conn': connection_count})
|
||||
LOG.debug("Mark: %(service)d VPN services and %(conn)d IPSec "
|
||||
"connections marked dirty", {'service': service_count,
|
||||
'conn': connection_count})
|
||||
|
||||
def remove_unknown_connections(self, context):
|
||||
"""Remove connections that are not known by service driver."""
|
||||
|
@ -251,8 +252,8 @@ class CiscoCsrIPsecDriver(device_drivers.DeviceDriver):
|
|||
del self.service_state[vpn_service_id]
|
||||
elif dirty:
|
||||
self.connections_removed = True
|
||||
LOG.debug(_("Sweep: Removed %(service)d dirty VPN service%(splural)s "
|
||||
"and %(conn)d dirty IPSec connection%(cplural)s"),
|
||||
LOG.debug("Sweep: Removed %(service)d dirty VPN service%(splural)s "
|
||||
"and %(conn)d dirty IPSec connection%(cplural)s",
|
||||
{'service': service_count, 'conn': connection_count,
|
||||
'splural': 's'[service_count == 1:],
|
||||
'cplural': 's'[connection_count == 1:]})
|
||||
|
@ -266,22 +267,22 @@ class CiscoCsrIPsecDriver(device_drivers.DeviceDriver):
|
|||
report info will be created for the connection. The combined report
|
||||
data is returned.
|
||||
"""
|
||||
LOG.debug(_("Report: Collecting status for IPSec connections on VPN "
|
||||
"service %s"), vpn_service.service_id)
|
||||
LOG.debug("Report: Collecting status for IPSec connections on VPN "
|
||||
"service %s", vpn_service.service_id)
|
||||
tunnels = vpn_service.get_ipsec_connections_status()
|
||||
report = {}
|
||||
for connection in vpn_service.conn_state.values():
|
||||
if connection.forced_down:
|
||||
LOG.debug(_("Connection %s forced down"), connection.conn_id)
|
||||
LOG.debug("Connection %s forced down", connection.conn_id)
|
||||
current_status = constants.DOWN
|
||||
else:
|
||||
current_status = connection.find_current_status_in(tunnels)
|
||||
LOG.debug(_("Connection %(conn)s reported %(status)s"),
|
||||
LOG.debug("Connection %(conn)s reported %(status)s",
|
||||
{'conn': connection.conn_id,
|
||||
'status': current_status})
|
||||
frag = connection.update_status_and_build_report(current_status)
|
||||
if frag:
|
||||
LOG.debug(_("Report: Adding info for IPSec connection %s"),
|
||||
LOG.debug("Report: Adding info for IPSec connection %s",
|
||||
connection.conn_id)
|
||||
report.update(frag)
|
||||
return report
|
||||
|
@ -301,7 +302,7 @@ class CiscoCsrIPsecDriver(device_drivers.DeviceDriver):
|
|||
pending_handled = plugin_utils.in_pending_status(
|
||||
vpn_service.last_status)
|
||||
vpn_service.update_last_status()
|
||||
LOG.debug(_("Report: Adding info for VPN service %s"),
|
||||
LOG.debug("Report: Adding info for VPN service %s",
|
||||
vpn_service.service_id)
|
||||
return {u'id': vpn_service.service_id,
|
||||
u'status': vpn_service.last_status,
|
||||
|
@ -323,17 +324,17 @@ class CiscoCsrIPsecDriver(device_drivers.DeviceDriver):
|
|||
def report_status_internal(self, context):
|
||||
"""Generate report and send to plugin, if anything changed."""
|
||||
service_report = []
|
||||
LOG.debug(_("Report: Starting status report processing"))
|
||||
LOG.debug("Report: Starting status report processing")
|
||||
for vpn_service_id, vpn_service in self.service_state.items():
|
||||
LOG.debug(_("Report: Collecting status for VPN service %s"),
|
||||
LOG.debug("Report: Collecting status for VPN service %s",
|
||||
vpn_service_id)
|
||||
report = self.build_report_for_service(vpn_service)
|
||||
if report:
|
||||
service_report.append(report)
|
||||
if service_report:
|
||||
LOG.info(_("Sending status report update to plugin"))
|
||||
LOG.info(_LI("Sending status report update to plugin"))
|
||||
self.agent_rpc.update_status(context, service_report)
|
||||
LOG.debug(_("Report: Completed status report processing"))
|
||||
LOG.debug("Report: Completed status report processing")
|
||||
return service_report
|
||||
|
||||
@lockutils.synchronized('vpn-agent', 'neutron-')
|
||||
|
@ -617,8 +618,8 @@ class CiscoCsrIPSecConnection(object):
|
|||
LOG.debug("%(resource)s %(which)s is configured",
|
||||
{'resource': resource, 'which': which})
|
||||
return
|
||||
LOG.error(_("Unable to create %(resource)s %(which)s: "
|
||||
"%(status)d"),
|
||||
LOG.error(_LE("Unable to create %(resource)s %(which)s: "
|
||||
"%(status)d"),
|
||||
{'resource': resource, 'which': which,
|
||||
'status': self.csr.status})
|
||||
# ToDO(pcm): Set state to error
|
||||
|
@ -630,7 +631,7 @@ class CiscoCsrIPSecConnection(object):
|
|||
try:
|
||||
getattr(self.csr, create_action)(info)
|
||||
except AttributeError:
|
||||
LOG.exception(_("Internal error - '%s' is not defined"),
|
||||
LOG.exception(_LE("Internal error - '%s' is not defined"),
|
||||
create_action)
|
||||
raise CsrResourceCreateFailure(resource=title,
|
||||
which=resource_id)
|
||||
|
@ -643,22 +644,22 @@ class CiscoCsrIPSecConnection(object):
|
|||
LOG.debug("%(resource)s configuration %(which)s was removed",
|
||||
{'resource': resource, 'which': which})
|
||||
else:
|
||||
LOG.warning(_("Unable to delete %(resource)s %(which)s: "
|
||||
"%(status)d"), {'resource': resource,
|
||||
'which': which,
|
||||
'status': status})
|
||||
LOG.warning(_LW("Unable to delete %(resource)s %(which)s: "
|
||||
"%(status)d"), {'resource': resource,
|
||||
'which': which,
|
||||
'status': status})
|
||||
|
||||
def do_rollback(self):
|
||||
"""Undo create steps that were completed successfully."""
|
||||
for step in reversed(self.steps):
|
||||
delete_action = 'delete_%s' % step.action
|
||||
LOG.debug(_("Performing rollback action %(action)s for "
|
||||
"resource %(resource)s"), {'action': delete_action,
|
||||
'resource': step.title})
|
||||
LOG.debug("Performing rollback action %(action)s for "
|
||||
"resource %(resource)s", {'action': delete_action,
|
||||
'resource': step.title})
|
||||
try:
|
||||
getattr(self.csr, delete_action)(step.resource_id)
|
||||
except AttributeError:
|
||||
LOG.exception(_("Internal error - '%s' is not defined"),
|
||||
LOG.exception(_LE("Internal error - '%s' is not defined"),
|
||||
delete_action)
|
||||
raise CsrResourceCreateFailure(resource=step.title,
|
||||
which=step.resource_id)
|
||||
|
@ -678,7 +679,7 @@ class CiscoCsrIPSecConnection(object):
|
|||
ike_policy_id = conn_info['cisco']['ike_policy_id']
|
||||
ipsec_policy_id = conn_info['cisco']['ipsec_policy_id']
|
||||
|
||||
LOG.debug(_('Creating IPSec connection %s'), conn_id)
|
||||
LOG.debug('Creating IPSec connection %s', conn_id)
|
||||
# Get all the attributes needed to create
|
||||
try:
|
||||
psk_info = self.create_psk_info(psk_id, conn_info)
|
||||
|
@ -711,10 +712,10 @@ class CiscoCsrIPSecConnection(object):
|
|||
route_id, 'Static Route')
|
||||
except CsrResourceCreateFailure:
|
||||
self.do_rollback()
|
||||
LOG.info(_("FAILED: Create of IPSec site-to-site connection %s"),
|
||||
LOG.info(_LI("FAILED: Create of IPSec site-to-site connection %s"),
|
||||
conn_id)
|
||||
else:
|
||||
LOG.info(_("SUCCESS: Created IPSec site-to-site connection %s"),
|
||||
LOG.info(_LI("SUCCESS: Created IPSec site-to-site connection %s"),
|
||||
conn_id)
|
||||
|
||||
def delete_ipsec_site_connection(self, context, conn_id):
|
||||
|
@ -723,13 +724,13 @@ class CiscoCsrIPSecConnection(object):
|
|||
This will be best effort and will continue, if there are any
|
||||
failures.
|
||||
"""
|
||||
LOG.debug(_('Deleting IPSec connection %s'), conn_id)
|
||||
LOG.debug('Deleting IPSec connection %s', conn_id)
|
||||
if not self.steps:
|
||||
LOG.warning(_('Unable to find connection %s'), conn_id)
|
||||
LOG.warning(_LW('Unable to find connection %s'), conn_id)
|
||||
else:
|
||||
self.do_rollback()
|
||||
|
||||
LOG.info(_("SUCCESS: Deleted IPSec site-to-site connection %s"),
|
||||
LOG.info(_LI("SUCCESS: Deleted IPSec site-to-site connection %s"),
|
||||
conn_id)
|
||||
|
||||
def set_admin_state(self, is_up):
|
||||
|
@ -737,6 +738,7 @@ class CiscoCsrIPSecConnection(object):
|
|||
self.csr.set_ipsec_connection_state(self.tunnel, admin_up=is_up)
|
||||
if self.csr.status != requests.codes.NO_CONTENT:
|
||||
state = "UP" if is_up else "DOWN"
|
||||
LOG.error(_("Unable to change %(tunnel)s admin state to "
|
||||
"%(state)s"), {'tunnel': self.tunnel, 'state': state})
|
||||
LOG.error(_LE("Unable to change %(tunnel)s admin state to "
|
||||
"%(state)s"), {'tunnel': self.tunnel,
|
||||
'state': state})
|
||||
raise CsrAdminStateChangeFailure(tunnel=self.tunnel, state=state)
|
||||
|
|
|
@ -28,6 +28,7 @@ from neutron.agent.linux import ip_lib
|
|||
from neutron.agent.linux import utils
|
||||
from neutron.common import rpc as n_rpc
|
||||
from neutron import context
|
||||
from neutron.openstack.common.gettextutils import _LE
|
||||
from neutron.openstack.common import lockutils
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.openstack.common import loopingcall
|
||||
|
@ -244,7 +245,7 @@ class BaseSwanProcess():
|
|||
self.start()
|
||||
except RuntimeError:
|
||||
LOG.exception(
|
||||
_("Failed to enable vpn process on router %s"),
|
||||
_LE("Failed to enable vpn process on router %s"),
|
||||
self.id)
|
||||
|
||||
def disable(self):
|
||||
|
@ -255,7 +256,7 @@ class BaseSwanProcess():
|
|||
self.remove_config()
|
||||
except RuntimeError:
|
||||
LOG.exception(
|
||||
_("Failed to disable vpn process on router %s"),
|
||||
_LE("Failed to disable vpn process on router %s"),
|
||||
self.id)
|
||||
|
||||
@abc.abstractmethod
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
# under the License.
|
||||
|
||||
from neutron.db.vpn import vpn_db
|
||||
from neutron.openstack.common.gettextutils import _LI
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.plugins.common import constants
|
||||
from neutron.services import service_base
|
||||
|
@ -41,7 +42,7 @@ class VPNDriverPlugin(VPNPlugin, vpn_db.VPNPluginRpcDbMixin):
|
|||
# Load the service driver from neutron.conf.
|
||||
drivers, default_provider = service_base.load_drivers(
|
||||
constants.VPN, self)
|
||||
LOG.info(_("VPN plugin using service driver: %s"), default_provider)
|
||||
LOG.info(_LI("VPN plugin using service driver: %s"), default_provider)
|
||||
self.ipsec_driver = drivers[default_provider]
|
||||
|
||||
def _get_driver_for_vpnservice(self, vpnservice):
|
||||
|
|
|
@ -94,8 +94,8 @@ class BaseIPsecVpnAgentApi(n_rpc.RpcProxy):
|
|||
admin_state_up=True,
|
||||
active=True)
|
||||
for l3_agent in l3_agents:
|
||||
LOG.debug(_('Notify agent at %(topic)s.%(host)s the message '
|
||||
'%(method)s %(args)s'),
|
||||
LOG.debug('Notify agent at %(topic)s.%(host)s the message '
|
||||
'%(method)s %(args)s',
|
||||
{'topic': self.topic,
|
||||
'host': l3_agent.host,
|
||||
'method': method,
|
||||
|
|
|
@ -32,8 +32,7 @@ from oslo.config import cfg
|
|||
|
||||
from neutron.db import l3_db
|
||||
from neutron.db import models_v2
|
||||
from neutron.openstack.common.gettextutils import _LE
|
||||
from neutron.openstack.common.gettextutils import _LI
|
||||
from neutron.openstack.common.gettextutils import _LE, _LI
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.services.vpn.device_drivers import (
|
||||
cisco_csr_rest_client as csr_client)
|
||||
|
@ -103,8 +102,8 @@ def get_available_csrs_from_config(config_files):
|
|||
try:
|
||||
netaddr.IPAddress(rest_mgmt_ip)
|
||||
except netaddr.core.AddrFormatError:
|
||||
LOG.error(_("Ignoring Cisco CSR for subnet %s - "
|
||||
"REST management is not an IP address"),
|
||||
LOG.error(_LE("Ignoring Cisco CSR for subnet %s - "
|
||||
"REST management is not an IP address"),
|
||||
for_router)
|
||||
continue
|
||||
try:
|
||||
|
|
|
@ -20,6 +20,7 @@ from neutron.common import exceptions
|
|||
from neutron.db import model_base
|
||||
from neutron.db import models_v2
|
||||
from neutron.db.vpn import vpn_db
|
||||
from neutron.openstack.common.gettextutils import _LI
|
||||
from neutron.openstack.common import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -156,10 +157,10 @@ def determine_csr_policy_id(policy_type, conn_policy_field, map_policy_field,
|
|||
then call lookup_policy() to find the current mapping for that ID.
|
||||
"""
|
||||
csr_id = get_next_available_id(session, map_policy_field, policy_type)
|
||||
LOG.debug(_("Reserved new CSR ID %(csr_id)d for %(policy)s "
|
||||
"ID %(policy_id)s"), {'csr_id': csr_id,
|
||||
'policy': policy_type,
|
||||
'policy_id': policy_id})
|
||||
LOG.debug("Reserved new CSR ID %(csr_id)d for %(policy)s "
|
||||
"ID %(policy_id)s", {'csr_id': csr_id,
|
||||
'policy': policy_type,
|
||||
'policy_id': policy_id})
|
||||
return csr_id
|
||||
|
||||
|
||||
|
@ -183,9 +184,9 @@ def get_tunnel_mapping_for(conn_id, session):
|
|||
try:
|
||||
entry = session.query(IdentifierMap).filter_by(
|
||||
ipsec_site_conn_id=conn_id).one()
|
||||
LOG.debug(_("Mappings for IPSec connection %(conn)s - "
|
||||
"tunnel=%(tunnel)s ike_policy=%(csr_ike)d "
|
||||
"ipsec_policy=%(csr_ipsec)d"),
|
||||
LOG.debug("Mappings for IPSec connection %(conn)s - "
|
||||
"tunnel=%(tunnel)s ike_policy=%(csr_ike)d "
|
||||
"ipsec_policy=%(csr_ipsec)d",
|
||||
{'conn': conn_id, 'tunnel': entry.csr_tunnel_id,
|
||||
'csr_ike': entry.csr_ike_policy_id,
|
||||
'csr_ipsec': entry.csr_ipsec_policy_id})
|
||||
|
@ -222,9 +223,9 @@ def create_tunnel_mapping(context, conn_info):
|
|||
msg = _("Attempt to create duplicate entry in Cisco CSR "
|
||||
"mapping table for connection %s") % conn_id
|
||||
raise CsrInternalError(reason=msg)
|
||||
LOG.info(_("Mapped connection %(conn_id)s to Tunnel%(tunnel_id)d "
|
||||
"using IKE policy ID %(ike_id)d and IPSec policy "
|
||||
"ID %(ipsec_id)d"),
|
||||
LOG.info(_LI("Mapped connection %(conn_id)s to Tunnel%(tunnel_id)d "
|
||||
"using IKE policy ID %(ike_id)d and IPSec policy "
|
||||
"ID %(ipsec_id)d"),
|
||||
{'conn_id': conn_id, 'tunnel_id': csr_tunnel_id,
|
||||
'ike_id': csr_ike_id, 'ipsec_id': csr_ipsec_id})
|
||||
|
||||
|
@ -234,4 +235,4 @@ def delete_tunnel_mapping(context, conn_info):
|
|||
with context.session.begin():
|
||||
sess_qry = context.session.query(IdentifierMap)
|
||||
sess_qry.filter_by(ipsec_site_conn_id=conn_id).delete()
|
||||
LOG.info(_("Removed mapping for connection %s"), conn_id)
|
||||
LOG.info(_LI("Removed mapping for connection %s"), conn_id)
|
||||
|
|
|
@ -101,8 +101,8 @@ class CiscoCsrIPsecVpnAgentApi(service_drivers.BaseIPsecVpnAgentApi,
|
|||
# NOTE: This is a config error for workaround. At this point we
|
||||
# can't set state of resource to error.
|
||||
return
|
||||
LOG.debug(_('Notify agent at %(topic)s.%(host)s the message '
|
||||
'%(method)s %(args)s for router %(router)s'),
|
||||
LOG.debug('Notify agent at %(topic)s.%(host)s the message '
|
||||
'%(method)s %(args)s for router %(router)s',
|
||||
{'topic': self.topic,
|
||||
'host': host,
|
||||
'method': method,
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
# Copyright 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.
|
|
@ -1,14 +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.
|
|
@ -434,7 +434,7 @@ class VPNPluginDbTestCase(VPNTestMixin,
|
|||
service_plugins=service_plugins
|
||||
)
|
||||
self._subnet_id = uuidutils.generate_uuid()
|
||||
self.core_plugin = TestVpnCorePlugin
|
||||
self.core_plugin = TestVpnCorePlugin()
|
||||
self.plugin = vpn_plugin.VPNPlugin()
|
||||
ext_mgr = api_extensions.PluginAwareExtensionManager(
|
||||
extensions_path,
|
||||
|
@ -867,6 +867,55 @@ class TestVpnaas(VPNPluginDbTestCase):
|
|||
if k in expected),
|
||||
expected)
|
||||
|
||||
def test_delete_router_interface_in_use_by_vpnservice(self):
|
||||
"""Test delete router interface in use by vpn service."""
|
||||
with self.subnet(cidr='10.2.0.0/24') as subnet:
|
||||
with self.router() as router:
|
||||
with self.vpnservice(subnet=subnet,
|
||||
router=router):
|
||||
self._router_interface_action('remove',
|
||||
router['router']['id'],
|
||||
subnet['subnet']['id'],
|
||||
None,
|
||||
expected_code=webob.exc.
|
||||
HTTPConflict.code)
|
||||
|
||||
def test_delete_external_gateway_interface_in_use_by_vpnservice(self):
|
||||
"""Test delete external gateway interface in use by vpn service."""
|
||||
with self.subnet(cidr='10.2.0.0/24') as subnet:
|
||||
with self.router() as router:
|
||||
with self.subnet(cidr='11.0.0.0/24') as public_sub:
|
||||
self._set_net_external(
|
||||
public_sub['subnet']['network_id'])
|
||||
self._add_external_gateway_to_router(
|
||||
router['router']['id'],
|
||||
public_sub['subnet']['network_id'])
|
||||
with self.vpnservice(subnet=subnet,
|
||||
router=router):
|
||||
self._remove_external_gateway_from_router(
|
||||
router['router']['id'],
|
||||
public_sub['subnet']['network_id'],
|
||||
expected_code=webob.exc.HTTPConflict.code)
|
||||
|
||||
def test_router_update_after_ipsec_site_connection(self):
|
||||
"""Test case to update router after vpn connection."""
|
||||
rname1 = "router_one"
|
||||
rname2 = "router_two"
|
||||
with self.subnet(cidr='10.2.0.0/24') as subnet:
|
||||
with self.router(name=rname1) as r:
|
||||
with self.vpnservice(subnet=subnet,
|
||||
router=r
|
||||
) as vpnservice:
|
||||
self.ipsec_site_connection(
|
||||
name='connection1', vpnservice=vpnservice
|
||||
)
|
||||
body = self._show('routers', r['router']['id'])
|
||||
self.assertEqual(body['router']['name'], rname1)
|
||||
body = self._update('routers', r['router']['id'],
|
||||
{'router': {'name': rname2}})
|
||||
body = self._show('routers', r['router']['id'])
|
||||
self.assertEqual(body['router']['name'], rname2)
|
||||
|
||||
def test_update_vpnservice(self):
|
||||
"""Test case to update a vpnservice."""
|
||||
name = 'new_vpnservice1'
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
# Copyright 2013 New Dream Network, LLC (DreamHost)
|
||||
#
|
||||
# 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.
|
|
@ -1,14 +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.
|
|
@ -1,14 +0,0 @@
|
|||
# Copyright 2013, Nachi Ueno, NTT I3, 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.
|
|
@ -1,577 +0,0 @@
|
|||
# Copyright 2014 Cisco Systems, 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.
|
||||
|
||||
"""Mock REST requests to Cisco Cloud Services Router."""
|
||||
|
||||
import re
|
||||
|
||||
import functools
|
||||
# TODO(pcm): Remove when switch to requests-mock package. Comment out, if use
|
||||
# local copy of httmock.py source. Needed for PEP8.
|
||||
import httmock
|
||||
import requests
|
||||
from requests import exceptions as r_exc
|
||||
|
||||
from neutron.openstack.common import log as logging
|
||||
# TODO(pcm) Remove once httmock package is added to test-requirements. For
|
||||
# now, uncomment and include httmock source to unit test.
|
||||
# from neutron.tests.unit.services.vpn.device_drivers import httmock
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def repeat(n):
|
||||
"""Decorator to limit the number of times a handler is called.
|
||||
|
||||
Will allow the wrapped function (handler) to be called 'n' times.
|
||||
After that, this will return None for any additional calls,
|
||||
allowing other handlers, if any, to be invoked.
|
||||
"""
|
||||
|
||||
class static:
|
||||
retries = n
|
||||
|
||||
def decorator(func):
|
||||
@functools.wraps(func)
|
||||
def wrapped(*args, **kwargs):
|
||||
if static.retries == 0:
|
||||
return None
|
||||
static.retries -= 1
|
||||
return func(*args, **kwargs)
|
||||
return wrapped
|
||||
return decorator
|
||||
|
||||
|
||||
def filter_request(methods, resource):
|
||||
"""Decorator to invoke handler once for a specific resource.
|
||||
|
||||
This will call the handler only for a specific resource using
|
||||
a specific method(s). Any other resource request or method will
|
||||
return None, allowing other handlers, if any, to be invoked.
|
||||
"""
|
||||
|
||||
class static:
|
||||
target_methods = [m.upper() for m in methods]
|
||||
target_resource = resource
|
||||
|
||||
def decorator(func):
|
||||
@functools.wraps(func)
|
||||
def wrapped(*args, **kwargs):
|
||||
if (args[1].method in static.target_methods and
|
||||
static.target_resource in args[0].path):
|
||||
return func(*args, **kwargs)
|
||||
else:
|
||||
return None # Not for this resource
|
||||
return wrapped
|
||||
return decorator
|
||||
|
||||
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def token(url, request):
|
||||
if 'auth/token-services' in url.path:
|
||||
return {'status_code': requests.codes.OK,
|
||||
'content': {'token-id': 'dummy-token'}}
|
||||
|
||||
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def token_unauthorized(url, request):
|
||||
if 'auth/token-services' in url.path:
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
|
||||
|
||||
@httmock.urlmatch(netloc=r'wrong-host')
|
||||
def token_wrong_host(url, request):
|
||||
raise r_exc.ConnectionError()
|
||||
|
||||
|
||||
@httmock.all_requests
|
||||
def token_timeout(url, request):
|
||||
raise r_exc.Timeout()
|
||||
|
||||
|
||||
@filter_request(['get'], 'global/host-name')
|
||||
@httmock.all_requests
|
||||
def timeout(url, request):
|
||||
"""Simulated timeout of a normal request."""
|
||||
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
raise r_exc.Timeout()
|
||||
|
||||
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def no_such_resource(url, request):
|
||||
"""Indicate not found error, when invalid resource requested."""
|
||||
return {'status_code': requests.codes.NOT_FOUND}
|
||||
|
||||
|
||||
@filter_request(['get'], 'global/host-name')
|
||||
@repeat(1)
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def expired_request(url, request):
|
||||
"""Simulate access denied failure on first request for this resource.
|
||||
|
||||
Intent here is to simulate that the token has expired, by failing
|
||||
the first request to the resource. Because of the repeat=1, this
|
||||
will only be called once, and subsequent calls will not be handled
|
||||
by this function, but instead will access the normal handler and
|
||||
will pass. Currently configured for a GET request, but will work
|
||||
with POST and PUT as well. For DELETE, would need to filter_request on a
|
||||
different resource (e.g. 'global/local-users')
|
||||
"""
|
||||
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
|
||||
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def normal_get(url, request):
|
||||
if request.method != 'GET':
|
||||
return
|
||||
LOG.debug("GET mock for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
if 'global/host-name' in url.path:
|
||||
content = {u'kind': u'object#host-name',
|
||||
u'host-name': u'Router'}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
if 'global/local-users' in url.path:
|
||||
content = {u'kind': u'collection#local-user',
|
||||
u'users': ['peter', 'paul', 'mary']}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
if 'interfaces/GigabitEthernet' in url.path:
|
||||
actual_interface = url.path.split('/')[-1]
|
||||
ip = actual_interface[-1]
|
||||
content = {u'kind': u'object#interface',
|
||||
u'description': u'Changed description',
|
||||
u'if-name': actual_interface,
|
||||
u'proxy-arp': True,
|
||||
u'subnet-mask': u'255.255.255.0',
|
||||
u'icmp-unreachable': True,
|
||||
u'nat-direction': u'',
|
||||
u'icmp-redirects': True,
|
||||
u'ip-address': u'192.168.200.%s' % ip,
|
||||
u'verify-unicast-source': False,
|
||||
u'type': u'ethernet'}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
if 'vpn-svc/ike/policies/2' in url.path:
|
||||
content = {u'kind': u'object#ike-policy',
|
||||
u'priority-id': u'2',
|
||||
u'version': u'v1',
|
||||
u'local-auth-method': u'pre-share',
|
||||
u'encryption': u'aes256',
|
||||
u'hash': u'sha',
|
||||
u'dhGroup': 5,
|
||||
u'lifetime': 3600}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
if 'vpn-svc/ike/keyrings' in url.path:
|
||||
content = {u'kind': u'object#ike-keyring',
|
||||
u'keyring-name': u'5',
|
||||
u'pre-shared-key-list': [
|
||||
{u'key': u'super-secret',
|
||||
u'encrypted': False,
|
||||
u'peer-address': u'10.10.10.20 255.255.255.0'}
|
||||
]}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
if 'vpn-svc/ipsec/policies/' in url.path:
|
||||
ipsec_policy_id = url.path.split('/')[-1]
|
||||
content = {u'kind': u'object#ipsec-policy',
|
||||
u'mode': u'tunnel',
|
||||
u'policy-id': u'%s' % ipsec_policy_id,
|
||||
u'protection-suite': {
|
||||
u'esp-encryption': u'esp-256-aes',
|
||||
u'esp-authentication': u'esp-sha-hmac',
|
||||
u'ah': u'ah-sha-hmac',
|
||||
},
|
||||
u'anti-replay-window-size': u'Disable',
|
||||
u'lifetime-sec': 120,
|
||||
u'pfs': u'group5',
|
||||
u'lifetime-kb': 4608000,
|
||||
u'idle-time': None}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
if 'vpn-svc/site-to-site/Tunnel' in url.path:
|
||||
tunnel = url.path.split('/')[-1]
|
||||
# Use same number, to allow mock to generate IPSec policy ID
|
||||
ipsec_policy_id = tunnel[6:]
|
||||
content = {u'kind': u'object#vpn-site-to-site',
|
||||
u'vpn-interface-name': u'%s' % tunnel,
|
||||
u'ip-version': u'ipv4',
|
||||
u'vpn-type': u'site-to-site',
|
||||
u'ipsec-policy-id': u'%s' % ipsec_policy_id,
|
||||
u'ike-profile-id': None,
|
||||
u'mtu': 1500,
|
||||
u'local-device': {
|
||||
u'ip-address': '10.3.0.1/24',
|
||||
u'tunnel-ip-address': '10.10.10.10'
|
||||
},
|
||||
u'remote-device': {
|
||||
u'tunnel-ip-address': '10.10.10.20'
|
||||
}}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
if 'vpn-svc/ike/keepalive' in url.path:
|
||||
content = {u'interval': 60,
|
||||
u'retry': 4,
|
||||
u'periodic': True}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
if 'routing-svc/static-routes' in url.path:
|
||||
content = {u'destination-network': u'10.1.0.0/24',
|
||||
u'kind': u'object#static-route',
|
||||
u'next-hop-router': None,
|
||||
u'outgoing-interface': u'GigabitEthernet1',
|
||||
u'admin-distance': 1}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
if 'vpn-svc/site-to-site/active/sessions' in url.path:
|
||||
# Only including needed fields for mock
|
||||
content = {u'kind': u'collection#vpn-active-sessions',
|
||||
u'items': [{u'status': u'DOWN-NEGOTIATING',
|
||||
u'vpn-interface-name': u'Tunnel123'}, ]}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
|
||||
|
||||
@filter_request(['get'], 'vpn-svc/ike/keyrings')
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def get_fqdn(url, request):
|
||||
LOG.debug("GET FQDN mock for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
content = {u'kind': u'object#ike-keyring',
|
||||
u'keyring-name': u'5',
|
||||
u'pre-shared-key-list': [
|
||||
{u'key': u'super-secret',
|
||||
u'encrypted': False,
|
||||
u'peer-address': u'cisco.com'}
|
||||
]}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
|
||||
|
||||
@filter_request(['get'], 'vpn-svc/ipsec/policies/')
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def get_no_ah(url, request):
|
||||
LOG.debug("GET No AH mock for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
ipsec_policy_id = url.path.split('/')[-1]
|
||||
content = {u'kind': u'object#ipsec-policy',
|
||||
u'mode': u'tunnel',
|
||||
u'anti-replay-window-size': u'128',
|
||||
u'policy-id': u'%s' % ipsec_policy_id,
|
||||
u'protection-suite': {
|
||||
u'esp-encryption': u'esp-aes',
|
||||
u'esp-authentication': u'esp-sha-hmac',
|
||||
},
|
||||
u'lifetime-sec': 120,
|
||||
u'pfs': u'group5',
|
||||
u'lifetime-kb': 4608000,
|
||||
u'idle-time': None}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
|
||||
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def get_defaults(url, request):
|
||||
if request.method != 'GET':
|
||||
return
|
||||
LOG.debug("GET mock for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
if 'vpn-svc/ike/policies/2' in url.path:
|
||||
content = {u'kind': u'object#ike-policy',
|
||||
u'priority-id': u'2',
|
||||
u'version': u'v1',
|
||||
u'local-auth-method': u'pre-share',
|
||||
u'encryption': u'des',
|
||||
u'hash': u'sha',
|
||||
u'dhGroup': 1,
|
||||
u'lifetime': 86400}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
if 'vpn-svc/ipsec/policies/' in url.path:
|
||||
ipsec_policy_id = url.path.split('/')[-1]
|
||||
content = {u'kind': u'object#ipsec-policy',
|
||||
u'mode': u'tunnel',
|
||||
u'policy-id': u'%s' % ipsec_policy_id,
|
||||
u'protection-suite': {},
|
||||
u'lifetime-sec': 3600,
|
||||
u'pfs': u'Disable',
|
||||
u'anti-replay-window-size': u'None',
|
||||
u'lifetime-kb': 4608000,
|
||||
u'idle-time': None}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
|
||||
|
||||
@filter_request(['get'], 'vpn-svc/site-to-site')
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def get_unnumbered(url, request):
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
tunnel = url.path.split('/')[-1]
|
||||
ipsec_policy_id = tunnel[6:]
|
||||
content = {u'kind': u'object#vpn-site-to-site',
|
||||
u'vpn-interface-name': u'%s' % tunnel,
|
||||
u'ip-version': u'ipv4',
|
||||
u'vpn-type': u'site-to-site',
|
||||
u'ipsec-policy-id': u'%s' % ipsec_policy_id,
|
||||
u'ike-profile-id': None,
|
||||
u'mtu': 1500,
|
||||
u'local-device': {
|
||||
u'ip-address': u'GigabitEthernet3',
|
||||
u'tunnel-ip-address': u'10.10.10.10'
|
||||
},
|
||||
u'remote-device': {
|
||||
u'tunnel-ip-address': u'10.10.10.20'
|
||||
}}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
|
||||
|
||||
@filter_request(['get'], 'vpn-svc/site-to-site/Tunnel')
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def get_admin_down(url, request):
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
# URI has .../Tunnel#/state, so get number from 2nd to last element
|
||||
tunnel = url.path.split('/')[-2]
|
||||
content = {u'kind': u'object#vpn-site-to-site-state',
|
||||
u'vpn-interface-name': u'%s' % tunnel,
|
||||
u'line-protocol-state': u'down',
|
||||
u'enabled': False}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
|
||||
|
||||
@filter_request(['get'], 'vpn-svc/site-to-site/Tunnel')
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def get_admin_up(url, request):
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
# URI has .../Tunnel#/state, so get number from 2nd to last element
|
||||
tunnel = url.path.split('/')[-2]
|
||||
content = {u'kind': u'object#vpn-site-to-site-state',
|
||||
u'vpn-interface-name': u'%s' % tunnel,
|
||||
u'line-protocol-state': u'down',
|
||||
u'enabled': True}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
|
||||
|
||||
@filter_request(['get'], 'vpn-svc/site-to-site')
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def get_mtu(url, request):
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
tunnel = url.path.split('/')[-1]
|
||||
ipsec_policy_id = tunnel[6:]
|
||||
content = {u'kind': u'object#vpn-site-to-site',
|
||||
u'vpn-interface-name': u'%s' % tunnel,
|
||||
u'ip-version': u'ipv4',
|
||||
u'vpn-type': u'site-to-site',
|
||||
u'ipsec-policy-id': u'%s' % ipsec_policy_id,
|
||||
u'ike-profile-id': None,
|
||||
u'mtu': 9192,
|
||||
u'local-device': {
|
||||
u'ip-address': u'10.3.0.1/24',
|
||||
u'tunnel-ip-address': u'10.10.10.10'
|
||||
},
|
||||
u'remote-device': {
|
||||
u'tunnel-ip-address': u'10.10.10.20'
|
||||
}}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
|
||||
|
||||
@filter_request(['get'], 'vpn-svc/ike/keepalive')
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def get_not_configured(url, request):
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
return {'status_code': requests.codes.NOT_FOUND}
|
||||
|
||||
|
||||
@filter_request(['get'], 'vpn-svc/site-to-site/active/sessions')
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def get_none(url, request):
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
content = {u'kind': u'collection#vpn-active-sessions',
|
||||
u'items': []}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
|
||||
|
||||
@filter_request(['get'], 'interfaces/GigabitEthernet3')
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def get_local_ip(url, request):
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
content = {u'kind': u'object#interface',
|
||||
u'subnet-mask': u'255.255.255.0',
|
||||
u'ip-address': u'10.5.0.2'}
|
||||
return httmock.response(requests.codes.OK, content=content)
|
||||
|
||||
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def post(url, request):
|
||||
if request.method != 'POST':
|
||||
return
|
||||
LOG.debug("POST mock for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
if 'interfaces/GigabitEthernet' in url.path:
|
||||
return {'status_code': requests.codes.NO_CONTENT}
|
||||
if 'global/local-users' in url.path:
|
||||
if 'username' not in request.body:
|
||||
return {'status_code': requests.codes.BAD_REQUEST}
|
||||
if '"privilege": 20' in request.body:
|
||||
return {'status_code': requests.codes.BAD_REQUEST}
|
||||
headers = {'location': '%s/test-user' % url.geturl()}
|
||||
return httmock.response(requests.codes.CREATED, headers=headers)
|
||||
if 'vpn-svc/ike/policies' in url.path:
|
||||
headers = {'location': "%s/2" % url.geturl()}
|
||||
return httmock.response(requests.codes.CREATED, headers=headers)
|
||||
if 'vpn-svc/ipsec/policies' in url.path:
|
||||
m = re.search(r'"policy-id": "(\S+)"', request.body)
|
||||
if m:
|
||||
headers = {'location': "%s/%s" % (url.geturl(), m.group(1))}
|
||||
return httmock.response(requests.codes.CREATED, headers=headers)
|
||||
return {'status_code': requests.codes.BAD_REQUEST}
|
||||
if 'vpn-svc/ike/keyrings' in url.path:
|
||||
headers = {'location': "%s/5" % url.geturl()}
|
||||
return httmock.response(requests.codes.CREATED, headers=headers)
|
||||
if 'vpn-svc/site-to-site' in url.path:
|
||||
m = re.search(r'"vpn-interface-name": "(\S+)"', request.body)
|
||||
if m:
|
||||
headers = {'location': "%s/%s" % (url.geturl(), m.group(1))}
|
||||
return httmock.response(requests.codes.CREATED, headers=headers)
|
||||
return {'status_code': requests.codes.BAD_REQUEST}
|
||||
if 'routing-svc/static-routes' in url.path:
|
||||
headers = {'location':
|
||||
"%s/10.1.0.0_24_GigabitEthernet1" % url.geturl()}
|
||||
return httmock.response(requests.codes.CREATED, headers=headers)
|
||||
|
||||
|
||||
@filter_request(['post'], 'global/local-users')
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def post_change_attempt(url, request):
|
||||
LOG.debug("POST change value mock for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
return {'status_code': requests.codes.NOT_FOUND,
|
||||
'content': {
|
||||
u'error-code': -1,
|
||||
u'error-message': u'user test-user already exists'}}
|
||||
|
||||
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def post_duplicate(url, request):
|
||||
LOG.debug("POST duplicate mock for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
return {'status_code': requests.codes.BAD_REQUEST,
|
||||
'content': {
|
||||
u'error-code': -1,
|
||||
u'error-message': u'policy 2 exist, not allow to '
|
||||
u'update policy using POST method'}}
|
||||
|
||||
|
||||
@filter_request(['post'], 'vpn-svc/site-to-site')
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def post_missing_ipsec_policy(url, request):
|
||||
LOG.debug("POST missing ipsec policy mock for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
return {'status_code': requests.codes.BAD_REQUEST}
|
||||
|
||||
|
||||
@filter_request(['post'], 'vpn-svc/site-to-site')
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def post_missing_ike_policy(url, request):
|
||||
LOG.debug("POST missing ike policy mock for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
return {'status_code': requests.codes.BAD_REQUEST}
|
||||
|
||||
|
||||
@filter_request(['post'], 'vpn-svc/site-to-site')
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def post_bad_ip(url, request):
|
||||
LOG.debug("POST bad IP mock for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
return {'status_code': requests.codes.BAD_REQUEST}
|
||||
|
||||
|
||||
@filter_request(['post'], 'vpn-svc/site-to-site')
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def post_bad_mtu(url, request):
|
||||
LOG.debug("POST bad mtu mock for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
return {'status_code': requests.codes.BAD_REQUEST}
|
||||
|
||||
|
||||
@filter_request(['post'], 'vpn-svc/ipsec/policies')
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def post_bad_lifetime(url, request):
|
||||
LOG.debug("POST bad lifetime mock for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
return {'status_code': requests.codes.BAD_REQUEST}
|
||||
|
||||
|
||||
@filter_request(['post'], 'vpn-svc/ipsec/policies')
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def post_bad_name(url, request):
|
||||
LOG.debug("POST bad IPSec policy name for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
return {'status_code': requests.codes.BAD_REQUEST}
|
||||
|
||||
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def put(url, request):
|
||||
if request.method != 'PUT':
|
||||
return
|
||||
LOG.debug("PUT mock for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
# Any resource
|
||||
return {'status_code': requests.codes.NO_CONTENT}
|
||||
|
||||
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def delete(url, request):
|
||||
if request.method != 'DELETE':
|
||||
return
|
||||
LOG.debug("DELETE mock for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
# Any resource
|
||||
return {'status_code': requests.codes.NO_CONTENT}
|
||||
|
||||
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def delete_unknown(url, request):
|
||||
if request.method != 'DELETE':
|
||||
return
|
||||
LOG.debug("DELETE unknown mock for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
# Any resource
|
||||
return {'status_code': requests.codes.NOT_FOUND,
|
||||
'content': {
|
||||
u'error-code': -1,
|
||||
u'error-message': 'user unknown not found'}}
|
||||
|
||||
|
||||
@httmock.urlmatch(netloc=r'localhost')
|
||||
def delete_not_allowed(url, request):
|
||||
if request.method != 'DELETE':
|
||||
return
|
||||
LOG.debug("DELETE not allowed mock for %s", url)
|
||||
if not request.headers.get('X-auth-token', None):
|
||||
return {'status_code': requests.codes.UNAUTHORIZED}
|
||||
# Any resource
|
||||
return {'status_code': requests.codes.METHOD_NOT_ALLOWED}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -14,6 +14,7 @@
|
|||
|
||||
import copy
|
||||
import httplib
|
||||
import operator
|
||||
|
||||
import mock
|
||||
|
||||
|
@ -124,7 +125,7 @@ class TestCiscoCsrIPSecConnection(base.BaseTestCase):
|
|||
steps are called in reverse order. At the end, there should be no
|
||||
rollback infromation for the connection.
|
||||
"""
|
||||
def fake_route_check_fails(*args, **kwargs):
|
||||
def fake_route_check_fails(*args):
|
||||
if args[0] == 'Static Route':
|
||||
# So that subsequent calls to CSR rest client (for rollback)
|
||||
# will fake as passing.
|
||||
|
@ -1530,7 +1531,8 @@ class TestCiscoCsrIPsecDeviceDriverSyncStatuses(base.BaseTestCase):
|
|||
u'4': {u'status': constants.ACTIVE,
|
||||
u'updated_pending_status': True}}
|
||||
}]
|
||||
self.assertEqual(expected_report, report)
|
||||
self.assertEqual(expected_report,
|
||||
sorted(report, key=operator.itemgetter('id')))
|
||||
# Check that service and connection statuses are updated
|
||||
self.assertEqual(constants.ACTIVE, vpn_service1.last_status)
|
||||
self.assertEqual(constants.ACTIVE,
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
# Copyright 2013, Nachi Ueno, NTT I3, 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.
|
|
@ -29,19 +29,15 @@ from neutron.tests.unit import testlib_api
|
|||
_uuid = uuidutils.generate_uuid
|
||||
|
||||
FAKE_VPN_CONN_ID = _uuid()
|
||||
FAKE_SERVICE_ID = _uuid()
|
||||
FAKE_VPN_CONNECTION = {
|
||||
'vpnservice_id': _uuid(),
|
||||
'vpnservice_id': FAKE_SERVICE_ID,
|
||||
'id': FAKE_VPN_CONN_ID,
|
||||
'ikepolicy_id': _uuid(),
|
||||
'ipsecpolicy_id': _uuid(),
|
||||
'tenant_id': _uuid()
|
||||
}
|
||||
|
||||
FAKE_SERVICE_ID = _uuid()
|
||||
FAKE_VPN_CONNECTION = {
|
||||
'vpnservice_id': FAKE_SERVICE_ID
|
||||
}
|
||||
|
||||
FAKE_ROUTER_ID = _uuid()
|
||||
FAKE_VPN_SERVICE = {
|
||||
'router_id': FAKE_ROUTER_ID
|
||||
|
|
|
@ -93,8 +93,9 @@ class TestVPNAgent(base.BaseTestCase):
|
|||
|
||||
def test_get_namespace(self):
|
||||
router_id = _uuid()
|
||||
ns = "ns-" + router_id
|
||||
ri = l3_agent.RouterInfo(router_id, self.conf.root_helper,
|
||||
self.conf.use_namespaces, {})
|
||||
self.conf.use_namespaces, {}, ns_name=ns)
|
||||
self.agent.router_info = {router_id: ri}
|
||||
namespace = self.agent.get_namespace(router_id)
|
||||
self.assertTrue(namespace.endswith(router_id))
|
||||
|
@ -170,9 +171,10 @@ class TestVPNAgent(base.BaseTestCase):
|
|||
'neutron.agent.linux.iptables_manager.IptablesManager').start()
|
||||
router_id = _uuid()
|
||||
ri = l3_agent.RouterInfo(router_id, self.conf.root_helper,
|
||||
self.conf.use_namespaces, {})
|
||||
self.conf.use_namespaces, {},
|
||||
ns_name="qrouter-%s" % router_id)
|
||||
ri.router = {
|
||||
'id': _uuid(),
|
||||
'id': router_id,
|
||||
'admin_state_up': True,
|
||||
'routes': [],
|
||||
'external_gateway_info': {},
|
||||
|
@ -183,15 +185,14 @@ class TestVPNAgent(base.BaseTestCase):
|
|||
self.agent._router_removed(router_id)
|
||||
device.destroy_router.assert_called_once_with(router_id)
|
||||
|
||||
def test_process_routers(self):
|
||||
def test_process_router_if_compatible(self):
|
||||
self.plugin_api.get_external_network_id.return_value = None
|
||||
routers = [
|
||||
{'id': _uuid(),
|
||||
'admin_state_up': True,
|
||||
'routes': [],
|
||||
'external_gateway_info': {}}]
|
||||
router = {'id': _uuid(),
|
||||
'admin_state_up': True,
|
||||
'routes': [],
|
||||
'external_gateway_info': {}}
|
||||
|
||||
device = mock.Mock()
|
||||
self.agent.devices = [device]
|
||||
self.agent._process_routers(routers, False)
|
||||
device.sync.assert_called_once_with(mock.ANY, routers)
|
||||
self.agent._process_router_if_compatible(router)
|
||||
device.sync.assert_called_once_with(mock.ANY, [router])
|
||||
|
|
|
@ -25,13 +25,11 @@ module=periodic_task
|
|||
module=policy
|
||||
module=processutils
|
||||
module=service
|
||||
module=sslutils
|
||||
module=strutils
|
||||
module=systemd
|
||||
module=threadgroup
|
||||
module=timeutils
|
||||
module=uuidutils
|
||||
module=versionutils
|
||||
|
||||
# The base module to hold the copy of openstack.common
|
||||
base=neutron
|
||||
|
|
|
@ -9,26 +9,28 @@ Routes>=1.12.3,!=2.0
|
|||
anyjson>=0.3.3
|
||||
argparse
|
||||
Babel>=1.3
|
||||
eventlet>=0.15.1
|
||||
eventlet>=0.15.2
|
||||
greenlet>=0.3.2
|
||||
httplib2>=0.7.5
|
||||
requests>=1.2.1,!=2.4.0
|
||||
requests>=2.2.0,!=2.4.0
|
||||
iso8601>=0.1.9
|
||||
jsonrpclib
|
||||
Jinja2
|
||||
keystonemiddleware>=1.0.0
|
||||
kombu>=2.4.8
|
||||
netaddr>=0.7.12
|
||||
python-neutronclient>=2.3.6,<3
|
||||
SQLAlchemy>=0.8.4,<=0.8.99,>=0.9.7,<=0.9.99
|
||||
WebOb>=1.2.3
|
||||
python-keystoneclient>=0.10.0
|
||||
python-keystoneclient>=0.11.1
|
||||
alembic>=0.6.4
|
||||
six>=1.7.0
|
||||
stevedore>=0.14
|
||||
oslo.config>=1.4.0.0a3
|
||||
oslo.db>=0.4.0 # Apache-2.0
|
||||
oslo.messaging>=1.4.0.0a3
|
||||
oslo.rootwrap>=1.3.0.0a1
|
||||
stevedore>=1.0.0 # Apache-2.0
|
||||
oslo.config>=1.4.0 # Apache-2.0
|
||||
oslo.db>=1.0.0 # Apache-2.0
|
||||
oslo.i18n>=1.0.0 # Apache-2.0
|
||||
oslo.messaging>=1.4.0
|
||||
oslo.rootwrap>=1.3.0
|
||||
oslo.serialization>=1.0.0 # Apache-2.0
|
||||
oslo.utils>=1.0.0 # Apache-2.0
|
||||
|
||||
python-novaclient>=2.18.0
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[metadata]
|
||||
name = neutron
|
||||
version = 2014.2
|
||||
version = 2015.1
|
||||
summary = OpenStack Networking
|
||||
description-file =
|
||||
README.rst
|
||||
|
@ -55,6 +55,7 @@ data_files =
|
|||
etc/neutron/plugins/bigswitch/ssl/host_certs/README
|
||||
etc/neutron/plugins/brocade = etc/neutron/plugins/brocade/brocade.ini
|
||||
etc/neutron/plugins/cisco =
|
||||
etc/neutron/plugins/cisco/cisco_cfg_agent.ini
|
||||
etc/neutron/plugins/cisco/cisco_plugins.ini
|
||||
etc/neutron/plugins/cisco/cisco_router_plugin.ini
|
||||
etc/neutron/plugins/cisco/cisco_vpn_agent.ini
|
||||
|
@ -133,14 +134,13 @@ neutron.core_plugins =
|
|||
embrane = neutron.plugins.embrane.plugins.embrane_ml2_plugin:EmbraneMl2Plugin
|
||||
hyperv = neutron.plugins.hyperv.hyperv_neutron_plugin:HyperVNeutronPlugin
|
||||
ibm = neutron.plugins.ibm.sdnve_neutron_plugin:SdnvePluginV2
|
||||
linuxbridge = neutron.plugins.linuxbridge.lb_neutron_plugin:LinuxBridgePluginV2
|
||||
midonet = neutron.plugins.midonet.plugin:MidonetPluginV2
|
||||
ml2 = neutron.plugins.ml2.plugin:Ml2Plugin
|
||||
mlnx = neutron.plugins.mlnx.mlnx_plugin:MellanoxEswitchPlugin
|
||||
nec = neutron.plugins.nec.nec_plugin:NECPluginV2
|
||||
nuage = neutron.plugins.nuage.plugin:NuagePlugin
|
||||
metaplugin = neutron.plugins.metaplugin.meta_neutron_plugin:MetaPluginV2
|
||||
oneconvergence = neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2
|
||||
oneconvergence = neutron.plugins.oneconvergence.plugin:OneConvergencePluginV2
|
||||
openvswitch = neutron.plugins.openvswitch.ovs_neutron_plugin:OVSNeutronPluginV2
|
||||
plumgrid = neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin:NeutronPluginPLUMgridV2
|
||||
ryu = neutron.plugins.ryu.ryu_neutron_plugin:RyuNeutronPluginV2
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# process, which may cause wedges in the gate later.
|
||||
hacking>=0.9.2,<0.10
|
||||
|
||||
cliff>=1.6.0
|
||||
cliff>=1.7.0 # Apache-2.0
|
||||
coverage>=3.6
|
||||
discover
|
||||
fixtures>=0.3.14
|
||||
|
@ -11,8 +11,12 @@ mock>=1.0
|
|||
python-subunit>=0.0.18
|
||||
ordereddict
|
||||
requests-mock>=0.4.0 # Apache-2.0
|
||||
sphinx>=1.1.2,!=1.2.0,<1.3
|
||||
oslosphinx>=2.2.0.0a2
|
||||
sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
|
||||
oslosphinx>=2.2.0 # Apache-2.0
|
||||
testrepository>=0.0.18
|
||||
testtools>=0.9.34
|
||||
testscenarios>=0.4
|
||||
WebTest>=2.0
|
||||
oslotest>=1.1.0 # Apache-2.0
|
||||
psycopg2
|
||||
MySQL-python
|
||||
|
|
13
tox.ini
13
tox.ini
|
@ -1,5 +1,5 @@
|
|||
[tox]
|
||||
envlist = py26,py27,py33,pep8
|
||||
envlist = py26,py27,py33,py34,pep8
|
||||
minversion = 1.6
|
||||
skipsdist = True
|
||||
|
||||
|
@ -64,13 +64,11 @@ commands = python setup.py build_sphinx
|
|||
# E126 continuation line over-indented for hanging indent
|
||||
# E128 continuation line under-indented for visual indent
|
||||
# E129 visually indented line with same indent as next logical line
|
||||
# E251 unexpected spaces around keyword / parameter equals
|
||||
# E265 block comment should start with ‘# ‘
|
||||
# E713 test for membership should be ‘not in’
|
||||
# F402 import module shadowed by loop variable
|
||||
# F811 redefinition of unused variable
|
||||
# F812 list comprehension redefines name from line
|
||||
# H104 file contains nothing but comments
|
||||
# H237 module is removed in Python 3
|
||||
# H305 imports not grouped correctly
|
||||
# H307 like imports should be grouped together
|
||||
|
@ -79,11 +77,18 @@ commands = python setup.py build_sphinx
|
|||
# H405 multi line docstring summary not separated with an empty line
|
||||
# H904 Wrap long lines in parentheses instead of a backslash
|
||||
# TODO(marun) H404 multi line docstring should start with a summary
|
||||
ignore = E125,E126,E128,E129,E251,E265,E713,F402,F811,F812,H104,H237,H305,H307,H401,H402,H404,H405,H904
|
||||
ignore = E125,E126,E128,E129,E265,E713,F402,F811,F812,H237,H305,H307,H401,H402,H404,H405,H904
|
||||
show-source = true
|
||||
builtins = _
|
||||
exclude = .venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build,tools,.ropeproject,rally-scenarios
|
||||
|
||||
[testenv:pylint]
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
pylint
|
||||
commands =
|
||||
pylint --rcfile=.pylintrc --output-format=colorized {posargs:neutron}
|
||||
|
||||
[hacking]
|
||||
import_exceptions = neutron.openstack.common.gettextutils
|
||||
local-check-factory = neutron.hacking.checks.factory
|
||||
|
|
Loading…
Reference in New Issue