Repository: ansible-collections/community.general

Issue:
Terraform module fails when using absent state with module diff
### Summary

Afetr updating ansible to 9.2.0 and hence community.general to 8.3.0 version module `terraform` fails when using with parameter `state: "absent"` and default diff on module. 

### Issue Type

Bug Report

### Component Name

terraform

### Ansible Version

```console (paste below)
$ ansible --version
ansible [core 2.16.3]
  config file = /playbook/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.10/dist-packages/ansible
  ansible collection location = /playbook/.ansible_galaxy/collections
  executable location = /usr/local/bin/ansible
  python version = 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] (/usr/bin/python)
  jinja version = 3.1.3
  libyaml = True
```


### Community.general Version

```console (paste below)
$ ansible-galaxy collection list community.general
[DEPRECATION WARNING]: [defaults]collections_paths option, does not fit var naming standard, use the singular form collections_path instead. This feature will be removed from ansible-core in version 2.19. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.

# /usr/local/lib/python3.10/dist-packages/ansible_collections
Collection        Version
----------------- -------
community.general 8.3.0
```


### Configuration

```console (paste below)
$ ansible-config dump --only-changed
[DEPRECATION WARNING]: [defaults]collections_paths option, does not fit var naming standard, use the singular form collections_path instead. This feature will be removed from ansible-core in version 2.19. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
ANSIBLE_COW_SELECTION(/playbook/ansible.cfg) = random
ANSIBLE_FORCE_COLOR(/playbook/ansible.cfg) = True
CALLBACKS_ENABLED(/playbook/ansible.cfg) = ['ansible.posix.profile_tasks']
COLLECTIONS_PATHS(/playbook/ansible.cfg) = ['/playbook/.ansible_galaxy/collections']
CONFIG_FILE() = /playbook/ansible.cfg
DEFAULT_FORKS(/playbook/ansible.cfg) = 32
DEFAULT_ROLES_PATH(/playbook/ansible.cfg) = ['/playbook/.ansible_galaxy/roles']
DEFAULT_STDOUT_CALLBACK(/playbook/ansible.cfg) = ansible.posix.debug
RETRY_FILES_ENABLED(/playbook/ansible.cfg) = False
```


### OS / Environment

```console
$ cat /etc/os-release 
PRETTY_NAME="Ubuntu 22.04.3 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.3 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
```
ansible installed in docker container based on ubuntu 

### Steps to Reproduce

<!--- Paste example playbooks or commands between quotes below -->
```yaml (paste below)
- name: "Terraform test"
  hosts: "localhost"
  any_errors_fatal: yes
  tasks:
    - name: "create Terraform resources"
      community.general.terraform:
        project_path: "{{ playbook_dir }}/test"
        force_init: "true"
        state: "present"
        init_reconfigure: yes
        provider_upgrade: yes

    # this fails
    - name: "destroy Terraform resources"
      community.general.terraform:
        project_path: "{{ playbook_dir }}/test"
        force_init: "true"
        state: "absent"
        init_reconfigure: yes
        provider_upgrade: yes

    # this runs corretcly
    - name: "destroy Terraform resources"
      community.general.terraform:
        project_path: "{{ playbook_dir }}/test"
        force_init: "true"
        state: "absent"
        init_reconfigure: yes
        provider_upgrade: yes
      diff: no
```




### Expected Results

Terraform module with `state: "absent"` should support diff mode or do not try to compare resources on this mode 

### Actual Results

