vmware-nsx/vmware_nsx/api_client/client.py

141 lines
5.6 KiB
Python

# Copyright 2012 VMware, Inc.
#
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from oslo_log import log as logging
from six.moves import http_client as httplib
from vmware_nsx.api_client import base
from vmware_nsx.api_client import eventlet_client
from vmware_nsx.api_client import eventlet_request
from vmware_nsx.api_client import exception
from vmware_nsx.api_client import version
LOG = logging.getLogger(__name__)
class NsxApiClient(eventlet_client.EventletApiClient):
"""The Nsx API Client."""
def __init__(self, api_providers, user, password,
concurrent_connections=base.DEFAULT_CONCURRENT_CONNECTIONS,
gen_timeout=base.GENERATION_ID_TIMEOUT,
use_https=True,
connect_timeout=base.DEFAULT_CONNECT_TIMEOUT,
http_timeout=75, retries=2, redirects=2):
'''Constructor. Adds the following:
:param http_timeout: how long to wait before aborting an
unresponsive controller (and allow for retries to another
controller in the cluster)
:param retries: the number of concurrent connections.
:param redirects: the number of concurrent connections.
'''
super(NsxApiClient, self).__init__(
api_providers, user, password,
concurrent_connections=concurrent_connections,
gen_timeout=gen_timeout, use_https=use_https,
connect_timeout=connect_timeout)
self._request_timeout = http_timeout * retries
self._http_timeout = http_timeout
self._retries = retries
self._redirects = redirects
self._version = None
# NOTE(salvatore-orlando): This method is not used anymore. Login is now
# performed automatically inside the request eventlet if necessary.
def login(self, user=None, password=None):
'''Login to NSX controller.
Assumes same password is used for all controllers.
:param user: controller user (usually admin). Provided for
backwards compatibility. In the normal mode of operation
this should be None.
:param password: controller password. Provided for backwards
compatibility. In the normal mode of operation this should
be None.
'''
if user:
self._user = user
if password:
self._password = password
return self._login()
def request(self, method, url, body="", content_type="application/json"):
'''Issues request to controller.'''
g = eventlet_request.GenericRequestEventlet(
self, method, url, body, content_type, auto_login=True,
http_timeout=self._http_timeout,
retries=self._retries, redirects=self._redirects)
g.start()
response = g.join()
LOG.debug('Request returns "%s"', response)
# response is a modified HTTPResponse object or None.
# response.read() will not work on response as the underlying library
# request_eventlet.ApiRequestEventlet has already called this
# method in order to extract the body and headers for processing.
# ApiRequestEventlet derived classes call .read() and
# .getheaders() on the HTTPResponse objects and store the results in
# the response object's .body and .headers data members for future
# access.
if response is None:
# Timeout.
LOG.error('Request timed out: %(method)s to %(url)s',
{'method': method, 'url': url})
raise exception.RequestTimeout()
status = response.status
if status == httplib.UNAUTHORIZED:
raise exception.UnAuthorizedRequest()
# Fail-fast: Check for exception conditions and raise the
# appropriate exceptions for known error codes.
if status in exception.ERROR_MAPPINGS:
LOG.error("Received error code: %s", status)
LOG.error("Server Error Message: %s", response.body)
exception.ERROR_MAPPINGS[status](response)
# Continue processing for non-error condition.
if (status != httplib.OK and status != httplib.CREATED
and status != httplib.NO_CONTENT):
LOG.error("%(method)s to %(url)s, unexpected response code: "
"%(status)d (content = '%(body)s')",
{'method': method, 'url': url,
'status': response.status, 'body': response.body})
return None
if not self._version:
self._version = version.find_version(response.headers)
return response.body
def get_version(self):
if not self._version:
# Determine the controller version by querying the
# cluster nodes. Currently, the version will be the
# one of the server that responds.
self.request('GET', '/ws.v1/control-cluster/node')
if not self._version:
LOG.error('Unable to determine NSX version. '
'Plugin might not work as expected.')
return self._version