[libvirt] RFC: take two on live update of network configuration

Laine Stump laine at laine.org
Wed Aug 22 04:36:59 UTC 2012


On 08/21/2012 11:47 PM, Daniel Veillard wrote:
> On Tue, Aug 21, 2012 at 11:26:08PM -0400, Laine Stump wrote:
> [...]
>> ===========
>> OPTION 2) have a separate API for each different type of element we may want to
>> change, e.g.:
>>
>>
>>     virNetworkUpdateForwardInterface(virNetworkPtr network,
>>                                      const char *xml,
>>                                      unsigned int flags);
>>     virNetworkUpdatePortgroup(virNetworkPtr network,
>>                               const char *xml,
>>                               unsigned int flags);
>>     virNetworkUpdateIpDhcpHost(virNetworkPtr network,
>>                                const char *xml,
>>                                unsigned int flags);
>>     virNetworkUpdateDnsEntry(virNetworkPtr network,
>>                              const char *xml,
>>                              unsigned int flags);
>>
>>     /* The name of this one may confuse... */
>>     virNetworkUpdateDomain(virNetworkPtr network,
>>                            const char *xml,
>>                            unsigned int flags);
>>     virNetworkUpdateBridge(virNetworkPtr network,
>>                            const char *xml,
>>                            unsigned int flags);
>>     virNetworkUpdateIpDnsHost(virNetworkPtr network,
>>                               const char *xml,
>>                               unsigned int flags);
>>     etc. (etc. etc.)
>>
>> "flags" would include:
>>
>>    /* force add if object with matching key doesn't exist */
>>    VIR_NETWORK_UPDATE_ADD
>>    /* delete existing object(s) that matches the xml */
>>    VIR_NETWORK_UPDATE_DELETE
>>    /* take effect immediately */
>>    VIR_NETWORK_UPDATE_LIVE
>>    /* persistent change */
>>    VIR_NETWORK_UPDATE_CONFIG
>>
>>
>> This method could be problematic, e.g., for something like
>> virNetworkUpdateIpDhcpHost() - although currently only a single <ip>
>> element can have a <dhcp> entries, in the future we could allow any/all
>> of them to have dhcp entries. Another downside is that we would need to
>> add an new function for each new element we decide we want to be able to
>> update.
>   that's an awful lot of potential APIs something more generic is needed
>
>> ===========
>> OPTION 3) Again, a single API, but with an added "nodespec" arg which would
>> be used to describe the parent node you of the node you want added/updated to:
>>
>>    int virNetworkUpdate(virNetworkPtr network,
>>                         const char *nodeSpec,
>>                         const char *xml,
>>                         unsigned int flags);
>>
>>    For example, if you wanted to add a new <host> entry to <ip
>> address='10.24.75.1' ...>'s dhcp element, you would do this:
>>
>>     /* nodespec obviously uses an XPath expression */
>>     virNetworkUpdate("/ip[address='10.24.75.1']/dhcp",
>>                      /* full text of <host> element to add */
>>                      "<host mac='00:16:3e:77:e2:ed' "
>>                      "name='X.example.com' ip='10.24.75.10'/>"
>>                      VIR_NETWORK_UPDATE_ADD | VIR_NETWORK_UPDATE_LIVE
>>                      | VIR_NETWORK_UPDATE_CONFIG);
>>
>> Or, to change the contents of the exiting portgroup "engineering" you
>> would use:
>>
>>     virNetworkUpdate("/",
>>                      /* full text of portgroup */,
>>                      "<portgroup name='engineering'> ..... </portgroup>"
>>                      VIR_NETWORK_UPDATE_LIVE|VIR_NETWORK_UPDATE_CONFIG);
>>
>> To delete a static dhcp host entry, you would use this:
>>
>>     virNetworkUpdate("/ip[address='10.24.75.1']/dhcp",
>   shouldn't that be //ip[address='10.24.75.1']/dhcp or your really
> expect to have ip as the root ?

Keep in mind that I've only used xpath expressions as much as I've
needed them in libvirt's parsing functions, which usually use "./xxxxx"
style, so I probably got the syntax wrong.

I had figured that the root node would be <network>, and would be "/". I
*think* I've just learned from you that isn't the case, and that an <ip>
element within <network> would be specified (if network was the root
node) as "//ip".


>
>>                      /* just enough to match existing entry */
>>                      "<host mac='00:16:3e:77:e2:ed'/>",
>>                      VIR_NETWORK_UPDATE_DELETE | VIR_NETWORK_UPDATE_LIVE
>>                      | VIR_NETWORK_UPDATE_CONFIG);
>>
>> or if you preferred:
>>
>>     virNetworkUpdate("/ip[address='10.24.75.1']/dhcp",
>>                      /* again, just enough to match */
>>                      "<host ip='10.24.75.10'/>",
>>                      VIR_NETWORK_UPDATE_DELETE |VIR_NETWORK_UPDATE_LIVE
>>                      | VIR_NETWORK_UPDATE_CONFIG);
>>
>> To remove an interface from the interface pool:
>>
>>     virNetworkUpdate("/forward",
>>                      "<interface dev='eth20'/>",
>>                      VIR_NETWORK_UPDATE_DELETE | VIR_NETWORK_UPDATE_LIVE
>>                      | VIR_NETWORK_UPDATE_CONFIG)
>>
>> (adding an interface would be identical, except the flag).
>>
>> (An alternate implementation would be to have nodeSpec specify the node
>> that is being updated/removed rather than its parent. This may make more
>> logical sense, (although not for ADD) and would even make the rest of
>> the code simpler for update/remove (we wouldn't have to do a manual
>> search within the node).
>>
>> The positive side of this is that the one API function allows you to modify
>> *anything* (even stuff not yet invented, so it's future-proof). The negative
>> side is that the code that implements it would need to go to quite a bit of
>> extra trouble to determine what has been changed (basically, it would
>>
>>     a) generate XML for the current state of the network,
>>     b) parse that into an xmlNode, 
>>     c) perform the operation on xmlNode using nodeset to figure out where,
>>        and adding in the new xml (or removing any nodes matching it),
>>     d) convert modified xmlNode back to xml text,
>>     e) parse the xml text into a virNetworkDef,
>>     f) compare it to the original virNetworkDef to determine what to do.
>   One problem I can see with 3) is that it would work for now
> but if we were to add namespaces to the XML then the API would
> not allow to address those elements/attributes
>
>   //foo in XPath cannot address an element foo with a namespace
>
> to do this you need to do
>
>   //prefix:foo  and provide separately the mapping between prefix
> and the namespace URI
>
>   So that will work as long as we don't add namespace to the XML

Hmm. I had been thinking recently of adding a private namespace to allow
adding custom commandline options to the dnsmasq commandline similar to
how we currently use a private namespace to allow adding custom
commandline options to the qemu commandline. Maybe something like this:

network xmlns:dnsmasq='http://libvirt.org/schemas/network/dnsmasq/1.0'>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='10.24.75.128' end='10.24.75.254' />
      <dnsmasq:commandline>
        <dnsmasq:arg value='--max-ttl'/>
        <dnsmasq:arg value='25400'/>
        <dnsmasq:arg value='--resolv-file=/etc/libvirt-resolv.conf'/>
      </dnsmasq:commandline>
    </dhcp>
  </ip>
</network>

So you're saying that xpath wouldn't allow me to select the
<dnsmasq:commandline> element and replace it? (my guess at the
expression to do that would have been
"//ip[address='10.24.75.128']/dhcp/dnsmasq::commandline")

> Another problem is making sure we have the addressing complete,
> for example suppose we have
>     <
>
> The other problem is that people who already have a beef with XML usage
> will see red when they see the need to learn XPath O:-) , but that could
> be alleviated in a large part with a good set of examples !
>
>  Also the problem with Update APIs to XML is that the next step is
> people will want to add one part (not replace) and then you need
> to define where to add, before/after ...

Fortunately there is nothing in <network> that is order-dependent, but
in the general sense I understand the problem you're describing. I think
what I'm taking away from your comments is that this isn't the 100%
future-proof solution that I'd imagined.

>
>   XML editing APIs are *hard*, I'm actually a bit worried to go there
> something like 2/ while potentially leading to more entry points
> probably makes thing easier for the user.

Or maybe I should reconsider option (1) (a single API that just replaces
the entire XML for the network). That would also require special
considerations for fine-grained access control though - it would need to
compare the old and new, then check to see if the current user was
authorized to change the bits that showed up in the diff. Again, I don't
know how well (if at all) that fits in with the model danpb is planning
to use for that - if it's a model where user's are granted access purely
on a per-API basis, then it won't work. If it's possible to do the
finer-grained check further down in the implementation of the API, then
it might work.




More information about the libvir-list mailing list