Repository: ansible/molecule

Issue:
Openstack instances get created sequentially
# Issue Type

- Bug report

Right now molecule creates  Openstack instances sequentially, waits until the instance was fully created and can be reached via SSH, then proceeds to the next instance. This is very time consuming.

Instead, the Openstack driver should just create all instances without waiting and afterwards wait until it can reach them all.


Discussion:
Moving the snippet where it checks for ssh availability to another for loop would resolve this. 

``` python

for instance in self.instances:
                ... 
                while not self._check_ssh_availability(
                        server['interface_ip'],
                        instance['sshuser'],
                        timeout=6,
                        sshkey_filename=self._get_keyfile(
                        )) or num_retries == 5:
                    util.print_info('\t Waiting for ssh availability...')
                    num_retries += 1
```
Yeah, I was playing around with the code a little yesterday, but found a couple more issues so I didn't really get anything done.

I think we would probably need three loops: One that creates the instances without `wait: True`, a second one that attaches an address to them and a third one for the availability check.
Unfortunately this will need addressed by someone in the community who uses the Openstack driver.  I do not use this driver, nor can I test it at the moment, so someone will need to tackle this if willing.

Resolving patch:
diff --git a/molecule/driver/openstackdriver.py b/molecule/driver/openstackdriver.py
--- a/molecule/driver/openstackdriver.py
+++ b/molecule/driver/openstackdriver.py
@@ -117,7 +117,7 @@ def up(self, no_provision=True):
 
         active_instances = self._openstack.list_servers()
         active_instance_names = {
-            instance['name']: instance['status']
+            instance['name']: instance['interface_ip']
             for instance in active_instances
         }
 
@@ -144,7 +144,7 @@ def up(self, no_provision=True):
                     image=self._openstack.get_image(instance['image']),
                     flavor=self._openstack.get_flavor(instance['flavor']),
                     auto_ip=True,
-                    wait=True,
+                    wait=False,
                     key_name=kpn,
                     ip_pool=instance.get('ip_pool')
                     if instance.get('ip_pool') else self.ip_pool,
@@ -152,23 +152,39 @@ def up(self, no_provision=True):
                     security_groups=instance.get('security_groups', []))
                 instance['created'] = True
                 instance['reachable'] = False
+                instance['server'] = server
+            else:
+                instance['address'] = active_instance_names[instance['name']]
+                instance['reachable'] = True
+
+        for instance in self.instances:
+            if not instance.get('server'):
+                instance['server'] = self._openstack.get_server(instance['name'])
+            if not instance.get('address'):
+                util.print_info('\t Waiting for instance %s to be in state active...'
+                                % instance['name'])
+                server = self._openstack.wait_for_server(instance['server'],
+                                                         auto_ip=True)
+                instance['address'] = server['interface_ip']
 
-                for _ in range(ssh_timeout):
-                    util.print_info('\t Waiting for ssh availability...')
-                    if self._check_ssh_availability(
-                            server['interface_ip'],
-                            instance['sshuser'],
-                            timeout=1,
-                            sshkey_filename=self._get_keyfile()):
-                        instance['reachable'] = True
-                        break
-                if not instance['reachable']:
-                    util.print_error(
-                        'Could not reach instance "%s"'
-                        ' within limit of %s seconds' %
-                        (instance['name'],
-                         instance.get('ssh_timeout', self.ssh_timeout)))
-                    util.sysexit()
+        for instance in self.instances:
+            for _ in range(ssh_timeout):
+                util.print_info('\t  Waiting for ssh availability of instance %s...'
+                        % instance['name'])
+                if self._check_ssh_availability(
+                        instance['address'],
+                        instance['sshuser'],
+                        timeout=1,
+                        sshkey_filename=self._get_keyfile()):
+                    instance['reachable'] = True
+                    break
+            if not instance['reachable']:
+                util.print_error(
+                    'Could not reach instance "%s"'
+                    ' within limit of %s seconds' %
+                    (instance['name'],
+                     instance.get('ssh_timeout', self.ssh_timeout)))
+                util.sysexit()
 
     def destroy(self):
         util.print_info('Deleting openstack instances...')


Test patch: