mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
487c826700
'name' is the preferred form. Similarly, take 'name' for the 'guest' argument to the 'virt' module.
452 lines
11 KiB
Python
Executable file
452 lines
11 KiB
Python
Executable file
#!/usr/bin/python
|
|
"""
|
|
Virt management features
|
|
|
|
Copyright 2007, 2012 Red Hat, Inc
|
|
Michael DeHaan <mdehaan@redhat.com>
|
|
Seth Vidal <skvidal@fedoraproject.org>
|
|
|
|
This software may be freely redistributed under the terms of the GNU
|
|
general public license.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
"""
|
|
|
|
VIRT_FAILED = 1
|
|
VIRT_SUCCESS = 0
|
|
VIRT_UNAVAILABLE=2
|
|
|
|
try:
|
|
import json
|
|
except ImportError:
|
|
import simplejson as json
|
|
|
|
|
|
# other modules
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
import syslog
|
|
try:
|
|
import libvirt
|
|
except ImportError:
|
|
print json.dumps({
|
|
"failed" : True,
|
|
"msg" : "libvirt python module unavailable",
|
|
"rc": VIRT_UNAVAILABLE,
|
|
})
|
|
sys.exit(1)
|
|
|
|
|
|
import shlex
|
|
|
|
VIRT_STATE_NAME_MAP = {
|
|
0 : "running",
|
|
1 : "running",
|
|
2 : "running",
|
|
3 : "paused",
|
|
4 : "shutdown",
|
|
5 : "shutdown",
|
|
6 : "crashed"
|
|
}
|
|
|
|
class LibvirtConnection(object):
|
|
|
|
def __init__(self):
|
|
|
|
cmd = subprocess.Popen("uname -r", shell=True, stdout=subprocess.PIPE,
|
|
close_fds=True)
|
|
output = cmd.communicate()[0]
|
|
|
|
if output.find("xen") != -1:
|
|
conn = libvirt.open(None)
|
|
else:
|
|
conn = libvirt.open("qemu:///system")
|
|
|
|
if not conn:
|
|
raise Exception("hypervisor connection failure")
|
|
|
|
self.conn = conn
|
|
|
|
def find_vm(self, vmid):
|
|
"""
|
|
Extra bonus feature: vmid = -1 returns a list of everything
|
|
"""
|
|
conn = self.conn
|
|
|
|
vms = []
|
|
|
|
# this block of code borrowed from virt-manager:
|
|
# get working domain's name
|
|
ids = conn.listDomainsID()
|
|
for id in ids:
|
|
vm = conn.lookupByID(id)
|
|
vms.append(vm)
|
|
# get defined domain
|
|
names = conn.listDefinedDomains()
|
|
for name in names:
|
|
vm = conn.lookupByName(name)
|
|
vms.append(vm)
|
|
|
|
if vmid == -1:
|
|
return vms
|
|
|
|
for vm in vms:
|
|
if vm.name() == vmid:
|
|
return vm
|
|
|
|
raise Exception("virtual machine %s not found" % vmid)
|
|
|
|
def shutdown(self, vmid):
|
|
return self.find_vm(vmid).shutdown()
|
|
|
|
def pause(self, vmid):
|
|
return self.suspend(self.conn,vmid)
|
|
|
|
def unpause(self, vmid):
|
|
return self.resume(self.conn,vmid)
|
|
|
|
def suspend(self, vmid):
|
|
return self.find_vm(vmid).suspend()
|
|
|
|
def resume(self, vmid):
|
|
return self.find_vm(vmid).resume()
|
|
|
|
def create(self, vmid):
|
|
return self.find_vm(vmid).create()
|
|
|
|
def destroy(self, vmid):
|
|
return self.find_vm(vmid).destroy()
|
|
|
|
def undefine(self, vmid):
|
|
return self.find_vm(vmid).undefine()
|
|
|
|
def get_status2(self, vm):
|
|
state = vm.info()[0]
|
|
return VIRT_STATE_NAME_MAP.get(state,"unknown")
|
|
|
|
def get_status(self, vmid):
|
|
state = self.find_vm(vmid).info()[0]
|
|
return VIRT_STATE_NAME_MAP.get(state,"unknown")
|
|
|
|
def nodeinfo(self):
|
|
return self.conn.getInfo()
|
|
|
|
def get_type(self):
|
|
return self.conn.getType()
|
|
|
|
def get_maxVcpus(self, vmid):
|
|
vm = self.conn.lookupByName(vmid)
|
|
return vm.maxVcpus()
|
|
|
|
def get_maxMemory(self, vmid):
|
|
vm = self.conn.lookupByName(vmid)
|
|
return vm.maxMemory()
|
|
|
|
def getFreeMemory(self):
|
|
return self.conn.getFreeMemory()
|
|
|
|
def get_autostart(self, vmid):
|
|
vm = self.conn.lookupByName(vmid)
|
|
return vm.autostart()
|
|
|
|
def set_autostart(self, vmid, val):
|
|
vm = self.conn.lookupByName(vmid)
|
|
return vm.setAutostart(val)
|
|
|
|
|
|
|
|
class Virt(object):
|
|
|
|
def __get_conn(self):
|
|
self.conn = LibvirtConnection()
|
|
return self.conn
|
|
|
|
def get_vm(self, vmid):
|
|
self.__get_conn()
|
|
return self.conn.find_vm(vmid)
|
|
|
|
def state(self):
|
|
vms = self.list_vms()
|
|
state = []
|
|
for vm in vms:
|
|
state_blurb = self.conn.get_status(vm)
|
|
state.append("%s %s" % (vm,state_blurb))
|
|
return state
|
|
|
|
|
|
def info(self):
|
|
vms = self.list_vms()
|
|
info = dict()
|
|
for vm in vms:
|
|
data = self.conn.find_vm(vm).info()
|
|
# libvirt returns maxMem, memory, and cpuTime as long()'s, which
|
|
# xmlrpclib tries to convert to regular int's during serialization.
|
|
# This throws exceptions, so convert them to strings here and
|
|
# assume the other end of the xmlrpc connection can figure things
|
|
# out or doesn't care.
|
|
info[vm] = {
|
|
"state" : VIRT_STATE_NAME_MAP.get(data[0],"unknown"),
|
|
"maxMem" : str(data[1]),
|
|
"memory" : str(data[2]),
|
|
"nrVirtCpu" : data[3],
|
|
"cpuTime" : str(data[4]),
|
|
}
|
|
info[vm]["autostart"] = self.conn.get_autostart(vm)
|
|
|
|
return info
|
|
|
|
def nodeinfo(self):
|
|
self.__get_conn()
|
|
info = dict()
|
|
data = self.conn.nodeinfo()
|
|
info = {
|
|
"cpumodel" : str(data[0]),
|
|
"phymemory" : str(data[1]),
|
|
"cpus" : str(data[2]),
|
|
"cpumhz" : str(data[3]),
|
|
"numanodes" : str(data[4]),
|
|
"sockets" : str(data[5]),
|
|
"cpucores" : str(data[6]),
|
|
"cputhreads" : str(data[7])
|
|
}
|
|
return info
|
|
|
|
def list_vms(self):
|
|
self.conn = self.__get_conn()
|
|
vms = self.conn.find_vm(-1)
|
|
results = []
|
|
for x in vms:
|
|
try:
|
|
results.append(x.name())
|
|
except:
|
|
pass
|
|
return results
|
|
|
|
def virttype(self):
|
|
return self.__get_conn().get_type()
|
|
|
|
|
|
def autostart(self, vmid):
|
|
self.conn = self.__get_conn()
|
|
return self.conn.set_autostart(vmid, True)
|
|
|
|
def freemem(self):
|
|
self.conn = self.__get_conn()
|
|
return self.conn.getFreeMemory()
|
|
|
|
def shutdown(self, vmid):
|
|
"""
|
|
Make the machine with the given vmid stop running.
|
|
Whatever that takes.
|
|
"""
|
|
self.__get_conn()
|
|
self.conn.shutdown(vmid)
|
|
return 0
|
|
|
|
|
|
def pause(self, vmid):
|
|
|
|
"""
|
|
Pause the machine with the given vmid.
|
|
"""
|
|
self.__get_conn()
|
|
return self.conn.suspend(vmid)
|
|
|
|
|
|
def unpause(self, vmid):
|
|
|
|
"""
|
|
Unpause the machine with the given vmid.
|
|
"""
|
|
|
|
self.__get_conn()
|
|
return self.conn.resume(vmid)
|
|
|
|
|
|
def create(self, vmid):
|
|
|
|
"""
|
|
Start the machine via the given mac address.
|
|
"""
|
|
self.__get_conn()
|
|
return self.conn.create(vmid)
|
|
|
|
def start(self, vmid):
|
|
|
|
"""
|
|
Start the machine via the given id/name
|
|
"""
|
|
self.__get_conn()
|
|
return self.conn.create(vmid)
|
|
|
|
|
|
def destroy(self, vmid):
|
|
|
|
"""
|
|
Pull the virtual power from the virtual domain, giving it virtually no
|
|
time to virtually shut down.
|
|
"""
|
|
self.__get_conn()
|
|
return self.conn.destroy(vmid)
|
|
|
|
|
|
def undefine(self, vmid):
|
|
|
|
"""
|
|
Stop a domain, and then wipe it from the face of the earth.
|
|
by deleting the disk image and its configuration file.
|
|
"""
|
|
|
|
self.__get_conn()
|
|
return self.conn.undefine(vmid)
|
|
|
|
|
|
def status(self, vmid):
|
|
|
|
"""
|
|
Return a state suitable for server consumption. Aka, codes.py values, not XM output.
|
|
"""
|
|
|
|
self.__get_conn()
|
|
return self.conn.get_status(vmid)
|
|
|
|
|
|
def get_xml(self, vmid):
|
|
"""
|
|
Receive a Vm id as input
|
|
Return an xml describing vm config returned by a libvirt call
|
|
"""
|
|
conn = libvirt.openReadOnly(None)
|
|
if conn == None:
|
|
return (-1,'Failed to open connection to the hypervisor')
|
|
try:
|
|
domV = conn.lookupByName(vmid)
|
|
except:
|
|
return (-1,'Failed to find the main domain')
|
|
return domV.XMLDesc(0)
|
|
|
|
|
|
def get_maxVcpus(self, vmid):
|
|
"""
|
|
Gets the max number of VCPUs on a guest
|
|
"""
|
|
|
|
self.__get_conn()
|
|
return self.conn.get_maxVcpus(vmid)
|
|
|
|
def get_max_memory(self, vmid):
|
|
"""
|
|
Gets the max memory on a guest
|
|
"""
|
|
|
|
self.__get_conn()
|
|
return self.conn.get_MaxMemory(vmid)
|
|
|
|
def main():
|
|
rc = VIRT_SUCCESS
|
|
vm_commands = ['create','status', 'start', 'stop', 'pause', 'unpause',
|
|
'shutdown', 'undefine', 'destroy', 'get_xml', 'autostart']
|
|
host_commands = ['freemem', 'list_vms', 'info', 'nodeinfo', 'virttype']
|
|
|
|
msg = """
|
|
virtmodule arguments:
|
|
state=[running|shutdown] guest=guestname
|
|
command=some_virt_command [guest=guestname]
|
|
"""
|
|
|
|
if len(sys.argv) == 1:
|
|
return VIRT_FAILED, msg
|
|
|
|
argfile = sys.argv[1]
|
|
if not os.path.exists(argfile):
|
|
msg = "Argument file not found"
|
|
return VIRT_FAILED, msg
|
|
|
|
args = open(argfile, 'r').read()
|
|
items = shlex.split(args)
|
|
syslog.openlog('ansible-%s' % os.path.basename(__file__))
|
|
syslog.syslog(syslog.LOG_NOTICE, 'Invoked with %s' % args)
|
|
|
|
if not len(items):
|
|
return VIRT_FAILED, msg
|
|
|
|
|
|
# guest=name state=[running|shutdown|destroyed|undefined]
|
|
# command=[some command] [guest=name]
|
|
|
|
params = {}
|
|
if '=' not in args:
|
|
msg = "No proper arguments provided to virt module: %s" % args
|
|
return VIRT_FAILED, msg
|
|
|
|
for x in items:
|
|
(k, v) = x.split("=")
|
|
params[k] = v
|
|
|
|
state = params.get('state', None)
|
|
guest = params.get('guest', params.get('name', None))
|
|
command = params.get('command', None)
|
|
options = params.get('options', [])
|
|
|
|
v = Virt()
|
|
res = {}
|
|
|
|
if state:
|
|
if not guest:
|
|
msg = "state change requires a guest specified"
|
|
return VIRT_FAILED, msg
|
|
|
|
res['changed'] = False
|
|
if state == 'running':
|
|
if v.status(guest) is not 'running':
|
|
res['changed'] = True
|
|
res['msg'] = v.start(guest)
|
|
elif state == 'shutdown':
|
|
if v.status(guest) is not 'shutdown':
|
|
res['changed'] = True
|
|
res['msg'] = v.shutdown(guest)
|
|
|
|
return VIRT_SUCCESS, res
|
|
|
|
if command:
|
|
if command in vm_commands:
|
|
if not guest:
|
|
msg = "%s requires 1 argument: guest" % command
|
|
return VIRT_FAILED, msg
|
|
|
|
res = getattr(v, command)(guest)
|
|
if type(res) != dict:
|
|
res = { command: res }
|
|
return rc, res
|
|
|
|
elif hasattr(v, command):
|
|
res = getattr(v, command)()
|
|
if type(res) != dict:
|
|
res = { command: res }
|
|
return rc, res
|
|
|
|
else:
|
|
msg = "Command %s not recognized" % basecmd
|
|
rc = VIRT_FAILED
|
|
|
|
return rc, msg
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
rc, result = main()
|
|
except Exception, e:
|
|
rc = 1
|
|
result = str(e)
|
|
|
|
if rc != 0: # something went wrong emit the msg
|
|
print json.dumps({
|
|
"failed" : rc,
|
|
"msg" : result,
|
|
"rc": rc,
|
|
})
|
|
sys.exit(rc)
|
|
else:
|
|
print json.dumps(result)
|
|
|