Merge "Functional tests for trigger-crash-dump (microversion 2.17)"
This commit is contained in:
commit
6a8df59254
@ -25,6 +25,9 @@ import novaclient.api_versions
|
|||||||
import novaclient.client
|
import novaclient.client
|
||||||
import novaclient.v2.shell
|
import novaclient.v2.shell
|
||||||
|
|
||||||
|
BOOT_IS_COMPLETE = ("login as 'cirros' user. default password: "
|
||||||
|
"'cubswin:)'. use 'sudo' for root.")
|
||||||
|
|
||||||
|
|
||||||
# The following are simple filter functions that filter our available
|
# The following are simple filter functions that filter our available
|
||||||
# image / flavor list so that they can be used in standard testing.
|
# image / flavor list so that they can be used in standard testing.
|
||||||
@ -224,6 +227,23 @@ class ClientTestBase(testtools.TestCase):
|
|||||||
self.fail("Volume %s did not reach status %s after %d s"
|
self.fail("Volume %s did not reach status %s after %d s"
|
||||||
% (volume.id, status, timeout))
|
% (volume.id, status, timeout))
|
||||||
|
|
||||||
|
def wait_for_server_os_boot(self, server_id, timeout=60,
|
||||||
|
poll_interval=1):
|
||||||
|
"""Wait until instance's operating system is completely booted.
|
||||||
|
|
||||||
|
:param server_id: uuid4 id of given instance
|
||||||
|
:param timeout: timeout in seconds
|
||||||
|
:param poll_interval: poll interval in seconds
|
||||||
|
"""
|
||||||
|
start_time = time.time()
|
||||||
|
while time.time() - start_time < timeout:
|
||||||
|
if BOOT_IS_COMPLETE in self.nova('console-log %s ' % server_id):
|
||||||
|
break
|
||||||
|
time.sleep(poll_interval)
|
||||||
|
else:
|
||||||
|
self.fail("Server %s did not boot after %d s"
|
||||||
|
% (server_id, timeout))
|
||||||
|
|
||||||
def wait_for_resource_delete(self, resource, manager,
|
def wait_for_resource_delete(self, resource, manager,
|
||||||
timeout=60, poll_interval=1):
|
timeout=60, poll_interval=1):
|
||||||
"""Wait until getting the resource raises NotFound exception.
|
"""Wait until getting the resource raises NotFound exception.
|
||||||
|
146
novaclient/tests/functional/v2/test_trigger_crash_dump.py
Normal file
146
novaclient/tests/functional/v2/test_trigger_crash_dump.py
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
# 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 time
|
||||||
|
|
||||||
|
from novaclient.tests.functional import base
|
||||||
|
from novaclient.v2 import shell
|
||||||
|
|
||||||
|
|
||||||
|
class TestTriggerCrashDumpNovaClientV217(base.TenantTestBase):
|
||||||
|
"""Functional tests for trigger crash dump"""
|
||||||
|
|
||||||
|
COMPUTE_API_VERSION = "2.17"
|
||||||
|
|
||||||
|
# It's a resource-consuming task to implement full-flow (up to getting
|
||||||
|
# and reading a dump file) functional test for trigger-crash-dump.
|
||||||
|
# We need to upload Ubuntu image for booting an instance based on it,
|
||||||
|
# and to install kdump with its further configuring on this instance.
|
||||||
|
# Here, the "light" version of functional test is proposed.
|
||||||
|
# It's based on knowledge that trigger-crash-dump uses a NMI injection,
|
||||||
|
# and when the 'trigger-crash-dump' operation is executed,
|
||||||
|
# instance's kernel receives the NMI signal, and an appropriate
|
||||||
|
# message will appear in the instance's log.
|
||||||
|
|
||||||
|
# The server status must be ACTIVE, PAUSED, RESCUED, RESIZED or ERROR.
|
||||||
|
# If not, the conflictingRequest(409) code is returned
|
||||||
|
|
||||||
|
def _wait_for_nmi(self, server_id, timeout=60,
|
||||||
|
poll_interval=1):
|
||||||
|
start_time = time.time()
|
||||||
|
while time.time() - start_time < timeout:
|
||||||
|
if 'trigger_crash_dump' in self.nova('instance-action-list %s ' %
|
||||||
|
server_id):
|
||||||
|
break
|
||||||
|
time.sleep(poll_interval)
|
||||||
|
else:
|
||||||
|
self.fail("Trigger crash dump hasn't been executed for server %s"
|
||||||
|
% (server_id, timeout))
|
||||||
|
|
||||||
|
def test_trigger_crash_dump_in_active_state(self):
|
||||||
|
server = self._create_server()
|
||||||
|
self.wait_for_server_os_boot(server.id)
|
||||||
|
self.nova('trigger-crash-dump %s ' % server.id)
|
||||||
|
self._wait_for_nmi(server.id)
|
||||||
|
output = self.nova('console-log %s ' % server.id)
|
||||||
|
self.assertIn("Uhhuh. NMI received for unknown reason ", output)
|
||||||
|
|
||||||
|
def test_trigger_crash_dump_in_error_state(self):
|
||||||
|
server = self._create_server()
|
||||||
|
self.wait_for_server_os_boot(server.id)
|
||||||
|
self.nova('reset-state %s ' % server.id)
|
||||||
|
shell._poll_for_status(
|
||||||
|
self.client.servers.get, server.id,
|
||||||
|
'active', ['error'])
|
||||||
|
self.nova('trigger-crash-dump %s ' % server.id)
|
||||||
|
self._wait_for_nmi(server.id)
|
||||||
|
output = self.nova('console-log %s ' % server.id)
|
||||||
|
self.assertIn("Uhhuh. NMI received for unknown reason ", output)
|
||||||
|
|
||||||
|
def test_trigger_crash_dump_in_paused_state(self):
|
||||||
|
server = self._create_server()
|
||||||
|
self.wait_for_server_os_boot(server.id)
|
||||||
|
self.nova('pause %s ' % server.id)
|
||||||
|
shell._poll_for_status(
|
||||||
|
self.client.servers.get, server.id,
|
||||||
|
'active', ['paused'])
|
||||||
|
self.nova('trigger-crash-dump %s ' % server.id)
|
||||||
|
self._wait_for_nmi(server.id)
|
||||||
|
output = self.nova('console-log %s ' % server.id)
|
||||||
|
# In PAUSED state a server's kernel shouldn't react onto NMI
|
||||||
|
self.assertNotIn("Uhhuh. NMI received for unknown reason ", output)
|
||||||
|
|
||||||
|
def test_trigger_crash_dump_in_rescued_state(self):
|
||||||
|
server = self._create_server()
|
||||||
|
self.wait_for_server_os_boot(server.id)
|
||||||
|
self.nova('rescue %s ' % server.id)
|
||||||
|
shell._poll_for_status(
|
||||||
|
self.client.servers.get, server.id,
|
||||||
|
'active', ['rescue'])
|
||||||
|
self.wait_for_server_os_boot(server.id)
|
||||||
|
self.nova('trigger-crash-dump %s ' % server.id)
|
||||||
|
self._wait_for_nmi(server.id)
|
||||||
|
output = self.nova('console-log %s ' % server.id)
|
||||||
|
self.assertIn("Uhhuh. NMI received for unknown reason ", output)
|
||||||
|
|
||||||
|
def test_trigger_crash_dump_in_resized_state(self):
|
||||||
|
server = self._create_server()
|
||||||
|
self.wait_for_server_os_boot(server.id)
|
||||||
|
self.nova('resize %s %s' % (server.id, 'm1.small'))
|
||||||
|
shell._poll_for_status(
|
||||||
|
self.client.servers.get, server.id,
|
||||||
|
'active', ['verify_resize'])
|
||||||
|
self.nova('trigger-crash-dump %s ' % server.id)
|
||||||
|
self._wait_for_nmi(server.id)
|
||||||
|
output = self.nova('console-log %s ' % server.id)
|
||||||
|
self.assertIn("Uhhuh. NMI received for unknown reason ", output)
|
||||||
|
|
||||||
|
def test_trigger_crash_dump_in_shutoff_state(self):
|
||||||
|
server = self._create_server()
|
||||||
|
self.wait_for_server_os_boot(server.id)
|
||||||
|
self.nova('stop %s ' % server.id)
|
||||||
|
shell._poll_for_status(
|
||||||
|
self.client.servers.get, server.id,
|
||||||
|
'active', ['shutoff'])
|
||||||
|
output = self.nova('trigger-crash-dump %s ' %
|
||||||
|
server.id, fail_ok=True, merge_stderr=True)
|
||||||
|
self.assertIn("ERROR (Conflict): "
|
||||||
|
"Cannot 'trigger_crash_dump' instance %s "
|
||||||
|
"while it is in vm_state stopped (HTTP 409) " %
|
||||||
|
server.id, output)
|
||||||
|
|
||||||
|
# If the specified server is locked, the conflictingRequest(409) code
|
||||||
|
# is returned to a user without administrator privileges.
|
||||||
|
def test_trigger_crash_dump_in_locked_state_admin(self):
|
||||||
|
server = self._create_server()
|
||||||
|
self.wait_for_server_os_boot(server.id)
|
||||||
|
self.nova('lock %s ' % server.id)
|
||||||
|
self.nova('trigger-crash-dump %s ' % server.id)
|
||||||
|
self._wait_for_nmi(server.id)
|
||||||
|
output = self.nova('console-log %s ' % server.id)
|
||||||
|
self.assertIn("Uhhuh. NMI received for unknown reason ", output)
|
||||||
|
|
||||||
|
def test_trigger_crash_dump_in_locked_state_nonadmin(self):
|
||||||
|
name = self.name_generate(prefix='server')
|
||||||
|
server = self.another_nova('boot --flavor %s --image %s --poll %s' %
|
||||||
|
(self.flavor.name, self.image.name, name))
|
||||||
|
self.addCleanup(self.another_nova, 'delete', params=name)
|
||||||
|
server_id = self._get_value_from_the_table(
|
||||||
|
server, 'id')
|
||||||
|
self.wait_for_server_os_boot(server_id)
|
||||||
|
self.another_nova('lock %s ' % server_id)
|
||||||
|
self.addCleanup(self.another_nova, 'unlock', params=name)
|
||||||
|
output = self.another_nova('trigger-crash-dump %s ' %
|
||||||
|
server_id, fail_ok=True, merge_stderr=True)
|
||||||
|
self.assertIn("ERROR (Conflict): Instance %s is in an invalid "
|
||||||
|
"state for 'trigger_crash_dump' (HTTP 409) " %
|
||||||
|
server_id, output)
|
Loading…
Reference in New Issue
Block a user