skip to Main Content

I am trying to use ansible to add two lines to a configuration file for an LXC container on a Proxmox server.

I have used both blockinfile and lineinfile to achieve this, and it works, but subsequent runs result in the duplication of lines despite that not being the (to my understanding) expected behavior.

When using blockinfile, the markers and block also appear in different locations in the file.

blockinfile

With this I am using a unique marker, with no newlines as per the documentation.

---
- name: Configure LXC Container
  ansible.builtin.blockinfile:
    path: "/etc/pve/lxc/{{ tailscale_lxc_vmid }}.conf"
    marker: "# {mark} ANSIBLE MANAGED BLOCK FOR CONTAINER {{ tailscale_lxc_vmid }}"
    block: |
      lxc.cgroup2.devices.allow = c 10:200 rwm
      lxc.mount.entry = /dev/net/tun dev/net/tun none bind,create=file
    owner: root
    group: www-data
    mode: "0640"
    insertafter: EOF
  register: lxc_config_result

Running the above results in the following configuration file.

# BEGIN ANSIBLE MANAGED BLOCK FOR CONTAINER 105
# END ANSIBLE MANAGED BLOCK FOR CONTAINER 105
arch: amd64
cmode: tty
console: 1
cores: 1
cpulimit: 0
cpuunits: 1024
hostname: test
memory: 512
net0: name=eth0,bridge=vmbr0,gw=192.168.0.1,hwaddr=XX:XX:XX:XX:XX:XX,ip=192.168.0.10/24,type=veth
onboot: 1
ostype: ubuntu
protection: 0
rootfs: local-lvm:vm-105-disk-0,size=8G
swap: 512
tty: 2
unprivileged: 1
lxc.cgroup2.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file

This seems to be bugged in some way because the marker lines are at the top of the file, and the block contents are at the end. I have tried removing insertafter, and also setting insertafter to unprivileged: 1 to force it to be placed in a specific location, but all three of these result in the above output.

In addition, running ansible again duplicated the block at the end of the file.

lineinfile

Because of the above issues, I tried switching to lineinfile.

- name: Ensure TUN device permissions
  ansible.builtin.lineinfile:
    path: "/etc/pve/lxc/{{ tailscale_lxc_vmid }}.conf"
    line: "lxc.cgroup2.devices.allow = c 10:200 rwm"
    state: present
  register: group_allow_result

- name: Ensure TUN device is mounted
  ansible.builtin.lineinfile:
    path: "/etc/pve/lxc/{{ tailscale_lxc_vmid }}.conf"
    line: "lxc.mount.entry = /dev/net/tun dev/net/tun none bind,create=file"
    state: present
  register: mount_result

This worked as expected, placing the two lines at the end of the file. But again, on subsequent runs, the lines are duplicated instead of being registered as already existing. I tried using the regexp option to specify how to search for the line, in-case of whitespace issues, but got the same result.

What am I doing wrong here?

I am thinking I am going to have to result to shell commands to grep for the line and then echo it in if it’s not present. Which will work, but I would like to know what the issue is with blockinfile and lineinfile because I am using them elsewhere with no issue.

2

Answers


  1. Chosen as BEST ANSWER

    This turned out to be a Proxmox issue, not an Ansible one.

    Proxmox LXC configuration files accept both <key>: <value and = . However, it automatically converts the latter into the former. This is why lineinfile` was not working.

    I am still slightly unsure as to why blockinfile was producing marker lines at the top of the file and placing the block at the bottom, but lineinfile is working as expected using the <key>: <value> format.


  2. Based on your comment

    Proxmox LXC configuration files accept both <key>: <value> and =. However, it automatically converts the latter into the former. This is why lineinfile was not working.

    and the documentation Anatomy of LXC Container Config File, Manual: pct.conf

    For a configuration file 105.conf

    arch: amd64
    cmode: tty
    console: 1
    cores: 1
    cpulimit: 0
    cpuunits: 1024
    hostname: test
    memory: 512
    net0: name=eth0,bridge=vmbr0,gw=192.168.0.1,hwaddr=XX:XX:XX:XX:XX:XX,ip=192.168.0.10/24,type=veth
    onboot: 1
    ostype: ubuntu
    protection: 0
    rootfs: local-lvm:vm-105-disk-0,size=8G
    swap: 512
    tty: 2
    unprivileged: 1
    

    a minimal example playbook

    ---
    - hosts: localhost
      become: false
      gather_facts: false
    
      vars:
    
        tailscale_lxc_vmid: 105
    
      tasks:
    
      - name: Configure LXC Container
        ansible.builtin.blockinfile:
          path: "{{ tailscale_lxc_vmid }}.conf"
          marker: "# {mark} ANSIBLE MANAGED BLOCK FOR CONTAINER {{ tailscale_lxc_vmid }}"
          block: |
            lxc.cgroup2.devices.allow: c 10:200 rwm
            lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file
          insertafter: EOF
        register: lxc_config_result
    

    will result into an output of

    TASK [Configure LXC Container] ******
    changed: [localhost]
    

    and a config file content cat 105.conf at the first run

    arch: amd64
    cmode: tty
    console: 1
    cores: 1
    cpulimit: 0
    cpuunits: 1024
    hostname: test
    memory: 512
    net0: name=eth0,bridge=vmbr0,gw=192.168.0.1,hwaddr=XX:XX:XX:XX:XX:XX,ip=192.168.0.10/24,type=veth
    onboot: 1
    ostype: ubuntu
    protection: 0
    rootfs: local-lvm:vm-105-disk-0,size=8G
    swap: 512
    tty: 2
    unprivileged: 1
    # BEGIN ANSIBLE MANAGED BLOCK FOR CONTAINER 105
    lxc.cgroup2.devices.allow: c 10:200 rwm
    lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file
    # END ANSIBLE MANAGED BLOCK FOR CONTAINER 105
    

    and for second run into

    TASK [Configure LXC Container] ******
    ok: [localhost]
    

    This will be the case for both syntax options, means also for INI-style

    lxc.cgroup2.devices.allow = c 10:200 rwm
    lxc.mount.entry = /dev/net/tun dev/net/tun none bind,create=file
    

    Q: "Why blockinfile was producing marker lines at the top of the file and placing the block at the bottom"

    A: This isn’t reproducible for me.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search