From 41f3007a80ea4410bc7a91ed616276d654a8a97f Mon Sep 17 00:00:00 2001
From: anbanerj <anbanerj@redhat.com>
Date: Thu, 30 Jun 2022 14:34:08 +0200
Subject: [PATCH] Makes stack module compatible with new sdk version

Change-Id: Iec99be0f422f1fab9b17e581b7b47a7540de749c
---
 ci/roles/orchestration/defaults/main.yaml |  33 +++++
 ci/roles/orchestration/tasks/main.yaml    |  11 ++
 plugins/modules/stack.py                  | 166 ++++++++++++++++------
 3 files changed, 163 insertions(+), 47 deletions(-)

diff --git a/ci/roles/orchestration/defaults/main.yaml b/ci/roles/orchestration/defaults/main.yaml
index 798cdf8..d419f1a 100644
--- a/ci/roles/orchestration/defaults/main.yaml
+++ b/ci/roles/orchestration/defaults/main.yaml
@@ -1,2 +1,35 @@
 ---
 stack_name: "test-stack"
+expected_fields:
+  - added
+  - capabilities
+  - created_at
+  - deleted
+  - deleted_at
+  - description
+  - environment
+  - environment_files
+  - files
+  - files_container
+  - id
+  - is_rollback_disabled
+  - links
+  - name
+  - notification_topics
+  - outputs
+  - owner_id
+  - parameters
+  - parent_id
+  - replaced
+  - stack_name
+  - status
+  - status_reason
+  - tags
+  - template
+  - template_description
+  - template_url
+  - timeout_mins
+  - unchanged
+  - updated
+  - updated_at
+  - user_project_id
diff --git a/ci/roles/orchestration/tasks/main.yaml b/ci/roles/orchestration/tasks/main.yaml
index b205d46..8cbecf5 100644
--- a/ci/roles/orchestration/tasks/main.yaml
+++ b/ci/roles/orchestration/tasks/main.yaml
@@ -5,6 +5,12 @@
     # template is searched related to playbook location or as absolute path
     template: "roles/orchestration/files/hello-world.yaml"
     name: "{{ stack_name }}"
+  register: minimal_stack
+
+- name: Assert fields returned by create stack
+  assert:
+    that: item in minimal_stack.stack
+  loop: "{{ expected_fields }}"
 
 - name: List stacks
   openstack.cloud.stack_info:
@@ -21,6 +27,11 @@
     name: "{{ stack_name }}"
   register: test_stack
 
+- name: Assert fields returned by stack info
+  assert:
+    that: item in test_stack.stack[0]
+  loop: "{{ expected_fields }}"
+
 - assert:
     that:
       - test_stack is defined
diff --git a/plugins/modules/stack.py b/plugins/modules/stack.py
index baff756..b36ed30 100644
--- a/plugins/modules/stack.py
+++ b/plugins/modules/stack.py
@@ -58,14 +58,12 @@ requirements:
 extends_documentation_fragment:
 - openstack.cloud.openstack
 '''
+
 EXAMPLES = '''
----
 - name: create stack
-  ignore_errors: True
-  register: stack_create
   openstack.cloud.stack:
-    name: "{{ stack_name }}"
-    tag: "{{ tag_name }}"
+    name: "teststack"
+    tag: "tag1,tag2"
     state: present
     template: "/path/to/my_stack.yaml"
     environment:
