Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4525670
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
124 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/agents/virt/include/server_plugin.h b/agents/virt/include/server_plugin.h
index abfbdbe9..1f8e931c 100644
--- a/agents/virt/include/server_plugin.h
+++ b/agents/virt/include/server_plugin.h
@@ -1,133 +1,131 @@
/* */
#ifndef _SERVER_PLUGIN_H
#define _SERVER_PLUGIN_H
#include "config.h"
#define PLUGIN_VERSION_LISTENER ((double)0.3)
#define PLUGIN_VERSION_BACKEND ((double)0.2)
typedef void * listener_context_t;
typedef void * backend_context_t;
/* These callbacks hand requests off to the
appropriate backend. */
/* Do nothing. Returns 1 (failure) to caller */
typedef int (*fence_null_callback)(const char *vm_name,
void *priv);
/* Turn the VM 'off'. Returns 0 to caller if successful or
nonzero if unsuccessful. */
typedef int (*fence_off_callback)(const char *vm_name, const char *src,
uint32_t seqno, void *priv);
/* Turn the VM 'on'. Returns 0 to caller if successful or
nonzero if unsuccessful. */
typedef int (*fence_on_callback)(const char *vm_name, const char *src,
uint32_t seqno, void *priv);
/* Reboot a VM. Returns 0 to caller if successful or
nonzero if unsuccessful. */
typedef int (*fence_reboot_callback)(const char *vm_name, const char *src,
uint32_t seqno, void *priv);
/* Get status of a VM. Returns 0 to caller if VM is alive or
nonzero if VM is not alive. */
typedef int (*fence_status_callback)(const char *vm_name,
void *priv);
/* Get status of backend. Returns 0 to caller if backend
is responding to requests. */
typedef int (*fence_devstatus_callback)(void *priv);
/* VMs available to fence. Returns 0 to caller if backend
is responding to requests and a host list can be produced */
typedef int (*hostlist_callback)(const char *vm_name, const char *uuid,
int state, void *arg);
typedef int (*fence_hostlist_callback)(hostlist_callback cb,
void *arg, void *priv);
typedef int (*backend_init_fn)(backend_context_t *c,
config_object_t *config);
typedef int (*backend_cleanup_fn)(backend_context_t c);
typedef struct _fence_callbacks {
fence_null_callback null;
fence_off_callback off;
fence_on_callback on;
fence_reboot_callback reboot;
fence_status_callback status;
fence_devstatus_callback devstatus;
fence_hostlist_callback hostlist;
} fence_callbacks_t;
typedef struct backend_plugin {
const char *name;
const char *version;
const fence_callbacks_t *callbacks;
backend_init_fn init;
backend_cleanup_fn cleanup;
} backend_plugin_t;
double backend_plugin_version(void);
const backend_plugin_t * backend_plugin_info(void);
#define BACKEND_VER_SYM backend_plugin_version
#define BACKEND_INFO_SYM backend_plugin_info
#define BACKEND_VER_STR "backend_plugin_version"
#define BACKEND_INFO_STR "backend_plugin_info"
typedef int (*listener_init_fn)(listener_context_t *c,
const fence_callbacks_t *cb,
config_object_t *config,
map_object_t *map,
void *priv);
typedef int (*listener_dispatch_fn)(listener_context_t c,
struct timeval *timeout);
typedef int (*listener_cleanup_fn)(listener_context_t c);
typedef struct listener_plugin {
const char *name;
const char *version;
listener_init_fn init;
listener_dispatch_fn dispatch;
listener_cleanup_fn cleanup;
} listener_plugin_t;
double listener_plugin_version(void);
const listener_plugin_t * listener_plugin_info(void);
#define LISTENER_VER_SYM listener_plugin_version
#define LISTENER_INFO_SYM listener_plugin_info
#define LISTENER_VER_STR "listener_plugin_version"
#define LISTENER_INFO_STR "listener_plugin_info"
typedef enum {
PLUGIN_NONE = 0,
PLUGIN_LISTENER = 1,
PLUGIN_BACKEND = 2
} plugin_type_t;
#ifdef __cplusplus
extern "C" {
#endif
int plugin_reg_backend(const backend_plugin_t *plugin);
int plugin_reg_listener(const listener_plugin_t *plugin);
const backend_plugin_t *plugin_find_backend(const char *name);
const listener_plugin_t *plugin_find_listener(const char *name);
void plugin_dump(void);
-#ifdef _MODULE
int plugin_load(const char *filename);
int plugin_search(const char *pathname);
-#endif
#ifdef __cplusplus
}
#endif
#endif
diff --git a/agents/virt/server/Makefile.am b/agents/virt/server/Makefile.am
index 787e3a85..9c839a36 100644
--- a/agents/virt/server/Makefile.am
+++ b/agents/virt/server/Makefile.am
@@ -1,172 +1,104 @@
###############################################################################
###############################################################################
##
## Copyright (C) 2009-2021 Red Hat, Inc.
##
## This copyrighted material is made available to anyone wishing to use,
## modify, copy, or redistribute it subject to the terms and conditions
## of the GNU General Public License v.2.
##
###############################################################################
###############################################################################
MAINTAINERCLEANFILES = Makefile.in
noinst_HEADERS = cpg.h serial.h uuid-test.h virt.h
sbin_PROGRAMS = fence_virtd
#
# daemon
#
fence_virtd_SOURCES = main.c plugin.c config.c static_map.c uuid-test.c \
daemon_init.c
fence_virtd_CFLAGS = $(VIRT_AM_CFLAGS) \
$(nss_CFLAGS) $(xml2_CFLAGS) $(uuid_CFLAGS) $(PTHREAD_CFLAGS) \
$(AM_CFLAGS)
fence_virtd_LDADD = $(VIRT_CONFIG_LIBS) $(VIRT_COMMON_LIBS) \
$(nss_LIBS) $(xml2_LIBS) $(uuid_LIBS) $(PTHREAD_LIBS) $(dl_LIBS)
fence_virtd_LDFLAGS = $(VIRT_AM_LDFLAGS) $(VIRT_COMMON_LDFLAGS)
-#
-# modules
-#
-
virt_la_SOURCES = libvirt.c
null_la_SOURCES = null.c
virt_qmf_la_SOURCES = libvirt-qmf.cpp
pm_fence_la_SOURCES = pm-fence.c
cpg_la_SOURCES = cpg-virt.c cpg.c
multicast_la_SOURCES = mcast.c
tcp_la_SOURCES = tcp.c
vsock_la_SOURCES = vsock.c
serial_la_SOURCES = virt-serial.c virt-sockets.c serial.c
-#################
-# Modular build #
-#################
-if modularbuild
-
fence_virtd_CFLAGS += -DMODULE_PATH=\"$(libdir)/fence-virt/\"
fvlibdir = $(libdir)/fence-virt
fvlib_LTLIBRARIES =
MODULESCFLAGS = $(VIRT_AM_CFLAGS) $(AM_CFLAGS)
MODULESLDFLAGS = $(VIRT_AM_LDFLAGS) $(VIRT_COMMON_LIBS) $(VIRT_COMMON_LDFLAGS) -module -avoid-version -export-dynamic
if modlibvirt
fvlib_LTLIBRARIES += virt.la
virt_la_SOURCES += virt.c uuid-test.c
virt_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) $(virt_CFLAGS)
virt_la_LDFLAGS = $(MODULESLDFLAGS) $(nss_LIBS) $(virt_LIBS)
endif
if modlibvirtqmf
fvlib_LTLIBRARIES += virt-qmf.la
virt_qmf_la_SOURCES += uuid-test.c
virt_qmf_la_CXXFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) $(qpid_CFLAGS)
virt_qmf_la_LDFLAGS = $(MODULESLDFLAGS) $(nss_LIBS) $(qpid_LIBS)
endif
if modpmfence
fvlib_LTLIBRARIES += pm-fence.la
pm_fence_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) $(cib_CFLAGS) $(glib2_CFLAGS) $(xml2_CFLAGS)
pm_fence_la_LDFLAGS = $(MODULESLDFLAGS) $(nss_LIBS) $(cib_LIBS) $(glib2_LIBS) $(xml2_LIBS)
endif
if modcpg
fvlib_LTLIBRARIES += cpg.la
cpg_la_SOURCES += virt.c history.c uuid-test.c
cpg_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) $(cpg_CFLAGS) $(virt_CFLAGS)
cpg_la_LDFLAGS = $(MODULESLDFLAGS) $(nss_LIBS) $(cpg_LIBS) $(virt_LIBS)
endif
if modmulticast
fvlib_LTLIBRARIES += multicast.la
multicast_la_SOURCES += history.c
multicast_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS)
multicast_la_LDFLAGS = $(MODULESLDFLAGS) $(nss_LIBS)
endif
if modserial
fvlib_LTLIBRARIES += serial.la
serial_la_SOURCES += history.c
serial_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS) $(xml2_CFLAGS) $(virt_CFLAGS)
serial_la_LDFLAGS = $(MODULESLDFLAGS) $(nss_LIBS) $(xml2_LIBS) $(virt_LIBS)
endif
if modtcp
fvlib_LTLIBRARIES += tcp.la
tcp_la_SOURCES += history.c
tcp_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS)
tcp_la_LDFLAGS = $(MODULESLDFLAGS) $(nss_LIBS)
endif
if modvsock
fvlib_LTLIBRARIES += vsock.la
vsock_la_SOURCES += history.c
vsock_la_CFLAGS = $(MODULESCFLAGS) $(nss_CFLAGS)
vsock_la_LDFLAGS = $(MODULESLDFLAGS) $(nss_LIBS)
endif
if modnull
fvlib_LTLIBRARIES += null.la
null_la_CFLAGS = $(MODULESCFLAGS)
null_la_LDFLAGS = $(MODULESLDFLAGS)
endif
-
-else
-
-####################
-# Monolithic build #
-####################
-
-# avoid a linking issues when:
-# 1) do a server modular build
-# 2) run configure to switch to monolithic build without make clean
-# 3) do a server build
-#
-# libtool will get confused by the presence of .la files in the builddir
-# and will fail to link the binary
-
-EXTRA_fence_virtd_DEPENDENCIES = cleanmods
-
-cleanmods:
- @rm -rf $(builddir)/*.la
-
-fence_virtd_SOURCES += virt.c history.c
-
-if modlibvirt
-fence_virtd_SOURCES += $(libvirt_la_SOURCES)
-fence_virtd_CFLAGS += $(virt_CFLAGS)
-fence_virtd_LDADD += $(virt_LIBS)
-endif
-if modlibvirtqmf
-fence_virtd_SOURCES += $(libvirt_qmf_la_SOURCES)
-fence_virtd_CFLAGS += $(qpid_CFLAGS)
-fence_virtd_LDADD += $(qpid_LIBS)
-endif
-if modpmfence
-fence_virtd_SOURCES += $(pm_fence_la_SOURCES)
-fence_virtd_CFLAGS += $(cib_CFLAGS)
-fence_virtd_LDADD += $(cib_LIBS)
-endif
-if modcpg
-fence_virtd_SOURCES += $(cpg_la_SOURCES)
-fence_virtd_CFLAGS += $(cpg_CFLAGS)
-fence_virtd_LDADD += $(cpg_LIBS)
-endif
-if modmulticast
-fence_virtd_SOURCES += $(multicast_la_SOURCES)
-endif
-if modserial
-fence_virtd_SOURCES += $(serial_la_SOURCES)
-endif
-if modtcp
-fence_virtd_SOURCES += $(tcp_la_SOURCES)
-endif
-if modvsock
-fence_virtd_SOURCES += $(vsock_la_SOURCES)
-endif
-if modnull
-fence_virtd_SOURCES += $(null_la_SOURCES)
-endif
-
-endif
diff --git a/agents/virt/server/config.c b/agents/virt/server/config.c
index 2d41100c..6b7e3ec8 100644
--- a/agents/virt/server/config.c
+++ b/agents/virt/server/config.c
@@ -1,663 +1,661 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <net/if.h>
#include <arpa/inet.h>
#include "simpleconfig.h"
#include "static_map.h"
#include "mcast.h"
#include "xvm.h"
#include "server_plugin.h"
#include "simple_auth.h"
static int
yesno(const char *prompt, int dfl)
{
char result[10];
printf("%s [%c/%c]? ", prompt, dfl?'Y':'y', dfl?'n':'N');
fflush(stdout);
memset(result, 0, sizeof(result));
if (fgets(result, 9, stdin) == NULL)
return dfl;
if (result[0] == 'y' || result[0] == 'Y')
return 1;
if (result[0] == 'n' || result[0] == 'N')
return 0;
return dfl;
}
static int
text_input(const char *prompt, char *dfl, char *input, size_t len)
{
printf("%s [%s]: ", prompt, dfl?dfl:"");
fflush(stdout);
memset(input, 0, len);
if (fgets(input, len, stdin) == NULL) {
strncpy(input, dfl, len);
return 0;
}
if (input[strlen(input)-1] == '\n')
input[strlen(input)-1] = 0;
if (strlen(input) == 0) {
strncpy(input, dfl, len);
return 0;
}
return 0;
}
static int
plugin_path_configure(config_object_t *config)
{
-#ifdef _MODULE
char val[4096];
char inp[4096];
int done = 0;
if (sc_get(config, "fence_virtd/@module_path", val,
sizeof(val))) {
#ifdef MODULE_PATH
snprintf(val, sizeof(val), MODULE_PATH);
#else
printf("Failed to determine module search path.\n");
#endif
}
do {
text_input("Module search path", val, inp, sizeof(inp));
printf("\n");
done = plugin_search(inp);
if (done > 0) {
plugin_dump();
done = 1;
} else {
done = 0;
printf("No modules found in %s!\n", inp);
if (yesno("Use this value anyway", 0) == 1)
done = 1;
}
} while (!done);
sc_set(config, "fence_virtd/@module_path", inp);
-#endif
return 0;
}
static int
backend_config_libvirt(config_object_t *config)
{
char val[4096];
char inp[4096];
printf("\n");
printf("The libvirt backend module is designed for single desktops or\n"
"servers. Do not use in environments where virtual machines\n"
"may be migrated between hosts.\n\n");
/* Default backend plugin */
if (sc_get(config, "backends/libvirt/@uri", val,
sizeof(val))) {
strncpy(val, DEFAULT_HYPERVISOR_URI, sizeof(val));
}
text_input("Libvirt URI", val, inp, sizeof(inp));
sc_set(config, "backends/libvirt/@uri", inp);
return 0;
}
static int
backend_config_cpg(config_object_t *config)
{
char val[4096];
char inp[4096];
int done = 0;
printf("\n");
printf("The CPG backend module is designed for use in clusters\n"
"running corosync and libvirt. It utilizes the CPG API to \n"
"route fencing requests, finally utilizing libvirt to perform\n"
"fencing actions.\n\n");
if (sc_get(config, "backends/cpg/@uri", val,
sizeof(val))) {
strncpy(val, DEFAULT_HYPERVISOR_URI, sizeof(val));
}
text_input("Libvirt URI", val, inp, sizeof(inp));
sc_set(config, "backends/cpg/@uri", inp);
printf("\n");
printf("The name mode is how the cpg plugin stores and \n"
"references virtual machines. Since virtual machine names\n"
"are not guaranteed to be unique cluster-wide, use of UUIDs\n"
"is strongly recommended. However, for compatibility with \n"
"fence_xvmd, the use of 'name' mode is also supported.\n\n");
if (sc_get(config, "backends/cpg/@name_mode", val,
sizeof(val))) {
strncpy(val, "uuid", sizeof(val));
}
do {
text_input("VM naming/tracking mode (name or uuid)",
val, inp, sizeof(inp));
if (!strcasecmp(inp, "uuid")) {
done = 1;
} else if (!strcasecmp(inp, "name")) {
done = 0;
printf("This can be dangerous if you do not take care to"
"ensure that\n"
"virtual machine names are unique "
"cluster-wide.\n");
if (yesno("Use name mode anyway", 1) == 1)
done = 1;
}
} while (!done);
sc_set(config, "backends/cpg/@name_mode", inp);
return 0;
}
static int
listener_config_multicast(config_object_t *config)
{
char val[4096];
char inp[4096];
const char *family = "ipv4";
struct in_addr sin;
struct in6_addr sin6;
int done = 0;
printf("\n");
printf("The multicast listener module is designed for use environments\n"
"where the guests and hosts may communicate over a network using\n"
"multicast.\n\n");
/* MULTICAST IP ADDRESS/FAMILY */
printf("The multicast address is the address that a client will use to\n"
"send fencing requests to fence_virtd.\n\n");
if (sc_get(config, "listeners/multicast/@address",
val, sizeof(val)-1)) {
strncpy(val, IPV4_MCAST_DEFAULT, sizeof(val));
}
done = 0;
do {
text_input("Multicast IP Address", val, inp, sizeof(inp));
if (inet_pton(AF_INET, inp, &sin) == 1) {
printf("\nUsing ipv4 as family.\n\n");
family = "ipv4";
done = 1;
} else if (inet_pton(AF_INET6, inp, &sin6) == 1) {
printf("\nUsing ipv6 as family.\n\n");
family = "ipv6";
done = 1;
} else
printf("'%s' is not a valid IP address!\n", inp);
} while (!done);
sc_set(config, "listeners/multicast/@family", family);
sc_set(config, "listeners/multicast/@address", inp);
/* MULTICAST IP PORT */
if (sc_get(config, "listeners/multicast/@port",
val, sizeof(val)-1)) {
snprintf(val, sizeof(val), "%d", DEFAULT_MCAST_PORT);
}
done = 0;
do {
char *p;
int ret;
text_input("Multicast IP Port", val, inp, sizeof(inp));
ret = strtol(inp, &p, 0);
if (*p != '\0' || ret <= 0 || ret >= 65536) {
printf("Port value '%s' is out of range\n", val);
continue;
} else
done = 1;
} while (!done);
sc_set(config, "listeners/multicast/@port", inp);
/* MULTICAST INTERFACE */
printf("\nSetting a preferred interface causes fence_virtd to listen only\n"
"on that interface. Normally, it listens on all interfaces.\n"
"In environments where the virtual machines are using the host\n"
"machine as a gateway, this *must* be set (typically to virbr0).\n"
"Set to 'none' for no interface.\n\n"
);
if (sc_get(config, "listeners/multicast/@interface",
val, sizeof(val)-1)) {
strncpy(val, "none", sizeof(val));
}
done = 0;
do {
text_input("Interface", val, inp, sizeof(inp));
if (!strcasecmp(inp, "none")) {
break;
}
if (strlen(inp) > 0) {
int ret;
ret = if_nametoindex(inp);
if (ret < 0) {
printf("Invalid interface: %s\n", inp);
if (yesno("Use anyway", 1) == 1)
done = 1;
} else
done = 1;
} else
printf("No interface given\n");
} while (!done);
if (!strcasecmp(inp, "none")) {
sc_set(config, "listeners/multicast/@interface", NULL);
} else {
sc_set(config, "listeners/multicast/@interface", inp);
}
/* KEY FILE */
printf("\nThe key file is the shared key information which is used to\n"
"authenticate fencing requests. The contents of this file must\n"
"be distributed to each physical host and virtual machine within\n"
"a cluster.\n\n");
if (sc_get(config, "listeners/multicast/@key_file",
val, sizeof(val)-1)) {
strncpy(val, DEFAULT_KEY_FILE, sizeof(val));
}
done = 0;
do {
text_input("Key File", val, inp, sizeof(inp));
if (!strcasecmp(inp, "none")) {
break;
}
if (strlen(inp) > 0) {
if (inp[0] != '/') {
printf("Invalid key file: %s\n", inp);
if (yesno("Use anyway", 1) == 1)
done = 1;
} else
done = 1;
} else
printf("No key file given\n");
} while (!done);
if (!strcasecmp(inp, "none")) {
sc_set(config, "listeners/multicast/@key_file", NULL);
} else {
sc_set(config, "listeners/multicast/@key_file", inp);
}
return 0;
}
static int
listener_config_tcp(config_object_t *config)
{
char val[4096];
char inp[4096];
const char *family = "ipv4";
struct in_addr sin;
struct in6_addr sin6;
int done = 0;
printf("\n");
printf("The TCP listener module is designed for use in environments\n"
"where the guests and hosts communicate over viosproxy.\n\n");
/* IP ADDRESS/FAMILY */
printf("The IP address is the address that a client will use to\n"
"send fencing requests to fence_virtd.\n\n");
if (sc_get(config, "listeners/tcp/@address",
val, sizeof(val)-1)) {
strncpy(val, IPV4_MCAST_DEFAULT, sizeof(val));
}
done = 0;
do {
text_input("TCP Listen IP Address", val, inp, sizeof(inp));
if (inet_pton(AF_INET, inp, &sin) == 1) {
printf("\nUsing ipv4 as family.\n\n");
family = "ipv4";
done = 1;
} else if (inet_pton(AF_INET6, inp, &sin6) == 1) {
printf("\nUsing ipv6 as family.\n\n");
family = "ipv6";
done = 1;
} else {
printf("'%s' is not a valid IP address!\n", inp);
continue;
}
} while (!done);
sc_set(config, "listeners/tcp/@family", family);
sc_set(config, "listeners/tcp/@address", inp);
/* MULTICAST IP PORT */
if (sc_get(config, "listeners/tcp/@port",
val, sizeof(val)-1)) {
snprintf(val, sizeof(val), "%d", DEFAULT_MCAST_PORT);
}
done = 0;
do {
char *p;
int ret;
text_input("TCP Listen Port", val, inp, sizeof(inp));
ret = strtol(inp, &p, 0);
if (*p != '\0' || ret <= 0 || ret >= 65536) {
printf("Port value '%s' is out of range\n", val);
continue;
}
done = 1;
} while (!done);
sc_set(config, "listeners/tcp/@port", inp);
/* KEY FILE */
printf("\nThe key file is the shared key information which is used to\n"
"authenticate fencing requests. The contents of this file must\n"
"be distributed to each physical host and virtual machine within\n"
"a cluster.\n\n");
if (sc_get(config, "listeners/tcp/@key_file",
val, sizeof(val)-1)) {
strncpy(val, DEFAULT_KEY_FILE, sizeof(val));
}
done = 0;
do {
text_input("Key File", val, inp, sizeof(inp));
if (!strcasecmp(inp, "none")) {
break;
}
if (strlen(inp) > 0) {
if (inp[0] != '/') {
printf("Invalid key file: %s\n", inp);
if (yesno("Use anyway", 1) == 1)
done = 1;
} else
done = 1;
} else
printf("No key file given\n");
} while (!done);
if (!strcasecmp(inp, "none")) {
sc_set(config, "listeners/tcp/@key_file", NULL);
} else {
sc_set(config, "listeners/tcp/@key_file", inp);
}
return 0;
}
static int
listener_config_serial(config_object_t *config)
{
char val[4096];
char inp[4096];
int done;
printf("\n");
printf("The serial plugin allows fence_virtd to communicate with\n"
"guests using serial or guest-forwarding VMChannel instead\n"
"of using TCP/IP networking.\n\n");
printf("Special configuration of virtual machines is required. See\n"
"fence_virt.conf(5) for more details.\n\n");
if (sc_get(config, "listeners/serial/@uri",
val, sizeof(val)-1)) {
strncpy(val, DEFAULT_HYPERVISOR_URI, sizeof(val));
}
text_input("Libvirt URI", val, inp, sizeof(inp));
printf("\nSetting a socket path prevents fence_virtd from taking\n"
"hold of all Unix domain sockets created when the guest\n"
"is started. A value like /var/run/cluster/fence might\n"
"be a good value. Don't forget to create the directory!\n\n");
if (sc_get(config, "listeners/serial/@path",
val, sizeof(val)-1)) {
strncpy(val, "none", sizeof(val));
}
text_input("Socket directory", val, inp, sizeof(inp));
if (!strcasecmp(inp, "none")) {
sc_set(config, "listeners/serial/@path", NULL);
} else {
sc_set(config, "listeners/serial/@path", inp);
}
printf("\nThe serial plugin allows two types of guest to host\n"
"configurations. One is via a serial port; the other is\n"
"utilizing the newer VMChannel.\n\n");
if (sc_get(config, "listeners/serial/@mode",
val, sizeof(val)-1)) {
strncpy(val, "serial", sizeof(val));
}
if (!strcasecmp(inp, "none")) {
sc_set(config, "listeners/serial/@path", NULL);
} else {
sc_set(config, "listeners/serial/@path", inp);
}
done = 0;
do {
text_input("Mode (serial or vmchannel)", val, inp,
sizeof(inp));
if (strcasecmp(inp, "serial") && strcasecmp(inp, "vmchannel")) {
printf("Invalid mode: %s\n", inp);
if (yesno("Use anyway", 1) == 1)
done = 1;
} else
done = 1;
} while (!done);
sc_set(config, "listeners/serial/@mode", inp);
return 0;
}
static int
backend_configure(config_object_t *config)
{
char val[4096];
char inp[4096];
int done;
printf("\n");
printf("Backend modules are responsible for routing requests to\n"
"the appropriate hypervisor or management layer.\n\n");
/* Default backend plugin */
if (sc_get(config, "fence_virtd/@backend", val,
sizeof(val))) {
strncpy(val, "libvirt", sizeof(val));
}
done = 0;
do {
text_input("Backend module", val, inp, sizeof(inp));
if (plugin_find_backend(inp) == NULL) {
printf("No backend module named %s found!\n", inp);
if (yesno("Use this value anyway", 0) == 1)
done = 1;
} else
done = 1;
} while (!done);
sc_set(config, "fence_virtd/@backend", inp);
if (!strcmp(inp, "libvirt")) {
backend_config_libvirt(config);
} else if (!strcmp(inp, "cpg")) {
backend_config_cpg(config);
}
return 0;
}
static int
listener_configure(config_object_t *config)
{
char val[4096];
char inp[4096];
int done;
printf("\n");
printf("Listener modules are responsible for accepting requests\n"
"from fencing clients.\n\n");
/* Default backend plugin */
if (sc_get(config, "fence_virtd/@listener", val,
sizeof(val))) {
strncpy(val, "multicast", sizeof(val));
}
done = 0;
do {
text_input("Listener module", val, inp, sizeof(inp));
if (plugin_find_listener(inp) == NULL) {
printf("No listener module named %s found!\n", inp);
if (yesno("Use this value anyway", 0) == 1)
done = 1;
} else
done = 1;
} while (!done);
sc_set(config, "fence_virtd/@listener", inp);
if (!strcmp(inp, "multicast"))
listener_config_multicast(config);
else if (!strcmp(inp, "tcp"))
listener_config_tcp(config);
else if (!strcmp(inp, "serial"))
listener_config_serial(config);
else
printf("Unable to configure unknown listner module '%s'\n", inp);
return 0;
}
int
do_configure(config_object_t *config, const char *config_file)
{
FILE *fp = NULL;
char message[80];
char tmp_filename[4096];
int tmp_fd = -1;
mode_t old_umask;
if (sc_parse(config, config_file) != 0) {
printf("Parsing of %s failed.\n", config_file);
if (yesno("Start from scratch", 0) == 0) {
return 1;
}
}
plugin_path_configure(config);
listener_configure(config);
backend_configure(config);
printf("\nConfiguration complete.\n\n");
printf("=== Begin Configuration ===\n");
sc_dump(config, stdout);
printf("=== End Configuration ===\n");
snprintf(message, sizeof(message), "Replace %s with the above",
config_file);
if (yesno(message, 0) == 0) {
return 1;
}
snprintf(tmp_filename, sizeof(tmp_filename),
"%s.XXXXXX", config_file);
old_umask = umask(077);
tmp_fd = mkstemp(tmp_filename);
umask(old_umask);
if (tmp_fd < 0) {
perror("fopen");
printf("Failed to write configuration file!\n");
return 1;
}
fp = fdopen(tmp_fd, "w+");
if (fp == NULL)
goto out_fail;
sc_dump(config, fp);
if (rename(tmp_filename, config_file) < 0) {
perror("rename");
goto out_fail;
}
fclose(fp);
close(tmp_fd);
return 0;
out_fail:
if (fp)
fclose(fp);
if (tmp_fd >= 0)
close(tmp_fd);
if (strlen(tmp_filename))
unlink(tmp_filename);
printf("Failed to write configuration file!\n");
return 1;
}
diff --git a/agents/virt/server/cpg-virt.c b/agents/virt/server/cpg-virt.c
index 3a9c2dd2..304519c4 100644
--- a/agents/virt/server/cpg-virt.c
+++ b/agents/virt/server/cpg-virt.c
@@ -1,654 +1,643 @@
/*
Copyright Red Hat, Inc. 2017
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: Ryan McCabe <rmccabe@redhat.com>
*/
#include "config.h"
#include <stdio.h>
#include <sys/types.h>
#include <stdint.h>
#include <time.h>
#include <string.h>
#include <syslog.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <corosync/cpg.h>
#include "debug.h"
#include "virt.h"
#include "xvm.h"
#include "cpg.h"
#include "simpleconfig.h"
#include "static_map.h"
#include "server_plugin.h"
#define NAME "cpg"
#define CPG_VERSION "0.1"
#define MAGIC 0x38e93fc2
struct cpg_info {
int magic;
config_object_t *config;
int vp_count;
virConnectPtr *vp;
};
#define VALIDATE(arg) \
do {\
if (!arg || ((struct cpg_info *) arg)->magic != MAGIC) { \
errno = EINVAL;\
return -1; \
} \
} while(0)
static struct cpg_info *cpg_virt_handle = NULL;
static int use_uuid = 0;
pthread_mutex_t local_vm_list_lock = PTHREAD_MUTEX_INITIALIZER;
static virt_list_t *local_vm_list = NULL;
pthread_mutex_t remote_vm_list_lock = PTHREAD_MUTEX_INITIALIZER;
static virt_list_t *remote_vm_list = NULL;
static void cpg_virt_init_libvirt(struct cpg_info *info);
static int
virt_list_update(struct cpg_info *info, virt_list_t **vl, int my_id)
{
virt_list_t *list = NULL;
if (*vl)
vl_free(*vl);
list = vl_get(info->vp, info->vp_count, my_id);
if (!list && (errno == EPIPE || errno == EINVAL)) {
do {
cpg_virt_init_libvirt(info);
} while (info->vp_count == 0);
list = vl_get(info->vp, info->vp_count, my_id);
}
*vl = list;
if (!list)
return -1;
return 0;
}
static void
store_domains(virt_list_t *vl)
{
int i;
if (!vl)
return;
for (i = 0 ; i < vl->vm_count ; i++) {
int ret;
if (!strcmp(DOMAIN0NAME, vl->vm_states[i].v_name))
continue;
ret = cpg_send_vm_state(&vl->vm_states[i]);
if (ret < 0) {
printf("Error storing VM state for %s|%s\n",
vl->vm_states[i].v_name, vl->vm_states[i].v_uuid);
}
}
}
static void
update_local_vms(struct cpg_info *info)
{
uint32_t my_id = 0;
if (!info)
return;
cpg_get_ids(&my_id, NULL);
virt_list_update(info, &local_vm_list, my_id);
store_domains(local_vm_list);
}
static int
do_off(struct cpg_info *info, const char *vm_name)
{
dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name);
return vm_off(info->vp, info->vp_count, vm_name);
}
static int
do_on(struct cpg_info *info, const char *vm_name)
{
dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name);
return vm_on(info->vp, info->vp_count, vm_name);
}
static int
do_reboot(struct cpg_info *info, const char *vm_name)
{
dbg_printf(5, "%s %s\n", __FUNCTION__, vm_name);
return vm_reboot(info->vp, info->vp_count, vm_name);
}
static void
cpg_join_cb(const struct cpg_address *join, size_t joinlen) {
struct cpg_info *info = cpg_virt_handle;
pthread_mutex_lock(&local_vm_list_lock);
update_local_vms(info);
pthread_mutex_unlock(&local_vm_list_lock);
}
static void
cpg_leave_cb(const struct cpg_address *left, size_t leftlen) {
struct cpg_info *info = cpg_virt_handle;
int i;
pthread_mutex_lock(&remote_vm_list_lock);
for (i = 0 ; i < leftlen ; i++) {
dbg_printf(2, "Removing VMs owned by nodeid %u\n", left[i].nodeid);
vl_remove_by_owner(&remote_vm_list, left[i].nodeid);
}
pthread_mutex_unlock(&remote_vm_list_lock);
pthread_mutex_lock(&local_vm_list_lock);
update_local_vms(info);
pthread_mutex_unlock(&local_vm_list_lock);
}
static void
store_cb(void *data, size_t len, uint32_t nodeid, uint32_t seqno)
{
uint32_t my_id;
virt_state_t *vs = (virt_state_t *) data;
struct cpg_info *info = cpg_virt_handle;
cpg_get_ids(&my_id, NULL);
if (nodeid == my_id)
return;
pthread_mutex_lock(&local_vm_list_lock);
if (!local_vm_list)
update_local_vms(info);
pthread_mutex_unlock(&local_vm_list_lock);
pthread_mutex_lock(&remote_vm_list_lock);
vl_update(&remote_vm_list, vs);
pthread_mutex_unlock(&remote_vm_list_lock);
}
/*
** This function must a send reply from at least one node, otherwise
** the requesting fence_virtd will block forever in wait_cpt_reply.
*/
static void
do_real_work(void *data, size_t len, uint32_t nodeid, uint32_t seqno)
{
struct cpg_info *info = cpg_virt_handle;
struct cpg_fence_req *req = data;
struct cpg_fence_req reply;
int reply_code = -1;
virt_state_t *vs = NULL;
int cur_state;
uint32_t cur_owner = 0;
int local = 0;
uint32_t my_id, high_id;
dbg_printf(2, "Request %d for VM %s\n", req->request, req->vm_name);
if (cpg_get_ids(&my_id, &high_id) == -1) {
syslog(LOG_WARNING, "Unable to get CPG IDs");
printf("Should never happen: Can't get CPG node ids - can't proceed\n");
return;
}
memcpy(&reply, req, sizeof(reply));
pthread_mutex_lock(&local_vm_list_lock);
update_local_vms(info);
if (strlen(req->vm_name)) {
if (use_uuid)
vs = vl_find_uuid(local_vm_list, req->vm_name);
else
vs = vl_find_name(local_vm_list, req->vm_name);
if (vs) {
local = 1;
cur_owner = vs->v_state.s_owner;
cur_state = vs->v_state.s_state;
dbg_printf(2, "Found VM %s locally state %d\n",
req->vm_name, cur_state);
}
}
pthread_mutex_unlock(&local_vm_list_lock);
if (vs == NULL) {
pthread_mutex_lock(&remote_vm_list_lock);
if (strlen(req->vm_name)) {
if (use_uuid)
vs = vl_find_uuid(remote_vm_list, req->vm_name);
else
vs = vl_find_name(remote_vm_list, req->vm_name);
if (vs) {
cur_owner = vs->v_state.s_owner;
cur_state = vs->v_state.s_state;
dbg_printf(2, "Found VM %s remotely on %u state %d\n",
req->vm_name, cur_owner, cur_state);
}
}
pthread_mutex_unlock(&remote_vm_list_lock);
}
if (!vs) {
/*
** We know about all domains on all nodes in the CPG group.
** If we didn't find it, and we're high ID, act on the request.
** We can safely assume the VM is OFF because it wasn't found
** on any current members of the CPG group.
*/
if (my_id == high_id) {
if (req->request == FENCE_STATUS)
reply_code = RESP_OFF;
else if (req->request == FENCE_OFF || req->request == FENCE_REBOOT)
reply_code = RESP_SUCCESS;
else
reply_code = 1;
dbg_printf(2, "Acting on request %d for unknown domain %s -> %d\n",
req->request, req->vm_name, reply_code);
goto out;
}
dbg_printf(2, "Not acting on request %d for unknown domain %s\n",
req->request, req->vm_name);
return;
}
if (local) {
if (req->request == FENCE_STATUS) {
/* We already have the status */
if (cur_state == VIR_DOMAIN_SHUTOFF)
reply_code = RESP_OFF;
else
reply_code = RESP_SUCCESS;
} else if (req->request == FENCE_OFF) {
reply_code = do_off(info, req->vm_name);
} else if (req->request == FENCE_ON) {
reply_code = do_on(info, req->vm_name);
} else if (req->request == FENCE_REBOOT) {
reply_code = do_reboot(info, req->vm_name);
} else {
dbg_printf(2, "Not explicitly handling request type %d for %s\n",
req->request, req->vm_name);
reply_code = 0;
}
goto out;
}
/*
** This is a request for a non-local domain that exists on a
** current CPG group member, so that member will see the request
** and act on it. We don't need to do anything.
*/
dbg_printf(2, "Nothing to do for non-local domain %s seq %d owner %u\n",
req->vm_name, seqno, cur_owner);
return;
out:
dbg_printf(2, "[%s] sending reply code seq %d -> %d\n",
req->vm_name, seqno, reply_code);
reply.response = reply_code;
if (cpg_send_reply(&reply, sizeof(reply), nodeid, seqno) < 0) {
dbg_printf(2, "cpg_send_reply failed for %s [%d %d]: %s\n",
req->vm_name, nodeid, seqno, strerror(errno));
}
}
static int
do_request(const char *vm_name, int request, uint32_t seqno)
{
struct cpg_fence_req freq, *frp;
size_t retlen;
uint32_t seq;
int ret;
memset(&freq, 0, sizeof(freq));
if (!vm_name) {
dbg_printf(1, "No VM name\n");
return 1;
}
if (strlen(vm_name) >= sizeof(freq.vm_name)) {
dbg_printf(1, "VM name %s too long\n", vm_name);
return 1;
}
strcpy(freq.vm_name, vm_name);
freq.request = request;
freq.seqno = seqno;
if (cpg_send_req(&freq, sizeof(freq), &seq) != 0) {
dbg_printf(1, "Failed to send request %d for VM %s\n",
freq.request, vm_name);
return 1;
}
dbg_printf(2, "Sent request %d for VM %s got seqno %d\n",
request, vm_name, seq);
if (cpg_wait_reply((void *) &frp, &retlen, seq) != 0) {
dbg_printf(1, "Failed to receive reply seq %d for %s\n", seq, vm_name);
return 1;
}
dbg_printf(2, "Received reply [%d] seq %d for %s\n",
frp->response, seq, vm_name);
ret = frp->response;
free(frp);
return ret;
}
static int
cpg_virt_null(const char *vm_name, void *priv)
{
VALIDATE(priv);
printf("[cpg-virt] Null operation on %s\n", vm_name);
return 1;
}
static int
cpg_virt_off(const char *vm_name, const char *src, uint32_t seqno, void *priv)
{
VALIDATE(priv);
printf("[cpg-virt] OFF operation on %s seq %d\n", vm_name, seqno);
return do_request(vm_name, FENCE_OFF, seqno);
}
static int
cpg_virt_on(const char *vm_name, const char *src, uint32_t seqno, void *priv)
{
VALIDATE(priv);
printf("[cpg-virt] ON operation on %s seq %d\n", vm_name, seqno);
return do_request(vm_name, FENCE_ON, seqno);
}
static int
cpg_virt_devstatus(void *priv)
{
printf("[cpg-virt] Device status\n");
VALIDATE(priv);
return 0;
}
static int
cpg_virt_status(const char *vm_name, void *priv)
{
VALIDATE(priv);
printf("[cpg-virt] STATUS operation on %s\n", vm_name);
return do_request(vm_name, FENCE_STATUS, 0);
}
static int
cpg_virt_reboot(const char *vm_name, const char *src,
uint32_t seqno, void *priv)
{
VALIDATE(priv);
printf("[cpg-virt] REBOOT operation on %s seq %d\n", vm_name, seqno);
return do_request(vm_name, FENCE_REBOOT, 0);
}
static int
cpg_virt_hostlist(hostlist_callback callback, void *arg, void *priv)
{
struct cpg_info *info = (struct cpg_info *) priv;
int i;
VALIDATE(priv);
printf("[cpg-virt] HOSTLIST operation\n");
pthread_mutex_lock(&local_vm_list_lock);
update_local_vms(info);
for (i = 0 ; i < local_vm_list->vm_count ; i++) {
callback(local_vm_list->vm_states[i].v_name,
local_vm_list->vm_states[i].v_uuid,
local_vm_list->vm_states[i].v_state.s_state, arg);
}
pthread_mutex_unlock(&local_vm_list_lock);
return 1;
}
static void
cpg_virt_init_libvirt(struct cpg_info *info) {
config_object_t *config = info->config;
int i = 0;
if (info->vp) {
dbg_printf(2, "Lost libvirtd connection. Reinitializing.\n");
for (i = 0 ; i < info->vp_count ; i++)
virConnectClose(info->vp[i]);
free(info->vp);
info->vp = NULL;
}
info->vp_count = 0;
do {
virConnectPtr vp;
virConnectPtr *vpl = NULL;
char conf_attr[256];
char value[1024];
char *uri;
if (i != 0) {
snprintf(conf_attr, sizeof(conf_attr),
"backends/cpg/@uri%d", i);
} else
snprintf(conf_attr, sizeof(conf_attr), "backends/cpg/@uri");
++i;
if (sc_get(config, conf_attr, value, sizeof(value)) != 0)
break;
uri = value;
vp = virConnectOpen(uri);
if (!vp) {
dbg_printf(1, "[cpg-virt:INIT] Failed to connect to URI: %s\n", uri);
continue;
}
vpl = realloc(info->vp, sizeof(*info->vp) * (info->vp_count + 1));
if (!vpl) {
dbg_printf(1, "[cpg-virt:INIT] Out of memory allocating URI: %s\n",
uri);
virConnectClose(vp);
continue;
}
info->vp = vpl;
info->vp[info->vp_count++] = vp;
if (i > 1)
dbg_printf(1, "[cpg-virt:INIT] Added URI%d %s\n", i - 1, uri);
else
dbg_printf(1, "[cpg_virt:INIT] Added URI %s\n", uri);
} while (1);
}
static int
cpg_virt_init(backend_context_t *c, config_object_t *config)
{
char value[1024];
struct cpg_info *info = NULL;
int ret;
ret = cpg_start(PACKAGE_NAME,
do_real_work, store_cb, cpg_join_cb, cpg_leave_cb);
if (ret < 0)
return -1;
info = calloc(1, sizeof(*info));
if (!info)
return -1;
info->magic = MAGIC;
info->config = config;
-#ifdef _MODULE
if (sc_get(config, "fence_virtd/@debug", value, sizeof(value)) == 0)
dset(atoi(value));
-#endif
cpg_virt_init_libvirt(info);
/* Naming scheme is no longer a top-level config option.
* However, we retain it here for configuration compatibility with
* versions 0.1.3 and previous.
*/
if (sc_get(config, "fence_virtd/@name_mode",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for name_mode\n", value);
if (!strcasecmp(value, "uuid")) {
use_uuid = 1;
} else if (!strcasecmp(value, "name")) {
use_uuid = 0;
} else {
dbg_printf(1, "Unsupported name_mode: %s\n", value);
}
}
if (sc_get(config, "backends/cpg/@name_mode",
value, sizeof(value)-1) == 0)
{
dbg_printf(1, "Got %s for name_mode\n", value);
if (!strcasecmp(value, "uuid")) {
use_uuid = 1;
} else if (!strcasecmp(value, "name")) {
use_uuid = 0;
} else {
dbg_printf(1, "Unsupported name_mode: %s\n", value);
}
}
if (info->vp_count < 1) {
dbg_printf(1, "[cpg_virt:INIT] Could not connect to any hypervisors\n");
cpg_stop();
free(info);
return -1;
}
pthread_mutex_lock(&local_vm_list_lock);
update_local_vms(info);
pthread_mutex_unlock(&local_vm_list_lock);
*c = (void *) info;
cpg_virt_handle = info;
return 0;
}
static int
cpg_virt_shutdown(backend_context_t c)
{
struct cpg_info *info = (struct cpg_info *)c;
int i = 0;
int ret = 0;
VALIDATE(info);
info->magic = 0;
cpg_stop();
for (i = 0 ; i < info->vp_count ; i++) {
if (virConnectClose(info->vp[i]) < 0)
ret = -errno;
}
free(info->vp);
free(info);
return ret;
}
static fence_callbacks_t cpg_callbacks = {
.null = cpg_virt_null,
.off = cpg_virt_off,
.on = cpg_virt_on,
.reboot = cpg_virt_reboot,
.status = cpg_virt_status,
.devstatus = cpg_virt_devstatus,
.hostlist = cpg_virt_hostlist
};
static backend_plugin_t cpg_virt_plugin = {
.name = NAME,
.version = CPG_VERSION,
.callbacks = &cpg_callbacks,
.init = cpg_virt_init,
.cleanup = cpg_virt_shutdown,
};
-
-#ifdef _MODULE
double
BACKEND_VER_SYM(void)
{
return PLUGIN_VERSION_BACKEND;
}
const backend_plugin_t *
BACKEND_INFO_SYM(void)
{
return &cpg_virt_plugin;
}
-#else
-static void __attribute__((constructor))
-cpg_register_plugin(void)
-{
- plugin_reg_backend(&cpg_virt_plugin);
-}
-#endif
diff --git a/agents/virt/server/libvirt.c b/agents/virt/server/libvirt.c
index 8467590d..8f010452 100644
--- a/agents/virt/server/libvirt.c
+++ b/agents/virt/server/libvirt.c
@@ -1,370 +1,359 @@
/*
Copyright Red Hat, Inc. 2006-2017
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 "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <libvirt/virterror.h>
#include <nss.h>
#include <libgen.h>
#include <syslog.h>
/* Local includes */
#include "xvm.h"
#include "simple_auth.h"
#include "options.h"
#include "mcast.h"
#include "tcp.h"
#include "virt.h"
#include "debug.h"
#include "uuid-test.h"
#include "simpleconfig.h"
#include "static_map.h"
#include "server_plugin.h"
#define NAME "libvirt"
#define LIBVIRT_VERSION "0.3"
#define MAGIC 0x1e19317a
struct libvirt_info {
int magic;
config_object_t *config;
int vp_count;
virConnectPtr *vp;
};
#define VALIDATE(arg) \
do {\
if (!arg || ((struct libvirt_info *)arg)->magic != MAGIC) { \
errno = EINVAL;\
return -1; \
} \
} while(0)
static void
libvirt_init_libvirt_conf(struct libvirt_info *info) {
config_object_t *config = info->config;
int i = 0;
if (info->vp) {
dbg_printf(2, "Lost libvirtd connection. Reinitializing.\n");
for (i = 0 ; i < info->vp_count ; i++)
virConnectClose(info->vp[i]);
free(info->vp);
info->vp = NULL;
}
info->vp_count = 0;
do {
virConnectPtr vp;
virConnectPtr *vpl = NULL;
char conf_attr[256];
char value[1024];
char *uri;
if (i != 0) {
snprintf(conf_attr, sizeof(conf_attr),
"backends/libvirt/@uri%d", i);
} else
snprintf(conf_attr, sizeof(conf_attr), "backends/libvirt/@uri");
++i;
if (sc_get(config, conf_attr, value, sizeof(value)) != 0)
break;
uri = value;
vp = virConnectOpen(uri);
if (!vp) {
dbg_printf(1, "[libvirt:INIT] Failed to connect to URI: %s\n", uri);
continue;
}
vpl = realloc(info->vp, sizeof(*info->vp) * (info->vp_count + 1));
if (!vpl) {
dbg_printf(1, "[libvirt:INIT] Out of memory allocating URI: %s\n",
uri);
virConnectClose(vp);
continue;
}
info->vp = vpl;
info->vp[info->vp_count++] = vp;
if (i > 1)
dbg_printf(1, "[libvirt:INIT] Added URI%d %s\n", i - 1, uri);
else
dbg_printf(1, "[libvirt:INIT] Added URI %s\n", uri);
} while (1);
}
static int
libvirt_bad_connections(struct libvirt_info *info) {
int bad = 0;
int i;
for (i = 0 ; i < info->vp_count ; i++) {
/*
** Send a dummy command to trigger an error if libvirtd
** died or restarted
*/
virConnectNumOfDomains(info->vp[i]);
if (!virConnectIsAlive(info->vp[i])) {
dbg_printf(1, "libvirt connection %d is dead\n", i);
bad++;
}
}
if (info->vp_count < 1 || bad)
libvirt_init_libvirt_conf(info);
return bad || info->vp_count < 1;
}
static void
libvirt_validate_connections(struct libvirt_info *info) {
while (1) {
if (libvirt_bad_connections(info))
sleep(1);
else
break;
}
}
static int
libvirt_null(const char *vm_name, void *priv)
{
dbg_printf(5, "ENTER %s %s\n", __FUNCTION__, vm_name);
printf("NULL operation: returning failure\n");
return 1;
}
static int
libvirt_off(const char *vm_name, const char *src, uint32_t seqno, void *priv)
{
struct libvirt_info *info = (struct libvirt_info *)priv;
dbg_printf(5, "ENTER %s %s %u\n", __FUNCTION__, vm_name, seqno);
VALIDATE(info);
libvirt_validate_connections(info);
return vm_off(info->vp, info->vp_count, vm_name);
}
static int
libvirt_on(const char *vm_name, const char *src, uint32_t seqno, void *priv)
{
struct libvirt_info *info = (struct libvirt_info *)priv;
dbg_printf(5, "ENTER %s %s %u\n", __FUNCTION__, vm_name, seqno);
VALIDATE(info);
libvirt_validate_connections(info);
return vm_on(info->vp, info->vp_count, vm_name);
}
static int
libvirt_devstatus(void *priv)
{
dbg_printf(5, "%s ---\n", __FUNCTION__);
if (priv)
return 0;
return 1;
}
static int
libvirt_status(const char *vm_name, void *priv)
{
struct libvirt_info *info = (struct libvirt_info *)priv;
dbg_printf(5, "ENTER %s %s\n", __FUNCTION__, vm_name);
VALIDATE(info);
libvirt_validate_connections(info);
return vm_status(info->vp, info->vp_count, vm_name);
}
static int
libvirt_reboot(const char *vm_name, const char *src, uint32_t seqno, void *priv)
{
struct libvirt_info *info = (struct libvirt_info *)priv;
dbg_printf(5, "ENTER %s %s %u\n", __FUNCTION__, vm_name, seqno);
VALIDATE(info);
libvirt_validate_connections(info);
return vm_reboot(info->vp, info->vp_count, vm_name);
}
static int
libvirt_hostlist(hostlist_callback callback, void *arg, void *priv)
{
struct libvirt_info *info = (struct libvirt_info *)priv;
virt_list_t *vl;
int x;
dbg_printf(5, "ENTER %s\n", __FUNCTION__);
VALIDATE(info);
libvirt_validate_connections(info);
vl = vl_get(info->vp, info->vp_count, 1);
if (!vl)
return 0;
for (x = 0; x < vl->vm_count; x++) {
callback(vl->vm_states[x].v_name,
vl->vm_states[x].v_uuid,
vl->vm_states[x].v_state.s_state, arg);
dbg_printf(10, "[libvirt:HOSTLIST] Sent %s %s %d\n",
vl->vm_states[x].v_name,
vl->vm_states[x].v_uuid,
vl->vm_states[x].v_state.s_state);
}
vl_free(vl);
return 0;
}
static int
libvirt_init(backend_context_t *c, config_object_t *config)
{
char value[256];
struct libvirt_info *info = NULL;
dbg_printf(5, "ENTER [%s:%d %s]\n", __FILE__, __LINE__, __FUNCTION__);
info = calloc(1, sizeof(*info));
if (!info)
return -1;
info->magic = MAGIC;
info->config = config;
libvirt_init_libvirt_conf(info);
-#ifdef _MODULE
if (sc_get(config, "fence_virtd/@debug", value, sizeof(value)) == 0)
dset(atoi(value));
-#endif
if (info->vp_count < 1) {
dbg_printf(1, "[libvirt:INIT] Could not connect to any hypervisors\n");
if (info->vp)
free(info->vp);
free(info);
return -1;
}
*c = (void *) info;
return 0;
}
static int
libvirt_shutdown(backend_context_t c)
{
struct libvirt_info *info = (struct libvirt_info *)c;
int i;
int ret = 0;
VALIDATE(info);
for (i = 0 ; i < info->vp_count ; i++) {
if (virConnectClose(info->vp[i]) < 0)
ret = -errno;
}
free(info->vp);
free(info);
return ret;
}
static fence_callbacks_t libvirt_callbacks = {
.null = libvirt_null,
.off = libvirt_off,
.on = libvirt_on,
.reboot = libvirt_reboot,
.status = libvirt_status,
.devstatus = libvirt_devstatus,
.hostlist = libvirt_hostlist
};
static backend_plugin_t libvirt_plugin = {
.name = NAME,
.version = LIBVIRT_VERSION,
.callbacks = &libvirt_callbacks,
.init = libvirt_init,
.cleanup = libvirt_shutdown,
};
-
-#ifdef _MODULE
double
BACKEND_VER_SYM(void)
{
return PLUGIN_VERSION_BACKEND;
}
const backend_plugin_t *
BACKEND_INFO_SYM(void)
{
return &libvirt_plugin;
}
-#else
-static void __attribute__((constructor))
-libvirt_register_plugin(void)
-{
- plugin_reg_backend(&libvirt_plugin);
-}
-#endif
diff --git a/agents/virt/server/main.c b/agents/virt/server/main.c
index 9da8f0ea..8d9c3c19 100644
--- a/agents/virt/server/main.c
+++ b/agents/virt/server/main.c
@@ -1,266 +1,264 @@
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/param.h>
#include <libgen.h>
#include <stdint.h>
#include <syslog.h>
/* Local includes */
#include "simpleconfig.h"
#include "static_map.h"
#include "server_plugin.h"
#include "debug.h"
/* configure.c */
int daemon_init(const char *prog, const char *pid_file, int nofork);
int daemon_cleanup(void);
static void
usage(void)
{
printf("Usage: fence_virtd [options]\n");
printf(" -F Do not daemonize.\n");
printf(" -f <file> Use <file> as configuration file.\n");
printf(" -d <level> Set debugging level to <level>.\n");
printf(" -c Configuration mode.\n");
printf(" -l List plugins.\n");
printf(" -w Wait for initialization.\n");
printf(" -p <file> Use <file> to record the active process id.\n");
}
static int run = 1;
static void
exit_handler(int sig)
{
run = 0;
}
int
main(int argc, char **argv)
{
char val[4096];
char listener_name[80];
char backend_name[80];
const char *config_file = SYSCONFDIR "/fence_virt.conf";
char *pid_file = NULL;
config_object_t *config = NULL;
map_object_t *map = NULL;
const listener_plugin_t *lp;
const backend_plugin_t *p;
listener_context_t listener_ctx = NULL;
backend_context_t backend_ctx = NULL;
int debug_set = 0, foreground = 0, wait_for_init = 0;
int opt, configure = 0;
config = sc_init();
map = map_init();
if (!config || !map) {
perror("malloc");
return -1;
}
while ((opt = getopt(argc, argv, "Ff:d:cwlhp:")) != EOF) {
switch(opt) {
case 'F':
printf("Background mode disabled\n");
foreground = 1;
break;
case 'f':
printf("Using %s\n", optarg);
config_file = optarg;
break;
case 'p':
printf("Using %s\n", optarg);
pid_file = optarg;
break;
case 'd':
debug_set = atoi(optarg);
break;
case 'c':
configure = 1;
break;
case 'w':
wait_for_init = 1;
break;
case 'l':
plugin_dump();
return 0;
case 'h':
case '?':
usage();
return 0;
default:
return -1;
}
}
if (configure) {
return do_configure(config, config_file);
}
if (sc_parse(config, config_file) != 0) {
printf("Failed to parse %s\n", config_file);
return -1;
}
if (debug_set) {
snprintf(val, sizeof(val), "%d", debug_set);
sc_set(config, "fence_virtd/@debug", val);
} else {
if (sc_get(config, "fence_virtd/@debug", val, sizeof(val))==0)
debug_set = atoi(val);
}
dset(debug_set);
if (!foreground) {
if (sc_get(config, "fence_virtd/@foreground",
val, sizeof(val)) == 0)
foreground = atoi(val);
}
if (!wait_for_init) {
if (sc_get(config, "fence_virtd/@wait_for_init",
val, sizeof(val)) == 0)
wait_for_init = atoi(val);
if (!wait_for_init) {
/* XXX compat */
if (sc_get(config, "fence_virtd/@wait_for_backend",
val, sizeof(val)) == 0)
wait_for_init = atoi(val);
}
}
if (dget() > 3)
sc_dump(config, stdout);
if (sc_get(config, "fence_virtd/@backend", backend_name,
sizeof(backend_name))) {
printf("Failed to determine backend.\n");
printf("%s\n", val);
return -1;
}
dbg_printf(1, "Backend plugin: %s\n", backend_name);
if (sc_get(config, "fence_virtd/@listener", listener_name,
sizeof(listener_name))) {
printf("Failed to determine backend.\n");
printf("%s\n", val);
return -1;
}
dbg_printf(1, "Listener plugin: %s\n", listener_name);
-#ifdef _MODULE
if (sc_get(config, "fence_virtd/@module_path", val,
sizeof(val))) {
#ifdef MODULE_PATH
snprintf(val, sizeof(val), MODULE_PATH);
#else
printf("Failed to determine module path.\n");
return -1;
#endif
}
dbg_printf(1, "Searching %s for plugins...\n", val);
opt = plugin_search(val);
if (opt > 0) {
dbg_printf(1, "%d plugins found\n", opt);
} else {
printf("No plugins found\n");
return 1;
}
-#endif
if (dget() > 3)
plugin_dump();
lp = plugin_find_listener(listener_name);
if (!lp) {
printf("Could not find listener \"%s\"\n", listener_name);
return 1;
}
p = plugin_find_backend(backend_name);
if (!p) {
printf("Could not find backend \"%s\"\n", backend_name);
return 1;
}
if (pid_file == NULL) {
pid_file = malloc(PATH_MAX);
memset(pid_file, 0, PATH_MAX);
snprintf(pid_file, PATH_MAX, "/var/run/%s.pid", basename(argv[0]));
}
openlog(basename(argv[0]), LOG_NDELAY | LOG_PID, LOG_DAEMON);
daemon_init(basename(argv[0]), pid_file, foreground);
signal(SIGINT, exit_handler);
signal(SIGTERM, exit_handler);
signal(SIGQUIT, exit_handler);
syslog(LOG_NOTICE, "fence_virtd starting. Listener: %s Backend: %s",
listener_name, backend_name);
while (p->init(&backend_ctx, config) < 0) {
if (!wait_for_init || !run) {
if (foreground) {
printf("Backend plugin %s failed to initialize\n",
backend_name);
}
syslog(LOG_ERR,
"Backend plugin %s failed to initialize\n",
backend_name);
return 1;
}
sleep(5);
}
if (map_load(map, config) < 0) {
syslog(LOG_WARNING, "Failed to load static maps\n");
}
/* only client we have now is mcast (fence_xvm behavior) */
while (lp->init(&listener_ctx, p->callbacks, config, map,
backend_ctx) != 0) {
if (!wait_for_init || !run) {
if (foreground) {
printf("Listener plugin %s failed to initialize\n",
listener_name);
}
syslog(LOG_ERR,
"Listener plugin %s failed to initialize\n",
listener_name);
return 1;
}
sleep(5);
}
while (run && lp->dispatch(listener_ctx, NULL) >= 0);
syslog(LOG_NOTICE, "fence_virtd shutting down");
map_release(map);
sc_release(config);
lp->cleanup(listener_ctx);
p->cleanup(backend_ctx);
daemon_cleanup();
return 0;
}
diff --git a/agents/virt/server/mcast.c b/agents/virt/server/mcast.c
index bf107237..a76888f9 100644
--- a/agents/virt/server/mcast.c
+++ b/agents/virt/server/mcast.c
@@ -1,634 +1,622 @@
/*
Copyright Red Hat, Inc. 2006
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 "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <nss.h>
#include <libgen.h>
/* Local includes */
#include "xvm.h"
#include "simple_auth.h"
#include "options.h"
#include "mcast.h"
#include "tcp.h"
#include "debug.h"
#include "fdops.h"
#include "list.h"
#include "simpleconfig.h"
#include "static_map.h"
#include "server_plugin.h"
#include "history.h"
#define NAME "multicast"
#define MCAST_VERSION "1.2"
#define MCAST_MAGIC 0xabb911a3
#define VALIDATE(info) \
do {\
if (!info || info->magic != MCAST_MAGIC)\
return -EINVAL;\
} while(0)
typedef struct _mcast_options {
char *addr;
char *key_file;
int ifindex;
int family;
unsigned int port;
unsigned int hash;
unsigned int auth;
unsigned int flags;
} mcast_options;
typedef struct _mcast_info {
uint64_t magic;
void *priv;
map_object_t *map;
history_info_t *history;
char key[MAX_KEY_LEN];
mcast_options args;
const fence_callbacks_t *cb;
ssize_t key_len;
int mc_sock;
int need_kill;
} mcast_info;
struct mcast_hostlist_arg {
map_object_t *map;
const char *src;
int fd;
};
/*
* See if we fenced this node recently (successfully)
* If so, ignore the request for a few seconds.
*
* We purge our history when the entries time out.
*/
static int
check_history(void *a, void *b) {
fence_req_t *old = a, *current = b;
if (old->request == current->request &&
old->seqno == current->seqno &&
!strcasecmp((const char *)old->domain,
(const char *)current->domain)) {
return 1;
}
return 0;
}
static int
connect_tcp(fence_req_t *req, fence_auth_type_t auth,
void *key, size_t key_len)
{
int fd = -1;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
char buf[128];
switch(req->family) {
case PF_INET:
memset(&sin, 0, sizeof(sin));
memcpy(&sin.sin_addr, req->address,
sizeof(sin.sin_addr));
sin.sin_family = PF_INET;
fd = ipv4_connect(&sin.sin_addr, req->port,
5);
if (fd < 0) {
printf("Failed to call back\n");
return -1;
}
break;
case PF_INET6:
memset(&sin6, 0, sizeof(sin6));
memcpy(&sin6.sin6_addr, req->address,
sizeof(sin6.sin6_addr));
sin.sin_family = PF_INET6;
fd = ipv6_connect(&sin6.sin6_addr, req->port,
5);
memset(buf,0,sizeof(buf));
inet_ntop(PF_INET6, &sin6.sin6_addr, buf, sizeof(buf));
if (fd < 0) {
printf("Failed to call back %s\n", buf);
return -1;
}
break;
default:
printf("Family = %d\n", req->family);
return -1;
}
/* Noops if auth == AUTH_NONE */
if (sock_response(fd, auth, key, key_len, 10) <= 0) {
printf("Failed to respond to challenge\n");
close(fd);
return -1;
}
if (sock_challenge(fd, auth, key, key_len, 10) <= 0) {
printf("Remote failed challenge\n");
close(fd);
return -1;
}
return fd;
}
static int
mcast_hostlist(const char *vm_name, const char *vm_uuid,
int state, void *priv)
{
struct mcast_hostlist_arg *arg = (struct mcast_hostlist_arg *)priv;
host_state_t hinfo;
struct timeval tv;
int ret;
if (map_check(arg->map, arg->src, vm_uuid) == 0) {
/* if we don't have access to fence this VM,
* we should not see it in a hostlist either */
return 0;
}
strncpy((char *)hinfo.domain, vm_name, sizeof(hinfo.domain) - 1);
strncpy((char *)hinfo.uuid, vm_uuid, sizeof(hinfo.uuid) - 1);
hinfo.state = state;
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = _write_retry(arg->fd, &hinfo, sizeof(hinfo), &tv);
if (ret == sizeof(hinfo))
return 0;
return 1;
}
static int
mcast_hostlist_begin(int fd)
{
struct timeval tv;
char val = (char)RESP_HOSTLIST;
tv.tv_sec = 1;
tv.tv_usec = 0;
return _write_retry(fd, &val, 1, &tv);
}
static int
mcast_hostlist_end(int fd)
{
host_state_t hinfo;
struct timeval tv;
int ret;
printf("Sending terminator packet\n");
memset(&hinfo, 0, sizeof(hinfo));
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = _write_retry(fd, &hinfo, sizeof(hinfo), &tv);
if (ret == sizeof(hinfo))
return 0;
return 1;
}
static int
do_fence_request_tcp(fence_req_t *req, mcast_info *info)
{
char ip_addr_src[1024];
int fd = -1;
char response = 1;
struct mcast_hostlist_arg arg;
fd = connect_tcp(req, info->args.auth, info->key, info->key_len);
if (fd < 0) {
dbg_printf(2, "Could not send reply to fence request: %s\n",
strerror(errno));
goto out;
}
inet_ntop(req->family, req->address,
ip_addr_src, sizeof(ip_addr_src));
dbg_printf(2, "Request %d seqno %d src %s target %s\n",
req->request, req->seqno, ip_addr_src, req->domain);
switch(req->request) {
case FENCE_NULL:
response = info->cb->null((char *)req->domain, info->priv);
break;
case FENCE_ON:
if (map_check(info->map, ip_addr_src,
(const char *)req->domain) == 0) {
response = RESP_PERM;
break;
}
response = info->cb->on((char *)req->domain, ip_addr_src,
req->seqno, info->priv);
break;
case FENCE_OFF:
if (map_check(info->map, ip_addr_src,
(const char *)req->domain) == 0) {
response = RESP_PERM;
break;
}
response = info->cb->off((char *)req->domain, ip_addr_src,
req->seqno, info->priv);
break;
case FENCE_REBOOT:
if (map_check(info->map, ip_addr_src,
(const char *)req->domain) == 0) {
response = RESP_PERM;
break;
}
response = info->cb->reboot((char *)req->domain, ip_addr_src,
req->seqno, info->priv);
break;
case FENCE_STATUS:
if (map_check(info->map, ip_addr_src,
(const char *)req->domain) == 0) {
response = RESP_PERM;
break;
}
response = info->cb->status((char *)req->domain, info->priv);
break;
case FENCE_DEVSTATUS:
response = info->cb->devstatus(info->priv);
break;
case FENCE_HOSTLIST:
arg.map = info->map;
arg.src = ip_addr_src;
arg.fd = fd;
mcast_hostlist_begin(arg.fd);
response = info->cb->hostlist(mcast_hostlist, &arg,
info->priv);
mcast_hostlist_end(arg.fd);
break;
}
dbg_printf(3, "Sending response to caller...\n");
if (_write_retry(fd, &response, 1, NULL) < 0) {
perror("write");
}
/* XVM shotguns multicast packets, so we want to avoid
* acting on the same request multiple times if the first
* attempt was successful.
*/
history_record(info->history, req);
out:
if (fd != -1)
close(fd);
return 1;
}
static int
mcast_dispatch(listener_context_t c, struct timeval *timeout)
{
mcast_info *info;
fence_req_t data;
fd_set rfds;
struct sockaddr_in sin;
int len;
int n;
socklen_t slen;
info = (mcast_info *)c;
VALIDATE(info);
FD_ZERO(&rfds);
FD_SET(info->mc_sock, &rfds);
n = select((info->mc_sock)+1, &rfds, NULL, NULL, timeout);
if (n <= 0) {
if (errno == EINTR || errno == EAGAIN)
n = 0;
else
dbg_printf(2, "select: %s\n", strerror(errno));
return n;
}
slen = sizeof(sin);
len = recvfrom(info->mc_sock, &data, sizeof(data), 0,
(struct sockaddr *)&sin, &slen);
if (len <= 0) {
perror("recvfrom");
return len;
}
swab_fence_req_t(&data);
if (!verify_request(&data, info->args.hash, info->key,
info->key_len)) {
printf("Key mismatch; dropping packet\n");
return 0;
}
printf("Request %d seqno %d domain %s\n", data.request, data.seqno,
data.domain);
if (history_check(info->history, &data) == 1) {
printf("We just did this request; dropping packet\n");
return 0;
}
switch(info->args.auth) {
case AUTH_NONE:
case AUTH_SHA1:
case AUTH_SHA256:
case AUTH_SHA512:
printf("Plain TCP request\n");
do_fence_request_tcp(&data, info);
break;
default:
printf("XXX Unhandled authentication\n");
}
return 0;
}
static int
mcast_config(config_object_t *config, mcast_options *args)
{
char value[1024];
int errors = 0;
-#ifdef _MODULE
if (sc_get(config, "fence_virtd/@debug", value, sizeof(value))==0)
dset(atoi(value));
-#endif
if (sc_get(config, "listeners/multicast/@key_file",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for key_file\n", value);
args->key_file = strdup(value);
} else {
args->key_file = strdup(DEFAULT_KEY_FILE);
if (!args->key_file) {
dbg_printf(1, "Failed to allocate memory\n");
return -1;
}
}
args->hash = DEFAULT_HASH;
if (sc_get(config, "listeners/multicast/@hash",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for hash\n", value);
if (!strcasecmp(value, "none")) {
args->hash = HASH_NONE;
} else if (!strcasecmp(value, "sha1")) {
args->hash = HASH_SHA1;
} else if (!strcasecmp(value, "sha256")) {
args->hash = HASH_SHA256;
} else if (!strcasecmp(value, "sha512")) {
args->hash = HASH_SHA512;
} else {
dbg_printf(1, "Unsupported hash: %s\n", value);
++errors;
}
}
args->auth = DEFAULT_AUTH;
if (sc_get(config, "listeners/multicast/@auth",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for auth\n", value);
if (!strcasecmp(value, "none")) {
args->auth = AUTH_NONE;
} else if (!strcasecmp(value, "sha1")) {
args->auth = AUTH_SHA1;
} else if (!strcasecmp(value, "sha256")) {
args->auth = AUTH_SHA256;
} else if (!strcasecmp(value, "sha512")) {
args->auth = AUTH_SHA512;
} else {
dbg_printf(1, "Unsupported auth: %s\n", value);
++errors;
}
}
args->family = PF_INET;
if (sc_get(config, "listeners/multicast/@family",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for family\n", value);
if (!strcasecmp(value, "ipv4")) {
args->family = PF_INET;
} else if (!strcasecmp(value, "ipv6")) {
args->family = PF_INET6;
} else {
dbg_printf(1, "Unsupported family: %s\n", value);
++errors;
}
}
if (sc_get(config, "listeners/multicast/@address",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for address\n", value);
args->addr = strdup(value);
} else {
if (args->family == PF_INET) {
args->addr = strdup(IPV4_MCAST_DEFAULT);
} else {
args->addr = strdup(IPV6_MCAST_DEFAULT);
}
}
if (!args->addr) {
return -1;
}
args->port = DEFAULT_MCAST_PORT;
if (sc_get(config, "listeners/multicast/@port",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for port\n", value);
args->port = atoi(value);
if (args->port <= 0) {
dbg_printf(1, "Invalid port: %s\n", value);
++errors;
}
}
args->ifindex = 0;
if (sc_get(config, "listeners/multicast/@interface",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for interface\n", value);
args->ifindex = if_nametoindex(value);
if (args->ifindex < 0) {
dbg_printf(1, "Invalid interface: %s\n", value);
++errors;
}
}
return errors;
}
static int
mcast_init(listener_context_t *c, const fence_callbacks_t *cb,
config_object_t *config, map_object_t *map, void *priv)
{
mcast_info *info;
int mc_sock, ret;
/* Initialize NSS; required to do hashing, as silly as that
sounds... */
if (NSS_NoDB_Init(NULL) != SECSuccess) {
printf("Could not initialize NSS\n");
return 1;
}
info = malloc(sizeof(*info));
if (!info)
return -1;
memset(info, 0, sizeof(*info));
info->priv = priv;
info->cb = cb;
info->map = map;
ret = mcast_config(config, &info->args);
if (ret < 0) {
perror("mcast_config");
free(info);
return -1;
} else if (ret > 0) {
printf("%d errors found during configuration\n",ret);
free(info);
return -1;
}
if (info->args.auth != AUTH_NONE || info->args.hash != HASH_NONE) {
info->key_len = read_key_file(info->args.key_file,
info->key, sizeof(info->key));
if (info->key_len < 0) {
printf("Could not read %s; operating without "
"authentication\n", info->args.key_file);
info->args.auth = AUTH_NONE;
info->args.hash = HASH_NONE;
info->key_len = 0;
}
}
if (info->args.family == PF_INET)
mc_sock = ipv4_recv_sk(info->args.addr,
info->args.port,
info->args.ifindex);
else
mc_sock = ipv6_recv_sk(info->args.addr,
info->args.port,
info->args.ifindex);
if (mc_sock < 0) {
printf("Could not set up multicast listen socket\n");
free(info);
return -1;
}
info->magic = MCAST_MAGIC;
info->mc_sock = mc_sock;
info->history = history_init(check_history, 10, sizeof(fence_req_t));
*c = (listener_context_t)info;
return 0;
}
static int
mcast_shutdown(listener_context_t c)
{
mcast_info *info = (mcast_info *)c;
VALIDATE(info);
info->magic = 0;
history_wipe(info->history);
free(info->history);
free(info->args.key_file);
free(info->args.addr);
close(info->mc_sock);
free(info);
return 0;
}
static listener_plugin_t mcast_plugin = {
.name = NAME,
.version = MCAST_VERSION,
.init = mcast_init,
.dispatch = mcast_dispatch,
.cleanup = mcast_shutdown,
};
-
-#ifdef _MODULE
double
LISTENER_VER_SYM(void)
{
return PLUGIN_VERSION_LISTENER;
}
const listener_plugin_t *
LISTENER_INFO_SYM(void)
{
return &mcast_plugin;
}
-#else
-static void __attribute__((constructor))
-mcast_register_plugin(void)
-{
- plugin_reg_listener(&mcast_plugin);
-}
-#endif
-
diff --git a/agents/virt/server/serial.c b/agents/virt/server/serial.c
index f218bea3..0aa73859 100644
--- a/agents/virt/server/serial.c
+++ b/agents/virt/server/serial.c
@@ -1,471 +1,459 @@
/*
Copyright Red Hat, Inc. 2010
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 "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <nss.h>
#include <libgen.h>
/* Local includes */
#include "debug.h"
#include "fdops.h"
#include "serial.h"
#include "list.h"
#include "simpleconfig.h"
#include "static_map.h"
#include "server_plugin.h"
#include "history.h"
#include "xvm.h"
#define NAME "serial"
#define SERIAL_VERSION "0.4"
#define SERIAL_PLUG_MAGIC 0x1227a000
#define VALIDATE(info) \
do {\
if (!info || info->magic != SERIAL_PLUG_MAGIC)\
return -EINVAL;\
} while(0)
typedef struct _serial_info {
uint64_t magic;
const fence_callbacks_t *cb;
void *priv;
char *uri;
char *path;
history_info_t *history;
map_object_t *maps;
int mode;
int wake_fd;
} serial_info;
struct serial_hostlist_arg {
map_object_t *map;
const char *src;
int fd;
};
/*
* See if we fenced this node recently (successfully)
* If so, ignore the request for a few seconds.
*
* We purge our history when the entries time out.
*/
static int
check_history(void *a, void *b) {
serial_req_t *old = a, *current = b;
if (old->request == current->request &&
old->seqno == current->seqno &&
!strcasecmp((const char *)old->domain,
(const char *)current->domain)) {
return 1;
}
return 0;
}
static int
serial_hostlist(const char *vm_name, const char *vm_uuid,
int state, void *priv)
{
struct serial_hostlist_arg *arg = (struct serial_hostlist_arg *)priv;
host_state_t hinfo;
struct timeval tv;
int ret;
if (map_check(arg->map, arg->src, vm_uuid) == 0) {
/* if we don't have access to fence this VM,
* we should not see it in a hostlist either */
return 0;
}
strncpy((char *)hinfo.domain, vm_name, sizeof(hinfo.domain) - 1);
strncpy((char *)hinfo.uuid, vm_uuid, sizeof(hinfo.uuid) - 1);
hinfo.state = state;
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = _write_retry(arg->fd, &hinfo, sizeof(hinfo), &tv);
if (ret == sizeof(hinfo))
return 0;
return 1;
}
static int
serial_hostlist_begin(int fd)
{
struct timeval tv;
serial_resp_t resp;
resp.magic = SERIAL_MAGIC;
resp.response = RESP_HOSTLIST;
tv.tv_sec = 1;
tv.tv_usec = 0;
return _write_retry(fd, &resp, sizeof(resp), &tv);
}
static int
serial_hostlist_end(int fd)
{
host_state_t hinfo;
struct timeval tv;
int ret;
//printf("Sending terminator packet\n");
memset(&hinfo, 0, sizeof(hinfo));
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = _write_retry(fd, &hinfo, sizeof(hinfo), &tv);
if (ret == sizeof(hinfo))
return 0;
return 1;
}
static int
do_fence_request(int fd, const char *src, serial_req_t *req, serial_info *info)
{
char response = RESP_FAIL;
struct serial_hostlist_arg arg;
serial_resp_t resp;
arg.fd = fd;
switch(req->request) {
case FENCE_NULL:
response = info->cb->null((char *)req->domain, info->priv);
break;
case FENCE_ON:
if (map_check(info->maps, src,
(const char *)req->domain) == 0) {
response = RESP_PERM;
break;
}
response = info->cb->on((char *)req->domain, src,
req->seqno, info->priv);
break;
case FENCE_OFF:
if (map_check(info->maps, src,
(const char *)req->domain) == 0) {
response = RESP_PERM;
break;
}
response = info->cb->off((char *)req->domain, src,
req->seqno, info->priv);
break;
case FENCE_REBOOT:
if (map_check(info->maps, src,
(const char *)req->domain) == 0) {
response = RESP_PERM;
break;
}
response = info->cb->reboot((char *)req->domain, src,
req->seqno, info->priv);
break;
case FENCE_STATUS:
if (map_check(info->maps, src,
(const char *)req->domain) == 0) {
response = RESP_PERM;
break;
}
response = info->cb->status((char *)req->domain, info->priv);
break;
case FENCE_DEVSTATUS:
response = info->cb->devstatus(info->priv);
break;
case FENCE_HOSTLIST:
arg.map = info->maps;
arg.src = src;
arg.fd = fd;
serial_hostlist_begin(arg.fd);
response = info->cb->hostlist(serial_hostlist, &arg,
info->priv);
serial_hostlist_end(arg.fd);
break;
}
resp.magic = SERIAL_MAGIC;
resp.response = response;
swab_serial_resp_t(&resp);
dbg_printf(3, "Sending response to caller...\n");
if (_write_retry(fd, &resp, sizeof(resp), NULL) < 0)
perror("write");
/* XVM shotguns multicast packets, so we want to avoid
* acting on the same request multiple times if the first
* attempt was successful.
*/
history_record(info->history, req);
return 1;
}
static int
serial_dispatch(listener_context_t c, struct timeval *timeout)
{
char src_domain[MAX_DOMAINNAME_LENGTH];
serial_info *info;
serial_req_t data;
fd_set rfds;
struct timeval tv;
int max;
int n, x, ret;
info = (serial_info *)c;
VALIDATE(info);
FD_ZERO(&rfds);
domain_sock_fdset(&rfds, &max);
FD_SET(info->wake_fd, &rfds);
if (info->wake_fd > max)
max = info->wake_fd;
n = select(max+1, &rfds, NULL, NULL, timeout);
if (n <= 0) {
if (errno == EINTR || errno == EAGAIN)
n = 0;
else
dbg_printf(2, "select: %s\n", strerror(errno));
return n;
}
/*
* See if the goal was just to be woken up in order to refill our
* file descriptor set. For example, if multiple domains were
* created simultaneously, we would have to refill our fd_set
*/
if (FD_ISSET(info->wake_fd, &rfds)) {
tv.tv_sec = 0;
tv.tv_usec = 10000;
_read_retry(info->wake_fd, &c, 1, &tv);
return 0;
}
/*
* If no requests, we're done
*/
if (n == 0)
return 0;
/* find & read request */
for (x = 0; x <= max; x++) {
if (FD_ISSET(x, &rfds)) {
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = _read_retry(x, &data, sizeof(data), &tv);
if (ret != sizeof(data)) {
if (--n > 0)
continue;
else
return 0;
} else {
swab_serial_req_t(&data);
break;
}
}
}
src_domain[0] = 0;
domain_sock_name(x, src_domain, sizeof(src_domain));
dbg_printf(2, "Sock %d Request %d seqno %d src %s target %s\n", x,
data.request, data.seqno, src_domain, data.domain);
if (history_check(info->history, &data) == 1) {
dbg_printf(3, "We just did this request; dropping packet\n");
return 0;
}
do_fence_request(x, src_domain[0] == 0 ? NULL : src_domain,
&data, info);
return 0;
}
static int
serial_config(config_object_t *config, serial_info *args)
{
char value[1024];
int errors = 0;
-#ifdef _MODULE
if (sc_get(config, "fence_virtd/@debug", value, sizeof(value))==0)
dset(atoi(value));
-#endif
if (sc_get(config, "listeners/serial/@uri",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for uri\n", value);
args->uri = strdup(value);
}
if (sc_get(config, "listeners/serial/@path",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for uri\n", value);
args->path = strdup(value);
}
if (sc_get(config, "listeners/serial/@mode",
value, sizeof(value)-1) == 0) {
if (!strcasecmp(value, "vmchannel")) {
args->mode = 1;
} else if (!strcasecmp(value, "serial")) {
args->mode = 0;
} else {
args->mode = atoi(value);
if (args->mode < 0)
args->mode = 0;
}
dbg_printf(1, "Got %s for mode\n",
args->mode?"VMChannel":"serial");
}
return errors;
}
static int
serial_init(listener_context_t *c, const fence_callbacks_t *cb,
config_object_t *config, map_object_t *map, void *priv)
{
serial_info *info;
int ret;
info = malloc(sizeof(*info));
if (!info)
return -1;
memset(info, 0, sizeof(*info));
info->priv = priv;
info->cb = cb;
ret = serial_config(config, info);
if (ret < 0) {
perror("serial_config");
return -1;
} else if (ret > 0) {
printf("%d errors found during configuration\n",ret);
return -1;
}
info->maps = map;
info->magic = SERIAL_PLUG_MAGIC;
info->history = history_init(check_history, 10, sizeof(fence_req_t));
*c = (listener_context_t)info;
start_event_listener(info->uri, info->path, info->mode, &info->wake_fd);
sleep(1);
return 0;
}
static int
serial_shutdown(listener_context_t c)
{
serial_info *info = (serial_info *)c;
dbg_printf(3, "Shutting down serial\n");
VALIDATE(info);
info->magic = 0;
stop_event_listener();
domain_sock_cleanup();
history_wipe(info->history);
free(info->history);
free(info->uri);
free(info->path);
free(info);
return 0;
}
static listener_plugin_t serial_plugin = {
.name = NAME,
.version = SERIAL_VERSION,
.init = serial_init,
.dispatch = serial_dispatch,
.cleanup = serial_shutdown,
};
-
-#ifdef _MODULE
double
LISTENER_VER_SYM(void)
{
return PLUGIN_VERSION_LISTENER;
}
const listener_plugin_t *
LISTENER_INFO_SYM(void)
{
return &serial_plugin;
}
-#else
-static void __attribute__((constructor))
-serial_register_plugin(void)
-{
- plugin_reg_listener(&serial_plugin);
-}
-#endif
-
diff --git a/agents/virt/server/tcp.c b/agents/virt/server/tcp.c
index 1ffb5a56..d39f3579 100644
--- a/agents/virt/server/tcp.c
+++ b/agents/virt/server/tcp.c
@@ -1,563 +1,552 @@
/*
Copyright Red Hat, Inc. 2006-2012
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.
*/
#include "config.h"
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <nss.h>
/* Local includes */
#include "xvm.h"
#include "simple_auth.h"
#include "options.h"
#include "mcast.h"
#include "tcp.h"
#include "tcp_listener.h"
#include "debug.h"
#include "fdops.h"
#include "list.h"
#include "simpleconfig.h"
#include "static_map.h"
#include "server_plugin.h"
#include "history.h"
#define NAME "tcp"
#define TCP_VERSION "0.1"
#define TCP_MAGIC 0xc3dff7a9
#define VALIDATE(info) \
do {\
if (!info || info->magic != TCP_MAGIC)\
return -EINVAL;\
} while(0)
typedef struct _tcp_options {
char *key_file;
char *addr;
int family;
unsigned int port;
unsigned int hash;
unsigned int auth;
unsigned int flags;
} tcp_options;
typedef struct _tcp_info {
uint64_t magic;
void *priv;
map_object_t *map;
history_info_t *history;
char key[MAX_KEY_LEN];
tcp_options args;
const fence_callbacks_t *cb;
ssize_t key_len;
int listen_sock;
} tcp_info;
struct tcp_hostlist_arg {
map_object_t *map;
const char *src;
int fd;
};
/*
* See if we fenced this node recently (successfully)
* If so, ignore the request for a few seconds.
*
* We purge our history when the entries time out.
*/
static int
check_history(void *a, void *b) {
fence_req_t *old = a, *current = b;
if (old->request == current->request &&
old->seqno == current->seqno &&
!strcasecmp((const char *)old->domain,
(const char *)current->domain)) {
return 1;
}
return 0;
}
static int
tcp_hostlist(const char *vm_name, const char *vm_uuid,
int state, void *priv)
{
struct tcp_hostlist_arg *arg = (struct tcp_hostlist_arg *)priv;
host_state_t hinfo;
struct timeval tv;
int ret;
if (map_check(arg->map, arg->src, vm_uuid) == 0) {
/* if we don't have access to fence this VM,
* we should not see it in a hostlist either */
return 0;
}
strncpy((char *)hinfo.domain, vm_name, sizeof(hinfo.domain) - 1);
strncpy((char *)hinfo.uuid, vm_uuid, sizeof(hinfo.uuid) - 1);
hinfo.state = state;
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = _write_retry(arg->fd, &hinfo, sizeof(hinfo), &tv);
if (ret == sizeof(hinfo))
return 0;
return 1;
}
static int
tcp_hostlist_begin(int fd)
{
struct timeval tv;
char val = (char)RESP_HOSTLIST;
tv.tv_sec = 1;
tv.tv_usec = 0;
return _write_retry(fd, &val, 1, &tv);
}
static int
tcp_hostlist_end(int fd)
{
host_state_t hinfo;
struct timeval tv;
int ret;
printf("Sending terminator packet\n");
memset(&hinfo, 0, sizeof(hinfo));
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = _write_retry(fd, &hinfo, sizeof(hinfo), &tv);
if (ret == sizeof(hinfo))
return 0;
return 1;
}
static int
do_fence_request_tcp(int fd, fence_req_t *req, tcp_info *info)
{
char ip_addr_src[1024];
char response = 1;
struct tcp_hostlist_arg arg;
int ret;
/* Noops if auth == AUTH_NONE */
if (sock_response(fd, info->args.auth, info->key, info->key_len, 10) <= 0) {
printf("Failed to respond to challenge\n");
close(fd);
return -1;
}
ret = sock_challenge(fd, info->args.auth, info->key, info->key_len, 10);
if (ret <= 0) {
printf("Remote failed challenge\n");
close(fd);
return -1;
}
dbg_printf(2, "Request %d seqno %d target %s\n",
req->request, req->seqno, req->domain);
switch(req->request) {
case FENCE_NULL:
response = info->cb->null((char *)req->domain, info->priv);
break;
case FENCE_ON:
if (map_check(info->map, ip_addr_src,
(const char *)req->domain) == 0) {
response = RESP_PERM;
break;
}
response = info->cb->on((char *)req->domain, ip_addr_src,
req->seqno, info->priv);
break;
case FENCE_OFF:
if (map_check(info->map, ip_addr_src,
(const char *)req->domain) == 0) {
response = RESP_PERM;
break;
}
response = info->cb->off((char *)req->domain, ip_addr_src,
req->seqno, info->priv);
break;
case FENCE_REBOOT:
if (map_check(info->map, ip_addr_src,
(const char *)req->domain) == 0) {
response = RESP_PERM;
break;
}
response = info->cb->reboot((char *)req->domain, ip_addr_src,
req->seqno, info->priv);
break;
case FENCE_STATUS:
if (map_check(info->map, ip_addr_src,
(const char *)req->domain) == 0) {
response = RESP_PERM;
break;
}
response = info->cb->status((char *)req->domain, info->priv);
break;
case FENCE_DEVSTATUS:
response = info->cb->devstatus(info->priv);
break;
case FENCE_HOSTLIST:
arg.map = info->map;
arg.src = ip_addr_src;
arg.fd = fd;
tcp_hostlist_begin(arg.fd);
response = info->cb->hostlist(tcp_hostlist, &arg,
info->priv);
tcp_hostlist_end(arg.fd);
break;
}
dbg_printf(3, "Sending response to caller...\n");
if (_write_retry(fd, &response, 1, NULL) < 0) {
perror("write");
}
history_record(info->history, req);
if (fd != -1)
close(fd);
return 1;
}
static int
tcp_dispatch(listener_context_t c, struct timeval *timeout)
{
tcp_info *info;
fence_req_t data;
fd_set rfds;
int n;
int client_fd;
int ret;
struct timeval tv;
if (timeout != NULL)
memcpy(&tv, timeout, sizeof(tv));
else {
tv.tv_sec = 1;
tv.tv_usec = 0;
}
info = (tcp_info *)c;
VALIDATE(info);
FD_ZERO(&rfds);
FD_SET(info->listen_sock, &rfds);
n = select(info->listen_sock + 1, &rfds, NULL, NULL, timeout);
if (n <= 0) {
if (errno == EINTR || errno == EAGAIN)
n = 0;
else
dbg_printf(2, "select: %s\n", strerror(errno));
return n;
}
client_fd = accept(info->listen_sock, NULL, NULL);
if (client_fd < 0) {
perror("accept");
return -1;
}
dbg_printf(3, "Accepted client...\n");
ret = _read_retry(client_fd, &data, sizeof(data), &tv);
if (ret != sizeof(data)) {
dbg_printf(3, "Invalid request (read %d bytes)\n", ret);
close(client_fd);
return 0;
}
swab_fence_req_t(&data);
if (!verify_request(&data, info->args.hash, info->key,
info->key_len)) {
printf("Key mismatch; dropping client\n");
close(client_fd);
return 0;
}
dbg_printf(3, "Request %d seqno %d domain %s\n",
data.request, data.seqno, data.domain);
if (history_check(info->history, &data) == 1) {
printf("We just did this request; dropping client\n");
close(client_fd);
return 0;
}
switch(info->args.auth) {
case AUTH_NONE:
case AUTH_SHA1:
case AUTH_SHA256:
case AUTH_SHA512:
printf("Plain TCP request\n");
do_fence_request_tcp(client_fd, &data, info);
break;
default:
printf("XXX Unhandled authentication\n");
}
return 0;
}
static int
tcp_config(config_object_t *config, tcp_options *args)
{
char value[1024];
int errors = 0;
-#ifdef _MODULE
if (sc_get(config, "fence_virtd/@debug", value, sizeof(value))==0)
dset(atoi(value));
-#endif
if (sc_get(config, "listeners/tcp/@key_file",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for key_file\n", value);
args->key_file = strdup(value);
} else {
args->key_file = strdup(DEFAULT_KEY_FILE);
if (!args->key_file) {
dbg_printf(1, "Failed to allocate memory\n");
return -1;
}
}
args->hash = DEFAULT_HASH;
if (sc_get(config, "listeners/tcp/@hash",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for hash\n", value);
if (!strcasecmp(value, "none")) {
args->hash = HASH_NONE;
} else if (!strcasecmp(value, "sha1")) {
args->hash = HASH_SHA1;
} else if (!strcasecmp(value, "sha256")) {
args->hash = HASH_SHA256;
} else if (!strcasecmp(value, "sha512")) {
args->hash = HASH_SHA512;
} else {
dbg_printf(1, "Unsupported hash: %s\n", value);
++errors;
}
}
args->auth = DEFAULT_AUTH;
if (sc_get(config, "listeners/tcp/@auth",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for auth\n", value);
if (!strcasecmp(value, "none")) {
args->hash = AUTH_NONE;
} else if (!strcasecmp(value, "sha1")) {
args->hash = AUTH_SHA1;
} else if (!strcasecmp(value, "sha256")) {
args->hash = AUTH_SHA256;
} else if (!strcasecmp(value, "sha512")) {
args->hash = AUTH_SHA512;
} else {
dbg_printf(1, "Unsupported auth: %s\n", value);
++errors;
}
}
args->family = PF_INET;
if (sc_get(config, "listeners/tcp/@family",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for family\n", value);
if (!strcasecmp(value, "ipv4")) {
args->family = PF_INET;
} else if (!strcasecmp(value, "ipv6")) {
args->family = PF_INET6;
} else {
dbg_printf(1, "Unsupported family: %s\n", value);
++errors;
}
}
if (sc_get(config, "listeners/tcp/@address",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for address\n", value);
args->addr = strdup(value);
} else {
if (args->family == PF_INET) {
args->addr = strdup(IPV4_TCP_ADDR_DEFAULT);
} else {
args->addr = strdup(IPV6_TCP_ADDR_DEFAULT);
}
}
if (!args->addr) {
return -1;
}
args->port = DEFAULT_MCAST_PORT;
if (sc_get(config, "listeners/tcp/@port",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for port\n", value);
args->port = atoi(value);
if (args->port <= 0) {
dbg_printf(1, "Invalid port: %s\n", value);
++errors;
}
}
return errors;
}
static int
tcp_init(listener_context_t *c, const fence_callbacks_t *cb,
config_object_t *config, map_object_t *map, void *priv)
{
tcp_info *info;
int listen_sock, ret;
/* Initialize NSS; required to do hashing, as silly as that
sounds... */
if (NSS_NoDB_Init(NULL) != SECSuccess) {
printf("Could not initialize NSS\n");
return 1;
}
info = calloc(1, sizeof(*info));
if (!info)
return -1;
info->priv = priv;
info->cb = cb;
info->map = map;
ret = tcp_config(config, &info->args);
if (ret < 0)
perror("tcp_config");
else if (ret > 0)
printf("%d errors found during configuration\n",ret);
if (ret != 0) {
if (info->args.key_file)
free(info->args.key_file);
if (info->args.addr)
free(info->args.addr);
free(info);
return -1;
}
if (info->args.auth != AUTH_NONE || info->args.hash != HASH_NONE) {
info->key_len = read_key_file(info->args.key_file,
info->key, sizeof(info->key));
if (info->key_len < 0) {
printf("Could not read %s; operating without "
"authentication\n", info->args.key_file);
info->args.auth = AUTH_NONE;
info->args.hash = HASH_NONE;
info->key_len = 0;
}
}
if (info->args.family == PF_INET) {
listen_sock = ipv4_listen(info->args.addr, info->args.port, 10);
} else {
listen_sock = ipv6_listen(info->args.addr, info->args.port, 10);
}
if (listen_sock < 0) {
printf("Could not set up listen socket\n");
if (info->args.key_file)
free(info->args.key_file);
if (info->args.addr)
free(info->args.addr);
free(info);
return -1;
}
info->magic = TCP_MAGIC;
info->listen_sock = listen_sock;
info->history = history_init(check_history, 10, sizeof(fence_req_t));
*c = (listener_context_t)info;
return 0;
}
static int
tcp_shutdown(listener_context_t c)
{
tcp_info *info = (tcp_info *)c;
VALIDATE(info);
info->magic = 0;
history_wipe(info->history);
free(info->history);
free(info->args.key_file);
free(info->args.addr);
close(info->listen_sock);
free(info);
return 0;
}
static listener_plugin_t tcp_plugin = {
.name = NAME,
.version = TCP_VERSION,
.init = tcp_init,
.dispatch = tcp_dispatch,
.cleanup = tcp_shutdown,
};
-
-#ifdef _MODULE
double
LISTENER_VER_SYM(void)
{
return PLUGIN_VERSION_LISTENER;
}
const listener_plugin_t *
LISTENER_INFO_SYM(void)
{
return &tcp_plugin;
}
-#else
-static void __attribute__((constructor))
-tcp_register_plugin(void)
-{
- plugin_reg_listener(&tcp_plugin);
-}
-#endif
diff --git a/agents/virt/server/vsock.c b/agents/virt/server/vsock.c
index 93f5880f..3ea26fb9 100644
--- a/agents/virt/server/vsock.c
+++ b/agents/virt/server/vsock.c
@@ -1,576 +1,565 @@
/*
Copyright Red Hat, Inc. 2017
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.
*/
#include "config.h"
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <nss.h>
#include <sys/socket.h>
#include <linux/vm_sockets.h>
/* Local includes */
#include "list.h"
#include "simpleconfig.h"
#include "static_map.h"
#include "server_plugin.h"
#include "history.h"
#include "xvm.h"
#include "simple_auth.h"
#include "options.h"
#include "mcast.h"
#include "tcp.h"
#include "tcp_listener.h"
#include "debug.h"
#include "fdops.h"
#define NAME "vsock"
#define VSOCK_VERSION "0.1"
#define VSOCK_MAGIC 0xa32d27c1e
#define VALIDATE(info) \
do {\
if (!info || info->magic != VSOCK_MAGIC)\
return -EINVAL;\
} while(0)
typedef struct _vsock_options {
char *key_file;
int cid;
unsigned int port;
unsigned int hash;
unsigned int auth;
unsigned int flags;
} vsock_options;
typedef struct _vsock_info {
uint64_t magic;
void *priv;
map_object_t *map;
history_info_t *history;
char key[MAX_KEY_LEN];
vsock_options args;
const fence_callbacks_t *cb;
ssize_t key_len;
int listen_sock;
} vsock_info;
struct vsock_hostlist_arg {
map_object_t *map;
int cid;
int fd;
};
static int get_peer_cid(int fd, uint32_t *peer_cid) {
struct sockaddr_vm svm;
socklen_t len;
int ret;
if (!peer_cid)
return -1;
len = sizeof(svm);
ret = getpeername(fd, (struct sockaddr *) &svm, &len);
if (ret < 0) {
printf("Error getting peer CID: %s\n", strerror(errno));
return -1;
}
*peer_cid = svm.svm_cid;
return 0;
}
/*
* See if we fenced this node recently (successfully)
* If so, ignore the request for a few seconds.
*
* We purge our history when the entries time out.
*/
static int
check_history(void *a, void *b) {
fence_req_t *old = a, *current = b;
if (old->request == current->request &&
old->seqno == current->seqno &&
!strcasecmp((const char *)old->domain,
(const char *)current->domain)) {
return 1;
}
return 0;
}
static int
vsock_hostlist(const char *vm_name, const char *vm_uuid,
int state, void *priv)
{
struct vsock_hostlist_arg *arg = (struct vsock_hostlist_arg *) priv;
host_state_t hinfo;
struct timeval tv;
int ret;
uint32_t peer_cid = 0;
char peer_cid_str[24];
ret = get_peer_cid(arg->fd, &peer_cid);
if (ret < 0) {
printf("Unable to get peer CID: %s\n", strerror(errno));
peer_cid_str[0] = '\0';
} else
snprintf(peer_cid_str, sizeof(peer_cid_str), "%u", peer_cid);
/* Noops if auth == AUTH_NONE */
if (map_check(arg->map, peer_cid_str, vm_uuid) == 0) {
/* if we don't have access to fence this VM,
* we should not see it in a hostlist either */
return 0;
}
strncpy((char *)hinfo.domain, vm_name, sizeof(hinfo.domain) - 1);
strncpy((char *)hinfo.uuid, vm_uuid, sizeof(hinfo.uuid) - 1);
hinfo.state = state;
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = _write_retry(arg->fd, &hinfo, sizeof(hinfo), &tv);
if (ret == sizeof(hinfo))
return 0;
return 1;
}
static int
vsock_hostlist_begin(int fd)
{
struct timeval tv;
char val = (char) RESP_HOSTLIST;
tv.tv_sec = 1;
tv.tv_usec = 0;
return _write_retry(fd, &val, 1, &tv);
}
static int
vsock_hostlist_end(int fd)
{
host_state_t hinfo;
struct timeval tv;
int ret;
printf("Sending terminator packet\n");
memset(&hinfo, 0, sizeof(hinfo));
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = _write_retry(fd, &hinfo, sizeof(hinfo), &tv);
if (ret == sizeof(hinfo))
return 0;
return 1;
}
static int
do_fence_request_vsock(int fd, fence_req_t *req, vsock_info *info)
{
char response = 1;
struct vsock_hostlist_arg arg;
uint32_t peer_cid = 0;
char peer_cid_str[24];
int ret;
ret = get_peer_cid(fd, &peer_cid);
if (ret < 0) {
printf("Unable to get peer CID: %s\n", strerror(errno));
return -1;
}
snprintf(peer_cid_str, sizeof(peer_cid_str), "%u", peer_cid);
/* Noops if auth == AUTH_NONE */
if (sock_response(fd, info->args.auth, info->key, info->key_len, 10) <= 0) {
printf("CID %u Failed to respond to challenge\n", peer_cid);
close(fd);
return -1;
}
ret = sock_challenge(fd, info->args.auth, info->key, info->key_len, 10);
if (ret <= 0) {
printf("Remote CID %u failed challenge\n", peer_cid);
close(fd);
return -1;
}
dbg_printf(2, "Request %d seqno %d target %s from CID %u\n",
req->request, req->seqno, req->domain, peer_cid);
switch(req->request) {
case FENCE_NULL:
response = info->cb->null((char *)req->domain, info->priv);
break;
case FENCE_ON:
if (map_check(info->map, peer_cid_str,
(const char *)req->domain) == 0) {
response = RESP_PERM;
break;
}
response = info->cb->on((char *)req->domain, peer_cid_str,
req->seqno, info->priv);
break;
case FENCE_OFF:
if (map_check(info->map, peer_cid_str,
(const char *)req->domain) == 0) {
response = RESP_PERM;
break;
}
response = info->cb->off((char *)req->domain, peer_cid_str,
req->seqno, info->priv);
break;
case FENCE_REBOOT:
if (map_check(info->map, peer_cid_str,
(const char *)req->domain) == 0) {
response = RESP_PERM;
break;
}
response = info->cb->reboot((char *)req->domain, peer_cid_str,
req->seqno, info->priv);
break;
case FENCE_STATUS:
if (map_check(info->map, peer_cid_str,
(const char *)req->domain) == 0) {
response = RESP_PERM;
break;
}
response = info->cb->status((char *)req->domain, info->priv);
break;
case FENCE_DEVSTATUS:
response = info->cb->devstatus(info->priv);
break;
case FENCE_HOSTLIST:
arg.map = info->map;
arg.fd = fd;
vsock_hostlist_begin(arg.fd);
response = info->cb->hostlist(vsock_hostlist, &arg, info->priv);
vsock_hostlist_end(arg.fd);
break;
}
dbg_printf(3, "Sending response to caller CID %u...\n", peer_cid);
if (_write_retry(fd, &response, 1, NULL) < 0)
perror("write");
history_record(info->history, req);
if (fd != -1)
close(fd);
return 1;
}
static int
vsock_dispatch(listener_context_t c, struct timeval *timeout)
{
vsock_info *info;
fence_req_t data;
fd_set rfds;
int n;
int client_fd;
int ret;
struct timeval tv;
if (timeout != NULL)
memcpy(&tv, timeout, sizeof(tv));
else {
tv.tv_sec = 1;
tv.tv_usec = 0;
}
info = (vsock_info *) c;
VALIDATE(info);
FD_ZERO(&rfds);
FD_SET(info->listen_sock, &rfds);
n = select(info->listen_sock + 1, &rfds, NULL, NULL, timeout);
if (n <= 0) {
if (errno == EINTR || errno == EAGAIN)
n = 0;
else
dbg_printf(2, "select: %s\n", strerror(errno));
return n;
}
client_fd = accept(info->listen_sock, NULL, NULL);
if (client_fd < 0) {
perror("accept");
return -1;
}
dbg_printf(3, "Accepted vsock client...\n");
ret = _read_retry(client_fd, &data, sizeof(data), &tv);
if (ret != sizeof(data)) {
dbg_printf(3, "Invalid request (read %d bytes)\n", ret);
close(client_fd);
return 0;
}
swab_fence_req_t(&data);
if (!verify_request(&data, info->args.hash, info->key, info->key_len)) {
printf("Key mismatch; dropping client\n");
close(client_fd);
return 0;
}
dbg_printf(3, "Request %d seqno %d domain %s\n",
data.request, data.seqno, data.domain);
if (history_check(info->history, &data) == 1) {
printf("We just did this request; dropping client\n");
close(client_fd);
return 0;
}
switch(info->args.auth) {
case AUTH_NONE:
case AUTH_SHA1:
case AUTH_SHA256:
case AUTH_SHA512:
printf("VSOCK request\n");
do_fence_request_vsock(client_fd, &data, info);
break;
default:
printf("XXX Unhandled authentication\n");
}
return 0;
}
static int
vsock_config(config_object_t *config, vsock_options *args)
{
char value[1024];
int errors = 0;
-#ifdef _MODULE
if (sc_get(config, "fence_virtd/@debug", value, sizeof(value))==0)
dset(atoi(value));
-#endif
if (sc_get(config, "listeners/vsock/@key_file",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for key_file\n", value);
args->key_file = strdup(value);
} else {
args->key_file = strdup(DEFAULT_KEY_FILE);
if (!args->key_file) {
dbg_printf(1, "Failed to allocate memory\n");
return -1;
}
}
args->hash = DEFAULT_HASH;
if (sc_get(config, "listeners/vsock/@hash",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for hash\n", value);
if (!strcasecmp(value, "none")) {
args->hash = HASH_NONE;
} else if (!strcasecmp(value, "sha1")) {
args->hash = HASH_SHA1;
} else if (!strcasecmp(value, "sha256")) {
args->hash = HASH_SHA256;
} else if (!strcasecmp(value, "sha512")) {
args->hash = HASH_SHA512;
} else {
dbg_printf(1, "Unsupported hash: %s\n", value);
++errors;
}
}
args->auth = DEFAULT_AUTH;
if (sc_get(config, "listeners/vsock/@auth",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for auth\n", value);
if (!strcasecmp(value, "none")) {
args->hash = AUTH_NONE;
} else if (!strcasecmp(value, "sha1")) {
args->hash = AUTH_SHA1;
} else if (!strcasecmp(value, "sha256")) {
args->hash = AUTH_SHA256;
} else if (!strcasecmp(value, "sha512")) {
args->hash = AUTH_SHA512;
} else {
dbg_printf(1, "Unsupported auth: %s\n", value);
++errors;
}
}
args->port = DEFAULT_MCAST_PORT;
if (sc_get(config, "listeners/vsock/@port",
value, sizeof(value)-1) == 0) {
dbg_printf(1, "Got %s for port\n", value);
args->port = atoi(value);
if (args->port <= 0) {
dbg_printf(1, "Invalid port: %s\n", value);
++errors;
}
}
return errors;
}
static int
vsock_init(listener_context_t *c, const fence_callbacks_t *cb,
config_object_t *config, map_object_t *map, void *priv)
{
vsock_info *info;
int listen_sock, ret;
struct sockaddr_vm svm;
if (NSS_NoDB_Init(NULL) != SECSuccess) {
printf("Could not initialize NSS\n");
return 1;
}
info = calloc(1, sizeof(*info));
if (!info)
return -1;
info->priv = priv;
info->cb = cb;
info->map = map;
ret = vsock_config(config, &info->args);
if (ret < 0)
perror("vsock_config");
else if (ret > 0)
printf("%d errors found during vsock listener configuration\n", ret);
if (ret != 0) {
if (info->args.key_file)
free(info->args.key_file);
free(info);
return -1;
}
if (info->args.auth != AUTH_NONE || info->args.hash != HASH_NONE) {
info->key_len = read_key_file(info->args.key_file,
info->key, sizeof(info->key));
if (info->key_len < 0) {
printf("Could not read %s; operating without "
"authentication\n", info->args.key_file);
info->args.auth = AUTH_NONE;
info->args.hash = HASH_NONE;
info->key_len = 0;
}
}
listen_sock = socket(PF_VSOCK, SOCK_STREAM, 0);
if (listen_sock < 0)
goto out_fail;
memset(&svm, 0, sizeof(svm));
svm.svm_family = AF_VSOCK;
svm.svm_cid = VMADDR_CID_ANY;
svm.svm_port = info->args.port;
if (bind(listen_sock, (struct sockaddr *) &svm, sizeof(svm)) < 0)
goto out_fail;
if (listen(listen_sock, 1) < 0)
goto out_fail;
info->magic = VSOCK_MAGIC;
info->listen_sock = listen_sock;
info->history = history_init(check_history, 10, sizeof(fence_req_t));
*c = (listener_context_t)info;
return 0;
out_fail:
printf("Could not set up listen socket: %s\n", strerror(errno));
if (listen_sock >= 0)
close(listen_sock);
if (info->args.key_file)
free(info->args.key_file);
free(info);
return -1;
}
static int
vsock_shutdown(listener_context_t c)
{
vsock_info *info = (vsock_info *)c;
VALIDATE(info);
info->magic = 0;
history_wipe(info->history);
free(info->history);
free(info->args.key_file);
close(info->listen_sock);
free(info);
return 0;
}
static listener_plugin_t vsock_plugin = {
.name = NAME,
.version = VSOCK_VERSION,
.init = vsock_init,
.dispatch = vsock_dispatch,
.cleanup = vsock_shutdown,
};
-
-#ifdef _MODULE
double
LISTENER_VER_SYM(void)
{
return PLUGIN_VERSION_LISTENER;
}
const listener_plugin_t *
LISTENER_INFO_SYM(void)
{
return &vsock_plugin;
}
-#else
-static void __attribute__((constructor))
-vsock_register_plugin(void)
-{
- plugin_reg_listener(&vsock_plugin);
-}
-#endif
diff --git a/configure.ac b/configure.ac
index 82c553cb..8faf820d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,623 +1,609 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.63])
# TODO: port .gitarchiver
AC_INIT([fence-agents],
[m4_esyscmd([make/git-version-gen .tarball-version])],
[developers@clusterlabs.org])
AC_CONFIG_AUX_DIR([.])
# Don't let AC_PROC_CC (invoked by AC_USE_SYSTEM_EXTENSIONS) replace
# undefined CFLAGS with -g -O2, overriding our special OPT_CFLAGS.
: ${CFLAGS=""}
AC_USE_SYSTEM_EXTENSIONS
AM_INIT_AUTOMAKE([1.13 dist-bzip2 dist-xz color-tests -Wno-portability subdir-objects])
# Sanitize path
if test "$prefix" = "NONE"; then
prefix="/usr"
if test "$localstatedir" = "\${prefix}/var"; then
localstatedir="/var"
fi
if test "$sysconfdir" = "\${prefix}/etc"; then
sysconfdir="/etc"
fi
if test "$libdir" = "\${exec_prefix}/lib"; then
if test -e /usr/lib64; then
libdir="/usr/lib64"
else
libdir="/usr/lib"
fi
fi
fi
case $exec_prefix in
NONE) exec_prefix=$prefix;;
prefix) exec_prefix=$prefix;;
esac
# It is necessary to have this done before libtool does linker detection.
# See also: https://github.com/kronosnet/kronosnet/issues/107
# --as-needed: Modern systems have builtin ceil() making -lm superfluous but
# AC_SEARCH_LIBS can't detect this because it tests with a false prototype
AX_CHECK_LINK_FLAG([-Wl,--enable-new-dtags],
[AM_LDFLAGS=-Wl,--enable-new-dtags],
[AC_MSG_ERROR(["Linker support for --enable-new-dtags is required"])])
AX_CHECK_LINK_FLAG([-Wl,--as-needed], [AM_LDFLAGS="$AM_LDFLAGS -Wl,--as-needed"])
LT_PREREQ([2.2.6])
LT_INIT
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR([lib/fencing.py.py])
AC_CONFIG_HEADERS([make/config.h])
AC_CANONICAL_HOST
AC_PROG_LIBTOOL
AC_LANG([C])
# Checks for programs.
# check stolen from gnulib/m4/gnu-make.m4
if ! ${MAKE-make} --version /cannot/make/this >/dev/null 2>&1; then
AC_MSG_ERROR([you don't seem to have GNU make; it is required])
fi
AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_GCC_TRADITIONAL
AC_PROG_LN_S
AC_PROG_INSTALL
AC_PROG_MAKE_SET
AC_PROG_AWK
AC_PROG_CXX
AC_PROG_YACC
AC_PROG_LEX
PKG_PROG_PKG_CONFIG
## local helper functions
# this function checks if CC support options passed as
# args. Global CFLAGS are ignored during this test.
cc_supports_flag() {
local CFLAGS="-Werror $@"
AC_MSG_CHECKING([whether $CC supports "$@"])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[ ]])],
[RC=0; AC_MSG_RESULT([yes])],
[RC=1; AC_MSG_RESULT([no])])
return $RC
}
# Checks for header files.
AC_HEADER_DIRENT
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_HEADER_TIME
AC_CHECK_HEADERS([arpa/inet.h fcntl.h malloc.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h syslog.h termios.h unistd.h libintl.h limits.h netdb.h stddef.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_INLINE
AC_C_CONST
AC_TYPE_SIZE_T
AC_TYPE_SSIZE_T
AC_TYPE_UINT32_T
AC_TYPE_OFF_T
AC_TYPE_SIGNAL
# Checks for library functions.
AC_FUNC_FORK
AC_FUNC_MALLOC
AC_FUNC_CLOSEDIR_VOID
AC_FUNC_MEMCMP
AC_FUNC_SELECT_ARGTYPES
AC_FUNC_STAT
AC_CHECK_FUNCS([alarm atexit bzero dup2 memmove memset select socket strcasecmp strchr strdup strerror strtol gettimeofday])
# local options
AC_ARG_ENABLE([debug],
[ --enable-debug enable debug build. ],
[ default="no" ])
AC_ARG_WITH([fenceagentslibdir],
[ --with-fenceagentslibdir=PATH
installation path for fence library. ],
[ FENCEAGENTSLIBDIR="$withval" ],
[ FENCEAGENTSLIBDIR="${datadir}/fence" ])
AC_ARG_WITH([agents],
[ --with-agents=LIST
list of agents to build/ship (default: all). ],
[ AGENTS_LIST="$withval" ],
[ AGENTS_LIST="all" ])
if test "x$AGENTS_LIST" = x; then
AC_ERROR([No agents selected])
fi
FENCE_KDUMP=0
if echo "$AGENTS_LIST" | grep -q -E "all|kdump"; then
case "$host_os" in
*bsd*)
;;
*)
FENCE_KDUMP=1
;;
esac
AGENTS_LIST=$(echo "$AGENTS_LIST" | sed -E "s/kdump( |$)//")
fi
FENCE_MANUAL=0
if echo "$AGENTS_LIST" | grep -q -E "all|manual"; then
FENCE_MANUAL=1
AGENTS_LIST=$(echo "$AGENTS_LIST" | sed -E "s/manual( |$)//")
fi
FENCE_MPATH=0
if echo "$AGENTS_LIST" | grep -q -E "all|mpath"; then
FENCE_MPATH=1
fi
FENCE_SCSI=0
if echo "$AGENTS_LIST" | grep -q -E "all|scsi"; then
FENCE_SCSI=1
fi
FENCE_ZVM=0
if echo "$AGENTS_LIST" | grep -q -E "all|zvm( |$)"; then
FENCE_ZVM=1
fi
FENCE_VIRT=0
if echo "$AGENTS_LIST" | grep -q -E "all|virt( |$)"; then
case "$host_os" in
*bsd*)
;;
*)
FENCE_VIRT=1
VIRT_AM_LDFLAGS="$AM_LDFLAGS -fPIC -fPIE -Wl,-z,now"
AC_SUBST([VIRT_AM_LDFLAGS])
VIRT_AM_CFLAGS="-fPIC -fPIE -I\$(top_srcdir)/agents/virt/include -D_GNU_SOURCE"
AC_SUBST([VIRT_AM_CFLAGS])
VIRT_COMMON_LDFLAGS="-Wl,-wrap,syslog,-wrap,closelog"
AC_SUBST([VIRT_COMMON_LDFLAGS])
VIRT_COMMON_LIBS="-Wl,-Bstatic -L\$(top_builddir)/agents/virt/common -lfence_virt -Wl,-Bdynamic"
AC_SUBST([VIRT_COMMON_LIBS])
VIRT_CONFIG_LIBS="-L\$(top_builddir)/agents/virt/config -lsimpleconfig"
AC_SUBST([VIRT_CONFIG_LIBS])
# Checks for libraries.
AX_PTHREAD(,[AC_MSG_ERROR([POSIX threads support is required])])
PKG_CHECK_MODULES([nss], [nss])
PKG_CHECK_MODULES([xml2], [libxml-2.0])
PKG_CHECK_MODULES([uuid], [uuid])
saved_LIBS="$LIBS"
LIBS=
AC_SEARCH_LIBS([dlopen], [dl dld], , [AC_MSG_ERROR([dlopen not found])])
AC_SUBST([dl_LIBS], [$LIBS])
LIBS="$saved_LIBS"
;;
esac
fi
if test "x$AGENTS_LIST" != xall; then
for j in $AGENTS_LIST; do
if ! test -f agents/$j/fence_$j*.py; then
AC_ERROR([Agent $j does not exists])
fi
AGENTS_LIST=`echo "$AGENTS_LIST" | sed -E -e "s#$j([^_/]|$)#$j/fence_$j\1#g" -e "s#zvm/fence_zvm( |$)#zvm/fence_zvmip\1#g"`
done
fi
if test "x$AGENTS_LIST" = xall; then
AGENTS_LIST=`find $srcdir/agents -mindepth 2 -maxdepth 2 -name 'fence_*.py' -print0 | xargs -0 | sed -E -e 's#[^ ]*/agents/##g' -e 's#lib/[A-Za-z_.]*( |$)##g' -e 's#nss_wrapper/[A-Za-z_.]*( |$)##g' -e 's#autodetect/[A-Za-z_.]*( |$)##g'`
fi
XENAPILIB=0
if echo "$AGENTS_LIST" | grep -q xenapi; then
XENAPILIB=1
fi
## random vars
LOGDIR=${localstatedir}/log/cluster
CLUSTERVARRUN=${localstatedir}/run/cluster
CLUSTERDATA=${datadir}/cluster
AC_PATH_PROGS(XMLLINT, xmllint)
AM_CONDITIONAL(BUILD_DOC, test "x$XMLLINT" != "x" )
if test "x$XMLLINT" = "x"; then
AC_MSG_WARN([xmllint not installed, unable to (re-)build manual pages])
exit 1
fi
AC_SUBST(XMLLINT)
AC_PATH_PROGS(XSLTPROC, xsltproc)
AM_CONDITIONAL(BUILD_DOC, test "x$XSLTPROC" != "x" )
if test "x$XSLTPROC" = "x"; then
AC_MSG_WARN([xsltproc not installed, unable to (re-)build manual pages])
exit 1
fi
AC_SUBST(XSLTPROC)
AM_PATH_PYTHON
if test -z "$PYTHON"; then
echo "*** Essential program python not found" 1>&2
exit 1
fi
dnl Ensure PYTHON is an absolute path
AC_PATH_PROG([PYTHON], [$PYTHON])
AC_PYTHON_MODULE(pexpect, 1)
AC_PYTHON_MODULE(pycurl, 1)
AC_PYTHON_MODULE(requests, 1)
if echo "$AGENTS_LIST" | grep -q amt_ws; then
AC_PYTHON_MODULE(pywsman)
if test "x${HAVE_PYMOD_PYWSMAN}" != xyes; then
AGENTS_LIST=$(echo "$AGENTS_LIST" | sed -E "s#amt_ws/fence_amt_ws.py( |$)##")
AC_MSG_WARN("Not building fence_amt_ws")
fi
fi
if echo "$AGENTS_LIST" | grep -q aws; then
AC_PYTHON_MODULE(boto3)
if test "x${HAVE_PYMOD_BOTO3}" != xyes; then
AGENTS_LIST=$(echo "$AGENTS_LIST" | sed -E "s#aws/fence_aws.py( |$)##")
AC_MSG_WARN("Not building fence_aws")
fi
fi
if echo "$AGENTS_LIST" | grep -q -E "ovh|vmware_soap"; then
AC_PYTHON_MODULE(suds)
if test "x${HAVE_PYMOD_SUDS}" != xyes; then
AGENTS_LIST=$(echo "$AGENTS_LIST" | sed -E "s#(ovh/fence_ovh|vmware_soap/fence_vmware_soap).py( |$)##g")
AC_MSG_WARN("Not building fence_ovh and fence_vmware_soap")
fi
fi
if echo "$AGENTS_LIST" | grep -q gce; then
AC_PYTHON_MODULE(googleapiclient)
AC_PYTHON_MODULE(oauth2client)
if test "x${HAVE_PYMOD_GOOGLEAPICLIENT}" != xyes; then
AGENTS_LIST=$(echo "$AGENTS_LIST" | sed -E "s#gce/fence_gce.py( |$)##")
AC_MSG_WARN("Not building fence_ovh and fence_gce")
fi
fi
## path to 3rd-party binaries
AC_PATH_PROG([IPMITOOL_PATH], [ipmitool], [/usr/bin/ipmitool])
AC_PATH_PROG([OPENSTACK_PATH], [openstack], [/usr/bin/openstack])
AC_PATH_PROG([AMTTOOL_PATH], [amttool], [/usr/bin/amttool])
AC_PATH_PROG([GNUTLSCLI_PATH], [gnutlscli], [/usr/bin/gnutls-cli])
AC_PATH_PROG([COROSYNC_CMAPCTL_PATH], [corosync-cmapctl], [/usr/sbin/corosync-cmapctl])
AC_PATH_PROG([SG_PERSIST_PATH], [sg_persist], [/usr/bin/sg_persist])
AC_PATH_PROG([SG_TURS_PATH], [sg_turs], [/usr/bin/sg_turs])
AC_PATH_PROG([VGS_PATH], [vgs], [/usr/sbin/vgs])
AC_PATH_PROG([SUDO_PATH], [sudo], [/usr/bin/sudo])
AC_PATH_PROG([SSH_PATH], [ssh], [/usr/bin/ssh])
AC_PATH_PROG([TELNET_PATH], [telnet], [/usr/bin/telnet])
AC_PATH_PROG([MPATH_PATH], [mpathpersist], [/usr/sbin/mpathpersist])
AC_PATH_PROG([SBD_PATH], [sbd], [/sbin/sbd])
AC_PATH_PROG([SUDO_PATH], [sudo], [/usr/bin/sudo])
AC_PATH_PROG([SNMPWALK_PATH], [snmpwalk], [/usr/bin/snmpwalk])
AC_PATH_PROG([SNMPSET_PATH], [snmpset], [/usr/bin/snmpset])
AC_PATH_PROG([SNMPGET_PATH], [snmpget], [/usr/bin/snmpget])
AC_PATH_PROG([NOVA_PATH], [nova], [/usr/bin/nova])
AC_PATH_PROG([POWERMAN_PATH], [powerman], [/usr/bin/powerman])
AC_PATH_PROG([PING_CMD], [ping])
AC_PATH_PROG([PING6_CMD], [ping6])
AC_PATH_PROG([PING4_CMD], [ping4])
if test "x${ac_cv_path_PING_CMD}" = x; then
# assume multicall-ping just not available in build-environment
PING_CMD="/bin/ping"
PING4_CMD="/bin/ping -4"
PING6_CMD="/bin/ping -6"
elif test "x${ac_cv_path_PING6_CMD}" = x; then
# just IPv4
PING4_CMD="${ac_cv_path_PING_CMD}"
elif test -L ${ac_cv_path_PING6_CMD}; then
# assume multicall-ping
PING4_CMD="${ac_cv_path_PING_CMD} -4"
else
# ping is just IPv4
PING4_CMD="${ac_cv_path_PING_CMD}"
fi
## do subst
AC_SUBST([LOGDIR])
AC_SUBST([CLUSTERVARRUN])
AC_SUBST([CLUSTERDATA])
AC_SUBST([FENCEAGENTSLIBDIR])
AC_SUBST([SNMPBIN])
AC_SUBST([AGENTS_LIST])
AM_CONDITIONAL(BUILD_FENCE_KDUMP, test $FENCE_KDUMP -eq 1)
AM_CONDITIONAL(BUILD_FENCE_MANUAL, test $FENCE_MANUAL -eq 1)
AM_CONDITIONAL(BUILD_FENCE_MPATH, test $FENCE_MPATH -eq 1)
AM_CONDITIONAL(BUILD_FENCE_SCSI, test $FENCE_SCSI -eq 1)
AM_CONDITIONAL(BUILD_FENCE_ZVM, test $FENCE_ZVM -eq 1)
AM_CONDITIONAL(BUILD_FENCE_VIRT, test $FENCE_VIRT -eq 1)
AM_CONDITIONAL(BUILD_XENAPILIB, test $XENAPILIB -eq 1)
AC_SUBST([IPMITOOL_PATH])
AC_SUBST([OPENSTACK_PATH])
AC_SUBST([AMTTOOL_PATH])
AC_SUBST([COROSYNC_CMAPCTL_PATH])
AC_SUBST([SG_PERSIST_PATH])
AC_SUBST([SG_TURS_PATH])
AC_SUBST([VGS_PATH])
AC_SUBST([POWERMAN_PATH])
## fence-virt stuff
if test "x$FENCE_VIRT" = "x1"; then
sysconf=$(eval echo $sysconfdir)
AC_DEFINE_UNQUOTED([SYSCONFDIR], ["$sysconf"], [Default config dir])
fi
-#
-# Modular build for fence_virtd to split up dependencies
-# (default)
-#
-AC_ARG_ENABLE(modules,
-[AS_HELP_STRING([--disable-modules],
- [Disable modular build])],
-[ modules=$enableval ], [ modules=yes ])
-AM_CONDITIONAL([modularbuild], [test "x$modules" == "xyes"])
-
-if test "x$modules" == "xyes"; then
- AC_DEFINE_UNQUOTED([_MODULE], [1], [modular build])
-fi
-
### The following options only are used when $modules="yes" ###
# Null plugin: Disabled by default
AC_ARG_ENABLE(null-plugin,
[AS_HELP_STRING([--enable-null-plugin],
[Enable null (no-op) backend plugin])],
[ modnull=$enableval ], [ modnull=no ])
AM_CONDITIONAL([modnull], [test "x$modnull" == "xyes"])
# libvirt plugin: Enabled by default
AC_ARG_ENABLE(libvirt-plugin,
[AS_HELP_STRING([--disable-libvirt-plugin],
[Disable local-mode libvirt backend plugin])],
[ modlibvirt=$enableval ], [ modlibvirt=yes ])
AM_CONDITIONAL([modlibvirt], [test "x$modlibvirt" == "xyes"])
if test "x$modlibvirt" == "xyes" && test "x$FENCE_VIRT" = "x1"; then
PKG_CHECK_MODULES([virt], [libvirt])
fi
# cpg plugin: Disabled by default
AC_ARG_ENABLE(cpg-plugin,
[AS_HELP_STRING([--enable-cpg-plugin],
[Enable CPG/libvirt backend plugin])],
[ modcpg=$enableval ], [ modcpg=no ])
AM_CONDITIONAL([modcpg], [test "x$modcpg" == "xyes"])
if test "x$modcpg" == "xyes" && test "x$FENCE_VIRT" = "x1"; then
PKG_CHECK_MODULES([cpg], [libcpg])
fi
# (broken!) libvirt-qmf plugin: Disabled by default
AC_ARG_ENABLE(libvirt-qmf-plugin,
[AS_HELP_STRING([--enable-libvirt-qmf-plugin],
[Enable libvirt-qmf backend plugin])],
[ modlibvirtqmf=$enableval ], [ modlibvirtqmf=no ])
AM_CONDITIONAL([modlibvirtqmf], [test "x$modlibvirtqmf" == "xyes"])
if test "x$modlibvirtqmf" == "xyes" && test "x$FENCE_VIRT" = "x1"; then
PKG_CHECK_MODULES([qpid], [qpid])
fi
# (broken with pcmk 2.0!) pm-fence plugin: Disabled by default
AC_ARG_ENABLE(pm-fence-plugin,
[AS_HELP_STRING([--enable-pm-fence-plugin],
[Enable pm-fence backend plugin])],
[ modpmfence=$enableval ], [ modpmfence=no ])
AM_CONDITIONAL([modpmfence], [test "x$modpmfence" == "xyes"])
if test "x$modpmfence" == "xyes" && test "x$FENCE_VIRT" = "x1"; then
PKG_CHECK_MODULES([cib], [pacemaker-cib])
PKG_CHECK_MODULES([ncurses], [ncurses])
PKG_CHECK_MODULES([glib2], [glib-2.0])
AC_SEARCH_LIBS([read_attr_delegate], [cib], [ ], [ AC_DEFINE_UNQUOTED([PM_1_0], [1], [pacemaker 1.0]) ])
fi
# multicast plugin: Enabled by default
AC_ARG_ENABLE(multicast-plugin,
[AS_HELP_STRING([--disable-multicast-plugin],
[Disable multicast listener plugin])],
[ modmulticast=$enableval ], [ modmulticast=yes ])
AM_CONDITIONAL([modmulticast], [test "x$modmulticast" == "xyes"])
# tcp plugin: Enabled by default
AC_ARG_ENABLE(tcp-plugin,
[AS_HELP_STRING([--disable-tcp-plugin],
[Disable TCP listener plugin])],
[ modtcp=$enableval ], [ modtcp=yes ])
AM_CONDITIONAL([modtcp], [test "x$modtcp" == "xyes"])
# serial/libvirt plugin: Enabled by default
AC_ARG_ENABLE(serial-plugin,
[AS_HELP_STRING([--disable-serial-plugin],
[Disable serial listener plugin])],
[ modserial=$enableval ], [ modserial=yes ])
AM_CONDITIONAL([modserial], [test "x$modserial" == "xyes"])
# vsock plugin: Enabled by default
AC_ARG_ENABLE(vsock-plugin,
[AS_HELP_STRING([--disable-vsock-plugin],
[Disable TCP listener plugin])],
[ modvsock=$enableval ], [ modvsock=yes ])
AM_CONDITIONAL([modvsock], [test "x$modvsock" == "xyes"])
#
# Compatibility symlink: enabled by default
#
AC_ARG_ENABLE(xvm-compat,
[AS_HELP_STRING([--disable-xvm-compat],
[Disable fence_xvm symlink compatibility])],
[ xvmcompat=$enableval ], [ xvmcompat=yes ])
AM_CONDITIONAL([xvmcompat], [test "x$xvmcompat" == "xyes"])
# Try to detect the appropriate conf dir. Several systems have both /etc/default
# and /etc/sysconfig but latter is always primary.
AC_ARG_VAR(initconfdir, [directory for initscripts configuration])
if test "x$initconfdir" = x && test "x$FENCE_VIRT" = "x1"; then
AC_CHECK_FILE(/etc/conf.d, [initconfdir='$(sysconfdir)/conf.d}'], [# Gentoo/Arch
AC_CHECK_FILE(/etc/sysconfig, [initconfdir='$(sysconfdir)/sysconfig'], [# RedHat/Fedora/Slax/Mandriva/S
AC_CHECK_FILE(/etc/default, [initconfdir='$(sysconfdir)/default'], [# Debian/Ubuntu
AC_MSG_ERROR([could not determine system initscripts config dir; please set initconfdir manually.])])])])
fi
## *FLAGS handling
ENV_CFLAGS="$CFLAGS"
ENV_CPPFLAGS="$CPPFLAGS"
ENV_LDFLAGS="$LDFLAGS"
# debug build stuff
if test "x${enable_debug}" = xyes; then
AC_DEFINE_UNQUOTED([DEBUG], [1], [Compiling Debugging code])
OPT_CFLAGS="-O0"
else
OPT_CFLAGS="-O2"
fi
# gdb flags
if test "x${GCC}" = xyes; then
GDB_FLAGS="-ggdb3"
else
GDB_FLAGS="-g"
fi
# extra warnings
EXTRA_WARNINGS=""
WARNLIST="
error
all
shadow
missing-prototypes
missing-declarations
strict-prototypes
declaration-after-statement
pointer-arith
write-strings
cast-align
bad-function-cast
missing-format-attribute
format=2
format-security
format-nonliteral
no-long-long
unsigned-char
gnu89-inline
no-strict-aliasing
"
for j in $WARNLIST; do
if cc_supports_flag -W$j; then
EXTRA_WARNINGS="$EXTRA_WARNINGS -W$j";
fi
done
AM_CFLAGS="$ENV_CFLAGS $OPT_CFLAGS $GDB_FLAGS $EXTRA_WARNINGS"
AC_SUBST([AM_CFLAGS])
CPPFLAGS="-I\$(top_builddir)/make -I\$(top_srcdir)/make -I. $ENV_CPPFLAGS"
LDFLAGS="$ENV_LDFLAGS"
AM_EXTRA_RECURSIVE_TARGETS([xml-check xml-upload])
AX_PROG_DATE
AS_IF([test "$ax_cv_prog_date_gnu_date:$ax_cv_prog_date_gnu_utc" = yes:yes],
[UTC_DATE_AT="date -u -d@"],
[AS_IF([test "x$ax_cv_prog_date_bsd_date" = xyes],
[UTC_DATE_AT="date -u -r"],
[AC_MSG_ERROR([date utility unable to convert epoch to UTC])])])
AC_SUBST([UTC_DATE_AT])
AC_ARG_VAR([SOURCE_EPOCH],[last modification date of the source])
AC_MSG_NOTICE([trying to determine source epoch])
AC_MSG_CHECKING([for source epoch in \$SOURCE_EPOCH])
AS_IF([test -n "$SOURCE_EPOCH"],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AC_MSG_CHECKING([for source epoch in source_epoch file])
AS_IF([test -e "$srcdir/source_epoch"],
[read SOURCE_EPOCH <"$srcdir/source_epoch"
AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AC_MSG_CHECKING([for source epoch baked in by gitattributes export-subst])
SOURCE_EPOCH='$Format:%at$' # template for rewriting by git-archive
AS_CASE([$SOURCE_EPOCH],
[?Format:*], # was not rewritten
[AC_MSG_RESULT([no])
AC_MSG_CHECKING([for source epoch in \$SOURCE_DATE_EPOCH])
AS_IF([test "x$SOURCE_DATE_EPOCH" != x],
[SOURCE_EPOCH="$SOURCE_DATE_EPOCH"
AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AC_MSG_CHECKING([whether git log can provide a source epoch])
SOURCE_EPOCH=f${SOURCE_EPOCH#\$F} # convert into git log --pretty format
SOURCE_EPOCH=$(cd "$srcdir" && git log -1 --pretty=${SOURCE_EPOCH%$} 2>/dev/null)
AS_IF([test -n "$SOURCE_EPOCH"],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no, using current time and breaking reproducibility])
SOURCE_EPOCH=$(date +%s)])])],
[AC_MSG_RESULT([yes])]
)])
])
AC_MSG_NOTICE([using source epoch $($UTC_DATE_AT$SOURCE_EPOCH +'%F %T %Z')])
if test "x$VERSION" = "xUNKNOWN"; then
AC_MSG_ERROR([m4_text_wrap([
configure was unable to determine the source tree's current version. This
generally happens when using git archive (or the github download button)
generated tarball/zip file. In order to workaround this issue, either use git
clone https://github.com/ClusterLabs/fence-virt.git or use an official release
tarball. Alternatively you can add a compatible version in a .tarball-version
file at the top of the source tree, wipe your autom4te.cache dir and generated
configure, and rerun autogen.sh.
], [ ], [ ], [76])])
fi
AC_CONFIG_FILES([Makefile
fence-agents.pc
agents/Makefile
lib/Makefile
doc/Makefile
agents/virt/Makefile
agents/virt/config/Makefile
agents/virt/common/Makefile
agents/virt/client/Makefile
agents/virt/server/Makefile
agents/virt/man/Makefile
])
AC_OUTPUT
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jun 26, 7:34 PM (1 d, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1959573
Default Alt Text
(124 KB)
Attached To
Mode
rF Fence Agents
Attached
Detach File
Event Timeline
Log In to Comment