Repository: ansible/ansible

Issue:
azure_rm_managed_disk cannot update existing os disk
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and devel branch are affected too.
Always add information AFTER of these html comments.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest -->
 - Bug Report

##### COMPONENT NAME
<!---
Insert, BELOW THIS COMMENT, the name of the module, plugin, task or feature.
Do not include extra details here, e.g. "vyos_command" not "the network module vyos_command" or the full path
-->

azure_rm_managed_disk

##### ANSIBLE VERSION
<!--- Paste, BELOW THIS COMMENT, verbatim output from "ansible --version" between quotes below -->
```
ansible 2.5.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python2.7/dist-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 2.7.12 (default, Dec  4 2017, 14:50:18) [GCC 5.4.0 20160609]
```

##### CONFIGURATION
<!---
If using Ansible 2.4 or above, paste, BELOW THIS COMMENT, the results of "ansible-config dump --only-changed"
Otherwise, mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

##### OS / ENVIRONMENT
<!---
Mention, BELOW THIS COMMENT, 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.

-->

Ubuntu 16.04.4

##### SUMMARY
<!--- Explain the problem briefly -->
We have been using 'azure_rm_virtualmachine' to create vm. After stopping the machine we would like to increase created os disk size using azure_rm_managed_disk, but updating task is failing:
```
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Error creating the managed disk: Azure Error: PropertyChangeNotAllowed\nMessage: Changing property 'creationData' is not allowed.\nTarget: creationData"}
```
##### 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.
-->
1. Create vm instance with azure_rm_virtualmachine
2. Stop the instance (creating the machine with azure_rm_virtualmachine and 'started' parameter set to 'no' doesn't work.)
3. Update created os disk with azure_rm_managed_disk

<!--- Paste example playbooks or commands between quotes below -->
```yaml

- name: "Create VM"
  azure_rm_virtualmachine:
    resource_group: "{{ resource_group_name }}"
    virtual_network_name: "{{ virtual_network_name }}"
    network_interface_names: "{{ network_interface_name }}"
    storage_account_name: "{{ storage_account_name }}"
    name: "{{vm_name}}"
    vm_size: "{{ vm_size_sku }}"
    image:
      offer: "{{ os_image_offer }}"
      sku: "{{ os_image_sku }}"
      publisher: "{{ os_image_publisher }}"
      version: "{{ os_image_version }}"
    managed_disk_type: Standard_LRS
    started: no

- name: "Power off the machine"
  azure_rm_virtualmachine:
    resource_group: "{{ resource_group_name }}"
    name: "{{vm_name}}"
    allocated: no

- name: "Increase disk size"
  azure_rm_managed_disk:
    name: "{{ vm_name }}"
    resource_group: "{{ resource_group_name }}"
    disk_size_gb: "{{ azure_disk_size }}"
    managed_by: "{{ vm_name }}"

```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
We expect that the task will update existing disk.

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
"msg": "Error creating the managed disk: Azure Error: PropertyChangeNotAllowed\nMessage: Changing property 'creationData' is not allowed.\nTarget: creationData"
```



Discussion:
Files identified in the description:
* [lib/ansible/modules/cloud/azure/azure_rm_managed_disk.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/cloud/azure/azure_rm_managed_disk.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @brusMX
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@PiotrMejer Perform the following YML file , did not meet you describe problem, when removing azure_rm_managed_disk location parameters, it will be prompted similar mistake as you report. could you add location parameter in you YML file , retest , Look to whether can have this problem . Thanks !
``` e.g.
---
# Resource_group and image has create before excute
- name: For Azure learn
  hosts: localhost
  connection: local
  vars:
    resource_group: myRG03
    location: westeurope
    storageaccount: sssaaa04
    virtualnetwork: virtualnetwork04
    subnet: subnet04
    public_ip: public_ip04
    security_ssh: security_ssh04
    test_nic: test_nic04
    vm_name: myVM04
  tasks:
  - name: create resource group
    azure_rm_resourcegroup:
      name: "{{ resource_group }}"
      location: "{{ location }}"

  - name: create storage account
    azure_rm_storageaccount:
      resource_group: "{{ resource_group }}"
      name: "{{ storageaccount }}"
      account_type: Standard_LRS

  - name: create virtual network
    azure_rm_virtualnetwork:
      resource_group: "{{ resource_group }}"
      name: "{{ virtualnetwork }}"
      address_prefixes: "10.0.0.0/16"

  - name: Add subnet
    azure_rm_subnet:
      resource_group: "{{ resource_group }}"
      name: "{{ subnet }}"
      address_prefix: "10.0.1.0/24"
      virtual_network: "{{ virtualnetwork }}"

  - name: create public ip
    azure_rm_publicipaddress:
      resource_group: "{{ resource_group }}"
      allocation_method: Static
      name: "{{ public_ip }}"
  
  - name: Create security group that allows SSH
    azure_rm_securitygroup:
      resource_group: "{{ resource_group }}"
      name: "{{ security_ssh }}"
      rules:
        - name: SSH
          protocol: Tcp
          destination_port_range: 22
          access: Allow
          priority: 101
          direction: Inbound
  
  - name: Create NIC
    azure_rm_networkinterface:
      resource_group: "{{ resource_group }}"
      name: "{{ test_nic }}"
      virtual_network: "{{ virtualnetwork }}"
      subnet: "{{ subnet }}"
      public_ip_name: "{{ public_ip}}"
      security_group: "{{ security_ssh }}"

  - name: create virtual machine
    azure_rm_virtualmachine: 
      resource_group: "{{ resource_group }}"
      name: "{{ vm_name }}"
      state: present
      vm_size: Standard_A0
      managed_disk_type: Standard_LRS
      admin_username: azureuser
      admin_password: Password@0329
      virtual_network_name: "{{ virtualnetwork }}"
      network_interface_names: "{{ test_nic }}"
      storage_account_name: "{{ storageaccount }}"
      image: 
        offer: UbuntuServer
        publisher: Canonical
        sku: 16.04-LTS 
        version: latest 
      started: no

  - name: "Power off the machine"
    azure_rm_virtualmachine:
     resource_group:  "{{ resource_group }}"
     name: "{{vm_name}}"
     allocated: no

  - name: "Increase disk size"
    azure_rm_managed_disk:
      name: mymanagedisk
      location: westeurope
      resource_group: "{{ resource_group }}"
      disk_size_gb: 4
      managed_by: "{{ vm_name }}"



@Fred-sun  thanks for Your reply. I suppose that the attached YML creates vm and os disk with the same name ("{{ vm_name }}"), last task do not update size of existing (created with vm) disk (named {{vm_name}}) but creates new disk (with name = mymanagedisk).
@PiotrMejer Thanks for Your verified, You are right, But when use same name "{{vm_name}}", it will meet error, error message as bellow:
``` e.g.
K [create virtual machine] **************************************************
changed: [127.0.0.1]

TASK [Power off the machine] ***************************************************
changed: [127.0.0.1]

TASK [Increase disk size] ******************************************************
fatal: [127.0.0.1]: FAILED! => {"changed": false, "msg": "Error creating the managed disk: Azure Error: BadRequest\nMessage: Disks or snapshot cannot be resized down."}
	to retry, use: --limit @/home/fred/task/azure_rm_virtualmachine_NSG01.retry

PLAY RECAP *********************************************************************
127.0.0.1                  : ok=10   changed=3    unreachable=0    failed=1   

@PiotrMejer  Yes , I meet same error as your describe.  if disk_disk_size value greater than or equal the source's size, will meet the same error. Thanks !
Also reproduce issue, so how we could increase os disk size? Any idea?
Any solution for this issue?
@unfii Thank you for your still tracking this, I think we can't increase Create OS disk by using azure_rm_managed_disk. But it can expand disk by mount method, YML as below, I will confirm with development personnel Thanks!
@zikalino  Could you help confirm azure_rm_managed_disk moudule feature and how to fix this issue ? Thanks a lot!

Expand VM disk by mount method
``` e.g.
  - name: "Mount the managed disk to VM"
    azure_rm_managed_disk:
      name: mymnageddisk
      location: westeurope
      resource_group: "{{ resource_group }}"
      disk_size_gb: 32
      managed_by: "{{ vm_name }}"

@Fred-sun Yep, this disk will be attach only to special vm, but how to automate mount disk inside vm?
@unfii I have try if mount disk to the VM ,it will not unmount by reboot or power off the VM. So we can use this method to expand disk. anyway, I cannot modify /etc/fstab  method to auto mount disk like Linux, But I will think other method , Thanks!

@zikalino  Could you help check this , How to automate mount disk inside VM? Thanks!

Did anyone find a method that works?
You can specify the os disk size in an RM template so I assume you can do it via the Python API too.

Ideally we should be able to specify `os_disk_size` in `azure_rm_virtualmachine` 
Hi @spmp , Do you want create  data disk when create VM , I am not sure it meet your means. just like:
``` e.g.
  - name: create virtual machine
    azure_rm_virtualmachine: 
      resource_group: "{{ resource_group }}"
      name: "{{ vm_name }}"
      state: present
      vm_size: Standard_A0
      managed_disk_type: Standard_LRS
      admin_username: azureuser
      admin_password: Password@0329
      virtual_network_name: "{{ virtualnetwork }}"
      network_interface_names: "{{ test_nic }}"
      storage_account_name: "{{ storageaccount }}"
      image: 
        offer: UbuntuServer
        publisher: Canonical
        sku: 16.04-LTS 
        version: latest 
      started: no
      data_disks:
      - lun: 0
        disk_size_gb: 128
        managed_disk_type: Standard_LRS

@Fred-sun I do create data disks as well, but I need a large os disk.
Hi @spmp , Let me summary this issue, I have confirm with our developer member, Cannot increase created OS disk size,  but it will be fixed on later Ansible version, Now we can use mount and create data disks method to expand the VM disk size, when this question be fixed,  You can by latest Ansible version to try. Thanks a lot!
I really have to have this unfortunately. 
Rather than rewriting the module in its most basic cut down form, is it possible to be connected with the developer of `azure_rm_virtualmachine` to help me add this functionality? It can be a brutal hack, and I would keep it in the local `library` directory of the project.

Cheers
I feel very sorry to you, Change a parameter relation more than one module, it need develop and test these modules, not a easy job, So it need time to finish this job, Thanks a lot!
I have resolved this problem in my branch:
https://github.com/spmp/ansible/tree/feature/os_disk_size

I am unlikely to have time to create tests etc. at this stage, but will open a PR soon pending comments.
workaround: use Azure CLI
```
- name: expand OS disk
  shell: az disk update -g {{ resource_group }} -n {{ item }} --size-gb {{ dev_os_disk_size }}
  with_sequence: start=1 end="{{ vm_count }}" format="{{ vm_name }}-%02u"
```
I modified the module, was a relativity simple fix. I believe I have
referenced my branch in the comments. I can do a pr if someone is willing
to write the tests. I am too busy ATM.

On 1/06/2018 7:45 PM, "royzeng-ericsson" <notifications@github.com> wrote:

workaround: use Azure CLI

- name: expand OS disk
  shell: az disk update -g {{ resource_group }} -n {{ item }}
--size-gb {{ dev_os_disk_size }}
  with_sequence: start=1 end="{{ vm_count }}" format="{{ vm_name }}-%02u"

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<https://github.com/ansible/ansible/issues/38883#issuecomment-393795271>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADEribDz_HohF3fAx9T0e_NH7rg_NmX8ks5t4PE1gaJpZM4TYT0c>
.

@spmp please create pr, i will take care of merging it
@zikalino you have push rights to my repo, thank you for volunteering to see this PR merged. It needs documentation and tests at a minimum. I hope that is all.

Resolving patch:
diff --git a/lib/ansible/modules/cloud/azure/azure_rm_managed_disk.py b/lib/ansible/modules/cloud/azure/azure_rm_managed_disk.py
--- a/lib/ansible/modules/cloud/azure/azure_rm_managed_disk.py
+++ b/lib/ansible/modules/cloud/azure/azure_rm_managed_disk.py
@@ -146,16 +146,17 @@
 
 
 def managed_disk_to_dict(managed_disk):
-    os_type = None
-    if managed_disk.os_type:
-        os_type = managed_disk.os_type.name
+    create_data = managed_disk.creation_data
     return dict(
         id=managed_disk.id,
         name=managed_disk.name,
         location=managed_disk.location,
         tags=managed_disk.tags,
+        create_option=create_data.create_option.value.lower(),
+        source_uri=create_data.source_uri,
+        source_resource_uri=create_data.source_resource_id,
         disk_size_gb=managed_disk.disk_size_gb,
-        os_type=os_type,
+        os_type=managed_disk.os_type.value if managed_disk.os_type else None,
         storage_account_type=managed_disk.sku.name.value,
         managed_by=managed_disk.managed_by
     )
diff --git a/lib/ansible/modules/cloud/azure/azure_rm_managed_disk_facts.py b/lib/ansible/modules/cloud/azure/azure_rm_managed_disk_facts.py
--- a/lib/ansible/modules/cloud/azure/azure_rm_managed_disk_facts.py
+++ b/lib/ansible/modules/cloud/azure/azure_rm_managed_disk_facts.py
@@ -79,27 +79,12 @@
 
 try:
     from msrestazure.azure_exceptions import CloudError
+    from ansible.modules.cloud.azure.azure_rm_managed_disk import managed_disk_to_dict
 except:
     # handled in azure_rm_common
     pass
 
 
-def managed_disk_to_dict(managed_disk):
-    os_type = None
-    if managed_disk.os_type:
-        os_type = managed_disk.os_type.name
-    return dict(
-        id=managed_disk.id,
-        name=managed_disk.name,
-        location=managed_disk.location,
-        tags=managed_disk.tags,
-        disk_size_gb=managed_disk.disk_size_gb,
-        os_type=os_type,
-        storage_account_type=managed_disk.sku.name.value,
-        managed_by=managed_disk.managed_by
-    )
-
-
 class AzureRMManagedDiskFacts(AzureRMModuleBase):
     """Utility class to get managed disk facts"""
 


Test patch:
diff --git a/test/integration/targets/azure_rm_managed_disk/tasks/main.yml b/test/integration/targets/azure_rm_managed_disk/tasks/main.yml
--- a/test/integration/targets/azure_rm_managed_disk/tasks/main.yml
+++ b/test/integration/targets/azure_rm_managed_disk/tasks/main.yml
@@ -1,6 +1,7 @@
  - name: Prepare random number
    set_fact:
      rpfx: "{{ resource_group | hash('md5') | truncate(7, True, '') }}{{ 1000 | random }}"
+     parameter: {}
    run_once: yes
 
  - name: Clearing (if) previous disks were created
@@ -174,6 +175,7 @@
    azure_rm_managed_disk_facts:
        resource_group: "{{ resource_group }}"
        name: "md{{ rpfx }}1"
+   register: fact
 
  - assert:
        that:
@@ -187,6 +189,19 @@
        that:
            - "azure_managed_disk | length > 0"
 
+ - set_fact:
+     parameter: "{{parameter |combine({item.key: item.value})}}"
+   when: "{{item.key not in ['id', 'changed'] and item.value != None}}"
+   with_dict: "{{ fact.ansible_facts.azure_managed_disk[0] }}"
+
+ - name: Create disk with facts return value
+   azure_rm_managed_disk: "{{ parameter | combine({'resource_group': resource_group}) }}"
+   register: output
+
+ - assert:
+       that:
+           - not output.changed
+
  - name: Create virtual network
    azure_rm_virtualnetwork:
        resource_group: "{{ resource_group }}"