nova-fusioncompute/nova/virt/fusioncomputeapi/fcclient.py

214 lines
6.7 KiB
Python

# Copyright 2016 Huawei Technologies Co.,LTD.
# 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 nova.i18n import _
from nova.virt.fusioncomputeapi import constant
from nova.virt.fusioncomputeapi import exception
from nova.virt.fusioncomputeapi import restclient
from nova.virt.fusioncomputeapi import utils
from nova.virt.fusioncomputeapi.utils import LOG
class FCBaseClient(restclient.RestClient):
STATUS_OK = [200, 201, 202]
STATUS_NO_AUTH = [401]
STATUS_INVALID = [400, 403, 404, 500, 503]
def __init__(self, host, user, key, user_type, api_version='6.0',
ssl=None, port=None, cert=None, request_time_out=120):
super(FCBaseClient, self).__init__(host, port=port, ssl=ssl, cert=cert)
self.__user = user
self.__key = key
self.__user_type = user_type
self.__api_version = api_version
self.__accept = ('application/json;version=%s;charset=UTF-8' %
api_version)
self.__content_type = 'application/json'
self.__accept_language = 'en_US'
self.__request_time_out = request_time_out
self.__token = None
self.context = FCClientContext(self)
def _update_and_get_headers(self, headers, force_get_token):
"""update fc rest header and return headers
:param headers:
:param force_get_token:
:return:
"""
if not self.__token or force_get_token:
self.get_token()
if not headers:
headers_res = self._make_headers(self.__token)
else:
headers_res = headers.copy()
headers_res.update(self._make_headers(self.__token))
return headers_res
def request_msg(self, method, path, data=None, headers=None, **kwargs):
req_headers = self._update_and_get_headers(headers, False)
# set default request time out
kwargs['timeout'] = kwargs.get('timeout', self.__request_time_out)
rsp = self._request(method, path, data, headers=req_headers, **kwargs)
if rsp.status_code in self.STATUS_NO_AUTH:
LOG.info('token may expired, fetch again.')
req_headers = self._update_and_get_headers(headers, True)
rsp = self._request(method, path, data, headers=req_headers,
**kwargs)
# catch message sending exception
self._raise_if_not_in_status_ok(rsp)
ret_data = {'response': rsp, 'data': None}
if rsp.text:
try:
ret_data['data'] = rsp.json()
# ignore pylint:disable=W0703
except Exception as excp:
LOG.warn(_('failed to loads json response data, %s'), excp)
ret_data['data'] = rsp.text
if kwargs.get('need_response', False):
return ret_data
return ret_data['data']
def _raise_if_not_in_status_ok(self, rsp):
"""if response is not normal,rasise exception
:param rsp:
:return:
"""
if rsp.status_code not in self.STATUS_OK:
error_info = {}
try:
error_info = rsp.json()
# ignore pylint:disable=W0703
except Exception as excp:
LOG.warn('try to get error response content failed: %s', excp)
raise exception.RequestError(reason=error_info.get('errorDes'),
error_code=error_info.get('errorCode')
)
def get_token(self):
"""Get token from FC
:return
"""
response = self._request('post', constant.TOKEN_URI, data={},
headers=self._make_headers())
self.__token = response.headers['X-Auth-Token']
def get_sites(self):
"""get fc default site info
:return:
"""
return self.get(constant.SITE_URI)
def get_first_site(self):
sites = self.get_sites()
if not sites or not sites.get('sites'):
raise exception.NoAvailableSite()
return sites['sites'][0]
def set_default_site(self):
self.context.set_default_site(self.get_first_site())
def _make_headers(self, token=None):
"""make token header info
:param token:
:return:
"""
headers = {
'Accept-Language': self.__accept_language,
'Content-Type': self.__content_type,
'Accept': self.__accept
}
if token:
headers.update({
'X-Auth-Token': token
})
else:
headers.update({
'X-Auth-User': self.__user,
'X-Auth-Key': self.__key,
'X-Auth-UserType': self.__user_type,
'X-ENCRIPT-ALGORITHM': '1'
})
return headers
class FCClientContext(dict):
"""fc base info"""
def __init__(self, client):
super(FCClientContext, self).__init__()
self.client = client
self.site_uri_map = None
def __getattr__(self, name):
"""if dict has attr,return dict ,else return site uri info
:param name:
:return:
"""
if self.get(name):
return self.get(name)
elif self.site_uri_map:
return utils.get_fc_uri(name, self.site_uri_map)
else:
return None
def set_default_site(self, site):
"""set default site infos
:param site:
:return:
"""
self['site'] = site
self['site_id'] = utils.get_id_from_urn(self['site']['urn'])
self['site_uri'] = '/'.join([constant.SITE_URI, self['site_id']])
self.site_uri_map = {'site_uri': self['site_uri']}
def get_path_by_site(self, path='', **kwargs):
"""Connect your path with default site path, and format args value
:param path: in format like '/resource/%<id>s/action/%(other)s'
:param kwargs: Dictionary args, matched path format, like (id=id_value,
other=other_value)
:return: path like
'/service/sites/site_id/resource/id_value/action/other_value'
"""
if not kwargs:
kwargs = {}
if isinstance(path, list):
path = ''.join(path)
return ''.join([self['site_uri'], path % kwargs])