Create a new machine on the given cloud

        :param name: Name of the machine
        :param key: Key Object to associate with the machine
        :param image_id: Id of image to be used with the creation
        :param location_id: Id of the cloud's location to create the machine
        :param size_id: If of the size of the machine
        :param image_extra: Needed only by Linode cloud
        :param disk: Needed only by Linode cloud
        :returns: An update list of added machines

def create_machine(self, name, key, image_id, location_id, size_id,
                       image_extra="", disk="", script="", monitoring=False,
                       ips=[], networks=[], location_name="", async=False,
                       docker_command="", quantity=1, persist=False, fire_and_forget=True,
                       timeout=6000, script_id="", script_params="", verbose=False,
                       associate_floating_ip=False, provider="", tags=None,
                       cloud_init='', env_vars=''):
        """
        Create a new machine on the given cloud

        :param name: Name of the machine
        :param key: Key Object to associate with the machine
        :param image_id: Id of image to be used with the creation
        :param location_id: Id of the cloud's location to create the machine
        :param size_id: If of the size of the machine
        :param image_extra: Needed only by Linode cloud
        :param disk: Needed only by Linode cloud
        :returns: An update list of added machines
        """
        if isinstance(key, basestring):
            key_id = key
        else:
            key_id = key.id

        payload = {
            'name': name,
            'provider': provider,
            'key': key_id,
            'image': image_id,
            'location': location_id,
            'size': size_id,
            'image_extra': image_extra,
            'disk': disk,
            'script': script,
            'monitoring': monitoring,
            'ips': ips,
            'networks': networks,
            'location_name': location_name,
            'docker_command': docker_command,
            'async': async,
            'quantity': quantity,
            'persist': persist,
            'associate_floating_ip': associate_floating_ip,
            'tags': tags,
            'cloud_init': cloud_init,
            'env_vars':  env_vars
        }
        # add as params only if they are provided
        if script_id:
            payload['script_id'] = script_id
        if script_params:
            payload['script_params'] = script_params
        data = json.dumps(payload)
        req = self.request(self.mist_client.uri+'/clouds/'+self.id+'/machines', data=data)
        result = req.post()
        self.update_machines()

        if not async or fire_and_forget:
            return result.json()
        else:
            job_id = result.json()['job_id']

            started_at = time()
            while True:
                job = self.mist_client.get_job(job_id)

                if verbose:
                    summary = job.get('summary', {})

                    probes = summary.get('probe', {})
                    creates = summary.get('create', {})
                    scripts = summary.get('script', {})
                    monitoring = summary.get('monitoring', {})

                    states = [
                        'success',
                        'error',
                        'skipped',
                        'pending'
                    ]

                    x = PrettyTable(['', 'SUCCESS', 'ERROR', 'SKIPPED', 'PENDING'])

                    if creates:
                        machines_created = {}
                        for state in states:
                            machines_created[state] = '%s/%s' % (creates.get(state, 'Undefined'), quantity)
                        x.add_row(["Create:", machines_created['success'], machines_created['error'],
                                   machines_created['skipped'], machines_created['pending']])

                    if probes:
                        probed_machines = {}
                        for state in states:
                            probed_machines[state] = '%s/%s' % (probes.get(state, 'Undefined'), quantity)
                        x.add_row(["Probe:", probed_machines['success'], probed_machines['error'],
                                   probed_machines['skipped'], probed_machines['pending']])

                    if scripts:
                        scripted_machines = {}
                        for state in states:
                            scripted_machines[state] = '%s/%s' % (scripts.get(state, 'Undefined'), quantity)
                        x.add_row(["Script:", scripted_machines['success'], scripted_machines['error'],
                                   scripted_machines['skipped'], scripted_machines['pending']])

                    if monitoring:
                        monitored_machines = {}
                        for state in states:
                            monitored_machines[state] = '%s/%s' % (monitoring.get(state, 'Undefined'), quantity)
                        x.add_row(["Monitoring:", monitored_machines['success'], monitored_machines['error'],
                                   monitored_machines['skipped'], monitored_machines['pending']])

                    print x
                    print

                if job.get('finished_at', 0):
                    provision_finished = True
                else:
                    # In case of nested logs, we have to make sure we parse the
                    # the logs correctly in order to determine whether the
                    # provisioned VM is running, since a story may contain logs
                    # of multiple machines
                    for log in job.get('logs', []):
                        if log.get('machine_name', '') == name and \
                            'machine_creation_finished' in log.values():
                            machine_id = log['machine_id']
                            error = log.get('error')
                            break
                    else:
                        sleep(5)
                        continue

                    if error:
                        provision_finished = True
                    else:
                        for log in job.get('logs', []):
                            if log.get('machine_id', '') == machine_id and \
                                'post_deploy_finished' in log.values():
                                provision_finished = True
                                break
                        else:
                            provision_finished = False

                if provision_finished:
                    error = job.get('error')
                    if error:
                        print "Finished with errors:"
                        logs = job.get('logs', [])
                        for log in logs:
                            error = log.get('error')
                            if error:
                                print " - ", error
                        raise Exception("Create machine failed. Check the logs.")
                    elif verbose and not error:
                        print "Finished without errors!"
                    self.update_machines()
                    return job

                elif time() - started_at > timeout:
                    print "Timed out!"
                    raise Exception("Create machine timed out. Check the logs.")
                    return job

                sleep(5)