【问题标题】:Ansible: Modify cmdline.txt on Raspberry PiAnsible:在树莓派上修改 cmdline.txt
【发布时间】:2020-05-23 13:33:11
【问题描述】:

我正在修改 /boot/cmdline.txt 以将容器功能添加到 Raspberry Pi,因此我需要将 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory 添加到文件中,在同一行内。

我正在尝试使用 lineinfile 模块来做这件事,但没有取得多大成功:

- hosts: mypi
  become: yes
  tasks:
  - name: Enable container features
    lineinfile:
      path: /boot/cmdline.txt
      regex: " cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory"
      line: " cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory"
      insertafter: EOF
      state: present

我一直在尝试将insertafter 修改为 BOF,也使用insertbefore,使用正则表达式来匹配最后一个单词......但它最终添加了一个回车。我一直找不到不添加新行的方法。

【问题讨论】:

  • 我不太明白。您想将这三个值添加到文件第一行的开头吗?
  • 我不介意。如果您检查 /boot/cmdline.txt 它只是在同一行中包含键值对,所以我不介意它们是在最后还是在开头。唯一的要求是它们应该是空白的。这是我的 Pi 示例:console=serial0,115200 console=tty1 root=PARTUUID=ea7d04d6-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
  • 文件中只有一行?

标签: ansible


【解决方案1】:

由于文件中只有一行,因此您可以使用replacelineinfile 来执行此操作。这是replace 版本:

  - name: Enable container features
    replace:
      path: cmdline.txt
      regexp: '^([\w](?!.*\b{{ item }}\b).*)$'
      replace: '\1 {{ item }}'
    with_items:
    - "cgroup_enable=cpuset"
    - "cgroup_memory=1"
    - "cgroup_enable=memory"

here偷了答案

【讨论】:

  • 好程序员写好代码,好程序员偷好代码!
【解决方案2】:

正如弗拉基米尔指出的那样,不幸的是,杰克的回答对于空文件来说是不够的,如果所需的参数已经存在于行首,也会失败。 以下建议的解决方案应解决这些问题。特别是应该

  • 支持空文件,
  • 支持字符串中任意位置的现有参数,
  • 即使是多行文件也很健壮(以防万一...),
  • 是幂等的,并且
  • 可选择使用所需值更新现有键。
# cmdline.yml

- name: read cmdline.txt
  become: true
  slurp: "src={{ cmdline_txt_path }}"
  register: result_cmdline

- name: generate regular expression for existing arguments
  set_fact:
    regex_existing: '{{ "\b" + key|string + "=" + ("[\w]*" if update else value|string) + "\b" }}'
    key_value_pair: '{{ key|string + "=" + value|string }}'

- name: generate regular expression for new arguments
  set_fact:
    regex_add_missing: '{{ "^((?!(?:.|\n)*" + regex_existing + ")((?:.|\n)*))$" }}'

- name: update cmdline.txt
  become: true
  copy:
    content: '{{ result_cmdline.content
        | b64decode
        | regex_replace(regex_existing, key_value_pair)
        | regex_replace(regex_add_missing, key_value_pair + " \1")
      }}'
    dest: "{{ cmdline_txt_path }}"

用法:

- set_fact:
    cmdline_txt_path: /boot/cmdline.txt

- include_tasks: cmdline.yml
  vars:
    key: cgroup_enable
    value: memory
    update: false
    # will add the argument if the key-value-pair doesn't exist

- include_tasks: cmdline.yml
  vars:
    key: cgroup_enable
    value: cpu
    update: false

- include_tasks: cmdline.yml
  vars:
    key: cgroup_memory
    value: 1
    update: true
    # will replace the value of the first matching key, if found;
    # will add it if it's not found

但是,我可能遗漏了一些边缘情况 - 如果您发现任何问题,请告诉我。

【讨论】:

  • 这非常有效。需要指出的一件事,因为它非常短暂地让我意识到,两个 cgroup_enable 的 必须update: false 否则它们会相互覆盖(这不仅仅是为了证明它可以是假的??‍♂️?)。
【解决方案3】:

问:“Ansible lineinfile 模块:不要添加新行。想办法不添加新行。”

答:不可能。新行将始终由模块 lineinfile 添加。以source 为例

b_lines.insert(index[1], b_line + b_linesep)

这就是添加新行的方式。此类添加将以b_linesep 终止。看看变量是怎么defined

b_linesep = to_bytes(os.linesep, errors='surrogate_or_strict')

当您想要遍历文本文件的行时使用 os.linesep。内部扫描器识别 os.linesep 并将其替换为单个“\n”。

What is os.linesep for?


模块replace 的任务也不能解决这个问题。它既不会创建没有换行符的行,也不会以这种方式修改现有的行。除此之外,它不是幂等的。
  - name: Enable container features
    replace:
      path: cmdline.txt
      regexp: '^([\w](?!.*\b{{ item }}\b).*)$'
      replace: '\1 {{ item }}'
    loop:
      - "cgroup_enable=cpuset"
      - "cgroup_memory=1"
      - "cgroup_enable=memory"

如果文件为空,它什么也不做

TASK [Enable container features]
ok: [localhost] => (item=cgroup_enable=cpuset)
ok: [localhost] => (item=cgroup_memory=1)
ok: [localhost] => (item=cgroup_enable=memory)

如果文件中存在该行,则此任务将更改它

shell> cat cmdline.txt 
cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory
ASK [Enable container features] *****************************************
ok: [localhost] => (item=cgroup_enable=cpuset)
--- before: cmdline.txt
+++ after: cmdline.txt
@@ -1 +1 @@
-cgroup_memory=1 cgroup_enable=memory cgroup_enable=cpuset
+cgroup_memory=1 cgroup_enable=memory cgroup_enable=cpuset cgroup_memory=1

【讨论】:

    【解决方案4】:

    我遵循了上面列出的所有不同策略,但最后,我想要一些简单的东西,因为这是我的第一本剧本,我现在需要理解它,等我以后再拿起它时,。

    我的 cmdline.txt 包含多行:

    cat /boot/cmdline.txt -E 
    console=serial0,115200 console=tty1 rootfstype=ext4 fsck.repair=yes rootwait cgroup_enable=memory cgroup_enable=cpuset cgroup_memory=1$
    dtoverlay=pi3-disable-bt$ 
    dtoverlay=pi3-disable-wifi$
    

    所以,我正在寻找的方法:

    • 将忽略 cmdline.txt 中的其他配置
    • 只有在缺少特定键=值时才添加添加
    • 它必须是幂等的

    我选择了一个简单的正则表达式来决定这是否是我要编辑的行:

    • 如果该行包含 console=(因为这是我要查找的行)
    • AND.. 如果该行不包含 cgroup_memory=1
    
    - name: Adding cgroup_enable=memory to boot parameters for k3s
      lineinfile:
        path: /boot/cmdline.txt
        state: present
        regexp: '^((?!.*cgroup_enable=memory).*console.*)$'
        line: '\1 cgroup_enable=memory'
        backrefs: yes
      notify: reboot
    
    - name: Adding cgroup_enable=cpuset to boot parameters for K3s
      lineinfile:
        path: /boot/cmdline.txt
        state: present
        regexp: '^((?!.*cgroup_enable=cpuset).*console.*)$'
        line: '\1 cgroup_enable=cpuset'
        backrefs: yes
      notify: reboot
    
    - name: Adding cgroup_memory=1 to boot parameters for K3s
      lineinfile:
        path: /boot/cmdline.txt
        state: present
        regexp: '^((?!.*cgroup_memory=1).*console.*)$'
        line: '\1 cgroup_memory=1'
        backrefs: yes
      notify: reboot
    
    

    在未来的某个时候,我可能会将所有这三个都浓缩为一个循环任务。但不是今天。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-04
      • 2014-01-18
      • 2015-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多