Repository: ansible-collections/community.general

Issue:
xfs_quota fails to initialize new project quotas
### Summary

When I initialize new XFS project quotas with the `xfs_quota` module the setup of the quotas fails, ansible is not reporting any errors (silent failure).

This is a new attempt to submit https://github.com/ansible-collections/community.general/pull/3350, I will try to also open a new PR.

### Issue Type

Bug Report

### Component Name

- plugins/modules/system/xfs_quota.py

### Ansible Version

```console (paste below)
$ ansible --version
ansible [core 2.13.0.post0] (stable-2.13 e6b16ddeb5) last updated 2022/06/01 12:54:52 (GMT +200)
  config file = $HOME/.ansible.cfg
  configured module search path = ['$HOME/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = $ansibledir/ansible/lib/ansible
  ansible collection location = $HOME/.ansible/collections:/usr/share/ansible/collections
  executable location = $ansibledir/ansible/bin/ansible
  python version = 3.10.6 (main, Aug  2 2022, 00:00:00) [GCC 12.1.1 20220507 (Red Hat 12.1.1-1)]
  jinja version = 3.0.3
  libyaml = True
```


### Community.general Version

```console (paste below)
$ ansible-galaxy collection list community.general
# $HOME/.ansible/collections/ansible_collections
Collection        Version
----------------- -------
community.general 5.0.1 
```


### Configuration

```console (paste below)
$ ansible-config dump --only-changed
DEFAULT_FORKS($HOME/.ansible.cfg) = 32
DEFAULT_HOST_LIST($HOME/.ansible.cfg) = ['$ansibledir/ansible>
DEFAULT_JINJA2_NATIVE($HOME/.ansible.cfg) = True
DEFAULT_ROLES_PATH($HOME/.ansible.cfg) = ['$HOME/.ansible/roles']
DEFAULT_STDOUT_CALLBACK($HOME/.ansible.cfg) = yaml
DEFAULT_TIMEOUT($HOME/.ansible.cfg) = 60

```


### OS / Environment

Fedora 36

### Steps to Reproduce

Have on your target machine `/etc/projects` with e.g.
```
100:/home
```
and `/etc/projid` with
```
home:100
```

<!--- Paste example playbooks or commands between quotes below -->
```yaml (paste below)
- name: Set root project soft and hard limit
  community.general.xfs_quota:
    type: project
    name: home
    mountpoint: /
    bsoft: 60g
    bhard: 60g
    state: present
```
Check the results with `xfs_quota -x -c report` on the target machine before and after. The entry should change from
```
home              232          0          0     00 [--------]
```
to
```
home              232   62914560   62914560     00 [--------]
```
but it does not.

### Expected Results

I expected the module to properly setup the quota project with something like `xfs_quota -x -c 'project -s <project name>' /`, but this setup fails.

### Actual Results

The ansible playbook run finishes without error message as if there is no problem.

`xfs_quota -x -c report` on the target machine reveals that the quota project group has not been set up.
```console (paste below)
home              232          0          0     00 [--------]
```

### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:
Files identified in the description:
* [`plugins/modules/system/xfs_quota.py`](https://github.com/ansible-collections/community.general/blob/main/plugins/modules/system/xfs_quota.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 @bushvin
[click here for bot help](https://github.com/ansible/ansibullbot/blob/devel/ISSUE_HELP.md)
<!--- boilerplate: notify --->
Files identified in the description:
* [`plugins/modules/xfs_quota.py`](https://github.com/ansible-collections/community.general/blob/main/plugins/modules/xfs_quota.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 --->

Resolving patch:
diff --git a/plugins/modules/xfs_quota.py b/plugins/modules/xfs_quota.py
--- a/plugins/modules/xfs_quota.py
+++ b/plugins/modules/xfs_quota.py
@@ -300,31 +300,35 @@ def main():
                         prj_set = False
                         break
 
-        if not prj_set and not module.check_mode:
-            cmd = "project -s"
-            rc, stdout, stderr = exec_quota(module, xfs_quota_bin, cmd, mountpoint)
-            if rc != 0:
-                result["cmd"] = cmd
-                result["rc"] = rc
-                result["stdout"] = stdout
-                result["stderr"] = stderr
-                module.fail_json(
-                    msg="Could not get quota realtime block report.", **result
-                )
+        if state == "present" and not prj_set:
+            if not module.check_mode:
+                cmd = "project -s %s" % name
+                rc, stdout, stderr = exec_quota(module, xfs_quota_bin, cmd, mountpoint)
+                if rc != 0:
+                    result["cmd"] = cmd
+                    result["rc"] = rc
+                    result["stdout"] = stdout
+                    result["stderr"] = stderr
+                    module.fail_json(
+                        msg="Could not get quota realtime block report.", **result
+                    )
 
             result["changed"] = True
 
-        elif not prj_set and module.check_mode:
-            result["changed"] = True
+        elif state == "absent" and prj_set and name != quota_default:
+            if not module.check_mode:
+                cmd = "project -C %s" % name
+                rc, stdout, stderr = exec_quota(module, xfs_quota_bin, cmd, mountpoint)
+                if rc != 0:
+                    result["cmd"] = cmd
+                    result["rc"] = rc
+                    result["stdout"] = stdout
+                    result["stderr"] = stderr
+                    module.fail_json(
+                        msg="Failed to clear managed tree from project quota control.", **result
+                    )
 
-    # Set limits
-    if state == "absent":
-        bhard = 0
-        bsoft = 0
-        ihard = 0
-        isoft = 0
-        rtbhard = 0
-        rtbsoft = 0
+            result["changed"] = True
 
     current_bsoft, current_bhard = quota_report(
         module, xfs_quota_bin, mountpoint, name, quota_type, "b"
@@ -336,6 +340,23 @@ def main():
         module, xfs_quota_bin, mountpoint, name, quota_type, "rtb"
     )
 
+    # Set limits
+    if state == "absent":
+        bhard = 0
+        bsoft = 0
+        ihard = 0
+        isoft = 0
+        rtbhard = 0
+        rtbsoft = 0
+
+        # Ensure that a non-existing quota does not trigger a change
+        current_bsoft = current_bsoft if current_bsoft is not None else 0
+        current_bhard = current_bhard if current_bhard is not None else 0
+        current_isoft = current_isoft if current_isoft is not None else 0
+        current_ihard = current_ihard if current_ihard is not None else 0
+        current_rtbsoft = current_rtbsoft if current_rtbsoft is not None else 0
+        current_rtbhard = current_rtbhard if current_rtbhard is not None else 0
+
     result["xfs_quota"] = dict(
         bsoft=current_bsoft,
         bhard=current_bhard,
@@ -370,23 +391,21 @@ def main():
         limit.append("rtbhard=%s" % rtbhard)
         result["rtbhard"] = int(rtbhard)
 
-    if len(limit) > 0 and not module.check_mode:
-        if name == quota_default:
-            cmd = "limit %s -d %s" % (type_arg, " ".join(limit))
-        else:
-            cmd = "limit %s %s %s" % (type_arg, " ".join(limit), name)
-
-        rc, stdout, stderr = exec_quota(module, xfs_quota_bin, cmd, mountpoint)
-        if rc != 0:
-            result["cmd"] = cmd
-            result["rc"] = rc
-            result["stdout"] = stdout
-            result["stderr"] = stderr
-            module.fail_json(msg="Could not set limits.", **result)
+    if len(limit) > 0:
+        if not module.check_mode:
+            if name == quota_default:
+                cmd = "limit %s -d %s" % (type_arg, " ".join(limit))
+            else:
+                cmd = "limit %s %s %s" % (type_arg, " ".join(limit), name)
 
-        result["changed"] = True
+            rc, stdout, stderr = exec_quota(module, xfs_quota_bin, cmd, mountpoint)
+            if rc != 0:
+                result["cmd"] = cmd
+                result["rc"] = rc
+                result["stdout"] = stdout
+                result["stderr"] = stderr
+                module.fail_json(msg="Could not set limits.", **result)
 
-    elif len(limit) > 0 and module.check_mode:
         result["changed"] = True
 
     module.exit_json(**result)


Test patch:
diff --git a/tests/integration/targets/xfs_quota/tasks/pquota.yml b/tests/integration/targets/xfs_quota/tasks/pquota.yml
--- a/tests/integration/targets/xfs_quota/tasks/pquota.yml
+++ b/tests/integration/targets/xfs_quota/tasks/pquota.yml
@@ -123,7 +123,7 @@
   - name: Assert project limits results for xft_quotaval after re-apply
     assert:
       that:
-      - test_pquota_project_after.changed
+      - test_pquota_project_after is not changed
   - name: Reset default project limits
     xfs_quota:
       mountpoint: '{{ remote_tmp_dir }}/pquota'