```console (paste below)
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: KeyError: 'resource_changes'
fatal: [localhost]: FAILED! => {
    "changed": false,
    "rc": 1
}

MSG:

MODULE FAILURE
See stdout/stderr for the exact error


MODULE_STDERR:

Traceback (most recent call last):
  File "/home/kszym/.ansible/tmp/ansible-tmp-1707738521.8943043-351-216305452502166/AnsiballZ_terraform.py", line 107, in <module>
    _ansiballz_main()
  File "/home/kszym/.ansible/tmp/ansible-tmp-1707738521.8943043-351-216305452502166/AnsiballZ_terraform.py", line 99, in _ansiballz_main
    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
  File "/home/kszym/.ansible/tmp/ansible-tmp-1707738521.8943043-351-216305452502166/AnsiballZ_terraform.py", line 47, in invoke_module
    runpy.run_module(mod_name='ansible_collections.community.general.plugins.modules.terraform', init_globals=dict(_module_fqn='ansible_collections.community.general.plugins.modules.terraform', _modlib_path=modlib_path),
  File "/usr/lib/python3.10/runpy.py", line 224, in run_module
    return _run_module_code(code, init_globals, run_name, mod_spec)
  File "/usr/lib/python3.10/runpy.py", line 96, in _run_module_code
    _run_code(code, mod_globals, init_globals,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/tmp/ansible_community.general.terraform_payload_insoo9v6/ansible_community.general.terraform_payload.zip/ansible_collections/community/general/plugins/modules/terraform.py", line 719, in <module>
  File "/tmp/ansible_community.general.terraform_payload_insoo9v6/ansible_community.general.terraform_payload.zip/ansible_collections/community/general/plugins/modules/terraform.py", line 663, in main
  File "/tmp/ansible_community.general.terraform_payload_insoo9v6/ansible_community.general.terraform_payload.zip/ansible_collections/community/general/plugins/modules/terraform.py", line 437, in get_diff
KeyError: 'resource_changes'
```


### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:
Files identified in the description:
* [`plugins/modules/terraform.py`](https://github.com/ansible-collections/community.general/blob/main/plugins/modules/terraform.py)

If these files are incorrect, 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/devel/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @m-yosefpor @rainerleber
[click here for bot help](https://github.com/ansible/ansibullbot/blob/devel/ISSUE_HELP.md)
<!--- boilerplate: notify --->
Diff mode was recently implemented in #7896. @parsa97 can you please take a look at this issue?
Thank you for your report. The issue has been verified and reproduced. A fix is being prepared and will be submitted for review tonight.


Resolving patch:
diff --git a/plugins/modules/terraform.py b/plugins/modules/terraform.py
--- a/plugins/modules/terraform.py
+++ b/plugins/modules/terraform.py
@@ -376,7 +376,7 @@ def remove_workspace(bin_path, project_path, workspace):
     _workspace_cmd(bin_path, project_path, 'delete', workspace)
 
 
-def build_plan(command, project_path, variables_args, state_file, targets, state, apply_args, plan_path=None):
+def build_plan(command, project_path, variables_args, state_file, targets, state, args, plan_path=None):
     if plan_path is None:
         f, plan_path = tempfile.mkstemp(suffix='.tfplan')
 
@@ -389,11 +389,15 @@ def build_plan(command, project_path, variables_args, state_file, targets, state
             plan_command.append(c)
 
     if state == "present":
-        for a in apply_args:
+        for a in args:
             local_command.remove(a)
         for c in local_command[1:]:
             plan_command.append(c)
 
+    if state == "absent":
+        for a in args:
+            plan_command.append(a)
+
     plan_command.extend(['-input=false', '-no-color', '-detailed-exitcode', '-out', plan_path])
 
     for t in targets:
@@ -434,7 +438,14 @@ def get_tf_resource_address(e):
         return e['resource']
 
     diff_json_output = json.loads(diff_output)
-    tf_reosource_changes = diff_json_output['resource_changes']
+
+    # Ignore diff if resource_changes does not exists in tfplan
+    if 'resource_changes' in diff_json_output:
+        tf_reosource_changes = diff_json_output['resource_changes']
+    else:
+        module.warn("Cannot find resource_changes in terraform plan, diff/check ignored")
+        return False, {}
+
     diff_after = []
     diff_before = []
     changed = False
@@ -658,6 +669,10 @@ def process_complex_args(vars):
 
     result_diff = dict()
     if module._diff or module.check_mode:
+        if state == 'absent':
+            plan_absent_args = ['-destroy']
+            plan_file, needs_application, out, err, command = build_plan(command, project_path, variables_args, state_file,
+                                                                         module.params.get('targets'), state, plan_absent_args, plan_file)
         diff_command = [command[0], 'show', '-json', plan_file]
         rc, diff_output, err = module.run_command(diff_command, check_rc=False, cwd=project_path)
         changed, result_diff = get_diff(diff_output)


Test patch: