[openstack-dev] [nova] Pulling nova/virt/hardware.py into nova/objects/

Jay Pipes jaypipes at gmail.com
Wed Oct 22 17:42:08 UTC 2014


On 10/21/2014 05:44 AM, Nikola Đipanov wrote:
> On 10/20/2014 07:38 PM, Jay Pipes wrote:
>> Hi Dan, Dan, Nikola, all Nova devs,
>>
>> OK, so in reviewing Dan B's patch series that refactors the virt
>> driver's get_available_resource() method [1], I am stuck between two
>> concerns. I like (love even) much of the refactoring work involved in
>> Dan's patches. They replace a whole bunch of our nested dicts that are
>> used in the resource tracker with real objects -- and this is something
>> I've been harping on for months that really hinders developer's
>> understanding of Nova's internals.
>>
>> However, all of the object classes that Dan B has introduced have been
>> unversioned objects -- i.e. they have not derived from
>> nova.objects.base.NovaObject. This means that these objects cannot be
>> sent over the wire via an RPC API call. In practical terms, this issue
>> has not yet reared its head, because the resource tracker still sends a
>> dictified JSON representation of the object's fields directly over the
>> wire, in the same format as Icehouse, therefore there have been no
>> breakages in RPC API compatibility.
>>
>> The problems with having all these objects not modelled by deriving from
>> nova.objects.base.NovaObject are two-fold:
>>
>>   * The object's fields/schema cannot be changed -- or rather, cannot be
>> changed without introducing upgrade problems.
>>   * The objects introduce a different way of serializing the object
>> contents than is used in nova/objects -- it's not that much different,
>> but it's different, and only has not caused a problem because the
>> serialization routines are not yet being used to transfer data over the
>> wire
>>
>> So, what to do? Clearly, I think the nova/virt/hardware.py objects are
>> badly needed. However, one of (the top?) priorities of the Nova project
>> is upgradeability, and by not deriving from
>> nova.objects.base.NovaObject, these nova.virt.hardware objects are
>> putting that mission in jeopardy, IMO.
>>
>> My proposal is that before we go and approve any BPs or patches that add
>> to nova/virt/hardware.py, we first put together a patch series that
>> moves the object models in nova/virt/hardware.py to being full-fledged
>> objects in nova/objects/*
>
> I think that we should have both in some cases, and although it makes
> sense to have them only as objects in some cases - having them as
> separate classes for some and not others may be confusing.
>
> So when does it make sense to have them as separate classes? Well
> basically whenever there is a need for driver-agnostic logic that will
> be used outside of the driver (scheduler/claims/API/). Can this stuff go
> in objects? Technically yes, but objects are really not a good place for
> such logic as they may already be trying to solve too much (data
> versioning and downgrading when there is a multi version cloud running,
> database access for compute, and there are at least 2 more features
> considered to be part of objects - cells integration and schema data
> migrations).
>
> Take CPU pinning as an example [1] - none of that logic would benefit
> from living in the NovaObject child class itself, and will make it quite
> bloated. Having it in the separate module objects can call into is
> definitely beneficial, while we definitely should stay with objects for
> versioning/backporting support. So I say in a number of cases we need both.
>
> Both is exactly what I did for NUMA, with the exception of the compute
> node side (we are hopping to start the json blob cleanup in K so I did
> not concern myself with it for the sake of getting things done, but we
> will need it). This is what I am doing now with CPU pinning.
>
> The question I did not touch upon is what kind of interface does that
> leave poor Nova developers with. Having everything as objects would
> allow us to write things like (in the CPU pinning case):
>
>    instance.cpu_pinning = compute.cpu_pinning.get_pinning_for_instance(
>       instance)
>
> Pretty slick, no? While keeping it completely separate would make us do
> things like
>
>    cpu_pinning = compute.cpu_pinning.topology_from_obj()
>    if cpu_pinning:
>      instance_pinning = cpu_pinning.get_pinning_for_instance(
>          instance.cpu_pinning.topology_from_obj())
>      instance.cpu_pinning = objects.InstanceCPUPinning.obj_from_topology(
>          instance_pinning)
>
> Way less slick, but can be easily fixed with a level of indirection.
> Note that the above holds only when we are objectified everywhere -
> until then - we pretty much *have* to have both.
>
> So to sum up - what I think we should do is:
>
> 1) Don't bloat the object code with low level stuff

By "low-level stuff", if you mean "methods that *do* something with the 
data in an object", I agree. However, the nova.objects framework should 
be used to represent the *data fields* of any object model that can 
potentially be transferred over the RPC API wires or stored in backend 
storage (DB or otherwise).

The reason is that the data fields of these objects will all surely need 
to undergo some changes -- field renames/adds/deletes/re-types, etc -- 
and that is where the nova.objects framework shines. It allows seamless 
modification of the schema of objects transmitted and stored in our systems.

> 2) Do have objects for versioning everything
> 3) Make nice APIs that developers can enjoy (after we've converted all
> the code to use objects).

I don't see problems with having the best of both worlds, frankly. We 
just need to model our data using nova.objects and having separate 
modules like hardware.py have classes and methods that consume those 
nova.objects and make calculations with them.

For example, classes that represent a NUMA topology should be modelled 
as nova/objects/numa_cell.py and nova/objects/numa_topology.py, and the 
code in /nova/virt/hardware.py should import those two modules and 
provide calculation functions and classmethods like the ones that 
currently exist -- for example, 
nova.virt.hardware.VirtCPUTopology.get_constraints().

Bottom line, we should use the nova.objects framework for modelling the 
data in an object, and put code that analyzes/uses those objects elsewhere.

Best,
-jay

> [1] https://review.openstack.org/#/c/128738/4/nova/virt/hardware.py
>
>> Thoughts?
>>
>> -jay
>>
>> [1]
>> https://review.openstack.org/#/q/status:open+project:openstack/nova+branch:master+topic:bp/virt-driver-get-available-resources-object,n,z
>>
>



More information about the OpenStack-dev mailing list