Add CLI to show instance usage audit logs

Currently we can get instance usage audit logs via Nova API,
and the docs also update for it. It is necessary to add that
to our client and CLI.

This patch adds the following command.

nova instance-usage-audit-log [--before <before>]

Co-Authored-by: Takashi Natsume <natsume.takashi@lab.ntt.co.jp>
Change-Id: I4ef8e40c322f1768ee1b5e01e9681cab0e2804bd
This commit is contained in:
int32bit 2016-12-10 12:12:41 +08:00 committed by Takashi NATSUME
parent beb90ec793
commit d418b5f245
8 changed files with 285 additions and 0 deletions

View File

@ -0,0 +1,87 @@
# 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 datetime
from oslo_utils import timeutils
from novaclient.tests.functional import base
class TestInstanceUsageAuditLogCLI(base.ClientTestBase):
COMPUTE_API_VERSION = '2.1'
# NOTE(takashin): By default, 'instance_usage_audit' is False in nova.
# So the instance usage audit log is not recoreded.
# Therefore an empty result can be got.
# But it is tested here to call APIs and get responses normally.
@staticmethod
def _get_begin_end_time():
current = timeutils.utcnow()
end = datetime.datetime(day=1, month=current.month, year=current.year)
year = end.year
if current.month == 1:
year -= 1
month = 12
else:
month = current.month - 1
begin = datetime.datetime(day=1, month=month, year=year)
return (begin, end)
def test_get_os_instance_usage_audit_log(self):
(begin, end) = self._get_begin_end_time()
expected = {
'hosts_not_run': '[]',
'log': '{}',
'num_hosts': '0',
'num_hosts_done': '0',
'num_hosts_not_run': '0',
'num_hosts_running': '0',
'overall_status': 'ALL hosts done. 0 errors.',
'total_errors': '0',
'total_instances': '0',
'period_beginning': str(begin),
'period_ending': str(end)
}
output = self.nova('instance-usage-audit-log')
for key in expected.keys():
self.assertEqual(expected[key],
self._get_value_from_the_table(output, key))
def test_get_os_instance_usage_audit_log_with_before(self):
expected = {
'hosts_not_run': '[]',
'log': '{}',
'num_hosts': '0',
'num_hosts_done': '0',
'num_hosts_not_run': '0',
'num_hosts_running': '0',
'overall_status': 'ALL hosts done. 0 errors.',
'total_errors': '0',
'total_instances': '0',
'period_beginning': '2016-11-01 00:00:00',
'period_ending': '2016-12-01 00:00:00'
}
output = self.nova(
'instance-usage-audit-log --before "2016-12-10 13:59:59.999999"')
for key in expected.keys():
self.assertEqual(expected[key],
self._get_value_from_the_table(output, key))

View File

@ -124,6 +124,8 @@ class FakeSessionClient(base_client.SessionClient):
munged_url = munged_url.replace(' ', '_')
munged_url = munged_url.replace('!', '_')
munged_url = munged_url.replace('@', '_')
munged_url = munged_url.replace('%20', '_')
munged_url = munged_url.replace('%3A', '_')
callback = "%s_%s" % (method.lower(), munged_url)
if url is None or callback == "get_http:__nova_api:8774":
@ -1974,6 +1976,86 @@ class FakeSessionClient(base_client.SessionClient):
return (200, FAKE_RESPONSE_HEADERS, {
"instanceAction": action})
def get_os_instance_usage_audit_log(self, **kw):
return (200, FAKE_RESPONSE_HEADERS, {
"instance_usage_audit_logs": {
"hosts_not_run": ["samplehost3"],
"log": {
"samplehost0": {
"errors": 1,
"instances": 1,
"message": ("Instance usage audit ran for host "
"samplehost0, 1 instances in 0.01 "
"seconds."),
"state": "DONE"
},
"samplehost1": {
"errors": 1,
"instances": 2,
"message": ("Instance usage audit ran for host "
"samplehost1, 2 instances in 0.01 "
"seconds."),
"state": "DONE"
},
"samplehost2": {
"errors": 1,
"instances": 3,
"message": ("Instance usage audit ran for host "
"samplehost2, 3 instances in 0.01 "
"seconds."),
"state": "DONE"
},
},
"num_hosts": 4,
"num_hosts_done": 3,
"num_hosts_not_run": 1,
"num_hosts_running": 0,
"overall_status": "3 of 4 hosts done. 3 errors.",
"period_beginning": "2012-06-01 00:00:00",
"period_ending": "2012-07-01 00:00:00",
"total_errors": 3,
"total_instances": 6}})
def get_os_instance_usage_audit_log_2016_12_10_13_59_59_999999(self, **kw):
return (200, FAKE_RESPONSE_HEADERS, {
"instance_usage_audit_log": {
"hosts_not_run": ["samplehost3"],
"log": {
"samplehost0": {
"errors": 1,
"instances": 1,
"message": ("Instance usage audit ran for host "
"samplehost0, 1 instances in 0.01 "
"seconds."),
"state": "DONE"
},
"samplehost1": {
"errors": 1,
"instances": 2,
"message": ("Instance usage audit ran for host "
"samplehost1, 2 instances in 0.01 "
"seconds."),
"state": "DONE"
},
"samplehost2": {
"errors": 1,
"instances": 3,
"message": ("Instance usage audit ran for host "
"samplehost2, 3 instances in 0.01 "
"seconds."),
"state": "DONE"
},
},
"num_hosts": 4,
"num_hosts_done": 3,
"num_hosts_not_run": 1,
"num_hosts_running": 0,
"overall_status": "3 of 4 hosts done. 3 errors.",
"period_beginning": "2012-06-01 00:00:00",
"period_ending": "2012-07-01 00:00:00",
"total_errors": 3,
"total_instances": 6}})
def post_servers_uuid1_action(self, **kw):
return 202, {}, {}

