Merge "Remove APIClient singleton from fuelclient library"
This commit is contained in:
@@ -26,7 +26,17 @@ except ImportError:
|
||||
__version__ = ""
|
||||
|
||||
|
||||
def get_client(resource, version='v1'):
|
||||
def connect(host, port, http_proxy=None, os_username=None, os_password=None,
|
||||
os_tenant_name=None, debug=False):
|
||||
"""Creates API connection."""
|
||||
from fuelclient import client
|
||||
|
||||
return client.Client(
|
||||
host, port, http_proxy=http_proxy, os_username=os_username,
|
||||
os_password=os_password, os_tenant_name=os_tenant_name, debug=debug)
|
||||
|
||||
|
||||
def get_client(resource, version='v1', connection=None):
|
||||
"""Gets an API client for a resource
|
||||
|
||||
python-fuelclient provides access to Fuel's API
|
||||
@@ -40,6 +50,8 @@ def get_client(resource, version='v1'):
|
||||
:param version: Version of the Fuel's API
|
||||
:type version: str,
|
||||
Available: v1. Default: v1.
|
||||
:param connection: API connection
|
||||
:type connection: fuelclient.client.Client
|
||||
:return: Facade to the specified resource that wraps
|
||||
calls to the specified version of the API.
|
||||
|
||||
@@ -65,7 +77,7 @@ def get_client(resource, version='v1'):
|
||||
}
|
||||
|
||||
try:
|
||||
return version_map[version][resource].get_client()
|
||||
return version_map[version][resource].get_client(connection)
|
||||
except KeyError:
|
||||
msg = 'Cannot load API client for "{r}" in the API version "{v}".'
|
||||
raise ValueError(msg.format(r=resource, v=version))
|
||||
|
||||
@@ -34,20 +34,40 @@ class Client(object):
|
||||
"""This class handles API requests
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
conf = fuelclient_settings.get_settings()
|
||||
def __init__(self, host, port, http_proxy=None, http_timeout=None,
|
||||
os_username=None, os_password=None,
|
||||
os_tenant_name=None, debug=False):
|
||||
self.debug = debug
|
||||
|
||||
self.debug = False
|
||||
self.root = "http://{server}:{port}".format(server=conf.SERVER_ADDRESS,
|
||||
port=conf.SERVER_PORT)
|
||||
self._http_proxy = http_proxy
|
||||
self._http_timeout = http_timeout
|
||||
self._os_username = os_username
|
||||
self._os_password = os_password
|
||||
self._os_tenant_name = os_tenant_name
|
||||
|
||||
self.root = "http://{host}:{port}".format(host=host, port=port)
|
||||
|
||||
self.keystone_base = urlparse.urljoin(self.root, "/keystone/v2.0")
|
||||
self.api_root = urlparse.urljoin(self.root, "/api/v1/")
|
||||
self.ostf_root = urlparse.urljoin(self.root, "/ostf/")
|
||||
|
||||
self._keystone_client = None
|
||||
self._auth_required = None
|
||||
self._session = None
|
||||
|
||||
@classmethod
|
||||
def default_client(cls):
|
||||
conf = fuelclient_settings.get_settings()
|
||||
return cls(
|
||||
host=conf.SERVER_ADDRESS,
|
||||
port=conf.SERVER_PORT,
|
||||
http_proxy=conf.HTTP_PROXY,
|
||||
http_timeout=conf.HTTP_TIMEOUT,
|
||||
os_username=conf.OS_USERNAME,
|
||||
os_password=conf.OS_PASSWORD,
|
||||
os_tenant_name=conf.OS_TENANT_NAME
|
||||
)
|
||||
|
||||
def _make_common_headers(self):
|
||||
"""Returns a dict of HTTP headers common for all requests."""
|
||||
|
||||
@@ -57,23 +77,17 @@ class Client(object):
|
||||
|
||||
def _make_proxies(self):
|
||||
"""Provides HTTP proxy configuration for requests module."""
|
||||
|
||||
conf = fuelclient_settings.get_settings()
|
||||
|
||||
if conf.HTTP_PROXY is None:
|
||||
if self._http_proxy is None:
|
||||
return None
|
||||
|
||||
return {'http': conf.HTTP_PROXY,
|
||||
'https': conf.HTTP_PROXY}
|
||||
return {'http': self._http_proxy,
|
||||
'https': self._http_proxy}
|
||||
|
||||
def _make_session(self):
|
||||
"""Initializes a HTTP session."""
|
||||
|
||||
conf = fuelclient_settings.get_settings()
|
||||
|
||||
session = requests.Session()
|
||||
session.headers.update(self._make_common_headers())
|
||||
session.timeout = conf.HTTP_TIMEOUT
|
||||
session.timeout = self._http_timeout
|
||||
session.proxies = self._make_proxies()
|
||||
|
||||
return session
|
||||
@@ -119,21 +133,17 @@ class Client(object):
|
||||
return self._keystone_client
|
||||
|
||||
def update_own_password(self, new_pass):
|
||||
conf = fuelclient_settings.get_settings()
|
||||
|
||||
if self.auth_token:
|
||||
self.keystone_client.users.update_own_password(conf.OS_PASSWORD,
|
||||
new_pass)
|
||||
self.keystone_client.users.update_own_password(
|
||||
self._os_password, new_pass)
|
||||
|
||||
def initialize_keystone_client(self):
|
||||
conf = fuelclient_settings.get_settings()
|
||||
|
||||
if self.auth_required:
|
||||
self._keystone_client = auth_client.Client(
|
||||
auth_url=self.keystone_base,
|
||||
username=conf.OS_USERNAME,
|
||||
password=conf.OS_PASSWORD,
|
||||
tenant_name=conf.OS_TENANT_NAME)
|
||||
username=self._os_username,
|
||||
password=self._os_password,
|
||||
tenant_name=self._os_tenant_name)
|
||||
|
||||
self._keystone_client.session.auth = self._keystone_client
|
||||
self._keystone_client.authenticate()
|
||||
@@ -233,4 +243,7 @@ class Client(object):
|
||||
|
||||
# This line is single point of instantiation for 'Client' class,
|
||||
# which intended to implement Singleton design pattern.
|
||||
APIClient = Client()
|
||||
APIClient = Client.default_client()
|
||||
"""
|
||||
.. deprecated:: Use fuelclient.client.Client instead
|
||||
"""
|
||||
|
||||
@@ -239,4 +239,4 @@ class TestUtils(base.UnitTestCase):
|
||||
|
||||
with self.assertRaisesRegexp(error.HTTPError,
|
||||
'403.*{}'.format(text)):
|
||||
client.Client().post_request('address')
|
||||
client.APIClient.post_request('address')
|
||||
|
||||
54
fuelclient/tests/unit/v2/lib/test_client.py
Normal file
54
fuelclient/tests/unit/v2/lib/test_client.py
Normal file
@@ -0,0 +1,54 @@
|
||||
#
|
||||
# Copyright 2016 Mirantis, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import fuelclient
|
||||
from fuelclient.objects import base
|
||||
from fuelclient.tests.unit.v2.lib import test_api
|
||||
from fuelclient.v1 import base_v1
|
||||
|
||||
|
||||
class FakeObject(base.BaseObject):
|
||||
class_api_path = 'fake/objects/'
|
||||
|
||||
|
||||
class FakeClient(base_v1.BaseV1Client):
|
||||
|
||||
_entity_wrapper = FakeObject
|
||||
|
||||
|
||||
class TestClient(test_api.BaseLibTest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestClient, self).setUp()
|
||||
|
||||
self.host = 'test.host.tld'
|
||||
self.port = 8888
|
||||
|
||||
self.connection = fuelclient.connect(self.host, self.port)
|
||||
|
||||
self.client = FakeClient(connection=self.connection)
|
||||
|
||||
self.version = 'v1'
|
||||
self.res_uri = '/api/{version}/fake/objects/'.format(
|
||||
version=self.version)
|
||||
|
||||
def test_custom_connection_used(self):
|
||||
m_get = self.m_request.get(self.res_uri, json={})
|
||||
self.client.get_all()
|
||||
|
||||
self.assertTrue(m_get.called)
|
||||
self.assertEqual(
|
||||
m_get.last_request.netloc,
|
||||
'{host}:{port}'.format(host=self.host, port=self.port))
|
||||
@@ -16,6 +16,8 @@ import abc
|
||||
|
||||
import six
|
||||
|
||||
from fuelclient import client
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class BaseV1Client(object):
|
||||
@@ -24,6 +26,18 @@ class BaseV1Client(object):
|
||||
def _entity_wrapper(self):
|
||||
pass
|
||||
|
||||
def __init__(self, connection=None):
|
||||
if connection is None:
|
||||
connection = client.APIClient
|
||||
self.connection = connection
|
||||
|
||||
cls_wrapper = self.__class__._entity_wrapper
|
||||
self._entity_wrapper = type(
|
||||
cls_wrapper.__name__,
|
||||
(cls_wrapper, ),
|
||||
{'connection': self.connection}
|
||||
)
|
||||
|
||||
def get_all(self):
|
||||
result = self._entity_wrapper.get_all_data()
|
||||
|
||||
|
||||
@@ -27,5 +27,5 @@ class ClusterSettingsClient(base_v1.BaseV1Client):
|
||||
return task.cluster_settings()
|
||||
|
||||
|
||||
def get_client():
|
||||
return ClusterSettingsClient()
|
||||
def get_client(connection):
|
||||
return ClusterSettingsClient(connection)
|
||||
|
||||
@@ -27,5 +27,5 @@ class DeploymentHistoryClient(base_v1.BaseV1Client):
|
||||
statuses=statuses)
|
||||
|
||||
|
||||
def get_client():
|
||||
return DeploymentHistoryClient()
|
||||
def get_client(connection):
|
||||
return DeploymentHistoryClient(connection)
|
||||
|
||||
@@ -27,5 +27,5 @@ class DeploymentInfoClient(base_v1.BaseV1Client):
|
||||
return task.deployment_info()
|
||||
|
||||
|
||||
def get_client():
|
||||
return DeploymentInfoClient()
|
||||
def get_client(connection):
|
||||
return DeploymentInfoClient(connection)
|
||||
|
||||
@@ -105,5 +105,5 @@ class EnvironmentClient(base_v1.BaseV1Client):
|
||||
env.delete_network_template_data()
|
||||
|
||||
|
||||
def get_client():
|
||||
return EnvironmentClient()
|
||||
def get_client(connection):
|
||||
return EnvironmentClient(connection)
|
||||
|
||||
@@ -21,5 +21,5 @@ class FuelVersionClient(base_v1.BaseV1Client):
|
||||
_entity_wrapper = objects.FuelVersion
|
||||
|
||||
|
||||
def get_client():
|
||||
return FuelVersionClient()
|
||||
def get_client(connection):
|
||||
return FuelVersionClient(connection)
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
# under the License.
|
||||
|
||||
from fuelclient.cli import error
|
||||
from fuelclient.client import APIClient
|
||||
from fuelclient import objects
|
||||
from fuelclient.v1 import base_v1
|
||||
|
||||
@@ -40,33 +39,30 @@ class GraphClient(base_v1.BaseV1Client):
|
||||
cluster_release_tasks_api_path = "clusters/{env_id}/deployment_tasks" \
|
||||
"/release/?graph_type={graph_type}"
|
||||
|
||||
@classmethod
|
||||
def update_graph_for_model(
|
||||
cls, data, related_model, related_model_id, graph_type=None):
|
||||
return APIClient.put_request(
|
||||
cls.related_graph_api_path.format(
|
||||
self, data, related_model, related_model_id, graph_type=None):
|
||||
return self.connection.put_request(
|
||||
self.related_graph_api_path.format(
|
||||
related_model=related_model,
|
||||
related_model_id=related_model_id,
|
||||
graph_type=graph_type or ""),
|
||||
data
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def create_graph_for_model(
|
||||
cls, data, related_model, related_model_id, graph_type=None):
|
||||
return APIClient.post_request(
|
||||
cls.related_graph_api_path.format(
|
||||
self, data, related_model, related_model_id, graph_type=None):
|
||||
return self.connection.post_request(
|
||||
self.related_graph_api_path.format(
|
||||
related_model=related_model,
|
||||
related_model_id=related_model_id,
|
||||
graph_type=graph_type or ""),
|
||||
data
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_graph_for_model(
|
||||
cls, related_model, related_model_id, graph_type=None):
|
||||
return APIClient.get_request(
|
||||
cls.related_graph_api_path.format(
|
||||
self, related_model, related_model_id, graph_type=None):
|
||||
return self.connection.get_request(
|
||||
self.related_graph_api_path.format(
|
||||
related_model=related_model,
|
||||
related_model_id=related_model_id,
|
||||
graph_type=graph_type or ""))
|
||||
@@ -83,8 +79,7 @@ class GraphClient(base_v1.BaseV1Client):
|
||||
self.create_graph_for_model(
|
||||
{'tasks': data}, related_model, related_id, graph_type)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, env_id, nodes, graph_type=None):
|
||||
def execute(self, env_id, nodes, graph_type=None):
|
||||
put_args = []
|
||||
|
||||
if nodes:
|
||||
@@ -94,32 +89,28 @@ class GraphClient(base_v1.BaseV1Client):
|
||||
put_args.append(("graph_type=" + graph_type))
|
||||
|
||||
url = "".join([
|
||||
cls.cluster_deploy_api_path.format(env_id=env_id),
|
||||
self.cluster_deploy_api_path.format(env_id=env_id),
|
||||
'?',
|
||||
'&'.join(put_args)])
|
||||
|
||||
deploy_data = APIClient.put_request(url, {})
|
||||
deploy_data = self.connection.put_request(url, {})
|
||||
return objects.DeployTask.init_with_data(deploy_data)
|
||||
|
||||
# download
|
||||
@classmethod
|
||||
def get_merged_cluster_tasks(cls, env_id, graph_type=None):
|
||||
return APIClient.get_request(
|
||||
cls.merged_cluster_tasks_api_path.format(
|
||||
def get_merged_cluster_tasks(self, env_id, graph_type=None):
|
||||
return self.connection.get_request(
|
||||
self.merged_cluster_tasks_api_path.format(
|
||||
env_id=env_id,
|
||||
graph_type=graph_type or ""))
|
||||
|
||||
@classmethod
|
||||
def get_merged_plugins_tasks(cls, env_id, graph_type=None):
|
||||
return APIClient.get_request(
|
||||
cls.merged_plugins_tasks_api_path.format(
|
||||
def get_merged_plugins_tasks(self, env_id, graph_type=None):
|
||||
return self.connection.get_request(
|
||||
self.merged_plugins_tasks_api_path.format(
|
||||
env_id=env_id,
|
||||
graph_type=graph_type or ""))
|
||||
|
||||
@classmethod
|
||||
def get_release_tasks_for_cluster(cls, env_id, graph_type=None):
|
||||
return APIClient.get_request(
|
||||
cls.merged_plugins_tasks_api_path.format(
|
||||
def get_release_tasks_for_cluster(self, env_id, graph_type=None):
|
||||
return self.connection.get_request(
|
||||
self.merged_plugins_tasks_api_path.format(
|
||||
env_id=env_id,
|
||||
graph_type=graph_type or ""))
|
||||
|
||||
@@ -143,15 +134,13 @@ class GraphClient(base_v1.BaseV1Client):
|
||||
}
|
||||
return tasks_levels[level]()
|
||||
|
||||
# list
|
||||
@classmethod
|
||||
def list(cls, env_id):
|
||||
def list(self, env_id):
|
||||
# todo(ikutukov): extend lists to support all models
|
||||
return APIClient.get_request(
|
||||
cls.related_graphs_list_api_path.format(
|
||||
return self.connection.get_request(
|
||||
self.related_graphs_list_api_path.format(
|
||||
related_model='clusters',
|
||||
related_model_id=env_id))
|
||||
|
||||
|
||||
def get_client():
|
||||
return GraphClient()
|
||||
def get_client(connection):
|
||||
return GraphClient(connection)
|
||||
|
||||
@@ -27,5 +27,5 @@ class NetworkConfigurationClient(base_v1.BaseV1Client):
|
||||
return task.network_configuration()
|
||||
|
||||
|
||||
def get_client():
|
||||
return NetworkConfigurationClient()
|
||||
def get_client(connection):
|
||||
return NetworkConfigurationClient(connection)
|
||||
|
||||
@@ -46,5 +46,5 @@ class NetworkGroupClient(base_v1.BaseV1Client):
|
||||
env_obj.delete()
|
||||
|
||||
|
||||
def get_client():
|
||||
return NetworkGroupClient()
|
||||
def get_client(connection):
|
||||
return NetworkGroupClient(connection)
|
||||
|
||||
@@ -213,5 +213,5 @@ class NodeClient(base_v1.BaseV1Client):
|
||||
return SplittedLabel(name, value, bool(separator))
|
||||
|
||||
|
||||
def get_client():
|
||||
return NodeClient()
|
||||
def get_client(connection):
|
||||
return NodeClient(connection)
|
||||
|
||||
@@ -46,5 +46,5 @@ class OpenstackConfigClient(base_v1.BaseV1Client):
|
||||
node_role=node_role, is_active=is_active)
|
||||
|
||||
|
||||
def get_client():
|
||||
return OpenstackConfigClient()
|
||||
def get_client(connection):
|
||||
return OpenstackConfigClient(connection)
|
||||
|
||||
@@ -54,5 +54,5 @@ class PluginsClient(base_v1.BaseV1Client):
|
||||
self._entity_wrapper.sync(plugin_ids=ids)
|
||||
|
||||
|
||||
def get_client():
|
||||
return PluginsClient()
|
||||
def get_client(connection):
|
||||
return PluginsClient(connection)
|
||||
|
||||
@@ -21,5 +21,5 @@ class TaskClient(base_v1.BaseV1Client):
|
||||
_entity_wrapper = objects.Task
|
||||
|
||||
|
||||
def get_client():
|
||||
return TaskClient()
|
||||
def get_client(connection):
|
||||
return TaskClient(connection)
|
||||
|
||||
@@ -50,5 +50,5 @@ class VipClient(base_v1.BaseV1Client):
|
||||
env.set_vips_data(vips_data)
|
||||
|
||||
|
||||
def get_client():
|
||||
return VipClient()
|
||||
def get_client(connection):
|
||||
return VipClient(connection)
|
||||
|
||||
Reference in New Issue
Block a user