def vm_present(name, vmconfig, config=None):
    '''
    Ensure vm is present on the computenode

    name : string
        hostname of vm
    vmconfig : dict
        options to set for the vm
    config : dict
        fine grain control over vm_present

    .. note::

        The following configuration properties can be toggled in the config parameter.
          - kvm_reboot (true) - reboots of kvm zones if needed for a config update
          - auto_import (false) - automatic importing of missing images
          - reprovision (false) - reprovision on image_uuid changes

    .. note::

        State ID is used as hostname. Hostnames must be unique.

    .. note::

        If hostname is provided in vmconfig this will take president over the State ID.
        This allows multiple states to be applied to the same vm.

    .. note::

        The following instances should have a unique ID.
          - nic : mac
          - filesystem: target
          - disk : path or diskN for zvols

        e.g. disk0 will be the first disk added, disk1 the 2nd,...

    '''
    name = name.lower()
    ret = {'name': name,
           'changes': {},
           'result': None,
           'comment': ''}

    # config defaults
    state_config = config if config else {}
    config = {
        'kvm_reboot': True,
        'auto_import': False,
        'reprovision': False
    }
    config.update(state_config)
    log.debug('smartos.vm_present::{0}::config - {1}'.format(name, config))

    # map special vmconfig parameters
    #  collections have set/remove handlers
    #  instances have add/update/remove handlers and a unique id
    vmconfig_type = {
        'collection': [
            'tags',
            'customer_metadata',
            'internal_metadata',
            'routes'
        ],
        'instance': {
            'nics': 'mac',
            'disks': 'path',
            'filesystems': 'target'
        },
        'create_only': [
            'filesystems'
        ]
    }

    # parse vmconfig
    vmconfig = _parse_vmconfig(vmconfig, vmconfig_type['instance'])
    log.debug('smartos.vm_present::{0}::vmconfig - {1}'.format(name, vmconfig))

    # set hostname if needed
    if 'hostname' not in vmconfig:
        vmconfig['hostname'] = name

    # check if vm exists
    if vmconfig['hostname'] in __salt__['vmadm.list'](order='hostname'):
        # update vm
        ret['result'] = True

        # expand vmconfig
        vmconfig = {
            'state': vmconfig,
            'current': __salt__['vmadm.get'](vmconfig['hostname'], key='hostname'),
            'changed': {},
            'reprovision_uuid': None
        }

        # prepare reprovision
        if 'image_uuid' in vmconfig['state']:
            vmconfig['reprovision_uuid'] = vmconfig['state']['image_uuid']
            vmconfig['state']['image_uuid'] = vmconfig['current']['image_uuid']

        # disks need some special care
        if 'disks' in vmconfig['state']:
            new_disks = []
            for disk in vmconfig['state']['disks']:
                path = False
                if 'disks' in vmconfig['current']:
                    for cdisk in vmconfig['current']['disks']:
                        if cdisk['path'].endswith(disk['path']):
                            path = cdisk['path']
                            break
                if not path:
                    del disk['path']
                else:
                    disk['path'] = path
                new_disks.append(disk)
            vmconfig['state']['disks'] = new_disks

        # process properties
        for prop in vmconfig['state']:
            # skip special vmconfig_types
            if prop in vmconfig_type['instance'] or \
                prop in vmconfig_type['collection'] or \
                prop in vmconfig_type['create_only']:
                continue

            # skip unchanged properties
            if prop in vmconfig['current']:
                if isinstance(vmconfig['current'][prop], (list)) or isinstance(vmconfig['current'][prop], (dict)):
                    if vmconfig['current'][prop] == vmconfig['state'][prop]:
                        continue
                else:
                    if "{0}".format(vmconfig['current'][prop]) == "{0}".format(vmconfig['state'][prop]):
                        continue

            # add property to changeset
            vmconfig['changed'][prop] = vmconfig['state'][prop]

        # process collections
        for collection in vmconfig_type['collection']:
            # skip create only collections
            if collection in vmconfig_type['create_only']:
                continue

            # process add and update for collection
            if collection in vmconfig['state'] and vmconfig['state'][collection] is not None:
                for prop in vmconfig['state'][collection]:
                    # skip unchanged properties
                    if prop in vmconfig['current'][collection] and \
                        vmconfig['current'][collection][prop] == vmconfig['state'][collection][prop]:
                        continue

                    # create set_ dict
                    if 'set_{0}'.format(collection) not in vmconfig['changed']:
                        vmconfig['changed']['set_{0}'.format(collection)] = {}

                    # add property to changeset
                    vmconfig['changed']['set_{0}'.format(collection)][prop] = vmconfig['state'][collection][prop]

            # process remove for collection
            if collection in vmconfig['current'] and vmconfig['current'][collection] is not None:
                for prop in vmconfig['current'][collection]:
                    # skip if exists in state
                    if collection in vmconfig['state'] and vmconfig['state'][collection] is not None:
                        if prop in vmconfig['state'][collection]:
                            continue

                    # create remove_ array
                    if 'remove_{0}'.format(collection) not in vmconfig['changed']:
                        vmconfig['changed']['remove_{0}'.format(collection)] = []

                    # remove property
                    vmconfig['changed']['remove_{0}'.format(collection)].append(prop)

        # process instances
        for instance in vmconfig_type['instance']:
            # skip create only instances
            if instance in vmconfig_type['create_only']:
                continue

            # add or update instances
            if instance in vmconfig['state'] and vmconfig['state'][instance] is not None:
                for state_cfg in vmconfig['state'][instance]:
                    add_instance = True

                    # find instance with matching ids
                    for current_cfg in vmconfig['current'][instance]:
                        if vmconfig_type['instance'][instance] not in state_cfg:
                            continue

                        if state_cfg[vmconfig_type['instance'][instance]] == current_cfg[vmconfig_type['instance'][instance]]:
                            # ids have matched, disable add instance
                            add_instance = False

                            changed = _get_instance_changes(current_cfg, state_cfg)
                            update_cfg = {}

                            # handle changes
                            if len(changed) > 0:
                                for prop in changed:
                                    update_cfg[prop] = state_cfg[prop]

                            # handle new properties
                            for prop in state_cfg:
                                # skip empty props like ips, options,..
                                if isinstance(state_cfg[prop], (list)) and len(state_cfg[prop]) == 0:
                                    continue

                                if prop not in current_cfg:
                                    update_cfg[prop] = state_cfg[prop]

                            # update instance
                            if len(update_cfg) > 0:
                                # create update_ array
                                if 'update_{0}'.format(instance) not in vmconfig['changed']:
                                    vmconfig['changed']['update_{0}'.format(instance)] = []

                                update_cfg[vmconfig_type['instance'][instance]] = state_cfg[vmconfig_type['instance'][instance]]
                                vmconfig['changed']['update_{0}'.format(instance)].append(update_cfg)

                    if add_instance:
                        # create add_ array
                        if 'add_{0}'.format(instance) not in vmconfig['changed']:
                            vmconfig['changed']['add_{0}'.format(instance)] = []

                        # add instance
                        vmconfig['changed']['add_{0}'.format(instance)].append(state_cfg)

            # remove instances
            if instance in vmconfig['current'] and vmconfig['current'][instance] is not None:
                for current_cfg in vmconfig['current'][instance]:
                    remove_instance = True

                    # find instance with matching ids
                    if instance in vmconfig['state'] and vmconfig['state'][instance] is not None:
                        for state_cfg in vmconfig['state'][instance]:
                            if vmconfig_type['instance'][instance] not in state_cfg:
                                continue

                            if state_cfg[vmconfig_type['instance'][instance]] == current_cfg[vmconfig_type['instance'][instance]]:
                                # keep instance if matched
                                remove_instance = False

                    if remove_instance:
                        # create remove_ array
                        if 'remove_{0}'.format(instance) not in vmconfig['changed']:
                            vmconfig['changed']['remove_{0}'.format(instance)] = []

                        # remove instance
                        vmconfig['changed']['remove_{0}'.format(instance)].append(
                            current_cfg[vmconfig_type['instance'][instance]]
                        )

        # update vm if we have pending changes
        kvm_needs_start = False
        if not __opts__['test'] and len(vmconfig['changed']) > 0:
            # stop kvm if disk updates and kvm_reboot
            if vmconfig['current']['brand'] == 'kvm' and config['kvm_reboot']:
                if 'add_disks' in vmconfig['changed'] or \
                    'update_disks' in vmconfig['changed'] or \
                    'remove_disks' in vmconfig['changed']:
                    if vmconfig['state']['hostname'] in __salt__['vmadm.list'](order='hostname', search='state=running'):
                        kvm_needs_start = True
                        __salt__['vmadm.stop'](vm=vmconfig['state']['hostname'], key='hostname')

            # do update
            rret = __salt__['vmadm.update'](vm=vmconfig['state']['hostname'], key='hostname', **vmconfig['changed'])
            if not isinstance(rret, (bool)) and 'Error' in rret:
                ret['result'] = False
                ret['comment'] = "{0}".format(rret['Error'])
            else:
                ret['result'] = True
                ret['changes'][vmconfig['state']['hostname']] = vmconfig['changed']

        if ret['result']:
            if __opts__['test']:
                ret['changes'][vmconfig['state']['hostname']] = vmconfig['changed']

            if vmconfig['state']['hostname'] in ret['changes'] and len(ret['changes'][vmconfig['state']['hostname']]) > 0:
                ret['comment'] = 'vm {0} updated'.format(vmconfig['state']['hostname'])
                if config['kvm_reboot'] and vmconfig['current']['brand'] == 'kvm' and not __opts__['test']:
                    if vmconfig['state']['hostname'] in __salt__['vmadm.list'](order='hostname', search='state=running'):
                        __salt__['vmadm.reboot'](vm=vmconfig['state']['hostname'], key='hostname')
                    if kvm_needs_start:
                        __salt__['vmadm.start'](vm=vmconfig['state']['hostname'], key='hostname')
            else:
                ret['changes'] = {}
                ret['comment'] = 'vm {0} is up to date'.format(vmconfig['state']['hostname'])

            if 'image_uuid' in vmconfig['current'] and vmconfig['reprovision_uuid'] != vmconfig['current']['image_uuid']:
                if config['reprovision']:
                    # check required image installed
                    if vmconfig['reprovision_uuid'] not in __salt__['imgadm.list']():
                        if config['auto_import']:
                            # check if image is available
                            available_images = __salt__['imgadm.avail']()
                            if vmconfig['reprovision_uuid'] in available_images and not __opts__['test']:
                                # import image
                                __salt__['imgadm.import'](vmconfig['reprovision_uuid'])

                    # reprovision
                    rret = __salt__['vmadm.reprovision'](
                        vm=vmconfig['state']['hostname'],
                        key='hostname',
                        image=vmconfig['reprovision_uuid']
                    )
                    if not isinstance(rret, (bool)) and 'Error' in rret:
                        ret['result'] = False
                        if vmconfig['reprovision_uuid'] not in __salt__['imgadm.list']():
                            ret['comment'] = 'vm {0} updated, reprovision failed because images {1} not installed'.format(
                                vmconfig['state']['hostname'],
                                vmconfig['reprovision_uuid']
                            )
                        else:
                            ret['comment'] = 'vm {0} updated, reprovision failed'.format(
                                vmconfig['state']['hostname']
                            )
                    else:
                        ret['comment'] = 'vm {0} updated and reprovisioned'.format(vmconfig['state']['hostname'])
                        if vmconfig['state']['hostname'] not in ret['changes']:
                            ret['changes'][vmconfig['state']['hostname']] = {}
                        ret['changes'][vmconfig['state']['hostname']]['image_uuid'] = vmconfig['reprovision_uuid']
                else:
                    log.warning('smartos.vm_present::{0}::reprovision - image_uuid in state does not match current, reprovision not allowed'.format(
                        name
                    ))
        else:
            ret['comment'] = 'vm {0} failed to be updated'.format(vmconfig['state']['hostname'])
            if not isinstance(rret, (bool)) and rret in 'Error':
                ret['comment'] = "{0}".format(rret['Error'])
    else:
        # check required image installed
        ret['result'] = True
        if 'image_uuid' in vmconfig and vmconfig['image_uuid'] not in __salt__['imgadm.list']():
            if config['auto_import']:
                # check if image is available
                available_images = __salt__['imgadm.avail']()
                if vmconfig['image_uuid'] not in available_images:
                    ret['result'] = False
                    ret['comment'] = 'image {0} not available'.format(vmconfig['image_uuid'])
                elif not __opts__['test']:
                    if vmconfig['image_uuid'] not in __salt__['imgadm.import'](vmconfig['image_uuid']):
                        ret['result'] = False
                        ret['comment'] = 'failed to import image {0}'.format(vmconfig['image_uuid'])
            else:
                ret['result'] = False
                ret['comment'] = 'image {0} not installed'.format(vmconfig['image_uuid'])

        # disks need some special care
        if 'disks' in vmconfig:
            new_disks = []
            for disk in vmconfig['disks']:
                if 'path' in disk:
                    del disk['path']
                new_disks.append(disk)
            vmconfig['disks'] = new_disks

        # create vm
        if ret['result']:
            uuid = __salt__['vmadm.create'](**vmconfig) if not __opts__['test'] else True
            if not isinstance(uuid, (bool)) and 'Error' in uuid:
                ret['result'] = False
                ret['comment'] = "{0}".format(uuid['Error'])
            else:
                ret['result'] = True
                ret['changes'][vmconfig['hostname']] = vmconfig
                ret['comment'] = 'vm {0} created'.format(vmconfig['hostname'])

    return ret
dataset/ETHPy150Open saltstack/salt/salt/states/smartos.py/vm_present/swapped operands of `in`