【问题标题】:ansible parted automate partition creation and get number and start dynamicallyansible parted 自动创建分区并获取编号并动态启动
【发布时间】:2023-02-15 16:11:14
【问题描述】:

我需要在需要添加文件系统的数百台服务器中自动创建分区。

这个想法是让 ansible 获取下一个分区的编号,并根据 parted 信息的输出开始。

---
- hosts: all
  become: true

  tasks:
    - name: get partition info
      parted:
         device: /dev/sda
         unit: GiB
      register: sda_info

    - name: create new partition
      parted:
        device: /dev/sda
        number: ???
        part_start: ???
        part_end: 3GiB
        state: present
      loop: '{{ sda_info.partitions }}

这是 sda_info 的输出

"sda_info": {
    "changed": false,
    "disk": {
        "dev": "/dev/sda",
        "logical_block": 512,
        "model": "VMware Virtual disk",
        "physical_block": 512,
        "size": 49.0,
        "table": "msdos",
        "unit": "gib"
    },
    "failed": false,
    "partitions": [
        {
            "begin": 0.0,
            "end": 0.49,
            "flags": [
                "boot"
            ],
            "fstype": "ext4",
            "name": "",
            "num": 1,
            "size": 0.49,
            "unit": "gib"
        },
        {
            "begin": 0.49,
            "end": 40.0,
            "flags": [
                "lvm"
            ],
            "fstype": "",
            "name": "",
            "num": 2,
            "size": 39.5,
            "unit": "gib"
        },
        {
            "begin": 40.0,
            "end": 46.0,
            "flags": [],
            "fstype": "",
            "name": "",
            "num": 3,
            "size": 6.0,
            "unit": "gib"
        }
    ],
    "script": "unit 'GiB' print"

我如何根据 sda_info 的输出计算数字和开始?

在手头的例子中,parted 应该是: item.num +1 = 4part_start = 46 磁盘上最后一个分区结束的地方。

每个服务器都有不同的磁盘结构,所以我需要动态获取它。

我正在考虑使用 last 作为数字,例如:

'{{ (sda_info.partitions|last).num +1 }}'
'{{ (sda_info.partitions|last).end }}'

但是如何确保 sda_info.partitions 按顺序输出并且 last 实际上是最高数字而不仅仅是字典中的最后一项并最终破坏坏分区?

sda_info.partition字典和字典在python中没有排序。

【问题讨论】:

    标签: ansible parted


    【解决方案1】:

    你只需像这样添加排序:

    - debug:
        msg: "maxnum: {{ maxnum | int + 1 }}, maxend: {{ maxend |float}}"
      vars:
        maxnum: "{{ ((sda_info.partitions|sort(attribute='num'))|last).num }}"
        maxend: "{{ ((sda_info.partitions|sort(attribute='end'))|last).end }}"
    

    如果您确定 maxnum 和 maxend 在同一条记录中:您可以简化

    - debug:
        msg: "maxnum: {{ lastsorted.num | int + 1 }}, maxend: {{ lastsorted.end |float}}"
      vars:
        lastsorted: "{{ sda_info.partitions|sort(attribute='num')|last }}"
    

    【讨论】:

      【解决方案2】:

      请参阅下面的完整剧本示例。这个想法是把剧本分成两部分。在第一个块中获取磁盘信息并将其写入控制器的文件。在第二个块中创建分区。原因是为了让代码更安全、更健壮、更灵活。

      • 第一部分是安全的。远程主机上没有任何变化。您可以在所有主机上运行一次并显示调试以检查详细信息。比如我们在4GB的闪存盘上测试
      shell> parted -l
      Model: Generic Flash Disk (scsi)
      Disk /dev/sdb: 4089MB
      Sector size (logical/physical): 512B/512B
      Partition Table: msdos
      Disk Flags: 
      
      Number  Start  End     Size    Type     File system  Flags
       1      512B   34.1MB  34.1MB  primary  fat32        esp
      

      设置变量

      disk: sdb
      part_size: 10
      unit: MB
      

      并运行剧本

      shell> ansible-playbook pb.yml -e debug=true -e get_info=true
      
      PLAY [localhost] *****************************************************************************
      
      TASK [debug] *********************************************************************************
      ok: [localhost] => 
        msg: |-
          disk: /dev/sdb
          part_unit: MB
          cache_update: False
          cache_path: /tmp/localhost-sdb-part_info.json
      
      TASK [get partition info] ********************************************************************
      ok: [localhost]
      
      TASK [debug] *********************************************************************************
      ok: [localhost] => 
        part_info:
          changed: false
          disk:
            dev: /dev/sdb
            logical_block: 512
            model: Generic Flash Disk
            physical_block: 512
            size: 4089.0
            table: msdos
            unit: mb
          failed: false
          partitions:
          - begin: 0.0
            end: 34.1
            flags:
            - esp
            fstype: fat32
            name: ''
            num: 1
            size: 34.1
            unit: mb
          script: unit 'MB' print
      
      TASK [debug] *********************************************************************************
      ok: [localhost] => 
        msg: |-
          part_size: 10
          last_number: 1
          last_end: 34.1
          next_number: 2
          next_part_start: 34.1MB
          next_part_end: 44.1MB
      
      TASK [copy] **********************************************************************************
      changed: [localhost]
      
      TASK [set_fact] ******************************************************************************
      skipping: [localhost]
      
      TASK [debug] *********************************************************************************
      skipping: [localhost]
      
      TASK [debug] *********************************************************************************
      skipping: [localhost]
      
      TASK [create new partition] ******************************************************************
      skipping: [localhost]
      
      TASK [debug] *********************************************************************************
      skipping: [localhost]
      
      PLAY RECAP ***********************************************************************************
      localhost: ok=5    changed=1    unreachable=0    failed=0    skipped=5    rescued=0    ignored=0
      

      可以看到任务复制变了.这意味着文件是写在控制器上的。看一看

      shell> cat /tmp/localhost-sdb-part_info.json 
      {"changed": false, "disk": {"dev": "/dev/sdb", "size": 4089.0, "unit": "mb", "table": "msdos", "model": "Generic Flash Disk", "logical_block": 512, "physical_block": 512}, "partitions": [{"num": 1, "begin": 0.0, "end": 34.1, "size": 34.1, "fstype": "fat32", "name": "", "flags": ["esp"], "unit": "mb"}], "script": "unit 'MB' print", "failed": false}
      

      复制参数force设置为错误的.这意味着该文件不会被替换。仅当目标不存在时才会传输文件。这就是你想让游戏幂等的原因。创建新分区后,您不想用分区信息替换缓存。但是,如果您出于某种原因想要更新缓存集 cache_update=true 并运行剧本

      shell> ansible-playbook pb.yml -e debug=true -e get_info=true -e cache_update=true
      
      • 第二部分将创建新分区。先以--check模式运行,查看调试输出
      shell> ansible-playbook pb6.yml -e debug=true -e create_part=true -C
      

      给出(删节)

      TASK [debug] *********************************************************************************
      ok: [localhost] => 
        msg: |-
          part_size: 10
          last_number: 1
          last_end: 34.1
          unit: MB
          next_number: 2
          next_part_start: 34.1MB
          next_part_end: 44.1MB
      

      这是对的。我们要创建大小为 10MB 的分区号​​ 2。让我们创造它

      shell> ansible-playbook pb.yml -e debug=true -e create_part=true
      
      PLAY [localhost] ********************************************************************************
      
      TASK [debug] ************************************************************************************
      skipping: [localhost]
      
      TASK [get partition info] ***********************************************************************
      skipping: [localhost]
      
      TASK [debug] ************************************************************************************
      skipping: [localhost]
      
      TASK [debug] ************************************************************************************
      skipping: [localhost]
      
      TASK [copy] *************************************************************************************
      skipping: [localhost]
      
      TASK [set_fact] *********************************************************************************
      ok: [localhost]
      
      TASK [debug] ************************************************************************************
      ok: [localhost] => 
        part_info:
          changed: false
          disk:
            dev: /dev/sdb
            logical_block: 512
            model: Generic Flash Disk
            physical_block: 512
            size: 4089.0
            table: msdos
            unit: mb
          failed: false
          partitions:
          - begin: 0.0
            end: 34.1
            flags:
            - esp
            fstype: fat32
            name: ''
            num: 1
            size: 34.1
            unit: mb
          script: unit 'MB' print
      
      TASK [debug] ************************************************************************************
      ok: [localhost] => 
        msg: |-
          part_size: 10
          last_number: 1
          last_end: 34.1
          unit: MB
          next_number: 2
          next_part_start: 34.1MB
          next_part_end: 44.1MB
      
      TASK [create new partition] *********************************************************************
      changed: [localhost]
      
      TASK [debug] ************************************************************************************
      ok: [localhost] => 
        result:
          changed: true
          disk:
            dev: /dev/sdb
            logical_block: 512
            model: Generic Flash Disk
            physical_block: 512
            size: 4089.0
            table: msdos
            unit: mb
          failed: false
          partitions:
          - begin: 0.0
            end: 34.1
            flags:
            - esp
            fstype: fat32
            name: ''
            num: 1
            size: 34.1
            unit: mb
          - begin: 34.1
            end: 44.1
            flags: []
            fstype: ''
            name: ''
            num: 2
            size: 10.0
            unit: mb
          script: unit MB mkpart primary 34.1MB 44.1MB
      
      PLAY RECAP **************************************************************************************
      localhost: ok=5    changed=1    unreachable=0    failed=0    skipped=5    rescued=0    ignored=0
      

      您可以看到新分区已创建。该剧本是幂等的。您可以重复运行它以确保分区存在。一切正常时,不会报告任何更改。

      shell> parted -l
      Model: Generic Flash Disk (scsi)
      Disk /dev/sdb: 4089MB
      Sector size (logical/physical): 512B/512B
      Partition Table: msdos
      Disk Flags: 
      
      Number  Start   End     Size    Type     File system  Flags
       1      512B    34.1MB  34.1MB  primary  fat32        esp
       2      34.1MB  44.1MB  10.0MB  primary
      
      • 当您第一次在大量远程主机上运行第二部分时,将远程主机分成较小的组可能是个好主意。创建分区后,您可以将其全部运行一次以进行审计。

      完整剧本的示例

      ---
      # All rights reserved (c) 2022, Vladimir Botka <vbotka@gmail.com>
      # Simplified BSD License, https://opensource.org/licenses/BSD-2-Clause
      
      - hosts: localhost
        gather_facts: false
        become: true
      
        vars:
      
          disk: sda          # change this
          part_size: 3       # change this
          unit: GiB          # change this
          cache_update: false
          cache_path: "/tmp/{{ inventory_hostname }}-{{ disk }}-part_info.json"
          # next variables are calculated from part_info
          last_number: "{{ part_info.partitions|map(attribute='num')|max }}"
          last_end: "{{ part_info.partitions|map(attribute='end')|max }}"
          next_number: "{{ last_number|int + 1 }}"
          next_part_start: "{{ last_end }}{{ unit }}"
          next_part_end: "{{ last_end|float + part_size|float }}{{ unit }}"
      
        tasks:
      
          - name: Get info and write part_info to cache_path
            block:
              - debug:
                  msg: |-
                    disk: /dev/{{ disk }}
                    unit: {{ unit }}
                    cache_update: {{ cache_update }}
                    cache_path: {{ cache_path }}
                when: debug|d(false)|bool
              - name: get partition info
                parted:
                   device: "/dev/{{ disk }}"
                   unit: "{{ unit }}"
                register: part_info
              - debug:
                  var: part_info
                when: debug|d(false)|bool
              - debug:
                  msg: |-
                    part_size: {{ part_size }}
                    last_number: {{ last_number }}
                    last_end: {{ last_end }}
                    next_number: {{ next_number }}
                    next_part_start: {{ next_part_start }}
                    next_part_end: {{ next_part_end }}
                when: debug|d(false)|bool
              - copy:
                  dest: "{{ cache_path }}"
                  force: "{{ cache_update|bool }}"
                  content: |
                    {{ part_info|to_json }}
                delegate_to: localhost
            when: get_info|d(false)|bool
      
          - name: Read part_info from cache_path and create partition
            block:
              - set_fact:
                  part_info: "{{ lookup('file', cache_path)|from_yaml }}"
              - debug:
                  var: part_info
                when: debug|d(false)|bool
              - debug:
                  msg: |-
                    part_size: {{ part_size }}
                    last_number: {{ last_number }}
                    last_end: {{ last_end }}
                    unit: {{ unit }}
                    next_number: {{ next_number }}
                    next_part_start: {{ next_part_start }}
                    next_part_end: {{ next_part_end }}
                when: debug|d(false)|bool
              - name: create new partition
                parted:
                  device: "/dev/{{ disk }}"
                  number: "{{ next_number }}"
                  part_start: "{{ next_part_start }}"
                  part_end: "{{ next_part_end }}"
                  align: optimal
                  unit: "{{ unit }}"
                  state: present
                register: result
              - debug:
                  var: result
                when: debug|d(false)|bool
            when: create_part|d(false)|bool
      

      【讨论】:

      • 你能解释一下这是做什么的吗?为什么要创建缓存?什么是布尔值 when 子句应该起作用。看起来很整洁,但我需要理解谢谢
      • 我添加了cmets。 HTH。
      【解决方案3】:

      这是我与unit: s(扇区为整数)一起使用的简单剧本,以避免由于浮动而导致的一些错误:

      - name: get partition info
        community.general.parted:
          device: /dev/sda
          unit: s
        register: sda_info
      - name: create new partition
        community.general.parted:
          device: /dev/sda
          label: gpt
          number: "{{ lastsorted.num | int + 1 }}"
          part_start: "{{ lastsorted.end | int + 1}}s"
          part_end: "100%"
          state: present
        vars:
          lastsorted: "{{ sda_info.partitions|sort(attribute='num')|last }}"
      

      它使用所有可用空间在磁盘末端创建一个新分区。

      【讨论】:

      • 使用浮动,引发的错误是The argument 'part_start' doesn't respect required format.The size unit is case sensitive.
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-14
      • 1970-01-01
      相关资源
      最近更新 更多