Repository: ansible/ansible-modules-core

Issue:
os_server_actions nova rebuild server
##### ISSUE TYPE

Feature Idea
##### COMPONENT NAME

os_server module
##### ANSIBLE VERSION

N/A
##### SUMMARY

Could it be possible to implement the nova rebuild server action in the os_server_actions module?

We use openstack in our CI pipeline, and this is far more cheaper then booting a new server every
time we test.



Discussion:
cc @emonty @Shrews @j2sol 

Should we have this feature in os_server_actions or os_server ?

Having this in os_server_actions would require an additional parameter "image_id" to rebuild the VM. 

In os_server it would be more suitable, we can have 3 states of os_server (present, absent, rebuild) ,  suggestions ?

I could see this going either way.

But given all the stuff we have in os_server, it probably makes more sense to put it there.

@emonty, @shrews, @juliakreger, @j2sol, @rcarrillocruz, ping. This issue is still waiting on your response.
[click here for bot help](https://github.com/jctanner/ansibullbot/blob/ISSUE_TRIAGE_CLASS/ISSUE_HELP.md)

<!--- boilerplate: issue_renotify_maintainer --->

I rather have this on os_server_actions.

rebuild is not a state itself, present/absent/suspended/paused is  (and yeah, i'm aware suspend/pause is in os_server_actions, I'd really like to see that moved to os_server at some point).

I'll review and test this in depth this week.


Resolving patch:
diff --git a/cloud/openstack/os_server_actions.py b/cloud/openstack/os_server_actions.py
--- a/cloud/openstack/os_server_actions.py
+++ b/cloud/openstack/os_server_actions.py
@@ -35,6 +35,7 @@
 description:
    - Perform server actions on an existing compute instance from OpenStack.
      This module does not return any data other than changed true/false.
+     When I(action) is 'rebuild', then I(image) parameter is required.
 options:
    server:
      description:
@@ -55,8 +56,14 @@
      description:
        - Perform the given action. The lock and unlock actions always return
          changed as the servers API does not provide lock status.
-     choices: [stop, start, pause, unpause, lock, unlock, suspend, resume]
+     choices: [stop, start, pause, unpause, lock, unlock, suspend, resume,
+               rebuild]
      default: present
+   image:
+     description:
+       - Image the server should be rebuilt with
+     default: null
+     version_added: "2.3"
 requirements:
     - "python >= 2.6"
     - "shade"
@@ -82,7 +89,8 @@
                'lock': 'ACTIVE', # API doesn't show lock/unlock status
                'unlock': 'ACTIVE',
                'suspend': 'SUSPENDED',
-               'resume': 'ACTIVE',}
+               'resume': 'ACTIVE',
+               'rebuild': 'ACTIVE'}
 
 _admin_actions = ['pause', 'unpause', 'suspend', 'resume', 'lock', 'unlock']
 
@@ -113,11 +121,15 @@ def main():
     argument_spec = openstack_full_argument_spec(
         server=dict(required=True),
         action=dict(required=True, choices=['stop', 'start', 'pause', 'unpause',
-                                            'lock', 'unlock', 'suspend', 'resume']),
+                                            'lock', 'unlock', 'suspend', 'resume',
+                                            'rebuild']),
+        image=dict(required=False),
     )
 
     module_kwargs = openstack_module_kwargs()
-    module = AnsibleModule(argument_spec, supports_check_mode=True, **module_kwargs)
+    module = AnsibleModule(argument_spec, supports_check_mode=True,
+                           required_if=[('action', 'rebuild', ['image'])],
+                           **module_kwargs)
 
     if not HAS_SHADE:
         module.fail_json(msg='shade is required for this module')
@@ -125,6 +137,7 @@ def main():
     action = module.params['action']
     wait = module.params['wait']
     timeout = module.params['timeout']
+    image = module.params['image']
 
     try:
         if action in _admin_actions:
@@ -203,6 +216,18 @@ def main():
                 _wait(timeout, cloud, server, action)
             module.exit_json(changed=True)
 
+        elif action == 'rebuild':
+            image = cloud.get_image(image)
+
+            if image is None:
+                module.fail_json(msg="Image does not exist")
+
+            # rebuild doesn't set a state, just do it
+            cloud.nova_client.servers.rebuild(server=server.id, image=image.id)
+            if wait:
+                _wait(timeout, cloud, server, action)
+            module.exit_json(changed=True)
+
     except shade.OpenStackCloudException as e:
         module.fail_json(msg=str(e), extra_data=e.extra_data)
 


Test patch: