Start to make placement client

This patch starts to prepare base methods for placement client
in a new class, ``BlazarPlacementClient``.

Change-Id: I58712bd9dd243daed0e616792e0ba11b80cd680b
Blueprint: placement-api
This commit is contained in:
Tetsuro Nakamura 2018-06-19 23:13:34 +09:00
parent c31dd15ac2
commit c86e2414b0
4 changed files with 227 additions and 0 deletions

View File

@ -0,0 +1,39 @@
# 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.
"""Fakes relating to the `requests` module."""
import requests
class FakeResponse(requests.Response):
def __init__(self, status_code, content=None, headers=None):
"""A requests.Response that can be used as a mock return_value.
A key feature is that the instance will evaluate to True or False like
a real Response, based on the status_code.
Properties like ok, status_code, text, and content, and methods like
json(), work as expected based on the inputs.
:param status_code: Integer HTTP response code (200, 404, etc.)
:param content: String supplying the payload content of the response.
Using a json-encoded string will make the json() method
behave as expected.
:param headers: Dict of HTTP header values to set.
"""
super(FakeResponse, self).__init__()
self.status_code = status_code
if content:
self._content = content.encode('utf-8')
self.encoding = 'utf-8'
if headers:
self.headers = headers

View File

@ -0,0 +1,93 @@
# 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 mock
from blazar import tests
from blazar.tests import fake_requests
from blazar.utils.openstack import placement
from oslo_config import cfg
from oslo_config import fixture as conf_fixture
CONF = cfg.CONF
PLACEMENT_MICROVERSION = 1.29
class TestPlacementClient(tests.TestCase):
def setUp(self):
super(TestPlacementClient, self).setUp()
self.cfg = self.useFixture(conf_fixture.Config(CONF))
self.cfg.config(os_auth_host='foofoo')
self.cfg.config(os_auth_port='8080')
self.cfg.config(os_auth_prefix='identity')
self.cfg.config(os_auth_version='v3')
self.client = placement.BlazarPlacementClient()
def test_client_auth_url(self):
self.assertEqual("http://foofoo:8080/identity/v3",
self.client._client.session.auth.auth_url)
@mock.patch('keystoneauth1.session.Session.request')
def test_get(self, kss_req):
kss_req.return_value = fake_requests.FakeResponse(200)
url = '/resource_providers'
resp = self.client.get(url)
self.assertEqual(200, resp.status_code)
kss_req.assert_called_once_with(
url, 'GET',
endpoint_filter={'service_type': 'placement',
'interface': 'public'},
headers={'accept': 'application/json'},
microversion=PLACEMENT_MICROVERSION, raise_exc=False)
@mock.patch('keystoneauth1.session.Session.request')
def test_post(self, kss_req):
kss_req.return_value = fake_requests.FakeResponse(200)
url = '/resource_providers'
data = {'name': 'unicorn'}
resp = self.client.post(url, data)
self.assertEqual(200, resp.status_code)
kss_req.assert_called_once_with(
url, 'POST', json=data,
endpoint_filter={'service_type': 'placement',
'interface': 'public'},
headers={'accept': 'application/json'},
microversion=PLACEMENT_MICROVERSION, raise_exc=False)
@mock.patch('keystoneauth1.session.Session.request')
def test_put(self, kss_req):
kss_req.return_value = fake_requests.FakeResponse(200)
url = '/resource_providers'
data = {'name': 'unicorn'}
resp = self.client.put(url, data)
self.assertEqual(200, resp.status_code)
kss_req.assert_called_once_with(
url, 'PUT', json=data,
endpoint_filter={'service_type': 'placement',
'interface': 'public'},
headers={'accept': 'application/json'},
microversion=PLACEMENT_MICROVERSION, raise_exc=False)
@mock.patch('keystoneauth1.session.Session.request')
def test_delete(self, kss_req):
kss_req.return_value = fake_requests.FakeResponse(200)
url = '/resource_providers'
resp = self.client.delete(url)
self.assertEqual(200, resp.status_code)
kss_req.assert_called_once_with(
url, 'DELETE',
endpoint_filter={'service_type': 'placement',
'interface': 'public'},
headers={'accept': 'application/json'},
microversion=PLACEMENT_MICROVERSION, raise_exc=False)

View File

@ -0,0 +1,93 @@
# 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 keystoneauth1 import adapter
from keystoneauth1.identity import v3
from keystoneauth1 import session
from oslo_config import cfg
from oslo_log import log as logging
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
PLACEMENT_MICROVERSION = 1.29
class BlazarPlacementClient(object):
"""Client class for updating placement."""
def __init__(self, **kwargs):
"""Initialize the report client.
If a prepared keystoneauth1 adapter for API communication is
specified, it is used.
Otherwise creates it via _create_client() function.
"""
adapter = kwargs.pop('adapter', None)
self._client = adapter or self._create_client(**kwargs)
def _create_client(self, **kwargs):
"""Create the HTTP session accessing the placement service."""
username = kwargs.pop('username',
CONF.os_admin_username)
user_domain_name = kwargs.pop('user_domain_name',
CONF.os_admin_user_domain_name)
project_name = kwargs.pop('project_name',
CONF.os_admin_project_name)
password = kwargs.pop('password',
CONF.os_admin_password)
project_domain_name = kwargs.pop('project_domain_name',
CONF.os_admin_project_domain_name)
auth_url = kwargs.pop('auth_url', None)
if auth_url is None:
auth_url = "%s://%s:%s/%s/%s" % (CONF.os_auth_protocol,
CONF.os_auth_host,
CONF.os_auth_port,
CONF.os_auth_prefix,
CONF.os_auth_version)
auth = v3.Password(auth_url=auth_url,
username=username,
password=password,
project_name=project_name,
user_domain_name=user_domain_name,
project_domain_name=project_domain_name)
sess = session.Session(auth=auth)
# Set accept header on every request to ensure we notify placement
# service of our response body media type preferences.
headers = {'accept': 'application/json'}
client = adapter.Adapter(session=sess,
service_type='placement',
interface='public',
additional_headers=headers)
return client
def get(self, url, microversion=PLACEMENT_MICROVERSION):
return self._client.get(url, raise_exc=False,
microversion=microversion)
def post(self, url, data, microversion=PLACEMENT_MICROVERSION):
return self._client.post(url, json=data, raise_exc=False,
microversion=microversion)
def put(self, url, data, microversion=PLACEMENT_MICROVERSION):
return self._client.put(url, json=data, raise_exc=False,
microversion=microversion)
def delete(self, url, microversion=PLACEMENT_MICROVERSION):
return self._client.delete(url, raise_exc=False,
microversion=microversion)

View File

@ -8,6 +8,7 @@ Babel!=2.4.0,>=2.3.4 # BSD
eventlet!=0.18.3,!=0.20.1,>=0.18.2 # MIT
Flask!=0.11,>=0.10 # BSD
iso8601>=0.1.11 # MIT
keystoneauth1>=3.4.0 # Apache-2.0
keystonemiddleware>=4.17.0 # Apache-2.0
kombu!=4.0.2,>=4.0.0 # BSD
oslo.concurrency>=3.26.0 # Apache-2.0
@ -26,6 +27,7 @@ netaddr>=0.7.18 # BSD
python-keystoneclient>=3.8.0 # Apache-2.0
pecan!=1.0.2,!=1.0.3,!=1.0.4,!=1.2,>=1.0.0 # BSD
sqlalchemy-migrate>=0.11.0 # Apache-2.0
requests>=2.18.4 # Apache-2.0
Routes>=2.3.1 # MIT
six>=1.10.0 # MIT
SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT