From 4dda895f122ecc19b267ed1485cf656bae76ff07 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 24 Feb 2022 11:25:14 -0800 Subject: [PATCH] initial nmcli parser --- jc/lib.py | 1 + jc/parsers/nmcli.py | 130 +++++++++++++++++ .../centos-7.7/nmcli-connection-all.out | 3 + .../nmcli-connection-show-ens33.out | 136 ++++++++++++++++++ .../fixtures/centos-7.7/nmcli-connection.out | 3 + .../fixtures/centos-7.7/nmcli-device-all.out | 5 + .../centos-7.7/nmcli-device-show-ens33.out | 18 +++ .../centos-7.7/nmcli-device-show-lo.out | 12 ++ .../fixtures/centos-7.7/nmcli-device-show.out | 42 ++++++ tests/fixtures/centos-7.7/nmcli-device.out | 4 + .../fixtures/centos-7.7/nmcli-general-all.out | 3 + .../centos-7.7/nmcli-general-permissions.out | 18 +++ tests/fixtures/centos-7.7/nmcli.out | 29 ++++ 13 files changed, 404 insertions(+) create mode 100644 jc/parsers/nmcli.py create mode 100644 tests/fixtures/centos-7.7/nmcli-connection-all.out create mode 100644 tests/fixtures/centos-7.7/nmcli-connection-show-ens33.out create mode 100644 tests/fixtures/centos-7.7/nmcli-connection.out create mode 100644 tests/fixtures/centos-7.7/nmcli-device-all.out create mode 100644 tests/fixtures/centos-7.7/nmcli-device-show-ens33.out create mode 100644 tests/fixtures/centos-7.7/nmcli-device-show-lo.out create mode 100644 tests/fixtures/centos-7.7/nmcli-device-show.out create mode 100644 tests/fixtures/centos-7.7/nmcli-device.out create mode 100644 tests/fixtures/centos-7.7/nmcli-general-all.out create mode 100644 tests/fixtures/centos-7.7/nmcli-general-permissions.out create mode 100644 tests/fixtures/centos-7.7/nmcli.out diff --git a/jc/lib.py b/jc/lib.py index bbf3a43b..6fe8311e 100644 --- a/jc/lib.py +++ b/jc/lib.py @@ -60,6 +60,7 @@ parsers = [ 'lsusb', 'mount', 'netstat', + 'nmcli', 'ntpq', 'passwd', 'ping', diff --git a/jc/parsers/nmcli.py b/jc/parsers/nmcli.py new file mode 100644 index 00000000..504b6d43 --- /dev/null +++ b/jc/parsers/nmcli.py @@ -0,0 +1,130 @@ +"""jc - JSON CLI output utility `nmcli` command output parser + +<> + +Usage (cli): + + $ nmcli | jc --nmcli + + or + + $ jc nmcli + +Usage (module): + + import jc + result = jc.parse('nmcli', nmcli_command_output) + + or + + import jc.parsers.nmcli + result = jc.parsers.nmcli.parse(nmcli_command_output) + +Schema: + + [ + { + "nmcli": string, + "bar": boolean, + "baz": integer + } + ] + +Examples: + + $ nmcli | jc --nmcli -p + [] + + $ nmcli | jc --nmcli -p -r + [] +""" +from typing import List, Dict +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`nmcli` command parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + magic_commands = ['nmcli'] + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + + # process the data here + # rebuild output for added semantic information + # use helper functions in jc.utils for int, float, bool + # conversions and timestamps + + return proc_data + +def _normalize_key(keyname: str) -> str: + return keyname.replace(' ', '_')\ + .replace('.', '_')\ + .replace('[', '_')\ + .replace(']', '')\ + .replace('-', '_')\ + .replace('GENERAL_', '')\ + .lower() + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + item: Dict = {} + current_item = '' + + if jc.utils.has_data(data): + + for line in filter(None, data.splitlines()): + key, value = line.split(':', maxsplit=1) + key = _normalize_key(key) + value = value.strip() + + if item and 'device' in key and value != current_item: + raw_output.append(item) + item = {} + current_item = value + + item.update({key: value}) + + if item: + raw_output.append(item) + + return raw_output if raw else _process(raw_output) diff --git a/tests/fixtures/centos-7.7/nmcli-connection-all.out b/tests/fixtures/centos-7.7/nmcli-connection-all.out new file mode 100644 index 00000000..e2b771e0 --- /dev/null +++ b/tests/fixtures/centos-7.7/nmcli-connection-all.out @@ -0,0 +1,3 @@ +NAME UUID TYPE TIMESTAMP TIMESTAMP-REAL AUTOCONNECT AUTOCONNECT-PRIORITY READONLY DBUS-PATH ACTIVE DEVICE STATE ACTIVE-PATH SLAVE FILENAME +ens33 d92ece08-9e02-47d5-b2d2-92c80e155744 ethernet 1645643581 Wed 23 Feb 2022 11:13:01 AM PST yes 0 no /org/freedesktop/NetworkManager/Settings/1 yes ens33 activated /org/freedesktop/NetworkManager/ActiveConnection/1 -- /etc/sysconfig/network-scripts/ifcfg-ens33 + diff --git a/tests/fixtures/centos-7.7/nmcli-connection-show-ens33.out b/tests/fixtures/centos-7.7/nmcli-connection-show-ens33.out new file mode 100644 index 00000000..868e8c0f --- /dev/null +++ b/tests/fixtures/centos-7.7/nmcli-connection-show-ens33.out @@ -0,0 +1,136 @@ +connection.id: ens33 +connection.uuid: d92ece08-9e02-47d5-b2d2-92c80e155744 +connection.stable-id: -- +connection.type: 802-3-ethernet +connection.interface-name: ens33 +connection.autoconnect: yes +connection.autoconnect-priority: 0 +connection.autoconnect-retries: -1 (default) +connection.multi-connect: 0 (default) +connection.auth-retries: -1 +connection.timestamp: 1645570618 +connection.read-only: no +connection.permissions: -- +connection.zone: -- +connection.master: -- +connection.slave-type: -- +connection.autoconnect-slaves: -1 (default) +connection.secondaries: -- +connection.gateway-ping-timeout: 0 +connection.metered: unknown +connection.lldp: default +connection.mdns: -1 (default) +connection.llmnr: -1 (default) +802-3-ethernet.port: -- +802-3-ethernet.speed: 0 +802-3-ethernet.duplex: -- +802-3-ethernet.auto-negotiate: no +802-3-ethernet.mac-address: -- +802-3-ethernet.cloned-mac-address: -- +802-3-ethernet.generate-mac-address-mask:-- +802-3-ethernet.mac-address-blacklist: -- +802-3-ethernet.mtu: auto +802-3-ethernet.s390-subchannels: -- +802-3-ethernet.s390-nettype: -- +802-3-ethernet.s390-options: -- +802-3-ethernet.wake-on-lan: default +802-3-ethernet.wake-on-lan-password: -- +ipv4.method: auto +ipv4.dns: -- +ipv4.dns-search: -- +ipv4.dns-options: "" +ipv4.dns-priority: 0 +ipv4.addresses: -- +ipv4.gateway: -- +ipv4.routes: -- +ipv4.route-metric: -1 +ipv4.route-table: 0 (unspec) +ipv4.routing-rules: -- +ipv4.ignore-auto-routes: no +ipv4.ignore-auto-dns: no +ipv4.dhcp-client-id: -- +ipv4.dhcp-timeout: 0 (default) +ipv4.dhcp-send-hostname: yes +ipv4.dhcp-hostname: -- +ipv4.dhcp-fqdn: -- +ipv4.never-default: no +ipv4.may-fail: yes +ipv4.dad-timeout: -1 (default) +ipv6.method: auto +ipv6.dns: -- +ipv6.dns-search: -- +ipv6.dns-options: "" +ipv6.dns-priority: 0 +ipv6.addresses: -- +ipv6.gateway: -- +ipv6.routes: -- +ipv6.route-metric: -1 +ipv6.route-table: 0 (unspec) +ipv6.routing-rules: -- +ipv6.ignore-auto-routes: no +ipv6.ignore-auto-dns: no +ipv6.never-default: no +ipv6.may-fail: yes +ipv6.ip6-privacy: -1 (unknown) +ipv6.addr-gen-mode: stable-privacy +ipv6.dhcp-duid: -- +ipv6.dhcp-send-hostname: yes +ipv6.dhcp-hostname: -- +ipv6.token: -- +proxy.method: none +proxy.browser-only: no +proxy.pac-url: -- +proxy.pac-script: -- +GENERAL.NAME: ens33 +GENERAL.UUID: d92ece08-9e02-47d5-b2d2-92c80e155744 +GENERAL.DEVICES: ens33 +GENERAL.STATE: activated +GENERAL.DEFAULT: yes +GENERAL.DEFAULT6: no +GENERAL.SPEC-OBJECT: -- +GENERAL.VPN: no +GENERAL.DBUS-PATH: /org/freedesktop/NetworkManager/ActiveConnection/1 +GENERAL.CON-PATH: /org/freedesktop/NetworkManager/Settings/1 +GENERAL.ZONE: -- +GENERAL.MASTER-PATH: -- +IP4.ADDRESS[1]: 192.168.71.180/24 +IP4.GATEWAY: 192.168.71.2 +IP4.ROUTE[1]: dst = 0.0.0.0/0, nh = 192.168.71.2, mt = 100 +IP4.ROUTE[2]: dst = 192.168.71.0/24, nh = 0.0.0.0, mt = 100 +IP4.DNS[1]: 192.168.71.2 +IP4.DOMAIN[1]: localdomain +DHCP4.OPTION[1]: broadcast_address = 192.168.71.255 +DHCP4.OPTION[2]: dhcp_lease_time = 1800 +DHCP4.OPTION[3]: dhcp_message_type = 5 +DHCP4.OPTION[4]: dhcp_server_identifier = 192.168.71.254 +DHCP4.OPTION[5]: domain_name = localdomain +DHCP4.OPTION[6]: domain_name_servers = 192.168.71.2 +DHCP4.OPTION[7]: expiry = 1645572241 +DHCP4.OPTION[8]: ip_address = 192.168.71.180 +DHCP4.OPTION[9]: network_number = 192.168.71.0 +DHCP4.OPTION[10]: next_server = 192.168.71.254 +DHCP4.OPTION[11]: requested_broadcast_address = 1 +DHCP4.OPTION[12]: requested_classless_static_routes = 1 +DHCP4.OPTION[13]: requested_domain_name = 1 +DHCP4.OPTION[14]: requested_domain_name_servers = 1 +DHCP4.OPTION[15]: requested_domain_search = 1 +DHCP4.OPTION[16]: requested_host_name = 1 +DHCP4.OPTION[17]: requested_interface_mtu = 1 +DHCP4.OPTION[18]: requested_ms_classless_static_routes = 1 +DHCP4.OPTION[19]: requested_nis_domain = 1 +DHCP4.OPTION[20]: requested_nis_servers = 1 +DHCP4.OPTION[21]: requested_ntp_servers = 1 +DHCP4.OPTION[22]: requested_rfc3442_classless_static_routes = 1 +DHCP4.OPTION[23]: requested_root_path = 1 +DHCP4.OPTION[24]: requested_routers = 1 +DHCP4.OPTION[25]: requested_static_routes = 1 +DHCP4.OPTION[26]: requested_subnet_mask = 1 +DHCP4.OPTION[27]: requested_time_offset = 1 +DHCP4.OPTION[28]: requested_wpad = 1 +DHCP4.OPTION[29]: routers = 192.168.71.2 +DHCP4.OPTION[30]: subnet_mask = 255.255.255.0 +IP6.ADDRESS[1]: fe80::c1cb:715d:bc3e:b8a0/64 +IP6.GATEWAY: -- +IP6.ROUTE[1]: dst = fe80::/64, nh = ::, mt = 100 +IP6.ROUTE[2]: dst = ff00::/8, nh = ::, mt = 256, table=255 + diff --git a/tests/fixtures/centos-7.7/nmcli-connection.out b/tests/fixtures/centos-7.7/nmcli-connection.out new file mode 100644 index 00000000..c1b5bf7c --- /dev/null +++ b/tests/fixtures/centos-7.7/nmcli-connection.out @@ -0,0 +1,3 @@ +NAME UUID TYPE DEVICE +ens33 d92ece08-9e02-47d5-b2d2-92c80e155744 ethernet ens33 + diff --git a/tests/fixtures/centos-7.7/nmcli-device-all.out b/tests/fixtures/centos-7.7/nmcli-device-all.out new file mode 100644 index 00000000..2884f28f --- /dev/null +++ b/tests/fixtures/centos-7.7/nmcli-device-all.out @@ -0,0 +1,5 @@ +DEVICE TYPE STATE IP4-CONNECTIVITY IP6-CONNECTIVITY DBUS-PATH CONNECTION CON-UUID CON-PATH +ens33 ethernet connected full full /org/freedesktop/NetworkManager/Devices/2 ens33 d92ece08-9e02-47d5-b2d2-92c80e155744 /org/freedesktop/NetworkManager/ActiveConnection/1 +docker0 bridge unmanaged unknown unknown /org/freedesktop/NetworkManager/Devices/3 -- -- -- +lo loopback unmanaged unknown unknown /org/freedesktop/NetworkManager/Devices/1 -- -- -- + diff --git a/tests/fixtures/centos-7.7/nmcli-device-show-ens33.out b/tests/fixtures/centos-7.7/nmcli-device-show-ens33.out new file mode 100644 index 00000000..9ded86e8 --- /dev/null +++ b/tests/fixtures/centos-7.7/nmcli-device-show-ens33.out @@ -0,0 +1,18 @@ +GENERAL.DEVICE: ens33 +GENERAL.TYPE: ethernet +GENERAL.HWADDR: 00:0C:29:3B:58:0E +GENERAL.MTU: 1500 +GENERAL.STATE: 100 (connected) +GENERAL.CONNECTION: ens33 +GENERAL.CON-PATH: /org/freedesktop/NetworkManager/ActiveConnection/1 +WIRED-PROPERTIES.CARRIER: on +IP4.ADDRESS[1]: 192.168.71.180/24 +IP4.GATEWAY: 192.168.71.2 +IP4.ROUTE[1]: dst = 0.0.0.0/0, nh = 192.168.71.2, mt = 100 +IP4.ROUTE[2]: dst = 192.168.71.0/24, nh = 0.0.0.0, mt = 100 +IP4.DNS[1]: 192.168.71.2 +IP4.DOMAIN[1]: localdomain +IP6.ADDRESS[1]: fe80::c1cb:715d:bc3e:b8a0/64 +IP6.GATEWAY: -- +IP6.ROUTE[1]: dst = fe80::/64, nh = ::, mt = 100 +IP6.ROUTE[2]: dst = ff00::/8, nh = ::, mt = 256, table=255 diff --git a/tests/fixtures/centos-7.7/nmcli-device-show-lo.out b/tests/fixtures/centos-7.7/nmcli-device-show-lo.out new file mode 100644 index 00000000..4214f760 --- /dev/null +++ b/tests/fixtures/centos-7.7/nmcli-device-show-lo.out @@ -0,0 +1,12 @@ +GENERAL.DEVICE: lo +GENERAL.TYPE: loopback +GENERAL.HWADDR: 00:00:00:00:00:00 +GENERAL.MTU: 65536 +GENERAL.STATE: 10 (unmanaged) +GENERAL.CONNECTION: -- +GENERAL.CON-PATH: -- +IP4.ADDRESS[1]: 127.0.0.1/8 +IP4.GATEWAY: -- +IP6.ADDRESS[1]: ::1/128 +IP6.GATEWAY: -- + diff --git a/tests/fixtures/centos-7.7/nmcli-device-show.out b/tests/fixtures/centos-7.7/nmcli-device-show.out new file mode 100644 index 00000000..8aec04bd --- /dev/null +++ b/tests/fixtures/centos-7.7/nmcli-device-show.out @@ -0,0 +1,42 @@ +GENERAL.DEVICE: ens33 +GENERAL.TYPE: ethernet +GENERAL.HWADDR: 00:0C:29:3B:58:0E +GENERAL.MTU: 1500 +GENERAL.STATE: 100 (connected) +GENERAL.CONNECTION: ens33 +GENERAL.CON-PATH: /org/freedesktop/NetworkManager/ActiveConnection/1 +WIRED-PROPERTIES.CARRIER: on +IP4.ADDRESS[1]: 192.168.71.180/24 +IP4.GATEWAY: 192.168.71.2 +IP4.ROUTE[1]: dst = 0.0.0.0/0, nh = 192.168.71.2, mt = 100 +IP4.ROUTE[2]: dst = 192.168.71.0/24, nh = 0.0.0.0, mt = 100 +IP4.DNS[1]: 192.168.71.2 +IP4.DOMAIN[1]: localdomain +IP6.ADDRESS[1]: fe80::c1cb:715d:bc3e:b8a0/64 +IP6.GATEWAY: -- +IP6.ROUTE[1]: dst = fe80::/64, nh = ::, mt = 100 +IP6.ROUTE[2]: dst = ff00::/8, nh = ::, mt = 256, table=255 + +GENERAL.DEVICE: docker0 +GENERAL.TYPE: bridge +GENERAL.HWADDR: 02:42:99:67:E8:21 +GENERAL.MTU: 1500 +GENERAL.STATE: 10 (unmanaged) +GENERAL.CONNECTION: -- +GENERAL.CON-PATH: -- +IP4.ADDRESS[1]: 172.17.0.1/16 +IP4.GATEWAY: -- +IP4.ROUTE[1]: dst = 172.17.0.0/16, nh = 0.0.0.0, mt = 0 +IP6.GATEWAY: -- + +GENERAL.DEVICE: lo +GENERAL.TYPE: loopback +GENERAL.HWADDR: 00:00:00:00:00:00 +GENERAL.MTU: 65536 +GENERAL.STATE: 10 (unmanaged) +GENERAL.CONNECTION: -- +GENERAL.CON-PATH: -- +IP4.ADDRESS[1]: 127.0.0.1/8 +IP4.GATEWAY: -- +IP6.ADDRESS[1]: ::1/128 +IP6.GATEWAY: -- diff --git a/tests/fixtures/centos-7.7/nmcli-device.out b/tests/fixtures/centos-7.7/nmcli-device.out new file mode 100644 index 00000000..b5e73778 --- /dev/null +++ b/tests/fixtures/centos-7.7/nmcli-device.out @@ -0,0 +1,4 @@ +DEVICE TYPE STATE CONNECTION +ens33 ethernet connected ens33 +docker0 bridge unmanaged -- +lo loopback unmanaged -- diff --git a/tests/fixtures/centos-7.7/nmcli-general-all.out b/tests/fixtures/centos-7.7/nmcli-general-all.out new file mode 100644 index 00000000..18cac50b --- /dev/null +++ b/tests/fixtures/centos-7.7/nmcli-general-all.out @@ -0,0 +1,3 @@ +RUNNING VERSION STATE STARTUP CONNECTIVITY NETWORKING WIFI-HW WIFI WWAN-HW WWAN +running 1.18.0 connected started full enabled enabled enabled enabled enabled + diff --git a/tests/fixtures/centos-7.7/nmcli-general-permissions.out b/tests/fixtures/centos-7.7/nmcli-general-permissions.out new file mode 100644 index 00000000..c1e94e0b --- /dev/null +++ b/tests/fixtures/centos-7.7/nmcli-general-permissions.out @@ -0,0 +1,18 @@ +PERMISSION VALUE +org.freedesktop.NetworkManager.enable-disable-network yes +org.freedesktop.NetworkManager.enable-disable-wifi yes +org.freedesktop.NetworkManager.enable-disable-wwan yes +org.freedesktop.NetworkManager.enable-disable-wimax yes +org.freedesktop.NetworkManager.sleep-wake yes +org.freedesktop.NetworkManager.network-control yes +org.freedesktop.NetworkManager.wifi.share.protected yes +org.freedesktop.NetworkManager.wifi.share.open yes +org.freedesktop.NetworkManager.settings.modify.system yes +org.freedesktop.NetworkManager.settings.modify.own yes +org.freedesktop.NetworkManager.settings.modify.hostname yes +org.freedesktop.NetworkManager.settings.modify.global-dns yes +org.freedesktop.NetworkManager.reload yes +org.freedesktop.NetworkManager.checkpoint-rollback yes +org.freedesktop.NetworkManager.enable-disable-statistics yes +org.freedesktop.NetworkManager.enable-disable-connectivity-check yes +org.freedesktop.NetworkManager.wifi.scan unknown diff --git a/tests/fixtures/centos-7.7/nmcli.out b/tests/fixtures/centos-7.7/nmcli.out new file mode 100644 index 00000000..1ac1c16b --- /dev/null +++ b/tests/fixtures/centos-7.7/nmcli.out @@ -0,0 +1,29 @@ +ens33: connected to ens33 + "Intel 82545EM" + ethernet (e1000), 00:0C:29:3B:58:0E, hw, mtu 1500 + ip4 default + inet4 192.168.71.181/24 + route4 0.0.0.0/0 + route4 192.168.71.0/24 + inet6 fe80::c1cb:715d:bc3e:b8a0/64 + route6 fe80::/64 + route6 ff00::/8 + +docker0: unmanaged + "docker0" + bridge, 02:42:76:3F:0D:C3, sw, mtu 1500 + +lo: unmanaged + "lo" + loopback (unknown), 00:00:00:00:00:00, sw, mtu 65536 + +DNS configuration: + servers: 192.168.71.2 + domains: localdomain + interface: ens33 + +Use "nmcli device show" to get complete information about known devices and +"nmcli connection show" to get an overview on active connection profiles. + +Consult nmcli(1) and nmcli-examples(7) manual pages for complete usage details. +