aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/virsh-network.c155
-rw-r--r--tools/virsh.pod39
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", &sectionStr) < 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