We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN 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 -->


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lib/ansible/modules/cloud/openstack/os_nova_flavor.py`
Content:
```
1 #!/usr/bin/python
2 
3 # Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
4 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
5 
6 from __future__ import absolute_import, division, print_function
7 __metaclass__ = type
8 
9 
10 ANSIBLE_METADATA = {'metadata_version': '1.1',
11                     'status': ['preview'],
12                     'supported_by': 'community'}
13 
14 
15 DOCUMENTATION = '''
16 ---
17 module: os_nova_flavor
18 short_description: Manage OpenStack compute flavors
19 extends_documentation_fragment: openstack
20 version_added: "2.0"
21 author: "David Shrewsbury (@Shrews)"
22 description:
23    - Add or remove flavors from OpenStack.
24 options:
25    state:
26      description:
27         - Indicate desired state of the resource. When I(state) is 'present',
28           then I(ram), I(vcpus), and I(disk) are all required. There are no
29           default values for those parameters.
30      choices: ['present', 'absent']
31      default: present
32    name:
33      description:
34         - Flavor name.
35      required: true
36    ram:
37      description:
38         - Amount of memory, in MB.
39    vcpus:
40      description:
41         - Number of virtual CPUs.
42    disk:
43      description:
44         - Size of local disk, in GB.
45    ephemeral:
46      description:
47         - Ephemeral space size, in GB.
48      default: 0
49    swap:
50      description:
51         - Swap space size, in MB.
52      default: 0
53    rxtx_factor:
54      description:
55         - RX/TX factor.
56      default: 1.0
57    is_public:
58      description:
59         - Make flavor accessible to the public.
60      type: bool
61      default: 'yes'
62    flavorid:
63      description:
64         - ID for the flavor. This is optional as a unique UUID will be
65           assigned if a value is not specified.
66      default: "auto"
67    availability_zone:
68      description:
69        - Ignored. Present for backwards compatibility
70    extra_specs:
71      description:
72         - Metadata dictionary
73      version_added: "2.3"
74 requirements: ["shade"]
75 '''
76 
77 EXAMPLES = '''
78 - name: "Create 'tiny' flavor with 1024MB of RAM, 1 virtual CPU, and 10GB of local disk, and 10GB of ephemeral."
79   os_nova_flavor:
80     cloud: mycloud
81     state: present
82     name: tiny
83     ram: 1024
84     vcpus: 1
85     disk: 10
86     ephemeral: 10
87 
88 - name: "Delete 'tiny' flavor"
89   os_nova_flavor:
90     cloud: mycloud
91     state: absent
92     name: tiny
93 
94 - name: Create flavor with metadata
95   os_nova_flavor:
96     cloud: mycloud
97     state: present
98     name: tiny
99     ram: 1024
100     vcpus: 1
101     disk: 10
102     extra_specs:
103       "quota:disk_read_iops_sec": 5000
104       "aggregate_instance_extra_specs:pinned": false
105 '''
106 
107 RETURN = '''
108 flavor:
109     description: Dictionary describing the flavor.
110     returned: On success when I(state) is 'present'
111     type: complex
112     contains:
113         id:
114             description: Flavor ID.
115             returned: success
116             type: string
117             sample: "515256b8-7027-4d73-aa54-4e30a4a4a339"
118         name:
119             description: Flavor name.
120             returned: success
121             type: string
122             sample: "tiny"
123         disk:
124             description: Size of local disk, in GB.
125             returned: success
126             type: int
127             sample: 10
128         ephemeral:
129             description: Ephemeral space size, in GB.
130             returned: success
131             type: int
132             sample: 10
133         ram:
134             description: Amount of memory, in MB.
135             returned: success
136             type: int
137             sample: 1024
138         swap:
139             description: Swap space size, in MB.
140             returned: success
141             type: int
142             sample: 100
143         vcpus:
144             description: Number of virtual CPUs.
145             returned: success
146             type: int
147             sample: 2
148         is_public:
149             description: Make flavor accessible to the public.
150             returned: success
151             type: bool
152             sample: true
153         extra_specs:
154             description: Flavor metadata
155             returned: success
156             type: dict
157             sample:
158                 "quota:disk_read_iops_sec": 5000
159                 "aggregate_instance_extra_specs:pinned": false
160 '''
161 
162 from ansible.module_utils.basic import AnsibleModule
163 from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module
164 
165 
166 def _system_state_change(module, flavor):
167     state = module.params['state']
168     if state == 'present' and not flavor:
169         return True
170     if state == 'absent' and flavor:
171         return True
172     return False
173 
174 
175 def main():
176     argument_spec = openstack_full_argument_spec(
177         state=dict(required=False, default='present',
178                    choices=['absent', 'present']),
179         name=dict(required=False),
180 
181         # required when state is 'present'
182         ram=dict(required=False, type='int'),
183         vcpus=dict(required=False, type='int'),
184         disk=dict(required=False, type='int'),
185 
186         ephemeral=dict(required=False, default=0, type='int'),
187         swap=dict(required=False, default=0, type='int'),
188         rxtx_factor=dict(required=False, default=1.0, type='float'),
189         is_public=dict(required=False, default=True, type='bool'),
190         flavorid=dict(required=False, default="auto"),
191         extra_specs=dict(required=False, default=None, type='dict'),
192     )
193 
194     module_kwargs = openstack_module_kwargs()
195     module = AnsibleModule(
196         argument_spec,
197         supports_check_mode=True,
198         required_if=[
199             ('state', 'present', ['ram', 'vcpus', 'disk'])
200         ],
201         **module_kwargs)
202 
203     state = module.params['state']
204     name = module.params['name']
205     extra_specs = module.params['extra_specs'] or {}
206 
207     shade, cloud = openstack_cloud_from_module(module)
208     try:
209         flavor = cloud.get_flavor(name)
210 
211         if module.check_mode:
212             module.exit_json(changed=_system_state_change(module, flavor))
213 
214         if state == 'present':
215             if not flavor:
216                 flavor = cloud.create_flavor(
217                     name=name,
218                     ram=module.params['ram'],
219                     vcpus=module.params['vcpus'],
220                     disk=module.params['disk'],
221                     flavorid=module.params['flavorid'],
222                     ephemeral=module.params['ephemeral'],
223                     swap=module.params['swap'],
224                     rxtx_factor=module.params['rxtx_factor'],
225                     is_public=module.params['is_public']
226                 )
227                 changed = True
228             else:
229                 changed = False
230 
231             old_extra_specs = flavor['extra_specs']
232             new_extra_specs = dict([(k, str(v)) for k, v in extra_specs.items()])
233             unset_keys = set(flavor['extra_specs'].keys()) - set(extra_specs.keys())
234 
235             if unset_keys:
236                 cloud.unset_flavor_specs(flavor['id'], unset_keys)
237 
238             if old_extra_specs != new_extra_specs:
239                 cloud.set_flavor_specs(flavor['id'], extra_specs)
240 
241             changed = (changed or old_extra_specs != new_extra_specs)
242 
243             module.exit_json(changed=changed,
244                              flavor=flavor,
245                              id=flavor['id'])
246 
247         elif state == 'absent':
248             if flavor:
249                 cloud.delete_flavor(name)
250                 module.exit_json(changed=True)
251             module.exit_json(changed=False)
252 
253     except shade.OpenStackCloudException as e:
254         module.fail_json(msg=str(e))
255 
256 
257 if __name__ == '__main__':
258     main()
259
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

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 @@
             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 @@
             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:

