从 VBoxManage 输出解析以冒号分隔的表格数据

Parsing colon delimited tabular data from VBoxManage output

我正在编写一些包装 VirtualBox 的 ansible 剧本 VBoxManage cli。返回的数据采用冒号分隔的表格格式,但我希望它采用类似 JSON/YAML 的格式以便更好地解析。

例如,我想获取以下命令的输出:

$ VBoxManage list hostonlyifs -l   
                                                                               Name:            VirtualBox Host-Only Ethernet Adapter #2
GUID:            355aa3ae-0a32-49e6-8532-4d18fd9baea2
DHCP:            Disabled
IPAddress:       10.0.10.10
NetworkMask:     255.255.255.0
IPV6Address:     fe80::acc9:a7bd:d178:b911
IPV6NetworkMaskPrefixLength: 64
HardwareAddress: 0a:00:27:00:00:3b
MediumType:      Ethernet
Wireless:        No
Status:          Up
VBoxNetworkName: HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter #2

Name:            VirtualBox Host-Only Ethernet Adapter
GUID:            405a4779-a6f3-47d9-bf83-6a2503a093f2
DHCP:            Disabled
IPAddress:       192.168.56.1
NetworkMask:     255.255.255.0
IPV6Address:     fe80::ede5:3927:714c:3958
IPV6NetworkMaskPrefixLength: 64
HardwareAddress: 0a:00:27:00:00:06
MediumType:      Ethernet
Wireless:        No
Status:          Up
VBoxNetworkName: HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter

并引用 HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter #2 接口的 IP 地址。

接近我正在寻找的示例 ansible 任务:

#!/usr/bin/env ansible-playbook
- hosts: localhost
  become: false
  gather_facts: false
  vars_files:
  - vars/main.yml
  tasks:
  - name: List all host-only interfaces
    shell: "VBoxManage list hostonlyifs 
            | <magic>"
    changed_when: false
    register: vbox_hostonlyifs

  - name: Use information from the previous command somehow
    shell: "VBoxManage hostonlyif ipconfig 
            '{{ vbox_hostonlyifs.stdout | <magic> }}' 
            --ip 10.0.10.0"

我在想 sed/regex 的组合也许可以解决问题。

我有一个正则表达式,可以从所有块中捕获键和值,而不是块本身。

(^[a-zA-Z0-9]+:)(?:[ \t]+)(.*)$

你可以利用输出是 almost yaml 的事实,稍微修改一下就可以把它变成一个列表:

tasks:
- shell: VBoxManage list hostonlyifs | sed -e 's/^/  /; s/^  Name:/- Name:/'
  register: vblist
- set_fact:
    vbox_interfaces: '{{ vblist.stdout | from_yaml }}'

通过在 Name: 键前加上 - Name: 将它们变成列表项,然后唯一的其他要求是缩进其余键以匹配与 [= 相同的缩进13=] 将它们变成对象

我有充分的理由相信你可以使用纯 jinja2 而不是使用 sed =]

运行 本地生产:

ok: [localhost] => {
    "vbox_interfaces": [
        {
            "DHCP": "Disabled",
            "GUID": "786f6276-656e-4074-8000-0a0027000000",
            "HardwareAddress": "0a:00:27:00:00:00",
            "Status": "Down",
...etc etc
            "VBoxNetworkName": "HostInterfaceNetworking-vboxnet0",
            "Wireless": false
        },
        {
            "DHCP": "Disabled",
            "GUID": "786f6276-656e-4374-8000-0a0027000003",
            "HardwareAddress": "0a:00:27:00:00:03",
...etc etc
        }
    ]
}

相同,但对于 Windows(我的 extpack 示例):

- name: Get facts about Extension Pack 4 Windows
  when:
    - ansible_os_family == 'Windows'
  become: yes
  become_method: runas
  become_flags: logon_type=new_credentials logon_flags=netcredentials_only
  win_shell: |
    $for_yaml = VBoxManage list extpacks
    $for_yaml -replace '^', '  ' -replace '  Extension', '- Extension'
  register: vboxmanage_list_extpacks_windows

- set_fact:
    virtualbox_installed_extpack_info_fact:
      "{{ vboxmanage_list_extpacks_windows.stdout
      | from_yaml
      | first }}"

结果:

{
  "virtualbox_installed_extpack_info_fact": {
    "Description": "Oracle Cloud Infrastructure integration, USB 2.0 and USB 3.0 Host Controller, Host Webcam, VirtualBox RDP, PXE ROM, Disk Encryption, NVMe.",
    "Edition": null,
    "Extension Packs": 1,
    "Pack no. 0": "Oracle VM VirtualBox Extension Pack",
    "Revision": 149290,
    "Usable": true,
    "VRDE Module": "VBoxVRDP",
    "Version": "6.1.32",
    "Why unusable": null
  }
}