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

Re: [libvirt] [PATCH 3/5] domaincaps: Report graphics spiceGL



On Mon, May 09, 2016 at 06:53:01PM -0400, Cole Robinson wrote:
> On 05/09/2016 09:48 AM, Daniel P. Berrange wrote:
> > Yeah, I find flat modelling quite desirable, because the relationships
> > between attributes will certainly grow quite complicate, and they do
> > not neccessarily form a nice simple tree relationship.
> > 
> > ie, whether  foo=bar is permitted may depend on whether wizz=eek *AND*
> > when lala=ooh, and you can't have the enum for 'foo' nested underneath
> > the enum for 'wizz' & 'lala' at the same time.  Also with nesting, if
> > you want the same values reported for multiple options, we end up
> > repeating the same information multiple times which is not good.
> > 
> > At the same time the flat modelling with "spiceGL" also doesn't scale
> > as you have to invent new names for each one, and again it doesn't
> > work if the 'gl' enum depended on type="spice" *and* something else
> > at the same time.
> > 
> > So I think we need a more flexible way to express dependancies here.
> > 
> > We could let the <enum> be repeated multiple times and express conditional
> > rules against each instance of the enum
> > 
> > So for example
> > 
> >     <graphics supported='yes'>
> >       <enum name='type'>
> >         <value>spice</value>
> >         <value>vnc</value>
> >         <value>sdl</value>
> >       </enum>
> >       <enum name='gl'>
> >         <condition>
> > 	  <enum name="type" value="spice">
> > 	</condition>
> >         <value>default</value>
> >         <value>yes</value>
> >         <value>no</value>
> >       </enum>
> >       <enum name='gl'>
> >         <value>default</value>
> >         <value>no</value>
> >       </enum>
> >     </graphics>
> > 
> > 
> > This would express that the first <enum type="gl"> entry only applies
> > when the @type == spice. If that doesn't match them fallback to the
> > second <enum type="gl">.  The nice thing about this is that we can
> > make the conditions arbitrarly complex
> > 
> > For example:
> > 
> >     <graphics supported='yes'>
> >       <enum name='type'>
> >         <value>spice</value>
> >         <value>vnc</value>
> >         <value>sdl</value>
> >       </enum>
> >       <enum name='gl'>
> >         <condition op="and">
> > 	  <enum name="type" value="spice">
> > 	  <condition op="or">
> >             <enum name="type" value="vnc">
> > 	    <enum name="wibble" value="eek">
> > 	  </condition>
> > 	</condition>
> >         <value>default</value>
> >         <value>yes</value>
> >         <value>no</value>
> >       </enum>
> >       <enum name='gl'>
> >         <value>default</value>
> >         <value>no</value>
> >       </enum>
> >     </graphics>
> > 
> > 
> > This shows how the "gl" option can be used with VNC, but only if you
> > also have the @wibble attribute set to "eek".
> > 
> > Of course complex conditions like this become quite tedious & verbose
> > so obviously we should strive to keep them as simple as possible and
> > not use nested conditions unless absolutely needed.
> > 
> 
> Writing a parser for this type of XML, that maintains behavior in a future
> proof way, is going to be a lot of work. Hypothetical example:
> 
>   <video supported='yes'>
>     <enum name='modelType'/>
>       <value>cirrus</value>
>       <value>qxl</value>
>     </enum>
>     <enum name='accel2d'/>
>       <value>no</value>
>     </enum>
>   </video>
> 
> 6 months later, qemu gets some accel2d support for model=qxl
> 
>   <video supported='yes'>
>     <enum name='modelType'/>
>       <value>cirrus</value>
>       <value>qxl</value>
>     </enum>
>     <enum name='accel2d'/>
>       <value>no</value>
>     </enum>
>     <enum name='accel2d'/>
>       <condition>
> 	<enum name="modelType" value="qxl">
>       </condition>
>       <value>yes</value>
>       <value>no</value>
>     </enum>
>   </video>
> 
> Another 6 months later, qemu gets accel2d support for cirrus only, but it
> requires <address type='pci'/> and doesn't work for <address type='isa'/>
> 
>   <video supported='yes'>
>     <enum name='modelType'/>
>       <value>cirrus</value>
>       <value>qxl</value>
>     </enum>
>     <enum name='addressType'/>
>       <value>pci</value>
>       <value>isa</value>
>     </enum>
>     <enum name='accel2d'/>
>       <value>no</value>
>     </enum>
>     <enum name='accel2d'/>
>       <condition>
> 	<enum name="modelType" value="qxl">
>       </condition>
>       <value>yes</value>
>       <value>no</value>
>     </enum>
>     <enum name='accel2d'/>
>       <condition>
> 	<enum name="modelType" value="cirrus">
>         <enum name="addressType" value="pci">
>       </condition>
>       <value>yes</value>
>       <value>no</value>
>     </enum>
>   </video>
> 
> 
> The app wants to answer the question 'can I specify accel2d by default for
> model=cirrus?' (note, cirrus, and not qxl)
> 
> For the first example, the code parses the accel2d enum, doesn't see 'yes', so
> it doesn't enable accel2d. The code will need to contain some knowledge that
> enum name='accel2d' == ./video/acceleration/@accel2d but that's presently
> unavoidable.
> 
> For the second example, code will need to be added to parse the basic
> condition, see that modelType=cirrus (./video/model/@type) doesn't match the
> condition, and so again accel2d=no
> 
> For the third example, code hits the modelType=cirrus condition, but then also
> needs to check that addressType (./video/address/@type) == pci, and if so,
> sets accel2d=yes
> 
> So, that's all achievable. But what kind of parser does the app write at each
> step that may fall over with the next XML iteration?
> 
> What if the parser in step 1 doesn't expect multiple <enum name='accel2d'/> ?
> If it naively parses only the first instance, then nothing will regress in
> step #2 or step #3. step #3's conclusion will be wrong, but that's okay. Note
> this depends on libvirt being smart about appending conditional enums, and not
> putting them first.
> 
> However if it parses the last instance, such as by iterating over every XML
> node and taking the last one that matches name='accel2d' (virtinst used to
> have a pattern like this when parsing capabilities XML), on step #2 the code
> will think the <enum> with the 'qxl' condition is the only instance. The
> parser doesn't know about <condition> yet, will assume accel2d is supported
> for everyone, and set accel2d=on for cirrus which will probably fail.

This is all simply a matter of documentation - if we're to allow multiple
<enum> elements, then clearly we need to document the rules that a parser
should follow so that its behaviour is consistent. IOW, we would have to
document whether the default (no conditional) enum always comes first or
last, or whether the application should explicitly look for an enum without
any <condition> rules. Any one of those is a viable option - we just need
to document which. Or if we're really needing to avoid causing trouble
for pre-existing parsers, we give the non-default enums which permit use
of <condition> a different element name, eg <enumVariant>.

> Okay, starting from a working step #2. The parser knows about multiple enums,
> and basic <condition> statements. Upgrade to step #3. If the parser was dumb,
> maybe it didn't know about multiple <condition> enums, which may cause an
> incorrect match, setting accel2d=yes, and the config fails.

Again you're just describing a case where we need to document the intended
semantics of the information. If apps using the data ignore the documented
semantics that's their problem. We also need to be extra careful about
how we extend the information in the future such that we don't add extra
elements can could confuse existing parsers. This is a little more strict
that we've been with XML extension in general, but totally managable.

> Assume the parser is smart enough to know about multiple <condition> enums. It
> sees addressType, but it doesn't know what XML value it maps to. Does the app
> just ignore it and hope the config works, possibly generating an error? Does
> the app completely abandon the check even though it may work correctly? The
> latter is certainly the safest, but coding errors/naive impls could make
> mistakes or possible even throw other errors.

We would document that if an application doesn't understand the particular
condition, then it should ignore that whole enum block. It would thus use
the next/previous best-matching enum block it found.

> Now consider that pattern expanding out with conditional or/and/not operators,
> maybe even numerical comparisons like <, >, etc. The only way for the parser
> from step #1 to not make a fatal error in step #3 is to implement <condition>
> parsing from the start and code very defensively. That's a lot of upfront
> overhead. And I think it will be tempting for apps to try and get by _without_
> implementing the whole comparison engine and potentially set themselves up for
> future pain.

Again apps should explicitly ignore enums with comparison operators that they
don't know about, and fallback to the next best matching enum they can find.

> Also having a very interconnected schema like this means that if we ever need
> to extend the XML format we need to think _very_ hard about how parsers are
> likely handing the existing XML, and how our additions might screw things up,
> because we are requiring users to perform some kind of comparison on the
> result. This is much different than extending the domain XML which is largely
> just a config file. <capabilities> XML is the closet analog but even that
> requires very little processing, the only tricky bit is handling that <domain
> type='kvm'> has its own <machine> list
> 
> And even after all that, the XML is not going to be completely introspectable
> unless we find a way to describe addressType=./video/address/@type in the XML.
> So any general parser is still going to need to be extended regularly to
> handle new enum names. So we end up with XML that
> appears-introspectable-but-not-quite

> So let's redo the example with the unique string names and flat namespace:
> 
> Step #1 is identical
> Step #2 addition is
> 
>     <enum name='qxlAccel2D'/>
>       <value>yes</value>
>       <value>no</value>
>     </enum>
> 
> Step #3 addition is
> 
>     <enum name='cirrusAccel2D'/>
>       <value>yes</value>
>       <value>no</value>
>     </enum>
> 
> And for step #3 we document that it's only valid for address type=pci, If
> address type=isa grows support later, we add a new top level string if we
> think it's worth it. The type=pci vs type=isa is a misleading example here, if
> it was some more obscure option that cirrus accel2d depended on, maybe we
> would want to put that in the string name.
> 
> The misinterpretation problems for the app are non-existent. Yes it will need
> to be extended at step #3 to support cirrus accel2d=yes but that's completely
> fine IMO.

IMHO it is a total failure if we require the application to extend its
parser every time we add a new enum to the domain capabilities. We have
the ability to design something that is data driven - we should not build
something it is forced to be code driven with code changes for every
libvirt addition.

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|


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