Repository: ansible/ansible

Issue:
os_nova_flavor module missing ability to update existing flavors
<!---
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 -->
 - Feature Idea

##### COMPONENT NAME
<!---
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
-->
os_nova_flavor

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.4.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/hccdev/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/dist-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.12 (default, Nov 20 2017, 18:23:56) [GCC 5.4.0 20160609]
```

##### CONFIGURATION
<!---
If using Ansible 2.4 or above, paste 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 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.
-->
N/A

##### SUMMARY
<!--- Explain the problem briefly -->
The os_nova_flavor module currently misses the ability to update existing flavors [[1]](https://groups.google.com/forum/#!topic/ansible-project/3lcvd61SvoM).

Horizon implements in by simply deleting the old flavor and creating a new one [[2]](https://github.com/openstack/horizon/blob/b0f3ec3ace531c110f328d208cded302d2617f88/openstack_dashboard/dashboards/admin/flavors/workflows.py#L304-L309).
It would be great to have this ability in the module as well.  


##### 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: Update flavor
     os_nova_flavor:
       name: existing_flavor
       vcpus: 1
       ram: 512
       disk: 10
       ephemeral: 0
       is_public: true
       state: present
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
The flavor `existing_flavor` should get updated with the new configuration.

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->
The flavor `existing_flavor` is unchanged.

<!--- Paste verbatim command output between quotes below -->



Discussion:
Files identified in the description:
* [lib/ansible/modules/cloud/openstack/os_nova_flavor.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/cloud/openstack/os_nova_flavor.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 @Shrews @dagnello @emonty @j2sol @juliakreger @rcarrillocruz @shrews @thingee
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
Can i work on this issue?

Resolving patch:
diff --git a/lib/ansible/modules/cloud/openstack/os_nova_flavor.py b/lib/ansible/modules/cloud/openstack/os_nova_flavor.py
--- a/lib/ansible/modules/cloud/openstack/os_nova_flavor.py
+++ b/lib/ansible/modules/cloud/openstack/os_nova_flavor.py
@@ -226,6 +226,20 @@ def main():
             module.exit_json(changed=_system_state_change(module, flavor))
 
         if state == 'present':
+            old_extra_specs = {}
+            require_update = False
+
+            if flavor:
+                old_extra_specs = flavor['extra_specs']
+                for param_key in ['ram', 'vcpus', 'disk', 'ephemeral', 'swap', 'rxtx_factor', 'is_public']:
+                    if module.params[param_key] != flavor[param_key]:
+                        require_update = True
+                        break
+
+            if flavor and require_update:
+                cloud.delete_flavor(name)
+                flavor = None
+
             if not flavor:
                 flavor = cloud.create_flavor(
                     name=name,
@@ -242,11 +256,10 @@ def main():
             else:
                 changed = False
 
-            old_extra_specs = flavor['extra_specs']
             new_extra_specs = dict([(k, str(v)) for k, v in extra_specs.items()])
-            unset_keys = set(flavor['extra_specs'].keys()) - set(extra_specs.keys())
+            unset_keys = set(old_extra_specs.keys()) - set(extra_specs.keys())
 
-            if unset_keys:
+            if unset_keys and not require_update:
                 cloud.unset_flavor_specs(flavor['id'], unset_keys)
 
             if old_extra_specs != new_extra_specs:


Test patch: