Re: libvirt profiles (a.k.a. virtuned) design ideas draft

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Martin and Daniel, are you making different scope assumptions here?  I suspect:
- Daniel is assuming that profiles and applications are orthogonal, and that any application has to be able to live with any profile dropped in;
- Martin is assuming that profiles are tied to applications; this is a tool for moving custom logic within an application to reusable tooling but each application has its own set of profiles.

Cheers,

- Peter

On 9 July 2018 at 15:01, Martin Kletzander <mkletzan@xxxxxxxxxx> wrote:
On Thu, Jul 05, 2018 at 05:58:46PM +0100, Daniel P. Berrangé wrote:
On Tue, Jul 03, 2018 at 04:41:52PM -0400, Cole Robinson wrote:
Nice work on the document! I'll duplicate the docs here and comment
in-line, might help to get more eyeballs.

On 06/20/2018 09:15 AM, Martin Kletzander wrote:
> After some discussion with people from various management apps we
> decided to try and create something that would help with common,
> duplicated, and perhaps easy to extract things for which the code
> exists in some (or most) of the projects. I'd be glad for any
> feedback, so here is the rendered document:
>
> https://github.com/nertpinx/virt-manager/blob/virtuned-docs/docs/virtuned.md
>
> and here you can comment:
>
> https://github.com/nertpinx/virt-manager/pull/1/files
>
> I'm sending this to this list because it might be beneficial to base
> this on top of virt-manager's codebase.  We'll see how that goes, but
> for now any feedback is welcome.
>


Before I get into specific replies/questions, let me make sure I have
the right idea:

virtuned is an API for applying preset VM config changes (profiles) to
libvirt domain XML. Current plan is to implement it in python, but
provide a REST API wrapper for access from other languages. The library
will ship with a set of profiles initially based on a collection of what
existing apps are already doing. Apps using virtuned can mix and match
which profiles they want to apply to new or existing libvirt domains.

Sound correct so far?


Yes.  They can also provide their own profiles.

> # Design document for virtuned implementation
>
> This document serves as a place to have open discussion about the design of so
> called *libvirt profiles*, a.k.a. **virtuned**. The project should provide a
> common ground to few problems which are currently being fixed on different
> layers (mostly up the stack). Starting from the small things first, virtuned is
> currently supposed to manage policies for creating XML definitions for VMs
> (domains).
>

One small quibble: do we expect this to ever be a daemon? I gather the
name is a play off of the existing 'tuned' project but the 'd' throws me
off a bit


For the REST API daemon is needed, yes.

FWIW, I find the naming rather misleading since this really is separate from
tuned. A better project name choice might simply be libvirt-profile or
something along those lines. Whether this project then provides a library
of binary or both is an impl detail.


I really really don't like the name, I used idfferent naming, but everyone was
still saying "virtuned", so I just went with it.  I didn't want to bikeshed, but
libvirt-profile is fine.


> ## Brief specification of functionality
>
> Currently virtuned aims to provide a consistent way of applying profiles to
> libvirt VM definitions.  That way management applications don't need to
> duplicate the implementation in their codebases.
>
> ### Functions
>
> As a starting point virtuned exposes one function.  As input the function
> accepts a VM definition with the only restriction being that it is a libvirt
> domain XML.  However it doesn't have to be complete.  The function applies all
> relevant profiles to that XML and produces a complete libvirt domain XML.
>
> The outcome of this is twofold:
> - Every libvirt domain XML is already working virtuned XML.
> - Applications can select, by arbitrarily small steps, how much functionality
>   they want to use from virtuned.

I'm not sure I understand this second point. IIUC, the contents of the profiles
are supposed to be opaque to the mgmt application. So while they use virtuned,
they'll be exposed to whatever arbitrary XML the profile contains, whether
they understand it or not.


Why would they need to be opaque to the mgmt app?  Either you are using some of
profiles that are shipped with it (in which case the mgmt app developers should
know what they are using in the code) or the mgmt app can construct their own
profile to be used in which case it should know what it is asking for.

