Merge "Add CLI to show instance usage audit logs"
This commit is contained in:
commit
5de74bef5c
|
@ -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":
|
||||
|
@ -2006,6 +2008,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, {}, {}
|
||||
|
||||
|
|
|
@ -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')
|
|
@ -3210,6 +3210,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 = \
|
||||
|
|
|
@ -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')
|
|
@ -5120,3 +5120,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