經過python-libvirt管理KVM虛擬機 代碼實現
初步代碼html
- <span style="font-size:18px;">''
-
- import os
- import re
- import shutil
- import subprocess
- from xml.dom import minidom
-
- try:
- import libvirt
- HAS_LIBVIRT = True
- except ImportError:
- HAS_LIBVIRT = False
- import yaml
-
- import salt.utils
- from salt._compat import StringIO as _StringIO
- from salt.exceptions import CommandExecutionError
-
-
- VIRT_STATE_NAME_MAP = {0: 'running',
- 1: 'running',
- 2: 'running',
- 3: 'paused',
- 4: 'shutdown',
- 5: 'shutdown',
- 6: 'crashed'}
-
-
- def __virtual__():
- if not HAS_LIBVIRT:
- return False
- return 'virt'
-
-
- def __get_conn():
- ''
-
-
- try:
- conn = libvirt.open('qemu:///system')
- except Exception:
- raise CommandExecutionError(
- 'Sorry, {0} failed to open a connection to the hypervisor '
- 'software'.format(
- __grains__['fqdn']
- )
- )
- return conn
-
-
- def _get_dom(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():
- ''
- 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('"'
- except IndexError:
- user = 'root'
- return {'user': user, 'group': group}
-
- def _get_migrate_command():
- ''
- return 'virsh migrate --live --persistent --undefinesource '
-
- def _get_target(target, ssh):
- proto = 'qemu'
- if ssh:
- proto += '+ssh'
- return ' %s://%s/%s' %(proto, target, 'system')
-
- def list_vms():
- ''
- vms = []
- vms.extend(list_active_vms())
- vms.extend(list_inactive_vms())
- return vms
-
-
- def list_active_vms():
- ''
- conn = __get_conn()
- vms = []
- for id_ in conn.listDomainsID():
- vms.append(conn.lookupByID(id_).name())
- return vms
-
-
- def list_inactive_vms():
- ''
- conn = __get_conn()
- vms = []
- for id_ in conn.listDefinedDomains():
- vms.append(id_)
- return vms
-
-
- def vm_info(vm_=None):
- ''
- 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):
- ''
- 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():
- ''
- 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_):
- ''
- 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')
-
- if re.match('(driver|source|address)', v_node.tagName):
- temp = {}
- for key in v_node.attributes.keys():
- temp[key] = v_node.getAttribute(key)
- nic[str(v_node.tagName)] = temp
-
-
- if v_node.tagName == 'virtualport':
- temp = {}
- temp['type'] = v_node.getAttribute('type')
- for key in v_node.attributes.keys():
- temp[key] = v_node.getAttribute(key)
- nic['virtualport'] = temp
- if 'mac' not in nic:
- continue
- nics[nic['mac']] = nic
- return nics
-
-
- def get_macs(vm_):
- ''
- 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_):
- ''
- 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 in g_node.attributes.keys():
- out[key] = g_node.getAttribute(key)
- return out
-
-
- def get_disks(vm_):
- ''
- 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'):
- qemu_target = '%s:%s' %(
- source.getAttribute('protocol'),
- source.getAttribute('name'))
- if qemu_target:
- disks[target.getAttribute('dev')] = {\
- 'file': qemu_target}
- for dev in disks:
- try:
- 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
- elif snapshots:
- if line.startswith('ID'):
- line = line.replace('VM SIZE', 'VMSIZE')
- line = line.replace('VM CLOCK', 'TIME VMCLOCK')
- columns = re.split('\s+', line)
- columns = [c.lower() for c in columns]
- output.append('snapshots:')
- continue
- fields = re.split('\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):
- ''
- if vm_state(vm_) != 'shutdown':
- return False
-
- dom = _get_dom(vm_)
-
-
-
-
- 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 ret1 == ret2 == 0
-
-
- def setvcpus(vm_, vcpus, config=False):
- ''
- if vm_state(vm_) != 'shutdown':
- return False
-
- dom = _get_dom(vm_)
-
-
- 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():
- ''
- conn = __get_conn()
- mem = conn.getInfo()[1]
-
- mem -= 256
- for vm_ in list_vms():
- dom = _get_dom(vm_)
- if dom.ID() > 0:
- mem -= dom.info()[2] / 1024
- return mem
-
-
- def 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 {'freecpu': freecpu(),
- 'freemem': freemem(),
- 'node_info': node_info(),
- 'vm_info': vm_info()}
-
-
- def get_xml(vm_):
- ''
- dom = _get_dom(vm_)
- return dom.XMLDesc(0)
-
-
- def shutdown(vm_):
- ''
- dom = _get_dom(vm_)
- return dom.shutdown() == 0
-
-
- def pause(vm_):
- ''
- dom = _get_dom(vm_)
- return dom.suspend() == 0
-
-
- def resume(vm_):
- ''
- dom = _get_dom(vm_)
- return dom.resume() == 0
-
-
- def create(vm_):
- ''
- dom = _get_dom(vm_)
- return dom.create() == 0
-
-
- def start(vm_):
- ''
- return create(vm_)
-
-
- def reboot(vm_):
- ''
- dom = _get_dom(vm_)
-
-
-
- return dom.reboot(0) == 0
-
-
- def reset(vm_):
- ''
- dom = _get_dom(vm_)
-
-
-
-
- return dom.reset(0) == 0
-
-
- def ctrl_alt_del(vm_):
- ''
- dom = _get_dom(vm_)
- return dom.sendKey(0, 0, [29, 56, 111], 3, 0) == 0
-
-
- def create_xml_str(xml):
- ''
- conn = __get_conn()
- return conn.createXML(xml, 0) is not None
-
-
- def create_xml_path(path):
- ''
- if not os.path.isfile(path):
- return False
- return create_xml_str(salt.utils.fopen(path, 'r').read())
-
-
- def define_xml_str(xml):
- ''
- conn = __get_conn()
- return conn.defineXML(xml) is not None
-
- def migrate_non_shared(vm_, target, ssh=False):
- ''
- 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):
- ''
- 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):
- ''
- 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):
- ''
- 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:
-
- pre = yaml.safe_load(subprocess.Popen('qemu-img info arch',
- shell=True,
- stdout=subprocess.PIPE).communicate()[0])
- if not pre['file format'] == data['file format']\
- and not 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'):
- ''
-
- dom = _get_dom(vm_)
-
- if state == 'on':
- return dom.setAutostart(1) == 0
-
- elif state == 'off':
- return dom.setAutostart(0) == 0
-
- else:
-
- return False
-
-
- def destroy(vm_):
- ''
- dom = _get_dom(vm_)
- return dom.destroy() == 0
-
-
- def undefine(vm_):
- ''
- dom = _get_dom(vm_)
- return dom.undefine() == 0
-
-
- def purge(vm_, dirs=False):
- ''
- disks = get_disks(vm_)
- if not destroy(vm_):
- return False
- 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_)
- return True
-
-
- def virt_type():
- ''
- return __grains__['virtual']
-
-
- def is_kvm_hyper():
- ''
- if __grains__['virtual'] != 'physical':
- return False
- try:
- if 'kvm_' not in salt.utils.fopen('/proc/modules').read():
- return False
- except IOError:
-
- return False
- return 'libvirtd' in __salt__['cmd.run'](__grains__['ps'])
-
-
- def is_xen_hyper():
- ''
- try:
- if __grains__['virtual_subtype'] != 'Xen Dom0':
- return False
- except KeyError:
-
- return False
- try:
- if 'xen_' not in salt.utils.fopen('/proc/modules').read():
- return False
- except IOError:
-
- return False
- return 'libvirtd' in __salt__['cmd.run'](__grains__['ps'])
-
-
- def is_hyper():
- ''
- return is_xen_hyper() or is_kvm_hyper()
-
- def vm_cputime(vm_=None):
- ''
- 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:
-
- cputime_percent = (1.0e-7 * cputime / host_cpus) / vcpus
- return {
- 'cputime': int(raw[4]),
- 'cputime_percent': int('%.0f' %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):
- ''
- 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 mac, attrs in nics.items():
- 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):
- ''
- 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_)
-
-
- 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:
-
- for vm_ in list_active_vms():
- info[vm_] = _info(vm_)
- return info
- </span>
歡迎關注本站公眾號,獲取更多信息