通过python-libvirt管理KVM虚拟机 代码实现

初步代码

[python]  view plain  copy
 
  1. <span style="font-size:18px;">''''' 
  2. Work with virtual machines managed by libvirt 
  3.     
  4. :depends: libvirt Python module 
  5. '''  
  6. # Special Thanks to Michael Dehann, many of the concepts, and a few structures  
  7. # of his in the virt func module have been used  
  8.      
  9. # Import python libs  
  10. import os  
  11. import re  
  12. import shutil  
  13. import subprocess  
  14. from xml.dom import minidom  
  15.      
  16. # Import third party libs  
  17. try:  
  18.     import libvirt  
  19.     HAS_LIBVIRT = True  
  20. except ImportError:  
  21.     HAS_LIBVIRT = False  
  22. import yaml  
  23.      
  24. # Import salt libs  
  25. import salt.utils  
  26. from salt._compat import StringIO as _StringIO  
  27. from salt.exceptions import CommandExecutionError  
  28.      
  29.      
  30. VIRT_STATE_NAME_MAP = {0: 'running',  
  31.                        1: 'running',  
  32.                        2: 'running',  
  33.                        3: 'paused',  
  34.                        4: 'shutdown',  
  35.                        5: 'shutdown',  
  36.                        6: 'crashed'}  
  37.      
  38.      
  39. def __virtual__():  
  40.     if not HAS_LIBVIRT:  
  41.         return False  
  42.     return 'virt'  
  43.      
  44.      
  45. def __get_conn():  
  46.     ''''' 
  47.     Detects what type of dom this node is and attempts to connect to the 
  48.     correct hypervisor via libvirt. 
  49.     '''  
  50.     # This has only been tested on kvm and xen, it needs to be expanded to  
  51.     # support all vm layers supported by libvirt  
  52.     try:  
  53.         conn = libvirt.open('qemu:///system')  
  54.     except Exception:  
  55.         raise CommandExecutionError(  
  56.             'Sorry, {0} failed to open a connection to the hypervisor '  
  57.             'software'.format(  
  58.                 __grains__['fqdn']  
  59.             )  
  60.         )  
  61.     return conn  
  62.      
  63.      
  64. def _get_dom(vm_):  
  65.     ''''' 
  66.     Return a domain object for the named vm 
  67.     '''  
  68.     conn = __get_conn()  
  69.     if vm_ not in list_vms():  
  70.         raise CommandExecutionError('The specified vm is not present')  
  71.     return conn.lookupByName(vm_)  
  72.      
  73.      
  74. def _libvirt_creds():  
  75.     ''''' 
  76.     Returns the user and group that the disk images should be owned by 
  77.     '''  
  78.     g_cmd = 'grep ^\s*group /etc/libvirt/qemu.conf'  
  79.     u_cmd = 'grep ^\s*user /etc/libvirt/qemu.conf'  
  80.     try:  
  81.         group = subprocess.Popen(g_cmd,  
  82.             shell=True,  
  83.             stdout=subprocess.PIPE).communicate()[0].split('"''"')[1] 
  84.     except IndexError: 
  85.         group = 'root' 
  86.     try: 
  87.         user = subprocess.Popen(u_cmd, 
  88.             shell=True, 
  89.             stdout=subprocess.PIPE).communicate()[0].split('"')[1]  
  90.     except IndexError:  
  91.         user = 'root'  
  92.     return {'user': user, 'group': group}  
  93.      
  94. def _get_migrate_command():  
  95.     ''''' 
  96.     Returns the command shared by the differnt migration types 
  97.     '''  
  98.     return 'virsh migrate --live --persistent --undefinesource '  
  99.      
  100. def _get_target(target, ssh):  
  101.     proto = 'qemu'  
  102.     if ssh:  
  103.         proto += '+ssh'  
  104.     return ' %s://%s/%s' %(proto, target, 'system')  
  105.      
  106. def list_vms():  
  107.     ''''' 
  108.     Return a list of virtual machine names on the minion 
  109.     
  110.     CLI Example:: 
  111.     
  112.         salt '*' virt.list_vms 
  113.     '''  
  114.     vms = []  
  115.     vms.extend(list_active_vms())  
  116.     vms.extend(list_inactive_vms())  
  117.     return vms  
  118.      
  119.      
  120. def list_active_vms():  
  121.     ''''' 
  122.     Return a list of names for active virtual machine on the minion 
  123.     
  124.     CLI Example:: 
  125.     
  126.         salt '*' virt.list_active_vms 
  127.     '''  
  128.     conn = __get_conn()  
  129.     vms = []  
  130.     for id_ in conn.listDomainsID():  
  131.         vms.append(conn.lookupByID(id_).name())  
  132.     return vms  
  133.      
  134.      
  135. def list_inactive_vms():  
  136.     ''''' 
  137.     Return a list of names for inactive virtual machine on the minion 
  138.     
  139.     CLI Example:: 
  140.     
  141.         salt '*' virt.list_inactive_vms 
  142.     '''  
  143.     conn = __get_conn()  
  144.     vms = []  
  145.     for id_ in conn.listDefinedDomains():  
  146.         vms.append(id_)  
  147.     return vms  
  148.      
  149.      
  150. def vm_info(vm_=None):  
  151.     ''''' 
  152.     Return detailed information about the vms on this hyper in a 
  153.     list of dicts:: 
  154.     
  155.         [ 
  156.             'your-vm': { 
  157.                 'cpu': <int>, 
  158.                 'maxMem': <int>, 
  159.                 'mem': <int>, 
  160.                 'state': '<state>', 
  161.                 'cputime' <int> 
  162.                 }, 
  163.             ... 
  164.             ] 
  165.     
  166.     If you pass a VM name in as an argument then it will return info 
  167.     for just the named VM, otherwise it will return all VMs. 
  168.     
  169.     CLI Example:: 
  170.     
  171.         salt '*' virt.vm_info 
  172.     '''  
  173.     def _info(vm_):  
  174.         dom = _get_dom(vm_)  
  175.         raw = dom.info()  
  176.         return {'cpu': raw[3],  
  177.                 'cputime': int(raw[4]),  
  178.                 'disks': get_disks(vm_),  
  179.                 'graphics': get_graphics(vm_),  
  180.                 'nics': get_nics(vm_),  
  181.                 'maxMem': int(raw[1]),  
  182.                 'mem': int(raw[2]),  
  183.                 'state': VIRT_STATE_NAME_MAP.get(raw[0], 'unknown')}  
  184.     info = {}  
  185.     if vm_:  
  186.         info[vm_] = _info(vm_)  
  187.     else:  
  188.         for vm_ in list_vms():  
  189.             info[vm_] = _info(vm_)  
  190.     return info  
  191.      
  192.      
  193. def vm_state(vm_=None):  
  194.     ''''' 
  195.     Return list of all the vms and their state. 
  196.     
  197.     If you pass a VM name in as an argument then it will return info 
  198.     for just the named VM, otherwise it will return all VMs. 
  199.     
  200.     CLI Example:: 
  201.     
  202.         salt '*' virt.vm_state <vm name> 
  203.     '''  
  204.     def _info(vm_):  
  205.         state = ''  
  206.         dom = _get_dom(vm_)  
  207.         raw = dom.info()  
  208.         state = VIRT_STATE_NAME_MAP.get(raw[0], 'unknown')  
  209.         return state  
  210.     info = {}  
  211.     if vm_:  
  212.         info[vm_] = _info(vm_)  
  213.     else:  
  214.         for vm_ in list_vms():  
  215.             info[vm_] = _info(vm_)  
  216.     return info  
  217.      
  218.      
  219. def node_info():  
  220.     ''''' 
  221.     Return a dict with information about this node 
  222.     
  223.     CLI Example:: 
  224.     
  225.         salt '*' virt.node_info 
  226.     '''  
  227.     conn = __get_conn()  
  228.     raw = conn.getInfo()  
  229.     info = {'cpucores': raw[6],  
  230.             'cpumhz': raw[3],  
  231.             'cpumodel': str(raw[0]),  
  232.             'cpus': raw[2],  
  233.             'cputhreads': raw[7],  
  234.             'numanodes': raw[4],  
  235.             'phymemory': raw[1],  
  236.             'sockets': raw[5]}  
  237.     return info  
  238.      
  239.      
  240. def get_nics(vm_):  
  241.     ''''' 
  242.     Return info about the network interfaces of a named vm 
  243.     
  244.     CLI Example:: 
  245.     
  246.         salt '*' virt.get_nics <vm name> 
  247.     '''  
  248.     nics = {}  
  249.     doc = minidom.parse(_StringIO(get_xml(vm_)))  
  250.     for node in doc.getElementsByTagName('devices'):  
  251.         i_nodes = node.getElementsByTagName('interface')  
  252.         for i_node in i_nodes:  
  253.             nic = {}  
  254.             nic['type'] = i_node.getAttribute('type')  
  255.             for v_node in i_node.getElementsByTagName('*'):  
  256.                 if v_node.tagName == 'mac':  
  257.                     nic['mac'] = v_node.getAttribute('address')  
  258.                 if v_node.tagName == 'model':  
  259.                     nic['model'] = v_node.getAttribute('type')  
  260.                 if v_node.tagName == 'target':  
  261.                     nic['target'] = v_node.getAttribute('dev')  
  262.                 # driver, source, and match can all have optional attributes  
  263.                 if re.match('(driver|source|address)', v_node.tagName):  
  264.                     temp = {}  
  265.                     for key in v_node.attributes.keys():  
  266.                         temp[key] = v_node.getAttribute(key)  
  267.                     nic[str(v_node.tagName)] = temp  
  268.                 # virtualport needs to be handled separately, to pick up the  
  269.                 # type attribute of the virtualport itself  
  270.                 if v_node.tagName == 'virtualport':  
  271.                     temp = {}  
  272.                     temp['type'] = v_node.getAttribute('type')  
  273.                     for key in v_node.attributes.keys():  
  274.                         temp[key] = v_node.getAttribute(key)  
  275.                     nic['virtualport'] = temp  
  276.             if 'mac' not in nic:  
  277.                 continue  
  278.             nics[nic['mac']] = nic  
  279.     return nics  
  280.      
  281.      
  282. def get_macs(vm_):  
  283.     ''''' 
  284.     Return a list off MAC addresses from the named vm 
  285.     
  286.     CLI Example:: 
  287.     
  288.         salt '*' virt.get_macs <vm name> 
  289.     '''  
  290.     macs = []  
  291.     doc = minidom.parse(_StringIO(get_xml(vm_)))  
  292.     for node in doc.getElementsByTagName('devices'):  
  293.         i_nodes = node.getElementsByTagName('interface')  
  294.         for i_node in i_nodes:  
  295.             for v_node in i_node.getElementsByTagName('mac'):  
  296.                 macs.append(v_node.getAttribute('address'))  
  297.     return macs  
  298.      
  299.      
  300. def get_graphics(vm_):  
  301.     ''''' 
  302.     Returns the information on vnc for a given vm 
  303.     
  304.     CLI Example:: 
  305.     
  306.         salt '*' virt.get_graphics <vm name> 
  307.     '''  
  308.     out = {'autoport': 'None',  
  309.            'keymap': 'None',  
  310.            'listen': 'None',  
  311.            'port': 'None',  
  312.            'type': 'vnc'}  
  313.     xml = get_xml(vm_)  
  314.     ssock = _StringIO(xml)  
  315.     doc = minidom.parse(ssock)  
  316.     for node in doc.getElementsByTagName('domain'):  
  317.         g_nodes = node.getElementsByTagName('graphics')  
  318.         for g_node in g_nodes:  
  319.             for key in g_node.attributes.keys():  
  320.                 out[key] = g_node.getAttribute(key)  
  321.     return out  
  322.      
  323.      
  324. def get_disks(vm_):  
  325.     ''''' 
  326.     Return the disks of a named vm 
  327.     
  328.     CLI Example:: 
  329.     
  330.         salt '*' virt.get_disks <vm name> 
  331.     '''  
  332.     disks = {}  
  333.     doc = minidom.parse(_StringIO(get_xml(vm_)))  
  334.     for elem in doc.getElementsByTagName('disk'):  
  335.         sources = elem.getElementsByTagName('source')  
  336.         targets = elem.getElementsByTagName('target')  
  337.         if len(sources) > 0:  
  338.             source = sources[0]  
  339.         else:  
  340.             continue  
  341.         if len(targets) > 0:  
  342.             target = targets[0]  
  343.         else:  
  344.             continue  
  345.         if target.hasAttribute('dev'):  
  346.             qemu_target = ''  
  347.             if source.hasAttribute('file'):  
  348.                 qemu_target = source.getAttribute('file')  
  349.             elif source.hasAttribute('dev'):  
  350.                 qemu_target = source.getAttribute('dev')  
  351.             elif source.hasAttribute('protocol') and \  
  352.                     source.hasAttribute('name'): # For rbd network  
  353.                 qemu_target = '%s:%s' %(  
  354.                         source.getAttribute('protocol'),  
  355.                         source.getAttribute('name'))  
  356.             if qemu_target:  
  357.                 disks[target.getAttribute('dev')] = {\  
  358.                     'file': qemu_target}  
  359.     for dev in disks:  
  360.         try:  
  361.             output = []  
  362.             qemu_output = subprocess.Popen(['qemu-img', 'info',  
  363.                 disks[dev]['file']],  
  364.                 shell=False,  
  365.                 stdout=subprocess.PIPE).communicate()[0]  
  366.             snapshots = False  
  367.             columns = None  
  368.             lines = qemu_output.strip().split('\n')  
  369.             for line in lines:  
  370.                 if line.startswith('Snapshot list:'):  
  371.                     snapshots = True  
  372.                     continue  
  373.                 elif snapshots:  
  374.                     if line.startswith('ID'):  # Do not parse table headers  
  375.                         line = line.replace('VM SIZE', 'VMSIZE')  
  376.                         line = line.replace('VM CLOCK', 'TIME VMCLOCK')  
  377.                         columns = re.split('\s+', line)  
  378.                         columns = [c.lower() for c in columns]  
  379.                         output.append('snapshots:')  
  380.                         continue  
  381.                     fields = re.split('\s+', line)  
  382.                     for i, field in enumerate(fields):  
  383.                         sep = ' '  
  384.                         if i == 0:  
  385.                             sep = '-'  
  386.                         output.append(  
  387.                             '{0} {1}: "{2}"'.format(  
  388.                                 sep, columns[i], field  
  389.                             )  
  390.                         )  
  391.                     continue  
  392.                 output.append(line)  
  393.             output = '\n'.join(output)  
  394.             disks[dev].update(yaml.safe_load(output))  
  395.         except TypeError:  
  396.             disks[dev].update(yaml.safe_load('image: Does not exist'))  
  397.     return disks  
  398.      
  399.      
  400. def setmem(vm_, memory, config=False):  
  401.     ''''' 
  402.     Changes the amount of memory allocated to VM. The VM must be shutdown 
  403.     for this to work. 
  404.     
  405.     memory is to be specified in MB 
  406.     If config is True then we ask libvirt to modify the config as well 
  407.     
  408.     CLI Example:: 
  409.     
  410.         salt '*' virt.setmem myvm 768 
  411.     '''  
  412.     if vm_state(vm_) != 'shutdown':  
  413.         return False  
  414.      
  415.     dom = _get_dom(vm_)  
  416.      
  417.     # libvirt has a funny bitwise system for the flags in that the flag  
  418.     # to affect the "current" setting is 0, which means that to set the  
  419.     # current setting we have to call it a second time with just 0 set  
  420.     flags = libvirt.VIR_DOMAIN_MEM_MAXIMUM  
  421.     if config:  
  422.         flags = flags | libvirt.VIR_DOMAIN_AFFECT_CONFIG  
  423.      
  424.     ret1 = dom.setMemoryFlags(memory * 1024, flags)  
  425.     ret2 = dom.setMemoryFlags(memory * 1024, libvirt.VIR_DOMAIN_AFFECT_CURRENT)  
  426.      
  427.     # return True if both calls succeeded  
  428.     return ret1 == ret2 == 0  
  429.      
  430.      
  431. def setvcpus(vm_, vcpus, config=False):  
  432.     ''''' 
  433.     Changes the amount of vcpus allocated to VM. The VM must be shutdown 
  434.     for this to work. 
  435.     
  436.     vcpus is an int representing the number to be assigned 
  437.     If config is True then we ask libvirt to modify the config as well 
  438.     
  439.     CLI Example:: 
  440.     
  441.         salt '*' virt.setvcpus myvm 2 
  442.     '''  
  443.     if vm_state(vm_) != 'shutdown':  
  444.         return False  
  445.      
  446.     dom = _get_dom(vm_)  
  447.      
  448.     # see notes in setmem  
  449.     flags = libvirt.VIR_DOMAIN_VCPU_MAXIMUM  
  450.     if config:  
  451.         flags = flags | libvirt.VIR_DOMAIN_AFFECT_CONFIG  
  452.      
  453.     ret1 = dom.setVcpusFlags(vcpus, flags)  
  454.     ret2 = dom.setVcpusFlags(vcpus, libvirt.VIR_DOMAIN_AFFECT_CURRENT)  
  455.      
  456.     return ret1 == ret2 == 0  
  457.      
  458.      
  459. def freemem():  
  460.     ''''' 
  461.     Return an int representing the amount of memory that has not been given 
  462.     to virtual machines on this node 
  463.     
  464.     CLI Example:: 
  465.     
  466.         salt '*' virt.freemem 
  467.     '''  
  468.     conn = __get_conn()  
  469.     mem = conn.getInfo()[1]  
  470.     # Take off just enough to sustain the hypervisor  
  471.     mem -= 256  
  472.     for vm_ in list_vms():  
  473.         dom = _get_dom(vm_)  
  474.         if dom.ID() > 0:  
  475.             mem -= dom.info()[2] / 1024  
  476.     return mem  
  477.      
  478.      
  479. def freecpu():  
  480.     ''''' 
  481.     Return an int representing the number of unallocated cpus on this 
  482.     hypervisor 
  483.     
  484.     CLI Example:: 
  485.     
  486.         salt '*' virt.freecpu 
  487.     '''  
  488.     conn = __get_conn()  
  489.     cpus = conn.getInfo()[2]  
  490.     for vm_ in list_vms():  
  491.         dom = _get_dom(vm_)  
  492.         if dom.ID() > 0:  
  493.             cpus -= dom.info()[3]  
  494.     return cpus  
  495.      
  496.      
  497. def full_info():  
  498.     ''''' 
  499.     Return the node_info, vm_info and freemem 
  500.     
  501.     CLI Example:: 
  502.     
  503.         salt '*' virt.full_info 
  504.     '''  
  505.     return {'freecpu': freecpu(),  
  506.             'freemem': freemem(),  
  507.             'node_info': node_info(),  
  508.             'vm_info': vm_info()}  
  509.      
  510.      
  511. def get_xml(vm_):  
  512.     ''''' 
  513.     Returns the xml for a given vm 
  514.     
  515.     CLI Example:: 
  516.     
  517.         salt '*' virt.get_xml <vm name> 
  518.     '''  
  519.     dom = _get_dom(vm_)  
  520.     return dom.XMLDesc(0)  
  521.      
  522.      
  523. def shutdown(vm_):  
  524.     ''''' 
  525.     Send a soft shutdown signal to the named vm 
  526.     
  527.     CLI Example:: 
  528.     
  529.         salt '*' virt.shutdown <vm name> 
  530.     '''  
  531.     dom = _get_dom(vm_)  
  532.     return dom.shutdown() == 0  
  533.      
  534.      
  535. def pause(vm_):  
  536.     ''''' 
  537.     Pause the named vm 
  538.     
  539.     CLI Example:: 
  540.     
  541.         salt '*' virt.pause <vm name> 
  542.     '''  
  543.     dom = _get_dom(vm_)  
  544.     return dom.suspend() == 0  
  545.      
  546.      
  547. def resume(vm_):  
  548.     ''''' 
  549.     Resume the named vm 
  550.     
  551.     CLI Example:: 
  552.     
  553.         salt '*' virt.resume <vm name> 
  554.     '''  
  555.     dom = _get_dom(vm_)  
  556.     return dom.resume() == 0  
  557.      
  558.      
  559. def create(vm_):  
  560.     ''''' 
  561.     Start a defined domain 
  562.     
  563.     CLI Example:: 
  564.     
  565.         salt '*' virt.create <vm name> 
  566.     '''  
  567.     dom = _get_dom(vm_)  
  568.     return dom.create() == 0  
  569.      
  570.      
  571. def start(vm_):  
  572.     ''''' 
  573.     Alias for the obscurely named 'create' function 
  574.     
  575.     CLI Example:: 
  576.     
  577.         salt '*' virt.start <vm name> 
  578.     '''  
  579.     return create(vm_)  
  580.      
  581.      
  582. def reboot(vm_):  
  583.     ''''' 
  584.     Reboot a domain via ACPI request 
  585.     
  586.     CLI Example:: 
  587.     
  588.         salt '*' virt.reboot <vm name> 
  589.     '''  
  590.     dom = _get_dom(vm_)  
  591.      
  592.     # reboot has a few modes of operation, passing 0 in means the  
  593.     # hypervisor will pick the best method for rebooting  
  594.     return dom.reboot(0) == 0  
  595.      
  596.      
  597. def reset(vm_):  
  598.     ''''' 
  599.     Reset a VM by emulating the reset button on a physical machine 
  600.     
  601.     CLI Example:: 
  602.     
  603.         salt '*' virt.reset <vm name> 
  604.     '''  
  605.     dom = _get_dom(vm_)  
  606.      
  607.     # reset takes a flag, like reboot, but it is not yet used  
  608.     # so we just pass in 0  
  609.     # see: http://libvirt.org/html/libvirt-libvirt.html#virDomainReset  
  610.     return dom.reset(0) == 0  
  611.      
  612.      
  613. def ctrl_alt_del(vm_):  
  614.     ''''' 
  615.     Sends CTRL+ALT+DEL to a VM 
  616.     
  617.     CLI Example:: 
  618.     
  619.         salt '*' virt.ctrl_alt_del <vm name> 
  620.     '''  
  621.     dom = _get_dom(vm_)  
  622.     return dom.sendKey(0, 0, [29, 56, 111], 3, 0) == 0  
  623.      
  624.      
  625. def create_xml_str(xml):  
  626.     ''''' 
  627.     Start a domain based on the xml passed to the function 
  628.     
  629.     CLI Example:: 
  630.     
  631.         salt '*' virt.create_xml_str <xml in string format> 
  632.     '''  
  633.     conn = __get_conn()  
  634.     return conn.createXML(xml, 0) is not None  
  635.      
  636.      
  637. def create_xml_path(path):  
  638.     ''''' 
  639.     Start a defined domain 
  640.     
  641.     CLI Example:: 
  642.     
  643.         salt '*' virt.create_xml_path <path to xml file on the node> 
  644.     '''  
  645.     if not os.path.isfile(path):  
  646.         return False  
  647.     return create_xml_str(salt.utils.fopen(path, 'r').read())  
  648.      
  649.      
  650. def define_xml_str(xml):  
  651.     ''''' 
  652.     Define a domain based on the xml passed to the function 
  653.     
  654.     CLI Example:: 
  655.     
  656.         salt '*' virt.define_xml_str <xml in string format> 
  657.     '''  
  658.     conn = __get_conn()  
  659.     return conn.defineXML(xml) is not None  
  660.      
  661. def migrate_non_shared(vm_, target, ssh=False):  
  662.     ''''' 
  663.     Attempt to execute non-shared storage "all" migration 
  664.     
  665.     CLI Example:: 
  666.     
  667.         salt '*' virt.migrate_non_shared <vm name> <target hypervisor> 
  668.     '''  
  669.     cmd = _get_migrate_command() + ' --copy-storage-all ' + vm_\  
  670.         + _get_target(target, ssh)  
  671.      
  672.     return subprocess.Popen(cmd,  
  673.             shell=True,  
  674.             stdout=subprocess.PIPE).communicate()[0]  
  675.      
  676.      
  677. def migrate_non_shared_inc(vm_, target, ssh=False):  
  678.     ''''' 
  679.     Attempt to execute non-shared storage "all" migration 
  680.     
  681.     CLI Example:: 
  682.     
  683.         salt '*' virt.migrate_non_shared_inc <vm name> <target hypervisor> 
  684.     '''  
  685.     cmd = _get_migrate_command() + ' --copy-storage-inc ' + vm_\  
  686.         + _get_target(target, ssh)  
  687.      
  688.     return subprocess.Popen(cmd,  
  689.             shell=True,  
  690.             stdout=subprocess.PIPE).communicate()[0]  
  691.      
  692.      
  693. def migrate(vm_, target, ssh=False):  
  694.     ''''' 
  695.     Shared storage migration 
  696.     
  697.     CLI Example:: 
  698.     
  699.         salt '*' virt.migrate <vm name> <target hypervisor> 
  700.     '''  
  701.     cmd = _get_migrate_command() + ' ' + vm_\  
  702.         + _get_target(target, ssh)  
  703.      
  704.     return subprocess.Popen(cmd,  
  705.             shell=True,  
  706.             stdout=subprocess.PIPE).communicate()[0]  
  707.      
  708. def seed_non_shared_migrate(disks, force=False):  
  709.     ''''' 
  710.     Non shared migration requires that the disks be present on the migration 
  711.     destination, pass the disks information via this function, to the 
  712.     migration destination before executing the migration. 
  713.     
  714.     CLI Example:: 
  715.     
  716.         salt '*' virt.seed_non_shared_migrate <disks> 
  717.     '''  
  718.     for _, data in disks.items():  
  719.         fn_ = data['file']  
  720.         form = data['file format']  
  721.         size = data['virtual size'].split()[1][1:]  
  722.         if os.path.isfile(fn_) and not force:  
  723.             # the target exists, check to see if is is compatible  
  724.             pre = yaml.safe_load(subprocess.Popen('qemu-img info arch',  
  725.                 shell=True,  
  726.                 stdout=subprocess.PIPE).communicate()[0])  
  727.             if not pre['file format'] == data['file format']\  
  728.                     and not pre['virtual size'] == data['virtual size']:  
  729.                 return False  
  730.         if not os.path.isdir(os.path.dirname(fn_)):  
  731.             os.makedirs(os.path.dirname(fn_))  
  732.         if os.path.isfile(fn_):  
  733.             os.remove(fn_)  
  734.         cmd = 'qemu-img create -f ' + form + ' ' + fn_ + ' ' + size  
  735.         subprocess.call(cmd, shell=True)  
  736.         creds = _libvirt_creds()  
  737.         cmd = 'chown ' + creds['user'] + ':' + creds['group'] + ' ' + fn_  
  738.         subprocess.call(cmd, shell=True)  
  739.     return True  
  740.      
  741.      
  742. def set_autostart(vm_, state='on'):  
  743.     ''''' 
  744.     Set the autostart flag on a VM so that the VM will start with the host 
  745.     system on reboot. 
  746.     
  747.     CLI Example:: 
  748.     
  749.         salt "*" virt.set_autostart <vm name> <on | off> 
  750.     '''  
  751.      
  752.     dom = _get_dom(vm_)  
  753.      
  754.     if state == 'on':  
  755.         return dom.setAutostart(1) == 0  
  756.      
  757.     elif state == 'off':  
  758.         return dom.setAutostart(0) == 0  
  759.      
  760.     else:  
  761.         # return False if state is set to something other then on or off  
  762.         return False  
  763.      
  764.      
  765. def destroy(vm_):  
  766.     ''''' 
  767.     Hard power down the virtual machine, this is equivalent to pulling the 
  768.     power 
  769.     
  770.     CLI Example:: 
  771.     
  772.         salt '*' virt.destroy <vm name> 
  773.     '''  
  774.     dom = _get_dom(vm_)  
  775.     return dom.destroy() == 0  
  776.      
  777.      
  778. def undefine(vm_):  
  779.     ''''' 
  780.     Remove a defined vm, this does not purge the virtual machine image, and 
  781.     this only works if the vm is powered down 
  782.     
  783.     CLI Example:: 
  784.     
  785.         salt '*' virt.undefine <vm name> 
  786.     '''  
  787.     dom = _get_dom(vm_)  
  788.     return dom.undefine() == 0  
  789.      
  790.      
  791. def purge(vm_, dirs=False):  
  792.     ''''' 
  793.     Recursively destroy and delete a virtual machine, pass True for dir's to 
  794.     also delete the directories containing the virtual machine disk images - 
  795.     USE WITH EXTREME CAUTION! 
  796.     
  797.     CLI Example:: 
  798.     
  799.         salt '*' virt.purge <vm name> 
  800.     '''  
  801.     disks = get_disks(vm_)  
  802.     if not destroy(vm_):  
  803.         return False  
  804.     directories = set()  
  805.     for disk in disks:  
  806.         os.remove(disks[disk]['file'])  
  807.         directories.add(os.path.dirname(disks[disk]['file']))  
  808.     if dirs:  
  809.         for dir_ in directories:  
  810.             shutil.rmtree(dir_)  
  811.     return True  
  812.      
  813.      
  814. def virt_type():  
  815.     ''''' 
  816.     Returns the virtual machine type as a string 
  817.     
  818.     CLI Example:: 
  819.     
  820.         salt '*' virt.virt_type 
  821.     '''  
  822.     return __grains__['virtual']  
  823.      
  824.      
  825. def is_kvm_hyper():  
  826.     ''''' 
  827.     Returns a bool whether or not this node is a KVM hypervisor 
  828.     
  829.     CLI Example:: 
  830.     
  831.         salt '*' virt.is_kvm_hyper 
  832.     '''  
  833.     if __grains__['virtual'] != 'physical':  
  834.         return False  
  835.     try:  
  836.         if 'kvm_' not in salt.utils.fopen('/proc/modules').read():  
  837.             return False  
  838.     except IOError:  
  839.         # No /proc/modules? Are we on Windows? Or Solaris?  
  840.         return False  
  841.     return 'libvirtd' in __salt__['cmd.run'](__grains__['ps'])  
  842.      
  843.      
  844. def is_xen_hyper():  
  845.     ''''' 
  846.     Returns a bool whether or not this node is a XEN hypervisor 
  847.     
  848.     CLI Example:: 
  849.     
  850.         salt '*' virt.is_xen_hyper 
  851.     '''  
  852.     try:  
  853.         if __grains__['virtual_subtype'] != 'Xen Dom0':  
  854.             return False  
  855.     except KeyError:  
  856.         # virtual_subtype isn't set everywhere.  
  857.         return False  
  858.     try:  
  859.         if 'xen_' not in salt.utils.fopen('/proc/modules').read():  
  860.             return False  
  861.     except IOError:  
  862.         # No /proc/modules? Are we on Windows? Or Solaris?  
  863.         return False  
  864.     return 'libvirtd' in __salt__['cmd.run'](__grains__['ps'])  
  865.      
  866.      
  867. def is_hyper():  
  868.     ''''' 
  869.     Returns a bool whether or not this node is a hypervisor of any kind 
  870.     
  871.     CLI Example:: 
  872.     
  873.         salt '*' virt.is_hyper 
  874.     '''  
  875.     return is_xen_hyper() or is_kvm_hyper()  
  876.      
  877. def vm_cputime(vm_=None):  
  878.     ''''' 
  879.     Return cputime used by the vms on this hyper in a 
  880.     list of dicts:: 
  881.     
  882.         [ 
  883.             'your-vm': { 
  884.                 'cputime' <int> 
  885.                 'cputime_percent' <int> 
  886.                 }, 
  887.             ... 
  888.             ] 
  889.     
  890.     If you pass a VM name in as an argument then it will return info 
  891.     for just the named VM, otherwise it will return all VMs. 
  892.     
  893.     CLI Example:: 
  894.     
  895.         salt '*' virt.vm_cputime 
  896.     '''  
  897.     host_cpus = __get_conn().getInfo()[2]  
  898.     def _info(vm_):  
  899.         dom = _get_dom(vm_)  
  900.         raw = dom.info()  
  901.         vcpus = int(raw[3])  
  902.         cputime = int(raw[4])  
  903.         cputime_percent = 0  
  904.         if cputime:  
  905.             # Divide by vcpus to always return a number between 0 and 100  
  906.             cputime_percent = (1.0e-7 * cputime / host_cpus) / vcpus  
  907.         return {  
  908.                 'cputime': int(raw[4]),  
  909.                 'cputime_percent': int('%.0f' %cputime_percent)  
  910.                }  
  911.     info = {}  
  912.     if vm_:  
  913.         info[vm_] = _info(vm_)  
  914.     else:  
  915.         for vm_ in list_vms():  
  916.             info[vm_] = _info(vm_)  
  917.     return info  
  918.      
  919. def vm_netstats(vm_=None):  
  920.     ''''' 
  921.     Return combined network counters used by the vms on this hyper in a 
  922.     list of dicts:: 
  923.     
  924.         [ 
  925.             'your-vm': { 
  926.                 'rx_bytes'   : 0, 
  927.                 'rx_packets' : 0, 
  928.                 'rx_errs'    : 0, 
  929.                 'rx_drop'    : 0, 
  930.                 'tx_bytes'   : 0, 
  931.                 'tx_packets' : 0, 
  932.                 'tx_errs'    : 0, 
  933.                 'tx_drop'    : 0 
  934.                 }, 
  935.             ... 
  936.             ] 
  937.     
  938.     If you pass a VM name in as an argument then it will return info 
  939.     for just the named VM, otherwise it will return all VMs. 
  940.     
  941.     CLI Example:: 
  942.     
  943.         salt '*' virt.vm_netstats 
  944.     '''  
  945.     def _info(vm_):  
  946.         dom = _get_dom(vm_)  
  947.         nics = get_nics(vm_)  
  948.         ret = {  
  949.                 'rx_bytes'   : 0,  
  950.                 'rx_packets' : 0,  
  951.                 'rx_errs'    : 0,  
  952.                 'rx_drop'    : 0,  
  953.                 'tx_bytes'   : 0,  
  954.                 'tx_packets' : 0,  
  955.                 'tx_errs'    : 0,  
  956.                 'tx_drop'    : 0  
  957.                }  
  958.         for mac, attrs in nics.items():  
  959.             if 'target' in attrs:  
  960.                 dev = attrs['target']  
  961.                 stats = dom.interfaceStats(dev)  
  962.                 ret['rx_bytes'] += stats[0]  
  963.                 ret['rx_packets'] += stats[1]  
  964.                 ret['rx_errs'] += stats[2]  
  965.                 ret['rx_drop'] += stats[3]  
  966.                 ret['tx_bytes'] += stats[4]  
  967.                 ret['tx_packets'] += stats[5]  
  968.                 ret['tx_errs'] += stats[6]  
  969.                 ret['tx_drop'] += stats[7]  
  970.      
  971.         return ret  
  972.     info = {}  
  973.     if vm_:  
  974.         info[vm_] = _info(vm_)  
  975.     else:  
  976.         for vm_ in list_vms():  
  977.             info[vm_] = _info(vm_)  
  978.     return info  
  979.      
  980. def vm_diskstats(vm_=None):  
  981.     ''''' 
  982.     Return disk usage counters used by the vms on this hyper in a 
  983.     list of dicts:: 
  984.     
  985.         [ 
  986.             'your-vm': { 
  987.                 'rd_req'   : 0, 
  988.                 'rd_bytes' : 0, 
  989.                 'wr_req'   : 0, 
  990.                 'wr_bytes' : 0, 
  991.                 'errs'     : 0 
  992.                 }, 
  993.             ... 
  994.             ] 
  995.     
  996.     If you pass a VM name in as an argument then it will return info 
  997.     for just the named VM, otherwise it will return all VMs. 
  998.     
  999.     CLI Example:: 
  1000.     
  1001.         salt '*' virt.vm_blockstats 
  1002.     '''  
  1003.     def get_disk_devs(vm_):  
  1004.         doc = minidom.parse(_StringIO(get_xml(vm_)))  
  1005.         disks = []  
  1006.         for elem in doc.getElementsByTagName('disk'):  
  1007.             targets = elem.getElementsByTagName('target')  
  1008.             target = targets[0]  
  1009.             disks.append(target.getAttribute('dev'))  
  1010.         return disks  
  1011.      
  1012.     def _info(vm_):  
  1013.         dom = _get_dom(vm_)  
  1014.         # Do not use get_disks, since it uses qemu-img and is very slow  
  1015.         # and unsuitable for any sort of real time statistics  
  1016.         disks = get_disk_devs(vm_)  
  1017.         ret = {  
  1018.                 'rd_req'   : 0,  
  1019.                 'rd_bytes' : 0,  
  1020.                 'wr_req'   : 0,  
  1021.                 'wr_bytes' : 0,  
  1022.                 'errs'     : 0  
  1023.                }  
  1024.         for disk in disks:  
  1025.             stats = dom.blockStats(disk)  
  1026.             ret['rd_req']   += stats[0]  
  1027.             ret['rd_bytes'] += stats[1]  
  1028.             ret['wr_req']   += stats[2]  
  1029.             ret['wr_bytes'] += stats[3]  
  1030.             ret['errs']     += stats[4]  
  1031.      
  1032.         return ret  
  1033.     info = {}  
  1034.     if vm_:  
  1035.         info[vm_] = _info(vm_)  
  1036.     else:  
  1037.         # Can not run function blockStats on inactive VMs  
  1038.         for vm_ in list_active_vms():  
  1039.             info[vm_] = _info(vm_)  
  1040.     return info  
  1041. </span>  
 

猜你喜欢

转载自www.cnblogs.com/zknublx/p/9200563.html