2009-10-21 00:16:44 +04:00
//
// Copyright Red Hat, Inc. 2009
//
// 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 02139, USA.
//
// Author: Lon Hohberger <lhh at redhat.com>
//
# include <stdio.h>
# include <simpleconfig.h>
2010-01-14 21:38:37 +03:00
# include <static_map.h>
2009-10-21 00:16:44 +04:00
# include <sys/types.h>
# include <stdint.h>
# include <time.h>
# include <server_plugin.h>
# include <string.h>
# include <malloc.h>
# include <errno.h>
2011-08-03 19:54:25 +04:00
# include <string>
# include <sstream>
# include <iostream>
2009-11-06 21:16:42 +03:00
# include "uuid-test.h"
2010-01-15 16:06:34 +03:00
# include <xvm.h>
2009-10-21 00:16:44 +04:00
2011-08-03 19:54:25 +04:00
# include <qpid/types/Variant.h>
# include <qpid/messaging/Connection.h>
# include <qpid/console/Object.h>
# include <qmf/ConsoleSession.h>
# include <qmf/ConsoleEvent.h>
2009-10-21 00:16:44 +04:00
2012-02-09 00:44:42 +04:00
# define NAME "libvirt-qmf"
# define VERSION "0.2"
2009-10-21 00:16:44 +04:00
# define MAGIC 0x1e01017a
struct lq_info {
int magic ;
2010-01-13 21:38:00 +03:00
int port ;
2009-10-21 00:16:44 +04:00
char * host ;
2010-01-13 21:38:00 +03:00
char * username ;
char * service ;
int use_gssapi ;
2009-10-21 00:16:44 +04:00
} ;
2011-08-03 19:54:25 +04:00
2009-10-21 00:16:44 +04:00
# define VALIDATE(arg) \
do { \
if ( ! arg | | ( ( struct lq_info * ) arg ) - > magic ! = MAGIC ) { \
errno = EINVAL ; \
return - 1 ; \
} \
} while ( 0 )
2011-08-03 19:54:25 +04:00
static qmf : : ConsoleSession
lq_open_session ( struct lq_info * info )
{
2012-02-09 00:44:42 +04:00
qmf : : ConsoleSession session ;
2011-08-03 19:54:25 +04:00
std : : stringstream url ;
url < < info - > host < < " : " < < info - > port ;
qpid : : types : : Variant : : Map options ;
if ( info - > username ) {
options [ " username " ] = info - > username ;
}
if ( info - > service ) {
options [ " sasl-service " ] = info - > service ;
}
if ( info - > use_gssapi ) {
options [ " sasl-mechanism " ] = " GSSAPI " ;
}
2012-02-09 00:44:42 +04:00
try {
qpid : : messaging : : Connection connection ( url . str ( ) , options ) ;
connection . open ( ) ;
if ( ! connection . isOpen ( ) ) {
std : : cout < < " Error connecting. " < < std : : endl ;
} else {
session = qmf : : ConsoleSession ( connection ) ;
std : : stringstream filter ;
filter < < " [or, "
" [eq, _product, [quote, 'libvirt-qmf']], "
" [eq, _product, [quote, 'libvirt-qpid']] "
" ] " ;
session . setAgentFilter ( filter . str ( ) ) ;
session . open ( ) ;
}
}
2011-08-03 19:54:25 +04:00
2012-02-09 00:44:42 +04:00
catch ( qpid : : messaging : : TransportFailure ex ) {
std : : cout < < " Error establishing session: " < < ex . what ( ) < < std : : endl ;
2011-08-03 19:54:25 +04:00
}
return session ;
}
2011-08-03 19:54:44 +04:00
static qmf : : ConsoleEvent
queryDomain ( qmf : : Agent & agent )
{
std : : string query ;
if ( agent . getProduct ( ) = = " libvirt-qmf " ) {
query = " {class: Domain, package: 'org.libvirt'} " ;
} else {
query = " {class: domain, package: 'com.redhat.libvirt'} " ;
}
return agent . query ( query ) ;
}
2009-10-21 00:16:44 +04:00
int
2010-01-13 21:04:46 +03:00
do_lq_request ( struct lq_info * info , const char * vm_name ,
const char * action )
2009-10-21 00:16:44 +04:00
{
2011-08-24 20:40:42 +04:00
std : : string vm_state ;
2011-08-03 19:54:25 +04:00
const char * property = " name " ;
2009-11-06 21:16:42 +03:00
if ( is_uuid ( vm_name ) = = 1 ) {
property = " uuid " ;
}
2009-10-21 00:16:44 +04:00
2011-08-03 19:54:25 +04:00
qmf : : ConsoleSession session ( lq_open_session ( info ) ) ;
if ( ! session . isValid ( ) ) {
std : : cout < < " Invalid session. " < < std : : endl ;
2009-10-21 00:16:44 +04:00
return 1 ;
}
2011-08-03 19:54:25 +04:00
qmf : : Agent agent ;
qmf : : Data domain ;
int result ;
unsigned tries = 0 ;
bool found = false ;
2010-01-15 01:39:01 +03:00
while ( + + tries < 10 & & ! found ) {
2009-10-21 00:16:44 +04:00
sleep ( 1 ) ;
2011-08-03 19:54:25 +04:00
uint32_t numAgents = session . getAgentCount ( ) ;
for ( unsigned a = 0 ; ! found & & a < numAgents ; a + + ) {
agent = session . getAgent ( a ) ;
2011-08-03 19:54:44 +04:00
qmf : : ConsoleEvent event ( queryDomain ( agent ) ) ;
2011-08-03 19:54:25 +04:00
uint32_t numDomains = event . getDataCount ( ) ;
for ( unsigned d = 0 ; ! found & & d < numDomains ; d + + ) {
domain = event . getData ( d ) ;
qpid : : types : : Variant prop ;
try {
prop = domain . getProperty ( property ) ;
} catch ( qmf : : KeyNotFound e ) {
std : : cout < < e . what ( ) < < " - skipping " < < std : : endl ;
continue ;
}
2009-10-21 00:16:44 +04:00
2011-08-03 19:54:25 +04:00
if ( prop . asString ( ) ! = vm_name ) {
continue ;
2009-10-21 00:16:44 +04:00
}
2011-08-03 19:54:25 +04:00
found = true ;
}
2009-10-21 00:16:44 +04:00
}
}
2010-01-15 16:06:34 +03:00
if ( ! found ) {
2011-08-03 19:54:25 +04:00
result = 1 ;
2010-01-15 16:06:34 +03:00
goto out ;
}
2011-08-24 20:40:42 +04:00
vm_state = domain . getProperty ( " state " ) . asString ( ) ;
2010-01-15 01:39:01 +03:00
2011-08-03 19:54:25 +04:00
std : : cout < < vm_name < < " " < < vm_state < < std : : endl ;
int r ;
2011-08-24 20:40:42 +04:00
if ( vm_state = = " running " | |
vm_state = = " idle " | |
vm_state = = " paused " | |
vm_state = = " no state " ) {
2011-08-03 19:54:25 +04:00
r = RESP_OFF ;
2010-01-15 01:39:01 +03:00
} else {
2011-08-03 19:54:25 +04:00
r = 0 ;
2010-01-15 01:39:01 +03:00
}
2011-08-03 19:54:25 +04:00
if ( strcasecmp ( action , " state " ) = = 0 ) {
result = r ;
2010-01-15 16:06:34 +03:00
goto out ;
}
2011-08-03 19:54:25 +04:00
result = 1 ;
if ( ! r & & strcasecmp ( action , " destroy " ) = = 0 ) {
2010-01-15 01:39:01 +03:00
std : : cout < < " Domain is inactive; nothing to do " < < std : : endl ;
2011-08-03 19:54:25 +04:00
result = 0 ;
2010-01-15 01:39:01 +03:00
goto out ;
}
2011-08-03 19:54:25 +04:00
if ( r & & strcasecmp ( action , " create " ) = = 0 ) {
2010-01-15 01:39:01 +03:00
std : : cout < < " Domain is active; nothing to do " < < std : : endl ;
2011-08-03 19:54:25 +04:00
result = 0 ;
2010-01-15 01:39:01 +03:00
goto out ;
}
2009-10-21 00:16:44 +04:00
2011-08-03 19:54:25 +04:00
{
qmf : : ConsoleEvent response ;
response = agent . callMethod ( action ,
qpid : : types : : Variant : : Map ( ) ,
domain . getAddr ( ) ) ;
if ( response . getType ( ) = = qmf : : CONSOLE_EXCEPTION ) {
std : : string errorText ;
if ( response . getDataCount ( ) ) {
qmf : : Data responseData ( response . getData ( 0 ) ) ;
qpid : : types : : Variant code ( responseData . getProperty ( " error_code " ) ) ;
if ( code . getType ( ) = = qpid : : types : : VAR_INT32 ) {
result = responseData . getProperty ( " error_code " ) . asInt32 ( ) ;
} else {
result = 7 ; // Exception
}
qpid : : types : : Variant text ( responseData . getProperty ( " error_text " ) ) ;
if ( text . getType ( ) ! = qpid : : types : : VAR_VOID ) {
errorText = text . asString ( ) ;
}
} else {
result = 7 ; // Exception
}
2009-10-21 00:16:44 +04:00
2011-08-03 19:54:25 +04:00
std : : cout < < " Response: " < < result ;
if ( errorText . length ( ) ) {
std : : cout < < " ( " < < errorText < < " ) " ;
}
std : : cout < < std : : endl ;
} else { // Success
result = 0 ;
}
}
2009-10-21 00:16:44 +04:00
2010-01-15 01:39:01 +03:00
out :
2011-08-03 19:54:25 +04:00
session . close ( ) ;
2009-10-21 00:16:44 +04:00
2011-08-03 19:54:25 +04:00
return result ;
2009-10-21 00:16:44 +04:00
}
static int
lq_null ( const char * vm_name , void * priv )
{
VALIDATE ( priv ) ;
2012-02-09 00:44:42 +04:00
printf ( " [libvirt-qmf] NULL operation on %s \n " , vm_name ) ;
2009-10-21 00:16:44 +04:00
return 1 ;
}
static int
2010-01-13 21:52:55 +03:00
lq_off ( const char * vm_name , const char * src , uint32_t seqno , void * priv )
2009-10-21 00:16:44 +04:00
{
VALIDATE ( priv ) ;
2012-02-09 00:44:42 +04:00
printf ( " [libvirt-qmf] OFF operation on %s \n " , vm_name ) ;
2009-10-21 00:16:44 +04:00
2010-01-13 21:04:46 +03:00
return do_lq_request ( ( lq_info * ) priv , vm_name , " destroy " ) ;
2009-10-21 00:16:44 +04:00
return 1 ;
}
static int
2010-01-13 21:52:55 +03:00
lq_on ( const char * vm_name , const char * src , uint32_t seqno , void * priv )
2009-10-21 00:16:44 +04:00
{
VALIDATE ( priv ) ;
2012-02-09 00:44:42 +04:00
printf ( " [libvirt-qmf] ON operation on %s \n " , vm_name ) ;
2009-10-21 00:16:44 +04:00
2010-01-13 21:04:46 +03:00
return do_lq_request ( ( lq_info * ) priv , vm_name , " create " ) ;
2009-10-21 00:16:44 +04:00
}
static int
lq_devstatus ( void * priv )
{
VALIDATE ( priv ) ;
2012-02-09 00:44:42 +04:00
printf ( " [libvirt-qmf] Device status \n " ) ;
2009-10-21 00:16:44 +04:00
return 0 ;
}
static int
lq_status ( const char * vm_name , void * priv )
{
VALIDATE ( priv ) ;
2012-02-09 00:44:42 +04:00
printf ( " [libvirt-qmf] STATUS operation on %s \n " , vm_name ) ;
2009-10-21 00:16:44 +04:00
2011-08-01 20:36:18 +04:00
return do_lq_request ( ( lq_info * ) priv , vm_name , " state " ) ;
2009-10-21 00:16:44 +04:00
}
static int
2010-01-13 21:52:55 +03:00
lq_reboot ( const char * vm_name , const char * src , uint32_t seqno , void * priv )
2009-10-21 00:16:44 +04:00
{
VALIDATE ( priv ) ;
2012-02-09 00:44:42 +04:00
printf ( " [libvirt-qmf] REBOOT operation on %s \n " , vm_name ) ;
2009-11-05 20:59:41 +03:00
2010-01-13 21:52:55 +03:00
if ( lq_off ( vm_name , src , seqno , priv ) ! = 0 )
2009-11-05 20:59:41 +03:00
return 1 ;
sleep ( 1 ) ;
2010-01-13 21:52:55 +03:00
lq_on ( vm_name , src , seqno , priv ) ;
2009-10-21 00:16:44 +04:00
2010-01-15 01:39:01 +03:00
return 0 ;
2009-10-21 00:16:44 +04:00
}
2009-12-07 20:55:48 +03:00
static int
lq_hostlist ( hostlist_callback callback , void * arg , void * priv )
{
VALIDATE ( priv ) ;
2012-02-09 00:44:42 +04:00
printf ( " [libvirt-qmf] HOSTLIST operation \n " ) ;
2009-12-07 20:55:48 +03:00
2011-08-03 19:54:25 +04:00
qmf : : ConsoleSession session ( lq_open_session ( ( struct lq_info * ) priv ) ) ;
if ( ! session . isValid ( ) ) {
2009-12-07 20:55:48 +03:00
return 1 ;
}
2011-08-03 19:54:25 +04:00
unsigned tries = 0 ;
qmf : : ConsoleEvent event ;
uint32_t numDomains = 0 ;
while ( + + tries < 10 & & ! numDomains ) {
2009-12-07 20:55:48 +03:00
sleep ( 1 ) ;
2011-08-03 19:54:25 +04:00
uint32_t numAgents = session . getAgentCount ( ) ;
for ( unsigned a = 0 ; a < numAgents ; a + + ) {
qmf : : Agent agent ( session . getAgent ( a ) ) ;
2011-08-03 19:54:44 +04:00
event = queryDomain ( agent ) ;
2011-08-03 19:54:25 +04:00
numDomains = event . getDataCount ( ) ;
if ( numDomains > = 1 ) {
break ;
}
2009-12-07 20:55:48 +03:00
}
}
2011-08-03 19:54:25 +04:00
for ( unsigned d = 0 ; d < numDomains ; d + + ) {
qmf : : Data domain = event . getData ( d ) ;
std : : string vm_name , vm_uuid , vm_state_str ;
try {
vm_name = domain . getProperty ( " name " ) . asString ( ) ;
vm_uuid = domain . getProperty ( " uuid " ) . asString ( ) ;
vm_state_str = domain . getProperty ( " state " ) . asString ( ) ;
} catch ( qmf : : KeyNotFound e ) {
std : : cout < < e . what ( ) < < " - skipping " < < std : : endl ;
continue ;
}
2009-12-07 20:55:48 +03:00
2011-08-03 19:54:25 +04:00
int vm_state ;
if ( ! strcasecmp ( vm_state_str . c_str ( ) , " shutoff " ) ) {
2009-12-07 20:55:48 +03:00
vm_state = 0 ;
2011-08-03 19:54:25 +04:00
} else {
2009-12-07 20:55:48 +03:00
vm_state = 1 ;
2011-08-03 19:54:25 +04:00
}
2009-12-07 20:55:48 +03:00
2011-08-03 19:54:25 +04:00
callback ( vm_name . c_str ( ) , vm_uuid . c_str ( ) , vm_state , arg ) ;
2009-12-07 20:55:48 +03:00
}
2011-08-03 19:54:25 +04:00
session . close ( ) ;
2009-12-07 20:55:48 +03:00
return 0 ;
}
2009-10-21 00:16:44 +04:00
static int
lq_init ( backend_context_t * c , config_object_t * config )
{
char value [ 256 ] ;
struct lq_info * info = NULL ;
info = ( lq_info * ) malloc ( sizeof ( * info ) ) ;
if ( ! info )
return - 1 ;
memset ( info , 0 , sizeof ( * info ) ) ;
2012-02-09 00:44:42 +04:00
info - > port = 5672 ; /* Actually match default qpid port */
2010-01-13 21:04:46 +03:00
2012-02-09 00:44:42 +04:00
if ( sc_get ( config , " backends/libvirt-qmf/@host " ,
2010-01-11 22:53:51 +03:00
value , sizeof ( value ) ) = = 0 ) {
printf ( " \n \n HOST = %s \n \n " , value ) ;
2010-01-13 21:38:00 +03:00
info - > host = strdup ( value ) ;
if ( ! info - > host ) {
goto out_fail ;
}
} else {
info - > host = strdup ( " 127.0.0.1 " ) ;
2010-01-11 22:53:51 +03:00
}
2012-02-09 00:44:42 +04:00
if ( sc_get ( config , " backends/libvirt-qmf/@port " ,
2010-01-11 22:53:51 +03:00
value , sizeof ( value ) - 1 ) = = 0 ) {
printf ( " \n \n PORT = %d \n \n " , atoi ( value ) ) ;
2010-01-13 21:38:00 +03:00
info - > port = atoi ( value ) ;
2009-10-21 00:16:44 +04:00
}
2012-02-09 00:44:42 +04:00
if ( sc_get ( config , " backends/libvirt-qmf/@username " ,
2010-01-13 21:38:00 +03:00
value , sizeof ( value ) ) = = 0 ) {
printf ( " \n \n USERNAME = %s \n \n " , value ) ;
info - > username = strdup ( value ) ;
if ( ! info - > username ) {
goto out_fail ;
}
}
2012-02-09 00:44:42 +04:00
if ( sc_get ( config , " backends/libvirt-qmf/@service " ,
2010-01-13 21:38:00 +03:00
value , sizeof ( value ) ) = = 0 ) {
printf ( " \n \n SERVICE = %s \n \n " , value ) ;
info - > service = strdup ( value ) ;
if ( ! info - > service ) {
goto out_fail ;
}
}
2012-02-09 00:44:42 +04:00
if ( sc_get ( config , " backends/libvirt-qmf/@gssapi " ,
2010-01-13 21:38:00 +03:00
value , sizeof ( value ) - 1 ) = = 0 ) {
printf ( " \n \n GSSAPI = %d \n \n " , atoi ( value ) ) ;
if ( atoi ( value ) > 0 ) {
info - > use_gssapi = 1 ;
}
2009-10-21 00:16:44 +04:00
}
info - > magic = MAGIC ;
* c = ( void * ) info ;
return 0 ;
2010-01-13 21:38:00 +03:00
out_fail :
free ( info - > service ) ;
free ( info - > username ) ;
free ( info - > host ) ;
free ( info ) ;
return - 1 ;
2009-10-21 00:16:44 +04:00
}
static int
lq_shutdown ( backend_context_t c )
{
struct lq_info * info = ( struct lq_info * ) c ;
VALIDATE ( info ) ;
info - > magic = 0 ;
2010-01-13 21:38:00 +03:00
free ( info - > service ) ;
free ( info - > username ) ;
free ( info - > host ) ;
2009-10-21 00:16:44 +04:00
free ( info ) ;
return 0 ;
}
static fence_callbacks_t lq_callbacks = {
2009-12-07 20:55:48 +03:00
lq_null , lq_off , lq_on , lq_reboot , lq_status , lq_devstatus ,
lq_hostlist
2009-10-21 00:16:44 +04:00
} ;
static backend_plugin_t lq_plugin = {
NAME , VERSION , & lq_callbacks , lq_init , lq_shutdown
} ;
# ifdef _MODULE
2009-11-12 22:12:42 +03:00
extern " C " double
2009-10-21 00:16:44 +04:00
BACKEND_VER_SYM ( void )
{
return PLUGIN_VERSION_BACKEND ;
}
2009-11-12 22:12:42 +03:00
extern " C " const backend_plugin_t *
2009-10-21 00:16:44 +04:00
BACKEND_INFO_SYM ( void )
{
return & lq_plugin ;
}
# else
static void __attribute__ ( ( constructor ) )
2009-11-05 22:01:35 +03:00
lq_register_plugin ( void )
2009-10-21 00:16:44 +04:00
{
2009-11-05 22:01:35 +03:00
plugin_reg_backend ( & lq_plugin ) ;
2009-10-21 00:16:44 +04:00
}
# endif