diff --git a/VERSION b/VERSION index c37d1232..3f7d43ca 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1!10.6.1 +1!10.7.0 diff --git a/pycloudlib/ec2/instance.py b/pycloudlib/ec2/instance.py index e928f29f..62ac43db 100644 --- a/pycloudlib/ec2/instance.py +++ b/pycloudlib/ec2/instance.py @@ -15,6 +15,7 @@ class EC2Instance(BaseInstance): """EC2 backed instance.""" _type = "ec2" + ready_timeout = 40 # To keep backwards compatibility (will lower soon) def __init__(self, key_pair, client, instance, *, username: Optional[str] = None): """Set up instance. diff --git a/pycloudlib/ibm_classic/instance.py b/pycloudlib/ibm_classic/instance.py index addfa356..9f668abd 100644 --- a/pycloudlib/ibm_classic/instance.py +++ b/pycloudlib/ibm_classic/instance.py @@ -285,13 +285,6 @@ def is_started(): logger.info("Instance %s started", self.name) self._instance = self._vs_manager.get_instance(self.id) - def wait(self, **kwargs): - """Wait for instance to be up and cloud-init to be complete.""" - logger.info("Waiting for instance %s to be ready", self.name) - self._wait_for_instance_start(**kwargs) - self._wait_for_execute(timeout=180) - self._wait_for_cloudinit() - def wait_for_restart(self, old_boot_id): """Wait for instance to be restarted and cloud-init to be complete. diff --git a/pycloudlib/instance.py b/pycloudlib/instance.py index 63a0aa75..e8d234ff 100644 --- a/pycloudlib/instance.py +++ b/pycloudlib/instance.py @@ -26,6 +26,7 @@ class BaseInstance(ABC): """Base instance object.""" _type = "base" + ready_timeout = 10 # Time to wait for instance to be ready after provisioning (in minutes) def __init__(self, key_pair, username: Optional[str] = None): """Set up instance.""" @@ -160,10 +161,23 @@ def _wait_for_instance_start(self, **kwargs): detecting when an instance has started through their API. """ - def wait(self, **kwargs): - """Wait for instance to be up and cloud-init to be complete.""" + def wait( + self, + ready_timeout: Optional[int] = None, + **kwargs, + ): + """ + Wait for instance to be up and cloud-init to be complete. + + Args: + ready_timeout (int): maximum time to wait for the instance to be ready for ssh after + instance provisioning is complete + + Raises: + PycloudlibTimeoutError: If the instance is not ready after the timeout + """ self._wait_for_instance_start(**kwargs) - self._wait_for_execute() + self._wait_for_execute(timeout=ready_timeout) self._wait_for_cloudinit() def wait_for_restart(self, old_boot_id): @@ -478,7 +492,7 @@ def _tmpfile(self): self._tmp_count += 1 return path - def _wait_for_execute(self, old_boot_id=None, timeout: int = 40): + def _wait_for_execute(self, old_boot_id=None, timeout: Optional[int] = None): """ Wait until we can execute a command in the instance. @@ -492,9 +506,7 @@ def _wait_for_execute(self, old_boot_id=None, timeout: int = 40): """ self._log.info("_wait_for_execute to complete") - # Wait 40 minutes before failing. AWS EC2 metal instances can take - # over 20 minutes to start or restart, so we shouldn't lower - # this timeout + timeout = timeout or self.ready_timeout start = time.time() end = start + timeout * 60 while time.time() < end: diff --git a/tests/unit_tests/test_instance.py b/tests/unit_tests/test_instance.py index 5a01ff1d..4f7884a2 100644 --- a/tests/unit_tests/test_instance.py +++ b/tests/unit_tests/test_instance.py @@ -67,9 +67,9 @@ def test_wait_execute_failure( ): """Test wait calls when execute command fails.""" instance = concrete_instance_cls(key_pair=None) - m_time.side_effect = [1, 1, 2, 40 * 60, 40 * 60 + 1] + m_time.side_effect = [1, 1, 2, 10 * 60, 10 * 60 + 1] m_execute.side_effect = execute_effect - expected_msg = "Instance can't be reached after 40 minutes. Failed to obtain new boot id" + expected_msg = "Instance can't be reached after 10 minutes. Failed to obtain new boot id" expected_call_args = [mock.call("cat /proc/sys/kernel/random/boot_id", no_log=True)] * 2 with pytest.raises(PycloudlibTimeoutError) as excinfo: @@ -190,8 +190,8 @@ def test_boot_id_failure( """Test wait calls when execute command fails.""" m_execute.side_effect = execute_side_effect instance = concrete_instance_cls(key_pair=None) - m_time.side_effect = [1, 1, 2, 40 * 60, 40 * 60 + 1] - expected_msg = "Instance can't be reached after 40 minutes. Failed to obtain new boot id" + m_time.side_effect = [1, 1, 2, 10 * 60, 10 * 60 + 1] + expected_msg = "Instance can't be reached after 10 minutes. Failed to obtain new boot id" expected_call_args = [mock.call("cat /proc/sys/kernel/random/boot_id", no_log=True)] * 2 with pytest.raises(PycloudlibTimeoutError) as excinfo: