docs: def start(self, min_nodes=None):
          """
          Starts up all the instances in the cloud.
  
          To speed things up, all
          instances are started in a seperate thread. To make sure
          ElastiCluster is not stopped during creation of an instance, it will
          overwrite the sigint handler. As soon as the last started instance
          is returned and saved to the repository, sigint is executed as usual.
  
          A VM instance is considered 'up and running' as soon as an SSH
          connection can be established. If the startup timeout is reached before
          all instances are started, ElastiCluster stops the cluster and
          terminates all VM instances.
  
          This method is blocking and might take some time depending on the
          amount of instances to start.
  
          :param min_nodes: minimum number of nodes to start in case the quota
                            is reached before all instances are up
          :type min_nodes: dict [node_kind] = number
          """
  
          nodes = self.get_all_nodes()
  
          log.info("Starting cluster nodes ...")
          if log.DO_NOT_FORK:
              nodes = self._start_nodes_sequentially(nodes)
          else:
              nodes = self._start_nodes_parallel(nodes, self.thread_pool_max_size)
  
          # checkpoint cluster state
          self.repository.save_or_update(self)
  
          not_started_nodes = self._check_starting_nodes(nodes, self.startup_timeout)
  
          # now that all nodes are up, checkpoint cluster state again
          self.repository.save_or_update(self)
  
          # Try to connect to each node to gather IP addresses and SSH host keys
          log.info("Checking SSH connection to nodes ...")
          pending_nodes = nodes - not_started_nodes
          self._gather_node_ip_addresses(pending_nodes, self.startup_timeout)
  
          # It might be possible that the node.connect() call updated
          # the `preferred_ip` attribute, so, let's save the cluster
          # again.
          self.repository.save_or_update(self)
  
          # A lot of things could go wrong when starting the cluster. To
          # ensure a stable cluster fitting the needs of the user in terms of
          # cluster size, we check the minimum nodes within the node groups to
          # match the current setup.
          min_nodes = self._compute_min_nodes(min_nodes)
          self._check_cluster_size(min_nodes)