Bug 1120502 - return TypeError when use sdk to get storages of a host
Summary: return TypeError when use sdk to get storages of a host
Keywords:
Status: CLOSED CURRENTRELEASE
Alias: None
Product: oVirt
Classification: Retired
Component: ovirt-engine-sdk
Version: 3.5
Hardware: Unspecified
OS: Unspecified
unspecified
high
Target Milestone: ---
: 3.5.0
Assignee: Juan Hernández
QA Contact: Antonin Pagac
URL:
Whiteboard: infra
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2014-07-17 05:26 UTC by 马立克
Modified: 2016-02-10 19:32 UTC (History)
5 users (show)

Fixed In Version: ovirt-engine-sdk-python-3.5.0.3-1
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2014-10-17 12:24:02 UTC
oVirt Team: Infra
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
oVirt gerrit 30210 0 master MERGED codegen: Fix naming conflict Never
oVirt gerrit 30251 0 sdk_3.5 MERGED codegen: Fix naming conflict Never

Description 马立克 2014-07-17 05:26:36 UTC
Description of problem:
When i use the python sdk to get storage of a host, it returns a TypeError:
__init__() got multiple values for keyword argument 'context'

Version-Release number of selected component (if applicable):


How reproducible:
Always

Steps to Reproduce:
1.Make sure there is a Up host in the datacenter
2.Supposed the uuid of the host is "11111111-1111-1111-1111-111111111111"
3.Use following codes to get storage of the host:
from ovirtsdk.xml import params
from ovirtsdk.api import API

api = API(url='127.0.0.1/api',username='admin@internal',password='password',insecure=True,persistent_auth=False)
storage = api.hosts.get(id='11111111-1111-1111-1111-111111111111').storage.list()

Actual results:
it returns TypeError: __init__() got multiple values for keyword argument 'context'

Expected results:
it returns storage of the host

Additional info:
Traceback (most recent call last):
  File "test.py", line 6, in <module>
    storages = api.hosts.get(id='11111111-1111-1111-1111-111111111111').storage.list()
  File "/root/sdkforbuild/src/ovirtsdk/infrastructure/brokers.py", line 10400, in list
    context=self.context
  File "/root/sdkforbuild/src/ovirtsdk/utils/parsehelper.py", line 148, in toSubCollection
    new_coll.append(ParseHelper.toSubType(fromItem, toType, parent, **kwargs))
  File "/root/sdkforbuild/src/ovirtsdk/utils/parsehelper.py", line 128, in toSubType
    return toType(parent, fromItem, **kwargs)
TypeError: __init__() got multiple values for keyword argument 'context'

Comment 1 Juan Hernández 2014-07-17 09:21:37 UTC
This happens because we have a sub collection of hosts that doesn't follow the convention of having names for collections in plural and names for entities in singular:

  /hosts/{host:id}/storage

Note that the name is *storage* instead of *storages*.

The generator of the SDK assumes this convention, and in this particular case it generates a HostStorage class for the entity that overwrites the same HostStorage class for the collection. As a result when the SDK tries to create the instance for the collection it is actually creating an instance of the entity, thus the constructor (the __init__() method of the HostStorage class) receives wrong arguments.

The ideal fix for this would be to rename that collection to "storages", but we can't do that as it would break backwards compatibility. Instead of that we will need to introduce an exception in the code generator, which isn't trivial.

Comment 2 马立克 2014-07-17 10:08:19 UTC
(In reply to Juan Hernández from comment #1)
> This happens because we have a sub collection of hosts that doesn't follow
> the convention of having names for collections in plural and names for
> entities in singular:
> 
>   /hosts/{host:id}/storage
> 
> Note that the name is *storage* instead of *storages*.
> 
> The generator of the SDK assumes this convention, and in this particular
> case it generates a HostStorage class for the entity that overwrites the
> same HostStorage class for the collection. As a result when the SDK tries to
> create the instance for the collection it is actually creating an instance
> of the entity, thus the constructor (the __init__() method of the
> HostStorage class) receives wrong arguments.
> 
> The ideal fix for this would be to rename that collection to "storages", but
> we can't do that as it would break backwards compatibility. Instead of that
> we will need to introduce an exception in the code generator, which isn't
> trivial.

OK, i see. Thank you for your reply.

Comment 3 Juan Hernández 2014-07-17 10:16:51 UTC
The proposed patch should fix the issue in the code generator. Once merged the SDK needs to be regenerated. I see that you are running the SDK from the source, so you may want to apply the patch and re-generate yourself. You can also apply the following patch to the brokers.py file:

diff --git a/src/ovirtsdk/infrastructure/brokers.py b/src/ovirtsdk/infrastructure/brokers.py
index e8fb278..3a4462e 100644
--- a/src/ovirtsdk/infrastructure/brokers.py
+++ b/src/ovirtsdk/infrastructure/brokers.py
@@ -7910,7 +7910,7 @@ class Host(params.Host, Base):
         self.numanodes = HostNumaNodes(self, context)
         self.permissions = HostPermissions(self, context)
         self.statistics = HostStatistics(self, context)
-        self.storage = HostStorage(self, context)
+        self.storage = HostStorages(self, context)
         self.tags = HostTags(self, context)
 
     def __new__(cls, host, context):
@@ -9318,7 +9318,29 @@ class HostStatistics(Base):
             context=self.context
         )
 
