Bug 1182092

Summary: [RFE] Make plug-able API for supervdsm
Product: [oVirt] vdsm Reporter: Yaniv Bronhaim <ybronhei>
Component: RFEsAssignee: Yaniv Bronhaim <ybronhei>
Status: CLOSED CURRENTRELEASE QA Contact: Yaniv Bronhaim <ybronhei>
Severity: medium Docs Contact:
Priority: medium    
Version: ---CC: bazulay, bugs, danken, edwardh, fromani, gklein, iheim, lsurette, mgoldboi, nsoffer, oourfali, pkliczew, pstehlik, rbalakri, srevivo, ybronhei, ykaul
Target Milestone: ovirt-4.0.0-alphaKeywords: CodeChange, FutureFeature
Target Release: 4.18.0Flags: rule-engine: ovirt-4.0.0+
mgoldboi: planning_ack+
rule-engine: devel_ack+
pstehlik: testing_ack+
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: ovirt 4.0.0 alpha1 Doc Type: Enhancement
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2016-08-11 07:57:41 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: Infra RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 1159945    

Description Yaniv Bronhaim 2015-01-14 12:33:57 UTC
Split the current mechanism in supervdsmServer to allow dynamic modules load instead of using the current _SuperVdsm class which requires code duplication.

This work is part of https://bugzilla.redhat.com/show_bug.cgi?id=1159945

Comment 1 Nir Soffer 2016-01-29 13:34:32 UTC
Why is this needed?

This looks like invalid bug. Bug should be about user needs and not about "solutions".

I don't know about code duplication with current supervdsm code.

Comment 2 Edward Haas 2016-01-29 19:37:30 UTC
There are several reasons why this pattern is preferred:
- It allows modules/capabilities to be loaded independently, per availability (we have such a scenario now).
- It decouples modules and reduces dependency in the project.
- It is cleaner: Instead of a messy single flat file that includes everything, it is grouped and distributed to independent api files of each module.
- An addition or change in a module api does not need to collide with same changes of a different module (I guess it falls in the 'decoupled' category).

As I see it, the supervdsm api is an infrastructure service, modules that need to expose their api to supervdsm should locate their api under supervdsm_api folder.

