diff options
-rw-r--r-- | tools/virsh-network.c | 155 | ||||
-rw-r--r-- | tools/virsh.pod | 39 |
2 files changed, 194 insertions, 0 deletions
diff --git a/tools/virsh-network.c b/tools/virsh-network.c index 68b9db7a9..6005e5bfb 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -737,6 +737,160 @@ cmdNetworkUndefine(vshControl *ctl, const vshCmd *cmd) } /* + * "net-update" command + */ +static const vshCmdInfo info_network_update[] = { + {"help", N_("update parts of an existing network's configuration")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_network_update[] = { + {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")}, + {"command", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("type of update (add-first, add-last (add), delete, or modify)")}, + {"section", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("which section of network configuration to update")}, + {"xml", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("name of file containing xml (or, if it starts with '<', the complete " + "xml element itself) to add/modify, or to be matched for search")}, + {"parent-index", VSH_OT_INT, 0, N_("which parent object to search through")}, + {"config", VSH_OT_BOOL, 0, N_("affect next boot")}, + {"live", VSH_OT_BOOL, 0, N_("affect running domain")}, + {"current", VSH_OT_BOOL, 0, N_("affect current domain")}, + {NULL, 0, 0, NULL} +}; + +VIR_ENUM_DECL(virNetworkUpdateCommand) +VIR_ENUM_IMPL(virNetworkUpdateCommand, VIR_NETWORK_UPDATE_COMMAND_LAST, + "none", "modify", "delete", "add-last", "add-first"); + +VIR_ENUM_DECL(virNetworkSection) +VIR_ENUM_IMPL(virNetworkSection, VIR_NETWORK_SECTION_LAST, + "none", "bridge", "domain", "ip", "ip-dhcp-host", + "ip-dhcp-range", "forward", "forward-interface", + "forward-pf", "portgroup", "dns-host", "dns-txt", + "dns-srv"); + +static bool +cmdNetworkUpdate(vshControl *ctl, const vshCmd *cmd) +{ + bool ret = false; + virNetworkPtr network; + const char *commandStr = NULL; + const char *sectionStr = NULL; + int command, section, parentIndex = -1; + const char *xml = NULL; + char *xmlFromFile = NULL; + bool current = vshCommandOptBool(cmd, "current"); + bool config = vshCommandOptBool(cmd, "config"); + bool live = vshCommandOptBool(cmd, "live"); + unsigned int flags = 0; + const char *affected; + + if (!(network = vshCommandOptNetwork(ctl, cmd, NULL))) + goto cleanup; + + if (vshCommandOptString(cmd, "command", &commandStr) < 0) { + vshError(ctl, "%s", _("missing or malformed command argument")); + goto cleanup; + } + + if (STREQ(commandStr, "add")) { + /* "add" is a synonym for "add-last" */ + command = VIR_NETWORK_UPDATE_COMMAND_ADD_LAST; + } else { + command = virNetworkUpdateCommandTypeFromString(commandStr); + if (command <= 0 || command >= VIR_NETWORK_UPDATE_COMMAND_LAST) { + vshError(ctl, _("unrecognized command name '%s'"), commandStr); + goto cleanup; + } + } + + if (vshCommandOptString(cmd, "section", §ionStr) < 0) { + vshError(ctl, "%s", _("missing or malformed section argument")); + goto cleanup; + } + section = virNetworkSectionTypeFromString(sectionStr); + if (section <= 0 || section >= VIR_NETWORK_SECTION_LAST) { + vshError(ctl, _("unrecognized section name '%s'"), sectionStr); + goto cleanup; + } + + if (vshCommandOptInt(cmd, "parent-index", &parentIndex) < 0) { + vshError(ctl, "%s", _("malformed parent-index argument")); + goto cleanup; + } + + /* The goal is to have a full xml element in the "xml" + * string. This is provided in the --xml option, either directly + * (detected by the first character being "<"), or indirectly by + * supplying a filename (first character isn't "<") that contains + * the desired xml. + */ + + if (vshCommandOptString(cmd, "xml", &xml) < 0) { + vshError(ctl, "%s", _("malformed or missing xml argument")); + goto cleanup; + } + + if (*xml != '<') { + /* contents of xmldata is actually the name of a file that + * contains the xml. + */ + if (virFileReadAll(xml, VSH_MAX_XML_FILE, &xmlFromFile) < 0) + goto cleanup; + /* NB: the original xml is just a const char * that points + * to a string owned by the vshCmd object, and will be freed + * by vshCommandFree, so it's safe to lose its pointer here. + */ + xml = xmlFromFile; + } + + if (current) { + if (live || config) { + vshError(ctl, "%s", _("--current must be specified exclusively")); + return false; + } + flags |= VIR_NETWORK_UPDATE_AFFECT_CURRENT; + } else { + if (config) + flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG; + if (live) + flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE; + } + + if (virNetworkUpdate(network, command, + section, parentIndex, xml, flags) < 0) { + vshError(ctl, _("Failed to update network %s"), + virNetworkGetName(network)); + goto cleanup; + } + + if (config) { + if (live) + affected = _("persistent config and live state"); + else + affected = _("persistent config"); + } else if (live) { + affected = _("live state"); + } else if (virNetworkIsActive(network)) { + affected = _("live state"); + } else { + affected = _("persistent config"); + } + + vshPrint(ctl, _("Updated network %s %s"), + virNetworkGetName(network), affected); + ret = true; +cleanup: + vshReportError(ctl); + virNetworkFree(network); + VIR_FREE(xmlFromFile); + return ret; +} + +/* * "net-uuid" command */ static const vshCmdInfo info_network_uuid[] = { @@ -854,6 +1008,7 @@ const vshCmdDef networkCmds[] = { {"net-start", cmdNetworkStart, opts_network_start, info_network_start, 0}, {"net-undefine", cmdNetworkUndefine, opts_network_undefine, info_network_undefine, 0}, + {"net-update", cmdNetworkUpdate, opts_network_update, info_network_update, 0}, {"net-uuid", cmdNetworkUuid, opts_network_uuid, info_network_uuid, 0}, {NULL, NULL, NULL, NULL, 0} }; diff --git a/tools/virsh.pod b/tools/virsh.pod index 4a79e12d0..2120429bf 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -2006,6 +2006,45 @@ Undefine the configuration for an inactive network. Convert a network name to network UUID. +=item B<net-update> I<network> I<command> I<section> I<xml> + [I<--parent-index> I<index>] [[I<--live>] [I<--config>] | [I<--current>]] + +Update the given section of an existing network definition, with the +changes optionally taking effect immediately, without needing to +destroy and re-start the network. + +I<command> is one of "add-first", "add-last", "add" (a synonym for +add-last), "delete", or "modify". + +I<section> is one of ""bridge", "domain", "ip", "ip-dhcp-host", +"ip-dhcp-range", "forward", "forward-interface", "forward-pf", +"portgroup", "dns-host", "dns-txt", or "dns-srv", each section being +named by a concatenation of the xml element hierarchy leading to the +element being changed. For example, "ip-dhcp-host" will change a +<host> element that is contained inside a <dhcp> element inside an +<ip> element of the network. + +I<xml> is either the text of a complete xml element of the type being +changed (e.g. "<host mac="00:11:22:33:44:55' ip='1.2.3.4'/>", or the +name of a file that contains a complete xml element. Disambiguation is +done by looking at the first character of the provided text - if the +first character is "<", it is xml text, if the first character is not +"<", it is the name of a file that contains the xml text to be used. + +The I<--parent-index> option is used to specify which of several +parent elements the requested element is in (0-based). For example, a +dhcp <host> element could be in any one of multiple <ip> elements in +the network; if a parent-index isn't provided, the "most appropriate" +<ip> element will be selected (usually the only one that already has a +<dhcp> element), but if I<--parent-index> is given, that particular +instance of <ip> will get the modification. + +If I<--live> is specified, affect a running guest. +If I<--config> is specified, affect the next boot of a persistent guest. +If I<--current> is specified, affect the current guest state. +Both I<--live> and I<--config> flags may be given, but I<--current> is +exclusive. Not specifying any flag is the same as specifying I<--current>. + =back =head1 INTERFACE COMMANDS |