Repository: ansible/ansible

Issue:
ovirt_vms: Unable to attach disks to VM which is create from template
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
ovirt_vms

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
2.3
```

##### CONFIGURATION
<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->

##### SUMMARY
<!--- Explain the problem briefly -->
When using `disks` parameter to attach other disks to VM the attach of disks fails, because VM is being created. We need to wait until VM is created and then attach the disks.

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- name: "Create VM {{current_vm.name }}"
  ovirt_vms:
    auth: "{{ ovirt_auth }}"
    state: "present"
    name: "{{ current_vm.name }}"
    cluster: "{{ current_vm.profile.cluster | default(omit) }}"
    template: "{{ current_vm.profile.template | default(omit) }}
    timeout: "{{ vm_infra_create_single_timeout }}"
    disks:
      - id: "123"
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
Successfully attached disk with ID `123`.

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->
```
The full traceback is:
Traceback (most recent call last):
  File "/tmp/ansible_e1Uae7/ansible_module_ovirt_vms.py", line 1155, in main
    clone_permissions=module.params['clone_permissions'],
  File "/tmp/ansible_e1Uae7/ansible_modlib.zip/ansible/module_utils/ovirt.py", line 576, in create
    self.post_create(entity)
  File "/tmp/ansible_e1Uae7/ansible_module_ovirt_vms.py", line 704, in post_create
    self.changed = self.__attach_disks(entity)
  File "/tmp/ansible_e1Uae7/ansible_module_ovirt_vms.py", line 864, in __attach_disks
    bootable=disk.get('bootable', False),
  File "/usr/lib64/python2.7/site-packages/ovirtsdk4/services.py", line 5180, in add
    return self._internal_add(attachment, headers, query, wait)
  File "/usr/lib64/python2.7/site-packages/ovirtsdk4/service.py", line 223, in _internal_add
    return future.wait() if wait else future
  File "/usr/lib64/python2.7/site-packages/ovirtsdk4/service.py", line 53, in wait
    return self._code(response)
  File "/usr/lib64/python2.7/site-packages/ovirtsdk4/service.py", line 220, in callback
    self._check_fault(response)
  File "/usr/lib64/python2.7/site-packages/ovirtsdk4/service.py", line 123, in _check_fault
    self._raise_error(response, body)
  File "/usr/lib64/python2.7/site-packages/ovirtsdk4/service.py", line 109, in _raise_error
    raise error
Error: Fault reason is "Operation Failed". Fault detail is "[Cannot attach Virtual Disk because the VM is in Image Locked status.]". HTTP response code is 409.

```

<!--- Paste verbatim command output between quotes below -->
```

```



Discussion:
@machacekondra , is it possible to attach disk at the time of creating a VM with template via GUI ? the 'instance image' field at the GUI is disabled in RHEV 4.0

if i attach secondary disk when the creation is in progress, it says
```
Error while executing action:
test-vm:
    Cannot add Virtual Disk: VM is locked. Please try again in a few minutes
```
@mkrish004c It's possible only with `Blank` template. Not with any template containing disks, but still this should work in Ansible..

In GUI you need to simply wait until all VMs disks are in `OK` state.
cc @mwperina
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/modules/cloud/ovirt/ovirt_vms.py b/lib/ansible/modules/cloud/ovirt/ovirt_vms.py
--- a/lib/ansible/modules/cloud/ovirt/ovirt_vms.py
+++ b/lib/ansible/modules/cloud/ovirt/ovirt_vms.py
@@ -843,6 +843,17 @@ def _wait_for_UP(self, vm_service):
             timeout=self.param('timeout'),
         )
 
+    def _wait_for_vm_disks(self, vm_service):
+        disks_service = self._connection.system_service().disks_service()
+        for da in vm_service.disk_attachments_service().list():
+            disk_service = disks_service.disk_service(da.disk.id)
+            wait(
+                service=disk_service,
+                condition=lambda disk: disk.status == otypes.DiskStatus.OK,
+                wait=self.param('wait'),
+                timeout=self.param('timeout'),
+            )
+
     def wait_for_down(self, vm):
         """
         This function will first wait for the status DOWN of the VM.
@@ -884,8 +895,14 @@ def wait_for_down(self, vm):
         return True
 
     def __attach_disks(self, entity):
+        if not self.param('disks'):
+            return
+
+        vm_service = self._service.service(entity.id)
         disks_service = self._connection.system_service().disks_service()
+        disk_attachments_service = vm_service.disk_attachments_service()
 
+        self._wait_for_vm_disks(vm_service)
         for disk in self.param('disks'):
             # If disk ID is not specified, find disk by name:
             disk_id = disk.get('id')
@@ -900,8 +917,8 @@ def __attach_disks(self, entity):
                 )
 
             # Attach disk to VM:
-            disk_attachments_service = self._service.service(entity.id).disk_attachments_service()
-            if get_entity(disk_attachments_service.attachment_service(disk_id)) is None:
+            disk_attachment = disk_attachments_service.attachment_service(disk_id)
+            if get_entity(disk_attachment) is None:
                 if not self._module.check_mode:
                     disk_attachments_service.add(
                         otypes.DiskAttachment(


Test patch: