This new virsh command uses the new virNetworkUpdate() API to modify
an existing network definition, and optionally have those
modifications take effect immediately without restarting the network.
An example usage:
virsh net-update add-last ip-dhcp-host \
--xml "<host mac='00:11:22:33:44:55'
ip='192.168.122.45'/>" \
--live --config
If you like, you can instead put the xml into a file, and call like
this:
virsh net-update add-last ip-dhcp-host \
--file "<host mac='00:11:22:33:44:55'
ip='192.168.122.45'/>" \
--live --config
(or just leave out the "--file", since that is the default).
--live, --config, and --current options - if you specify --live, only
the live state of the network will be updated. If you also specify
--config, then the persistent configuration will also be updated;
these two commands can be given separately, or both together. If you
don't specify either (you can optionally specify "--current" for the
same effect), then the "current" config will be updated (i.e. if the
network is active, then only its live config is affected, but if the
network is inactive, only the persistent config is affected).
A --parent-index option is also available (to give the index within a
list of parent objects, e.g. the index of the parent <ip> element when
updating ip-dhcp-host elements), but is optional and at least for now
will probably be used rarely.
---
tools/virsh-network.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 158 insertions(+)
diff --git a/tools/virsh-network.c b/tools/virsh-network.c
index 2c32a78..64be260 100644
--- a/tools/virsh-network.c
+++ b/tools/virsh-network.c
@@ -737,6 +737,163 @@ 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, delete, or modify)")},
+ {"section", VSH_OT_DATA, VSH_OFLAG_REQ,
+ N_("which section of network configuration to update")},
+ {"xml", VSH_OT_BOOL, 0, N_("xml is specified directly on
commandline")},
+ {"file", VSH_OT_BOOL, 0, N_("file containing xml is specified on
commandline")},
+ {"xmldata", VSH_OT_DATA, VSH_OFLAG_REQ,
+ N_("complete xml element (or name of file containing xml) 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 *xmldata = NULL;
+ char *xmldataFromFile = NULL;
+ bool isFile = vshCommandOptBool(cmd, "file");
+ bool isXml = vshCommandOptBool(cmd, "xml");
+ 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;
+ }
+ 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 "xmldata"
+ * string. This can either be directly given with the --xml
+ * option, or indirectly with the --file option (default,
+ * indicates that the xmldata on the commandline is really the
+ * name of a file whose contents are the desired xml).
+ */
+
+ if (!isXml)
+ isFile = true;
+ if (isXml && isFile) {
+ vshError(ctl, "%s", _("you can specify file (default) or xml,
"
+ "but not both"));
+ goto cleanup;
+ }
+ if (vshCommandOptString(cmd, "xmldata", (const char **)&xmldata) <
0) {
+ vshError(ctl, "%s", _("malformed xmldata argument"));
+ goto cleanup;
+ }
+
+ if (isFile) {
+ /* contents of xmldata is actually the name of a file that
+ * contains the xml.
+ */
+ if (virFileReadAll(xmldata, VSH_MAX_XML_FILE, &xmldataFromFile) < 0)
+ return false;
+ /* NB: the original xmldata is freed by the vshCommand
+ * infrastructure, so it's safe to lose its pointer here.
+ */
+ xmldata = xmldataFromFile;
+ }
+
+ 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, xmldata, flags) < 0) {
+ vshError(ctl, _("Failed to update network %s"),
+ virNetworkGetName(network));
+ goto cleanup;
+ }
+
+ if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
+ if (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE)
+ affected = _("persistent config and live state");
+ else
+ affected = _("persistent config");
+ } else if (flags & VIR_NETWORK_UPDATE_AFFECT_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:
+ virNetworkFree(network);
+ VIR_FREE(xmldataFromFile);
+ return ret;
+}
+
+/*
* "net-uuid" command
*/
static const vshCmdInfo info_network_uuid[] = {
@@ -854,6 +1011,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}
};
--
1.7.11.4