Repository: ansible-collections/community.general

Issue:
lxc_container: lxc-create commandline yields unknown option error
### Summary

The `lxc_container` module builds an invalid commandline for `lxc-create` with Ansible 6.6.0; works as expected on Ansible 6.5.0.

### Issue Type

Bug Report

### Component Name

`lxc_container`

### Ansible Version

```console (paste below)
$ ansible --version
ansible [core 2.13.6]
  config file = /home/user/somepath/ansible.cfg
  configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/user/.pyenv/versions/3.10.8/envs/ansible/lib/python3.10/site-packages/ansible
  ansible collection location = /home/user/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/user/.pyenv/versions/ansible/bin/ansible
  python version = 3.10.8 (main, Nov  9 2022, 12:23:27) [GCC 12.2.0]
  jinja version = 3.1.2
  libyaml = True
```

### Community.general Version

```console (paste below)
$ ansible-galaxy collection list community.general

# /home/user/.pyenv/versions/3.10.8/envs/ansible/lib/python3.10/site-packages/ansible_collections
Collection        Version
----------------- -------
community.general 5.8.0  
```


### Configuration

not relevant

### OS / Environment

* Controller on Arch, Python 3.10.8
* Node Debian 11, Python 3.9, python3-lxc 3.0.4-1+b4

### Steps to Reproduce

<!--- Paste example playbooks or commands between quotes below -->
```yaml (paste below)
- name: Create a started container
  community.general.lxc_container:
    name: mycontainer
    state: started
    template: debian
    template_options: --release bullseye
```

### Expected Results

A running container. The above steps to reproduce work just fine in Ansible 6.5.0, so it seems to be a regression in 6.6.0.

### Actual Results

```console (paste below)
TASK [lxc_container : Create a started container] *********************************************************************************************************************************************************************************************
fatal: [node]: FAILED! => {"changed": false, "command": "/usr/bin/lxc-create --name mycontainer --quiet template --template backing_store --bdev -- --release bullseye", "err": "/usr/bin/lxc-create: unrecognized option '--release'\nUsage: lxc-create --name=NAME --template=TEMPLATE [OPTION...] [-- template-options]\n\nlxc-create creates a container\n\nOptions :\n  -n, --name=NAME               NAME of the container\n  -f, --config=CONFIG           Initial configuration file\n  -t, --template=TEMPLATE       Template to use to setup container\n  -B, --bdev=BDEV               Backing store type to use\n      --dir=DIR                 Place rootfs directory under DIR\n\n  BDEV options for LVM (with -B/--bdev lvm):\n      --lvname=LVNAME           Use LVM lv name LVNAME\n                                (Default: container name)\n      --vgname=VG               Use LVM vg called VG\n                                (Default: lxc)\n      --thinpool=TP             Use LVM thin pool called TP\n                                (Default: lxc)\n\n  BDEV options for Ceph RBD (with -B/--bdev rbd) :\n      --rbdname=RBDNAME         Use Ceph RBD name RBDNAME\n                                (Default: container name)\n      --rbdpool=POOL            Use Ceph RBD pool name POOL\n                                (Default: lxc)\n\n  BDEV option for ZFS (with -B/--bdev zfs) :\n      --zfsroot=PATH            Create zfs under given zfsroot\n                                (Default: tank/lxc)\n\n  BDEV options for LVM or Loop (with -B/--bdev lvm/loop) :\n      --fstype=TYPE             Create fstype TYPE\n                                (Default: ext4)\n      --fssize=SIZE[U]          Create filesystem of\n                                size SIZE * unit U (bBkKmMgGtT)\n                                (Default: 1G, default unit: M)\n  -- template-options\n         This will pass template-options to the template as arguments.\n         To see the list of options supported by the template,\n         you can run lxc-create -t TEMPLATE -h.\n\nCommon options :\n  -o, --logfile=FILE               Output log to FILE instead of stderr\n  -l, --logpriority=LEVEL          Set log priority to LEVEL\n  -q, --quiet                      Don't produce any output\n  -P, --lxcpath=PATH               Use specified container path\n  -?, --help                       Give this help list\n      --usage                      Give a short usage message\n      --version                    Print the version number\n\nMandatory or optional arguments to long options are also mandatory or optional\nfor any corresponding short options.\n\nSee the lxc-create man page for further information.\n\n", "msg": "Failed executing lxc-create.", "rc": 1}
```

