From e26cae6b85508cc209958cf002fb1d0c8bb4f6a2 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Fri, 13 Dec 2013 12:54:10 +0100 Subject: [PATCH] examples: Resurrect domsuspend example This partially reverts 5eb4b04211 and 62774afb6ba8. Rewrite the domsuspend example from scratch. This time do it right. Signed-off-by: Michal Privoznik --- .gitignore | 1 + Makefile.am | 4 +- cfg.mk | 2 +- configure.ac | 1 + examples/domsuspend/Makefile.am | 27 ++++ examples/domsuspend/suspend.c | 276 ++++++++++++++++++++++++++++++++ libvirt.spec.in | 3 +- 7 files changed, 310 insertions(+), 4 deletions(-) create mode 100644 examples/domsuspend/Makefile.am create mode 100644 examples/domsuspend/suspend.c diff --git a/.gitignore b/.gitignore index d5a6cf52b1..496c2ef03e 100644 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,7 @@ /docs/todo.html.in /examples/object-events/event-test /examples/dominfo/info1 +/examples/domsuspend/suspend /examples/hellolibvirt/hellolibvirt /examples/openauth/openauth /gnulib/lib/* diff --git a/Makefile.am b/Makefile.am index 88c70734b9..eb88fee66c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,8 +21,8 @@ GENHTML = genhtml SUBDIRS = . gnulib/lib include src daemon tools docs gnulib/tests \ tests po examples/object-events examples/hellolibvirt \ - examples/dominfo examples/apparmor examples/xml/nwfilter \ - examples/openauth examples/systemtap + examples/dominfo examples/domsuspend examples/apparmor \ + examples/xml/nwfilter examples/openauth examples/systemtap ACLOCAL_AMFLAGS = -I m4 diff --git a/cfg.mk b/cfg.mk index 9a06650616..5591065afd 100644 --- a/cfg.mk +++ b/cfg.mk @@ -1003,7 +1003,7 @@ exclude_file_name_regexp--sc_prohibit_sprintf = \ exclude_file_name_regexp--sc_prohibit_strncpy = ^src/util/virstring\.c$$ exclude_file_name_regexp--sc_prohibit_strtol = \ - ^src/(util/virsexpr|(vbox|xen|xenxs)/.*)\.c$$ + ^(src/(util/virsexpr|(vbox|xen|xenxs)/.*)\.c)|(examples/domsuspend/suspend.c)$$ exclude_file_name_regexp--sc_prohibit_xmlGetProp = ^src/util/virxml\.c$$ diff --git a/configure.ac b/configure.ac index ddbcc8ec1f..2622dfd530 100644 --- a/configure.ac +++ b/configure.ac @@ -2555,6 +2555,7 @@ AC_CONFIG_FILES([\ tests/Makefile \ examples/apparmor/Makefile \ examples/object-events/Makefile \ + examples/domsuspend/Makefile \ examples/dominfo/Makefile \ examples/openauth/Makefile \ examples/hellolibvirt/Makefile \ diff --git a/examples/domsuspend/Makefile.am b/examples/domsuspend/Makefile.am new file mode 100644 index 0000000000..b8e65f24a2 --- /dev/null +++ b/examples/domsuspend/Makefile.am @@ -0,0 +1,27 @@ +## Process this file with automake to produce Makefile.in + +## Copyright (C) 2013 Red Hat, Inc. +## +## This library is free software; you can redistribute it and/or +## modify it under the terms of the GNU Lesser General Public +## License as published by the Free Software Foundation; either +## version 2.1 of the License, or (at your option) any later version. +## +## This library 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 +## Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public +## License along with this library. If not, see +## . + +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include +LDADDS = $(STATIC_BINARIES) $(WARN_CFLAGS) $(top_builddir)/src/libvirt.la \ + $(COVERAGE_LDFLAGS) + +noinst_PROGRAMS=suspend + +suspend_SOURCES=suspend.c +suspend_LDFLAGS= +suspend_LDADD= $(LDADDS) diff --git a/examples/domsuspend/suspend.c b/examples/domsuspend/suspend.c new file mode 100644 index 0000000000..f61a5d1aab --- /dev/null +++ b/examples/domsuspend/suspend.c @@ -0,0 +1,276 @@ +/* + * suspend.c: Demo program showing how to suspend a domain + * + * Copyright (C) 2006-2013 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Author: Michal Privoznik + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static int debug; + +#define ERROR(...) \ +do { \ + fprintf(stderr, "ERROR %s:%d : ", __FUNCTION__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ +} while (0) + +#define DEBUG(...) \ +do { \ + if (!debug) \ + break; \ + fprintf(stderr, "DEBUG %s:%d : ", __FUNCTION__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ +} while (0) + +static void +print_usage(const char *progname) +{ + const char *unified_progname; + + if (!(unified_progname = strrchr(progname, '/'))) + unified_progname = progname; + else + unified_progname++; + + printf("\n%s [options] [domain name]\n\n" + " options:\n" + " -d | --debug enable debug printings\n" + " -h | --help print this help\n" + " -c | --connect=URI hypervisor connection URI\n" + " -s | --seconds=X suspend domain for X seconds (default 1)\n", + unified_progname); +} + +static int +parse_argv(int argc, char *argv[], + const char **uri, + const char **dom_name, + unsigned int *seconds) +{ + int ret = -1; + int arg; + unsigned long val; + char *p; + struct option opt[] = { + {"debug", no_argument, NULL, 'd'}, + {"help", no_argument, NULL, 'h'}, + {"connect", required_argument, NULL, 'c'}, + {"seconds", required_argument, NULL, 's'}, + {NULL, 0, NULL, 0} + }; + + while ((arg = getopt_long(argc, argv, "+:dhc:s:", opt, NULL)) != -1) { + switch (arg) { + case 'd': + debug = 1; + break; + case 'h': + print_usage(argv[0]); + exit(EXIT_SUCCESS); + break; + case 'c': + *uri = optarg; + break; + case 's': + /* strtoul man page suggest clearing errno prior to call */ + errno = 0; + val = strtoul(optarg, &p, 10); + if (errno || *p || p == optarg) { + ERROR("Invalid number: '%s'", optarg); + goto cleanup; + } + *seconds = val; + if (*seconds != val) { + ERROR("Integer overflow: %ld", val); + goto cleanup; + } + break; + case ':': + ERROR("option '-%c' requires an argument", optopt); + exit(EXIT_FAILURE); + case '?': + if (optopt) + ERROR("unsupported option '-%c'. See --help.", optopt); + else + ERROR("unsupported option '%s'. See --help.", argv[optind - 1]); + exit(EXIT_FAILURE); + default: + ERROR("unknown option"); + exit(EXIT_FAILURE); + } + } + + if (argc > optind) + *dom_name = argv[optind]; + + ret = 0; +cleanup: + return ret; +} + +static int +fetch_domains(virConnectPtr conn) +{ + int num_domains, ret = -1; + virDomainPtr *domains = NULL; + size_t i; + const int list_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE; + + DEBUG("Fetching list of running domains"); + num_domains = virConnectListAllDomains(conn, &domains, list_flags); + + DEBUG("num_domains=%d", num_domains); + if (num_domains < 0) { + ERROR("Unable to fetch list of running domains"); + goto cleanup; + } + + printf("Running domains:\n"); + printf("----------------\n"); + for (i = 0; i < num_domains; i++) { + virDomainPtr dom = domains[i]; + const char *dom_name = virDomainGetName(dom); + printf("%s\n", dom_name); + virDomainFree(dom); + } + + ret = 0; +cleanup: + free(domains); + return ret; +} + +static int +suspend_and_resume(virConnectPtr conn, + const char *dom_name, + unsigned int seconds) +{ + int ret = -1; + virDomainPtr dom; + virDomainInfo dom_info; + + if (!(dom = virDomainLookupByName(conn, dom_name))) { + ERROR("Unable to find domain '%s'", dom_name); + goto cleanup; + } + + if (virDomainGetInfo(dom, &dom_info) < 0) { + ERROR("Unable to get domain info"); + goto cleanup; + } + + DEBUG("Domain state %d", dom_info.state); + + switch (dom_info.state) { + case VIR_DOMAIN_NOSTATE: + case VIR_DOMAIN_RUNNING: + case VIR_DOMAIN_BLOCKED: + /* In these states the domain can be suspended */ + DEBUG("Suspending domain"); + if (virDomainSuspend(dom) < 0) { + ERROR("Unable to suspend domain"); + goto cleanup; + } + + DEBUG("Domain suspended. Entering sleep for %u seconds.", seconds); + sleep(seconds); + DEBUG("Sleeping done. Resuming the domain."); + + if (virDomainResume(dom) < 0) { + ERROR("Unable to resume domain"); + goto cleanup; + } + break; + + default: + /* In all other states domain can't be suspended */ + ERROR("Domain is not in a state where it can be suspended: %d", + dom_info.state); + goto cleanup; + } + + ret = 0; +cleanup: + if (dom) + virDomainFree(dom); + return ret; +} + +int +main(int argc, char *argv[]) +{ + int ret = EXIT_FAILURE; + virConnectPtr conn = NULL; + const char *uri = NULL; + const char *dom_name = NULL; + unsigned int seconds = 1; /* Suspend domain for this long */ + const int connect_flags = 0; /* No connect flags for now */ + + if (parse_argv(argc, argv, &uri, &dom_name, &seconds) < 0) + goto cleanup; + + DEBUG("Proceeding with uri=%s dom_name=%s seconds=%u", + uri, dom_name, seconds); + + if (!(conn = virConnectOpenAuth(uri, + virConnectAuthPtrDefault, + connect_flags))) { + ERROR("Failed to connect to hypervisor"); + goto cleanup; + } + + DEBUG("Successfully connected"); + + if (!dom_name) { + if (fetch_domains(conn) == 0) + ret = EXIT_SUCCESS; + goto cleanup; + } + + if (suspend_and_resume(conn, dom_name, seconds) < 0) + goto cleanup; + + ret = EXIT_SUCCESS; +cleanup: + if (conn) { + int tmp; + tmp = virConnectClose(conn); + if (tmp < 0) { + ERROR("Failed to disconnect from the hypervisor"); + ret = EXIT_FAILURE; + } else if (tmp > 0) { + ERROR("One or more references were leaked after " + "disconnect from the hypervisor"); + ret = EXIT_FAILURE; + } else { + DEBUG("Connection successfully closed"); + } + } + return ret; +} diff --git a/libvirt.spec.in b/libvirt.spec.in index 3f8db09430..0b530fe43f 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -1430,7 +1430,7 @@ rm -fr %{buildroot} # on RHEL 5, thus we need to expand it here. make install DESTDIR=%{?buildroot} SYSTEMD_UNIT_DIR=%{_unitdir} -for i in object-events dominfo hellolibvirt openauth xml/nwfilter systemtap +for i in object-events dominfo domsuspend hellolibvirt openauth xml/nwfilter systemtap do (cd examples/$i ; make clean ; rm -rf .deps .libs Makefile Makefile.in) done @@ -2142,6 +2142,7 @@ exit 0 %doc examples/hellolibvirt %doc examples/object-events %doc examples/dominfo +%doc examples/domsuspend %doc examples/openauth %doc examples/xml %doc examples/systemtap