81d8a87155
Change-Id: I12012bbcfdd28452d7772a5b652716d0c69f5282
(cherry picked from commit bcb3210760
)
278 lines
13 KiB
Python
278 lines
13 KiB
Python
# Copyright 2016 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 oslo_log import log
|
|
|
|
from requests import exceptions as requests_exceptions
|
|
|
|
from vmware_nsxlib.v3 import exceptions as v3_exceptions
|
|
|
|
LOG = log.getLogger(__name__)
|
|
|
|
|
|
class ExceptionConfig(object):
|
|
|
|
def __init__(self):
|
|
# When hit during API call, these exceptions will mark
|
|
# endpoint as DOWN immediately
|
|
# This setting has no effect on keepalive validation
|
|
self.ground_triggers = [requests_exceptions.ConnectionError,
|
|
requests_exceptions.Timeout]
|
|
|
|
# When hit during API call, these exceptions will be
|
|
# retried with next available endpoint
|
|
# When hit during validation, these exception will not
|
|
# mark endpoint as DOWN
|
|
self.retriables = [v3_exceptions.APITransactionAborted,
|
|
v3_exceptions.CannotConnectToServer,
|
|
v3_exceptions.ServerBusy]
|
|
|
|
# When hit during API call, these exceptions will be retried
|
|
# after the endpoints are regenerated with up-to-date auth
|
|
# credentials / tokens
|
|
self.regenerate_triggers = [v3_exceptions.InvalidCredentials,
|
|
v3_exceptions.ClientCertificateNotTrusted,
|
|
v3_exceptions.BadXSRFToken]
|
|
|
|
def should_ground_endpoint(self, ex):
|
|
for exception in self.ground_triggers:
|
|
if isinstance(ex, exception):
|
|
return True
|
|
|
|
return False
|
|
|
|
def should_retry(self, ex):
|
|
for exception in self.retriables:
|
|
if isinstance(ex, exception):
|
|
return True
|
|
|
|
return False
|
|
|
|
def should_regenerate(self, ex):
|
|
for exception in self.regenerate_triggers:
|
|
if isinstance(ex, exception):
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
class NsxLibConfig(object):
|
|
"""Class holding all the configuration parameters used by the nsxlib code.
|
|
|
|
:param nsx_api_managers: List of IP addresses of the NSX managers.
|
|
Each IP address should be of the form:
|
|
[<scheme>://]<ip_address>[:<port>]
|
|
If scheme is not provided https is used.
|
|
If port is not provided port 80 is used for http
|
|
and port 443 for https.
|
|
:param username: User name for the NSX manager
|
|
:param password: Password for the NSX manager
|
|
:param client_cert_provider: None, or ClientCertProvider object.
|
|
If specified, nsxlib will use client cert auth
|
|
instead of basic authentication.
|
|
:param insecure: If true, the NSX Manager server certificate is not
|
|
verified. If false the CA bundle specified via "ca_file"
|
|
will be used or if unset the "thumbprint" will be used.
|
|
If "thumbprint" is unset, the default system root CAs
|
|
will be used.
|
|
:param ca_file: Specify a CA bundle file to use in verifying the NSX
|
|
Manager server certificate. This option is ignored if
|
|
"insecure" is set to True. If "insecure" is set to False
|
|
and "ca_file" is unset, the "thumbprint" will be used.
|
|
If "thumbprint" is unset, the system root CAs will be
|
|
used to verify the server certificate.
|
|
:param thumbprint: Specify a thumbprint string to use in verifying the
|
|
NSX Manager server certificate. This option is ignored
|
|
if "insecure" is set to True or "ca_file" is defined.
|
|
:param token_provider: None, or instance of implemented AbstractJWTProvider
|
|
which will return the JSON Web Token used in the
|
|
requests in NSX for authorization.
|
|
|
|
:param concurrent_connections: Maximum concurrent connections to each NSX
|
|
manager.
|
|
:param retries: Maximum number of times to retry a HTTP connection.
|
|
:param http_timeout: The time in seconds before aborting a HTTP connection
|
|
to a NSX manager.
|
|
:param http_read_timeout: The time in seconds before aborting a HTTP read
|
|
response from a NSX manager.
|
|
:param conn_idle_timeout: The amount of time in seconds to wait before
|
|
ensuring connectivity to the NSX manager if no
|
|
manager connection has been used.
|
|
:param http_provider: HTTPProvider object, or None.
|
|
|
|
:param max_attempts: Maximum number of times to retry API requests upon
|
|
stale revision errors.
|
|
|
|
:param plugin_scope: The default scope for the v3 api-version tag
|
|
:param plugin_tag: The value for the v3 api-version tag
|
|
:param plugin_ver: The version of the plugin used as the 'os-api-version'
|
|
tag value in the v3 api-version tag
|
|
:param dns_nameservers: List of nameservers to configure for the DHCP
|
|
binding entries. These will be used if there are
|
|
no nameservers defined on the subnet.
|
|
:param dns_domain: Domain to use for building the hostnames.
|
|
:param allow_overwrite_header: If True, a default header of
|
|
X-Allow-Overwrite:true will be added to all
|
|
the requests, to allow admin user to update/
|
|
delete all entries.
|
|
:param rate_limit_retry: If True, the client will retry requests failed on
|
|
"Too many requests" error.
|
|
:param cluster_unavailable_retry: If True, skip fatal errors when no
|
|
endpoint in the NSX management cluster is
|
|
available to serve a request, and retry
|
|
the request instead. This setting can
|
|
not be False if single endpoint is
|
|
configured in the cluster, since there
|
|
will be no keepalive probes in this
|
|
case.
|
|
:param api_rate_limit_per_endpoint: If set to positive integer, API calls
|
|
sent to each endpoint will be limited
|
|
to a max rate of this value per second.
|
|
The rate limit is not enforced on
|
|
connection validations. This option
|
|
defaults to None, which disables rate
|
|
limit.
|
|
:param api_rate_mode: Algorithm used to adaptively adjust max API rate
|
|
limit. If not set, the max rate will not be
|
|
automatically changed. If set to 'AIMD', max API
|
|
rate will be increase by 1 after successful calls
|
|
that was blocked before sent, and will be decreased
|
|
by half after 429/503 error for each period.
|
|
The rate has hard max limit of min(100/s, param
|
|
api_rate_limit_per_endpoint).
|
|
:param api_log_mode: Option to collect API call logs within nsxlib.
|
|
When set to API_LOG_PER_CLUSTER, API calls sent to all
|
|
endpoints will be collected at one place.
|
|
When set to API_LOG_PER_ENDPOINT, API calls sent to
|
|
each endpoint will be collected individually.
|
|
By default, this option is disabled as set to None.
|
|
|
|
-- Additional parameters which are relevant only for the Policy manager:
|
|
:param allow_passthrough: If True, use nsx manager api for cases which are
|
|
not supported by the policy manager api.
|
|
:param realization_max_attempts: Maximum number of times to retry while
|
|
waiting for a resource to be realized.
|
|
:param realization_wait_sec: Number of seconds to wait between attempts
|
|
for a resource to be realized.
|
|
"""
|
|
|
|
def __init__(self,
|
|
nsx_api_managers=None,
|
|
username=None,
|
|
password=None,
|
|
client_cert_provider=None,
|
|
insecure=True,
|
|
ca_file=None,
|
|
thumbprint=None,
|
|
token_provider=None,
|
|
concurrent_connections=10,
|
|
retries=3,
|
|
http_timeout=10,
|
|
http_read_timeout=180,
|
|
conn_idle_timeout=10,
|
|
http_provider=None,
|
|
max_attempts=10,
|
|
plugin_scope=None,
|
|
plugin_tag=None,
|
|
plugin_ver=None,
|
|
dns_nameservers=None,
|
|
dns_domain='openstacklocal',
|
|
allow_overwrite_header=False,
|
|
rate_limit_retry=True,
|
|
cluster_unavailable_retry=False,
|
|
allow_passthrough=False,
|
|
realization_max_attempts=50,
|
|
realization_wait_sec=1.0,
|
|
api_rate_limit_per_endpoint=None,
|
|
api_rate_mode=None,
|
|
exception_config=None,
|
|
api_log_mode=None):
|
|
|
|
self.nsx_api_managers = nsx_api_managers
|
|
self._username = username
|
|
self._password = password
|
|
self._ca_file = ca_file
|
|
self._thumbprint = thumbprint
|
|
self.insecure = insecure
|
|
self.concurrent_connections = concurrent_connections
|
|
self.retries = retries
|
|
self.http_timeout = http_timeout
|
|
self.http_read_timeout = http_read_timeout
|
|
self.conn_idle_timeout = conn_idle_timeout
|
|
self.http_provider = http_provider
|
|
self.client_cert_provider = client_cert_provider
|
|
self.token_provider = token_provider
|
|
self.max_attempts = max_attempts
|
|
self.plugin_scope = plugin_scope
|
|
self.plugin_tag = plugin_tag
|
|
self.plugin_ver = plugin_ver
|
|
self.dns_nameservers = dns_nameservers or []
|
|
self.dns_domain = dns_domain
|
|
self.allow_overwrite_header = allow_overwrite_header
|
|
self.rate_limit_retry = rate_limit_retry
|
|
self.cluster_unavailable_retry = cluster_unavailable_retry
|
|
self.allow_passthrough = allow_passthrough
|
|
self.realization_max_attempts = realization_max_attempts
|
|
self.realization_wait_sec = realization_wait_sec
|
|
self.api_rate_limit_per_endpoint = api_rate_limit_per_endpoint
|
|
self.api_rate_mode = api_rate_mode
|
|
self.exception_config = exception_config or ExceptionConfig()
|
|
self.api_log_mode = api_log_mode
|
|
|
|
if len(nsx_api_managers) == 1 and not self.cluster_unavailable_retry:
|
|
LOG.warning("When only one endpoint is provided, keepalive probes"
|
|
" are disabled. For the system to be able to recover"
|
|
" from DOWN state, cluster_unavailable_retry is set"
|
|
" to True, overriding provided configuration")
|
|
self.cluster_unavailable_retry = True
|
|
|
|
if len(nsx_api_managers) > self.max_attempts:
|
|
LOG.warning("max_attempts setting (%d) is lower than amount of"
|
|
" endpoints (%d), which means that not all endpoints"
|
|
" will be probed in case of retriable error",
|
|
self.max_attempts, len(nsx_api_managers))
|
|
|
|
def extend(self, keepalive_section, validate_connection_method=None,
|
|
url_base=None):
|
|
if keepalive_section or validate_connection_method:
|
|
LOG.warning("keepalive_section and validate_connection_method are"
|
|
" no longer used to conduct keepalive probes. For"
|
|
" most efficient keepalive roundtrip, proxy health"
|
|
" API is always used.")
|
|
self.url_base = url_base
|
|
|
|
def _attribute_by_index(self, scalar_or_list, index):
|
|
if isinstance(scalar_or_list, list):
|
|
if not len(scalar_or_list):
|
|
return None
|
|
if len(scalar_or_list) > index:
|
|
return scalar_or_list[index]
|
|
# if not long enough - use the first one as default
|
|
return scalar_or_list[0]
|
|
# this is a scalar
|
|
return scalar_or_list
|
|
|
|
def username(self, index):
|
|
return self._attribute_by_index(self._username, index)
|
|
|
|
def password(self, index):
|
|
return self._attribute_by_index(self._password, index)
|
|
|
|
def ca_file(self, index):
|
|
return self._attribute_by_index(self._ca_file, index)
|
|
|
|
def thumbprint(self, index):
|
|
return self._attribute_by_index(self._thumbprint, index)
|