>
> The main advantage of this approach is that applications can adopt the new
> functionality incrementally by small steps that they themselves can choose,
> starting from nothing.  Simply plugging virtuned into the process of domain XML
> creation shouldn't change anything until you explicitly start using profiles.

If you're not using profiles, what is virtuned actally doing for you ?


Nothing.  The point was that you can first plug it in, then add a profile that
sets one option to some particular value, then add another, etc. and thanks to
that adopt it incrementally.

This bit confused me for a while, describing a function that only takes
domain XML as the input. But after a re-read I see the requested
profiles are specified as their own xmlns in the domain <metadata>
section. That makes sense to me and provides a lot of flexibility


And we don't have to come up with yet another virtual machine definition format.

(although YAVMDF would be very slick and catchy format name as well as extension)

> ### API endpoints ###
>
> For now the API will be exposed as:
>
> 1. Python module - trivial if we're basing it on virt-manager codebase which is
>    using python

What's the key reasons/benefit to be part of virt-manager codebase as opposed
to a standalone project ?


Few things:

1) The XMLBuilder makes it easier to work with the XML, particularly the domain
   XML.  This is not that big of a deal since libvirt-go-xml does a good job of
   that as well

2) There is an existing logic for "intermediate" devices.  By that I mean the
   devices that are needed to add the requested one.  For example when
   requesting an addition of a SATA disk, there is already a logic that figures
   out if there is an existing SATA controller with a free slot and adds one if
   there is not.  The reason for this is that there might be some defaults
   specified which affect the intermediate devices.

3) The possibility of exposing virt-xml and virt-install in the future.  The
   former would be used for making changes to the XML and the latter is
   something that stateless mgmt apps would like to use (cockpit currently).

4) Last but not least (although this shouldn't be used as a point for decision)
   it is easier to make it available in existing distributions and package
   managers.

Personally I'm pretty disillusioned with the maint burden of python (and dynamic
languages in general). For a new effort like this I'd encourage consideration
of Go or Rust. That said since I'm not working on it, don't consider this a
blocker, just an opinion.


It's still up for discussion.  I would love to use Rust, but I'm not as
proficient in it.  I would go with Go as well, but there would again be some
code duplication (e.g. for the logic that virt-manager has already).  Anyway,
see open questions at the bottom (there's even demo in Go that utilizes the
struct tags).


