Merge "Remove APIClient singleton from fuelclient library"

This commit is contained in:
Jenkins
2016-05-04 12:06:54 +00:00
committed by Gerrit Code Review
18 changed files with 171 additions and 89 deletions

View File

@@ -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))

View File

@@ -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
"""

View File

@@ -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')

View 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))

View File

@@ -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()

View File

@@ -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)

View File

@@ -27,5 +27,5 @@ class DeploymentHistoryClient(base_v1.BaseV1Client):
statuses=statuses)
def get_client():
return DeploymentHistoryClient()
def get_client(connection):
return DeploymentHistoryClient(connection)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -46,5 +46,5 @@ class NetworkGroupClient(base_v1.BaseV1Client):
env_obj.delete()
def get_client():
return NetworkGroupClient()
def get_client(connection):
return NetworkGroupClient(connection)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)