ping, it's been a while since i have put this out.

On Sat, 16 Mar 2024 at 01:51, Abhiram Tilak <[email protected]> wrote:

> The current way of updating a network configuration uses `virsh
> net-update` to add, delete or modify entries. But with such a mechansim
> one should know if an entry with current info already exists. Adding
> modify-or-add option automatically performs either modify or add
> depending on the current state.
>
> Fixes: https://gitlab.com/libvirt/libvirt/-/issues/363
> Signed-off-by: Abhiram Tilak <[email protected]>
> ---
>  docs/manpages/virsh.rst           |   5 +-
>  include/libvirt/libvirt-network.h |   2 +
>  src/conf/network_conf.c           | 148 ++++++++++++++++++++++++------
>  tools/virsh-network.c             |   4 +-
>  4 files changed, 126 insertions(+), 33 deletions(-)
>
> diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
> index 115b802c45..dc91ba895c 100644
> --- a/docs/manpages/virsh.rst
> +++ b/docs/manpages/virsh.rst
> @@ -5908,7 +5908,10 @@ changes optionally taking effect immediately,
> without needing to
>  destroy and re-start the network.
>
>  *command* is one of "add-first", "add-last", "add" (a synonym for
> -add-last), "delete", or "modify".
> +add-last), "delete", "modify", "modify-or-add" (modify + add-last),
> +"modify-or-add-first". The 'modify-or-add' commands perform modify or
> +add operation depending on the given state, and can be useful for
> +scripting.
>
>  *section* is one of "bridge", "domain", "ip", "ip-dhcp-host",
>  "ip-dhcp-range", "forward", "forward-interface", "forward-pf",
> diff --git a/include/libvirt/libvirt-network.h
> b/include/libvirt/libvirt-network.h
> index 58591be7ac..a6e132f407 100644
> --- a/include/libvirt/libvirt-network.h
> +++ b/include/libvirt/libvirt-network.h
> @@ -181,6 +181,8 @@ typedef enum {
>      VIR_NETWORK_UPDATE_COMMAND_DELETE    = 2, /* delete an existing
> element (Since: 0.10.2) */
>      VIR_NETWORK_UPDATE_COMMAND_ADD_LAST  = 3, /* add an element at end of
> list (Since: 0.10.2) */
>      VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST = 4, /* add an element at start
> of list (Since: 0.10.2) */
> +    VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_LAST = 5, /* if exists
> modify or add an element at end of list (Since: 0.10.2) */
> +    VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_FIRST = 6, /* if exists
> modify or add an element at start of list (Since: 0.10.2) */
>  # ifdef VIR_ENUM_SENTINELS
>      VIR_NETWORK_UPDATE_COMMAND_LAST /* (Since: 0.10.2) */
>  # endif
> diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
> index cc92ed0b03..2835395385 100644
> --- a/src/conf/network_conf.c
> +++ b/src/conf/network_conf.c
> @@ -2721,6 +2721,9 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDef *def,
>      virNetworkDHCPHostDef host = { 0 };
>      bool partialOkay = (command == VIR_NETWORK_UPDATE_COMMAND_DELETE);
>
> +    /* added for modify-or-add feature */
> +    bool modified = false;
> +
>      if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "host") < 0)
>          goto cleanup;
>
> @@ -2826,7 +2829,34 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDef *def,
>          virNetworkDHCPHostDefClear(&ipdef->hosts[i]);
>          VIR_DELETE_ELEMENT(ipdef->hosts, i, ipdef->nhosts);
>
> -    } else {
> +    } else if ((command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_LAST)
> ||
> +               (command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_FIRST)) {
> +
> +        /* find entries with matching name/address/ip */
> +        for (i = 0; i < ipdef->nhosts; i++) {
> +            if ((host.mac && ipdef->hosts[i].mac &&
> +                 !virMacAddrCompare(host.mac, ipdef->hosts[i].mac)) ||
> +                (host.name &&
> +                 STREQ_NULLABLE(host.name, ipdef->hosts[i].name)) ||
> +                (VIR_SOCKET_ADDR_VALID(&host.ip) &&
> +                 virSocketAddrEqual(&host.ip, &ipdef->hosts[i].ip))) {
> +
> +                modified = true;
> +                break;
> +            }
> +        }
> +
> +        /* if element is found then modify, or else add to beginning/end
> of list */
> +        if (modified) {
> +            virNetworkDHCPHostDefClear(&ipdef->hosts[i]);
> +            ipdef->hosts[i] = host;
> +            memset(&host, 0, sizeof(host));
> +        } else if (VIR_INSERT_ELEMENT(ipdef->hosts,
> +                        command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_FIRST
> +                        ? 0 : ipdef->nhosts,
> +                        ipdef->nhosts, host) < 0)
> +            goto cleanup;
> +    } else  {
>          virNetworkDefUpdateUnknownCommand(command);
>          goto cleanup;
>      }
> @@ -2885,7 +2915,9 @@ virNetworkDefUpdateIPDHCPRange(virNetworkDef *def,
>      }
>
>      if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) ||
> -        (command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST)) {
> +        (command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST) ||
> +        (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_LAST) ||
> +        (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_FIRST)) {
>
>          if (virNetworkDefUpdateCheckMultiDHCP(def, ipdef) < 0)
>              return -1;
> @@ -2894,17 +2926,24 @@ virNetworkDefUpdateIPDHCPRange(virNetworkDef *def,
>              g_autofree char *startip =
> virSocketAddrFormat(&range.addr.start);
>              g_autofree char *endip = virSocketAddrFormat(&range.addr.end);
>
> -            virReportError(VIR_ERR_OPERATION_INVALID,
> -                           _("there is an existing dhcp range entry in
> network '%1$s' that matches \"<range start='%2$s' end='%3$s'/>\""),
> -                           def->name,
> -                           startip ? startip : "unknown",
> -                           endip ? endip : "unknown");
> +
> +            if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) ||
> +                (command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST))
> +                virReportError(VIR_ERR_OPERATION_INVALID,
> +                               _("there is an existing dhcp range entry
> in network '%1$s' that matches \"<range start='%2$s' end='%3$s'/>\""),
> +                               def->name,
> +                               startip ? startip : "unknown",
> +                               endip ? endip : "unknown");
> +            else
> +                virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
> +                               _("dhcp ranges cannot be modified, only
> added or deleted"));
>              return -1;
>          }
>
>          /* add to beginning/end of list */
>          if (VIR_INSERT_ELEMENT(ipdef->ranges,
> -                               command ==
> VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST
> +                               (command ==
> VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST ||
> +                                command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_FIRST)
>                                 ? 0 : ipdef->nranges,
>                                 ipdef->nranges, range) < 0)
>              return -1;
> @@ -2981,18 +3020,26 @@ virNetworkDefUpdateForwardInterface(virNetworkDef
> *def,
>      }
>
>      if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) ||
> -        (command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST)) {
> +        (command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST) ||
> +        (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_LAST) ||
> +        (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_FIRST)) {
>
>          if (i < def->forward.nifs) {
> -            virReportError(VIR_ERR_OPERATION_INVALID,
> -                           _("there is an existing interface entry in
> network '%1$s' that matches \"<interface dev='%2$s'>\""),
> -                           def->name, iface.device.dev);
> +            if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST) ||
> +                command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST)
> +                virReportError(VIR_ERR_OPERATION_INVALID,
> +                               _("there is an existing interface entry in
> network '%1$s' that matches \"<interface dev='%2$s'>\""),
> +                               def->name, iface.device.dev);
> +            else
> +                virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
> +                               _("forward interface entries cannot be
> modified, only added or deleted"));
>              goto cleanup;
>          }
>
>          /* add to beginning/end of list */
>          if (VIR_INSERT_ELEMENT(def->forward.ifs,
> -                               command ==
> VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST
> +                               (command ==
> VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST ||
> +                                command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_FIRST)
>                                 ? 0 : def->forward.nifs,
>                                 def->forward.nifs, iface) < 0)
>              goto cleanup;
> @@ -3056,6 +3103,9 @@ virNetworkDefUpdatePortGroup(virNetworkDef *def,
>      int ret = -1;
>      virPortGroupDef portgroup = { 0 };
>
> +    /* added for modify-or-add feature */
> +    bool modified = false;
> +
>      if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "portgroup")
> < 0)
>          goto cleanup;
>
> @@ -3097,6 +3147,17 @@ virNetworkDefUpdatePortGroup(virNetworkDef *def,
>          goto cleanup;
>      }
>
> +    /* modify found entries for modify-or-add command */
> +    if (foundName >= 0 && (command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_LAST ||
> +        command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_FIRST)) {
> +
> +        /* replace existing entry */
> +        virPortGroupDefClear(&def->portGroups[foundName]);
> +        def->portGroups[foundName] = portgroup;
> +        memset(&portgroup, 0, sizeof(portgroup));
> +        modified = true;
> +    }
> +
>      if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
>
>          /* replace existing entry */
> @@ -3105,11 +3166,14 @@ virNetworkDefUpdatePortGroup(virNetworkDef *def,
>          memset(&portgroup, 0, sizeof(portgroup));
>
>      } else if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) ||
> -        (command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST)) {
> +        (command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST) ||
> +        (!modified && command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_LAST) ||
> +        (!modified && command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_FIRST)) {
>
>          /* add to beginning/end of list */
>          if (VIR_INSERT_ELEMENT(def->portGroups,
> -                               command ==
> VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST
> +                               (command ==
> VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST ||
> +                               command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_FIRST)
>                                 ? 0 : def->nPortGroups,
>                                 def->nPortGroups, portgroup) < 0)
>              goto cleanup;
> @@ -3144,7 +3208,9 @@ virNetworkDefUpdateDNSHost(virNetworkDef *def,
>      virNetworkDNSDef *dns = &def->dns;
>      virNetworkDNSHostDef host = { 0 };
>      bool isAdd = (command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST ||
> -                  command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST);
> +                  command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST ||
> +                  command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_FIRST ||
> +                  command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_LAST);
>      int foundCt = 0;
>
>      if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
> @@ -3185,15 +3251,21 @@ virNetworkDefUpdateDNSHost(virNetworkDef *def,
>      if (isAdd) {
>
>          if (foundCt > 0) {
> -            virReportError(VIR_ERR_OPERATION_INVALID,
> -                           _("there is already at least one DNS HOST
> record with a matching field in network %1$s"),
> -                           def->name);
> +            if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) ||
> +                command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST)
> +                virReportError(VIR_ERR_OPERATION_INVALID,
> +                               _("there is already at least one DNS HOST
> record with a matching field in network %1$s"),
> +                               def->name);
> +            else
> +                virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
> +                               _("DNS HOST records cannot be modified,
> only added or deleted"));
>              goto cleanup;
>          }
>
>          /* add to beginning/end of list */
>          if (VIR_INSERT_ELEMENT(dns->hosts,
> -                               command ==
> VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST
> +                               (command ==
> VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST ||
> +                                command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_FIRST)
>                                 ? 0 : dns->nhosts, dns->nhosts, host) < 0)
>              goto cleanup;
>      } else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
> @@ -3240,7 +3312,9 @@ virNetworkDefUpdateDNSSrv(virNetworkDef *def,
>      virNetworkDNSDef *dns = &def->dns;
>      virNetworkDNSSrvDef srv = { 0 };
>      bool isAdd = (command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST ||
> -                  command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST);
> +                  command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST ||
> +                  command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_FIRST ||
> +                  command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_LAST);
>      int foundCt = 0;
>
>      if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
> @@ -3268,15 +3342,21 @@ virNetworkDefUpdateDNSSrv(virNetworkDef *def,
>      if (isAdd) {
>
>          if (foundCt > 0) {
> -            virReportError(VIR_ERR_OPERATION_INVALID,
> -                           _("there is already at least one DNS SRV
> record matching all specified fields in network %1$s"),
> -                           def->name);
> +            if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) ||
> +                (command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST))
> +                virReportError(VIR_ERR_OPERATION_INVALID,
> +                               _("there is already at least one DNS SRV
> record matching all specified fields in network %1$s"),
> +                               def->name);
> +            else
> +                virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
> +                               _("DNS SRV records cannot be modified,
> only added or deleted"));
>              goto cleanup;
>          }
>
>          /* add to beginning/end of list */
>          if (VIR_INSERT_ELEMENT(dns->srvs,
> -                               command ==
> VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST
> +                               (command ==
> VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST ||
> +                                command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_FIRST)
>                                 ? 0 : dns->nsrvs, dns->nsrvs, srv) < 0)
>              goto cleanup;
>      } else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
> @@ -3322,7 +3402,9 @@ virNetworkDefUpdateDNSTxt(virNetworkDef *def,
>      virNetworkDNSDef *dns = &def->dns;
>      virNetworkDNSTxtDef txt = { 0 };
>      bool isAdd = (command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST ||
> -                  command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST);
> +                  command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST ||
> +                  command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_FIRST ||
> +                  command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_LAST);
>
>      if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
>          virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
> @@ -3344,15 +3426,21 @@ virNetworkDefUpdateDNSTxt(virNetworkDef *def,
>      if (isAdd) {
>
>          if (foundIdx < dns->ntxts) {
> -            virReportError(VIR_ERR_OPERATION_INVALID,
> -                           _("there is already a DNS TXT record with name
> '%1$s' in network %2$s"),
> -                           txt.name, def->name);
> +            if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST) ||
> +                (command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST))
> +                virReportError(VIR_ERR_OPERATION_INVALID,
> +                               _("there is already a DNS TXT record with
> name '%1$s' in network %2$s"),
> +                               txt.name, def->name);
> +            else
> +                virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
> +                               _("DNS TXT records cannot be modified,
> only added or deleted"));
>              goto cleanup;
>          }
>
>          /* add to beginning/end of list */
>          if (VIR_INSERT_ELEMENT(dns->txts,
> -                               command ==
> VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST
> +                               (command ==
> VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST ||
> +                                command ==
> VIR_NETWORK_UPDATE_COMMAND_MODIFY_OR_ADD_FIRST)
>                                 ? 0 : dns->ntxts, dns->ntxts, txt) < 0)
>              goto cleanup;
>      } else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
> diff --git a/tools/virsh-network.c b/tools/virsh-network.c
> index 597e3d4530..c30305ac50 100644
> --- a/tools/virsh-network.c
> +++ b/tools/virsh-network.c
> @@ -1231,7 +1231,7 @@ static const vshCmdOptDef opts_network_update[] = {
>       .positional = true,
>       .required = true,
>       .completer = virshNetworkUpdateCommandCompleter,
> -     .help = N_("type of update (add-first, add-last (add), delete, or
> modify)")
> +     .help = N_("type of update (add-first, add-last (add), delete,
> modify, modify-or-add, or modify-or-add-first)")
>      },
>      {.name = "section",
>       .type = VSH_OT_STRING,
> @@ -1260,7 +1260,7 @@ static const vshCmdOptDef opts_network_update[] = {
>
>  VIR_ENUM_IMPL(virshNetworkUpdateCommand,
>                VIR_NETWORK_UPDATE_COMMAND_LAST,
> -              "none", "modify", "delete", "add-last", "add-first");
> +              "none", "modify", "delete", "add-last", "add-first",
> "modify-or-add", "modify-or-add-first");
>
>  VIR_ENUM_IMPL(virshNetworkSection,
>                VIR_NETWORK_SECTION_LAST,
> --
> 2.44.0
>
>

-- 
Abhiram
_______________________________________________
Devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to