-class HostStorage(Base):
+class HostStorage(params.HostStorage, Base):
+    def __init__(self, host, storage, context):
+        Base.__init__(self, context)
+        self.parentclass = host
+        self.superclass  =  storage
+
+        #SUB_COLLECTIONS
+    def __new__(cls, host, storage, context):
+        if storage is None: return None
+        obj = object.__new__(cls)
+        obj.__init__(host, storage, context)
+        return obj
+
+    def __getProxy(self):
+        proxy = context.manager[self.context].get('proxy')
+        if proxy:
+            return proxy
+        #This may happen only if sdk was explicitly disconnected
+        #using .disconnect() method, but resource instance ref. is
+        #still available at client's code.
+        raise DisconnectedError
+
+class HostStorages(Base):
 
     def __init__(self, host , context):
         Base.__init__(self, context)

Comment 4 马立克 2014-07-17 10:28:37 UTC
(In reply to Juan Hernández from comment #3)
> The proposed patch should fix the issue in the code generator. Once merged
> the SDK needs to be regenerated. I see that you are running the SDK from the
> source, so you may want to apply the patch and re-generate yourself. You can
> also apply the following patch to the brokers.py file:
> 
> diff --git a/src/ovirtsdk/infrastructure/brokers.py
> b/src/ovirtsdk/infrastructure/brokers.py
> index e8fb278..3a4462e 100644
> --- a/src/ovirtsdk/infrastructure/brokers.py
> +++ b/src/ovirtsdk/infrastructure/brokers.py
> @@ -7910,7 +7910,7 @@ class Host(params.Host, Base):
>          self.numanodes = HostNumaNodes(self, context)
>          self.permissions = HostPermissions(self, context)
>          self.statistics = HostStatistics(self, context)
> -        self.storage = HostStorage(self, context)
> +        self.storage = HostStorages(self, context)
>          self.tags = HostTags(self, context)
>  
>      def __new__(cls, host, context):
> @@ -9318,7 +9318,29 @@ class HostStatistics(Base):
>              context=self.context
>          )
>  
> -class HostStorage(Base):
> +class HostStorage(params.HostStorage, Base):
> +    def __init__(self, host, storage, context):
> +        Base.__init__(self, context)
> +        self.parentclass = host
> +        self.superclass  =  storage
> +
> +        #SUB_COLLECTIONS
> +    def __new__(cls, host, storage, context):
> +        if storage is None: return None
> +        obj = object.__new__(cls)
> +        obj.__init__(host, storage, context)
> +        return obj
> +
> +    def __getProxy(self):
> +        proxy = context.manager[self.context].get('proxy')
> +        if proxy:
> +            return proxy
> +        #This may happen only if sdk was explicitly disconnected
> +        #using .disconnect() method, but resource instance ref. is
> +        #still available at client's code.
> +        raise DisconnectedError
> +
> +class HostStorages(Base):
>  
>      def __init__(self, host , context):
>          Base.__init__(self, context)

Thank you very much. The patch works well.

Comment 5 Juan Hernández 2014-07-18 07:43:27 UTC
The fix for the code generator has been merged, now the SDK needs to be regenerated.

Comment 6 Antonin Pagac 2014-09-03 12:34:33 UTC
Verified.

sdk: ovirt-engine-sdk-python-3.5.0.5
ovirt: oVirt Engine Version: 3.5.0-0.0.master.20140821064931.gitb794d66.el6

Comment 7 Sandro Bonazzola 2014-10-17 12:24:02 UTC
oVirt 3.5 has been released and should include the fix for this issue.


Note You need to log in before you can comment on or make changes to this bug.