blob: aace60912ccad0fcf2b49b4ee0cff32d71f91052 [file] [log] [blame]
import json
import time
from kong import exceptions
from kong import openstack
from kong import tests
from kong.common import ssh
import unittest2 as unittest
class ServerActionsTest(tests.FunctionalTest):
multi_node = openstack.Manager().config.env.multi_node
def setUp(self):
super(ServerActionsTest, self).setUp()
self.os = openstack.Manager()
self.image_ref = self.os.config.env.image_ref
self.image_ref_alt = self.os.config.env.image_ref_alt
self.flavor_ref = self.os.config.env.flavor_ref
self.flavor_ref_alt = self.os.config.env.flavor_ref_alt
self.ssh_timeout = self.os.config.nova.ssh_timeout
self.server_password = 'testpwd'
self.server_name = 'testserver'
expected_server = {
'name' : self.server_name,
'imageRef' : self.image_ref,
'flavorRef' : self.flavor_ref,
'adminPass' : self.server_password,
}
created_server = self.os.nova.create_server(expected_server)
self.server_id = created_server['id']
self._wait_for_status(self.server_id, 'ACTIVE')
server = self.os.nova.get_server(self.server_id)
# KNOWN-ISSUE lp?
#self.access_ip = server['accessIPv4']
self.access_ip = server['addresses']['public'][0]['addr']
# Ensure server came up
self._assert_ssh_password()
def tearDown(self):
self.os.nova.delete_server(self.server_id)
def _get_ssh_client(self, password):
return ssh.Client(self.access_ip, 'root', password, self.ssh_timeout)
def _assert_ssh_password(self, password=None):
_password = password or self.server_password
client = self._get_ssh_client(_password)
self.assertTrue(client.test_connection_auth())
def _wait_for_status(self, server_id, status):
try:
self.os.nova.wait_for_server_status(server_id, status)
except exceptions.TimeoutException:
self.fail("Server failed to change status to %s" % status)
def _get_boot_time(self):
"""Return the time the server was started"""
output = self._read_file("/proc/uptime")
uptime = float(output.split().pop(0))
return time.time() - uptime
def _write_file(self, filename, contents):
return self._exec_command("echo -n %s > %s" % (contents, filename))
def _read_file(self, filename):
return self._exec_command("cat %s" % filename)
def _exec_command(self, command):
client = self._get_ssh_client(self.server_password)
return client.exec_command(command)
def test_reboot_server_soft(self):
"""Reboot a server (SOFT)"""
# SSH and get the uptime
initial_time_started = self._get_boot_time()
# Make reboot request
post_body = json.dumps({
'reboot' : {
'type' : 'SOFT',
}
})
url = "/servers/%s/action" % self.server_id
response, body = self.os.nova.request('POST', url, body=post_body)
self.assertEqual(response['status'], '202')
# Assert status transition
# KNOWN-ISSUE
#self.os.nova.wait_for_server_status(self.server_id, 'REBOOT')
ssh_client = self._get_ssh_client(self.server_password)
ssh_client.connect_until_closed()
self.os.nova.wait_for_server_status(self.server_id, 'ACTIVE')
# SSH and verify uptime is less than before
post_reboot_time_started = self._get_boot_time()
self.assertTrue(initial_time_started < post_reboot_time_started)
def test_reboot_server_hard(self):
"""Reboot a server (HARD)"""
# SSH and get the uptime
initial_time_started = self._get_boot_time()
# Make reboot request
post_body = json.dumps({
'reboot' : {
'type' : 'HARD',
}
})
url = "/servers/%s/action" % self.server_id
response, body = self.os.nova.request('POST', url, body=post_body)
self.assertEqual(response['status'], '202')
# Assert status transition
# KNOWN-ISSUE
#self.os.nova.wait_for_server_status(self.server_id, 'HARD_REBOOT')
ssh_client = self._get_ssh_client(self.server_password)
ssh_client.connect_until_closed()
self.os.nova.wait_for_server_status(self.server_id, 'ACTIVE')
# SSH and verify uptime is less than before
post_reboot_time_started = self._get_boot_time()
self.assertTrue(initial_time_started < post_reboot_time_started)
def test_change_server_password(self):
"""Change root password of a server"""
# SSH into server using original password
self._assert_ssh_password()
# Change server password
post_body = json.dumps({
'changePassword' : {
'adminPass' : 'test123',
}
})
url = '/servers/%s/action' % self.server_id
response, body = self.os.nova.request('POST', url, body=post_body)
# Assert status transition
self.assertEqual('202', response['status'])
# KNOWN-ISSUE
#self.os.nova.wait_for_server_status(self.server_id, 'PASSWORD')
self.os.nova.wait_for_server_status(self.server_id, 'ACTIVE')
# SSH into server using new password
self._assert_ssh_password('test123')
def test_rebuild_server(self):
"""Rebuild a server"""
filename = '/tmp/testfile'
contents = 'WORDS'
self._write_file(filename, contents)
self.assertEqual(self._read_file(filename), contents)
# Make rebuild request
post_body = json.dumps({
'rebuild' : {
'imageRef' : self.image_ref_alt,
}
})
url = '/servers/%s/action' % self.server_id
response, body = self.os.nova.request('POST', url, body=post_body)
# Ensure correct status transition
self.assertEqual('202', response['status'])
# KNOWN-ISSUE
#self.os.nova.wait_for_server_status(self.server_id, 'REBUILD')
self.os.nova.wait_for_server_status(self.server_id, 'BUILD')
self.os.nova.wait_for_server_status(self.server_id, 'ACTIVE')
# Treats an issue where we ssh'd in too soon after rebuild
time.sleep(30)
# Check that the instance's imageRef matches the new imageRef
server = self.os.nova.get_server(self.server_id)
ref_match = self.image_ref_alt == server['image']['links'][0]['href']
id_match = self.image_ref_alt == server['image']['id']
self.assertTrue(ref_match or id_match)
# SSH into the server to ensure it came back up
self._assert_ssh_password()
# make sure file is gone
self.assertEqual(self._read_file(filename), '')
@unittest.skipIf(not multi_node, 'Multiple compute nodes required')
def test_resize_server_confirm(self):
"""Resize a server"""
# Make resize request
post_body = json.dumps({
'resize' : {
'flavorRef': self.flavor_ref_alt,
}
})
url = '/servers/%s/action' % self.server_id
response, body = self.os.nova.request('POST', url, body=post_body)
# Wait for status transition
self.assertEqual('202', response['status'])
# KNOWN-ISSUE
#self.os.nova.wait_for_server_status(self.server_id, 'VERIFY_RESIZE')
self.os.nova.wait_for_server_status(self.server_id, 'RESIZE-CONFIRM')
# Ensure API reports new flavor
server = self.os.nova.get_server(self.server_id)
self.assertEqual(self.flavor_ref_alt, server['flavor']['id'])
#SSH into the server to ensure it came back up
self._assert_ssh_password()
# Make confirmResize request
post_body = json.dumps({
'confirmResize' : 'null'
})
url = '/servers/%s/action' % self.server_id
response, body = self.os.nova.request('POST', url, body=post_body)
# Wait for status transition
self.assertEqual('204', response['status'])
self.os.nova.wait_for_server_status(self.server_id, 'ACTIVE')
# Ensure API still reports new flavor
server = self.os.nova.get_server(self.server_id)
self.assertEqual(self.flavor_ref_alt, server['flavor']['id'])
@unittest.skipIf(not multi_node, 'Multiple compute nodes required')
def test_resize_server_revert(self):
"""Resize a server, then revert"""
# Make resize request
post_body = json.dumps({
'resize' : {
'flavorRef': self.flavor_ref_alt,
}
})
url = '/servers/%s/action' % self.server_id
response, body = self.os.nova.request('POST', url, body=post_body)
# Wait for status transition
self.assertEqual('202', response['status'])
# KNOWN-ISSUE
#self.os.nova.wait_for_server_status(self.server_id, 'VERIFY_RESIZE')
self.os.nova.wait_for_server_status(self.server_id, 'RESIZE-CONFIRM')
# SSH into the server to ensure it came back up
self._assert_ssh_password()
# Ensure API reports new flavor
server = self.os.nova.get_server(self.server_id)
self.assertEqual(self.flavor_ref_alt, server['flavor']['id'])
# Make revertResize request
post_body = json.dumps({
'revertResize' : 'null'
})
url = '/servers/%s/action' % self.server_id
response, body = self.os.nova.request('POST', url, body=post_body)
# Assert status transition
self.assertEqual('202', response['status'])
self.os.nova.wait_for_server_status(self.server_id, 'ACTIVE')
# Ensure flavor ref was reverted to original
server = self.os.nova.get_server(self.server_id)
self.assertEqual(self.flavor_ref, server['flavor']['id'])
class SnapshotTests(unittest.TestCase):
def setUp(self):
self.os = openstack.Manager()
self.image_ref = self.os.config.env.image_ref
self.flavor_ref = self.os.config.env.flavor_ref
self.ssh_timeout = self.os.config.nova.ssh_timeout
self.server_name = 'testserver'
expected_server = {
'name' : self.server_name,
'imageRef' : self.image_ref,
'flavorRef' : self.flavor_ref,
}
created_server = self.os.nova.create_server(expected_server)
self.server_id = created_server['id']
def tearDown(self):
self.os.nova.delete_server(self.server_id)
def _wait_for_status(self, server_id, status):
try:
self.os.nova.wait_for_server_status(server_id, status)
except exceptions.TimeoutException:
self.fail("Server failed to change status to %s" % status)
def test_snapshot_server_active(self):
"""Create image from an existing server"""
# Wait for server to come up before running this test
self._wait_for_status(self.server_id, 'ACTIVE')
# Create snapshot
image_data = {'name' : 'backup'}
req_body = json.dumps({'createImage': image_data})
url = '/servers/%s/action' % self.server_id
response, body = self.os.nova.request('POST', url, body=req_body)
print response
print body
self.assertEqual(response['status'], '202')
image_ref = response['location']
snapshot_id = image_ref.rsplit('/',1)[1]
# Get snapshot and check its attributes
resp, body = self.os.nova.request('GET', '/images/%s' % snapshot_id)
snapshot = json.loads(body)['image']
self.assertEqual(snapshot['name'], image_data['name'])
server_ref = snapshot['server']['links'][0]['href']
self.assertTrue(server_ref.endswith('/%s' % self.server_id))
# Ensure image is actually created
self.os.nova.wait_for_image_status(snapshot['id'], 'ACTIVE')
# Cleaning up
self.os.nova.request('DELETE', '/images/%s' % snapshot_id)
def test_snapshot_server_inactive(self):
"""Ensure inability to snapshot server in BUILD state"""
# Create snapshot
req_body = json.dumps({'createImage': {'name' : 'backup'}})
url = '/servers/%s/action' % self.server_id
response, body = self.os.nova.request('POST', url, body=req_body)
# KNOWN-ISSUE - we shouldn't be able to snapshot a building server
#self.assertEqual(response['status'], '400') # what status code?
self.assertEqual(response['status'], '202')
snapshot_id = response['location'].rsplit('/', 1)[1]
# Delete image for now, won't need this once correct status code is in
self.os.nova.request('DELETE', '/images/%s' % snapshot_id)