> 2. RESTful service - this will just be a separate file handing the glue between
>    the python module and the different way of API exposure.  For that reason
>    (and simplicity's sake) this could be outsourced (to
>    e.g. [hug](https://www.hug.rest/)), at least for now<sup
>    id='fn1'>[[1]](#fn1d)</sup>.
>
> This will make it usable by most known projects and additional APIs can be added
> later on without much friction (similarly to the REST API).  If virt-manager's
> codebase is used as a base, then it will also simplify the exposure of other
> parts of virt-manager under that RESTful service, for example virt-xml and
> virt-install.  As far as I know this is something cockpit project would like a
> lot <sup id='fn2'>[[2]](#fn2d)</sup>.
>
> <sub id='fn1d'>1. <a href=""> > With hug we'll get CLI almost automatically as well.
> </sub>
> <sub id='fn2d'>2. <a href=""> > This is not a strict requirement for virtuned, just a helpful side-effect.
> </sub>
>
> ## Data specifications
>
> There are several data formats that need to be specified.  What is discussed
> below is mainly:
> - **Format of the profiles** - Syntax of the format itself
> - **Profile behaviours** - Possible changes profiles can do to VM definitions
> - **Connection between profiles and VM definitions** - how to select changes
>   which should be applied
> - **Behaviour of the above connection** - How to specify multiple profiles and
>   under what circumstances do they mutually exclude.
>
> For a TL;DR example, see [Full Example](#full-example) below.
>
> ### Profile specification
>
> The profile itself can influence the VM definition in three different ways:
>
> - Requesting a specific part of the XML to (not) exist.  This includes:
>   - Adding a specific XML snippet
>   - Making sure specific XML snippet exists (without necessarily adding it)
>   - Removing a specific XML snippet
> - Setting default for existing parts of the XML (setting if unset)
>
> Due to the fact that the profiles will influence how the resulting XML will look
> like, virtuned profiles use XML as well, however that does not prevent the
> support for other formats to be added later on.
>
> Simple profile can look like this:
>
> ``` xml
> <profile name='add-qxl'>
>   <add>
>     <devices>
>       <video>
>         <model type='qxl'/>
>       </video>
>     <devices>
>   </add>
> </profile>
> ```
>
> The above example will request a video card with model QXL to exist in the VM
> definition.  The precise outcome of this depends on the existing devices in the
> VM definition:
>
> - **VM has no video device:** the XML snippet (`qxl` video card) will simply be
>   added to the list of devices.
> - **VM has video device with no model specified:** Just fill in the video model
>   for the existing video card.
> - **VM has video device with different model:** Add one more video device with
>   the specified model since multiple video cards are perfectly fine.
>
> The above is very concrete example, but it can be very easily and efficiently
> generalized for any `<add/>` sub-element.  The only information which is
> required for said generalization is the knowledge of libvirt's domain XML
> format.  This could be one of the reasons for virtuned to be spun off of
> virt-manager's codebase (since most of that information is already there).  The
> other option would be using
> [libvirt-go-xml](https://libvirt.org/git/?p=libvirt-go-xml.git) as that should
> have enough information for this as well <sup id='fn3'>[[3]](#fn3d)</sup>.

FYI, libvirt-go-xml should have 100% coverage of all XML constructs in the
libvirt schema. Any ommissions are entirely due to libvirt's own master XML
test files being incomplete. libvirt-go-xml unit tests check that it can
roundtrip all XML files in libvirt.git without data loss. I don't think any
other XML parser impl for libvirt has the same level of coverage, principally
because none of them do similar kind of testing to prove it.


Coverage is one thing, but another thing is the logic that is in XMLBuilder
(even though it's not there for all the elements).  For example if there are
different sub-elements allowed based on an attribute.  But even simpler,
elements that cannot be duplicated, but in the struct it is saved in a list.  If
that is not fully introspectable from the struct tags, then we will need to
duplicate the code that already exists in virt-manager if this is a side
project.


> As mentioned above this is not the only type of action that the profile format
> supports.  Here is the proposed list of actions with optional attributes:
>
> - **`add`** - Make sure such XML snippet exists.  Can have attribute `multiple`
>   with the following values:
>   - **`yes`** - Unconditionally add the snippet if it can exist multiple times
>     (the lowest level that can exist multiple times to be precise) or fail if it
>     cannot (machine type)
>   - **`no`** - Adjust existing part of the XML so that it matches the
>     requirements from the snippet, overriding values if needed.
>   - **`auto`** (default) - Try adjusting existing part of the XML so that it
>     matches the requirements, but only override values if there is no part of
>     that snippet that could be specified multiple times.  If any part of it can
>     be specified multiple times, then find the lowest such part and append that.
> - **`remove`** - Make sure such XML snippet does not exists.  All matching XML
>   snippets (even if they have more attributes or sub-elements) will be removed.
> - **`default`** - If VM definition has an XML snippet which does fit this
>   description except some values not existing, then fill in those values.  This
>   can be used for example for default device model types or machine types.
>
> The `<add multiple='X'/>` is just a naming and it can be changed in any way that
> suits others, for example instead of having:
>
> ``` xml
> <add multiple='auto'/>
> <add multiple='yes'/>
> <add multiple='no'/>
> ```
>
> There could be:
>
> ``` xml
> <append/>
> <set/>
> <force/> <!-- or <replace/> -->
> ```
>
> All action elements can have optional attribute `constraint` with the following
> possible values:
> - **`soft`** (default) - Profiles with higher priority can override this value.
>   This is the default and should be used whenever it is not absolutely necessary
>   for the XML snippet to be kept.
> - **`hard`** - If profile with higher priority needs to override this value,
>   then error out.  This should be selected only when it is absolutely necessary
>   for the XML snippet to exist in this way.  For example in the following cases:
>   - The system would be unstable.
>   - Data corruption might occur.
>   - Other parts of the profile would cause harm without this set.
>
> Yet another simple profile can look like this:
> ``` xml
> <profile name='some-interesting-things'>
>   <add>
>     <iothreads>2</iothreads>
>   </add>
>   <add>
>     <devices>
>       <disk device='cdrom'>
>     </devices>
>   </add>
>   <add multiple='yes'>
>     <devices>
>       <redirdev bus='usb' type='spicevmc'/>
>       <redirdev bus='usb' type='spicevmc'/>
>     </devices>
>   </add>
>   <remove type='hard'>
>     <features>
>       <apic/>
>     </features>
>   </remove>
>   <defaults>
>     <devices>
>       <interface>
>         <model type='virtio'/>
>       </interface>
>     <devices>
>   </defaults>
> </profile>
> ```

This is where I really start to get very concerned. The examples you're giving
a nice and simple, so composition of arbitrary profiles, together with application
written XML looks like it'll work.

I think it will be all too easy, however, to write profiles where the result of
composition profiles and merging with app XML is an XML document that is
semantically invalid / unrunnable.

Consider if you have a two profiles, one sets up a XML doc with 'pc' machine
type and other profile sets up an XML doc with 'q35' machine type.

Now a third profile wants to setup NUMA for the guest such that PCI devices
are associated with NUMA nodes. The way you do this is very different for
'pc' and 'q35' machine types due to PCI vs PCI-Express topology changes.
So if the 'numa' profile assumes 'pc' it will break if the app composes it
with the 'q35' profile, or vica-verca.

Now consider you have a 'networking-nfv' profile that is supposed to setup
NICs in a way that is optimized for NFV use cases. This profile now needs
to know if it should put the NICs in the default PCI bus, or in the NUMA
specific PCI bus. So the result may or may not do the right thing if you
compose it with the 'numa' profile.

Solving these problems would require a combinatorial expansion in the
number of profiles. eg a numa-pc, numa-q35 profile, and then a
networking-nfv-pc, networking-nfv-q46, networking-nfv-numa-pc, and
networking-nfv-numa-q35 profiles. There would then have to be dependancies
expressed to tell the app which profiles can be composed with each other.


So this is how tuned does it and I didn't really like the way the matrix
explodes with added dimensions.

This still only solves the problem of composing profiles, and does not
consider how to merge with the application defined XML parts. The only
way an application can know if the XML it wants to write, is compatible
with the profiles it has used, is if it parses and understands all the
parts of the profile.


I hear what you are saying, but I don't see why the app would need to parse the
profiles.  There can be conditions in profiles (proposed in open questions) that
would eliminated the need for multiple profiles for the same thing.  Yes, DSL
would be better for this.  We could just right away use what "xq" provides (see
open questions).  That would also solve erroring out.

If something was used in the profile that the app doesn't know about,
it could ignore it, but the resulting VM config may well be unrunnable,
or worse, runnable but doing something completely inappropriate.


I think these kind of problems are inherant in any approach which allows
arbitrary user defined XML as the schema for the profiles.

This is one of reasons why libosinfo didn't base the information it
provides around the libvirt XML schema. Instead it defines its own
domain specific language, and applications only use the features in
it that they actually know how to handle.

This means if we add some new concept to libosinfo database, applications
are not going to automagically use it, and instead have to add explicit
support. As above though, I think this is inevitable, because it is too
easy to create unrunnable/nonsensical XML configs if you allow arbitrary
user specified XML inputs.


Thanks for the info with the NUMA locality example.  On one hand it would really
save us a lot of work if we just used something that exists (by just extending
it) and for DSL there is a solution we can use as well.  If not then we can
build it from existing parts at least partially.



> This profile consists of various actions and has the following implications for
> the VM definition:
>
> - The VM should have 2 I/O Threads (profiles with higher priority can override
>   this setting)
> - The VM should have a CDROM drive.  It will not be added multiple times if it
>   already exists.
> - Two spice redirdev ports will be added to the VM definition.  If there were
>   some existing ones, these will be added<sup id='fn4'>[[4]](#fn4d)</sup>.
> - The VM must not have APIC (cannot be overridden)
> - Any interface should default to virtio model type.  That means model will be
>   set to `virtio` unless already specified.
>
> There are some open questions related to more actions being specified, however
> they should be limited to minimum.
>
> <sub id='fn3d'>3. <a href=""> > Actually maybe even more since virt-manager's info is also incomplete.
> </sub>
> <sub id='fn4d'>4. <a href=""> > Without the `multiple='yes'` this would mean that **at least** 2 such ports
> should exist.
> </sub>
>
> ### VM <-> Profile connection
>
> Not all profiles need to be applied to all VM definitions.  In order to select
> only the relevant ones we need to specify the connection between the VM
> definition and the profile.  That can can be done in multiple different ways
> depending on the preference, however each approach has pros and cons so they are
> discussed in this section.
>
> Since multiple profiles can be applied to the same VM definition at the same
> time, there also needs to be a way to deal with conflicts.  Even though this
> issue seems orthogonal to the connection itself, it can be dealt with in
> different ways depending on the connection specification used.  What is proposed
> below are two ways how to handle the connection with a way how to deal with
> profile clashes together with two ways that were removed from the consideration
> (just to makes sure the decisions are covered for future observers).
>
> #### Selectors in profiles
>
> Similarly to KubeVirt's approach to [VM
> Presets](https://github.com/kubevirt/kubevirt/blob/master/docs/vm-presets.md)
> this is something that has a great power.  Each profile specification includes a
> selector based on which that particular profile will (not) be selected.
>
> Multiple profiles clash and error out in case they cannot be combined.  For this
> we propose a solution in the later section.
>
> Example:
>
> ``` xml
> <profile name='add-qxl-for-spice'>
>   <match>
>     <devices>
>       <graphics type='spice'/>
>     <devices>
>   </match>
>   <add>
>     <devices>
>       <video>
>         <model type='qxl'/>
>       </video>
>     <devices>
>   </add>
> </profile>
> ```
>
> This profile is similar to the one in [Profile
> specification](#profile-specification) with one difference, which is a
> `<match/>` element.   That element includes a condition under which the profile
> actions will be executed.  In this particular case the profiles says that a QXL
> video card should be present in case the VM has a SPICE graphics device.
>
> These matches might include any part of the XML, even metadata, so this can
> match guest OS (if provided as part of the VM metadata).
>
> For example this condition:
>
> ``` xml
> <match>
>   <metadata>
>     <myapp:myapp>
>       <myapp:guest os_type='windows'/>
>     </myapp:myapp>
>   <metadata>
> </match>
> ```
>
> would be matched on this VM definition:
>
> ``` xml
> <domain>
>   <name>Win10</name>
>   <metadata>
>     <myapp:myapp xmlns:myapp='http://example.org/myapp'>
>       <myapp:guest os_type='windows' os_version='10'/>
>     </myapp:myapp>
>   </metadata>
>   ...
> </domain>
> ```
>
> As you can see the metadata used for the condition don't need to be virtuned's
> specific metadata, but rather any management applications metadata.
>

I didn't really know where to cut in so this is a big comment...

The idea here is that virtuned will ship with something like a
profile/add-qxl.xml, and profile="" will then effectively be part
of the virtuned API, like an osinfo ID value is to libosinfo; the
profile will never go away, so apps can depend on it being there.
Presumably we can extend the profile as necessary as long as it
accomplishes its stated goal and we confirm it doesn't break apps.


Yes, we're probably going to need to version it as well.


Using XML for this kind of thing makes me nervous, trying to model
conditional actions with XML. I feel like it's a real quick slippery
slope to implementing a turing complete schema. For example how would we
handle complex examples like:


The idea to use XML was sparkled by two facts:

1) Apps will be able to create their own profiles.

2) Simple profiles (addition of few elements) could be created by just taking
   the specific part of the domain XML and wrapping it in a tag that says what
   to do (e.g. `<add><existing_xml_snippet/></add>`).

* set graphics=spice. Except spice is only available for qemu depending
on the _host_ arch. qemu-system-aarch64 on x86 has spice, but not
qemu-system-aarch64

* Give me USB tablet, if (os-supports-usb-tablet && (arch == x86 ||
(arch == aarch64 && machine.startswith("virt")))

* Give me USB3, if os-supports-usb3. If qemu version > X,
model=qemu-xhci, else model=nec-xhci


So there are three possibilities:

1) We leave this out to the mgmt app,

2) we "just do it" and leave it for someone else to error out properly,

3) or we consult libvirt capabilities

What's the motivation for doing this in XML? So apps or distros can drop
in their own profiles? Or extend system profiles? I'm wondering why XML
over privately implemented. Maybe you can explain some specific app
usecases that motivated this? I feel like I missed a lot in the previous
discussion


You didn't miss much and you hit the two points nicely, dropping in own profiles
and, possibly, extend existing ones.

Also do we expect the API to talk directly to libvirt? Like for checking
domcapabilities?


For KubeVirt that wouldn't be that much of a help as they need to do bunch of
these things without libvirt running.  Also not being dependent on libvirt makes
it independent from the host.  Capabilities might be provided as another input,
but question is whether it should be full blown libvirt (dom)capabilities.  The
reason is that you might need to migrate between various nodes and the mgmt
app/cluster knows the minimal requirements better than host-oriented daemon.

sidenote: I was also trying to come up with something that would take any number
         of libvirt capabilities (one for each node) and based on few more
         input points (e.g. minimum number of supported nodes) it would return
         the maximal capability set that can be used for creating a VM.

I think there's similar issues with have this overlaps / integrates with
libosinfo. When using libosinfo we can dynamically query which type of
device is appropriate on a per guest OS basis. We can also query the
libvirt domain capabilities, and then determine the compatible overlap
between libosinfo and QEMU and libvirt.

The profiles appear to largely loose this ability, going back to having
to write different protocols to cover different types of guest OS.

A the very least I think this means profiles need to be able allow for
complex conditional expressions, along with variable subsistitutions
from external data sources.


Apart from external data sources it is written down in the open questions.
External data sources should not be a problem given they are provided as a
separate input.


This gets hard though when you try to compose profiles with the app
being opaque about what's in the profile. eg if the guest supports
virtio-scsi the result is very different from if the guest supports
virtio-blk.

So if one base profile sets up controllers, a later add-on profile
that works with disks needs to be able to write an _expression_ to
determine whether the existing XML as a virtio-scsi or IDE controller
present and use those, vs deciding to add controller-less virtio-blk
disks.  This rapidly becomes a turing complete problemspace I think.



> ### Open Questions
>
> There are still couple of things to be discussed, which I will only cover
> slightly <sup id='fn5'>[[5]](#fn5d)</sup>.
>
> 1. **How are profiles added**
>    They can be files in a filesystem, there could be separate API for defining
>    profiles.  Some of them will most probably be shared in the repository
>    together with virtuned, but applications need to be able to define their own
>    ones.  Filesystem-based storage seems fine for usage in a container for
>    example, but might not be usable for some deployments.
>

I get that applications will want to add their own profiles and tweak
defaults. But is writing <profile> XML going to be much easier than
editing the XML directly? It isn't clear to me one way or the other.

I tend to think writing the profiles is going to be more complex and
error prone than directly writing the XML, because of the composability
problems I mention above.

My gut feeling is that it would be a more tractable problem if the profiles
used a domain specific language (DSL), possibly still XML, but not libvirt
domain XML. Applications would have to explicitly know about individual
features in the DSL, but they could consume it in a way that the way they
generate libvirt XML is more fully data-driven.

ie, taking my example above, applications would need explicit knowledge
of machine types, NUMA topologies, and attaching devices to NUMA nodes.
Given that knowledge though, the decision about /when/ to use these
respective features would be data driven from profiles that simply
stated desired traits.


I lost you at the last paragraph.  Could you rephrase it or maybe give another
example?  The idea is that mgmt app knows when it wants to use what profile.
And what is provided as an API is the composition of the XML.  But you were
probably addressing something else, right?  As I said, I lost you here.
_______________________________________________
virt-tools-list mailing list
virt-tools-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/virt-tools-list

_______________________________________________
virt-tools-list mailing list
virt-tools-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/virt-tools-list

[Index of Archives]     [Linux Virtualization]     [KVM Development]     [CentOS Virtualization]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]     [Video 4 Linux]

  Powered by Linux