@@ -75,62 +73,90 @@ EXAMPLES = '''
         bmc_flavor: m1.medium
         bmc_image: CentOS
         key_name: default
-        private_net: "{{ private_net_param }}"
         node_count: 2
         name: undercloud
         image: CentOS
         my_flavor: m1.large
-        external_net: "{{ external_net_param }}"
 '''
 
 RETURN = '''
-id:
-    description: Stack ID.
-    type: str
-    sample: "97a3f543-8136-4570-920e-fd7605c989d6"
-    returned: always
-
 stack:
     description: stack info
-    type: complex
+    type: dict
     returned: always
     contains:
-        action:
-            description: Action, could be Create or Update.
+        added:
+            description: List of resource objects that will be added.
+            type: list
+        capabilities:
+            description: AWS compatible template listing capabilities.
+            type: list
+        created_at:
+            description: Time when created.
             type: str
-            sample: "CREATE"
-        creation_time:
-            description: Time when the action has been made.
+            sample: "2016-07-05T17:38:12Z"
+        deleted:
+            description: A list of resource objects that will be deleted.
+            type: list
+        deleted_at:
+            description: Time when the deleted.
             type: str
             sample: "2016-07-05T17:38:12Z"
         description:
-            description: Description of the Stack provided in the heat template.
+            description: >
+              Description of the Stack provided in the heat
+              template.
             type: str
             sample: "HOT template to create a new instance and networks"
+        environment:
+            description: A JSON environment for the stack.
+            type: dict
+        environment_files:
+            description: >
+              An ordered list of names for environment files found
+              in the files dict.
+            type: list
+        files:
+            description: >
+              Additional files referenced in the template or
+              the environment
+            type: dict
+        files_container:
+            description: >
+              Name of swift container with child templates and
+              files.
+            type: str
         id:
             description: Stack ID.
             type: str
             sample: "97a3f543-8136-4570-920e-fd7605c989d6"
+        is_rollback_disabled:
+            description: Whether the stack will support a rollback.
+            type: bool
+        links:
+            description: Links to the current Stack.
+            type: list
+            elements: dict
+            sample: "[{'href': 'http://foo:8004/v1/7f6a/stacks/test-stack/
+                     97a3f543-8136-4570-920e-fd7605c989d6']"
         name:
             description: Name of the Stack
             type: str
             sample: "test-stack"
-        identifier:
-            description: Identifier of the current Stack action.
+        notification_topics:
+            description: Stack related events.
             type: str
-            sample: "test-stack/97a3f543-8136-4570-920e-fd7605c989d6"
-        links:
-            description: Links to the current Stack.
-            type: list
-            elements: dict
-            sample: "[{'href': 'http://foo:8004/v1/7f6a/stacks/test-stack/97a3f543-8136-4570-920e-fd7605c989d6']"
+            sample: "HOT template to create a new instance and networks"
         outputs:
             description: Output returned by the Stack.
             type: list
             elements: dict
-            sample: "{'description': 'IP address of server1 in private network',
+            sample: "[{'description': 'IP of server1 in private network',
                         'output_key': 'server1_private_ip',
-                        'output_value': '10.1.10.103'}"
+                        'output_value': '10.1.10.103'}]"
+        owner_id:
+            description: The ID of the owner stack if any.
+            type: str
         parameters:
             description: Parameters of the current Stack
             type: dict
@@ -138,21 +164,70 @@ stack:
                         'OS::stack_id': '97a3f543-8136-4570-920e-fd7605c989d6',
                         'OS::stack_name': 'test-stack',
                         'stack_status': 'CREATE_COMPLETE',
-                        'stack_status_reason': 'Stack CREATE completed successfully',
+                        'stack_status_reason':
+                            'Stack CREATE completed successfully',
                         'status': 'COMPLETE',
-                        'template_description': 'HOT template to create a new instance and networks',
+                        'template_description':
+                            'HOT template to create a new instance and nets',
                         'timeout_mins': 60,
                         'updated_time': null}"
+        parent_id:
+            description: The ID of the parent stack if any.
+            type: str
+        replaced:
+            description: A list of resource objects that will be replaced.
+            type: str
+        stack_name:
+            description: Name of the stack.
+            type: str
+        status:
+            description: stack status.
+            type: str
+        status_reason:
+            description: >
+              Explaining how the stack transits to its current
+              status.
+            type: str
+        tags:
+            description: A list of strings used as tags on the stack
+            type: list
+        template:
+            description: A dict containing the template use for stack creation.
+            type: dict
+        template_description:
+            description: Stack template description text.
+            type: str
+        template_url:
+            description: The URL where a stack template can be found.
+            type: str
+        timeout_mins:
+            description: Stack operation timeout in minutes.
+            type: str
+        unchanged:
+            description: >
+              A list of resource objects that will remain unchanged
+              if a stack.
+            type: list
+        updated:
+            description: >
+              A list of resource objects that will have their
+              properties updated.
+            type: list
+        updated_at:
+            description: Timestamp of last update on the stack.
+            type: str
+        user_project_id:
+            description: The ID of the user project created for this stack.
+            type: str
 '''
 
-
 from ansible_collections.openstack.cloud.plugins.module_utils.openstack import OpenStackModule
 
 
 class StackModule(OpenStackModule):
     argument_spec = dict(
         name=dict(required=True),
-        tag=dict(min_ver='0.28.0'),
+        tag=dict(),
         template=dict(),
         environment=dict(type='list', elements='str'),
         parameters=dict(default={}, type='dict'),
@@ -162,7 +237,9 @@ class StackModule(OpenStackModule):
     )
 
     module_kwargs = dict(
-        supports_check_mode=True
+        supports_check_mode=True,
+        required_if=[
+            ('state', 'present', ('template',), True)]
     )
 
     def _create_stack(self, stack, parameters):
@@ -175,8 +252,7 @@ class StackModule(OpenStackModule):
             rollback=self.params['rollback'],
             **parameters)
 
-        stack = self.conn.get_stack(stack.id, None)
-        if stack.stack_status == 'CREATE_COMPLETE':
+        if stack.status == 'CREATE_COMPLETE':
             return stack
         else:
             self.fail_json(msg="Failure in creating stack: {0}".format(stack))
@@ -200,8 +276,10 @@ class StackModule(OpenStackModule):
     def _system_state_change(self, stack):
         state = self.params['state']
         if state == 'present':
-            if not stack:
-                return True
+            # This method will always return True if state is present to
+            # include the case of stack update as there is no simple way
+            # to check if the stack will indeed be updated
+            return True
         if state == 'absent' and stack:
             return True
         return False
@@ -209,11 +287,6 @@ class StackModule(OpenStackModule):
     def run(self):
         state = self.params['state']
         name = self.params['name']
-        # Check for required parameters when state == 'present'
-        if state == 'present':
-            for p in ['template']:
-                if not self.params[p]:
-                    self.fail_json(msg='%s required with present state' % p)
 
         stack = self.conn.get_stack(name)
 
@@ -227,14 +300,13 @@ class StackModule(OpenStackModule):
             else:
                 stack = self._update_stack(stack, parameters)
             self.exit_json(changed=True,
-                           stack=stack,
-                           id=stack.id)
+                           stack=stack.to_dict(computed=False))
         elif state == 'absent':
             if not stack:
                 changed = False
             else:
                 changed = True
-                if not self.conn.delete_stack(name, wait=self.params['wait']):
+                if not self.conn.delete_stack(stack['id'], wait=self.params['wait']):
                     self.fail_json(msg='delete stack failed for stack: %s' % name)
             self.exit_json(changed=changed)
 
-- 
GitLab