Merge "Add wait_for_server API call."
This commit is contained in:
commit
07a191da8b
3
releasenotes/notes/wait_for_server-8dc8446b7c673d36.yaml
Normal file
3
releasenotes/notes/wait_for_server-8dc8446b7c673d36.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- New wait_for_server() API call to wait for a server to reach ACTIVE status.
|
@ -3477,7 +3477,6 @@ class OpenStackCloud(object):
|
|||||||
with _utils.shade_exceptions("Error in creating instance"):
|
with _utils.shade_exceptions("Error in creating instance"):
|
||||||
server = self.manager.submitTask(_tasks.ServerCreate(
|
server = self.manager.submitTask(_tasks.ServerCreate(
|
||||||
name=name, flavor=flavor, **kwargs))
|
name=name, flavor=flavor, **kwargs))
|
||||||
server_id = server.id
|
|
||||||
admin_pass = server.get('adminPass') or kwargs.get('admin_pass')
|
admin_pass = server.get('adminPass') or kwargs.get('admin_pass')
|
||||||
if not wait:
|
if not wait:
|
||||||
# This is a direct get task call to skip the list_servers
|
# This is a direct get task call to skip the list_servers
|
||||||
@ -3492,41 +3491,55 @@ class OpenStackCloud(object):
|
|||||||
if server.status == 'ERROR':
|
if server.status == 'ERROR':
|
||||||
raise OpenStackCloudException(
|
raise OpenStackCloudException(
|
||||||
"Error in creating the server.")
|
"Error in creating the server.")
|
||||||
|
|
||||||
if wait:
|
if wait:
|
||||||
timeout_message = "Timeout waiting for the server to come up."
|
server = self.wait_for_server(
|
||||||
start_time = time.time()
|
server, auto_ip=auto_ip, ips=ips, ip_pool=ip_pool,
|
||||||
# There is no point in iterating faster than the list_servers cache
|
reuse=reuse_ips, timeout=timeout
|
||||||
for count in _utils._iterate_timeout(
|
)
|
||||||
timeout,
|
|
||||||
timeout_message,
|
|
||||||
wait=self._SERVER_AGE):
|
|
||||||
try:
|
|
||||||
# Use the get_server call so that the list_servers
|
|
||||||
# cache can be leveraged
|
|
||||||
server = self.get_server(server_id)
|
|
||||||
except Exception:
|
|
||||||
continue
|
|
||||||
if not server:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# We have more work to do, but the details of that are
|
|
||||||
# hidden from the user. So, calculate remaining timeout
|
|
||||||
# and pass it down into the IP stack.
|
|
||||||
remaining_timeout = timeout - int(time.time() - start_time)
|
|
||||||
if remaining_timeout <= 0:
|
|
||||||
raise OpenStackCloudTimeout(timeout_message)
|
|
||||||
|
|
||||||
server = self.get_active_server(
|
|
||||||
server=server, reuse=reuse_ips,
|
|
||||||
auto_ip=auto_ip, ips=ips, ip_pool=ip_pool,
|
|
||||||
wait=wait, timeout=remaining_timeout)
|
|
||||||
if server:
|
|
||||||
server.adminPass = admin_pass
|
|
||||||
return server
|
|
||||||
|
|
||||||
server.adminPass = admin_pass
|
server.adminPass = admin_pass
|
||||||
return server
|
return server
|
||||||
|
|
||||||
|
def wait_for_server(
|
||||||
|
self, server, auto_ip=True, ips=None, ip_pool=None,
|
||||||
|
reuse=True, timeout=180):
|
||||||
|
"""
|
||||||
|
Wait for a server to reach ACTIVE status.
|
||||||
|
"""
|
||||||
|
server_id = server['id']
|
||||||
|
timeout_message = "Timeout waiting for the server to come up."
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
# There is no point in iterating faster than the list_servers cache
|
||||||
|
for count in _utils._iterate_timeout(
|
||||||
|
timeout,
|
||||||
|
timeout_message,
|
||||||
|
wait=self._SERVER_AGE):
|
||||||
|
try:
|
||||||
|
# Use the get_server call so that the list_servers
|
||||||
|
# cache can be leveraged
|
||||||
|
server = self.get_server(server_id)
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
if not server:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# We have more work to do, but the details of that are
|
||||||
|
# hidden from the user. So, calculate remaining timeout
|
||||||
|
# and pass it down into the IP stack.
|
||||||
|
remaining_timeout = timeout - int(time.time() - start_time)
|
||||||
|
if remaining_timeout <= 0:
|
||||||
|
raise OpenStackCloudTimeout(timeout_message)
|
||||||
|
|
||||||
|
server = self.get_active_server(
|
||||||
|
server=server, reuse=reuse,
|
||||||
|
auto_ip=auto_ip, ips=ips, ip_pool=ip_pool,
|
||||||
|
wait=True, timeout=remaining_timeout)
|
||||||
|
|
||||||
|
if server is not None and server['status'] == 'ACTIVE':
|
||||||
|
return server
|
||||||
|
|
||||||
def get_active_server(
|
def get_active_server(
|
||||||
self, server, auto_ip=True, ips=None, ip_pool=None,
|
self, server, auto_ip=True, ips=None, ip_pool=None,
|
||||||
reuse=True, wait=False, timeout=180):
|
reuse=True, wait=False, timeout=180):
|
||||||
|
@ -20,6 +20,7 @@ Tests for the `create_server` command.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from mock import patch, Mock
|
from mock import patch, Mock
|
||||||
|
import mock
|
||||||
import os_client_config
|
import os_client_config
|
||||||
from shade import _utils
|
from shade import _utils
|
||||||
from shade import meta
|
from shade import meta
|
||||||
@ -164,67 +165,84 @@ class TestCreateServer(base.TestCase):
|
|||||||
name='server-name', image='image=id',
|
name='server-name', image='image=id',
|
||||||
flavor='flavor-id', admin_pass='ooBootheiX0edoh'))
|
flavor='flavor-id', admin_pass='ooBootheiX0edoh'))
|
||||||
|
|
||||||
def test_create_server_with_admin_pass_wait(self):
|
@patch.object(OpenStackCloud, "wait_for_server")
|
||||||
|
@patch.object(OpenStackCloud, "nova_client")
|
||||||
|
def test_create_server_with_admin_pass_wait(self, mock_nova, mock_wait):
|
||||||
"""
|
"""
|
||||||
Test that a server with an admin_pass passed returns the password
|
Test that a server with an admin_pass passed returns the password
|
||||||
"""
|
"""
|
||||||
with patch("shade.OpenStackCloud"):
|
fake_server = fakes.FakeServer('1234', '', 'BUILD')
|
||||||
build_server = fakes.FakeServer(
|
fake_server_with_pass = fakes.FakeServer('1234', '', 'BUILD',
|
||||||
'1234', '', 'BUILD', addresses=dict(public='1.1.1.1'),
|
adminPass='ooBootheiX0edoh')
|
||||||
adminPass='ooBootheiX0edoh')
|
|
||||||
next_server = fakes.FakeServer(
|
|
||||||
'1234', '', 'BUILD', addresses=dict(public='1.1.1.1'))
|
|
||||||
fake_server = fakes.FakeServer(
|
|
||||||
'1234', '', 'ACTIVE', addresses=dict(public='1.1.1.1'))
|
|
||||||
ret_fake_server = fakes.FakeServer(
|
|
||||||
'1234', '', 'ACTIVE', addresses=dict(public='1.1.1.1'),
|
|
||||||
adminPass='ooBootheiX0edoh')
|
|
||||||
config = {
|
|
||||||
"servers.create.return_value": build_server,
|
|
||||||
"servers.get.return_value": next_server,
|
|
||||||
"servers.list.side_effect": [
|
|
||||||
[next_server], [fake_server]]
|
|
||||||
}
|
|
||||||
OpenStackCloud.nova_client = Mock(**config)
|
|
||||||
with patch.object(OpenStackCloud, "add_ips_to_server",
|
|
||||||
return_value=fake_server):
|
|
||||||
self.assertEqual(
|
|
||||||
_utils.normalize_server(
|
|
||||||
meta.obj_to_dict(ret_fake_server),
|
|
||||||
cloud_name=self.client.name,
|
|
||||||
region_name=self.client.region_name),
|
|
||||||
_utils.normalize_server(
|
|
||||||
meta.obj_to_dict(
|
|
||||||
self.client.create_server(
|
|
||||||
'server-name', 'image-id', 'flavor-id',
|
|
||||||
wait=True, admin_pass='ooBootheiX0edoh')),
|
|
||||||
cloud_name=self.client.name,
|
|
||||||
region_name=self.client.region_name)
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_create_server_wait(self):
|
mock_nova.servers.create.return_value = fake_server
|
||||||
|
mock_nova.servers.get.return_value = fake_server
|
||||||
|
# The wait returns non-password server
|
||||||
|
mock_wait.return_value = _utils.normalize_server(
|
||||||
|
meta.obj_to_dict(fake_server), None, None)
|
||||||
|
|
||||||
|
server = self.client.create_server(
|
||||||
|
name='server-name', image='image-id',
|
||||||
|
flavor='flavor-id', admin_pass='ooBootheiX0edoh', wait=True)
|
||||||
|
|
||||||
|
# Assert that we did wait
|
||||||
|
self.assertTrue(mock_wait.called)
|
||||||
|
|
||||||
|
# Even with the wait, we should still get back a passworded server
|
||||||
|
self.assertEqual(
|
||||||
|
server,
|
||||||
|
_utils.normalize_server(meta.obj_to_dict(fake_server_with_pass),
|
||||||
|
None, None)
|
||||||
|
)
|
||||||
|
|
||||||
|
@patch.object(OpenStackCloud, "get_active_server")
|
||||||
|
@patch.object(OpenStackCloud, "get_server")
|
||||||
|
def test_wait_for_server(self, mock_get_server, mock_get_active_server):
|
||||||
"""
|
"""
|
||||||
Test that create_server with a wait returns the server instance when
|
Test that waiting for a server returns the server instance when
|
||||||
its status changes to "ACTIVE".
|
its status changes to "ACTIVE".
|
||||||
"""
|
"""
|
||||||
with patch("shade.OpenStackCloud"):
|
building_server = {'id': 'fake_server_id', 'status': 'BUILDING'}
|
||||||
build_server = fakes.FakeServer(
|
active_server = {'id': 'fake_server_id', 'status': 'ACTIVE'}
|
||||||
'1234', '', 'ACTIVE', addresses=dict(public='1.1.1.1'))
|
|
||||||
fake_server = fakes.FakeServer(
|
mock_get_server.side_effect = iter([building_server, active_server])
|
||||||
'1234', '', 'ACTIVE', addresses=dict(public='1.1.1.1'))
|
mock_get_active_server.side_effect = iter([
|
||||||
config = {
|
building_server, active_server])
|
||||||
"servers.create.return_value": build_server,
|
|
||||||
"servers.get.return_value": build_server,
|
server = self.client.wait_for_server(building_server)
|
||||||
"servers.list.side_effect": [
|
|
||||||
[build_server], [fake_server]]
|
self.assertEqual(2, mock_get_server.call_count)
|
||||||
}
|
mock_get_server.assert_has_calls([
|
||||||
OpenStackCloud.nova_client = Mock(**config)
|
mock.call(building_server['id']),
|
||||||
with patch.object(OpenStackCloud, "add_ips_to_server",
|
mock.call(active_server['id']),
|
||||||
return_value=fake_server):
|
])
|
||||||
self.assertEqual(
|
|
||||||
self.client.create_server(
|
self.assertEqual(2, mock_get_active_server.call_count)
|
||||||
'server-name', 'image-id', 'flavor-id', wait=True),
|
mock_get_active_server.assert_has_calls([
|
||||||
fake_server)
|
mock.call(server=building_server, reuse=True, auto_ip=True,
|
||||||
|
ips=None, ip_pool=None, wait=True, timeout=mock.ANY),
|
||||||
|
mock.call(server=active_server, reuse=True, auto_ip=True,
|
||||||
|
ips=None, ip_pool=None, wait=True, timeout=mock.ANY),
|
||||||
|
])
|
||||||
|
|
||||||
|
self.assertEqual('ACTIVE', server['status'])
|
||||||
|
|
||||||
|
@patch.object(OpenStackCloud, 'wait_for_server')
|
||||||
|
@patch.object(OpenStackCloud, 'nova_client')
|
||||||
|
def test_create_server_wait(self, mock_nova, mock_wait):
|
||||||
|
"""
|
||||||
|
Test that create_server with a wait actually does the wait.
|
||||||
|
"""
|
||||||
|
fake_server = {'id': 'fake_server_id', 'status': 'BUILDING'}
|
||||||
|
mock_nova.servers.create.return_value = fake_server
|
||||||
|
|
||||||
|
self.client.create_server(
|
||||||
|
'server-name', 'image-id', 'flavor-id', wait=True),
|
||||||
|
|
||||||
|
mock_wait.assert_called_once_with(
|
||||||
|
fake_server, auto_ip=True, ips=None,
|
||||||
|
ip_pool=None, reuse=True, timeout=180
|
||||||
|
)
|
||||||
|
|
||||||
@patch('time.sleep')
|
@patch('time.sleep')
|
||||||
def test_create_server_no_addresses(self, mock_sleep):
|
def test_create_server_no_addresses(self, mock_sleep):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user