You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
277 lines
13 KiB
277 lines
13 KiB
# 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 call sent to all |
|
endpoints will be collected at one place. |
|
When set to API_LOG_PER_ENDPOINT, API call 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)
|
|
|