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:
parent
beb90ec793
commit
d418b5f245
@ -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))
|
@ -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, {}, {}
|
||||
|
||||
|
37
novaclient/tests/unit/v2/test_instance_usage_audit_log.py
Normal file
37
novaclient/tests/unit/v2/test_instance_usage_audit_log.py
Normal 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')
|
@ -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')
|
||||
|
@ -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 = \
|
||||
|
40
novaclient/v2/instance_usage_audit_log.py
Normal file
40
novaclient/v2/instance_usage_audit_log.py
Normal 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')
|
@ -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)
|
||||
|
@ -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.
|
Loading…
Reference in New Issue
Block a user