[libvirt] PATCH: 0/5: Refactoring LXC & switching to generic domain APIs
by Daniel P. Berrange
The following series of 5 patches perform some general re-factoring of the
LXC driver, the relationship between libvirtd & the processes it spawns,
and finally switches LXC over to the generic domain XML APIs. This is just
basically 1 day's work, so its a little rough around the edges in places,
but I can confim that the core functionality is still all operational - by
which I mean, start, stop, list, console, & re-start of daemon.
Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
16 years, 3 months
[libvirt] Updating xml (cmdline)
by Stefan de Konink
Hi,
Is it possible to 'update' a defined domain before it is started. I have
run into a chicken and egg problem related to the <cmdline> and the
first ethernet interface, I cannot create the interface before I have a
domain and visa versa.
Stefan
16 years, 3 months
[libvirt] PATCH: Bash auto-completion for virsh
by Daniel P. Berrange
Everyone[1] seems to be doing funky bash auto-completion for commands these
days, so I thought I'd make a stab at doing something for virsh.
First of all I needed the command line help in an easier format to deal
with, so I've added
virsh _complete-command commands|arguments|options
eg,
$ virsh _complete-command commands
help
attach-device
attach-disk
attach-interface
autostart
capabilities
connect
console
...snip rest...
$ virsh _complete-command arguments vcpupin
domain
vcpu
cpulist
$ virsh _complete-command options
-c
--connect
-r
--readonly
-d
--debug
-h
--help
-q
--quiet
-t
--timing
-l
--log
-v
--version
$ virsh _complete-command options net-list
--inactive
--all
That's enough to get all the basic commands & options auto-completing.
For the arguments though I wanted to be able to auto-complete domain
names, ids and UUIDs. likewise for storage pools and networks. I also
wanted to auto-complete connect URIs ,eg test://default, qemu:///system
$ virsh _complete-domain
ISCSIServer
35e5efcc-f6a3-b489-fc33-99f2e4792e6d
untangle
dc502cb8-4bdd-7a15-f35a-cf76287ea2bd
VirtTest
82038f2a-1344-aaf7-1a85-2a7250be2076
xenner
18c23d31-4d74-0bff-986d-e4251d2a2ff0
And
$ virsh _complete-uri
test:///default
qemu:///system
lxc:///
For this latter command, I needed to add a new API
/**
* virConnectURIs:
* uris: pointer to a list to be filled with URI strings
*
* This functions returns the list of available connection
* URIs. The caller is responsible for freeing the returned
* strings, and the array they're stored in.
*
* Returns the number of URIs in case of success or -1 in
* case of error.
*/
int virConnectURIs(char ***uris);
This simply calls the existing probe() method for each driver and
stores the list of URIs returned.
Finally to tie this all together simply needs a little helper script
which by convention is added to the /etc/bash_completion.d/. On Fedora
this isn't enable by default, so you have to turn it on with
source /etc/bash_completion.d/virsh
To your $HOME/.bashrc
Daniel
[1] For a definition of 'everyone' which includes git & mercurial
b/src/virsh.bash | 79 +++++++
include/libvirt/libvirt.h | 1
include/libvirt/libvirt.h.in | 1
libvirt.spec.in | 1
src/Makefile.am | 10
src/libvirt.c | 54 +++++
src/libvirt_sym.version | 2
src/test.c | 6
src/virsh.c | 442 ++++++++++++++++++++++++++++++++++++++++++-
9 files changed, 581 insertions(+), 15 deletions(-)
diff -r f3413463b3ff include/libvirt/libvirt.h
--- a/include/libvirt/libvirt.h Sun Jul 13 13:14:50 2008 +0100
+++ b/include/libvirt/libvirt.h Mon Jul 14 11:54:10 2008 +0100
@@ -397,6 +397,7 @@
virConnectAuthPtr auth,
int flags);
int virConnectClose (virConnectPtr conn);
+int virConnectURIs (char ***uris);
const char * virConnectGetType (virConnectPtr conn);
int virConnectGetVersion (virConnectPtr conn,
unsigned long *hvVer);
diff -r f3413463b3ff include/libvirt/libvirt.h.in
--- a/include/libvirt/libvirt.h.in Sun Jul 13 13:14:50 2008 +0100
+++ b/include/libvirt/libvirt.h.in Mon Jul 14 11:54:10 2008 +0100
@@ -397,6 +397,7 @@
virConnectAuthPtr auth,
int flags);
int virConnectClose (virConnectPtr conn);
+int virConnectURIs (char ***uris);
const char * virConnectGetType (virConnectPtr conn);
int virConnectGetVersion (virConnectPtr conn,
unsigned long *hvVer);
diff -r f3413463b3ff libvirt.spec.in
--- a/libvirt.spec.in Sun Jul 13 13:14:50 2008 +0100
+++ b/libvirt.spec.in Mon Jul 14 11:54:10 2008 +0100
@@ -227,6 +227,7 @@
%dir %attr(0700, root, root) %{_sysconfdir}/libvirt/qemu/
%dir %attr(0700, root, root) %{_sysconfdir}/libvirt/qemu/networks/
%dir %attr(0700, root, root) %{_sysconfdir}/libvirt/qemu/networks/autostart
+%{_sysconfdir}/bash_completion.d/virsh
%{_sysconfdir}/rc.d/init.d/libvirtd
%config(noreplace) %{_sysconfdir}/sysconfig/libvirtd
%config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf
diff -r f3413463b3ff src/Makefile.am
--- a/src/Makefile.am Sun Jul 13 13:14:50 2008 +0100
+++ b/src/Makefile.am Mon Jul 14 11:54:10 2008 +0100
@@ -25,8 +25,9 @@
confdir = $(sysconfdir)/libvirt/
conf_DATA = qemu.conf
+bashdir = $(sysconfdir)/bash_completion.d
-EXTRA_DIST = libvirt_sym.version $(conf_DATA)
+EXTRA_DIST = libvirt_sym.version $(conf_DATA) virsh.bash
lib_LTLIBRARIES = libvirt.la
@@ -153,7 +154,12 @@
endif
# Create the /var/cache/libvirt directory when installing.
-install-exec-local:
+install-exec-local::
$(MKDIR_P) $(DESTDIR)$(localstatedir)/cache/libvirt
+ $(MKDIR_P) $(DESTDIR)$(bashdir)
+ $(INSTALL_SCRIPT) virsh.bash $(bashdir)/virsh
+
+uninstall-local::
+ $(RM) -f $(bashdir)/virsh
CLEANFILES = *.gcov .libs/*.gcda .libs/*.gcno *.gcno *.gcda
diff -r f3413463b3ff src/libvirt.c
--- a/src/libvirt.c Sun Jul 13 13:14:50 2008 +0100
+++ b/src/libvirt.c Mon Jul 14 11:54:10 2008 +0100
@@ -37,6 +37,7 @@
#include "uuid.h"
#include "util.h"
#include "test.h"
+#include "memory.h"
#include "xen_unified.h"
#include "remote_internal.h"
#include "qemu_driver.h"
@@ -701,7 +702,8 @@
int probes = 0;
for (i = 0; i < virDriverTabCount; i++) {
if ((virDriverTab[i]->probe != NULL) &&
- ((latest = virDriverTab[i]->probe()) != NULL)) {
+ ((latest = virDriverTab[i]->probe()) != NULL) &&
+ STRNEQ(latest, "test:///default")) {
probes++;
DEBUG("Probed %s", latest);
@@ -946,6 +948,56 @@
if (virUnrefConnect(conn) < 0)
return (-1);
return (0);
+}
+
+
+/**
+ * virConnectURIs:
+ * uris: pointer to a list to be filled with URI strings
+ *
+ * This functions returns the list of available connection
+ * URIs. The caller is responsible for freeing the returned
+ * strings, and the array they're stored in.
+ *
+ * Returns the number of URIs in case of success or -1 in
+ * case of error.
+ */
+int
+virConnectURIs(char ***uris)
+{
+ const char *uri;
+ char **ret = NULL;
+ int nuris = 0, i;
+ DEBUG("uris=%p", uris);
+
+ if (!initialized)
+ if (virInitialize() < 0)
+ return -1;
+
+ if (!uris)
+ return -1;
+
+ for (i = 0; i < virDriverTabCount; i++) {
+ if ((virDriverTab[i]->probe != NULL) &&
+ ((uri = virDriverTab[i]->probe()) != NULL)) {
+ if (VIR_REALLOC_N(ret, nuris + 1) < 0)
+ goto no_memory;
+ if ((ret[nuris++] = strdup(uri)) == NULL)
+ goto no_memory;
+
+ DEBUG("Probed %s", uri);
+ }
+ }
+
+ *uris = ret;
+ return (nuris);
+
+no_memory:
+ for (i = 0 ; i < nuris ; i++)
+ VIR_FREE(ret[i]);
+ VIR_FREE(ret);
+ virLibConnError(NULL, VIR_ERR_NO_MEMORY, NULL);
+ return -1;
}
/* Not for public use. This function is part of the internal
diff -r f3413463b3ff src/libvirt_sym.version
--- a/src/libvirt_sym.version Sun Jul 13 13:14:50 2008 +0100
+++ b/src/libvirt_sym.version Mon Jul 14 11:54:10 2008 +0100
@@ -5,7 +5,7 @@
virConnectOpenReadOnly;
virConnectOpenAuth;
virConnectAuthPtrDefault;
-
+ virConnectURIs;
virConnectClose;
virConnectGetType;
virConnectGetVersion;
diff -r f3413463b3ff src/test.c
--- a/src/test.c Sun Jul 13 13:14:50 2008 +0100
+++ b/src/test.c Mon Jul 14 11:54:10 2008 +0100
@@ -215,6 +215,10 @@
" </ip>"
"</network>";
+
+static const char *testProbe(void) {
+ return "test:///default";
+}
static int testOpenDefault(virConnectPtr conn) {
int u;
@@ -1545,7 +1549,7 @@
VIR_DRV_TEST,
"Test",
LIBVIR_VERSION_NUMBER,
- NULL, /* probe */
+ testProbe, /* probe */
testOpen, /* open */
testClose, /* close */
NULL, /* supports_feature */
diff -r f3413463b3ff src/virsh.bash
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virsh.bash Mon Jul 14 11:54:10 2008 +0100
@@ -0,0 +1,79 @@
+
+_virsh()
+{
+ local cur prev cmd cmd_index arg arg_index i results
+ local virsh="$1"
+ local canonical=0
+
+ COMPREPLY=()
+ cur="$2"
+ prev="$3"
+
+ if [[ $COMP_CWORD > 1 && ${COMP_WORDS[COMP_CWORD-1]} = '--connect' ]]; then
+ results="$("$virsh" _complete-uri)" || nets=""
+ fi
+
+ if [ -z "$results" ]; then
+ # searching for the command name
+ for ((i=1; $i<=$COMP_CWORD; i++)); do
+ if [[ ${COMP_WORDS[i]} != -* ]]; then
+ if [[ ${COMP_WORDS[i-1]} != '--connect' ]]; then
+ if [[ $i < $COMP_CWORD ]]; then
+ cmd="${COMP_WORDS[i]}"
+ cmd_index=$i
+ arg_index=`expr $COMP_CWORD - $cmd_index`
+ break
+ fi
+ fi
+ fi
+ done
+
+ if [[ "$cur" == -* ]]; then
+ # Generate args - global or command specific
+ results="$("$virsh" _complete-command options "$cmd")"
+ else
+ if [ -z "$cmd" ]; then
+ # No command set, so generate list of all commands
+ results="$("$virsh" _complete-command commands)" || commands=""
+ else
+ # Command set, to generate command specific args
+ n=0
+ for i in "$("$virsh" _complete-command arguments "$cmd")"
+ do
+ n=`expr $n + 1`
+ if [ $n = $arg_index ]; then
+ arg=$i
+ break
+ fi
+ done
+
+ case $arg in
+ file)
+ COMPREPLY=(${COMPREPLY[@]:-} $(compgen -o "default" -- "$cur"))
+ ;;
+
+ domain)
+ results="$("$virsh" _complete-domain)" || doms=""
+ ;;
+
+ network)
+ results="$("$virsh" _complete-network)" || nets=""
+ ;;
+
+ pool)
+ results="$("$virsh" _complete-pool)" || nets=""
+ ;;
+
+ uri)
+ results="$("$virsh" _complete-uri)" || nets=""
+ ;;
+ esac
+ fi
+ fi
+ fi
+ if [ ! -z "$results" ]; then
+ COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$results' -- "$cur"))
+ fi
+}
+
+complete -F _virsh virsh
diff -r f3413463b3ff src/virsh.c
--- a/src/virsh.c Sun Jul 13 13:14:50 2008 +0100
+++ b/src/virsh.c Mon Jul 14 11:54:10 2008 +0100
@@ -329,6 +329,409 @@
* ---------------
*/
+
+
+/*
+ * "_compcmds" command
+ */
+static vshCmdInfo info_compcommand[] = {
+ {"syntax", "_complete-command [commands|arguments|options] [<command>]"},
+ {"help", gettext_noop("print shell completion data")},
+ {"desc", gettext_noop("Prints data useful for shell autocompletion of commands.")},
+
+ {NULL, NULL}
+};
+
+static vshCmdOptDef opts_compcommand[] = {
+ {"type", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("type of data")},
+ {"cmd", VSH_OT_DATA, 0, gettext_noop("command name")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdCompCommand(vshControl * ctl, vshCmd * cmd)
+{
+ const char *type = vshCommandOptString(cmd, "type", NULL);
+ const char *name = vshCommandOptString(cmd, "cmd", NULL);
+
+ if (STREQ(type, "commands")) {
+ vshCmdDef *def;
+ for (def = commands; def->name; def++)
+ if (def->name[0] != '_')
+ vshPrint(ctl, "%s\n", def->name);
+ } else if (STREQ(type, "options")) {
+ if (name) {
+ vshCmdDef *def = vshCmddefSearch(name);
+ if (!def) {
+ vshError(ctl, FALSE, _("command '%s' doesn't exist"), name);
+ return FALSE;
+ } else if (def->opts) {
+ vshCmdOptDef *opt;
+ for (opt = def->opts; opt->name; opt++)
+ if (opt->type == VSH_OT_BOOL ||
+ opt->type == VSH_OT_INT ||
+ opt->type == VSH_OT_STRING)
+ vshPrint(ctl, "--%s\n", opt->name);
+ }
+ } else {
+ vshPrint(ctl,
+ "-c\n--connect\n"
+ "-r\n--readonly\n"
+ "-d\n--debug\n"
+ "-h\n--help\n"
+ "-q\n--quiet\n"
+ "-t\n--timing\n"
+ "-l\n--log\n"
+ "-v\n--version\n");
+ }
+ } else if (STREQ(type, "arguments")) {
+ if (!name) {
+ vshError(ctl, FALSE, "%s", _("no command specified"));
+ return FALSE;
+ } else {
+ vshCmdDef *def = vshCmddefSearch(name);
+ if (!def) {
+ vshError(ctl, FALSE, _("command '%s' doesn't exist"), name);
+ return FALSE;
+ } else if (def->opts) {
+ vshCmdOptDef *opt;
+ for (opt = def->opts; opt->name; opt++)
+ if (opt->type == VSH_OT_DATA)
+ vshPrint(ctl, "%s\n", opt->name);
+ }
+ }
+ }
+ return TRUE;
+}
+
+/*
+ * "_compuris" command
+ */
+static vshCmdInfo info_compuri[] = {
+ {"syntax", "_complete-uri"},
+ {"help", gettext_noop("print shell completion data for URIs")},
+ {"desc", gettext_noop("Prints data useful for shell autocompletion of URIs.")},
+
+ {NULL, NULL}
+};
+
+static vshCmdOptDef opts_compuri[] = {
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdCompUri(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+ char **uris = NULL;
+ int nuris, i;
+
+ nuris = virConnectURIs(&uris);
+ if (nuris < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list connection URIs"));
+ return FALSE;
+ }
+ for (i = 0 ; i < nuris ; i++) {
+ vshPrint(ctl, "%s\n", uris[i]);
+ free(uris[i]);
+ }
+
+ free(uris);
+ return TRUE;
+}
+/*
+ * "_compdomains" command
+ */
+static vshCmdInfo info_compdomain[] = {
+ {"syntax", "_complete-domain"},
+ {"help", gettext_noop("print shell completion data for domains")},
+ {"desc", gettext_noop("Prints data useful for shell autocompletion of domains.")},
+
+ {NULL, NULL}
+};
+
+static vshCmdOptDef opts_compdomain[] = {
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdCompDomain(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+ int *ids = NULL;
+ char **names = NULL;
+ int maxname = 0, maxid = 0, i;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ maxid = virConnectNumOfDomains(ctl->conn);
+ if (maxid < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list active domains"));
+ return FALSE;
+ }
+ if (maxid) {
+ ids = vshMalloc(ctl, sizeof(int) * maxid);
+
+ if ((maxid = virConnectListDomains(ctl->conn, &ids[0], maxid)) < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list active domains"));
+ free(ids);
+ return FALSE;
+ }
+
+ qsort(&ids[0], maxid, sizeof(int), idsorter);
+ }
+ maxname = virConnectNumOfDefinedDomains(ctl->conn);
+ if (maxname < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list inactive domains"));
+ free(ids);
+ return FALSE;
+ }
+ if (maxname) {
+ names = vshMalloc(ctl, sizeof(char *) * maxname);
+
+ if ((maxname = virConnectListDefinedDomains(ctl->conn, names, maxname)) < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list inactive domains"));
+ free(ids);
+ free(names);
+ return FALSE;
+ }
+
+ qsort(&names[0], maxname, sizeof(char*), namesorter);
+ }
+
+ for (i = 0; i < maxid; i++) {
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ virDomainPtr dom = virDomainLookupByID(ctl->conn, ids[i]);
+ /* this kind of work with domains is not atomic operation */
+ if (!dom)
+ continue;
+ virDomainGetUUIDString(dom, uuid);
+ vshPrint(ctl, "%d\n%s\n%s\n",
+ virDomainGetID(dom),
+ virDomainGetName(dom),
+ uuid);
+ virDomainFree(dom);
+ }
+ for (i = 0; i < maxname; i++) {
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ virDomainPtr dom = virDomainLookupByName(ctl->conn, names[i]);
+
+ /* this kind of work with domains is not atomic operation */
+ if (!dom) {
+ free(names[i]);
+ continue;
+ }
+ virDomainGetUUIDString(dom, uuid);
+ vshPrint(ctl, "%s\n%s\n",
+ virDomainGetName(dom),
+ uuid);
+ virDomainFree(dom);
+ free(names[i]);
+ }
+ free(ids);
+ free(names);
+ return TRUE;
+}
+
+/*
+ * "_compnetworks" command
+ */
+static vshCmdInfo info_compnetwork[] = {
+ {"syntax", "_complete-network"},
+ {"help", gettext_noop("print shell completion data for networks")},
+ {"desc", gettext_noop("Prints data useful for shell autocompletion of networks.")},
+
+ {NULL, NULL}
+};
+
+static vshCmdOptDef opts_compnetwork[] = {
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdCompNetwork(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+ char **activeNames = NULL, **inactiveNames = NULL;
+ int maxactive = 0, maxinactive = 0, i;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ maxactive = virConnectNumOfNetworks(ctl->conn);
+ if (maxactive < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list active networks"));
+ return FALSE;
+ }
+ if (maxactive) {
+ activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);
+
+ if ((maxactive = virConnectListNetworks(ctl->conn, activeNames,
+ maxactive)) < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list active networks"));
+ free(activeNames);
+ return FALSE;
+ }
+
+ qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
+ }
+ maxinactive = virConnectNumOfDefinedNetworks(ctl->conn);
+ if (maxinactive < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list inactive networks"));
+ free(activeNames);
+ return FALSE;
+ }
+ if (maxinactive) {
+ inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive);
+
+ if ((maxinactive = virConnectListDefinedNetworks(ctl->conn, inactiveNames, maxinactive)) < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list inactive networks"));
+ free(activeNames);
+ free(inactiveNames);
+ return FALSE;
+ }
+
+ qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter);
+ }
+
+ for (i = 0; i < maxactive; i++) {
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ virNetworkPtr network = virNetworkLookupByName(ctl->conn, activeNames[i]);
+
+ /* this kind of work with networks is not atomic operation */
+ if (!network) {
+ free(activeNames[i]);
+ continue;
+ }
+ virNetworkGetUUIDString(network, uuid);
+ vshPrint(ctl, "%s\n%s\n",
+ virNetworkGetName(network),
+ uuid);
+ virNetworkFree(network);
+ free(activeNames[i]);
+ }
+ for (i = 0; i < maxinactive; i++) {
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ virNetworkPtr network = virNetworkLookupByName(ctl->conn, inactiveNames[i]);
+
+ /* this kind of work with networks is not atomic operation */
+ if (!network) {
+ free(inactiveNames[i]);
+ continue;
+ }
+ virNetworkGetUUIDString(network, uuid);
+ vshPrint(ctl, "%s\n%s\n",
+ virNetworkGetName(network),
+ uuid);
+
+ virNetworkFree(network);
+ free(inactiveNames[i]);
+ }
+ free(activeNames);
+ free(inactiveNames);
+
+ return TRUE;
+}
+
+
+/*
+ * "_comppools" command
+ */
+static vshCmdInfo info_comppool[] = {
+ {"syntax", "_complete-pool"},
+ {"help", gettext_noop("print shell completion data for pools")},
+ {"desc", gettext_noop("Prints data useful for shell autocompletion of pools.")},
+
+ {NULL, NULL}
+};
+
+static vshCmdOptDef opts_comppool[] = {
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdCompPool(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+ char **activeNames = NULL, **inactiveNames = NULL;
+ int maxactive = 0, maxinactive = 0, i;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ maxactive = virConnectNumOfStoragePools(ctl->conn);
+ if (maxactive < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list active pools"));
+ return FALSE;
+ }
+ if (maxactive) {
+ activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);
+
+ if ((maxactive = virConnectListStoragePools(ctl->conn, activeNames,
+ maxactive)) < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list active pools"));
+ free(activeNames);
+ return FALSE;
+ }
+
+ qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
+ }
+ maxinactive = virConnectNumOfDefinedStoragePools(ctl->conn);
+ if (maxinactive < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list inactive pools"));
+ free(activeNames);
+ return FALSE;
+ }
+ if (maxinactive) {
+ inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive);
+
+ if ((maxinactive = virConnectListDefinedStoragePools(ctl->conn, inactiveNames, maxinactive)) < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list inactive pools"));
+ free(activeNames);
+ free(inactiveNames);
+ return FALSE;
+ }
+
+ qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter);
+ }
+
+ for (i = 0; i < maxactive; i++) {
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ virStoragePoolPtr pool = virStoragePoolLookupByName(ctl->conn, activeNames[i]);
+
+ /* this kind of work with pools is not atomic operation */
+ if (!pool) {
+ free(activeNames[i]);
+ continue;
+ }
+ virStoragePoolGetUUIDString(pool, uuid);
+ vshPrint(ctl, "%s\n%s\n",
+ virStoragePoolGetName(pool),
+ uuid);
+ virStoragePoolFree(pool);
+ free(activeNames[i]);
+ }
+ for (i = 0; i < maxinactive; i++) {
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ virStoragePoolPtr pool = virStoragePoolLookupByName(ctl->conn, inactiveNames[i]);
+
+ /* this kind of work with pools is not atomic operation */
+ if (!pool) {
+ free(inactiveNames[i]);
+ continue;
+ }
+ virStoragePoolGetUUIDString(pool, uuid);
+ vshPrint(ctl, "%s\n%s\n",
+ virStoragePoolGetName(pool),
+ uuid);
+
+ virStoragePoolFree(pool);
+ free(inactiveNames[i]);
+ }
+ free(activeNames);
+ free(inactiveNames);
+
+ return TRUE;
+}
+
+
/*
* "help" command
*/
@@ -355,8 +758,9 @@
vshPrint(ctl, "%s", _("Commands:\n\n"));
for (def = commands; def->name; def++)
- vshPrint(ctl, " %-15s %s\n", def->name,
- N_(vshCmddefGetInfo(def, "help")));
+ if (def->name[0] != '_')
+ vshPrint(ctl, " %-15s %s\n", def->name,
+ N_(vshCmddefGetInfo(def, "help")));
return TRUE;
}
return vshCmddefHelp(ctl, cmdname, FALSE);
@@ -426,7 +830,7 @@
};
static vshCmdOptDef opts_connect[] = {
- {"name", VSH_OT_DATA, 0, gettext_noop("hypervisor connection URI")},
+ {"uri", VSH_OT_DATA, 0, gettext_noop("hypervisor connection URI")},
{"readonly", VSH_OT_BOOL, 0, gettext_noop("read-only connection")},
{NULL, 0, 0, NULL}
};
@@ -446,7 +850,7 @@
}
free(ctl->name);
- ctl->name = vshStrdup(ctl, vshCommandOptString(cmd, "name", NULL));
+ ctl->name = vshStrdup(ctl, vshCommandOptString(cmd, "uri", NULL));
if (!ro) {
ctl->conn = virConnectOpen(ctl->name);
@@ -1004,7 +1408,7 @@
};
static vshCmdOptDef opts_start[] = {
- {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the inactive domain")},
+ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the inactive domain")},
{NULL, 0, 0, NULL}
};
@@ -1017,7 +1421,7 @@
if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
return FALSE;
- if (!(dom = vshCommandOptDomainBy(ctl, cmd, "name", NULL, VSH_BYNAME)))
+ if (!(dom = vshCommandOptDomainBy(ctl, cmd, "domain", NULL, VSH_BYNAME)))
return FALSE;
if (virDomainGetID(dom) != (unsigned int)-1) {
@@ -2650,7 +3054,7 @@
};
static vshCmdOptDef opts_network_start[] = {
- {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the inactive network")},
+ {"network", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the inactive network")},
{NULL, 0, 0, NULL}
};
@@ -2663,7 +3067,7 @@
if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
return FALSE;
- if (!(network = vshCommandOptNetworkBy(ctl, cmd, "name", NULL, VSH_BYNAME)))
+ if (!(network = vshCommandOptNetworkBy(ctl, cmd, "network", NULL, VSH_BYNAME)))
return FALSE;
if (virNetworkCreate(network) == 0) {
@@ -3554,7 +3958,7 @@
};
static vshCmdOptDef opts_pool_start[] = {
- {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the inactive pool")},
+ {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the inactive pool")},
{NULL, 0, 0, NULL}
};
@@ -3567,7 +3971,7 @@
if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
return FALSE;
- if (!(pool = vshCommandOptPoolBy(ctl, cmd, "name", NULL, VSH_BYNAME)))
+ if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, VSH_BYNAME)))
return FALSE;
if (virStoragePoolCreate(pool, 0) == 0) {
@@ -5074,6 +5478,12 @@
* Commands
*/
static vshCmdDef commands[] = {
+ {"_complete-command", cmdCompCommand, opts_compcommand, info_compcommand},
+ {"_complete-uri", cmdCompUri, opts_compuri, info_compuri},
+ {"_complete-domain", cmdCompDomain, opts_compdomain, info_compdomain},
+ {"_complete-network", cmdCompNetwork, opts_compnetwork, info_compnetwork},
+ {"_complete-pool", cmdCompPool, opts_comppool, info_comppool},
+
{"help", cmdHelp, opts_help, info_help},
{"attach-device", cmdAttachDevice, opts_attach_device, info_attach_device},
{"attach-disk", cmdAttachDisk, opts_attach_disk, info_attach_disk},
@@ -6514,6 +6924,18 @@
ret = vshCommandParse(ctl, cmdstr);
free(cmdstr);
+
+ /* Special case 'help' to avoid virConnectOpen */
+ if (ctl->cmd &&
+ ctl->cmd->def &&
+ ctl->cmd->def->name &&
+ (STREQ(ctl->cmd->def->name, "help") ||
+ STREQ(ctl->cmd->def->name, "_complete-command") ||
+ STREQ(ctl->cmd->def->name, "_complete-uri"))) {
+ ret = vshCommandRun(ctl, ctl->cmd);
+ exit(ret ? EXIT_SUCCESS : EXIT_FAILURE);
+ }
+
return ret;
}
return TRUE;
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
16 years, 3 months
[libvirt] auto shutdown for qemu / kvm
by Matthias Pfafferodt
Hello,
there is the possibility to autostart a (qemu/kvm) domain. If libvirtd is
stopped this domain is killed and the filesystem is in a unclean state. I
miss the possible of an 'autostop' option that will shutdown a (qemu/kvm)
domain if libvirtd is stopped.
I changed the init script of my system (opensuse 11.0) to implement
the 'autostop' option. Is there a simpler solution? Do you have tips how to
improve the script?
Matthias
## Path: System/Virtualization
## Description: libvirtd stop configuration
## Type: yesno
## Default: yes
#
# On 'libvirtd stop' all running (kvm) domains are killed. If
# LIBVIRTD_KVM_SHUTDOWN is set to 'yes' all running vm's are given time
# for a gracefully shutdown.
#
LIBVIRTD_KVM_SHUTDOWN="yes"
## Path: System/Virtualization
## Description: libvirtd timeout
## Type: integer
## Default: 300
#
# On 'libvirtd stop' the vm's are ask to shutdown. This optine gives the
# maximum number of seconds the script will wait until libvirt is stopped.
#
LIBVIRTD_KVM_SHUTDOWN_MAXWAIT=300
16 years, 3 months
[libvirt] static address assignment via dnsmasq
by Kurt Sussman
I want my VMs to be assigned static addresses by hostname. I would
prefer to set up a generic way to configure dnsmasq, since I don't think
this is the last thing I'll want to change about address assignment.
I saw this patch from "Mads Chr. Olesen"
https://www.redhat.com/archives/libvir-list/2008-April/msg00327.html
But it seems like a lot of work to give access to only one dnsmasq
option.
I'm working on a patch that enables a dnsmasq.d directory where you can
(optionally) put individual configuration files. I have not fully tested
it yet, so please don't consider this an official submission.
I also don't feel that I have spent enough time with the code to
understand the 'philosphy' if you will, the guiding attitudes. Is the
all-XML approach better according the libvirt developer community
standards? If so, why?
Thanks. Untested patch follows. Please let me know if I'm on the right
path and if not, why.
--Kurt
diff -u /root/libvirt-0.4.4-virgin/src/qemu_driver.c ./qemu_driver.c
--- /root/libvirt-0.4.4-virgin/src/qemu_driver.c 2008-06-12
07:52:53.000000000 -0700
+++ ./qemu_driver.c 2008-07-13 11:31:26.000000000 -0700
@@ -1048,6 +1048,7 @@
1 + /* --bind-interfaces */
2 + /* --pid-file "" */
2 + /* --conf-file "" */
+ 2 + /* --conf-dir DNSMASQCONF_DIR */
/*2 + *//* --interface virbr0 */
2 + /* --except-interface lo */
2 + /* --listen-address 10.0.0.1 */
@@ -1081,6 +1082,9 @@
APPEND_ARG(*argv, i++, "--conf-file");
APPEND_ARG(*argv, i++, "");
+ APPEND_ARG(*argv, i++, "--conf-dir");
+ APPEND_ARG(*argv, i++, DNSMASQCONF_DIR);
+
/*
* XXX does not actually work, due to some kind of
* race condition setting up ipv6 addresses on the
diff -u /root/libvirt-0.4.4-virgin/src/qemu_driver.h ./qemu_driver.h
--- /root/libvirt-0.4.4-virgin/src/qemu_driver.h 2008-04-23
07:19:02.000000000 -0700
+++ ./qemu_driver.h 2008-07-13 11:26:47.000000000 -0700
@@ -33,6 +33,8 @@
int qemudRegister(void);
+#define DNSMASQCONF_DIR SYSCONF_DIR "/dnsmasq.d"
+
#endif /* WITH_QEMU */
#endif /* QEMUD_DRIVER_H */
--
----------------------------------------------------------------------
Merlot Research Group, Inc kls[at]merlot.com
"Quality is free, but only to those who are willing to pay
heavily for it." (Lister, DeMarco: "Peopleware")
16 years, 3 months
[libvirt] PATCH: Refactor LXC to remove some state from lxc_vm_t
by Daniel P. Berrange
I've been working on getting LXC ready to use the common XML routines. One
of the first tasks is finding a way to remove some of the state stored in
the lxc_vm_t struct, so it can be switched over to virDomainObj struct
instead. This patch does some simple re-factoring of the way the TTYs and
control socket are handled to prepare for the switchover.
lxc_conf.c | 1
lxc_conf.h | 10 --
lxc_container.c | 61 +++++++---------
lxc_container.h | 14 +++
lxc_driver.c | 211 ++++++++++++++++----------------------------------------
5 files changed, 103 insertions(+), 194 deletions(-)
Daniel
diff -r 6273f6456bd2 src/lxc_conf.c
--- a/src/lxc_conf.c Sun Jul 13 10:33:25 2008 +0100
+++ b/src/lxc_conf.c Sun Jul 13 11:45:04 2008 +0100
@@ -1041,7 +1041,6 @@
void lxcFreeVM(lxc_vm_t *vm)
{
lxcFreeVMDef(vm->def);
- VIR_FREE(vm->containerTty);
VIR_FREE(vm);
}
diff -r 6273f6456bd2 src/lxc_conf.h
--- a/src/lxc_conf.h Sun Jul 13 10:33:25 2008 +0100
+++ b/src/lxc_conf.h Sun Jul 13 11:45:04 2008 +0100
@@ -35,12 +35,6 @@
#define LXC_MAX_XML_LENGTH 16384
#define LXC_MAX_ERROR_LEN 1024
#define LXC_DOMAIN_TYPE "lxc"
-#define LXC_PARENT_SOCKET 0
-#define LXC_CONTAINER_SOCKET 1
-
-/* messages between parent and container */
-typedef char lxc_message_t;
-#define LXC_CONTINUE_MSG 'c'
/* types of networks for containers */
enum lxc_net_type {
@@ -100,10 +94,6 @@
char ttyPidFile[PATH_MAX];
int parentTty;
- int containerTtyFd;
- char *containerTty;
-
- int sockpair[2];
lxc_vm_def_t *def;
diff -r 6273f6456bd2 src/lxc_container.c
--- a/src/lxc_container.c Sun Jul 13 10:33:25 2008 +0100
+++ b/src/lxc_container.c Sun Jul 13 11:45:04 2008 +0100
@@ -33,7 +33,6 @@
#include <unistd.h>
#include "lxc_container.h"
-#include "lxc_conf.h"
#include "util.h"
#include "memory.h"
#include "veth.h"
@@ -83,7 +82,7 @@
*
* Returns 0 on success or -1 in case of error
*/
-static int lxcSetContainerStdio(const char *ttyName)
+static int lxcSetContainerStdio(const char *ttyPath)
{
int rc = -1;
int ttyfd;
@@ -94,10 +93,10 @@
goto error_out;
}
- ttyfd = open(ttyName, O_RDWR|O_NOCTTY);
+ ttyfd = open(ttyPath, O_RDWR|O_NOCTTY);
if (ttyfd < 0) {
lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
- _("open(%s) failed: %s"), ttyName, strerror(errno));
+ _("open(%s) failed: %s"), ttyPath, strerror(errno));
goto error_out;
}
@@ -106,8 +105,6 @@
_("ioctl(TIOCSTTY) failed: %s"), strerror(errno));
goto cleanup;
}
-
- close(0); close(1); close(2);
if (dup2(ttyfd, 0) < 0) {
lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
@@ -144,12 +141,18 @@
*
* Returns 0 on success or -1 in case of error
*/
-static int lxcExecWithTty(lxc_vm_t *vm)
+static int lxcExecWithTty(lxc_vm_def_t *vmDef, char *ttyPath)
{
int rc = -1;
- lxc_vm_def_t *vmDef = vm->def;
+ int open_max, i;
- if(lxcSetContainerStdio(vm->containerTty) < 0) {
+ /* Just in case someone forget to set FD_CLOEXEC, explicitly
+ * close all FDs before executing the container */
+ open_max = sysconf (_SC_OPEN_MAX);
+ for (i = 0; i < open_max; i++)
+ close(i);
+
+ if(lxcSetContainerStdio(ttyPath) < 0) {
goto exit_with_error;
}
@@ -161,7 +164,7 @@
/**
* lxcWaitForContinue:
- * @vm: Pointer to vm structure
+ * @monitor: monitor FD from parent
*
* This function will wait for the container continue message from the
* parent process. It will send this message on the socket pair stored in
@@ -169,31 +172,23 @@
*
* Returns 0 on success or -1 in case of error
*/
-static int lxcWaitForContinue(lxc_vm_t *vm)
+static int lxcWaitForContinue(int monitor)
{
- int rc = -1;
lxc_message_t msg;
int readLen;
- readLen = saferead(vm->sockpair[LXC_CONTAINER_SOCKET], &msg, sizeof(msg));
- if (readLen != sizeof(msg)) {
+ readLen = saferead(monitor, &msg, sizeof(msg));
+ if (readLen != sizeof(msg) ||
+ msg != LXC_CONTINUE_MSG) {
lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
_("Failed to read the container continue message: %s"),
strerror(errno));
- goto error_out;
+ return -1;
}
DEBUG0("Received container continue message");
- close(vm->sockpair[LXC_PARENT_SOCKET]);
- vm->sockpair[LXC_PARENT_SOCKET] = -1;
- close(vm->sockpair[LXC_CONTAINER_SOCKET]);
- vm->sockpair[LXC_CONTAINER_SOCKET] = -1;
-
- rc = 0;
-
-error_out:
- return rc;
+ return 0;
}
/**
@@ -204,12 +199,12 @@
*
* Returns 0 on success or nonzero in case of error
*/
-static int lxcEnableInterfaces(const lxc_vm_t *vm)
+static int lxcEnableInterfaces(const lxc_vm_def_t *def)
{
int rc = 0;
const lxc_net_def_t *net;
- for (net = vm->def->nets; net; net = net->next) {
+ for (net = def->nets; net; net = net->next) {
DEBUG("Enabling %s", net->containerVeth);
rc = vethInterfaceUpOrDown(net->containerVeth, 1);
if (0 != rc) {
@@ -218,7 +213,7 @@
}
/* enable lo device only if there were other net devices */
- if (vm->def->nets)
+ if (def->nets)
rc = vethInterfaceUpOrDown("lo", 1);
error_out:
@@ -237,11 +232,11 @@
*
* Returns 0 on success or -1 in case of error
*/
-int lxcChild( void *argv )
+int lxcChild( void *data )
{
int rc = -1;
- lxc_vm_t *vm = (lxc_vm_t *)argv;
- lxc_vm_def_t *vmDef = vm->def;
+ lxc_child_argv_t *argv = data;
+ lxc_vm_def_t *vmDef = argv->config;
lxc_mount_t *curMount;
int i;
@@ -278,16 +273,16 @@
}
/* Wait for interface devices to show up */
- if (0 != (rc = lxcWaitForContinue(vm))) {
+ if (0 != (rc = lxcWaitForContinue(argv->monitor))) {
goto cleanup;
}
/* enable interfaces */
- if (0 != (rc = lxcEnableInterfaces(vm))) {
+ if (0 != (rc = lxcEnableInterfaces(vmDef))) {
goto cleanup;
}
- rc = lxcExecWithTty(vm);
+ rc = lxcExecWithTty(vmDef, argv->ttyPath);
/* this function will only return if an error occured */
cleanup:
diff -r 6273f6456bd2 src/lxc_container.h
--- a/src/lxc_container.h Sun Jul 13 10:33:25 2008 +0100
+++ b/src/lxc_container.h Sun Jul 13 11:45:04 2008 +0100
@@ -24,7 +24,21 @@
#ifndef LXC_CONTAINER_H
#define LXC_CONTAINER_H
+#include "lxc_conf.h"
+
#ifdef WITH_LXC
+
+typedef struct __lxc_child_argv lxc_child_argv_t;
+struct __lxc_child_argv {
+ lxc_vm_def_t *config;
+ int monitor;
+ char *ttyPath;
+};
+
+/* messages between parent and container */
+typedef char lxc_message_t;
+#define LXC_CONTINUE_MSG 'c'
+
/* Function declarations */
int lxcChild( void *argv );
diff -r 6273f6456bd2 src/lxc_driver.c
--- a/src/lxc_driver.c Sun Jul 13 10:33:25 2008 +0100
+++ b/src/lxc_driver.c Sun Jul 13 11:45:04 2008 +0100
@@ -561,27 +561,23 @@
/**
* lxcSendContainerContinue:
- * @vm: pointer to virtual machine structure
+ * @monitor: FD for communicating with child
*
* Sends the continue message via the socket pair stored in the vm
* structure.
*
* Returns 0 on success or -1 in case of error
*/
-static int lxcSendContainerContinue(const lxc_vm_t *vm)
+static int lxcSendContainerContinue(virConnectPtr conn,
+ int monitor)
{
int rc = -1;
lxc_message_t msg = LXC_CONTINUE_MSG;
int writeCount = 0;
- if (NULL == vm) {
- goto error_out;
- }
-
- writeCount = safewrite(vm->sockpair[LXC_PARENT_SOCKET], &msg,
- sizeof(msg));
+ writeCount = safewrite(monitor, &msg, sizeof(msg));
if (writeCount != sizeof(msg)) {
- lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
_("unable to send container continue message: %s"),
strerror(errno));
goto error_out;
@@ -605,12 +601,15 @@
*/
static int lxcStartContainer(virConnectPtr conn,
lxc_driver_t* driver,
- lxc_vm_t *vm)
+ lxc_vm_t *vm,
+ int monitor,
+ char *ttyPath)
{
int rc = -1;
int flags;
int stacksize = getpagesize() * 4;
char *stack, *stacktop;
+ lxc_child_argv_t args = { vm->def, monitor, ttyPath };
/* allocate a stack for the container */
if (VIR_ALLOC_N(stack, stacksize) < 0) {
@@ -625,7 +624,7 @@
if (vm->def->nets != NULL)
flags |= CLONE_NEWNET;
- vm->def->id = clone(lxcChild, stacktop, flags, (void *)vm);
+ vm->def->id = clone(lxcChild, stacktop, flags, &args);
DEBUG("clone() returned, %d", vm->def->id);
@@ -643,117 +642,9 @@
return rc;
}
-/**
- * lxcPutTtyInRawMode:
- * @conn: pointer to connection
- * @ttyDev: file descriptor for tty
- *
- * Sets tty attributes via cfmakeraw()
- *
- * Returns 0 on success or -1 in case of error
- */
-static int lxcPutTtyInRawMode(virConnectPtr conn, int ttyDev)
-{
- int rc = -1;
-
- struct termios ttyAttr;
-
- if (tcgetattr(ttyDev, &ttyAttr) < 0) {
- lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
- "tcgetattr() failed: %s", strerror(errno));
- goto cleanup;
- }
-
- cfmakeraw(&ttyAttr);
-
- if (tcsetattr(ttyDev, TCSADRAIN, &ttyAttr) < 0) {
- lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
- "tcsetattr failed: %s", strerror(errno));
- goto cleanup;
- }
-
- rc = 0;
-
-cleanup:
- return rc;
-}
/**
- * lxcSetupTtyTunnel:
- * @conn: pointer to connection
- * @vmDef: pointer to virtual machine definition structure
- * @ttyDev: pointer to int. On success will be set to fd for master
- * end of tty
- *
- * Opens and configures the parent side tty
- *
- * Returns 0 on success or -1 in case of error
- */
-static int lxcSetupTtyTunnel(virConnectPtr conn,
- lxc_vm_def_t *vmDef,
- int* ttyDev)
-{
- int rc = -1;
- char *ptsStr;
-
- if (0 < strlen(vmDef->tty)) {
- *ttyDev = posix_openpt(O_RDWR|O_NOCTTY|O_NONBLOCK);
- if (*ttyDev < 0) {
- lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
- "open() tty failed: %s", strerror(errno));
- goto setup_complete;
- }
-
- rc = grantpt(*ttyDev);
- if (rc < 0) {
- lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
- "grantpt() failed: %s", strerror(errno));
- goto setup_complete;
- }
-
- rc = unlockpt(*ttyDev);
- if (rc < 0) {
- lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
- "unlockpt() failed: %s", strerror(errno));
- goto setup_complete;
- }
-
- /* get the name and print it to stdout */
- ptsStr = ptsname(*ttyDev);
- if (ptsStr == NULL) {
- lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
- "ptsname() failed");
- goto setup_complete;
- }
- /* This value needs to be stored in the container configuration file */
- VIR_FREE(vmDef->tty);
- if (!(vmDef->tty = strdup(ptsStr))) {
- lxcError(conn, NULL, VIR_ERR_NO_MEMORY,
- _("unable to get storage for vm tty name"));
- goto setup_complete;
- }
-
- /* Enter raw mode, so all characters are passed directly to child */
- if (lxcPutTtyInRawMode(conn, *ttyDev) < 0) {
- goto setup_complete;
- }
-
- } else {
- *ttyDev = -1;
- }
-
- rc = 0;
-
-setup_complete:
- if((0 != rc) && (*ttyDev > 0)) {
- close(*ttyDev);
- }
-
- return rc;
-}
-
-/**
- * lxcSetupContainerTty:
+ * lxcOpenTty:
* @conn: pointer to connection
* @ttymaster: pointer to int. On success, set to fd for master end
* @ttyName: On success, will point to string slave end of tty. Caller
@@ -763,12 +654,12 @@
*
* Returns 0 on success or -1 in case of error
*/
-static int lxcSetupContainerTty(virConnectPtr conn,
- int *ttymaster,
- char **ttyName)
+static int lxcOpenTty(virConnectPtr conn,
+ int *ttymaster,
+ char **ttyName,
+ int rawmode)
{
int rc = -1;
- char tempTtyName[PATH_MAX];
*ttymaster = posix_openpt(O_RDWR|O_NOCTTY|O_NONBLOCK);
if (*ttymaster < 0) {
@@ -783,27 +674,43 @@
goto cleanup;
}
- if (0 != ptsname_r(*ttymaster, tempTtyName, sizeof(tempTtyName))) {
- lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
- _("ptsname_r failed: %s"), strerror(errno));
- goto cleanup;
+ if (rawmode) {
+ struct termios ttyAttr;
+ if (tcgetattr(*ttymaster, &ttyAttr) < 0) {
+ lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+ "tcgetattr() failed: %s", strerror(errno));
+ goto cleanup;
+ }
+
+ cfmakeraw(&ttyAttr);
+
+ if (tcsetattr(*ttymaster, TCSADRAIN, &ttyAttr) < 0) {
+ lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+ "tcsetattr failed: %s", strerror(errno));
+ goto cleanup;
+ }
}
- if (VIR_ALLOC_N(*ttyName, strlen(tempTtyName) + 1) < 0) {
- lxcError(conn, NULL, VIR_ERR_NO_MEMORY,
- _("unable to allocate container name string"));
- goto cleanup;
+ if (ttyName) {
+ char tempTtyName[PATH_MAX];
+ if (0 != ptsname_r(*ttymaster, tempTtyName, sizeof(tempTtyName))) {
+ lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("ptsname_r failed: %s"), strerror(errno));
+ goto cleanup;
+ }
+
+ if ((*ttyName = strdup(tempTtyName)) == NULL) {
+ lxcError(conn, NULL, VIR_ERR_NO_MEMORY, NULL);
+ goto cleanup;
+ }
}
-
- strcpy(*ttyName, tempTtyName);
rc = 0;
cleanup:
- if (0 != rc) {
- if (-1 != *ttymaster) {
- close(*ttymaster);
- }
+ if (rc != 0 &&
+ *ttymaster != -1) {
+ close(*ttymaster);
}
return rc;
@@ -989,15 +896,18 @@
lxc_vm_t * vm)
{
int rc = -1;
- lxc_vm_def_t *vmDef = vm->def;
+ int sockpair[2];
+ int containerTty;
+ char *containerTtyPath = NULL;
/* open parent tty */
- if (lxcSetupTtyTunnel(conn, vmDef, &vm->parentTty) < 0) {
+ VIR_FREE(vm->def->tty);
+ if (lxcOpenTty(conn, &vm->parentTty, &vm->def->tty, 1) < 0) {
goto cleanup;
}
/* open container tty */
- if (lxcSetupContainerTty(conn, &(vm->containerTtyFd), &(vm->containerTty)) < 0) {
+ if (lxcOpenTty(conn, &containerTty, &containerTtyPath, 0) < 0) {
goto cleanup;
}
@@ -1011,7 +921,7 @@
if (vm->pid == 0) {
/* child process calls forward routine */
- lxcTtyForward(vm->parentTty, vm->containerTtyFd);
+ lxcTtyForward(vm->parentTty, containerTty);
}
if (lxcStoreTtyPid(driver, vm)) {
@@ -1019,7 +929,7 @@
}
close(vm->parentTty);
- close(vm->containerTtyFd);
+ close(containerTty);
if (0 != (rc = lxcSetupInterfaces(conn, vm))) {
goto cleanup;
@@ -1027,7 +937,7 @@
/* create a socket pair to send continue message to the container once */
/* we've completed the post clone configuration */
- if (0 != socketpair(PF_UNIX, SOCK_STREAM, 0, vm->sockpair)) {
+ if (0 != socketpair(PF_UNIX, SOCK_STREAM, 0, sockpair)) {
lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
_("sockpair failed: %s"), strerror(errno));
goto cleanup;
@@ -1035,7 +945,9 @@
/* check this rc */
- rc = lxcStartContainer(conn, driver, vm);
+ rc = lxcStartContainer(conn, driver, vm,
+ sockpair[1],
+ containerTtyPath);
if (rc != 0)
goto cleanup;
@@ -1043,7 +955,7 @@
if (rc != 0)
goto cleanup;
- rc = lxcSendContainerContinue(vm);
+ rc = lxcSendContainerContinue(conn, sockpair[0]);
if (rc != 0)
goto cleanup;
@@ -1052,10 +964,9 @@
driver->nactivevms++;
cleanup:
- close(vm->sockpair[LXC_PARENT_SOCKET]);
- vm->sockpair[LXC_PARENT_SOCKET] = -1;
- close(vm->sockpair[LXC_CONTAINER_SOCKET]);
- vm->sockpair[LXC_CONTAINER_SOCKET] = -1;
+ close(sockpair[0]);
+ close(sockpair[1]);
+ VIR_FREE(containerTtyPath);
return rc;
}
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
16 years, 3 months
[libvirt] save / restore for KVM
by Matthias Pfafferodt
Hello,
I try to save a KVM domain which has its hard disk on a LVM volume. I can
execute the command to save the domain but restore fails
# virsh list
Id Name State
----------------------------------
3 kvm-linux03 running
4 kvm-linux01 running
# virsh save kvm-linux01 ./kvm-linux01.ram
Domain kvm-linux01 saved to ./kvm-linux01.ram
# virsh list
Id Name State
----------------------------------
3 kvm-linux03 running
# virsh restore ./kvm-linux01.ram
libvir: QEMU error : operation failed: failed to start VM
error: Failed to restore domain from ./kvm-linux01.ram
I tried to save and restore this domain using kvm directly
# /usr/bin/qemu-kvm -m 1024 -boot c -drive
file=/dev/virtual/kvm_linux01,if=ide,index=0,boot=on -net
nic,macaddr=00:16:3e:00:01:02,vlan=0 -net
tap,fd=24,script=,vlan=0,ifname=vnet3
(qemu) savevm kvm-linux01.ram
Device id0-hd0 does not support VM state snapshots
(qemu)
Here I get an error message which I also found on the qemu homepage: to save a
qemu vm the hard disk must be a file using the qcow format. But in the libvirt
documentation there is no hint to this limitation. Is it possible to save the
state of a kvm vm using physical hard disks with libvirt?
Kind regards
Matthias Pfafferodt
--
Matthias Pfafferodt - http://www.mapfa.de
Matthias.Pfafferodt <at> mapfa.de
16 years, 3 months
[libvirt] [PATCH] default URI in probe
by Evgeniy Sokolov
I specified default URI in probe().
To use libvirt with OpenVZ:
# ./configure --with-openvz
# make
# ./src/virsh list
Id Name State
----------------------------------
33 33 running
105 105 running
108 108 running
16 years, 3 months