Comment 3 Nir Soffer 2016-01-29 20:36:05 UTC
(In reply to Edward Haas from comment #2)
> There are several reasons why this pattern is preferred:
> - It allows modules/capabilities to be loaded independently, per
> availability (we have such a scenario now).

You can load modules modules as needed without having a plugable api
for supervdsm.

> - It decouples modules and reduces dependency in the project.

We don't have a need to decouple supervdsm modules from the code implementing
it.

> - It is cleaner: Instead of a messy single flat file that includes
> everything, it is grouped and distributed to independent api files of each
> module.

There is nothing messy about the current supervdsm code; it is a single 
class exposed to vdsm via multiprocessing, that should contain one line
wrapper for each api.

Having independent apis is not needed currently, is more complex, and
needs more code that someone has to maintain.

> - An addition or change in a module api does not need to collide with same
> changes of a different module (I guess it falls in the 'decoupled' category).

supervdsm changes infrequently, this is a non-issue.

> As I see it, the supervdsm api is an infrastructure service, modules that
> need to expose their api to supervdsm should locate their api under
> supervdsm_api folder.

Or locate their api in the single supervdsm file, as we do today.

Having single location for defining the apis that allowed to run as root make
it easier to maintain and keep secure.

Currently vdsm always contain all subsystems, so all supervdsm apis are 
always needed. We may like a plugable api if we break vdsm to multiple
components, and only some of them may be installed on a host.

I suggest to close this bug for now.

Comment 4 Oved Ourfali 2016-01-29 21:00:09 UTC
As there are benefits (some outlined above, and I'm sure Yaniv can add more) and there is work we've done around that, we aren't gonna close it. 
Unless the patch has technical issues, which should be reviewed in Gerrit, I don't see a reason not to push this work. 

The infra team is the owner of this code, and will maintain it.

Comment 5 Edward Haas 2016-01-29 22:40:54 UTC
(In reply to Nir Soffer from comment #3)
> (In reply to Edward Haas from comment #2)
> > There are several reasons why this pattern is preferred:
> > - It allows modules/capabilities to be loaded independently, per
> > availability (we have such a scenario now).
> 
> You can load modules modules as needed without having a plugable api
> for supervdsm.
> 
How would you propose to do that? The trivial way is with an if statement for each module, that checks something (and that something is a module logic), but that pollutes the api with if/s.

> > - It decouples modules and reduces dependency in the project.
> 
> We don't have a need to decouple supervdsm modules from the code implementing
> it.
Why modularity is not a need here? I thought it is an universal need :)

> 
> > - It is cleaner: Instead of a messy single flat file that includes
> > everything, it is grouped and distributed to independent api files of each
> > module.
> 
> There is nothing messy about the current supervdsm code; it is a single 
> class exposed to vdsm via multiprocessing, that should contain one line
> wrapper for each api.

The api/s themselves are not flat, they are owned by different modules, some belong to the same module.
One file for such a thing is not scalable, it grows and is not clean.

> 
> Having independent apis is not needed currently, is more complex, and
> needs more code that someone has to maintain.
> 
> > - An addition or change in a module api does not need to collide with same
> > changes of a different module (I guess it falls in the 'decoupled' category).
> 
> supervdsm changes infrequently, this is a non-issue.
> 
> > As I see it, the supervdsm api is an infrastructure service, modules that
> > need to expose their api to supervdsm should locate their api under
> > supervdsm_api folder.
> 
> Or locate their api in the single supervdsm file, as we do today.
> 
> Having single location for defining the apis that allowed to run as root make
> it easier to maintain and keep secure.
>
Having it under a dedicated folder has the same result IMO.
 
> Currently vdsm always contain all subsystems, so all supervdsm apis are 
> always needed. We may like a plugable api if we break vdsm to multiple
> components, and only some of them may be installed on a host.
> 
> I suggest to close this bug for now.

There are VDSM features that may not be available on a specific host, therefore, its  corresponding apis better not be available.
We are focusing here on supervdsm, which is internal.. And I think it will be good to start breaking components at all layers.

Comment 6 Yaniv Bronhaim 2016-01-30 08:13:58 UTC
Oved is current. same as splitting vm.py, same as changing names and clean code, same as changing to yaml scheme and more other improvements for readability and easier maintaining to the code - here we also provide such thing. instead of one package which contains the server logic and the api logic inside a huge object, with tons of imports above, we want to separate it, and allow others to add functions which supervdsm exposes without reading the server code - only by dropping new package.py with foo func, and you'll be able to run it with root privileges by supervdsm proxy. 
In addition, supervdsmServer code needs to include only server implementation, external logic should not be there. Dima suggested much nicer approach in the past which Dan found a bit risky (the proxy decorator - the patch is still attached), the api folder is another alternative which also provide nice solution for adding\removing logic to the service. unless you provide good explanation why not to do that, lets move on .. we (and other that requested for it) want to refine this code in that direction

Comment 7 Dan Kenigsberg 2016-02-02 12:09:46 UTC
For me, the greatest importance modularizing supervdsm is to simplify splitting the service based on verticals: network, storage, virt and gluster. gLuster has a @decorator trick of their own, so they are not clustered into supervdsmServer, but everybody else - does.

Comment 8 Nir Soffer 2016-02-20 19:39:01 UTC
(In reply to Yaniv Bronhaim from comment #6)
Not clear what info is requested, removing needinfo.

Comment 9 Dan Kenigsberg 2016-03-01 08:38:14 UTC
Yaniv, please note that supervdsm.log must still include the name of the called function. I believe that as of dce403f222c this is no longer the case. Please fix it.

Comment 10 Francesco Romani 2016-03-01 08:40:47 UTC
(In reply to Dan Kenigsberg from comment #9)
> Yaniv, please note that supervdsm.log must still include the name of the
> called function. I believe that as of dce403f222c this is no longer the
> case. Please fix it.

Indeed this is what I saw why testing my

MainProcess|Thread-119::DEBUG::2016-02-29 11:44:16,211::supervdsmServer::111::SuperVdsm.ServerCallback::(wrapper) call wrapper with (u'/var/lib/libvirt/qemu/channels/b29c12fe-d0ce-4bed-b2f5-184488854d37.com.redhat.rhevm.vdsm',) {}
MainProcess|Thread-119::DEBUG::2016-02-29 11:44:16,212::supervdsmServer::118::SuperVdsm.ServerCallback::(wrapper) return wrapper with None
MainProcess|Thread-119::DEBUG::2016-02-29 11:44:16,213::supervdsmServer::111::SuperVdsm.ServerCallback::(wrapper) call wrapper with (u'/var/run/ovirt-vmconsole-console/b29c12fe-d0ce-4bed-b2f5-184488854d37.sock', 'ovirt-vmconsole') {}
MainProcess|Thread-119::DEBUG::2016-02-29 11:44:16,213::supervdsmServer::118::SuperVdsm.ServerCallback::(wrapper) return wrapper with None
MainProcess|Thread-119::DEBUG::2016-02-29 11:44:16,215::supervdsmServer::111::SuperVdsm.ServerCallback::(wrapper) call wrapper with ('a_c7_1',) {}
MainProcess|Thread-119::DEBUG::2016-02-29 11:44:16,216::supervdsmServer::118::SuperVdsm.ServerCallback::(wrapper) return wrapper with 7169
MainProcess|periodic/2::DEBUG::2016-02-29 11:44:19,249::supervdsmServer::111::SuperVdsm.ServerCallback::(wrapper) call wrapper with ('a_c7_1',) {}
MainProcess|periodic/2::DEBUG::2016-02-29 11:44:19,261::supervdsmServer::118::SuperVdsm.ServerCallback::(wrapper) return wrapper with {0: [0], 1: [0]}
MainProcess|periodic/0::DEBUG::2016-02-29 11:44:34,240::supervdsmServer::111::SuperVdsm.ServerCallback::(wrapper) call wrapper with ('a_c7_1',) {}
MainProcess|periodic/0::DEBUG::2016-02-29 11:44:34,249::supervdsmServer::118::SuperVdsm.ServerCallback::(wrapper) return wrapper with {0: [0], 1: [0]}
MainProcess|periodic/1::DEBUG::2016-02-29 11:44:49,244::supervdsmServer::111::SuperVdsm.ServerCallback::(wrapper) call wrapper with ('a_c7_1',) {}
MainProcess|periodic/1::DEBUG::2016-02-29 11:44:49,252::supervdsmServer::118::SuperVdsm.ServerCallback::(wrapper) return wrapper with {0: [0], 1: [0]}
MainProcess|periodic/0::DEBUG::2016-02-29 11:45:04,226::supervdsmServer::111::SuperVdsm.ServerCallback::(wrapper) call wrapper with ('a_c7_1',) {}
MainProcess|periodic/0::DEBUG::2016-02-29 11:45:04,234::supervdsmServer::118::SuperVdsm.ServerCallback::(wrapper) return wrapper with {0: [0], 1: [0]}
MainProcess|periodic/2::DEBUG::2016-02-29 11:45:19,228::supervdsmServer::111::SuperVdsm.ServerCallback::(wrapper) call wrapper with ('a_c7_1',) {}
MainProcess|periodic/2::DEBUG::2016-02-29 11:45:19,237::supervdsmServer::118::SuperVdsm.ServerCallback::(wrapper) return wrapper with {0: [0], 1: [0]}
MainProcess|periodic/2::DEBUG::2016-02-29 11:45:34,234::supervdsmServer::111::SuperVdsm.ServerCallback::(wrapper) call wrapper with ('a_c7_1',) {}
MainProcess|periodic/2::DEBUG::2016-02-29 11:45:34,242::supervdsmServer::118::SuperVdsm.ServerCallback::(wrapper) return wrapper with {0: [0], 1: [0]}
MainProcess|periodic/3::DEBUG::2016-02-29 11:45:49,228::supervdsmServer::111::SuperVdsm.ServerCallback::(wrapper) call wrapper with ('a_c7_1',) {}
MainProcess|periodic/3::DEBUG::2016-02-29 11:45:49,236::supervdsmServer::118::SuperVdsm.ServerCallback::(wrapper) return wrapper with {0: [0], 1: [0]}
MainProcess|periodic/2::DEBUG::2016-02-29 11:46:04,240::supervdsmServer::111::SuperVdsm.ServerCallback::(wrapper) call wrapper with ('a_c7_1',) {}
MainProcess|periodic/2::DEBUG::2016-02-29 11:46:04,248::supervdsmServer::118::SuperVdsm.ServerCallback::(wrapper) return wrapper with {0: [0], 1: [0]}
MainProcess|periodic/0::DEBUG::2016-02-29 11:46:19,245::supervdsmServer::111::SuperVdsm.ServerCallback::(wrapper) call wrapper with ('a_c7_1',) {}
MainProcess|periodic/0::DEBUG::2016-02-29 11:46:19,254::supervdsmServer::118::SuperVdsm.ServerCallback::(wrapper) return wrapper with {0: [0], 1: [0]}
MainProcess|periodic/3::DEBUG::2016-02-29 11:46:34,240::supervdsmServer::111::SuperVdsm.ServerCallback::(wrapper) call wrapper with ('a_c7_1',) {}
MainProcess|periodic/3::DEBUG::2016-02-29 11:46:34,248::supervdsmServer::118::SuperVdsm.ServerCallback::(wrapper) return wrapper with {0: [0], 1: [0]}
MainProcess|periodic/1::DEBUG::2016-02-29 11:46:49,240::supervdsmServer::111::SuperVdsm.ServerCallback::(wrapper) call wrapper with ('a_c7_1',) {}
MainProcess|periodic/1::DEBUG::2016-02-29 11:46:49,249::supervdsmServer::118::SuperVdsm.ServerCallback::(wrapper) return wrapper with {0: [0], 1: [0]}

https://gerrit.ovirt.org/#/c/54004/3

Comment 11 Francesco Romani 2016-03-01 08:41:29 UTC
Previously it was something like

MainProcess|periodic/1::DEBUG::2016-02-25 02:02:15,769::supervdsmServer::122::SuperVdsm.ServerCallback::(wrapper) return getVcpuNumaMemoryMapping with {0: [0], 1: [0]}
MainProcess|periodic/2::DEBUG::2016-02-25 02:02:30,779::supervdsmServer::115::SuperVdsm.ServerCallback::(wrapper) call getVcpuNumaMemoryMapping with ('a_c7_1',) {}
MainProcess|periodic/2::DEBUG::2016-02-25 02:02:30,780::supervdsmServer::115::SuperVdsm.ServerCallback::(wrapper) call getVmPid with ('a_c7_1',) {}
MainProcess|periodic/2::DEBUG::2016-02-25 02:02:30,780::supervdsmServer::122::SuperVdsm.ServerCallback::(wrapper) return getVmPid with 22331
MainProcess|periodic/2::DEBUG::2016-02-25 02:02:30,788::supervdsmServer::122::SuperVdsm.ServerCallback::(wrapper) return getVcpuNumaMemoryMapping with {0: [0], 1: [0]}
MainProcess|periodic/1::DEBUG::2016-02-25 02:02:45,762::supervdsmServer::115::SuperVdsm.ServerCallback::(wrapper) call getVcpuNumaMemoryMapping with ('a_c7_1',) {}
MainProcess|periodic/1::DEBUG::2016-02-25 02:02:45,762::supervdsmServer::115::SuperVdsm.ServerCallback::(wrapper) call getVmPid with ('a_c7_1',) {}
MainProcess|periodic/1::DEBUG::2016-02-25 02:02:45,762::supervdsmServer::122::SuperVdsm.ServerCallback::(wrapper) return getVmPid with 22331
MainProcess|periodic/1::DEBUG::2016-02-25 02:02:45,770::supervdsmServer::122::SuperVdsm.ServerCallback::(wrapper) return getVcpuNumaMemoryMapping with {0: [0], 1: [0]}
MainProcess|periodic/3::DEBUG::2016-02-25 02:03:00,766::supervdsmServer::115::SuperVdsm.ServerCallback::(wrapper) call getVcpuNumaMemoryMapping with ('a_c7_1',) {}
MainProcess|periodic/3::DEBUG::2016-02-25 02:03:00,766::supervdsmServer::115::SuperVdsm.ServerCallback::(wrapper) call getVmPid with ('a_c7_1',) {}
MainProcess|periodic/3::DEBUG::2016-02-25 02:03:00,767::supervdsmServer::122::SuperVdsm.ServerCallback::(wrapper) return getVmPid with 22331
MainProcess|periodic/3::DEBUG::2016-02-25 02:03:00,774::supervdsmServer::122::SuperVdsm.ServerCallback::(wrapper) return getVcpuNumaMemoryMapping with {0: [0], 1: [0]}
MainProcess|periodic/1::DEBUG::2016-02-25 02:03:15,763::supervdsmServer::115::SuperVdsm.ServerCallback::(wrapper) call getVcpuNumaMemoryMapping with ('a_c7_1',) {}
MainProcess|periodic/1::DEBUG::2016-02-25 02:03:15,763::supervdsmServer::115::SuperVdsm.ServerCallback::(wrapper) call getVmPid with ('a_c7_1',) {}
MainProcess|periodic/1::DEBUG::2016-02-25 02:03:15,763::supervdsmServer::122::SuperVdsm.ServerCallback::(wrapper) return getVmPid with 22331
MainProcess|periodic/1::DEBUG::2016-02-25 02:03:15,771::supervdsmServer::122::SuperVdsm.ServerCallback::(wrapper) return getVcpuNumaMemoryMapping with {0: [0], 1: [0]}
MainProcess|periodic/3::DEBUG::2016-02-25 02:03:30,768::supervdsmServer::115::SuperVdsm.ServerCallback::(wrapper) call getVcpuNumaMemoryMapping with ('a_c7_1',) {}
MainProcess|periodic/3::DEBUG::2016-02-25 02:03:30,768::supervdsmServer::115::SuperVdsm.ServerCallback::(wrapper) call getVmPid with ('a_c7_1',) {}
MainProcess|periodic/3::DEBUG::2016-02-25 02:03:30,769::supervdsmServer::122::SuperVdsm.ServerCallback::(wrapper) return getVmPid with 22331
MainProcess|periodic/3::DEBUG::2016-02-25 02:03:30,776::supervdsmServer::122::SuperVdsm.ServerCallback::(wrapper) return getVcpuNumaMemoryMapping with {0: [0], 1: [0]}
MainProcess|periodic/1::DEBUG::2016-02-25 02:03:45,765::supervdsmServer::115::SuperVdsm.ServerCallback::(wrapper) call getVcpuNumaMemoryMapping with ('a_c7_1',) {}
MainProcess|periodic/1::DEBUG::2016-02-25 02:03:45,765::supervdsmServer::115::SuperVdsm.ServerCallback::(wrapper) call getVmPid with ('a_c7_1',) {}
MainProcess|periodic/1::DEBUG::2016-02-25 02:03:45,765::supervdsmServer::122::SuperVdsm.ServerCallback::(wrapper) return getVmPid with 22331
MainProcess|periodic/1::DEBUG::2016-02-25 02:03:45,773::supervdsmServer::122::SuperVdsm.ServerCallback::(wrapper) return getVcpuNumaMemoryMapping with {0: [0], 1: [0]}
MainProcess|periodic/0::DEBUG::2016-02-25 02:04:00,768::supervdsmServer::115::SuperVdsm.ServerCallback::(wrapper) call getVcpuNumaMemoryMapping with ('a_c7_1',) {}
MainProcess|periodic/0::DEBUG::2016-02-25 02:04:00,769::supervdsmServer::115::SuperVdsm.ServerCallback::(wrapper) call getVmPid with ('a_c7_1',) {}
MainProcess|periodic/0::DEBUG::2016-02-25 02:04:00,769::supervdsmServer::122::SuperVdsm.ServerCallback::(wrapper) return getVmPid with 22331

Comment 12 Yaniv Bronhaim 2016-03-01 12:03:35 UTC
oh sorry. apparently I checked only vdsm.log in that regards which prints this same output fine: 

Thread-191::DEBUG::2016-03-01 04:05:14,299::bindingxmlrpc::1253::vds::(wrapper) client [::1]::call getHardwareInfo with () {}

Thread-982::DEBUG::2016-03-01 06:48:09,922::bindingxmlrpc::1253::vds::(wrapper) client [::1]::call setupNetworks with ({}, {}, {'connectivityCheck': 'False'}) {}

fixing it is easy - posting https://gerrit.ovirt.org/54209

Moving bug to modified, as this issue is not related to the RFE itself and the patch for the plug-able API is already merged.

Comment 13 Gil Klein 2016-08-11 07:57:41 UTC
This bug was fixed and is slated to be in the upcoming version. As we
are focusing our testing at this phase on severe bugs, this bug was
closed without going through its verification step. If you think this
bug should be verified by QE, please set its severity to high and move
it back to ON_QA