Merge "task_state must be consider before many action"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index cca3cdd..cd57354 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -122,6 +122,10 @@
# Number of seconds to wait to authenticate to an instance
ssh_timeout = 300
+# Additinal wait time for clean state, when there is
+# no OS-EXT-STS extension availiable
+ready_wait = 0
+
# Number of seconds to wait for output from ssh channel
ssh_channel_timeout = 60
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
new file mode 100644
index 0000000..15569cd
--- /dev/null
+++ b/tempest/common/waiters.py
@@ -0,0 +1,82 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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 tempest import config
+from tempest import exceptions
+from tempest.openstack.common import log as logging
+
+CONFIG = config.TempestConfig()
+LOG = logging.getLogger(__name__)
+
+
+# NOTE(afazekas): This function needs to know a token and a subject.
+def wait_for_server_status(client, server_id, status, ready_wait=True):
+ """Waits for a server to reach a given status."""
+
+ def _get_task_state(body):
+ task_state = body.get('OS-EXT-STS:task_state', None)
+ return task_state
+
+ # NOTE(afazekas): UNKNOWN status possible on ERROR
+ # or in a very early stage.
+ resp, body = client.get_server(server_id)
+ old_status = server_status = body['status']
+ old_task_state = task_state = _get_task_state(body)
+ start_time = int(time.time())
+ while True:
+ # NOTE(afazekas): Now the BUILD status only reached
+ # between the UNKOWN->ACTIVE transition.
+ # TODO(afazekas): enumerate and validate the stable status set
+ if status == 'BUILD' and server_status != 'UNKNOWN':
+ return
+ if server_status == status:
+ if ready_wait:
+ if status == 'BUILD':
+ return
+ # NOTE(afazekas): The instance is in "ready for action state"
+ # when no task in progress
+ # NOTE(afazekas): Converted to string bacuse of the XML
+ # responses
+ if str(task_state) == "None":
+ # without state api extension 3 sec usually enough
+ time.sleep(CONFIG.compute.ready_wait)
+ return
+ else:
+ return
+
+ time.sleep(client.build_interval)
+ resp, body = client.get_server(server_id)
+ server_status = body['status']
+ task_state = _get_task_state(body)
+ if (server_status != old_status) or (task_state != old_task_state):
+ LOG.info('State transition "%s" ==> "%s" after %d second wait',
+ '/'.join((old_status, str(old_task_state))),
+ '/'.join((server_status, str(task_state))),
+ time.time() - start_time)
+ if server_status == 'ERROR':
+ raise exceptions.BuildErrorException(server_id=server_id)
+
+ timed_out = int(time.time()) - start_time >= client.build_timeout
+
+ if timed_out:
+ message = ('Server %s failed to reach %s status within the '
+ 'required time (%s s).' %
+ (server_id, status, client.build_timeout))
+ message += ' Current status: %s.' % server_status
+ raise exceptions.TimeoutException(message)
+ old_status = server_status
+ old_task_state = task_state
diff --git a/tempest/config.py b/tempest/config.py
index 100c673..b386968 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -177,6 +177,10 @@
default=300,
help="Timeout in seconds to wait for authentication to "
"succeed."),
+ cfg.IntOpt('ready_wait',
+ default=0,
+ help="Additinal wait time for clean state, when there is"
+ " no OS-EXT-STS extension availiable"),
cfg.IntOpt('ssh_channel_timeout',
default=60,
help="Timeout in seconds to wait for output from ssh "
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index c5827f6..1f2daec 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -21,6 +21,7 @@
import urllib
from tempest.common.rest_client import RestClient
+from tempest.common import waiters
from tempest import exceptions
@@ -152,28 +153,7 @@
def wait_for_server_status(self, server_id, status):
"""Waits for a server to reach a given status."""
- resp, body = self.get_server(server_id)
- server_status = body['status']
- start = int(time.time())
-
- while(server_status != status):
- if status == 'BUILD' and server_status != 'UNKNOWN':
- return
- time.sleep(self.build_interval)
- resp, body = self.get_server(server_id)
- server_status = body['status']
-
- if server_status == 'ERROR':
- raise exceptions.BuildErrorException(server_id=server_id)
-
- timed_out = int(time.time()) - start >= self.build_timeout
-
- if server_status != status and timed_out:
- message = ('Server %s failed to reach %s status within the '
- 'required time (%s s).' %
- (server_id, status, self.build_timeout))
- message += ' Current status: %s.' % server_status
- raise exceptions.TimeoutException(message)
+ return waiters.wait_for_server_status(self, server_id, status)
def wait_for_server_termination(self, server_id, ignore_error=False):
"""Waits for server to reach termination."""
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index 6f17611..bf72bdc 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -22,6 +22,7 @@
from lxml import etree
from tempest.common.rest_client import RestClientXML
+from tempest.common import waiters
from tempest import exceptions
from tempest.openstack.common import log as logging
from tempest.services.compute.xml.common import Document
@@ -336,28 +337,7 @@
def wait_for_server_status(self, server_id, status):
"""Waits for a server to reach a given status."""
- resp, body = self.get_server(server_id)
- server_status = body['status']
- start = int(time.time())
-
- while(server_status != status):
- if status == 'BUILD' and server_status != 'UNKNOWN':
- return
- time.sleep(self.build_interval)
- resp, body = self.get_server(server_id)
- server_status = body['status']
-
- if server_status == 'ERROR':
- raise exceptions.BuildErrorException(server_id=server_id)
-
- timed_out = int(time.time()) - start >= self.build_timeout
-
- if server_status != status and timed_out:
- message = ('Server %s failed to reach %s status within the '
- 'required time (%s s).' %
- (server_id, status, self.build_timeout))
- message += ' Current status: %s.' % server_status
- raise exceptions.TimeoutException(message)
+ return waiters.wait_for_server_status(self, server_id, status)
def wait_for_server_termination(self, server_id, ignore_error=False):
"""Waits for server to reach termination."""