Scalability updates for cgtsclient

- added session based httpclient support to cgtsclient
- removed the unused smapi_endpoint code from the client.
- replaced calls to keystoneclient with keystoneauth
- fixed an issue in the post-processing where sort was
making deep copies during the display of the results.

Test plan:
PASS: System host-lock and unlock.
PASS: System load-import.
PASS: System host-add.
PASS: System host-delete.
PASS: dcmanager subcloud add.
PASS: Simulated test: multiple sysinv-api calls in parallel
      with cached token and endpoint.

Story: 2008943
Task: 42954
Signed-off-by: albailey <Al.Bailey@windriver.com>
Change-Id: I249bb9fc88fa6489bc8eda3da50b7a474ef09d90
This commit is contained in:
albailey 2021-08-04 09:19:57 -05:00 committed by Iago Estrela
parent 0ed46984cd
commit 39919f7be0
14 changed files with 436 additions and 314 deletions

View File

@ -3,139 +3,151 @@
#
# SPDX-License-Identifier: Apache-2.0
#
from keystoneauth1 import loading
from oslo_utils import importutils
from cgtsclient._i18n import _
from cgtsclient.common import utils
from cgtsclient import exc
def _get_ksclient(**kwargs):
"""Get an endpoint and auth token from Keystone.
SERVICE_NAME = 'sysinv'
SERVICE_TYPE = 'platform'
:param kwargs: keyword args containing credentials:
* username: name of user
* password: user's password
* user_domain_name: User's domain name for authentication.
* project_domain_name: Project's domain name for project
* auth_url: endpoint to authenticate against
* insecure: allow insecure SSL (no cert verification)
* project_name: Project name for project scoping.
def _make_session(**kwargs):
"""Construct a session based on authentication information
:param kwargs: keyword args containing credentials, either:
* os_auth_token: pre-existing token to re-use
* system_url: system API endpoint
or:
* os_username: name of user
* os_password: user's password
* os_auth_url: endpoint to authenticate against
* insecure: allow insecure SSL (no cert verification)
* os_tenant_{name|id}: name or ID of tenant
* os_region_name: region of the service
* os_project_name: name of a project
* os_project_id: ID of a project
* os_user_domain_name: name of a domain the user belongs to
* os_user_domain_id: ID of a domain the user belongs to
* os_project_domain_name: name of a domain the project belongs to
* os_project_domain_id: ID of a domain the project belongs to
* timeout: request timeout (in seconds)
"""
from keystoneclient.v3 import client as ksclient
return ksclient.Client(username=kwargs.get('username'),
password=kwargs.get('password'),
user_domain_name=kwargs.get('user_domain_name'),
project_domain_name=kwargs.get('project_domain_name'),
project_name=kwargs.get('project_name'),
auth_url=kwargs.get('auth_url'),
insecure=kwargs.get('insecure'),
cacert=kwargs.get('os_cacert'))
session = None
if (kwargs.get('os_username') and
kwargs.get('os_password') and
kwargs.get('os_auth_url') and
(kwargs.get('os_project_id') or
kwargs.get('os_project_name'))):
auth_kwargs = {}
auth_url = kwargs.get('os_auth_url')
project_id = kwargs.get('os_project_id')
project_name = kwargs.get('os_project_name')
user_domain_id = kwargs.get('os_user_domain_id')
user_domain_name = kwargs.get('os_user_domain_name') or "Default"
project_domain_id = kwargs.get('os_project_domain_id')
project_domain_name = kwargs.get('os_project_domain_name') or "Default"
# todo(abailey): we can enhance this to also support token
auth_type = 'password'
username = kwargs.get('os_username')
password = kwargs.get('os_password')
auth_kwargs.update({
'auth_url': auth_url,
'project_id': project_id,
'project_name': project_name,
'user_domain_id': user_domain_id,
'user_domain_name': user_domain_name,
'project_domain_id': project_domain_id,
'project_domain_name': project_domain_name,
'username': username,
'password': password
})
# construct the appropriate session
timeout = kwargs.get('timeout')
loader = loading.get_plugin_loader(auth_type)
auth_plugin = loader.load_from_options(**auth_kwargs)
session = loading.session.Session().load_from_options(auth=auth_plugin,
timeout=timeout)
# session could still be None
return session
def _get_sm_endpoint(client, **kwargs):
"""Get an endpoint for smapi using the provided keystone client."""
return client.auth_ref.service_catalog.url_for(
service_type=kwargs.get('service_name') or 'smapi',
endpoint_type=kwargs.get('endpoint_type') or 'public',
region_name=kwargs.get('os_region_name') or 'RegionOne')
def _get_endpoint(client, **kwargs):
"""Get an endpoint using the provided keystone client."""
return client.auth_ref.service_catalog.url_for(
service_type=kwargs.get('service_type') or 'platform',
endpoint_type=kwargs.get('endpoint_type') or 'public',
region_name=kwargs.get('os_region_name') or 'RegionOne')
def get_client(api_version, **kwargs):
"""Get an authenticated client, based on the credentials
in the keyword args.
def get_client(api_version, session=None, service_type=SERVICE_TYPE, **kwargs):
"""Get an authenticated client, based on credentials in the keyword args.
:param api_version: the API version to use ('1' or '2')
:param kwargs: keyword args containing credentials, either:
* os_auth_token: pre-existing token to re-use
* system_url: system API endpoint
or:
* os_username: name of user
* os_password: user's password
* os_auth_url: endpoint to authenticate against
* insecure: allow insecure SSL (no cert verification)
* os_tenant_{name|id}: name or ID of tenant
* os_region_name: region of the service
* os_project_name: name of a project
* os_project_id: ID of a project
* os_user_domain_name: name of a domain the user belongs to
* os_user_domain_id: ID of a domain the user belongs to
* os_project_domain_name: name of a domain the project belongs to
* os_project_domain_id: ID of a domain the project belongs to
:param session: the session to use (if it exists)
:param service_type: service_type should always be 'platform'
:param kwargs: additional keyword args to pass to the client or auth
"""
if kwargs.get('os_auth_token') and kwargs.get('system_url'):
token = kwargs.get('os_auth_token')
endpoint = kwargs.get('system_url')
auth_ref = None
elif (kwargs.get('os_username') and
kwargs.get('os_password') and
kwargs.get('os_auth_url') and
(kwargs.get('os_project_id') or kwargs.get('os_project_name'))):
ks_kwargs = {
'username': kwargs.get('os_username'),
'password': kwargs.get('os_password'),
'project_id': kwargs.get('os_project_id'),
'project_name': kwargs.get('os_project_name'),
'user_domain_id': kwargs.get('os_user_domain_id'),
'user_domain_name': kwargs.get('os_user_domain_name'),
'project_domain_id': kwargs.get('os_project_domain_id'),
'project_domain_name': kwargs.get('os_project_domain_name'),
'auth_url': kwargs.get('os_auth_url'),
'service_type': kwargs.get('os_service_type'),
'endpoint_type': kwargs.get('os_endpoint_type'),
'insecure': kwargs.get('insecure'),
'os_cacert': kwargs.get('ca_file')
endpoint = kwargs.get('system_url')
if endpoint:
api_version_str = '/v' + api_version
if api_version_str not in endpoint.split('/'):
endpoint += api_version_str
auth_token = kwargs.get('os_auth_token')
# if we have an endpoint and token, use those
if endpoint and auth_token:
pass
elif not session:
# Make a session to determine the endpoint
session = _make_session(**kwargs)
if not endpoint:
exception_msg = _('Must provide Keystone credentials or '
'user-defined endpoint and token')
if session:
try:
# todo(abailey): add support for non 'os_' keys
interface = kwargs.get('os_endpoint_type')
region_name = kwargs.get('os_region_name')
endpoint = session.get_endpoint(service_type=service_type,
interface=interface,
region_name=region_name)
except Exception as e:
raise exc.EndpointException(
_('%(message)s, error was: %(error)s') %
{'message': exception_msg, 'error': e})
else:
raise exc.AmbigiousAuthSystem(exception_msg)
if session:
# this will be a LegacyJsonAdapter
cli_kwargs = {
'session': session,
'service_type': service_type,
'service_name': SERVICE_NAME,
'interface': kwargs.get('os_endpoint_type'),
'region_name': kwargs.get('os_region_name'),
'endpoint_override': endpoint,
'global_request_id': kwargs.get('global_request_id'),
'user_agent': kwargs.get('user_agent', 'cgtsclient')
}
_ksclient = _get_ksclient(**ks_kwargs)
token = kwargs.get('os_auth_token') if kwargs.get('os_auth_token') else _ksclient.auth_ref.auth_token
ep_kwargs = {
'service_type': kwargs.get('os_service_type'),
'endpoint_type': kwargs.get('os_endpoint_type'),
'os_region_name': kwargs.get('os_region_name'),
}
endpoint = kwargs.get('system_url') or \
_get_endpoint(_ksclient, **ep_kwargs)
auth_ref = _ksclient.auth_ref
else:
e = (_('Must provide Keystone credentials or user-defined endpoint '
'and token'))
raise exc.AmbigiousAuthSystem(e)
try:
smapi_endpoint = _get_sm_endpoint(_ksclient, **ep_kwargs)
except Exception:
# Could be invoked during controller bootstrap where smapi
# endpoint is not yet available.
smapi_endpoint = None
cli_kwargs = {
'token': token,
'insecure': kwargs.get('insecure'),
'cacert': kwargs.get('cacert'),
'timeout': kwargs.get('timeout'),
'ca_file': kwargs.get('ca_file'),
'cert_file': kwargs.get('cert_file'),
'key_file': kwargs.get('key_file'),
'auth_ref': auth_ref,
'auth_url': kwargs.get('os_auth_url'),
'smapi_endpoint': smapi_endpoint,
}
return Client(api_version, endpoint, **cli_kwargs)
# This will become a httplib2 object
auth_ref = None
cli_kwargs = {
'token': auth_token,
'insecure': kwargs.get('insecure'),
'cacert': kwargs.get('cacert'),
'timeout': kwargs.get('timeout'),
'ca_file': kwargs.get('ca_file'),
'cert_file': kwargs.get('cert_file'),
'key_file': kwargs.get('key_file'),
'auth_ref': auth_ref,
'auth_url': kwargs.get('os_auth_url'),
}
return Client(api_version, endpoint, session, **cli_kwargs)
def Client(version, *args, **kwargs):
module = utils.import_versioned_module(version, 'client')
module = importutils.import_versioned_module('cgtsclient',
version, 'client')
client_class = getattr(module, 'Client')
return client_class(*args, **kwargs)

View File

@ -15,10 +15,13 @@
# under the License.
#
import copy
import hashlib
import httplib2
from keystoneauth1 import adapter
import logging
import os
from oslo_serialization import jsonutils
from oslo_utils import encodeutils
import requests
from requests_toolbelt import MultipartEncoder
@ -27,6 +30,7 @@ import socket
import six
from six.moves.urllib.parse import urlparse
try:
import ssl
except ImportError:
@ -45,6 +49,9 @@ _logger = logging.getLogger(__name__)
CHUNKSIZE = 1024 * 64 # 64kB
SENSITIVE_HEADERS = ('X-Auth-Token',)
UPLOAD_REQUEST_TIMEOUT = 1800
USER_AGENT = 'cgtsclient'
API_VERSION = '/v1'
DEFAULT_API_VERSION = 'latest'
# httplib2 retries requests on socket.timeout which
# is not idempotent and can lead to orhan objects.
@ -105,6 +112,163 @@ class ServiceCatalog(object):
return matching_endpoints[0][endpoint_type]
def _extract_error_json_text(body_json):
error_json = {}
if 'error_message' in body_json:
raw_msg = body_json['error_message']
error_json = jsonutils.loads(raw_msg)
elif 'error' in body_json:
error_body = body_json['error']
error_json = {'faultstring': error_body['title'],
'debuginfo': error_body['message']}
else:
error_body = body_json['errors'][0]
error_json = {'faultstring': error_body['title']}
if 'detail' in error_body:
error_json['debuginfo'] = error_body['detail']
elif 'description' in error_body:
error_json['debuginfo'] = error_body['description']
return error_json
def _extract_error_json(body, resp):
"""Return error_message from the HTTP response body."""
try:
content_type = resp.headers.get("Content-Type", "")
except AttributeError:
content_type = ""
if content_type.startswith("application/json"):
try:
body_json = resp.json()
return _extract_error_json_text(body_json)
except AttributeError:
body_json = jsonutils.loads(body)
return _extract_error_json_text(body_json)
except ValueError:
return {}
else:
try:
body_json = jsonutils.loads(body)
return _extract_error_json_text(body_json)
except ValueError:
return {}
class SessionClient(adapter.LegacyJsonAdapter):
def __init__(self, *args, **kwargs):
self.user_agent = USER_AGENT
self.api_version = DEFAULT_API_VERSION
super(SessionClient, self).__init__(*args, **kwargs)
def _http_request(self, url, method, **kwargs):
if url.startswith(API_VERSION):
url = url[len(API_VERSION):]
kwargs.setdefault('user_agent', self.user_agent)
kwargs.setdefault('auth', self.auth)
kwargs.setdefault('endpoint_override', self.endpoint_override)
# Copy the kwargs so we can reuse the original in case of redirects
kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {}))
kwargs['headers'].setdefault('User-Agent', self.user_agent)
endpoint_filter = kwargs.setdefault('endpoint_filter', {})
endpoint_filter.setdefault('interface', self.interface)
endpoint_filter.setdefault('service_type', self.service_type)
endpoint_filter.setdefault('region_name', self.region_name)
resp = self.session.request(url, method,
raise_exc=False, **kwargs)
if 400 <= resp.status_code < 600:
error_json = _extract_error_json(resp.content, resp)
raise exceptions.from_response(
resp, error_json.get('faultstring'),
error_json.get('debuginfo'), method, url)
elif resp.status_code in (301, 302, 305):
# Redirected. Reissue the request to the new location.
location = resp.headers.get('location')
resp = self._http_request(location, method, **kwargs)
elif resp.status_code == 300:
raise exceptions.from_response(resp, method=method, url=url)
return resp
def json_request(self, method, url, **kwargs):
kwargs.setdefault('headers', {})
kwargs['headers'].setdefault('Content-Type', 'application/json')
kwargs['headers'].setdefault('Accept', 'application/json')
if 'body' in kwargs:
kwargs['data'] = jsonutils.dumps(kwargs.pop('body'))
resp = self._http_request(url, method, **kwargs)
body = resp.content
content_type = resp.headers.get('content-type', None)
status = resp.status_code
if status == 204 or status == 205 or content_type is None:
return resp, list()
if 'application/json' in content_type:
try:
body = resp.json()
except ValueError:
_logger.error('Could not decode response body as JSON')
else:
body = None
return resp, body
def raw_request(self, method, url, **kwargs):
kwargs.setdefault('headers', {})
kwargs['headers'].setdefault('Content-Type',
'application/octet-stream')
return self._http_request(url, method, **kwargs)
def _get_connection_url(self, url):
endpoint = self.endpoint_override
# if 'v1 in both, remove 'v1' from endpoint
if 'v1' in endpoint and 'v1' in url:
endpoint = endpoint.replace('/v1', '', 1)
# if 'v1 not in both, add 'v1' to endpoint
elif 'v1' not in endpoint and 'v1' not in url:
endpoint = endpoint.rstrip('/') + '/v1'
return endpoint.rstrip('/') + '/' + url.lstrip('/')
def upload_request_with_data(self, method, url, **kwargs):
requests_url = self._get_connection_url(url)
headers = {"X-Auth-Token": self.session.get_token()}
files = {'file': ("for_upload",
kwargs['body'],
)}
data = kwargs.get('data')
req = requests.post(requests_url, headers=headers, files=files,
data=data)
return req.json()
def upload_request_with_multipart(self, method, url, **kwargs):
requests_url = self._get_connection_url(url)
fields = kwargs.get('data')
files = kwargs['body']
if fields is None:
fields = dict()
for k, v in files.items():
fields[k] = (v, open(v, 'rb'),)
enc = MultipartEncoder(fields)
headers = {'Content-Type': enc.content_type,
"X-Auth-Token": self.session.get_token()}
response = requests.post(requests_url, data=enc, headers=headers)
if kwargs.get('check_exceptions'):
if response.status_code != 200:
err_message = _extract_error_json(response.text, response)
fault_text = err_message.get('faultstring') or "Unknown Error"
raise exceptions.HTTPBadRequest(fault_text)
return response.json()
class HTTPClient(httplib2.Http):
"""Handles the REST calls and responses, include authn."""
@ -586,4 +750,33 @@ class ResponseBodyIterator(object):
if chunk:
return chunk
else:
return
raise StopIteration()
def construct_http_client(endpoint=None, username=None, password=None,
endpoint_type=None, auth_url=None, **kwargs):
session = kwargs.pop('session', None)
auth = kwargs.pop('auth', None)
if session:
# SessionClient
if 'endpoint_override' not in kwargs and endpoint:
kwargs['endpoint_override'] = endpoint
if 'service_type' not in kwargs:
kwargs['service_type'] = 'platform'
if 'interface' not in kwargs and endpoint_type:
kwargs['interface'] = endpoint_type
if 'region_name' in kwargs:
kwargs['additional_headers'] = {
'X-Region-Name': kwargs['region_name']}
return SessionClient(session, auth=auth, **kwargs)
else:
# httplib2
return HTTPClient(endpoint=endpoint, username=username,
password=password, endpoint_type=endpoint_type,
auth_url=auth_url, **kwargs)

