2009-07-28 18:46:53 +04:00
/*
2017-05-25 06:18:18 +03:00
Copyright Red Hat , Inc . 2006 - 2017
2009-07-28 18:46:53 +04:00
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 2 , 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 ; see the file COPYING . If not , write to the
Free Software Foundation , Inc . , 675 Mass Ave , Cambridge ,
MA 0213 9 , USA .
*/
2017-05-25 06:18:18 +03:00
2009-07-28 18:46:53 +04:00
# include <stdio.h>
2017-05-25 06:18:18 +03:00
# include <unistd.h>
2009-07-28 18:46:53 +04:00
# include <sys/types.h>
# include <stdlib.h>
# include <libvirt/libvirt.h>
# include <string.h>
# include <malloc.h>
# include <stdint.h>
# include <errno.h>
2017-05-25 06:18:18 +03:00
# include <syslog.h>
2009-07-28 18:46:53 +04:00
2017-05-25 06:18:18 +03:00
# include "debug.h"
# include "uuid-test.h"
# include "virt.h"
2009-07-28 18:46:53 +04:00
static int
_compare_virt ( const void * _left , const void * _right )
{
virt_state_t * left = ( virt_state_t * ) _left ,
* right = ( virt_state_t * ) _right ;
return strcasecmp ( left - > v_name , right - > v_name ) ;
}
2017-05-25 06:18:18 +03:00
static void
_free_dom_list ( virDomainPtr * dom_list , int len ) {
int x ;
2009-07-28 18:46:53 +04:00
2017-05-25 06:18:18 +03:00
if ( ! dom_list | | len < = 0 )
return ;
for ( x = 0 ; x < len ; x + + )
virDomainFree ( dom_list [ x ] ) ;
2009-07-28 18:46:53 +04:00
2017-05-25 06:18:18 +03:00
free ( dom_list ) ;
}
2009-07-28 18:46:53 +04:00
2017-05-25 06:18:18 +03:00
virt_list_t * vl_get ( virConnectPtr * vp , int vp_count , int my_id )
{
virt_list_t * vl = NULL ;
int d_count = 0 ;
int i ;
2009-07-28 18:46:53 +04:00
2017-05-25 06:18:18 +03:00
errno = EINVAL ;
if ( ! vp | | vp_count < 1 )
return NULL ;
2009-07-28 18:46:53 +04:00
2017-05-25 06:18:18 +03:00
for ( i = 0 ; i < vp_count ; i + + ) {
int x ;
virDomainPtr * dom_list ;
int ret = virConnectListAllDomains ( vp [ i ] , & dom_list , 0 ) ;
if ( ret < = 0 )
continue ;
d_count + = ret ;
vl = realloc ( vl , sizeof ( uint32_t ) + sizeof ( virt_state_t ) * d_count ) ;
if ( ! vl ) {
_free_dom_list ( dom_list , ret ) ;
return NULL ;
}
vl - > vm_count = d_count ;
/* Ok, we have the domain IDs - let's get their names and states */
for ( x = 0 ; x < ret ; x + + ) {
char * d_name ;
virDomainInfo d_info ;
char d_uuid [ MAX_DOMAINNAME_LENGTH ] ;
virDomainPtr dom = dom_list [ x ] ;
if ( ! ( d_name = ( char * ) virDomainGetName ( dom ) ) ) {
_free_dom_list ( dom_list , ret ) ;
free ( vl ) ;
return NULL ;
}
if ( virDomainGetUUIDString ( dom , d_uuid ) ! = 0 ) {
_free_dom_list ( dom_list , ret ) ;
free ( vl ) ;
return NULL ;
}
if ( virDomainGetInfo ( dom , & d_info ) < 0 ) {
_free_dom_list ( dom_list , ret ) ;
free ( vl ) ;
return NULL ;
}
/* Store the name & state */
strncpy ( vl - > vm_states [ x ] . v_name , d_name , MAX_DOMAINNAME_LENGTH ) ;
strncpy ( vl - > vm_states [ x ] . v_uuid , d_uuid , MAX_DOMAINNAME_LENGTH ) ;
vl - > vm_states [ x ] . v_state . s_state = d_info . state ;
vl - > vm_states [ x ] . v_state . s_owner = my_id ;
}
_free_dom_list ( dom_list , ret ) ;
2009-07-28 18:46:53 +04:00
}
/* We have all the locally running domains & states now */
/* Sort */
qsort ( & vl - > vm_states [ 0 ] , vl - > vm_count , sizeof ( vl - > vm_states [ 0 ] ) ,
_compare_virt ) ;
return vl ;
}
void
vl_print ( virt_list_t * vl )
{
int x ;
printf ( " %-24.24s %-36.36s %-5.5s %-5.5s \n " , " Domain " , " UUID " ,
" Owner " , " State " ) ;
printf ( " %-24.24s %-36.36s %-5.5s %-5.5s \n " , " ------ " , " ---- " ,
" ----- " , " ----- " ) ;
if ( ! vl | | ! vl - > vm_count )
return ;
for ( x = 0 ; x < vl - > vm_count ; x + + ) {
printf ( " %-24.24s %-36.36s %-5.5d %-5.5d \n " ,
vl - > vm_states [ x ] . v_name ,
vl - > vm_states [ x ] . v_uuid ,
vl - > vm_states [ x ] . v_state . s_owner ,
vl - > vm_states [ x ] . v_state . s_state ) ;
}
}
virt_state_t *
2009-09-17 04:07:46 +04:00
vl_find_name ( virt_list_t * vl , const char * name )
2009-07-28 18:46:53 +04:00
{
int x ;
if ( ! vl | | ! name | | ! vl - > vm_count )
return NULL ;
for ( x = 0 ; x < vl - > vm_count ; x + + ) {
if ( ! strcasecmp ( vl - > vm_states [ x ] . v_name , name ) )
return & vl - > vm_states [ x ] ;
}
return NULL ;
}
virt_state_t *
2009-09-17 04:07:46 +04:00
vl_find_uuid ( virt_list_t * vl , const char * uuid )
2009-07-28 18:46:53 +04:00
{
int x ;
if ( ! vl | | ! uuid | | ! vl - > vm_count )
return NULL ;
for ( x = 0 ; x < vl - > vm_count ; x + + ) {
if ( ! strcasecmp ( vl - > vm_states [ x ] . v_uuid , uuid ) )
return & vl - > vm_states [ x ] ;
}
return NULL ;
}
void
vl_free ( virt_list_t * old )
{
free ( old ) ;
}
2017-05-25 06:18:18 +03:00
static inline int
wait_domain ( const char * vm_name , virConnectPtr vp , int timeout )
{
int tries = 0 ;
int response = 1 ;
int ret ;
virDomainPtr vdp ;
virDomainInfo vdi ;
int uuid_check ;
uuid_check = is_uuid ( vm_name ) ;
if ( uuid_check ) {
vdp = virDomainLookupByUUIDString ( vp , ( const char * ) vm_name ) ;
} else {
vdp = virDomainLookupByName ( vp , vm_name ) ;
}
if ( ! vdp )
return 0 ;
/* Check domain liveliness. If the domain is still here,
we return failure , and the client must then retry */
/* XXX On the xen 3.0.4 API, we will be able to guarantee
synchronous virDomainDestroy , so this check will not
be necessary */
do {
if ( + + tries > timeout )
break ;
sleep ( 1 ) ;
if ( uuid_check ) {
vdp = virDomainLookupByUUIDString ( vp , ( const char * ) vm_name ) ;
} else {
vdp = virDomainLookupByName ( vp , vm_name ) ;
}
if ( ! vdp ) {
dbg_printf ( 2 , " Domain no longer exists \n " ) ;
response = 0 ;
break ;
}
memset ( & vdi , 0 , sizeof ( vdi ) ) ;
ret = virDomainGetInfo ( vdp , & vdi ) ;
virDomainFree ( vdp ) ;
if ( ret < 0 )
continue ;
if ( vdi . state = = VIR_DOMAIN_SHUTOFF ) {
dbg_printf ( 2 , " Domain has been shut off \n " ) ;
response = 0 ;
break ;
}
dbg_printf ( 4 , " Domain still exists (state %d) after %d seconds \n " ,
vdi . state , tries ) ;
} while ( 1 ) ;
return response ;
}
int
vm_off ( virConnectPtr * vp , int vp_count , const char * vm_name )
{
virDomainPtr vdp = NULL ;
virDomainInfo vdi ;
virDomainPtr ( * virt_lookup_fn ) ( virConnectPtr , const char * ) ;
int ret = - 1 ;
int i ;
if ( is_uuid ( vm_name ) )
virt_lookup_fn = virDomainLookupByUUIDString ;
else
virt_lookup_fn = virDomainLookupByName ;
for ( i = 0 ; i < vp_count ; i + + ) {
vdp = virt_lookup_fn ( vp [ i ] , vm_name ) ;
if ( vdp )
break ;
}
if ( ! vdp ) {
dbg_printf ( 2 , " [virt:OFF] Domain %s does not exist \n " , vm_name ) ;
return 1 ;
}
if ( virDomainGetInfo ( vdp , & vdi ) = = 0 & & vdi . state = = VIR_DOMAIN_SHUTOFF )
{
dbg_printf ( 2 , " [virt:OFF] Nothing to do - "
" domain %s is already off \n " ,
vm_name ) ;
virDomainFree ( vdp ) ;
return 0 ;
}
syslog ( LOG_NOTICE , " Destroying domain %s \n " , vm_name ) ;
dbg_printf ( 2 , " [virt:OFF] Calling virDomainDestroy for %s \n " , vm_name ) ;
ret = virDomainDestroy ( vdp ) ;
virDomainFree ( vdp ) ;
if ( ret < 0 ) {
syslog ( LOG_NOTICE ,
" Failed to destroy domain %s: %d \n " , vm_name , ret ) ;
dbg_printf ( 2 , " [virt:OFF] Failed to destroy domain: %s %d \n " ,
vm_name , ret ) ;
return 1 ;
}
if ( ret ) {
syslog ( LOG_NOTICE , " Domain %s still exists; fencing failed \n " ,
vm_name ) ;
dbg_printf ( 2 ,
" [virt:OFF] Domain %s still exists; fencing failed \n " ,
vm_name ) ;
return 1 ;
}
dbg_printf ( 2 , " [virt:OFF] Success for %s \n " , vm_name ) ;
return 0 ;
}
int
vm_on ( virConnectPtr * vp , int vp_count , const char * vm_name )
{
virDomainPtr vdp = NULL ;
virDomainInfo vdi ;
virDomainPtr ( * virt_lookup_fn ) ( virConnectPtr , const char * ) ;
int ret = - 1 ;
int i ;
if ( is_uuid ( vm_name ) )
virt_lookup_fn = virDomainLookupByUUIDString ;
else
virt_lookup_fn = virDomainLookupByName ;
for ( i = 0 ; i < vp_count ; i + + ) {
vdp = virt_lookup_fn ( vp [ i ] , vm_name ) ;
if ( vdp )
break ;
}
if ( ! vdp ) {
dbg_printf ( 2 , " [virt:ON] Domain %s does not exist \n " , vm_name ) ;
return 1 ;
}
if ( virDomainGetInfo ( vdp , & vdi ) = = 0 & & vdi . state ! = VIR_DOMAIN_SHUTOFF ) {
dbg_printf ( 2 , " Nothing to do - domain %s is already running \n " ,
vm_name ) ;
virDomainFree ( vdp ) ;
return 0 ;
}
syslog ( LOG_NOTICE , " Starting domain %s \n " , vm_name ) ;
dbg_printf ( 2 , " [virt:ON] Calling virDomainCreate for %s \n " , vm_name ) ;
ret = virDomainCreate ( vdp ) ;
virDomainFree ( vdp ) ;
if ( ret < 0 ) {
syslog ( LOG_NOTICE , " Failed to start domain %s: %d \n " , vm_name , ret ) ;
dbg_printf ( 2 , " [virt:ON] virDomainCreate() failed for %s: %d \n " ,
vm_name , ret ) ;
return 1 ;
}
if ( ret ) {
syslog ( LOG_NOTICE , " Domain %s did not start \n " , vm_name ) ;
dbg_printf ( 2 , " [virt:ON] Domain %s did not start \n " , vm_name ) ;
return 1 ;
}
syslog ( LOG_NOTICE , " Domain %s started \n " , vm_name ) ;
dbg_printf ( 2 , " [virt:ON] Success for %s \n " , vm_name ) ;
return 0 ;
}
int
vm_status ( virConnectPtr * vp , int vp_count , const char * vm_name )
{
virDomainPtr vdp = NULL ;
virDomainInfo vdi ;
int ret = 0 ;
int i ;
virDomainPtr ( * virt_lookup_fn ) ( virConnectPtr , const char * ) ;
if ( is_uuid ( vm_name ) )
virt_lookup_fn = virDomainLookupByUUIDString ;
else
virt_lookup_fn = virDomainLookupByName ;
for ( i = 0 ; i < vp_count ; i + + ) {
vdp = virt_lookup_fn ( vp [ i ] , vm_name ) ;
if ( vdp )
break ;
}
if ( ! vdp ) {
dbg_printf ( 2 , " [virt:STATUS] Unknown VM %s - return OFF \n " , vm_name ) ;
return RESP_OFF ;
}
if ( virDomainGetInfo ( vdp , & vdi ) = = 0 & & vdi . state = = VIR_DOMAIN_SHUTOFF ) {
dbg_printf ( 2 , " [virt:STATUS] VM %s is OFF \n " , vm_name ) ;
ret = RESP_OFF ;
}
if ( vdp )
virDomainFree ( vdp ) ;
return ret ;
}
int
vm_reboot ( virConnectPtr * vp , int vp_count , const char * vm_name )
{
virDomainPtr vdp = NULL , nvdp ;
virDomainInfo vdi ;
char * domain_desc ;
virConnectPtr vcp = NULL ;
virDomainPtr ( * virt_lookup_fn ) ( virConnectPtr , const char * ) ;
int ret ;
int i ;
if ( is_uuid ( vm_name ) )
virt_lookup_fn = virDomainLookupByUUIDString ;
else
virt_lookup_fn = virDomainLookupByName ;
for ( i = 0 ; i < vp_count ; i + + ) {
vdp = virt_lookup_fn ( vp [ i ] , vm_name ) ;
if ( vdp ) {
vcp = vp [ i ] ;
break ;
}
}
if ( ! vdp | | ! vcp ) {
dbg_printf ( 2 ,
" [virt:REBOOT] Nothing to do - domain %s does not exist \n " ,
vm_name ) ;
return 1 ;
}
if ( virDomainGetInfo ( vdp , & vdi ) = = 0 & & vdi . state = = VIR_DOMAIN_SHUTOFF ) {
dbg_printf ( 2 , " [virt:REBOOT] Nothing to do - domain %s is off \n " ,
vm_name ) ;
virDomainFree ( vdp ) ;
return 0 ;
}
syslog ( LOG_NOTICE , " Rebooting domain %s \n " , vm_name ) ;
dbg_printf ( 5 , " [virt:REBOOT] Rebooting domain %s... \n " , vm_name ) ;
domain_desc = virDomainGetXMLDesc ( vdp , 0 ) ;
if ( ! domain_desc ) {
dbg_printf ( 5 , " [virt:REBOOT] Failed getting domain description "
" from libvirt for %s... \n " , vm_name ) ;
}
dbg_printf ( 2 , " [virt:REBOOT] Calling virDomainDestroy(%p) for %s \n " ,
vdp , vm_name ) ;
ret = virDomainDestroy ( vdp ) ;
if ( ret < 0 ) {
dbg_printf ( 2 ,
" [virt:REBOOT] virDomainDestroy() failed for %s: %d/%d \n " ,
vm_name , ret , errno ) ;
if ( domain_desc )
free ( domain_desc ) ;
virDomainFree ( vdp ) ;
return 1 ;
}
ret = wait_domain ( vm_name , vcp , 15 ) ;
if ( ret ) {
syslog ( LOG_NOTICE , " Domain %s still exists; fencing failed \n " , vm_name ) ;
dbg_printf ( 2 ,
" [virt:REBOOT] Domain %s still exists; fencing failed \n " ,
vm_name ) ;
if ( domain_desc )
free ( domain_desc ) ;
virDomainFree ( vdp ) ;
return 1 ;
}
if ( ! domain_desc )
return 0 ;
/* 'on' is not a failure */
ret = 0 ;
dbg_printf ( 3 , " [[ XML Domain Info ]] \n " ) ;
dbg_printf ( 3 , " %s \n [[ XML END ]] \n " , domain_desc ) ;
dbg_printf ( 2 , " [virt:REBOOT] Calling virDomainCreateLinux() for %s \n " ,
vm_name ) ;
nvdp = virDomainCreateLinux ( vcp , domain_desc , 0 ) ;
if ( nvdp = = NULL ) {
/* More recent versions of libvirt or perhaps the
* KVM back - end do not let you create a domain from
* XML if there is already a defined domain description
* with the same name that it knows about . You must
* then call virDomainCreate ( ) */
dbg_printf ( 2 ,
" [virt:REBOOT] virDomainCreateLinux() failed for %s; "
" Trying virDomainCreate() \n " ,
vm_name ) ;
if ( virDomainCreate ( vdp ) < 0 ) {
syslog ( LOG_NOTICE , " Could not restart %s \n " , vm_name ) ;
dbg_printf ( 1 , " [virt:REBOOT] Failed to recreate guest %s! \n " ,
vm_name ) ;
}
}
free ( domain_desc ) ;
virDomainFree ( vdp ) ;
return ret ;
}