1

I'm attempting to update /boot/firmware/cmdline.txt on a few Raspberry Pis to enable cgroup support. Seemed a good fit for ansible.builtin.lineinfile.

The existing contents of /boot/firmware/cmdline.txt are a single line of key-value pairs

console=serial0,115200 dwc_otg.lpm_enable=0 console=tty1 root=LABEL=writable rootfstype=ext4 rootwait fixrtc quiet splash

I want the following key-value pairs to be appended to any existing contents of that file that might exist.

  • cgroup_enable=cpuset
  • cgroup_enable=memory
  • cgroup_memory=1
  • swapaccount=1

In the end, I want the file to look like

console=serial0,115200 dwc_otg.lpm_enable=0 console=tty1 root=LABEL=writable rootfstype=ext4 rootwait fixrtc quiet splash cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1 swapaccount=1

Here's the task I created:

- name: "Modify /boot/firmware/cmdline.txt to enable cGroup support if not already enabled"
    ansible.builtin.lineinfile:
      path: /boot/firmware/cmdline.txt
      regexp: '(.*) ((cgroup_enable=cpuset|cgroup_enable=memory|cgroup_memory=1|swapaccount=1)( {0,}|\n)){4}(.*)'
      line: '$1 cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1 swapaccount=1 $5'
      state: present
      backrefs: true
      backup: true
      owner: root
      group: root
      mode: '0755'

Unfortunately, it doesn't seem to update the file and I'm struggling to understand why. To clarify, the task executes fine but indicates that the file already matches the regexp with the following output:

TASK [common : Modify /boot/firmware/cmdline.txt to enable cGroup support if not already enabled] **************************
ok: [kube02.local]
ok: [kube03.local]
ok: [kube01.local]

As far as I can tell, it does not and I've tested in a few ways. Increasing verbosity of this doesn't help me figure this out, unfortunately.

I did find this post's answer which has a more robust solution, but I would love to understand why my solution doesn't work.

1 Answer 1

1

Put the new items into a list. For example,

  cmdline_add:
    - cgroup_enable=cpuset
    - cgroup_enable=memory
    - cgroup_memory=1
    - swapaccount=1

Add the items in the loop

  - lineinfile:
      path: /boot/firmware/cmdline.txt
      regexp: '^(?!.*?{{ item }})(.*)$'
      line: '\1 {{ item }}'
      backrefs: true
    loop: "{{ cmdline_add }}"

Because of the negative lookahead assertion (?!...) the regexp matches if the item is not in the line. The task is idempotent.


Example. Consolidate the configuration into comma-separated lists

Given the file

shell> cat /tmp/cmdline.txt

console=serial0,115200 dwc_otg.lpm_enable=0 console=tty1 root=LABEL=writable rootfstype=ext4 rootwait fixrtc quiet splash

The play

- hosts: localhost

  vars:

    cmdline_path: /tmp/cmdline.txt
    cmdline_add:
      - cgroup_enable=cpuset
      - cgroup_enable=memory
      - cgroup_memory=1
      - swapaccount=1

    cmdline_add_items: "{{ cmdline_add|map('split', '=', 1) }}"
    cmdline_add_list: |
      {% filter from_yaml %}
      {% for i in cmdline_add_items %}
      - {key: {{ i.0 }}, value: {{ i.1|d('')|split(',') }} }
      {% endfor %}
      {% endfilter %}

    cmdline_items: "{{ cmdline_out.stdout|trim|split(' ')|map('split', '=', 1) }}"
    cmdline_list: |
      {% filter from_yaml %}
      {% for i in cmdline_items %}
      - {key: {{ i.0 }}, value: {{ i.1|d('')|split(',') }} }
      {% endfor %}
      {% endfilter %}
     
    cmdline_dict: "{{ [cmdline_list, cmdline_add_list]|
                      community.general.lists_mergeby('key', list_merge='append_rp')|
                      items2dict }}"
    cmdline: >-
      {% for k,v in cmdline_dict.items() -%}
      {% if v.0|length > 0 -%}
      {{ k }}={{ v|join(',') }}
      {% else -%}
      {{ k }}
      {% endif -%}
      {% endfor -%}

  tasks:

    - command: "cat {{ cmdline_path }}"
      register: cmdline_out

    - block:
        - debug:
            var: cmdline_add_items|to_yaml
        - debug:
            var: cmdline_add_list|to_yaml
        - debug:
            var: cmdline_items|to_yaml
        - debug:
            var: cmdline_list|to_yaml
        - debug:
            var: cmdline_dict|to_yaml
        - debug:
            var: cmdline
      when: debug|d(false)|bool

    - copy:
        dest: "{{ cmdline_path }}"
        content: "{{ cmdline }}"

gives

shell> cat /tmp/cmdline.txt

cgroup_enable=cpuset,memory cgroup_memory=1 console=serial0,115200,tty1 dwc_otg.lpm_enable=0 fixrtc quiet root=LABEL=writable rootfstype=ext4 rootwait splash swapaccount=1

2
  • That's a good solution, thank you. I still don't follow why my task fails. Jul 3, 2023 at 20:26
  • Probably because the first group is greedy (.*). Try (.*?). I haven't tested your pattern. There are more problems like $1. Jul 3, 2023 at 21:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.