{"golden_diff": "diff --git a/lib/ansible/modules/cloud/openstack/os_nova_flavor.py b/lib/ansible/modules/cloud/openstack/os_nova_flavor.py\n--- a/lib/ansible/modules/cloud/openstack/os_nova_flavor.py\n+++ b/lib/ansible/modules/cloud/openstack/os_nova_flavor.py\n@@ -226,6 +226,20 @@\n             module.exit_json(changed=_system_state_change(module, flavor))\n \n         if state == 'present':\n+            old_extra_specs = {}\n+            require_update = False\n+\n+            if flavor:\n+                old_extra_specs = flavor['extra_specs']\n+                for param_key in ['ram', 'vcpus', 'disk', 'ephemeral', 'swap', 'rxtx_factor', 'is_public']:\n+                    if module.params[param_key] != flavor[param_key]:\n+                        require_update = True\n+                        break\n+\n+            if flavor and require_update:\n+                cloud.delete_flavor(name)\n+                flavor = None\n+\n             if not flavor:\n                 flavor = cloud.create_flavor(\n                     name=name,\n@@ -242,11 +256,10 @@\n             else:\n                 changed = False\n \n-            old_extra_specs = flavor['extra_specs']\n             new_extra_specs = dict([(k, str(v)) for k, v in extra_specs.items()])\n-            unset_keys = set(flavor['extra_specs'].keys()) - set(extra_specs.keys())\n+            unset_keys = set(old_extra_specs.keys()) - set(extra_specs.keys())\n \n-            if unset_keys:\n+            if unset_keys and not require_update:\n                 cloud.unset_flavor_specs(flavor['id'], unset_keys)\n \n             if old_extra_specs != new_extra_specs:\n", "issue": "os_nova_flavor module missing ability to update existing flavors\n<!---\r\nVerify first that your issue/request is not already reported on GitHub.\r\nAlso test if the latest release, and master branch are affected too.\r\n-->\r\n\r\n##### ISSUE TYPE\r\n<!--- Pick one below and delete the rest -->\r\n - Feature Idea\r\n\r\n##### COMPONENT NAME\r\n<!---\r\nName of the module, plugin, task or feature\r\nDo not include extra details here, e.g. \"vyos_command\" not \"the network module vyos_command\" or the full path\r\n-->\r\nos_nova_flavor\r\n\r\n##### ANSIBLE VERSION\r\n<!--- Paste verbatim output from \"ansible --version\" between quotes below -->\r\n```\r\nansible 2.4.1.0\r\n  config file = /etc/ansible/ansible.cfg\r\n  configured module search path = [u'/home/hccdev/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']\r\n  ansible python module location = /usr/lib/python2.7/dist-packages/ansible\r\n  executable location = /usr/bin/ansible\r\n  python version = 2.7.12 (default, Nov 20 2017, 18:23:56) [GCC 5.4.0 20160609]\r\n```\r\n\r\n##### CONFIGURATION\r\n<!---\r\nIf using Ansible 2.4 or above, paste the results of \"ansible-config dump --only-changed\"\r\nOtherwise, mention any settings you have changed/added/removed in ansible.cfg\r\n(or using the ANSIBLE_* environment variables).\r\n-->\r\n\r\n##### OS / ENVIRONMENT\r\n<!---\r\nMention the OS you are running Ansible from, and the OS you are\r\nmanaging, or say \"N/A\" for anything that is not platform-specific.\r\nAlso mention the specific version of what you are trying to control,\r\ne.g. if this is a network bug the version of firmware on the network device.\r\n-->\r\nN/A\r\n\r\n##### SUMMARY\r\n<!--- Explain the problem briefly -->\r\nThe os_nova_flavor module currently misses the ability to update existing flavors [[1]](https://groups.google.com/forum/#!topic/ansible-project/3lcvd61SvoM).\r\n\r\nHorizon 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).\r\nIt would be great to have this ability in the module as well.  \r\n\r\n\r\n##### STEPS TO REPRODUCE\r\n<!---\r\nFor bugs, show exactly how to reproduce the problem, using a minimal test-case.\r\nFor new features, show how the feature would be used.\r\n-->\r\n\r\n<!--- Paste example playbooks or commands between quotes below -->\r\n```yaml\r\n   - name: Update flavor\r\n     os_nova_flavor:\r\n       name: existing_flavor\r\n       vcpus: 1\r\n       ram: 512\r\n       disk: 10\r\n       ephemeral: 0\r\n       is_public: true\r\n       state: present\r\n```\r\n\r\n<!--- You can also paste gist.github.com links for larger files -->\r\n\r\n##### EXPECTED RESULTS\r\n<!--- What did you expect to happen when running the steps above? -->\r\nThe flavor `existing_flavor` should get updated with the new configuration.\r\n\r\n##### ACTUAL RESULTS\r\n<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->\r\nThe flavor `existing_flavor` is unchanged.\r\n\r\n<!--- Paste verbatim command output between quotes below -->\r\n\n", "before_files": [{"content": "#!/usr/bin/python\n\n# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.\n# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: os_nova_flavor\nshort_description: Manage OpenStack compute flavors\nextends_documentation_fragment: openstack\nversion_added: \"2.0\"\nauthor: \"David Shrewsbury (@Shrews)\"\ndescription:\n   - Add or remove flavors from OpenStack.\noptions:\n   state:\n     description:\n        - Indicate desired state of the resource. When I(state) is 'present',\n          then I(ram), I(vcpus), and I(disk) are all required. There are no\n          default values for those parameters.\n     choices: ['present', 'absent']\n     default: present\n   name:\n     description:\n        - Flavor name.\n     required: true\n   ram:\n     description:\n        - Amount of memory, in MB.\n   vcpus:\n     description:\n        - Number of virtual CPUs.\n   disk:\n     description:\n        - Size of local disk, in GB.\n   ephemeral:\n     description:\n        - Ephemeral space size, in GB.\n     default: 0\n   swap:\n     description:\n        - Swap space size, in MB.\n     default: 0\n   rxtx_factor:\n     description:\n        - RX/TX factor.\n     default: 1.0\n   is_public:\n     description:\n        - Make flavor accessible to the public.\n     type: bool\n     default: 'yes'\n   flavorid:\n     description:\n        - ID for the flavor. This is optional as a unique UUID will be\n          assigned if a value is not specified.\n     default: \"auto\"\n   availability_zone:\n     description:\n       - Ignored. Present for backwards compatibility\n   extra_specs:\n     description:\n        - Metadata dictionary\n     version_added: \"2.3\"\nrequirements: [\"shade\"]\n'''\n\nEXAMPLES = '''\n- name: \"Create 'tiny' flavor with 1024MB of RAM, 1 virtual CPU, and 10GB of local disk, and 10GB of ephemeral.\"\n  os_nova_flavor:\n    cloud: mycloud\n    state: present\n    name: tiny\n    ram: 1024\n    vcpus: 1\n    disk: 10\n    ephemeral: 10\n\n- name: \"Delete 'tiny' flavor\"\n  os_nova_flavor:\n    cloud: mycloud\n    state: absent\n    name: tiny\n\n- name: Create flavor with metadata\n  os_nova_flavor:\n    cloud: mycloud\n    state: present\n    name: tiny\n    ram: 1024\n    vcpus: 1\n    disk: 10\n    extra_specs:\n      \"quota:disk_read_iops_sec\": 5000\n      \"aggregate_instance_extra_specs:pinned\": false\n'''\n\nRETURN = '''\nflavor:\n    description: Dictionary describing the flavor.\n    returned: On success when I(state) is 'present'\n    type: complex\n    contains:\n        id:\n            description: Flavor ID.\n            returned: success\n            type: string\n            sample: \"515256b8-7027-4d73-aa54-4e30a4a4a339\"\n        name:\n            description: Flavor name.\n            returned: success\n            type: string\n            sample: \"tiny\"\n        disk:\n            description: Size of local disk, in GB.\n            returned: success\n            type: int\n            sample: 10\n        ephemeral:\n            description: Ephemeral space size, in GB.\n            returned: success\n            type: int\n            sample: 10\n        ram:\n            description: Amount of memory, in MB.\n            returned: success\n            type: int\n            sample: 1024\n        swap:\n            description: Swap space size, in MB.\n            returned: success\n            type: int\n            sample: 100\n        vcpus:\n            description: Number of virtual CPUs.\n            returned: success\n            type: int\n            sample: 2\n        is_public:\n            description: Make flavor accessible to the public.\n            returned: success\n            type: bool\n            sample: true\n        extra_specs:\n            description: Flavor metadata\n            returned: success\n            type: dict\n            sample:\n                \"quota:disk_read_iops_sec\": 5000\n                \"aggregate_instance_extra_specs:pinned\": false\n'''\n\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module\n\n\ndef _system_state_change(module, flavor):\n    state = module.params['state']\n    if state == 'present' and not flavor:\n        return True\n    if state == 'absent' and flavor:\n        return True\n    return False\n\n\ndef main():\n    argument_spec = openstack_full_argument_spec(\n        state=dict(required=False, default='present',\n                   choices=['absent', 'present']),\n        name=dict(required=False),\n\n        # required when state is 'present'\n        ram=dict(required=False, type='int'),\n        vcpus=dict(required=False, type='int'),\n        disk=dict(required=False, type='int'),\n\n        ephemeral=dict(required=False, default=0, type='int'),\n        swap=dict(required=False, default=0, type='int'),\n        rxtx_factor=dict(required=False, default=1.0, type='float'),\n        is_public=dict(required=False, default=True, type='bool'),\n        flavorid=dict(required=False, default=\"auto\"),\n        extra_specs=dict(required=False, default=None, type='dict'),\n    )\n\n    module_kwargs = openstack_module_kwargs()\n    module = AnsibleModule(\n        argument_spec,\n        supports_check_mode=True,\n        required_if=[\n            ('state', 'present', ['ram', 'vcpus', 'disk'])\n        ],\n        **module_kwargs)\n\n    state = module.params['state']\n    name = module.params['name']\n    extra_specs = module.params['extra_specs'] or {}\n\n    shade, cloud = openstack_cloud_from_module(module)\n    try:\n        flavor = cloud.get_flavor(name)\n\n        if module.check_mode:\n            module.exit_json(changed=_system_state_change(module, flavor))\n\n        if state == 'present':\n            if not flavor:\n                flavor = cloud.create_flavor(\n                    name=name,\n                    ram=module.params['ram'],\n                    vcpus=module.params['vcpus'],\n                    disk=module.params['disk'],\n                    flavorid=module.params['flavorid'],\n                    ephemeral=module.params['ephemeral'],\n                    swap=module.params['swap'],\n                    rxtx_factor=module.params['rxtx_factor'],\n                    is_public=module.params['is_public']\n                )\n                changed = True\n            else:\n                changed = False\n\n            old_extra_specs = flavor['extra_specs']\n            new_extra_specs = dict([(k, str(v)) for k, v in extra_specs.items()])\n            unset_keys = set(flavor['extra_specs'].keys()) - set(extra_specs.keys())\n\n            if unset_keys:\n                cloud.unset_flavor_specs(flavor['id'], unset_keys)\n\n            if old_extra_specs != new_extra_specs:\n                cloud.set_flavor_specs(flavor['id'], extra_specs)\n\n            changed = (changed or old_extra_specs != new_extra_specs)\n\n            module.exit_json(changed=changed,\n                             flavor=flavor,\n                             id=flavor['id'])\n\n        elif state == 'absent':\n            if flavor:\n                cloud.delete_flavor(name)\n                module.exit_json(changed=True)\n            module.exit_json(changed=False)\n\n    except shade.OpenStackCloudException as e:\n        module.fail_json(msg=str(e))\n\n\nif __name__ == '__main__':\n    main()\n", "path": "lib/ansible/modules/cloud/openstack/os_nova_flavor.py"}], "after_files": [{"content": "#!/usr/bin/python\n\n# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.\n# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: os_nova_flavor\nshort_description: Manage OpenStack compute flavors\nextends_documentation_fragment: openstack\nversion_added: \"2.0\"\nauthor: \"David Shrewsbury (@Shrews)\"\ndescription:\n   - Add or remove flavors from OpenStack.\noptions:\n   state:\n     description:\n        - Indicate desired state of the resource. When I(state) is 'present',\n          then I(ram), I(vcpus), and I(disk) are all required. There are no\n          default values for those parameters.\n     choices: ['present', 'absent']\n     required: false\n     default: present\n   name:\n     description:\n        - Flavor name.\n     required: true\n   ram:\n     description:\n        - Amount of memory, in MB.\n     required: false\n     default: null\n   vcpus:\n     description:\n        - Number of virtual CPUs.\n     required: false\n     default: null\n   disk:\n     description:\n        - Size of local disk, in GB.\n     required: false\n     default: null\n   ephemeral:\n     description:\n        - Ephemeral space size, in GB.\n     required: false\n     default: 0\n   swap:\n     description:\n        - Swap space size, in MB.\n     required: false\n     default: 0\n   rxtx_factor:\n     description:\n        - RX/TX factor.\n     required: false\n     default: 1.0\n   is_public:\n     description:\n        - Make flavor accessible to the public.\n     required: false\n     default: true\n   flavorid:\n     description:\n        - ID for the flavor. This is optional as a unique UUID will be\n          assigned if a value is not specified.\n     required: false\n     default: \"auto\"\n   availability_zone:\n     description:\n       - Ignored. Present for backwards compatibility\n     required: false\n   extra_specs:\n     description:\n        - Metadata dictionary\n     required: false\n     default: None\n     version_added: \"2.3\"\nrequirements: [\"shade\"]\n'''\n\nEXAMPLES = '''\n- name: \"Create 'tiny' flavor with 1024MB of RAM, 1 virtual CPU, and 10GB of local disk, and 10GB of ephemeral.\"\n  os_nova_flavor:\n    cloud: mycloud\n    state: present\n    name: tiny\n    ram: 1024\n    vcpus: 1\n    disk: 10\n    ephemeral: 10\n\n- name: \"Delete 'tiny' flavor\"\n  os_nova_flavor:\n    cloud: mycloud\n    state: absent\n    name: tiny\n\n- name: Create flavor with metadata\n  os_nova_flavor:\n    cloud: mycloud\n    state: present\n    name: tiny\n    ram: 1024\n    vcpus: 1\n    disk: 10\n    extra_specs:\n      \"quota:disk_read_iops_sec\": 5000\n      \"aggregate_instance_extra_specs:pinned\": false\n'''\n\nRETURN = '''\nflavor:\n    description: Dictionary describing the flavor.\n    returned: On success when I(state) is 'present'\n    type: complex\n    contains:\n        id:\n            description: Flavor ID.\n            returned: success\n            type: string\n            sample: \"515256b8-7027-4d73-aa54-4e30a4a4a339\"\n        name:\n            description: Flavor name.\n            returned: success\n            type: string\n            sample: \"tiny\"\n        disk:\n            description: Size of local disk, in GB.\n            returned: success\n            type: int\n            sample: 10\n        ephemeral:\n            description: Ephemeral space size, in GB.\n            returned: success\n            type: int\n            sample: 10\n        ram:\n            description: Amount of memory, in MB.\n            returned: success\n            type: int\n            sample: 1024\n        swap:\n            description: Swap space size, in MB.\n            returned: success\n            type: int\n            sample: 100\n        vcpus:\n            description: Number of virtual CPUs.\n            returned: success\n            type: int\n            sample: 2\n        is_public:\n            description: Make flavor accessible to the public.\n            returned: success\n            type: bool\n            sample: true\n        extra_specs:\n            description: Flavor metadata\n            returned: success\n            type: dict\n            sample:\n                \"quota:disk_read_iops_sec\": 5000\n                \"aggregate_instance_extra_specs:pinned\": false\n'''\n\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module\n\n\ndef _system_state_change(module, flavor):\n    state = module.params['state']\n    if state == 'present' and not flavor:\n        return True\n    if state == 'absent' and flavor:\n        return True\n    return False\n\n\ndef main():\n    argument_spec = openstack_full_argument_spec(\n        state=dict(required=False, default='present',\n                   choices=['absent', 'present']),\n        name=dict(required=False),\n\n        # required when state is 'present'\n        ram=dict(required=False, type='int'),\n        vcpus=dict(required=False, type='int'),\n        disk=dict(required=False, type='int'),\n\n        ephemeral=dict(required=False, default=0, type='int'),\n        swap=dict(required=False, default=0, type='int'),\n        rxtx_factor=dict(required=False, default=1.0, type='float'),\n        is_public=dict(required=False, default=True, type='bool'),\n        flavorid=dict(required=False, default=\"auto\"),\n        extra_specs=dict(required=False, default=None, type='dict'),\n    )\n\n    module_kwargs = openstack_module_kwargs()\n    module = AnsibleModule(\n        argument_spec,\n        supports_check_mode=True,\n        required_if=[\n            ('state', 'present', ['ram', 'vcpus', 'disk'])\n        ],\n        **module_kwargs)\n\n    state = module.params['state']\n    name = module.params['name']\n    extra_specs = module.params['extra_specs'] or {}\n\n    shade, cloud = openstack_cloud_from_module(module)\n    try:\n        flavor = cloud.get_flavor(name)\n\n        if module.check_mode:\n            module.exit_json(changed=_system_state_change(module, flavor))\n\n        if state == 'present':\n            old_extra_specs = {}\n            require_update = False\n\n            if flavor:\n                old_extra_specs = flavor['extra_specs']\n                for param_key in ['ram', 'vcpus', 'disk', 'ephemeral', 'swap', 'rxtx_factor', 'is_public']:\n                    if module.params[param_key] != flavor[param_key]:\n                        require_update = True\n                        break\n\n            if flavor and require_update:\n                cloud.delete_flavor(name)\n                flavor = None\n\n            if not flavor:\n                flavor = cloud.create_flavor(\n                    name=name,\n                    ram=module.params['ram'],\n                    vcpus=module.params['vcpus'],\n                    disk=module.params['disk'],\n                    flavorid=module.params['flavorid'],\n                    ephemeral=module.params['ephemeral'],\n                    swap=module.params['swap'],\n                    rxtx_factor=module.params['rxtx_factor'],\n                    is_public=module.params['is_public']\n                )\n                changed = True\n            else:\n                changed = False\n\n            new_extra_specs = dict([(k, str(v)) for k, v in extra_specs.items()])\n            unset_keys = set(old_extra_specs.keys()) - set(extra_specs.keys())\n\n            if unset_keys and not require_update:\n                cloud.unset_flavor_specs(flavor['id'], unset_keys)\n\n            if old_extra_specs != new_extra_specs:\n                cloud.set_flavor_specs(flavor['id'], extra_specs)\n\n            changed = (changed or old_extra_specs != new_extra_specs)\n\n            module.exit_json(changed=changed,\n                             flavor=flavor,\n                             id=flavor['id'])\n\n        elif state == 'absent':\n            if flavor:\n                cloud.delete_flavor(name)\n                module.exit_json(changed=True)\n            module.exit_json(changed=False)\n\n    except shade.OpenStackCloudException as e:\n        module.fail_json(msg=str(e))\n\n\nif __name__ == '__main__':\n    main()\n", "path": "lib/ansible/modules/cloud/openstack/os_nova_flavor.py"}]}