Add API call to fetch tenant entities

This commit is contained in:
Frédéric Guillot 2017-05-15 15:57:03 -04:00
parent 75b72d4e34
commit d263c9ae17
8 changed files with 114 additions and 14 deletions

View File

@ -16,7 +16,7 @@ from cliff.command import Command
class EndpointCommand(Command):
"""Show the Almanach Endpoint URL"""
"""Show Almanach Endpoint URL"""
def take_action(self, parsed_args):
self.app.stdout.write('{}\n'.format(self.app.get_client().get_url()))

View File

@ -0,0 +1,46 @@
# Copyright 2017 INAP
#
# 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 cliff.lister import Lister
from dateutil import parser
class TenantEntityCommand(Lister):
"""Show all entities for a given tenant"""
def get_parser(self, prog_name):
parser = super().get_parser(prog_name)
parser.add_argument('tenant_id', help='Tenant ID')
parser.add_argument('start', help='Start Date')
parser.add_argument('end', help='End Date')
return parser
def take_action(self, parsed_args):
start = parser.parse(parsed_args.start)
end = parser.parse(parsed_args.end)
entities = self.app.get_client().get_tenant_entities(parsed_args.tenant_id, start, end)
rows = []
for entity in entities:
entity_type = entity.get('entity_type')
if entity_type == 'instance':
properties = dict(flavor=entity.get('flavor'), image=entity.get('image_meta'))
else:
properties = dict(volume_type=entity.get('volume_type'), attached_to=entity.get('attached_to'))
rows.append((entity.get('entity_id'), entity_type, entity.get('name'),
entity.get('start'), entity.get('end'), properties))
return ('Entity ID', 'Type', 'Name', 'Start', 'End', 'Properties'), rows

View File

@ -16,7 +16,7 @@ from cliff.command import Command
class VersionCommand(Command):
"""Show the Almanach version number"""
"""Show Almanach version number"""
def take_action(self, parsed_args):
info = self.app.get_client().get_info()

View File

@ -24,18 +24,25 @@ logger = logging.getLogger(__name__)
class HttpClient(metaclass=abc.ABCMeta):
def _get(self, url):
def __init__(self, url, token=None):
self.url = url
self.token = token
def _get(self, url, params=None):
logger.debug(url)
response = requests.get(url, headers=self._get_headers())
response = requests.get(url, headers=self._get_headers(), params=params)
body = response.json()
if response.status_code != 200:
raise exceptions.HTTPError('HTTP Error ({})'.format(response.status_code))
raise exceptions.HTTPError('{} ({})'.format(body.get('error') or 'HTTP Error', response.status_code))
return response.json()
return body
def _get_headers(self):
return {
'Content-Type': 'application/json',
'Accept': 'application/json',
'User-Agent': 'python-almanachclient/{}'.format(client_version.__version__),
'X-Auth-Token': self.token,
}

View File

@ -19,6 +19,7 @@ from cliff import app
from cliff import commandmanager
from almanachclient.commands.endpoint import EndpointCommand
from almanachclient.commands.tenant_entities import TenantEntityCommand
from almanachclient.commands.version import VersionCommand
from almanachclient.keystone_client import KeystoneClient
from almanachclient.v1.client import Client
@ -29,6 +30,7 @@ class AlmanachCommandManager(commandmanager.CommandManager):
SHELL_COMMANDS = {
'version': VersionCommand,
'endpoint': EndpointCommand,
'tenant entities': TenantEntityCommand,
}
def load_commands(self, namespace):
@ -66,8 +68,12 @@ class AlmanachApp(app.App):
help='OpenStack username (Env: OS_USERNAME).')
parser.add_argument('--almanach-service',
default=os.environ.get('ALMANACH_SERVICE'),
default=os.environ.get('ALMANACH_SERVICE', 'almanach'),
help='Almanach keystone service name (Env: ALMANACH_SERVICE).')
parser.add_argument('--almanach-token',
default=os.environ.get('ALMANACH_TOKEN'),
help='Almanach API token (Env: ALMANACH_TOKEN).')
return parser
def get_client(self):
@ -77,7 +83,7 @@ class AlmanachApp(app.App):
service=self.options.almanach_service,
region_name=self.options.os_region_name)
return Client(keystone.get_endpoint_url())
return Client(keystone.get_endpoint_url(), token=self.options.almanach_token)
def main(argv=sys.argv[1:]):

View File

@ -12,8 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from datetime import datetime
from unittest import mock
from almanachclient import exceptions
from almanachclient.tests import base
from almanachclient.v1.client import Client
@ -21,8 +23,14 @@ from almanachclient.v1.client import Client
class TestClient(base.TestCase):
def setUp(self):
super().setUp()
self.almanach_url = 'http://almanach_url'
self.client = Client(self.almanach_url)
self.url = 'http://almanach_url'
self.token = 'token'
self.headers = {'Content-Type': 'application/json',
'User-Agent': 'python-almanachclient/0.0.1',
'X-Auth-Token': self.token,
'Accept': 'application/json'}
self.client = Client(self.url, self.token)
@mock.patch('requests.get')
def test_get_info(self, requests):
@ -37,3 +45,31 @@ class TestClient(base.TestCase):
response.status_code = 200
self.assertEqual(expected, self.client.get_info())
requests.assert_called_once_with('{}{}'.format(self.url, '/v1/info'), headers=self.headers, params=None)
@mock.patch('requests.get')
def test_get_info_with_http_error(self, requests):
response = mock.Mock()
requests.return_value = response
response.status_code = 500
self.assertRaises(exceptions.HTTPError, self.client.get_info)
@mock.patch('requests.get')
def test_get_tenant_entities(self, requests):
response = mock.Mock()
expected = [mock.Mock()]
requests.return_value = response
response.json.return_value = expected
response.status_code = 200
start = datetime.now()
end = datetime.now()
params = dict(start=start.strftime(Client.DATE_FORMAT), end=end.strftime(Client.DATE_FORMAT))
self.assertEqual(expected, self.client.get_tenant_entities('my_tenant_id', start, end))
requests.assert_called_once_with('{}{}'.format(self.url, '/v1/project/my_tenant_id/entities'),
params=params,
headers=self.headers)

View File

@ -16,13 +16,17 @@ from almanachclient.http_client import HttpClient
class Client(HttpClient):
api_version = 'v1'
DATE_FORMAT = '%Y-%m-%d %H:%M:%S.%f'
def __init__(self, url):
self.url = url
api_version = 'v1'
def get_url(self):
return self.url
def get_info(self):
return self._get('{}/{}/info'.format(self.url, self.api_version))
def get_tenant_entities(self, tenant_id, start, end):
url = '{}/{}/project/{}/entities'.format(self.url, self.api_version, tenant_id)
params = {'start': start.strftime(self.DATE_FORMAT), 'end': end.strftime(self.DATE_FORMAT)}
return self._get(url, params)

View File

@ -1,4 +1,5 @@
pbr>=2.0.0,!=2.1.0 # Apache-2.0
cliff>=2.6.0 # Apache-2.0
requests>=2.10.0,!=2.12.2,!=2.13.0 # Apache-2.0
python-keystoneclient>=3.8.0 # Apache-2.0
python-keystoneclient>=3.8.0 # Apache-2.0
python-dateutil>=2.4.2 # BSD