Description of problem: AttributeError: 'VMSnapshotDisks' object has no attribute 'export' Traceback (most recent call last): File "/var/lib/jenkins/workspace/3.3-storage_virtio_scsi_sanity-iscsi-sdk/automation/ART/art/test_handler/plmanagement/plugins/unittest_test_runner_plugin.py", line 126, in __call__ self.f() File "/var/lib/jenkins/workspace/3.3-storage_virtio_scsi_sanity-iscsi-sdk/automation/ART/art/tests/rhevm/unittests/storage/storage_virtio_scsi/test_virtio_scsi.py", line 335, in test_clone_vm_with_virtio_scsi_disk_from_snapshot cluster=config.CLUSTER_NAME)) File "/var/lib/jenkins/workspace/3.3-storage_virtio_scsi_sanity-iscsi-sdk/automation/ART/art/rhevm_api/tests_lib/low_level/vms.py", line 359, in addVm vmObj, status = VM_API.create(vmObj, positive, expectedEntity=expectedVm) File "/var/lib/jenkins/workspace/3.3-storage_virtio_scsi_sanity-iscsi-sdk/automation/ART/art/core_api/ovirtsdk_utils.py", line 126, in create response = collection.add(entity, **self.getReqMatrixParams(current)) File "/usr/lib/python2.6/site-packages/ovirtsdk/infrastructure/brokers.py", line 16982, in add body=ParseHelper.toXml(vm), File "/usr/lib/python2.6/site-packages/ovirtsdk/utils/parsehelper.py", line 35, in toXml entity.export(output, 0, name_=ParseHelper.getXmlTypeInstance(type_name)) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 16003, in export self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 16084, in exportChildren self.snapshots.export(outfile, level, namespace_, name_='snapshots', pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19350, in export self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19364, in exportChildren snapshot_.export(outfile, level, namespace_, name_='snapshot', pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19223, in export self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19231, in exportChildren super(Snapshot, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 16076, in exportChildren self.disks.export(outfile, level, namespace_, name_='disks', pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/infrastructure/common.py", line 32, in __getattr__ return self.__getattribute__(item) AttributeError: 'VMSnapshotDisks' object has no attribute 'export' Version-Release number of selected component (if applicable): is20 How reproducible: 100%
Meital, 1. VMSnapshotDisks is a collection proxy, while this type of actions are exist at object 2. VMSnapshotDisk does not have /export cause it not exposed/supported by api at [1]. [1] '/api/vms/{vm:id}/snapshots/{snapshot:id}/disks/{disk:id}' thanks.
Reproduced directly on sdk: Trying to clone a VM from snapshot works only if the snapshots argument passed to the VM object is initially created with snapshot passed as a list: >>> snapshots = params.Snapshots(snapshot=[snap_to_clone]) >>> newVM = params.VM(name='newVM', description='newVM', cluster=cluster, snapshots=snapshots) >>> api.vms.add(newVM) <ovirtsdk.infrastructure.brokers.VM object at 0x1e53510> Creating a new Snapshots() object and using the .add_snapshot(snapshot) method fails: >>> snapshots = params.Snapshots() >>> snapshots.add_snapshot(snap_to_clone) >>> newVM = params.VM(name='newVM', description='newVM', cluster=cluster, snapshots=snapshots) >>> api.vms.add(newVM) Traceback (most recent call last): File "<input>", line 1, in <module> File "/usr/lib/python2.6/site-packages/ovirtsdk/infrastructure/brokers.py", line 16996, in add body=ParseHelper.toXml(vm), File "/usr/lib/python2.6/site-packages/ovirtsdk/utils/parsehelper.py", line 35, in toXml entity.export(output, 0, name_=ParseHelper.getXmlTypeInstance(type_name)) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 16099, in export self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 16180, in exportChildren self.snapshots.export(outfile, level, namespace_, name_='snapshots', pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19474, in export self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19488, in exportChildren snapshot_.export(outfile, level, namespace_, name_='snapshot', pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19347, in export self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19355, in exportChildren super(Snapshot, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 16172, in exportChildren self.disks.export(outfile, level, namespace_, name_='disks', pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/infrastructure/common.py", line 32, in _getattr_ return self._getattribute_(item) AttributeError: 'VMSnapshotDisks' object has no attribute 'export' Passing a list to .add_snapshot() also fails: >>> snapshots = params.Snapshots() >>> snapshots.add_snapshot([snap_to_clone]) >>> newVM = params.VM(name='newVM', description='newVM', cluster=cluster, snapshots=snapshots) >>> api.vms.add(newVM) Traceback (most recent call last): File "<input>", line 1, in <module> File "/usr/lib/python2.6/site-packages/ovirtsdk/infrastructure/brokers.py", line 16996, in add body=ParseHelper.toXml(vm), File "/usr/lib/python2.6/site-packages/ovirtsdk/utils/parsehelper.py", line 35, in toXml entity.export(output, 0, name_=ParseHelper.getXmlTypeInstance(type_name)) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 16099, in export self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 16180, in exportChildren self.snapshots.export(outfile, level, namespace_, name_='snapshots', pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19474, in export self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19488, in exportChildren snapshot_.export(outfile, level, namespace_, name_='snapshot', pretty_print=pretty_print) AttributeError: 'list' object has no attribute 'export'
(In reply to Gadi Ickowicz from comment #3) > Reproduced directly on sdk: > > Trying to clone a VM from snapshot works only if the snapshots argument > passed to the VM object is initially created with snapshot passed as a list: > > >>> snapshots = params.Snapshots(snapshot=[snap_to_clone]) > >>> newVM = params.VM(name='newVM', description='newVM', cluster=cluster, snapshots=snapshots) > >>> api.vms.add(newVM) > <ovirtsdk.infrastructure.brokers.VM object at 0x1e53510> > > Creating a new Snapshots() object and using the .add_snapshot(snapshot) > method fails: > > >>> snapshots = params.Snapshots() > >>> snapshots.add_snapshot(snap_to_clone) > >>> newVM = params.VM(name='newVM', description='newVM', cluster=cluster, snapshots=snapshots) > >>> api.vms.add(newVM) > Traceback (most recent call last): > File "<input>", line 1, in <module> > File "/usr/lib/python2.6/site-packages/ovirtsdk/infrastructure/brokers.py", > line 16996, in add > body=ParseHelper.toXml(vm), > File "/usr/lib/python2.6/site-packages/ovirtsdk/utils/parsehelper.py", line > 35, in toXml > entity.export(output, 0, name_=ParseHelper.getXmlTypeInstance(type_name)) > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 16099, > in export > self.exportChildren(outfile, level + 1, namespace_, name_, > pretty_print=pretty_print) > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 16180, > in exportChildren > self.snapshots.export(outfile, level, namespace_, name_='snapshots', > pretty_print=pretty_print) > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19474, > in export > self.exportChildren(outfile, level + 1, namespace_, name_, > pretty_print=pretty_print) > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19488, > in exportChildren > snapshot_.export(outfile, level, namespace_, name_='snapshot', > pretty_print=pretty_print) > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19347, > in export > self.exportChildren(outfile, level + 1, namespace_, name_, > pretty_print=pretty_print) > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19355, > in exportChildren > super(Snapshot, self).exportChildren(outfile, level, namespace_, name_, > True, pretty_print=pretty_print) > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 16172, > in exportChildren > self.disks.export(outfile, level, namespace_, name_='disks', > pretty_print=pretty_print) > File "/usr/lib/python2.6/site-packages/ovirtsdk/infrastructure/common.py", > line 32, in _getattr_ > return self._getattribute_(item) > AttributeError: 'VMSnapshotDisks' object has no attribute 'export' > > Passing a list to .add_snapshot() also fails: > > >>> snapshots = params.Snapshots() > >>> snapshots.add_snapshot([snap_to_clone]) > >>> newVM = params.VM(name='newVM', description='newVM', cluster=cluster, snapshots=snapshots) > >>> api.vms.add(newVM) > Traceback (most recent call last): > File "<input>", line 1, in <module> > File > "/usr/lib/python2.6/site-packages/ovirtsdk/infrastructure/brokers.py", line > 16996, in add > body=ParseHelper.toXml(vm), > File "/usr/lib/python2.6/site-packages/ovirtsdk/utils/parsehelper.py", > line 35, in toXml > entity.export(output, 0, name_=ParseHelper.getXmlTypeInstance(type_name)) > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line > 16099, in export > self.exportChildren(outfile, level + 1, namespace_, name_, > pretty_print=pretty_print) > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line > 16180, in exportChildren > self.snapshots.export(outfile, level, namespace_, name_='snapshots', > pretty_print=pretty_print) > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line > 19474, in export > self.exportChildren(outfile, level + 1, namespace_, name_, > pretty_print=pretty_print) > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line > 19488, in exportChildren > snapshot_.export(outfile, level, namespace_, name_='snapshot', > pretty_print=pretty_print) > AttributeError: 'list' object has no attribute 'export' Gadi, Snapshot should be added via /snapshots collection and not to vm object (you trying to access vm property), the code should look like: vm = api.vms.get(name=xxx) snapshot = params.Snapshot(...) vm.snapshots.add(snapshot)
(In reply to Michael Pasternak from comment #4) > (In reply to Gadi Ickowicz from comment #3) > > Reproduced directly on sdk: > > > > Trying to clone a VM from snapshot works only if the snapshots argument > > passed to the VM object is initially created with snapshot passed as a list: > > > > >>> snapshots = params.Snapshots(snapshot=[snap_to_clone]) > > >>> newVM = params.VM(name='newVM', description='newVM', cluster=cluster, snapshots=snapshots) > > >>> api.vms.add(newVM) > > <ovirtsdk.infrastructure.brokers.VM object at 0x1e53510> > > > > Creating a new Snapshots() object and using the .add_snapshot(snapshot) > > method fails: > > this is by design, when you pass parameters holder, it should have all necessary info for the action, passing it afterwords does not make any sense.
(In reply to Michael Pasternak from comment #4) > (In reply to Gadi Ickowicz from comment #3) > > Reproduced directly on sdk: > > > > Trying to clone a VM from snapshot works only if the snapshots argument > > passed to the VM object is initially created with snapshot passed as a list: > > > > >>> snapshots = params.Snapshots(snapshot=[snap_to_clone]) > > >>> newVM = params.VM(name='newVM', description='newVM', cluster=cluster, snapshots=snapshots) > > >>> api.vms.add(newVM) > > <ovirtsdk.infrastructure.brokers.VM object at 0x1e53510> > > > > Creating a new Snapshots() object and using the .add_snapshot(snapshot) > > method fails: > > > > >>> snapshots = params.Snapshots() > > >>> snapshots.add_snapshot(snap_to_clone) > > >>> newVM = params.VM(name='newVM', description='newVM', cluster=cluster, snapshots=snapshots) > > >>> api.vms.add(newVM) > > Traceback (most recent call last): > > File "<input>", line 1, in <module> > > File "/usr/lib/python2.6/site-packages/ovirtsdk/infrastructure/brokers.py", > > line 16996, in add > > body=ParseHelper.toXml(vm), > > File "/usr/lib/python2.6/site-packages/ovirtsdk/utils/parsehelper.py", line > > 35, in toXml > > entity.export(output, 0, name_=ParseHelper.getXmlTypeInstance(type_name)) > > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 16099, > > in export > > self.exportChildren(outfile, level + 1, namespace_, name_, > > pretty_print=pretty_print) > > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 16180, > > in exportChildren > > self.snapshots.export(outfile, level, namespace_, name_='snapshots', > > pretty_print=pretty_print) > > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19474, > > in export > > self.exportChildren(outfile, level + 1, namespace_, name_, > > pretty_print=pretty_print) > > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19488, > > in exportChildren > > snapshot_.export(outfile, level, namespace_, name_='snapshot', > > pretty_print=pretty_print) > > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19347, > > in export > > self.exportChildren(outfile, level + 1, namespace_, name_, > > pretty_print=pretty_print) > > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 19355, > > in exportChildren > > super(Snapshot, self).exportChildren(outfile, level, namespace_, name_, > > True, pretty_print=pretty_print) > > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line 16172, > > in exportChildren > > self.disks.export(outfile, level, namespace_, name_='disks', > > pretty_print=pretty_print) > > File "/usr/lib/python2.6/site-packages/ovirtsdk/infrastructure/common.py", > > line 32, in _getattr_ > > return self._getattribute_(item) > > AttributeError: 'VMSnapshotDisks' object has no attribute 'export' > > > > Passing a list to .add_snapshot() also fails: > > > > >>> snapshots = params.Snapshots() > > >>> snapshots.add_snapshot([snap_to_clone]) > > >>> newVM = params.VM(name='newVM', description='newVM', cluster=cluster, snapshots=snapshots) > > >>> api.vms.add(newVM) > > Traceback (most recent call last): > > File "<input>", line 1, in <module> > > File > > "/usr/lib/python2.6/site-packages/ovirtsdk/infrastructure/brokers.py", line > > 16996, in add > > body=ParseHelper.toXml(vm), > > File "/usr/lib/python2.6/site-packages/ovirtsdk/utils/parsehelper.py", > > line 35, in toXml > > entity.export(output, 0, name_=ParseHelper.getXmlTypeInstance(type_name)) > > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line > > 16099, in export > > self.exportChildren(outfile, level + 1, namespace_, name_, > > pretty_print=pretty_print) > > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line > > 16180, in exportChildren > > self.snapshots.export(outfile, level, namespace_, name_='snapshots', > > pretty_print=pretty_print) > > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line > > 19474, in export > > self.exportChildren(outfile, level + 1, namespace_, name_, > > pretty_print=pretty_print) > > File "/usr/lib/python2.6/site-packages/ovirtsdk/xml/params.py", line > > 19488, in exportChildren > > snapshot_.export(outfile, level, namespace_, name_='snapshot', > > pretty_print=pretty_print) > > AttributeError: 'list' object has no attribute 'export' > > Gadi, > > Snapshot should be added via /snapshots collection and not to vm object > (you trying to access vm property), the code should look like: > > vm = api.vms.get(name=xxx) > snapshot = params.Snapshot(...) > vm.snapshots.add(snapshot) I am not creating a new snapshot - I am trying to set the snapshot for a newVM to be cloned from. That is: >>> snapshot = api.vms.get(name=...).snapshots.get(...) >>> newVM = params.VM(...... snapshots=snapshot) However this syntax does not work, I must pass snapsots=[snapshot] for it to work. Trying to do newVM = params.VM(.....) without the snapshots attribute then using newVM.snapshots.add_snapshot fails since newVM.snapshots is None
(In reply to Gadi Ickowicz from comment #6) > > Gadi, > > > > Snapshot should be added via /snapshots collection and not to vm object > > (you trying to access vm property), the code should look like: > > > > vm = api.vms.get(name=xxx) > > snapshot = params.Snapshot(...) > > vm.snapshots.add(snapshot) > I am not creating a new snapshot - I am trying to set the snapshot for a > newVM to be cloned from. > > That is: > >>> snapshot = api.vms.get(name=...).snapshots.get(...) > >>> newVM = params.VM(...... snapshots=snapshot) > > However this syntax does not work, I must pass snapsots=[snapshot] for it to > work. > > Trying to do newVM = params.VM(.....) without the snapshots attribute then > using newVM.snapshots.add_snapshot fails since newVM.snapshots is None gadi, this is not the syntax to be used, you mix two concepts, please refer to sdk documentation.
Gadi, this is indeed a bug that involves generateDS objects assignment, but solution i see includes upgrading/modifying generateDS what is obviously too noisy for 3.3, also since it's a "edge case" (the official and documented way to assign parameters is via constructor), i'm moving this bug to 3.4 thanks.
The way to create a VM from a snapshot is the following: # Find the id of the source snapshot, and then create a Snapshot object # wrapping it, and a Snapshots object wrapping the list: snap = ovirtsdk.xml.params.Snapshot(id=...) snaps = ovirtsdk.xml.params.Snapshots(snapshot=[snap]) # Create and populate the VM object: vm = ovirtsdk.xml.params.VM(name="newvm", snapshots=snaps, cluster=...) api.vms.add(vm) The reason for this verbosity is how the operation to add a VM is defined in the RESTAPI (from rdsl_metadata.yaml): - name: /vms|rel=add description: add a virtual machine to the system request: body: parameterType: VM signatures: ... # the following signature is for clone VM from a Snapshot - requires the Snapshot ID - mandatoryArguments: {vm.name: 'xs:string', vm.template.id|name: 'xs:string', vm.cluster.id|name: 'xs:string', vm.snapshots.snapshot--COLLECTION: {snapshot.id: 'xs:string'}} We have selected to reuse the vm.snapshots.snapshot collection for this purpose, and thus the user of the SDK needs to reproduce that structure, including the [snap] list. Same happens for any parameter that is defined as a collection. I think that there isn't a problem with generateDS here, updating its version won't change anything in these regards.
The problem is that the python sdk exposes the Snapshots.add_snapshot() method, yet using function creates objects that are not valid. Either the function should not be exposed, or the objects it creates should be usable - that is: >>> snapshots = ovirtsdk.xml.params.Snapshots() >>> snap = api.vms.find(...).get_snapshots()[0] >>> snapshots.add_snapshot(snap)
I think that the way you are using the SDK is bad practice, and not efficient. You can do the same this way using parameters classes instead of decorators: snapshot = ovirtsdk.xml.params.Snapshot(id="...") snapshots = ovirtsdk.xml.params.Snapshots() snapshots.add_snapshot(snapshot) newvm = ovirtsdk.xml.params.VM(name="newvm", snapshots=snapshots, ...) api.vms.add(newvm) But I understand your point of view. The proposed patch should fix your use case.
*** Bug 1063665 has been marked as a duplicate of this bug. ***
[root@pb-rh35 ~]# ./test.py Connected to oVirt Engine successfully! [root@pb-rh35 ~]# cat test.py #!/usr/bin/env python from ovirtsdk.api import API from ovirtsdk.xml import params try: api = API (url="TODO", username="admin@internal", password="XXXXXX", ca_file="ca.crt") print "Connected to %s successfully!" % api.get_product_info().name snapshots = params.Snapshots() # snap = api.vms.find(...).get_snapshots()[0] vm = api.vms.get(name="testtesttest") snap = vm.get_snapshots() snapshots.add_snapshot(snap.list()[0]) api.disconnect() except Exception as ex: print "Unexpected error: %s" % ex [root@pb-rh35 ~]# rpm -qa ovirt-engine-cli ovirt-engine-cli-3.5.0.2-1.20140710.git52d7a57.el6.noarch
Updated the scenario, thanks Gadi for your comments. [root@pb-rh35 ~]# ./test.py Connected to oVirt Engine successfully! [root@pb-rh35 ~]# cat test.py #!/usr/bin/env python from ovirtsdk.api import API from ovirtsdk.xml import params try: api = API (url="TODO", username="admin@internal", password="XXXXXXX", ca_file="ca.crt") print "Connected to %s successfully!" % api.get_product_info().name snapshots = params.Snapshots() # snap = api.vms.find(...).get_snapshots()[0] vm = api.vms.get(name="testtesttest") snap = vm.get_snapshots() snapshots.add_snapshot(snap.list()[0]) cluster = api.clusters.get(name='Default') newVM = params.VM(name='newVM', description='foo', cluster=cluster, snapshots=snapshots) api.vms.add(vm=newVM) api.disconnect() except Exception as ex: print "Unexpected error: %s" % ex
The fix for this bug has been reverted: http://gerrit.ovirt.org/31362
Why? This was already verified in 3.5...
Because it introduced a regression, see bug 1122546.
Moved the bug back to VERIFIED and 3.5 as requested by QE. Note that the issue is *not* fixed in 3.5, as the patch has been reverted.
Changing to NEW and 3.6 after discussing it again with QE.
*** Bug 1131901 has been marked as a duplicate of this bug. ***
Verified on 3.6.0-0.0.master.20150519172219.git9a2e2b3.el6
Since the problem described in this bug report should be resolved in a recent advisory, it has been closed with a resolution of ERRATA. For information on the advisory, and where to find the updated files, follow the link below. If the solution does not work for you, open a new bug report. https://rhn.redhat.com/errata/RHEA-2016-0403.html