View File

@ -208,7 +208,7 @@ def _sort_for_list(objs, fields, formatters=None, sortby=0, reversesort=False):
if sortby is None:
return objs
rows_to_sort = copy.deepcopy(objs)
rows_to_sort = objs
sort_field = fields[sortby]
# figure out sort key function

View File

@ -154,7 +154,7 @@ for obj_name in dir(sys.modules[__name__]):
def from_response(response, message=None, traceback=None,
method=None, url=None):
"""Return an instance of an HTTPException based on httplib response."""
cls = _code_map.get(response.status, HTTPException)
cls = _code_map.get(response.status_code, HTTPException)
return cls(message)

View File

@ -12,6 +12,8 @@ from six.moves import cStringIO as StringIO
import sys
from testtools import matchers
import keystoneauth1
from cgtsclient import exc
from cgtsclient import shell as cgts_shell
from cgtsclient.tests import utils
@ -28,6 +30,9 @@ FAKE_ENV = {'OS_USERNAME': 'username',
class ShellTest(utils.BaseTestCase):
re_options = re.DOTALL | re.MULTILINE
mock_endpoint_patcher = mock.patch.object(keystoneauth1.session.Session,
'get_endpoint')
# Patch os.environ to avoid required auth info.
def make_env(self, exclude=None):
env = dict((k, v) for k, v in FAKE_ENV.items() if k != exclude)
@ -35,9 +40,11 @@ class ShellTest(utils.BaseTestCase):
def setUp(self):
super(ShellTest, self).setUp()
self.mock_endpoint = self.mock_endpoint_patcher.start()
def tearDown(self):
super(ShellTest, self).tearDown()
self.mock_endpoint_patcher.stop()
def shell(self, argstr):
orig = sys.stdout
@ -100,11 +107,8 @@ class ShellTest(utils.BaseTestCase):
self.test_help()
@mock.patch('cgtsclient.v1.ihost.ihostManager.list')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_host_list(self, mock_get_endpoint, mock_get_client, mock_list):
def test_host_list(self, mock_list):
# This unit test mocks returning a single controller-0 host through host-list
mock_get_endpoint.return_value = 'http://fakelocalhost:6385/v1'
fake_controller = {'id': '0',
'hostname': 'controller-0',
'personality': 'controller',

View File

@ -36,16 +36,6 @@ class ControllerFsTest(test_shell.ShellTest):
def setUp(self):
super(ControllerFsTest, self).setUp()
# Mock the client
p = mock.patch('cgtsclient.client._get_endpoint')
self.mock_cgtsclient_client_get_endpoint = p.start()
self.mock_cgtsclient_client_get_endpoint.return_value = \
'http://fakelocalhost:6385/v1'
self.addCleanup(p.stop)
p = mock.patch('cgtsclient.client._get_ksclient')
self.mock_cgtsclient_client_get_ksclient = p.start()
self.addCleanup(p.stop)
# Mock the ControllerFsManager
self.controller_fs_manager_list_result = [
ControllerFs(None, FAKE_CONTROLLER_FS, True)]

View File

@ -67,16 +67,6 @@ class HostTest(test_shell.ShellTest):
def setUp(self):
super(HostTest, self).setUp()
# Mock the client
p = mock.patch('cgtsclient.client._get_endpoint')
self.mock_cgtsclient_client_get_endpoint = p.start()
self.mock_cgtsclient_client_get_endpoint.return_value = \
'http://fakelocalhost:6385/v1'
self.addCleanup(p.stop)
p = mock.patch('cgtsclient.client._get_ksclient')
self.mock_cgtsclient_client_get_ksclient = p.start()
self.addCleanup(p.stop)
# Mock the KubeHostUpgradeManager
self.kube_host_upgrade_manager_list_result = [
KubeHostUpgrade(None, FAKE_KUBE_HOST_UPGRADE, True)]

View File

@ -131,11 +131,7 @@ class KubeClusterTest(test_shell.ShellTest):
super(KubeClusterTest, self).tearDown()
@mock.patch('cgtsclient.v1.kube_cluster.KubeClusterManager.list')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_cluster_list(self, mock_get_endpoint, mock_get_client,
mock_list):
mock_get_endpoint.return_value = 'http://fakelocalhost:6385/v1'
def test_kube_cluster_list(self, mock_list):
mock_list.return_value = [KubeCluster(None, FAKE_CLUSTER, True)]
self.make_env()
cluster_results = self.shell("kube-cluster-list")
@ -144,11 +140,7 @@ class KubeClusterTest(test_shell.ShellTest):
self.assertIn(FAKE_CLUSTER['cluster_api_endpoint'], cluster_results)
@mock.patch('cgtsclient.v1.kube_cluster.KubeClusterManager.get')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_cluster_show(self, mock_get_endpoint, mock_get_client,
mock_get):
mock_get_endpoint.return_value = 'http://fakelocalhost:6385/v1'
def test_kube_cluster_show(self, mock_get):
mock_get.return_value = KubeCluster(None, FAKE_CLUSTER, True)
self.make_env()
cluster_results = self.shell("kube-cluster-show {}".format(

View File

@ -57,11 +57,7 @@ class KubeRootCAUpdateTest(test_shell.ShellTest):
@mock.patch('cgtsclient.v1.kube_rootca_update.KubeRootCAUpdateManager.create')
@mock.patch('cgtsclient.v1.kube_rootca_update.KubeRootCAUpdateManager.get')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_rootca_update_start(self, mock_get_endpoint, mock_get_client,
mock_get, mock_create):
mock_get_endpoint.return_value = self.mock_get_endpoint_return_value
def test_kube_rootca_update_start(self, mock_get, mock_create):
mock_create.return_value = KubeRootCAUpdate(None, self.fake_kube_rootca_update, True)
mock_get.return_value = KubeRootCAUpdate(None, self.fake_kube_rootca_update, True)
@ -71,11 +67,9 @@ class KubeRootCAUpdateTest(test_shell.ShellTest):
@mock.patch('cgtsclient.v1.kube_rootca_update.KubeRootCAUpdateManager.create')
@mock.patch('cgtsclient.v1.kube_rootca_update.KubeRootCAUpdateManager.get_list')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_rootca_update_show_current_update(self, mock_get_endpoint, mock_get_client,
mock_get_list, mock_create):
mock_get_endpoint.return_value = self.mock_get_endpoint_return_value
def test_kube_rootca_update_show_current_update(self,
mock_get_list,
mock_create):
mock_create.return_value = KubeRootCAUpdate(None, self.fake_kube_rootca_update, True)
mock_get_list.return_value = [KubeRootCAUpdate(None, self.fake_kube_rootca_update, True)]
@ -84,11 +78,7 @@ class KubeRootCAUpdateTest(test_shell.ShellTest):
self._check_rootca_update(self.fake_kube_rootca_update, results)
@mock.patch('cgtsclient.v1.kube_rootca_update.KubeRootCAUpdateManager.host_update_list')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_rootca_update_list_current_update(self, mock_get_endpoint, mock_get_client,
mock_update_list):
mock_get_endpoint.return_value = self.mock_get_endpoint_return_value
def test_kube_rootca_update_list_current_update(self, mock_update_list):
mock_update_list.return_value = [KubeRootCAUpdate(None, self.fake_kube_rootca_host_update, True)]
self.make_env()
results = self.shell("kube-rootca-host-update-list")
@ -98,12 +88,8 @@ class KubeRootCAUpdateTest(test_shell.ShellTest):
@mock.patch('cgtsclient.v1.kube_rootca_update.KubeRootCAUpdateManager.create')
@mock.patch('cgtsclient.v1.kube_rootca_update.KubeRootCAUpdateManager.rootCA_pods_update')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_rootca_pods_update(self, mock_get_endpoint, mock_get_client,
mock_pods_update, mock_create):
def test_kube_rootca_pods_update(self, mock_pods_update, mock_create):
self.fake_kube_rootca_update['state'] = 'updated-host-trust-both-cas'
mock_get_endpoint.return_value = self.mock_get_endpoint_return_value
mock_create.return_value = KubeRootCAUpdate(None, self.fake_kube_rootca_update, True)
self.fake_kube_rootca_update['state'] = 'updating-pods-trust-both-cas'
mock_pods_update.return_value = KubeRootCAUpdate(None, self.fake_kube_rootca_update, True)
@ -115,10 +101,10 @@ class KubeRootCAUpdateTest(test_shell.ShellTest):
@mock.patch('cgtsclient.v1.kube_rootca_update.KubeRootCAUpdateManager.create')
@mock.patch('cgtsclient.v1.ihost.ihostManager.kube_update_rootca')
@mock.patch('cgtsclient.v1.ihost._find_ihost')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_rootca_host_update(self, mock_get_endpoint, mock_get_client,
mock_get_host, mock_host_update, mock_create):
def test_kube_rootca_host_update(self,
mock_get_host,
mock_host_update,
mock_create):
fake_controller = {'id': '0',
'uuid': '1127ea5e-067b-11ec-9a03-0242ac130003',
'hostname': 'fake-hostname',
@ -128,7 +114,6 @@ class KubeRootCAUpdateTest(test_shell.ShellTest):
'availability': 'available'}
self.fake_kube_rootca_host_update['state'] = 'updating-host-trust-both-cas'
mock_get_host.return_value = ihost(None, fake_controller, True)
mock_get_endpoint.return_value = self.mock_get_endpoint_return_value
mock_create.return_value = KubeRootCAUpdate(None, self.fake_kube_rootca_update, True)
mock_host_update.return_value = KubeRootCAUpdate(None, self.fake_kube_rootca_host_update, True)
@ -138,12 +123,10 @@ class KubeRootCAUpdateTest(test_shell.ShellTest):
@mock.patch('cgtsclient.v1.kube_rootca_update.KubeRootCAUpdateManager.create')
@mock.patch('cgtsclient.v1.kube_rootca_update.KubeRootCAUpdateManager.update_complete')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_rootca_update_complete(self, mock_get_endpoint, mock_get_client,
mock_update_complete, mock_create):
def test_kube_rootca_update_complete(self,
mock_update_complete,
mock_create):
self.fake_kube_rootca_update['state'] = 'updated-pods-trust-new-ca'
mock_get_endpoint.return_value = self.mock_get_endpoint_return_value
mock_create.return_value = KubeRootCAUpdate(None, self.fake_kube_rootca_update, True)
self.fake_kube_rootca_update['state'] = 'update-completed'
mock_update_complete.return_value = KubeRootCAUpdate(None, self.fake_kube_rootca_update, True)
@ -154,11 +137,9 @@ class KubeRootCAUpdateTest(test_shell.ShellTest):
@mock.patch('cgtsclient.v1.kube_rootca_update.KubeRootCAUpdateManager.create')
@mock.patch('cgtsclient.v1.kube_rootca_update.KubeRootCAUpdateManager.update_complete')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_rootca_update_abort(self, mock_get_endpoint, mock_get_client,
mock_update_complete, mock_create):
mock_get_endpoint.return_value = self.mock_get_endpoint_return_value
def test_kube_rootca_update_abort(self,
mock_update_complete,
mock_create):
mock_create.return_value = KubeRootCAUpdate(None, self.fake_kube_rootca_update, True)
self.fake_kube_rootca_update['state'] = 'update-aborted'
mock_update_complete.return_value = KubeRootCAUpdate(None, self.fake_kube_rootca_update, True)

View File

@ -19,11 +19,7 @@ class KubeUpgradeTest(test_shell.ShellTest):
super(KubeUpgradeTest, self).tearDown()
@mock.patch('cgtsclient.v1.kube_upgrade.KubeUpgradeManager.list')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_upgrade_show(self, mock_get_endpoint, mock_get_client,
mock_list):
mock_get_endpoint.return_value = 'http://fakelocalhost:6385/v1'
def test_kube_upgrade_show(self, mock_list):
fake_kube_upgrade = {'from_version': 'v1.42.1',
'to_version': 'v1.42.2',
'state': 'upgrade-started',
@ -45,11 +41,7 @@ class KubeUpgradeTest(test_shell.ShellTest):
@mock.patch('cgtsclient.v1.kube_upgrade.KubeUpgradeManager.create')
@mock.patch('cgtsclient.v1.kube_upgrade.KubeUpgradeManager.get')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_upgrade_start(self, mock_get_endpoint, mock_get_client,
mock_get, mock_create):
mock_get_endpoint.return_value = 'http://fakelocalhost:6385/v1'
def test_kube_upgrade_start(self, mock_get, mock_create):
fake_kube_upgrade = {'from_version': 'v1.42.1',
'to_version': 'v1.42.2',
'state': 'upgrade-started',
@ -72,11 +64,7 @@ class KubeUpgradeTest(test_shell.ShellTest):
@mock.patch('cgtsclient.v1.kube_upgrade.KubeUpgradeManager.create')
@mock.patch('cgtsclient.v1.kube_upgrade.KubeUpgradeManager.get')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_upgrade_start_force(self, mock_get_endpoint, mock_get_client,
mock_get, mock_create):
mock_get_endpoint.return_value = 'http://fakelocalhost:6385/v1'
def test_kube_upgrade_start_force(self, mock_get, mock_create):
fake_kube_upgrade = {'from_version': 'v1.42.1',
'to_version': 'v1.42.2',
'state': 'upgrade-started',
@ -98,12 +86,7 @@ class KubeUpgradeTest(test_shell.ShellTest):
self.assertIn(fake_kube_upgrade['updated_at'], results)
@mock.patch('cgtsclient.v1.kube_upgrade.KubeUpgradeManager.update')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_upgrade_download_images(self, mock_get_endpoint,
mock_get_client,
mock_update):
mock_get_endpoint.return_value = 'http://fakelocalhost:6385/v1'
def test_kube_upgrade_download_images(self, mock_update):
fake_kube_upgrade = {'from_version': 'v1.42.1',
'to_version': 'v1.42.2',
'state': 'downloading-images',
@ -123,11 +106,7 @@ class KubeUpgradeTest(test_shell.ShellTest):
self.assertIn(fake_kube_upgrade['updated_at'], results)
@mock.patch('cgtsclient.v1.kube_upgrade.KubeUpgradeManager.update')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_upgrade_networking(self, mock_get_endpoint, mock_get_client,
mock_update):
mock_get_endpoint.return_value = 'http://fakelocalhost:6385/v1'
def test_kube_upgrade_networking(self, mock_update):
fake_kube_upgrade = {'from_version': 'v1.42.1',
'to_version': 'v1.42.2',
'state': 'upgrading-networking',
@ -147,11 +126,7 @@ class KubeUpgradeTest(test_shell.ShellTest):
self.assertIn(fake_kube_upgrade['updated_at'], results)
@mock.patch('cgtsclient.v1.kube_upgrade.KubeUpgradeManager.update')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_upgrade_complete(self, mock_get_endpoint, mock_get_client,
mock_update):
mock_get_endpoint.return_value = 'http://fakelocalhost:6385/v1'
def test_kube_upgrade_complete(self, mock_update):
fake_kube_upgrade = {'from_version': 'v1.42.1',
'to_version': 'v1.42.2',
'state': 'upgrade-complete',
@ -171,12 +146,7 @@ class KubeUpgradeTest(test_shell.ShellTest):
self.assertIn(fake_kube_upgrade['updated_at'], results)
@mock.patch('cgtsclient.v1.kube_upgrade.KubeUpgradeManager.delete')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_upgrade_delete(self, mock_get_endpoint, mock_get_client,
mock_delete):
mock_get_endpoint.return_value = 'http://fakelocalhost:6385/v1'
def test_kube_upgrade_delete(self, mock_delete):
self.make_env()
results = self.shell("kube-upgrade-delete")
self.assertIn("Kubernetes upgrade deleted", results)

View File

@ -19,11 +19,7 @@ class KubeVersionTest(test_shell.ShellTest):
super(KubeVersionTest, self).tearDown()
@mock.patch('cgtsclient.v1.kube_version.KubeVersionManager.list')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_version_list(self, mock_get_endpoint, mock_get_client,
mock_list):
mock_get_endpoint.return_value = 'http://fakelocalhost:6385/v1'
def test_kube_version_list(self, mock_list):
fake_version = {'version': 'v1.42.2',
'upgrade_from': ['v1.42.1'],
'downgrade_to': [],
@ -46,11 +42,7 @@ class KubeVersionTest(test_shell.ShellTest):
version_results)
@mock.patch('cgtsclient.v1.kube_version.KubeVersionManager.get')
@mock.patch('cgtsclient.client._get_ksclient')
@mock.patch('cgtsclient.client._get_endpoint')
def test_kube_version_show(self, mock_get_endpoint, mock_get_client,
mock_get):
mock_get_endpoint.return_value = 'http://fakelocalhost:6385/v1'
def test_kube_version_show(self, mock_get):
fake_version = {'version': 'v1.42.2',
'upgrade_from': ['v1.42.1'],
'downgrade_to': [],

View File

@ -92,7 +92,7 @@ from cgtsclient.v1 import storage_tier
from cgtsclient.v1 import upgrade
class Client(http.HTTPClient):
class Client(object):
"""Client for the Cgts v1 API.
:param string endpoint: A user-supplied endpoint URL for the cgts
@ -104,80 +104,80 @@ class Client(http.HTTPClient):
def __init__(self, *args, **kwargs):
"""Initialize a new client for the Cgts v1 API."""
super(Client, self).__init__(*args, **kwargs)
self.smapi_endpoint = kwargs.get('smapi_endpoint')
super(Client, self).__init__()
self.http_client = http.construct_http_client(*args, **kwargs)
self.isystem = isystem.isystemManager(self)
self.ihost = ihost.ihostManager(self)
self.inode = inode.inodeManager(self)
self.icpu = icpu.icpuManager(self)
self.imemory = imemory.imemoryManager(self)
self.iinterface = iinterface.iinterfaceManager(self)
self.idisk = idisk.idiskManager(self)
self.istor = istor.istorManager(self)
self.ipv = ipv.ipvManager(self)
self.ilvg = ilvg.ilvgManager(self)
self.iuser = iuser.iuserManager(self)
self.idns = idns.idnsManager(self)
self.intp = intp.intpManager(self)
self.ptp = ptp.ptpManager(self)
self.ptp_instance = ptp_instance.PtpInstanceManager(self)
self.ptp_interface = ptp_interface.PtpInterfaceManager(self)
self.ptp_parameter = ptp_parameter.PtpParameterManager(self)
self.iextoam = iextoam.iextoamManager(self)
self.controller_fs = controller_fs.ControllerFsManager(self)
self.storage_backend = storage_backend.StorageBackendManager(self)
self.storage_lvm = storage_lvm.StorageLvmManager(self)
self.storage_file = storage_file.StorageFileManager(self)
self.storage_external = storage_external.StorageExternalManager(self)
self.storage_ceph = storage_ceph.StorageCephManager(self)
self.storage_ceph_rook = storage_ceph_rook.StorageCephRookManager(self)
self.ceph_mon = ceph_mon.CephMonManager(self)
self.drbdconfig = drbdconfig.drbdconfigManager(self)
self.port = port.PortManager(self)
self.ethernet_port = ethernetport.EthernetPortManager(self)
self.address = address.AddressManager(self)
self.address_pool = address_pool.AddressPoolManager(self)
self.route = route.RouteManager(self)
self.isensor = isensor.isensorManager(self)
self.isensorgroup = isensorgroup.isensorgroupManager(self)
self.pci_device = pci_device.PciDeviceManager(self)
self.load = load.LoadManager(self)
self.upgrade = upgrade.UpgradeManager(self)
self.network = network.NetworkManager(self)
self.datanetwork = datanetwork.DataNetworkManager(self)
self.isystem = isystem.isystemManager(self.http_client)
self.ihost = ihost.ihostManager(self.http_client)
self.inode = inode.inodeManager(self.http_client)
self.icpu = icpu.icpuManager(self.http_client)
self.imemory = imemory.imemoryManager(self.http_client)
self.iinterface = iinterface.iinterfaceManager(self.http_client)
self.idisk = idisk.idiskManager(self.http_client)
self.istor = istor.istorManager(self.http_client)
self.ipv = ipv.ipvManager(self.http_client)
self.ilvg = ilvg.ilvgManager(self.http_client)
self.iuser = iuser.iuserManager(self.http_client)
self.idns = idns.idnsManager(self.http_client)
self.intp = intp.intpManager(self.http_client)
self.ptp = ptp.ptpManager(self.http_client)
self.ptp_instance = ptp_instance.PtpInstanceManager(self.http_client)
self.ptp_interface = ptp_interface.PtpInterfaceManager(self.http_client)
self.ptp_parameter = ptp_parameter.PtpParameterManager(self.http_client)
self.iextoam = iextoam.iextoamManager(self.http_client)
self.controller_fs = controller_fs.ControllerFsManager(self.http_client)
self.storage_backend = storage_backend.StorageBackendManager(self.http_client)
self.storage_lvm = storage_lvm.StorageLvmManager(self.http_client)
self.storage_file = storage_file.StorageFileManager(self.http_client)
self.storage_external = storage_external.StorageExternalManager(self.http_client)
self.storage_ceph = storage_ceph.StorageCephManager(self.http_client)
self.storage_ceph_rook = storage_ceph_rook.StorageCephRookManager(self.http_client)
self.ceph_mon = ceph_mon.CephMonManager(self.http_client)
self.drbdconfig = drbdconfig.drbdconfigManager(self.http_client)
self.port = port.PortManager(self.http_client)
self.ethernet_port = ethernetport.EthernetPortManager(self.http_client)
self.address = address.AddressManager(self.http_client)
self.address_pool = address_pool.AddressPoolManager(self.http_client)
self.route = route.RouteManager(self.http_client)
self.isensor = isensor.isensorManager(self.http_client)
self.isensorgroup = isensorgroup.isensorgroupManager(self.http_client)
self.pci_device = pci_device.PciDeviceManager(self.http_client)
self.load = load.LoadManager(self.http_client)
self.upgrade = upgrade.UpgradeManager(self.http_client)
self.network = network.NetworkManager(self.http_client)
self.datanetwork = datanetwork.DataNetworkManager(self.http_client)
self.interface_datanetwork = \
interface_datanetwork.InterfaceDataNetworkManager(self)
self.interface_network = interface_network.InterfaceNetworkManager(self)
self.service_parameter = service_parameter.ServiceParameterManager(self)
self.cluster = cluster.ClusterManager(self)
self.lldp_agent = lldp_agent.LldpAgentManager(self)
self.lldp_neighbour = lldp_neighbour.LldpNeighbourManager(self)
self.sm_service_nodes = sm_service_nodes.SmNodesManager(self)
self.sm_service = sm_service.SmServiceManager(self)
self.sm_servicegroup = sm_servicegroup.SmServiceGroupManager(self)
self.health = health.HealthManager(self)
self.registry_image = registry_image.RegistryImageManager(self)
self.remotelogging = remotelogging.RemoteLoggingManager(self)
self.sdn_controller = sdn_controller.SDNControllerManager(self)
self.partition = partition.partitionManager(self)
self.license = license.LicenseManager(self)
self.certificate = certificate.CertificateManager(self)
self.storage_tier = storage_tier.StorageTierManager(self)
interface_datanetwork.InterfaceDataNetworkManager(self.http_client)
self.interface_network = interface_network.InterfaceNetworkManager(self.http_client)
self.service_parameter = service_parameter.ServiceParameterManager(self.http_client)
self.cluster = cluster.ClusterManager(self.http_client)
self.lldp_agent = lldp_agent.LldpAgentManager(self.http_client)
self.lldp_neighbour = lldp_neighbour.LldpNeighbourManager(self.http_client)
self.sm_service_nodes = sm_service_nodes.SmNodesManager(self.http_client)
self.sm_service = sm_service.SmServiceManager(self.http_client)
self.sm_servicegroup = sm_servicegroup.SmServiceGroupManager(self.http_client)
self.health = health.HealthManager(self.http_client)
self.registry_image = registry_image.RegistryImageManager(self.http_client)
self.remotelogging = remotelogging.RemoteLoggingManager(self.http_client)
self.sdn_controller = sdn_controller.SDNControllerManager(self.http_client)
self.partition = partition.partitionManager(self.http_client)
self.license = license.LicenseManager(self.http_client)
self.certificate = certificate.CertificateManager(self.http_client)
self.storage_tier = storage_tier.StorageTierManager(self.http_client)
self.storage_ceph_external = \
storage_ceph_external.StorageCephExternalManager(self)
self.helm = helm.HelmManager(self)
self.label = label.KubernetesLabelManager(self)
self.fernet = fernet.FernetManager(self)
self.app = app.AppManager(self)
self.host_fs = host_fs.HostFsManager(self)
self.kube_cluster = kube_cluster.KubeClusterManager(self)
self.kube_version = kube_version.KubeVersionManager(self)
self.kube_cmd_version = kube_cmd_version.KubeCmdVersionManager(self)
self.kube_upgrade = kube_upgrade.KubeUpgradeManager(self)
self.kube_host_upgrade = kube_host_upgrade.KubeHostUpgradeManager(self)
self.device_image = device_image.DeviceImageManager(self)
self.device_image_state = device_image_state.DeviceImageStateManager(self)
self.device_label = device_label.DeviceLabelManager(self)
self.restore = restore.RestoreManager(self)
self.kube_rootca_update = kube_rootca_update.KubeRootCAUpdateManager(self)
storage_ceph_external.StorageCephExternalManager(self.http_client)
self.helm = helm.HelmManager(self.http_client)
self.label = label.KubernetesLabelManager(self.http_client)
self.fernet = fernet.FernetManager(self.http_client)
self.app = app.AppManager(self.http_client)
self.host_fs = host_fs.HostFsManager(self.http_client)
self.kube_cluster = kube_cluster.KubeClusterManager(self.http_client)
self.kube_version = kube_version.KubeVersionManager(self.http_client)
self.kube_cmd_version = kube_cmd_version.KubeCmdVersionManager(self.http_client)
self.kube_upgrade = kube_upgrade.KubeUpgradeManager(self.http_client)
self.kube_host_upgrade = kube_host_upgrade.KubeHostUpgradeManager(self.http_client)
self.device_image = device_image.DeviceImageManager(self.http_client)
self.device_image_state = device_image_state.DeviceImageStateManager(self.http_client)
self.device_label = device_label.DeviceLabelManager(self.http_client)
self.restore = restore.RestoreManager(self.http_client)
self.kube_rootca_update = kube_rootca_update.KubeRootCAUpdateManager(self.http_client)

View File

@ -4,6 +4,8 @@
# Newer hacking already pins down pep8, pyflakes and flake8
flake8<3.8.0
astroid<2.0;python_version<"3.0" # GPLv2
astroid<= 2.2.5;python_version>="3.0" # GPLv2
pycodestyle<2.6.0 # MIT License
hacking>=1.1.0,<=2.0.0 # Apache-2.0
coverage!=4.4,>=4.0 # Apache-2.0

View File

@ -118,10 +118,6 @@ ignore = H102,H104,H105,H238,H404,H405,
[testenv:pylint]
basepython = python3
deps = {[testenv]deps}
pylint
commands = pylint {posargs} cgtsclient --rcfile=./pylint.rc --extension-pkg-whitelist=lxml.etree,greenlet
[testenv:bindep]