Running the created commandline in the shell for some nicer output:

```shell
# /usr/bin/lxc-create --name mycontainer --quiet template --template backing_store --bdev -- --release bullseye
/usr/bin/lxc-create: unrecognized option '--release'
Usage: lxc-create --name=NAME --template=TEMPLATE [OPTION...] [-- template-options]

lxc-create creates a container

Options :
  -n, --name=NAME               NAME of the container
  -f, --config=CONFIG           Initial configuration file
  -t, --template=TEMPLATE       Template to use to setup container
  -B, --bdev=BDEV               Backing store type to use
      --dir=DIR                 Place rootfs directory under DIR

  BDEV options for LVM (with -B/--bdev lvm):
      --lvname=LVNAME           Use LVM lv name LVNAME
                                (Default: container name)
      --vgname=VG               Use LVM vg called VG
                                (Default: lxc)
      --thinpool=TP             Use LVM thin pool called TP
                                (Default: lxc)

  BDEV options for Ceph RBD (with -B/--bdev rbd) :
      --rbdname=RBDNAME         Use Ceph RBD name RBDNAME
                                (Default: container name)
      --rbdpool=POOL            Use Ceph RBD pool name POOL
                                (Default: lxc)

  BDEV option for ZFS (with -B/--bdev zfs) :
      --zfsroot=PATH            Create zfs under given zfsroot
                                (Default: tank/lxc)

  BDEV options for LVM or Loop (with -B/--bdev lvm/loop) :
      --fstype=TYPE             Create fstype TYPE
                                (Default: ext4)
      --fssize=SIZE[U]          Create filesystem of
                                size SIZE * unit U (bBkKmMgGtT)
                                (Default: 1G, default unit: M)
  -- template-options
         This will pass template-options to the template as arguments.
         To see the list of options supported by the template,
         you can run lxc-create -t TEMPLATE -h.

Common options :
  -o, --logfile=FILE               Output log to FILE instead of stderr
  -l, --logpriority=LEVEL          Set log priority to LEVEL
  -q, --quiet                      Don't produce any output
  -P, --lxcpath=PATH               Use specified container path
  -?, --help                       Give this help list
      --usage                      Give a short usage message
      --version                    Print the version number

Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.

See the lxc-create man page for further information.
```

### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:
Files identified in the description:
None

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 --->
Files identified in the description:
* [`plugins/modules/lxc_container.py`](https://github.com/ansible-collections/community.general/blob/main/plugins/modules/lxc_container.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 @cloudnull
[click here for bot help](https://github.com/ansible/ansibullbot/blob/devel/ISSUE_HELP.md)
<!--- boilerplate: notify --->
The only change to this module between c.g 5.6.0 and 5.7.0 is #5358. CC @russoz
hi @nblock thanks for reporting this!

I have no experience with LXC, so I cannot easily pinpoint what the problem is. That being said, I am reading:
* https://www.man7.org/linux/man-pages/man1/lxc-create.1.html
* https://ubuntu.com/server/docs/containers-lxc

And based on that, it *looks like* this command line is syntactically correct:
```bash
# /usr/bin/lxc-create --name mycontainer --quiet template --template backing_store --bdev -- --release bullseye
```

It seems that one would be able to check the available template options by running:
```bash
# /usr/bin/lxc-create --template backing_store -h
```

Could you please run that and paste the results here? TIA
Thx for looking into this!

> ```shell
> # /usr/bin/lxc-create --template backing_store -h
> ```

```
# /usr/bin/lxc-create --template backing_store -h
Usage: lxc-create --name=NAME --template=TEMPLATE [OPTION...] [-- template-options]

lxc-create creates a container

Options :
-n, --name=NAME               NAME of the container
-f, --config=CONFIG           Initial configuration file
-t, --template=TEMPLATE       Template to use to setup container
-B, --bdev=BDEV               Backing store type to use
--dir=DIR                 Place rootfs directory under DIR

BDEV options for LVM (with -B/--bdev lvm):
--lvname=LVNAME           Use LVM lv name LVNAME
(Default: container name)
--vgname=VG               Use LVM vg called VG
(Default: lxc)
--thinpool=TP             Use LVM thin pool called TP
(Default: lxc)

BDEV options for Ceph RBD (with -B/--bdev rbd) :
--rbdname=RBDNAME         Use Ceph RBD name RBDNAME
(Default: container name)
--rbdpool=POOL            Use Ceph RBD pool name POOL
(Default: lxc)

BDEV option for ZFS (with -B/--bdev zfs) :
--zfsroot=PATH            Create zfs under given zfsroot
(Default: tank/lxc)

BDEV options for LVM or Loop (with -B/--bdev lvm/loop) :
--fstype=TYPE             Create fstype TYPE
(Default: ext4)
--fssize=SIZE[U]          Create filesystem of
size SIZE * unit U (bBkKmMgGtT)
(Default: 1G, default unit: M)
-- template-options
This will pass template-options to the template as arguments.
To see the list of options supported by the template,
you can run lxc-create -t TEMPLATE -h.

Common options :
-o, --logfile=FILE               Output log to FILE instead of stderr
-l, --logpriority=LEVEL          Set log priority to LEVEL
-q, --quiet                      Don't produce any output
-P, --lxcpath=PATH               Use specified container path
-?, --help                       Give this help list
--usage                      Give a short usage message
--version                    Print the version number

Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.

See the lxc-create man page for further information.
```

There is no template `backing_store`. As a reference, this is the output of the `debian` template:

```
# /usr/bin/lxc-create --template debian -h
Usage: lxc-create --name=NAME --template=TEMPLATE [OPTION...] [-- template-options]

lxc-create creates a container

Options :
-n, --name=NAME               NAME of the container
-f, --config=CONFIG           Initial configuration file
-t, --template=TEMPLATE       Template to use to setup container
-B, --bdev=BDEV               Backing store type to use
--dir=DIR                 Place rootfs directory under DIR

BDEV options for LVM (with -B/--bdev lvm):
--lvname=LVNAME           Use LVM lv name LVNAME
(Default: container name)
--vgname=VG               Use LVM vg called VG
(Default: lxc)
--thinpool=TP             Use LVM thin pool called TP
(Default: lxc)

BDEV options for Ceph RBD (with -B/--bdev rbd) :
--rbdname=RBDNAME         Use Ceph RBD name RBDNAME
(Default: container name)
--rbdpool=POOL            Use Ceph RBD pool name POOL
(Default: lxc)

BDEV option for ZFS (with -B/--bdev zfs) :
--zfsroot=PATH            Create zfs under given zfsroot
(Default: tank/lxc)

BDEV options for LVM or Loop (with -B/--bdev lvm/loop) :
--fstype=TYPE             Create fstype TYPE
(Default: ext4)
--fssize=SIZE[U]          Create filesystem of
size SIZE * unit U (bBkKmMgGtT)
(Default: 1G, default unit: M)
-- template-options
This will pass template-options to the template as arguments.
To see the list of options supported by the template,
you can run lxc-create -t TEMPLATE -h.

Common options :
-o, --logfile=FILE               Output log to FILE instead of stderr
-l, --logpriority=LEVEL          Set log priority to LEVEL
-q, --quiet                      Don't produce any output
-P, --lxcpath=PATH               Use specified container path
-?, --help                       Give this help list
--usage                      Give a short usage message
--version                    Print the version number

Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.

See the lxc-create man page for further information.

Template specific options can be passed to lxc-create after a '--' like this:

lxc-create --name=NAME [-lxc-create-options] -- [-template-options]

Usage: /usr/share/lxc/templates/lxc-debian -h|--help -p|--path=<path> [-c|--clean] [-a|--arch=<arch>] [-r|--release=<release>]
[--mirror=<mirror>] [--security-mirror=<security mirror>]
[--package=<package_name1,package_name2,...>]
[-I|--interpreter-path=<interpreter path>]
[-F | --flush-cache] [-S|--auth-key=<keyfile>]

Options :

-h, --help             print this help text
-p, --path=PATH        directory where config and rootfs of this VM will be kept
-S, --auth-key=KEYFILE SSH public key to inject into the container as the root user.
-a, --arch=ARCH        The container architecture. Can be one of: i686, x86_64,
amd64, armhf, armel, powerpc. Defaults to host arch.
-r, --release=RELEASE  Debian release. Can be one of: wheezy, jessie, stretch, buster, sid.
Defaults to current stable.
--mirror=MIRROR        Debian mirror to use during installation. Overrides the MIRROR
environment variable (see below).
--security-mirror=SECURITY_MIRROR
Debian mirror to use for security updates. Overrides the
SECURITY_MIRROR environment variable (see below).
--packages=PACKAGE_NAME1,PACKAGE_NAME2,...
List of additional packages to install. Comma separated, without space.
-c, --clean            only clean up the cache and terminate
--enable-non-free      include also Debian's contrib and non-free repositories.
-I|--interpreter-path=INTERPRETER-PATH
Path of the binfmt interpreter to copy to the rootfs
-F | --flush-cache     Flush the debian release cache

Environment variables:

MIRROR                 The Debian package mirror to use. See also the --mirror switch above.
Defaults to 'http://deb.debian.org/debian'
SECURITY_MIRROR        The Debian package security mirror to use. See also the --security-mirror switch above.
Defaults to 'http://security.debian.org/debian-security'
```


Also note that the `template` argument of the task is no longer part of the built commandline, it should contain `--template debian` somewhere before template specific options.

Working example: `/usr/bin/lxc-create --name mycontainer --quiet --template debian -- --release bullseye`
Pending more investigation (probably writing some tests too), but given:
* https://github.com/ansible-collections/community.general/blob/main/plugins/modules/lxc_container.py#L462-L474
* https://github.com/ansible-collections/community.general/blob/main/plugins/modules/lxc_container.py#L661-L664
* https://github.com/ansible-collections/community.general/blob/main/plugins/modules/lxc_container.py#L829-L834

It seems that the command line has been built wrongly for a long time. It is not `--template backing_store`, it is `template --template` and `backing_store --bdev`. Looks like the actual template name `debian` got lost in the way.

Hi, ok, it seems there was already ticket on this broken lxc_container. I updated my ansible stuff yesterday from some very old version to current, and this lxc_container went broken.
I am not a python developer, but with these changes i was able to fix the lxc_container module.
[0001-Correct-module-params-for-add_variables.patch.txt](https://github.com/ansible-collections/community.general/files/10064691/0001-Correct-module-params-for-add_variables.patch.txt)


Resolving patch:
diff --git a/plugins/modules/cloud/lxc/lxc_container.py b/plugins/modules/cloud/lxc/lxc_container.py
--- a/plugins/modules/cloud/lxc/lxc_container.py
+++ b/plugins/modules/cloud/lxc/lxc_container.py
@@ -677,7 +677,7 @@ def _get_vars(self, variables):
 
         false_values = BOOLEANS_FALSE.union([None, ''])
         result = dict(
-            (k, v)
+            (v, self.module.params[k])
             for k, v in variables.items()
             if self.module.params[k] not in false_values
         )


Test patch: