add custom virt module
diff --git a/_modules/virt_ng.py b/_modules/virt_ng.py
new file mode 100644
index 0000000..4c55e22
--- /dev/null
+++ b/_modules/virt_ng.py
@@ -0,0 +1,1784 @@
+# -*- coding: utf-8 -*-
+'''
+Work with virtual machines managed by libvirt
+
+:depends: libvirt Python module
+'''
+# Special Thanks to Michael Dehann, many of the concepts, and a few structures
+# of his in the virt func module have been used
+
+# Import python libs
+from __future__ import absolute_import
+import os
+import re
+import sys
+import shutil
+import subprocess
+import string  # pylint: disable=deprecated-module
+import logging
+
+# Import third party libs
+import yaml
+import jinja2
+import jinja2.exceptions
+import salt.ext.six as six
+from salt.ext.six.moves import StringIO as _StringIO  # pylint: disable=import-error
+from xml.dom import minidom
+try:
+    import libvirt  # pylint: disable=import-error
+    HAS_ALL_IMPORTS = True
+except ImportError:
+    HAS_ALL_IMPORTS = False
+
+# Import salt libs
+import salt.utils
+import salt.utils.files
+import salt.utils.templates
+import salt.utils.validate.net
+from salt.exceptions import CommandExecutionError, SaltInvocationError
+
+log = logging.getLogger(__name__)
+
+# Set up template environment
+JINJA = jinja2.Environment(
+    loader=jinja2.FileSystemLoader(
+        os.path.join(salt.utils.templates.TEMPLATE_DIRNAME, 'virt')
+    )
+)
+
+VIRT_STATE_NAME_MAP = {0: 'running',
+                       1: 'running',
+                       2: 'running',
+                       3: 'paused',
+                       4: 'shutdown',
+                       5: 'shutdown',
+                       6: 'crashed'}
+
+VIRT_DEFAULT_HYPER = 'kvm'
+
+
+def __virtual__():
+    if not HAS_ALL_IMPORTS:
+        return False
+    return 'virt'
+
+
+def __get_conn():
+    '''
+    Detects what type of dom this node is and attempts to connect to the
+    correct hypervisor via libvirt.
+    '''
+    # This has only been tested on kvm and xen, it needs to be expanded to
+    # support all vm layers supported by libvirt
+
+    def __esxi_uri():
+        '''
+        Connect to an ESXi host with a configuration like so:
+
+        .. code-block:: yaml
+
+            libvirt:
+              hypervisor: esxi
+              connection: esx01
+
+        The connection setting can either be an explicit libvirt URI,
+        or a libvirt URI alias as in this example. No, it cannot be
+        just a hostname.
+
+
+        Example libvirt `/etc/libvirt/libvirt.conf`:
+
+        .. code-block::
+
+            uri_aliases = [
+              "esx01=esx://10.1.1.101/?no_verify=1&auto_answer=1",
+              "esx02=esx://10.1.1.102/?no_verify=1&auto_answer=1",
+            ]
+
+        Reference:
+
+         - http://libvirt.org/drvesx.html#uriformat
+         - http://libvirt.org/uri.html#URI_config
+        '''
+        connection = __salt__['config.get']('libvirt:connection', 'esx')
+        return connection
+
+    def __esxi_auth():
+        '''
+        We rely on that the credentials is provided to libvirt through
+        its built in mechanisms.
+
+        Example libvirt `/etc/libvirt/auth.conf`:
+
+        .. code-block::
+
+            [credentials-myvirt]
+            username=user
+            password=secret
+
+            [auth-esx-10.1.1.101]
+            credentials=myvirt
+
+            [auth-esx-10.1.1.102]
+            credentials=myvirt
+
+        Reference:
+
+          - http://libvirt.org/auth.html#Auth_client_config
+        '''
+        return [[libvirt.VIR_CRED_EXTERNAL], lambda: 0, None]
+
+    if 'virt.connect' in __opts__:
+        conn_str = __opts__['virt.connect']
+    else:
+        conn_str = 'qemu:///system'
+
+    conn_func = {
+        'esxi': [libvirt.openAuth, [__esxi_uri(),
+                                    __esxi_auth(),
+                                    0]],
+        'qemu': [libvirt.open, [conn_str]],
+        }
+
+    hypervisor = __salt__['config.get']('libvirt:hypervisor', 'qemu')
+
+    try:
+        conn = conn_func[hypervisor][0](*conn_func[hypervisor][1])
+    except Exception:
+        raise CommandExecutionError(
+            'Sorry, {0} failed to open a connection to the hypervisor '
+            'software at {1}'.format(
+                __grains__['fqdn'],
+                conn_func[hypervisor][1][0]
+            )
+        )
+    return conn
+
+
+def _get_dom(vm_):
+    '''
+    Return a domain object for the named vm
+    '''
+    conn = __get_conn()
+    if vm_ not in list_vms():
+        raise CommandExecutionError('The specified vm is not present')
+    return conn.lookupByName(vm_)
+
+
+def _libvirt_creds():
+    '''
+    Returns the user and group that the disk images should be owned by
+    '''
+    g_cmd = 'grep ^\\s*group /etc/libvirt/qemu.conf'
+    u_cmd = 'grep ^\\s*user /etc/libvirt/qemu.conf'
+    try:
+        group = subprocess.Popen(g_cmd,
+            shell=True,
+            stdout=subprocess.PIPE).communicate()[0].split('"')[1]
+    except IndexError:
+        group = 'root'
+    try:
+        user = subprocess.Popen(u_cmd,
+            shell=True,
+            stdout=subprocess.PIPE).communicate()[0].split('"')[1]
+    except IndexError:
+        user = 'root'
+    return {'user': user, 'group': group}
+
+
+def _get_migrate_command():
+    '''
+    Returns the command shared by the different migration types
+    '''
+    if __salt__['config.option']('virt.tunnel'):
+        return ('virsh migrate --p2p --tunnelled --live --persistent '
+                '--undefinesource ')
+    return 'virsh migrate --live --persistent --undefinesource '
+
+
+def _get_target(target, ssh):
+    proto = 'qemu'
+    if ssh:
+        proto += '+ssh'
+    return ' {0}://{1}/{2}'.format(proto, target, 'system')
+
+
+def _gen_xml(name,
+             cpu,
+             mem,
+             diskp,
+             nicp,
+             hypervisor,
+             **kwargs):
+    '''
+    Generate the XML string to define a libvirt vm
+    '''
+    hypervisor = 'vmware' if hypervisor == 'esxi' else hypervisor
+    mem = mem * 1024  # MB
+    context = {
+        'hypervisor': hypervisor,
+        'name': name,
+        'cpu': str(cpu),
+        'mem': str(mem),
+    }
+    if hypervisor in ['qemu', 'kvm']:
+        context['controller_model'] = False
+    elif hypervisor in ['esxi', 'vmware']:
+        # TODO: make bus and model parameterized, this works for 64-bit Linux
+        context['controller_model'] = 'lsilogic'
+
+    if 'boot_dev' in kwargs:
+        context['boot_dev'] = []
+        for dev in kwargs['boot_dev'].split():
+            context['boot_dev'].append(dev)
+    else:
+        context['boot_dev'] = ['hd']
+
+    if 'serial_type' in kwargs:
+        context['serial_type'] = kwargs['serial_type']
+    if 'serial_type' in context and context['serial_type'] == 'tcp':
+        if 'telnet_port' in kwargs:
+            context['telnet_port'] = kwargs['telnet_port']
+        else:
+            context['telnet_port'] = 23023  # FIXME: use random unused port
+    if 'serial_type' in context:
+        if 'console' in kwargs:
+            context['console'] = kwargs['console']
+        else:
+            context['console'] = True
+
+    context['disks'] = {}
+    for i, disk in enumerate(diskp):
+        for disk_name, args in disk.items():
+            context['disks'][disk_name] = {}
+            fn_ = '{0}.{1}'.format(disk_name, args['format'])
+            context['disks'][disk_name]['file_name'] = fn_
+            context['disks'][disk_name]['source_file'] = os.path.join(args['pool'],
+                                                                      name,
+                                                                      fn_)
+            if hypervisor in ['qemu', 'kvm']:
+                context['disks'][disk_name]['target_dev'] = 'vd{0}'.format(string.ascii_lowercase[i])
+                context['disks'][disk_name]['address'] = False
+                context['disks'][disk_name]['driver'] = True
+            elif hypervisor in ['esxi', 'vmware']:
+                context['disks'][disk_name]['target_dev'] = 'sd{0}'.format(string.ascii_lowercase[i])
+                context['disks'][disk_name]['address'] = True
+                context['disks'][disk_name]['driver'] = False
+            context['disks'][disk_name]['disk_bus'] = args['model']
+            context['disks'][disk_name]['type'] = args['format']
+            context['disks'][disk_name]['index'] = str(i)
+
+    context['nics'] = nicp
+
+    fn_ = 'libvirt_domain.jinja'
+    try:
+        template = JINJA.get_template(fn_)
+    except jinja2.exceptions.TemplateNotFound:
+        log.error('Could not load template {0}'.format(fn_))
+        return ''
+
+    return template.render(**context)
+
+
+def _gen_vol_xml(vmname,
+                 diskname,
+                 size,
+                 hypervisor,
+                 **kwargs):
+    '''
+    Generate the XML string to define a libvirt storage volume
+    '''
+    size = int(size) * 1024  # MB
+    disk_info = _get_image_info(hypervisor, vmname, **kwargs)
+    context = {
+        'name': vmname,
+        'filename': '{0}.{1}'.format(diskname, disk_info['disktype']),
+        'volname': diskname,
+        'disktype': disk_info['disktype'],
+        'size': str(size),
+        'pool': disk_info['pool'],
+    }
+    fn_ = 'libvirt_volume.jinja'
+    try:
+        template = JINJA.get_template(fn_)
+    except jinja2.exceptions.TemplateNotFound:
+        log.error('Could not load template {0}'.format(fn_))
+        return ''
+    return template.render(**context)
+
+
+def _qemu_image_info(path):
+    '''
+    Detect information for the image at path
+    '''
+    ret = {}
+    out = __salt__['cmd.run']('qemu-img info {0}'.format(path))
+
+    match_map = {'size': r'virtual size: \w+ \((\d+) byte[s]?\)',
+                 'format': r'file format: (\w+)'}
+
+    for info, search in match_map.items():
+        try:
+            ret[info] = re.search(search, out).group(1)
+        except AttributeError:
+            continue
+    return ret
+
+
+# TODO: this function is deprecated, should be replaced with
+# _qemu_image_info()
+def _image_type(vda):
+    '''
+    Detect what driver needs to be used for the given image
+    '''
+    out = __salt__['cmd.run']('qemu-img info {0}'.format(vda))
+    if 'file format: qcow2' in out:
+        return 'qcow2'
+    else:
+        return 'raw'
+
+
+# TODO: this function is deprecated, should be merged and replaced
+# with _disk_profile()
+def _get_image_info(hypervisor, name, **kwargs):
+    '''
+    Determine disk image info, such as filename, image format and
+    storage pool, based on which hypervisor is used
+    '''
+    ret = {}
+    if hypervisor in ['esxi', 'vmware']:
+        ret['disktype'] = 'vmdk'
+        ret['filename'] = '{0}{1}'.format(name, '.vmdk')
+        ret['pool'] = '[{0}] '.format(kwargs.get('pool', '0'))
+    elif hypervisor in ['kvm', 'qemu']:
+        ret['disktype'] = 'qcow2'
+        ret['filename'] = '{0}{1}'.format(name, '.qcow2')
+        ret['pool'] = __salt__['config.option']('virt.images')
+    return ret
+
+
+def _disk_profile(profile, hypervisor, **kwargs):
+    '''
+    Gather the disk profile from the config or apply the default based
+    on the active hypervisor
+
+    This is the ``default`` profile for KVM/QEMU, which can be
+    overridden in the configuration:
+
+    .. code-block:: yaml
+
+        virt:
+          disk:
+            default:
+              - system:
+                  size: 8192
+                  format: qcow2
+                  model: virtio
+
+    The ``format`` and ``model`` parameters are optional, and will
+    default to whatever is best suitable for the active hypervisor.
+    '''
+    default = [
+          {'system':
+             {'size': '8192'}
+          }
+    ]
+    if hypervisor in ['esxi', 'vmware']:
+        overlay = {'format': 'vmdk',
+                   'model': 'scsi',
+                   'pool': '[{0}] '.format(kwargs.get('pool', '0'))
+                  }
+    elif hypervisor in ['qemu', 'kvm']:
+        overlay = {'format': 'qcow2',
+                   'model': 'virtio',
+                   'pool': __salt__['config.option']('virt.images')
+                  }
+    else:
+        overlay = {}
+
+    disklist = __salt__['config.get']('virt:disk', {}).get(profile, default)
+    for key, val in overlay.items():
+        for i, disks in enumerate(disklist):
+            for disk in disks:
+                if key not in disks[disk]:
+                    disklist[i][disk][key] = val
+    return disklist
+
+
+def _nic_profile(profile_name, hypervisor, **kwargs):
+
+    default = [{'eth0': {}}]
+    vmware_overlay = {'type': 'bridge', 'source': 'DEFAULT', 'model': 'e1000'}
+    kvm_overlay = {'type': 'bridge', 'source': 'br0', 'model': 'virtio'}
+    overlays = {
+            'kvm': kvm_overlay,
+            'qemu': kvm_overlay,
+            'esxi': vmware_overlay,
+            'vmware': vmware_overlay,
+            }
+
+    # support old location
+    config_data = __salt__['config.option']('virt.nic', {}).get(
+        profile_name, None
+    )
+
+    if config_data is None:
+        config_data = __salt__['config.get']('virt:nic', {}).get(
+            profile_name, default
+        )
+
+    interfaces = []
+
+    def append_dict_profile_to_interface_list(profile_dict):
+        for interface_name, attributes in profile_dict.items():
+            attributes['name'] = interface_name
+            interfaces.append(attributes)
+
+    # old style dicts (top-level dicts)
+    #
+    # virt:
+    #    nic:
+    #        eth0:
+    #            bridge: br0
+    #        eth1:
+    #            network: test_net
+    if isinstance(config_data, dict):
+        append_dict_profile_to_interface_list(config_data)
+
+    # new style lists (may contain dicts)
+    #
+    # virt:
+    #   nic:
+    #     - eth0:
+    #         bridge: br0
+    #     - eth1:
+    #         network: test_net
+    #
+    # virt:
+    #   nic:
+    #     - name: eth0
+    #       bridge: br0
+    #     - name: eth1
+    #       network: test_net
+    elif isinstance(config_data, list):
+        for interface in config_data:
+            if isinstance(interface, dict):
+                if len(interface) == 1:
+                    append_dict_profile_to_interface_list(interface)
+                else:
+                    interfaces.append(interface)
+
+    def _normalize_net_types(attributes):
+        '''
+        Guess which style of definition:
+
+            bridge: br0
+
+             or
+
+            network: net0
+
+             or
+
+            type: network
+            source: net0
+        '''
+        for type_ in ['bridge', 'network']:
+            if type_ in attributes:
+                attributes['type'] = type_
+                # we want to discard the original key
+                attributes['source'] = attributes.pop(type_)
+
+        attributes['type'] = attributes.get('type', None)
+        attributes['source'] = attributes.get('source', None)
+
+    def _apply_default_overlay(attributes):
+        for key, value in overlays[hypervisor].items():
+            if key not in attributes or not attributes[key]:
+                attributes[key] = value
+
+    def _assign_mac(attributes):
+        dmac = '{0}_mac'.format(attributes['name'])
+        if dmac in kwargs:
+            dmac = kwargs[dmac]
+            if salt.utils.validate.net.mac(dmac):
+                attributes['mac'] = dmac
+            else:
+                msg = 'Malformed MAC address: {0}'.format(dmac)
+                raise CommandExecutionError(msg)
+        else:
+            attributes['mac'] = salt.utils.gen_mac()
+
+    for interface in interfaces:
+        _normalize_net_types(interface)
+        _assign_mac(interface)
+        if hypervisor in overlays:
+            _apply_default_overlay(interface)
+
+    return interfaces
+
+
+def init(name,
+         cpu,
+         mem,
+         image=None,
+         nic='default',
+         hypervisor=VIRT_DEFAULT_HYPER,
+         start=True,  # pylint: disable=redefined-outer-name
+         disk='default',
+         saltenv='base',
+         **kwargs):
+    '''
+    Initialize a new vm
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt 'hypervisor' virt.init vm_name 4 512 salt://path/to/image.raw
+        salt 'hypervisor' virt.init vm_name 4 512 nic=profile disk=profile
+    '''
+    hypervisor = __salt__['config.get']('libvirt:hypervisor', hypervisor)
+
+    nicp = _nic_profile(nic, hypervisor, **kwargs)
+
+    diskp = None
+    seedable = False
+    if image:  # with disk template image
+        # if image was used, assume only one disk, i.e. the
+        # 'default' disk profile
+        # TODO: make it possible to use disk profiles and use the
+        # template image as the system disk
+        #diskp = _disk_profile('default', hypervisor, **kwargs)
+	#new diskp TCP cloud
+	diskp = _disk_profile(disk, hypervisor, **kwargs)
+        # When using a disk profile extract the sole dict key of the first
+        # array element as the filename for disk
+        disk_name = next(diskp[0].iterkeys())
+        disk_type = diskp[0][disk_name]['format']
+        disk_file_name = '{0}.{1}'.format(disk_name, disk_type)
+	# disk size TCP cloud
+	disk_size = diskp[0][disk_name]['size']
+
+
+        if hypervisor in ['esxi', 'vmware']:
+            # TODO: we should be copying the image file onto the ESX host
+            raise SaltInvocationError('virt.init does not support image '
+                                      'template template in conjunction '
+                                      'with esxi hypervisor')
+        elif hypervisor in ['qemu', 'kvm']:
+            img_dir = __salt__['config.option']('virt.images')
+            img_dest = os.path.join(
+                img_dir,
+                name,
+                disk_file_name
+            )
+            img_dir = os.path.dirname(img_dest)
+            sfn = __salt__['cp.cache_file'](image, saltenv)
+            if not os.path.isdir(img_dir):
+                os.makedirs(img_dir)
+            try:
+                salt.utils.files.copyfile(sfn, img_dest)
+                mask = os.umask(0)
+                os.umask(mask)
+                # Apply umask and remove exec bit
+
+		# Resizing image TCP cloud
+		cmd = 'qemu-img resize ' + img_dest  + ' ' +  str(disk_size) + 'M'
+ 	        subprocess.call(cmd, shell=True)
+		
+                mode = (0o0777 ^ mask) & 0o0666
+                os.chmod(img_dest, mode)
+
+            except (IOError, OSError) as e:
+                raise CommandExecutionError('problem copying image. {0} - {1}'.format(image, e))
+
+            seedable = True
+        else:
+            log.error('unsupported hypervisor when handling disk image')
+
+    else:
+        # no disk template image specified, create disks based on disk profile
+        diskp = _disk_profile(disk, hypervisor, **kwargs)
+        if hypervisor in ['qemu', 'kvm']:
+            # TODO: we should be creating disks in the local filesystem with
+            # qemu-img
+            raise SaltInvocationError('virt.init does not support disk '
+                                      'profiles in conjunction with '
+                                      'qemu/kvm at this time, use image '
+                                      'template instead')
+        else:
+            # assume libvirt manages disks for us
+            for disk in diskp:
+                for disk_name, args in disk.items():
+                    xml = _gen_vol_xml(name,
+                                       disk_name,
+                                       args['size'],
+                                       hypervisor)
+                    define_vol_xml_str(xml)
+
+    xml = _gen_xml(name, cpu, mem, diskp, nicp, hypervisor, **kwargs)
+    define_xml_str(xml)
+
+    if kwargs.get('seed') and seedable:
+        install = kwargs.get('install', True)
+        seed_cmd = kwargs.get('seed_cmd', 'seed.apply')
+
+        __salt__[seed_cmd](img_dest,
+                           id_=name,
+                           config=kwargs.get('config'),
+                           install=install)
+    if start:
+        create(name)
+
+    return True
+
+
+def list_vms():
+    '''
+    Return a list of virtual machine names on the minion
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.list_vms
+    '''
+    vms = []
+    vms.extend(list_active_vms())
+    vms.extend(list_inactive_vms())
+    return vms
+
+
+def list_active_vms():
+    '''
+    Return a list of names for active virtual machine on the minion
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.list_active_vms
+    '''
+    conn = __get_conn()
+    vms = []
+    for id_ in conn.listDomainsID():
+        vms.append(conn.lookupByID(id_).name())
+    return vms
+
+
+def list_inactive_vms():
+    '''
+    Return a list of names for inactive virtual machine on the minion
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.list_inactive_vms
+    '''
+    conn = __get_conn()
+    vms = []
+    for id_ in conn.listDefinedDomains():
+        vms.append(id_)
+    return vms
+
+
+def vm_info(vm_=None):
+    '''
+    Return detailed information about the vms on this hyper in a
+    list of dicts:
+
+    .. code-block:: python
+
+        [
+            'your-vm': {
+                'cpu': <int>,
+                'maxMem': <int>,
+                'mem': <int>,
+                'state': '<state>',
+                'cputime' <int>
+                },
+            ...
+            ]
+
+    If you pass a VM name in as an argument then it will return info
+    for just the named VM, otherwise it will return all VMs.
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.vm_info
+    '''
+    def _info(vm_):
+        dom = _get_dom(vm_)
+        raw = dom.info()
+        return {'cpu': raw[3],
+                'cputime': int(raw[4]),
+                'disks': get_disks(vm_),
+                'graphics': get_graphics(vm_),
+                'nics': get_nics(vm_),
+                'maxMem': int(raw[1]),
+                'mem': int(raw[2]),
+                'state': VIRT_STATE_NAME_MAP.get(raw[0], 'unknown')}
+    info = {}
+    if vm_:
+        info[vm_] = _info(vm_)
+    else:
+        for vm_ in list_vms():
+            info[vm_] = _info(vm_)
+    return info
+
+
+def vm_state(vm_=None):
+    '''
+    Return list of all the vms and their state.
+
+    If you pass a VM name in as an argument then it will return info
+    for just the named VM, otherwise it will return all VMs.
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.vm_state <vm name>
+    '''
+    def _info(vm_):
+        state = ''
+        dom = _get_dom(vm_)
+        raw = dom.info()
+        state = VIRT_STATE_NAME_MAP.get(raw[0], 'unknown')
+        return state
+    info = {}
+    if vm_:
+        info[vm_] = _info(vm_)
+    else:
+        for vm_ in list_vms():
+            info[vm_] = _info(vm_)
+    return info
+
+
+def node_info():
+    '''
+    Return a dict with information about this node
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.node_info
+    '''
+    conn = __get_conn()
+    raw = conn.getInfo()
+    info = {'cpucores': raw[6],
+            'cpumhz': raw[3],
+            'cpumodel': str(raw[0]),
+            'cpus': raw[2],
+            'cputhreads': raw[7],
+            'numanodes': raw[4],
+            'phymemory': raw[1],
+            'sockets': raw[5]}
+    return info
+
+
+def get_nics(vm_):
+    '''
+    Return info about the network interfaces of a named vm
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.get_nics <vm name>
+    '''
+    nics = {}
+    doc = minidom.parse(_StringIO(get_xml(vm_)))
+    for node in doc.getElementsByTagName('devices'):
+        i_nodes = node.getElementsByTagName('interface')
+        for i_node in i_nodes:
+            nic = {}
+            nic['type'] = i_node.getAttribute('type')
+            for v_node in i_node.getElementsByTagName('*'):
+                if v_node.tagName == 'mac':
+                    nic['mac'] = v_node.getAttribute('address')
+                if v_node.tagName == 'model':
+                    nic['model'] = v_node.getAttribute('type')
+                if v_node.tagName == 'target':
+                    nic['target'] = v_node.getAttribute('dev')
+                # driver, source, and match can all have optional attributes
+                if re.match('(driver|source|address)', v_node.tagName):
+                    temp = {}
+                    for key, value in v_node.attributes.items():
+                        temp[key] = value
+                    nic[str(v_node.tagName)] = temp
+                # virtualport needs to be handled separately, to pick up the
+                # type attribute of the virtualport itself
+                if v_node.tagName == 'virtualport':
+                    temp = {}
+                    temp['type'] = v_node.getAttribute('type')
+                    for key, value in v_node.attributes.items():
+                        temp[key] = value
+                    nic['virtualport'] = temp
+            if 'mac' not in nic:
+                continue
+            nics[nic['mac']] = nic
+    return nics
+
+
+def get_macs(vm_):
+    '''
+    Return a list off MAC addresses from the named vm
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.get_macs <vm name>
+    '''
+    macs = []
+    doc = minidom.parse(_StringIO(get_xml(vm_)))
+    for node in doc.getElementsByTagName('devices'):
+        i_nodes = node.getElementsByTagName('interface')
+        for i_node in i_nodes:
+            for v_node in i_node.getElementsByTagName('mac'):
+                macs.append(v_node.getAttribute('address'))
+    return macs
+
+
+def get_graphics(vm_):
+    '''
+    Returns the information on vnc for a given vm
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.get_graphics <vm name>
+    '''
+    out = {'autoport': 'None',
+           'keymap': 'None',
+           'listen': 'None',
+           'port': 'None',
+           'type': 'vnc'}
+    xml = get_xml(vm_)
+    ssock = _StringIO(xml)
+    doc = minidom.parse(ssock)
+    for node in doc.getElementsByTagName('domain'):
+        g_nodes = node.getElementsByTagName('graphics')
+        for g_node in g_nodes:
+            for key, value in g_node.attributes.items():
+                out[key] = value
+    return out
+
+
+def get_disks(vm_):
+    '''
+    Return the disks of a named vm
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.get_disks <vm name>
+    '''
+    disks = {}
+    doc = minidom.parse(_StringIO(get_xml(vm_)))
+    for elem in doc.getElementsByTagName('disk'):
+        sources = elem.getElementsByTagName('source')
+        targets = elem.getElementsByTagName('target')
+        if len(sources) > 0:
+            source = sources[0]
+        else:
+            continue
+        if len(targets) > 0:
+            target = targets[0]
+        else:
+            continue
+        if target.hasAttribute('dev'):
+            qemu_target = ''
+            if source.hasAttribute('file'):
+                qemu_target = source.getAttribute('file')
+            elif source.hasAttribute('dev'):
+                qemu_target = source.getAttribute('dev')
+            elif source.hasAttribute('protocol') and \
+                    source.hasAttribute('name'):  # For rbd network
+                qemu_target = '{0}:{1}'.format(
+                        source.getAttribute('protocol'),
+                        source.getAttribute('name'))
+            if qemu_target:
+                disks[target.getAttribute('dev')] = {
+                    'file': qemu_target}
+    for dev in disks:
+        try:
+            hypervisor = __salt__['config.get']('libvirt:hypervisor', 'kvm')
+            if hypervisor not in ['qemu', 'kvm']:
+                break
+
+            output = []
+            qemu_output = subprocess.Popen(['qemu-img', 'info',
+                disks[dev]['file']],
+                shell=False,
+                stdout=subprocess.PIPE).communicate()[0]
+            snapshots = False
+            columns = None
+            lines = qemu_output.strip().split('\n')
+            for line in lines:
+                if line.startswith('Snapshot list:'):
+                    snapshots = True
+                    continue
+
+                # If this is a copy-on-write image, then the backing file
+                # represents the base image
+                #
+                # backing file: base.qcow2 (actual path: /var/shared/base.qcow2)
+                elif line.startswith('backing file'):
+                    matches = re.match(r'.*\(actual path: (.*?)\)', line)
+                    if matches:
+                        output.append('backing file: {0}'.format(matches.group(1)))
+                    continue
+
+                elif snapshots:
+                    if line.startswith('ID'):  # Do not parse table headers
+                        line = line.replace('VM SIZE', 'VMSIZE')
+                        line = line.replace('VM CLOCK', 'TIME VMCLOCK')
+                        columns = re.split(r'\s+', line)
+                        columns = [c.lower() for c in columns]
+                        output.append('snapshots:')
+                        continue
+                    fields = re.split(r'\s+', line)
+                    for i, field in enumerate(fields):
+                        sep = ' '
+                        if i == 0:
+                            sep = '-'
+                        output.append(
+                            '{0} {1}: "{2}"'.format(
+                                sep, columns[i], field
+                            )
+                        )
+                    continue
+                output.append(line)
+            output = '\n'.join(output)
+            disks[dev].update(yaml.safe_load(output))
+        except TypeError:
+            disks[dev].update(yaml.safe_load('image: Does not exist'))
+    return disks
+
+
+def setmem(vm_, memory, config=False):
+    '''
+    Changes the amount of memory allocated to VM. The VM must be shutdown
+    for this to work.
+
+    memory is to be specified in MB
+    If config is True then we ask libvirt to modify the config as well
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.setmem myvm 768
+    '''
+    if vm_state(vm_) != 'shutdown':
+        return False
+
+    dom = _get_dom(vm_)
+
+    # libvirt has a funny bitwise system for the flags in that the flag
+    # to affect the "current" setting is 0, which means that to set the
+    # current setting we have to call it a second time with just 0 set
+    flags = libvirt.VIR_DOMAIN_MEM_MAXIMUM
+    if config:
+        flags = flags | libvirt.VIR_DOMAIN_AFFECT_CONFIG
+
+    ret1 = dom.setMemoryFlags(memory * 1024, flags)
+    ret2 = dom.setMemoryFlags(memory * 1024, libvirt.VIR_DOMAIN_AFFECT_CURRENT)
+
+    # return True if both calls succeeded
+    return ret1 == ret2 == 0
+
+
+def setvcpus(vm_, vcpus, config=False):
+    '''
+    Changes the amount of vcpus allocated to VM. The VM must be shutdown
+    for this to work.
+
+    vcpus is an int representing the number to be assigned
+    If config is True then we ask libvirt to modify the config as well
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.setvcpus myvm 2
+    '''
+    if vm_state(vm_) != 'shutdown':
+        return False
+
+    dom = _get_dom(vm_)
+
+    # see notes in setmem
+    flags = libvirt.VIR_DOMAIN_VCPU_MAXIMUM
+    if config:
+        flags = flags | libvirt.VIR_DOMAIN_AFFECT_CONFIG
+
+    ret1 = dom.setVcpusFlags(vcpus, flags)
+    ret2 = dom.setVcpusFlags(vcpus, libvirt.VIR_DOMAIN_AFFECT_CURRENT)
+
+    return ret1 == ret2 == 0
+
+
+def freemem():
+    '''
+    Return an int representing the amount of memory that has not been given
+    to virtual machines on this node
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.freemem
+    '''
+    conn = __get_conn()
+    mem = conn.getInfo()[1]
+    # Take off just enough to sustain the hypervisor
+    mem -= 256
+    for vm_ in list_vms():
+        dom = _get_dom(vm_)
+        if dom.ID() > 0:
+            mem -= dom.info()[2] / 1024
+    return mem
+
+
+def freecpu():
+    '''
+    Return an int representing the number of unallocated cpus on this
+    hypervisor
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.freecpu
+    '''
+    conn = __get_conn()
+    cpus = conn.getInfo()[2]
+    for vm_ in list_vms():
+        dom = _get_dom(vm_)
+        if dom.ID() > 0:
+            cpus -= dom.info()[3]
+    return cpus
+
+
+def full_info():
+    '''
+    Return the node_info, vm_info and freemem
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.full_info
+    '''
+    return {'freecpu': freecpu(),
+            'freemem': freemem(),
+            'node_info': node_info(),
+            'vm_info': vm_info()}
+
+
+def get_xml(vm_):
+    '''
+    Returns the XML for a given vm
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.get_xml <vm name>
+    '''
+    dom = _get_dom(vm_)
+    return dom.XMLDesc(0)
+
+
+def get_profiles(hypervisor=None):
+    '''
+    Return the virt profiles for hypervisor.
+
+    Currently there are profiles for:
+
+     - nic
+     - disk
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.get_profiles
+        salt '*' virt.get_profiles hypervisor=esxi
+    '''
+    ret = {}
+    if hypervisor:
+        hypervisor = hypervisor
+    else:
+        hypervisor = __salt__['config.get']('libvirt:hypervisor', VIRT_DEFAULT_HYPER)
+    virtconf = __salt__['config.get']('virt', {})
+    for typ in ['disk', 'nic']:
+        _func = getattr(sys.modules[__name__], '_{0}_profile'.format(typ))
+        ret[typ] = {'default': _func('default', hypervisor)}
+        if typ in virtconf:
+            ret.setdefault(typ, {})
+            for prf in virtconf[typ]:
+                ret[typ][prf] = _func(prf, hypervisor)
+    return ret
+
+
+def shutdown(vm_):
+    '''
+    Send a soft shutdown signal to the named vm
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.shutdown <vm name>
+    '''
+    dom = _get_dom(vm_)
+    return dom.shutdown() == 0
+
+
+def pause(vm_):
+    '''
+    Pause the named vm
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.pause <vm name>
+    '''
+    dom = _get_dom(vm_)
+    return dom.suspend() == 0
+
+
+def resume(vm_):
+    '''
+    Resume the named vm
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.resume <vm name>
+    '''
+    dom = _get_dom(vm_)
+    return dom.resume() == 0
+
+
+def create(vm_):
+    '''
+    Start a defined domain
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.create <vm name>
+    '''
+    dom = _get_dom(vm_)
+    return dom.create() == 0
+
+
+def start(vm_):
+    '''
+    Alias for the obscurely named 'create' function
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.start <vm name>
+    '''
+    return create(vm_)
+
+
+def stop(vm_):
+    '''
+    Alias for the obscurely named 'destroy' function
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.stop <vm name>
+    '''
+    return destroy(vm_)
+
+
+def reboot(vm_):
+    '''
+    Reboot a domain via ACPI request
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.reboot <vm name>
+    '''
+    dom = _get_dom(vm_)
+
+    # reboot has a few modes of operation, passing 0 in means the
+    # hypervisor will pick the best method for rebooting
+    return dom.reboot(0) == 0
+
+
+def reset(vm_):
+    '''
+    Reset a VM by emulating the reset button on a physical machine
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.reset <vm name>
+    '''
+    dom = _get_dom(vm_)
+
+    # reset takes a flag, like reboot, but it is not yet used
+    # so we just pass in 0
+    # see: http://libvirt.org/html/libvirt-libvirt.html#virDomainReset
+    return dom.reset(0) == 0
+
+
+def ctrl_alt_del(vm_):
+    '''
+    Sends CTRL+ALT+DEL to a VM
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.ctrl_alt_del <vm name>
+    '''
+    dom = _get_dom(vm_)
+    return dom.sendKey(0, 0, [29, 56, 111], 3, 0) == 0
+
+
+def create_xml_str(xml):
+    '''
+    Start a domain based on the XML passed to the function
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.create_xml_str <XML in string format>
+    '''
+    conn = __get_conn()
+    return conn.createXML(xml, 0) is not None
+
+
+def create_xml_path(path):
+    '''
+    Start a domain based on the XML-file path passed to the function
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.create_xml_path <path to XML file on the node>
+    '''
+    if not os.path.isfile(path):
+        return False
+    return create_xml_str(salt.utils.fopen(path, 'r').read())
+
+
+def define_xml_str(xml):
+    '''
+    Define a domain based on the XML passed to the function
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.define_xml_str <XML in string format>
+    '''
+    conn = __get_conn()
+    return conn.defineXML(xml) is not None
+
+
+def define_xml_path(path):
+    '''
+    Define a domain based on the XML-file path passed to the function
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.define_xml_path <path to XML file on the node>
+
+    '''
+    if not os.path.isfile(path):
+        return False
+    return define_xml_str(salt.utils.fopen(path, 'r').read())
+
+
+def define_vol_xml_str(xml):
+    '''
+    Define a volume based on the XML passed to the function
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.define_vol_xml_str <XML in string format>
+    '''
+    poolname = __salt__['config.get']('libvirt:storagepool', 'default')
+    conn = __get_conn()
+    pool = conn.storagePoolLookupByName(str(poolname))
+    return pool.createXML(xml, 0) is not None
+
+
+def define_vol_xml_path(path):
+    '''
+    Define a volume based on the XML-file path passed to the function
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.define_vol_xml_path <path to XML file on the node>
+
+    '''
+    if not os.path.isfile(path):
+        return False
+    return define_vol_xml_str(salt.utils.fopen(path, 'r').read())
+
+
+def migrate_non_shared(vm_, target, ssh=False):
+    '''
+    Attempt to execute non-shared storage "all" migration
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.migrate_non_shared <vm name> <target hypervisor>
+    '''
+    cmd = _get_migrate_command() + ' --copy-storage-all ' + vm_\
+        + _get_target(target, ssh)
+
+    return subprocess.Popen(cmd,
+            shell=True,
+            stdout=subprocess.PIPE).communicate()[0]
+
+
+def migrate_non_shared_inc(vm_, target, ssh=False):
+    '''
+    Attempt to execute non-shared storage "all" migration
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.migrate_non_shared_inc <vm name> <target hypervisor>
+    '''
+    cmd = _get_migrate_command() + ' --copy-storage-inc ' + vm_\
+        + _get_target(target, ssh)
+
+    return subprocess.Popen(cmd,
+            shell=True,
+            stdout=subprocess.PIPE).communicate()[0]
+
+
+def migrate(vm_, target, ssh=False):
+    '''
+    Shared storage migration
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.migrate <vm name> <target hypervisor>
+    '''
+    cmd = _get_migrate_command() + ' ' + vm_\
+        + _get_target(target, ssh)
+
+    return subprocess.Popen(cmd,
+            shell=True,
+            stdout=subprocess.PIPE).communicate()[0]
+
+
+def seed_non_shared_migrate(disks, force=False):
+    '''
+    Non shared migration requires that the disks be present on the migration
+    destination, pass the disks information via this function, to the
+    migration destination before executing the migration.
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.seed_non_shared_migrate <disks>
+    '''
+    for _, data in disks.items():
+        fn_ = data['file']
+        form = data['file format']
+        size = data['virtual size'].split()[1][1:]
+        if os.path.isfile(fn_) and not force:
+            # the target exists, check to see if it is compatible
+            pre = yaml.safe_load(subprocess.Popen('qemu-img info arch',
+                shell=True,
+                stdout=subprocess.PIPE).communicate()[0])
+            if pre['file format'] != data['file format']\
+                    and pre['virtual size'] != data['virtual size']:
+                return False
+        if not os.path.isdir(os.path.dirname(fn_)):
+            os.makedirs(os.path.dirname(fn_))
+        if os.path.isfile(fn_):
+            os.remove(fn_)
+        cmd = 'qemu-img create -f ' + form + ' ' + fn_ + ' ' + size
+        subprocess.call(cmd, shell=True)
+        creds = _libvirt_creds()
+        cmd = 'chown ' + creds['user'] + ':' + creds['group'] + ' ' + fn_
+        subprocess.call(cmd, shell=True)
+    return True
+
+
+def set_autostart(vm_, state='on'):
+    '''
+    Set the autostart flag on a VM so that the VM will start with the host
+    system on reboot.
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt "*" virt.set_autostart <vm name> <on | off>
+    '''
+
+    dom = _get_dom(vm_)
+
+    if state == 'on':
+        return dom.setAutostart(1) == 0
+
+    elif state == 'off':
+        return dom.setAutostart(0) == 0
+
+    else:
+        # return False if state is set to something other then on or off
+        return False
+
+
+def destroy(vm_):
+    '''
+    Hard power down the virtual machine, this is equivalent to pulling the
+    power
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.destroy <vm name>
+    '''
+    dom = _get_dom(vm_)
+    return dom.destroy() == 0
+
+
+def undefine(vm_):
+    '''
+    Remove a defined vm, this does not purge the virtual machine image, and
+    this only works if the vm is powered down
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.undefine <vm name>
+    '''
+    dom = _get_dom(vm_)
+    return dom.undefine() == 0
+
+
+def purge(vm_, dirs=False):
+    '''
+    Recursively destroy and delete a virtual machine, pass True for dir's to
+    also delete the directories containing the virtual machine disk images -
+    USE WITH EXTREME CAUTION!
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.purge <vm name>
+    '''
+    disks = get_disks(vm_)
+    try:
+        if not destroy(vm_):
+            return False
+    except libvirt.libvirtError:
+        # This is thrown if the machine is already shut down
+        pass
+    directories = set()
+    for disk in disks:
+        os.remove(disks[disk]['file'])
+        directories.add(os.path.dirname(disks[disk]['file']))
+    if dirs:
+        for dir_ in directories:
+            shutil.rmtree(dir_)
+    undefine(vm_)
+    return True
+
+
+def virt_type():
+    '''
+    Returns the virtual machine type as a string
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.virt_type
+    '''
+    return __grains__['virtual']
+
+
+def is_kvm_hyper():
+    '''
+    Returns a bool whether or not this node is a KVM hypervisor
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.is_kvm_hyper
+    '''
+    try:
+        if 'kvm_' not in salt.utils.fopen('/proc/modules').read():
+            return False
+    except IOError:
+        # No /proc/modules? Are we on Windows? Or Solaris?
+        return False
+    return 'libvirtd' in __salt__['cmd.run'](__grains__['ps'])
+
+
+def is_xen_hyper():
+    '''
+    Returns a bool whether or not this node is a XEN hypervisor
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.is_xen_hyper
+    '''
+    try:
+        if __grains__['virtual_subtype'] != 'Xen Dom0':
+            return False
+    except KeyError:
+        # virtual_subtype isn't set everywhere.
+        return False
+    try:
+        if 'xen_' not in salt.utils.fopen('/proc/modules').read():
+            return False
+    except IOError:
+        # No /proc/modules? Are we on Windows? Or Solaris?
+        return False
+    return 'libvirtd' in __salt__['cmd.run'](__grains__['ps'])
+
+
+def is_hyper():
+    '''
+    Returns a bool whether or not this node is a hypervisor of any kind
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.is_hyper
+    '''
+    try:
+        import libvirt  # pylint: disable=import-error
+    except ImportError:
+        # not a usable hypervisor without libvirt module
+        return False
+    return is_xen_hyper() or is_kvm_hyper()
+
+
+def vm_cputime(vm_=None):
+    '''
+    Return cputime used by the vms on this hyper in a
+    list of dicts:
+
+    .. code-block:: python
+
+        [
+            'your-vm': {
+                'cputime' <int>
+                'cputime_percent' <int>
+                },
+            ...
+            ]
+
+    If you pass a VM name in as an argument then it will return info
+    for just the named VM, otherwise it will return all VMs.
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.vm_cputime
+    '''
+    host_cpus = __get_conn().getInfo()[2]
+
+    def _info(vm_):
+        dom = _get_dom(vm_)
+        raw = dom.info()
+        vcpus = int(raw[3])
+        cputime = int(raw[4])
+        cputime_percent = 0
+        if cputime:
+            # Divide by vcpus to always return a number between 0 and 100
+            cputime_percent = (1.0e-7 * cputime / host_cpus) / vcpus
+        return {
+                'cputime': int(raw[4]),
+                'cputime_percent': int('{0:.0f}'.format(cputime_percent))
+               }
+    info = {}
+    if vm_:
+        info[vm_] = _info(vm_)
+    else:
+        for vm_ in list_vms():
+            info[vm_] = _info(vm_)
+    return info
+
+
+def vm_netstats(vm_=None):
+    '''
+    Return combined network counters used by the vms on this hyper in a
+    list of dicts:
+
+    .. code-block:: python
+
+        [
+            'your-vm': {
+                'rx_bytes'   : 0,
+                'rx_packets' : 0,
+                'rx_errs'    : 0,
+                'rx_drop'    : 0,
+                'tx_bytes'   : 0,
+                'tx_packets' : 0,
+                'tx_errs'    : 0,
+                'tx_drop'    : 0
+                },
+            ...
+            ]
+
+    If you pass a VM name in as an argument then it will return info
+    for just the named VM, otherwise it will return all VMs.
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.vm_netstats
+    '''
+    def _info(vm_):
+        dom = _get_dom(vm_)
+        nics = get_nics(vm_)
+        ret = {
+                'rx_bytes': 0,
+                'rx_packets': 0,
+                'rx_errs': 0,
+                'rx_drop': 0,
+                'tx_bytes': 0,
+                'tx_packets': 0,
+                'tx_errs': 0,
+                'tx_drop': 0
+               }
+        for attrs in six.itervalues(nics):
+            if 'target' in attrs:
+                dev = attrs['target']
+                stats = dom.interfaceStats(dev)
+                ret['rx_bytes'] += stats[0]
+                ret['rx_packets'] += stats[1]
+                ret['rx_errs'] += stats[2]
+                ret['rx_drop'] += stats[3]
+                ret['tx_bytes'] += stats[4]
+                ret['tx_packets'] += stats[5]
+                ret['tx_errs'] += stats[6]
+                ret['tx_drop'] += stats[7]
+
+        return ret
+    info = {}
+    if vm_:
+        info[vm_] = _info(vm_)
+    else:
+        for vm_ in list_vms():
+            info[vm_] = _info(vm_)
+    return info
+
+
+def vm_diskstats(vm_=None):
+    '''
+    Return disk usage counters used by the vms on this hyper in a
+    list of dicts:
+
+    .. code-block:: python
+
+        [
+            'your-vm': {
+                'rd_req'   : 0,
+                'rd_bytes' : 0,
+                'wr_req'   : 0,
+                'wr_bytes' : 0,
+                'errs'     : 0
+                },
+            ...
+            ]
+
+    If you pass a VM name in as an argument then it will return info
+    for just the named VM, otherwise it will return all VMs.
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' virt.vm_blockstats
+    '''
+    def get_disk_devs(vm_):
+        doc = minidom.parse(_StringIO(get_xml(vm_)))
+        disks = []
+        for elem in doc.getElementsByTagName('disk'):
+            targets = elem.getElementsByTagName('target')
+            target = targets[0]
+            disks.append(target.getAttribute('dev'))
+        return disks
+
+    def _info(vm_):
+        dom = _get_dom(vm_)
+        # Do not use get_disks, since it uses qemu-img and is very slow
+        # and unsuitable for any sort of real time statistics
+        disks = get_disk_devs(vm_)
+        ret = {'rd_req': 0,
+               'rd_bytes': 0,
+               'wr_req': 0,
+               'wr_bytes': 0,
+               'errs': 0
+               }
+        for disk in disks:
+            stats = dom.blockStats(disk)
+            ret['rd_req'] += stats[0]
+            ret['rd_bytes'] += stats[1]
+            ret['wr_req'] += stats[2]
+            ret['wr_bytes'] += stats[3]
+            ret['errs'] += stats[4]
+
+        return ret
+    info = {}
+    if vm_:
+        info[vm_] = _info(vm_)
+    else:
+        # Can not run function blockStats on inactive VMs
+        for vm_ in list_active_vms():
+            info[vm_] = _info(vm_)
+    return info