2018-05-31 20:26:44 -04:00
#!/usr/bin/env python3
2018-10-14 02:01:35 -04:00
# DomainInstance.py - Class implementing a PVC virtual machine in pvcd
2018-06-06 01:47:53 -04:00
# Part of the Parallel Virtual Cluster (PVC) system
#
# Copyright (C) 2018 Joshua M. Boniface <joshua@boniface.me>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
###############################################################################
2018-09-20 03:42:40 -04:00
import os
import sys
import uuid
import socket
import time
import threading
import libvirt
import kazoo . client
2018-10-14 02:01:35 -04:00
import pvcd . log as log
import pvcd . zkhandler as zkhandler
2018-06-06 22:56:03 -04:00
2019-04-11 19:06:06 -04:00
import pvcd . DomainConsoleWatcherInstance as DomainConsoleWatcherInstance
2018-10-14 22:14:29 -04:00
class DomainInstance ( object ) :
2018-06-06 22:59:31 -04:00
# Initialization function
2018-10-14 02:01:35 -04:00
def __init__ ( self , domuuid , zk_conn , config , logger , this_node ) :
2018-05-31 20:26:44 -04:00
# Passed-in variables on creation
self . domuuid = domuuid
2019-04-11 19:06:06 -04:00
self . domname = zkhandler . readdata ( zk_conn , ' /domains/ {} ' . format ( domuuid ) )
2018-06-17 21:55:39 -04:00
self . zk_conn = zk_conn
2018-06-08 12:19:48 -04:00
self . config = config
2018-10-14 02:01:35 -04:00
self . logger = logger
self . this_node = this_node
2018-05-31 20:26:44 -04:00
# These will all be set later
2018-10-14 02:01:35 -04:00
self . node = None
2018-05-31 20:26:44 -04:00
self . state = None
2018-06-02 18:34:48 -04:00
self . instart = False
2018-06-13 12:47:30 -04:00
self . inrestart = False
2018-06-02 18:34:48 -04:00
self . inmigrate = False
self . inreceive = False
2018-06-13 12:47:30 -04:00
self . inshutdown = False
self . instop = False
2018-05-31 20:26:44 -04:00
2019-04-11 19:06:06 -04:00
# Libvirt domuuid
2018-06-11 20:12:11 -04:00
self . dom = self . lookupByUUID ( self . domuuid )
2018-07-17 21:42:28 -04:00
2019-04-11 19:06:06 -04:00
# Log watcher instance
self . console_log_instance = DomainConsoleWatcherInstance . DomainConsoleWatcherInstance ( self . domuuid , self . domname , self . zk_conn , self . config , self . logger , self . this_node )
2018-05-31 20:26:44 -04:00
# Watch for changes to the state field in Zookeeper
2018-10-01 22:51:34 -04:00
@self.zk_conn.DataWatch ( ' /domains/ {} /state ' . format ( self . domuuid ) )
2018-06-01 12:21:58 -04:00
def watch_state ( data , stat , event = " " ) :
2018-10-01 22:51:34 -04:00
if event and event . type == ' DELETED ' :
# The key has been deleted after existing before; terminate this watcher
# because this class instance is about to be reaped in Daemon.py
return False
2018-06-15 01:40:06 -04:00
# If we get a delete state, just terminate outselves
2018-06-15 01:50:39 -04:00
if data == None :
return
2018-06-15 01:40:06 -04:00
# Otherwise perform a management command
else :
self . manage_vm_state ( )
2018-06-11 20:12:11 -04:00
2019-04-11 19:06:06 -04:00
2018-06-02 15:03:44 -04:00
# Get data functions
2018-06-02 15:19:29 -04:00
def getstate ( self ) :
2018-06-02 15:03:44 -04:00
return self . state
2018-10-14 02:01:35 -04:00
def getnode ( self ) :
return self . node
2018-06-02 15:03:44 -04:00
2018-06-12 01:54:01 -04:00
def getdom ( self ) :
return self . dom
2018-07-17 21:51:49 -04:00
def getmemory ( self ) :
try :
2018-07-17 21:55:38 -04:00
memory = int ( self . dom . info ( ) [ 2 ] / 1024 )
2018-07-17 21:51:49 -04:00
except :
memory = 0
return memory
2018-07-17 21:40:30 -04:00
2018-07-18 12:09:07 -04:00
def getvcpus ( self ) :
try :
vcpus = int ( self . dom . info ( ) [ 3 ] )
except :
vcpus = 0
return vcpus
2018-06-19 20:01:26 -04:00
# Manage local node domain_list
def addDomainToList ( self ) :
2018-10-14 02:01:35 -04:00
if not self . domuuid in self . this_node . domain_list :
2018-06-19 20:01:26 -04:00
try :
2018-06-20 11:53:48 -04:00
# Add the domain to the domain_list array
2018-10-14 02:01:35 -04:00
self . this_node . domain_list . append ( self . domuuid )
2018-06-20 11:53:48 -04:00
# Push the change up to Zookeeper
2018-10-14 02:01:35 -04:00
zkhandler . writedata ( self . zk_conn , { ' /nodes/ {} /runningdomains ' . format ( self . this_node . name ) : ' ' . join ( self . this_node . domain_list ) } )
2018-06-19 20:01:26 -04:00
except Exception as e :
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Error adding domain to list: {} ' . format ( e ) , state = ' c ' )
2018-06-19 20:01:26 -04:00
def removeDomainFromList ( self ) :
2018-10-14 02:01:35 -04:00
if self . domuuid in self . this_node . domain_list :
2018-06-19 20:01:26 -04:00
try :
2018-06-20 11:53:48 -04:00
# Remove the domain from the domain_list array
2018-10-14 02:01:35 -04:00
self . this_node . domain_list . remove ( self . domuuid )
2018-06-20 11:53:48 -04:00
# Push the change up to Zookeeper
2018-10-14 02:01:35 -04:00
zkhandler . writedata ( self . zk_conn , { ' /nodes/ {} /runningdomains ' . format ( self . this_node . name ) : ' ' . join ( self . this_node . domain_list ) } )
2018-06-19 20:01:26 -04:00
except Exception as e :
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Error removing domain from list: {} ' . format ( e ) , state = ' c ' )
2018-06-19 20:01:26 -04:00
2018-05-31 20:26:44 -04:00
# Start up the VM
2018-06-13 12:31:27 -04:00
def start_vm ( self ) :
2019-04-11 19:06:06 -04:00
# Start the log watcher
self . console_log_instance . start ( )
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Starting VM ' , state = ' i ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-02 18:34:48 -04:00
self . instart = True
2018-06-04 01:22:18 -04:00
# Start up a new Libvirt connection
libvirt_name = " qemu:///system "
2018-06-17 21:55:39 -04:00
lv_conn = libvirt . open ( libvirt_name )
if lv_conn == None :
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Failed to open local libvirt connection ' , state = ' e ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-04 01:22:18 -04:00
self . instart = False
return
2018-08-23 19:01:57 -04:00
# Try to get the current state in case it's already running
2018-06-02 00:30:25 -04:00
try :
2018-08-23 19:01:57 -04:00
self . dom = self . lookupByUUID ( self . domuuid )
curstate = self . dom . state ( ) [ 0 ]
except :
curstate = ' notstart '
if curstate == libvirt . VIR_DOMAIN_RUNNING :
# If it is running just update the model
2018-06-19 20:01:26 -04:00
self . addDomainToList ( )
2018-07-19 22:46:50 -04:00
zkhandler . writedata ( self . zk_conn , { ' /domains/ {} /failedreason ' . format ( self . domuuid ) : ' ' } )
2018-08-23 19:01:57 -04:00
else :
# Or try to create it
try :
# Grab the domain information from Zookeeper
xmlconfig = zkhandler . readdata ( self . zk_conn , ' /domains/ {} /xml ' . format ( self . domuuid ) )
dom = lv_conn . createXML ( xmlconfig , 0 )
self . addDomainToList ( )
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Successfully started VM ' , state = ' o ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-08-23 19:01:57 -04:00
self . dom = dom
zkhandler . writedata ( self . zk_conn , { ' /domains/ {} /failedreason ' . format ( self . domuuid ) : ' ' } )
except libvirt . libvirtError as e :
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Failed to create VM ' , state = ' e ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-08-23 19:01:57 -04:00
zkhandler . writedata ( self . zk_conn , { ' /domains/ {} /state ' . format ( self . domuuid ) : ' failed ' } )
zkhandler . writedata ( self . zk_conn , { ' /domains/ {} /failedreason ' . format ( self . domuuid ) : str ( e ) } )
self . dom = None
2018-06-02 00:33:54 -04:00
2018-06-17 21:55:39 -04:00
lv_conn . close ( )
2019-04-11 19:06:06 -04:00
2018-06-02 18:34:48 -04:00
self . instart = False
2018-06-13 12:47:30 -04:00
# Restart the VM
def restart_vm ( self ) :
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Restarting VM ' , state = ' i ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-13 12:47:30 -04:00
self . inrestart = True
# Start up a new Libvirt connection
libvirt_name = " qemu:///system "
2018-06-17 21:55:39 -04:00
lv_conn = libvirt . open ( libvirt_name )
if lv_conn == None :
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Failed to open local libvirt connection ' , state = ' e ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-13 12:47:30 -04:00
self . inrestart = False
return
2018-07-20 01:02:18 -04:00
self . shutdown_vm ( )
self . start_vm ( )
self . addDomainToList ( )
2018-06-13 12:47:30 -04:00
2018-06-26 23:24:33 -04:00
zkhandler . writedata ( self . zk_conn , { ' /domains/ {} /state ' . format ( self . domuuid ) : ' start ' } )
2018-06-17 21:55:39 -04:00
lv_conn . close ( )
2018-06-13 12:47:30 -04:00
self . inrestart = False
2018-06-06 21:47:06 -04:00
# Stop the VM forcibly without updating state
def terminate_vm ( self ) :
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Terminating VM ' , state = ' i ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-06 21:47:06 -04:00
self . instop = True
try :
self . dom . destroy ( )
except AttributeError :
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Failed to terminate VM ' , state = ' e ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-19 20:01:26 -04:00
self . removeDomainFromList ( )
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Successfully terminated VM ' , state = ' o ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-12 21:44:06 -04:00
self . dom = None
2018-06-11 19:14:22 -04:00
self . instop = False
2018-06-06 21:47:06 -04:00
2019-04-11 19:06:06 -04:00
# Stop the log watcher
self . console_log_instance . stop ( )
2018-05-31 20:26:44 -04:00
# Stop the VM forcibly
def stop_vm ( self ) :
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Forcibly stopping VM ' , state = ' i ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-02 18:34:48 -04:00
self . instop = True
2018-06-06 11:48:28 -04:00
try :
self . dom . destroy ( )
except AttributeError :
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Failed to stop VM ' , state = ' e ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-19 20:01:26 -04:00
self . removeDomainFromList ( )
2018-06-02 15:52:50 -04:00
2018-06-13 12:52:40 -04:00
if self . inrestart == False :
2018-06-26 23:24:33 -04:00
zkhandler . writedata ( self . zk_conn , { ' /domains/ {} /state ' . format ( self . domuuid ) : ' stop ' } )
2018-06-13 12:52:40 -04:00
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Successfully stopped VM ' , state = ' o ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-02 15:52:50 -04:00
self . dom = None
2018-06-02 18:34:48 -04:00
self . instop = False
2018-05-31 20:26:44 -04:00
2019-04-11 19:06:06 -04:00
# Stop the log watcher
self . console_log_instance . stop ( )
2018-05-31 20:26:44 -04:00
# Shutdown the VM gracefully
def shutdown_vm ( self ) :
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Gracefully stopping VM ' , state = ' i ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-02 18:34:48 -04:00
self . inshutdown = True
2018-05-31 20:26:44 -04:00
self . dom . shutdown ( )
2018-06-02 16:24:11 -04:00
try :
2018-06-02 16:28:18 -04:00
tick = 0
while self . dom . state ( ) [ 0 ] == libvirt . VIR_DOMAIN_RUNNING and tick < 60 :
tick + = 1
2018-06-02 16:24:11 -04:00
time . sleep ( 0.5 )
2018-06-02 16:28:18 -04:00
if tick > = 60 :
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Shutdown timeout expired ' , state = ' e ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-02 16:28:18 -04:00
self . stop_vm ( )
2018-06-02 18:34:48 -04:00
self . inshutdown = False
2018-06-02 16:28:18 -04:00
return
2018-06-02 16:24:11 -04:00
except :
pass
2018-06-02 16:19:51 -04:00
2018-06-19 20:01:26 -04:00
self . removeDomainFromList ( )
2018-06-19 19:52:03 -04:00
2018-06-13 12:52:40 -04:00
if self . inrestart == False :
2018-06-26 23:24:33 -04:00
zkhandler . writedata ( self . zk_conn , { ' /domains/ {} /state ' . format ( self . domuuid ) : ' stop ' } )
2018-06-13 12:52:40 -04:00
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Successfully shutdown VM ' , state = ' o ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-02 15:52:50 -04:00
self . dom = None
2018-06-02 18:34:48 -04:00
self . inshutdown = False
2018-06-02 15:52:50 -04:00
2019-04-11 19:06:06 -04:00
# Stop the log watcher
self . console_log_instance . stop ( )
2018-10-14 02:01:35 -04:00
def live_migrate_vm ( self , dest_node ) :
2018-06-02 15:39:17 -04:00
try :
2018-10-14 02:01:35 -04:00
dest_lv_conn = libvirt . open ( ' qemu+tcp:// {} /system ' . format ( self . node ) )
2018-06-17 21:55:39 -04:00
if dest_lv_conn == None :
2018-06-02 15:39:17 -04:00
raise
except :
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Failed to open connection to qemu+tcp:// {} /system; aborting migration. ' . format ( self . node ) , state = ' e ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2019-04-11 19:06:06 -04:00
return False
2018-05-31 20:26:44 -04:00
2018-06-02 15:39:17 -04:00
try :
2018-06-17 21:55:39 -04:00
target_dom = self . dom . migrate ( dest_lv_conn , libvirt . VIR_MIGRATE_LIVE , None , None , 0 )
2018-06-02 15:39:17 -04:00
if target_dom == None :
raise
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Successfully migrated VM ' , state = ' o ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-06 22:59:31 -04:00
2018-06-02 15:39:17 -04:00
except :
2018-06-17 21:55:39 -04:00
dest_lv_conn . close ( )
2019-04-11 19:06:06 -04:00
return False
2018-06-04 12:15:37 -04:00
2018-06-17 21:55:39 -04:00
dest_lv_conn . close ( )
2019-04-11 19:06:06 -04:00
return True
2018-06-04 12:15:37 -04:00
# Migrate the VM to a target host
def migrate_vm ( self ) :
self . inmigrate = True
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Migrating VM to node " {} " ' . format ( self . node ) , state = ' i ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-20 11:53:48 -04:00
try :
2018-10-14 02:01:35 -04:00
migrate_ret = self . live_migrate_vm ( self . node )
2018-06-20 11:53:48 -04:00
except :
2019-04-11 19:06:06 -04:00
migrate_ret = True
2018-06-20 11:53:48 -04:00
2019-04-11 19:06:06 -04:00
if not migrate_ret :
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Could not live migrate VM; shutting down to migrate instead ' , state = ' e ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-04 16:30:09 -04:00
self . shutdown_vm ( )
2018-06-06 21:54:38 -04:00
time . sleep ( 1 )
2018-06-19 19:52:03 -04:00
else :
2018-06-19 20:01:26 -04:00
self . removeDomainFromList ( )
2018-06-19 19:52:03 -04:00
time . sleep ( 1 )
2018-06-02 15:58:21 -04:00
2018-06-26 23:24:33 -04:00
zkhandler . writedata ( self . zk_conn , { ' /domains/ {} /state ' . format ( self . domuuid ) : ' start ' } )
2018-06-02 18:34:48 -04:00
self . inmigrate = False
2018-06-04 11:49:39 -04:00
2019-04-11 19:06:06 -04:00
# Stop the log watcher
self . console_log_instance . stop ( )
2018-05-31 20:26:44 -04:00
# Receive the migration from another host (wait until VM is running)
2018-06-04 01:22:18 -04:00
def receive_migrate ( self ) :
2019-04-11 19:06:06 -04:00
# Start the log watcher
self . console_log_instance . start ( )
2018-06-02 18:34:48 -04:00
self . inreceive = True
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Receiving migration ' , state = ' i ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-11 03:01:12 -04:00
while True :
2018-06-11 22:47:53 -04:00
time . sleep ( 0.5 )
2018-06-26 21:52:22 -04:00
self . state = zkhandler . readdata ( self . zk_conn , ' /domains/ {} /state ' . format ( self . domuuid ) )
2018-06-07 00:40:32 -04:00
self . dom = self . lookupByUUID ( self . domuuid )
2018-06-11 13:11:42 -04:00
2018-06-11 17:02:36 -04:00
if self . dom == None and self . state == ' migrate ' :
2018-06-02 19:06:59 -04:00
continue
2018-06-02 18:38:59 -04:00
2018-06-11 17:02:36 -04:00
if self . state != ' migrate ' :
2018-06-02 19:06:59 -04:00
break
2018-06-02 18:38:59 -04:00
2018-06-11 17:02:36 -04:00
try :
if self . dom . state ( ) [ 0 ] == libvirt . VIR_DOMAIN_RUNNING :
break
except :
continue
2018-06-18 00:51:22 -04:00
try :
dom_state = self . dom . state ( ) [ 0 ]
except AttributeError :
dom_state = None
if dom_state == libvirt . VIR_DOMAIN_RUNNING :
2018-06-19 20:01:26 -04:00
self . addDomainToList ( )
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Successfully received migrated VM ' , state = ' o ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-11 16:53:04 -04:00
else :
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Failed to receive migrated VM ' , state = ' e ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-04 03:00:17 -04:00
2018-06-02 18:34:48 -04:00
self . inreceive = False
2018-05-31 23:28:26 -04:00
2018-05-31 20:26:44 -04:00
#
# Main function to manage a VM (taking only self)
#
def manage_vm_state ( self ) :
2018-06-11 21:32:13 -04:00
# Give ourselves a bit of leeway time
time . sleep ( 0.2 )
2018-06-11 21:51:38 -04:00
# Get the current values from zookeeper (don't rely on the watch)
2018-06-26 21:52:22 -04:00
self . state = zkhandler . readdata ( self . zk_conn , ' /domains/ {} /state ' . format ( self . domuuid ) )
2018-10-14 02:01:35 -04:00
self . node = zkhandler . readdata ( self . zk_conn , ' /domains/ {} /node ' . format ( self . domuuid ) )
2018-06-11 18:45:37 -04:00
2018-05-31 20:26:44 -04:00
# Check the current state of the VM
try :
2018-05-31 23:28:26 -04:00
if self . dom != None :
2018-06-06 11:42:49 -04:00
running , reason = self . dom . state ( )
2018-05-31 23:28:26 -04:00
else :
2018-06-02 15:52:50 -04:00
raise
2018-05-31 20:26:44 -04:00
except :
2018-06-01 12:21:58 -04:00
running = libvirt . VIR_DOMAIN_NOSTATE
2018-05-31 20:26:44 -04:00
2018-10-14 02:01:35 -04:00
self . logger . out ( ' VM state change for " {} " : {} {} ' . format ( self . domuuid , self . state , self . node ) , state = ' i ' )
2018-06-11 19:22:33 -04:00
2018-06-13 12:31:27 -04:00
#######################
# Handle state changes
#######################
# Valid states are:
# start
# migrate
2018-06-13 12:47:30 -04:00
# restart
2018-06-13 12:31:27 -04:00
# shutdown
# stop
# Conditional pass one - Are we already performing an action
2018-06-13 12:47:30 -04:00
if self . instart == False \
and self . inrestart == False \
and self . inmigrate == False \
and self . inreceive == False \
and self . inshutdown == False \
and self . instop == False :
2018-10-14 02:01:35 -04:00
# Conditional pass two - Is this VM configured to run on this node
if self . node == self . this_node . name :
# Conditional pass three - Is this VM currently running on this node
2018-06-13 12:31:27 -04:00
if running == libvirt . VIR_DOMAIN_RUNNING :
# VM is already running and should be
if self . state == " start " :
2019-04-11 19:06:06 -04:00
# Start the log watcher
self . console_log_instance . start ( )
# Add domain to running list
2018-06-19 20:01:26 -04:00
self . addDomainToList ( )
2018-06-13 12:31:27 -04:00
# VM is already running and should be but stuck in migrate state
elif self . state == " migrate " :
2019-04-11 19:06:06 -04:00
# Start the log watcher
self . console_log_instance . start ( )
2018-06-26 23:24:33 -04:00
zkhandler . writedata ( self . zk_conn , { ' /domains/ {} /state ' . format ( self . domuuid ) : ' start ' } )
2019-04-11 19:06:06 -04:00
# Add domain to running list
2018-06-19 20:01:26 -04:00
self . addDomainToList ( )
2018-06-13 12:47:30 -04:00
# VM should be restarted
elif self . state == " restart " :
self . restart_vm ( )
2018-06-13 12:31:27 -04:00
# VM should be shut down
elif self . state == " shutdown " :
self . shutdown_vm ( )
# VM should be stopped
elif self . state == " stop " :
self . stop_vm ( )
else :
# VM should be started
if self . state == " start " :
2019-04-11 19:06:06 -04:00
# Start the domain
2018-06-13 12:31:27 -04:00
self . start_vm ( )
2018-10-14 02:01:35 -04:00
# VM should be migrated to this node
2018-06-13 12:31:27 -04:00
elif self . state == " migrate " :
2019-04-11 19:06:06 -04:00
# Receive the migration
2018-06-13 12:31:27 -04:00
self . receive_migrate ( )
2018-06-13 12:47:30 -04:00
# VM should be restarted (i.e. started since it isn't running)
if self . state == " restart " :
2018-06-26 23:24:33 -04:00
zkhandler . writedata ( self . zk_conn , { ' /domains/ {} /state ' . format ( self . domuuid ) : ' start ' } )
2018-06-19 19:52:03 -04:00
# VM should be shut down; ensure it's gone from this node's domain_list
2018-06-13 12:31:27 -04:00
elif self . state == " shutdown " :
2018-06-19 20:01:26 -04:00
self . removeDomainFromList ( )
2019-04-11 19:06:06 -04:00
# Stop the log watcher
self . console_log_instance . stop ( )
2018-06-19 19:52:03 -04:00
# VM should be stoped; ensure it's gone from this node's domain_list
2018-06-13 12:31:27 -04:00
elif self . state == " stop " :
2018-06-19 20:01:26 -04:00
self . removeDomainFromList ( )
2019-04-11 19:06:06 -04:00
# Stop the log watcher
self . console_log_instance . stop ( )
2018-06-19 19:52:03 -04:00
2018-06-13 12:31:27 -04:00
else :
2018-10-14 02:01:35 -04:00
# Conditional pass three - Is this VM currently running on this node
2018-06-13 12:31:27 -04:00
if running == libvirt . VIR_DOMAIN_RUNNING :
2018-10-14 02:01:35 -04:00
# VM should be migrated away from this node
2018-06-13 12:31:27 -04:00
if self . state == " migrate " :
self . migrate_vm ( )
# VM should be terminated
else :
self . terminate_vm ( )
2018-06-06 21:45:03 -04:00
2018-06-06 01:47:53 -04:00
2018-06-06 22:59:31 -04:00
# This function is a wrapper for libvirt.lookupByUUID which fixes some problems
# 1. Takes a text UUID and handles converting it to bytes
# 2. Try's it and returns a sensible value if not
def lookupByUUID ( self , tuuid ) :
2018-06-17 21:55:39 -04:00
lv_conn = None
2018-06-06 22:59:31 -04:00
dom = None
libvirt_name = " qemu:///system "
2018-06-06 01:47:53 -04:00
2018-06-06 22:59:31 -04:00
# Convert the text UUID to bytes
buuid = uuid . UUID ( tuuid ) . bytes
# Try
try :
# Open a libvirt connection
2018-06-17 21:55:39 -04:00
lv_conn = libvirt . open ( libvirt_name )
if lv_conn == None :
2018-10-14 02:01:35 -04:00
self . logger . out ( ' Failed to open local libvirt connection ' , state = ' e ' , prefix = ' Domain {} : ' . format ( self . domuuid ) )
2018-06-06 22:59:31 -04:00
return dom
# Lookup the UUID
2018-06-17 21:55:39 -04:00
dom = lv_conn . lookupByUUID ( buuid )
2018-06-06 22:59:31 -04:00
# Fail
except :
pass
# After everything
finally :
# Close the libvirt connection
2018-06-17 21:55:39 -04:00
if lv_conn != None :
lv_conn . close ( )
2018-06-06 22:59:31 -04:00
# Return the dom object (or None)
return dom