View File

@ -0,0 +1,37 @@
# Copyright 2013 Rackspace Hosting
# All Rights Reserved.
#
# 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 novaclient import api_versions
from novaclient.tests.unit import utils
from novaclient.tests.unit.v2 import fakes
class InstanceUsageAuditLogTests(utils.TestCase):
def setUp(self):
super(InstanceUsageAuditLogTests, self).setUp()
self.cs = fakes.FakeClient(api_versions.APIVersion("2.1"))
def test_instance_usage_audit_log(self):
audit_log = self.cs.instance_usage_audit_log.get()
self.assert_request_id(audit_log, fakes.FAKE_REQUEST_ID_LIST)
self.cs.assert_called('GET', '/os-instance_usage_audit_log')
def test_instance_usage_audit_log_with_before(self):
audit_log = self.cs.instance_usage_audit_log.get(
before='2016-12-10 13:59:59.999999')
self.assert_request_id(audit_log, fakes.FAKE_REQUEST_ID_LIST)
self.cs.assert_called(
'GET',
'/os-instance_usage_audit_log/2016-12-10%2013%3A59%3A59.999999')

View File

@ -3019,6 +3019,17 @@ class ShellTest(utils.TestCase):
api_version='2.58')
self.assertIn('Invalid changes-since value', six.text_type(ex))
def test_instance_usage_audit_log(self):
self.run_command('instance-usage-audit-log')
self.assert_called('GET', '/os-instance_usage_audit_log')
def test_instance_usage_audit_log_with_before(self):
self.run_command(
["instance-usage-audit-log", "--before",
"2016-12-10 13:59:59.999999"])
self.assert_called('GET', '/os-instance_usage_audit_log'
'/2016-12-10%2013%3A59%3A59.999999')
def test_cell_show(self):
self.run_command('cell-show child_cell')
self.assert_called('GET', '/os-cells/child_cell')

View File

@ -29,6 +29,7 @@ from novaclient.v2 import flavors
from novaclient.v2 import hypervisors
from novaclient.v2 import images
from novaclient.v2 import instance_action
from novaclient.v2 import instance_usage_audit_log
from novaclient.v2 import keypairs
from novaclient.v2 import limits
from novaclient.v2 import list_extensions
@ -169,6 +170,8 @@ class Client(object):
assisted_volume_snapshots.AssistedSnapshotManager(self)
self.cells = cells.CellsManager(self)
self.instance_action = instance_action.InstanceActionManager(self)
self.instance_usage_audit_log = \
instance_usage_audit_log.InstanceUsageAuditLogManager(self)
self.list_extensions = list_extensions.ListExtManager(self)
self.migrations = migrations.MigrationManager(self)
self.server_external_events = \

View File

@ -0,0 +1,40 @@
# Copyright 2013 Rackspace Hosting
# All Rights Reserved.
#
# 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 six.moves.urllib import parse
from novaclient import base
class InstanceUsageAuditLog(base.Resource):
pass
class InstanceUsageAuditLogManager(base.Manager):
resource_class = InstanceUsageAuditLog
def get(self, before=None):
"""Get server usage audits.
:param before: Filters the response by the date and time
before which to list usage audits.
"""
if before:
return self._get('/os-instance_usage_audit_log/%s' %
parse.quote(before, safe=''),
'instance_usage_audit_log')
else:
return self._get('/os-instance_usage_audit_log',
'instance_usage_audit_logs')

View File

@ -5084,3 +5084,20 @@ def do_migration_list(cs, args):
changes_since=args.changes_since)
# TODO(yikun): Output a "Marker" column if there is a next link?
_print_migrations(cs, migrations)
@utils.arg(
'--before',
dest='before',
metavar='<before>',
default=None,
help=_("Filters the response by the date and time before which to list "
"usage audits. The date and time stamp format is as follows: "
"CCYY-MM-DD hh:mm:ss.NNNNNN ex 2015-08-27 09:49:58 or "
"2015-08-27 09:49:58.123456."))
def do_instance_usage_audit_log(cs, args):
"""List/Get server usage audits."""
audit_log = cs.instance_usage_audit_log.get(before=args.before).to_dict()
if 'hosts_not_run' in audit_log:
audit_log['hosts_not_run'] = pprint.pformat(audit_log['hosts_not_run'])
utils.print_dict(audit_log)

View File

@ -0,0 +1,8 @@
---
features:
- Added new client API and CLI (``nova instance-usage-audit-log``)
to get server usage audit logs.
By default, it lists usage audits for all servers on all
compute hosts where usage auditing is configured.
If you specify the ``--before`` option, the result is filtered
by the date and time before which to list server usage audits.