Closed ThomasADavis closed 1 year ago
This is what you get when you use just curl against it.
[tdavis@mouse-r11 omni-netbox]$ curl -s -X POST -H "Content-Type: application/json" http://cobbler.omni:8001 -d '{ "command": "config-get" }' | jq
[
{
"arguments": {
"Dhcp4": {
"authoritative": false,
"boot-file-name": "",
"calculate-tee-times": false,
"client-classes": [
{
"boot-file-name": "pxelinux.0",
"name": "Legacy_Intel_x86PC",
"next-server": "0.0.0.0",
"option-data": [],
"option-def": [],
"server-hostname": "",
"test": "option[93].hex == 0x0000"
},
{
"boot-file-name": "ipx-snponly.efi",
"name": "EFI_x86-64",
"next-server": "0.0.0.0",
"option-data": [],
"option-def": [],
"server-hostname": "",
"test": "option[93].hex == 0x0009"
},
{
"boot-file-name": "http://192.168.97.6/ipxe-x86_64.efi",
"name": "HTTPClient",
"next-server": "0.0.0.0",
"option-data": [
{
"always-send": false,
"code": 60,
"csv-format": true,
"data": "HTTPClient",
"name": "vendor-class-identifier",
"space": "dhcp4"
}
],
"option-def": [],
"server-hostname": "",
"test": "option[93].hex == 0x0010"
},
{
"boot-file-name": "http://192.168.97.6/ipxe/boot.ipxe",
"name": "boot_iPXE",
"next-server": "0.0.0.0",
"option-data": [],
"option-def": [],
"server-hostname": "",
"test": "(substring(option[77].hex,0,4) == 'iPXE') and (pkt.iface == 'boot')"
},
{
"boot-file-name": "http://192.168.84.6/ipxe/ovirtmgmt.ipxe",
"name": "ovirtmgmt_iPXE",
"next-server": "0.0.0.0",
"option-data": [],
"option-def": [],
"server-hostname": "",
"test": "(substring(option[77].hex,0,4) == 'iPXE') and (pkt.iface == 'ovirtmgmt')"
}
],
"control-socket": {
"socket-name": "/run/kea/kea-dhcp4-ctrl.sock",
"socket-type": "unix"
},
"ddns-generated-prefix": "myhost",
"ddns-override-client-update": false,
"ddns-override-no-update": false,
"ddns-qualifying-suffix": "",
"ddns-replace-client-name": "never",
"ddns-send-updates": true,
"ddns-update-on-renew": false,
"ddns-use-conflict-resolution": true,
"decline-probation-period": 86400,
"dhcp-ddns": {
"enable-updates": false,
"max-queue-size": 1024,
"ncr-format": "JSON",
"ncr-protocol": "UDP",
"sender-ip": "0.0.0.0",
"sender-port": 0,
"server-ip": "127.0.0.1",
"server-port": 53001
},
"dhcp-queue-control": {
"capacity": 64,
"enable-queue": false,
"queue-type": "kea-ring4"
},
"dhcp4o6-port": 0,
"early-global-reservations-lookup": false,
"echo-client-id": true,
"expired-leases-processing": {
"flush-reclaimed-timer-wait-time": 25,
"hold-reclaimed-time": 3600,
"max-reclaim-leases": 100,
"max-reclaim-time": 250,
"reclaim-timer-wait-time": 10,
"unwarned-reclaim-cycles": 5
},
"hooks-libraries": [
{
"library": "/usr/lib/kea/hooks/libdhcp_bootp.so",
"parameters": {}
},
{
"library": "/usr/lib/kea/hooks/libdhcp_lease_cmds.so",
"parameters": {}
},
{
"library": "/usr/lib/kea/hooks/libdhcp_ha.so",
"parameters": {
"high-availability": [
{
"delayed-updates-limit": 0,
"heartbeat-delay": 10000,
"max-ack-delay": 5000,
"max-response-delay": 10000,
"max-unacked-clients": 3,
"mode": "hot-standby",
"multi-threading": {
"enable-multi-threading": true,
"http-client-threads": 4,
"http-dedicated-listener": true,
"http-listener-threads": 4
},
"peers": [
{
"auto-failover": true,
"name": "cobbler",
"role": "primary",
"url": "http://192.168.84.6:8001/"
},
{
"auto-failover": true,
"name": "mouse-r11",
"role": "standby",
"url": "http://192.168.84.2:8001/"
},
{
"auto-failover": true,
"name": "mouse-r12",
"role": "backup",
"url": "http://192.168.84.3:8001/"
},
{
"auto-failover": true,
"name": "mouse-r13",
"role": "backup",
"url": "http://192.168.84.4:8001/"
}
],
"require-client-certs": true,
"restrict-commands": false,
"send-lease-updates": true,
"sync-leases": true,
"sync-page-limit": 10000,
"sync-timeout": 60000,
"this-server-name": "cobbler",
"wait-backup-ack": false
}
]
}
}
],
"host-reservation-identifiers": [
"hw-address",
"duid",
"circuit-id",
"client-id"
],
"hostname-char-replacement": "",
"hostname-char-set": "[^A-Za-z0-9.-]",
"hosts-databases": [
{
"host": "mariadb.kea-cobbler.svc.cluster.local.",
"name": "kea",
"password": "PASSWORDWASHERE",
"type": "mysql",
"user": "kea"
}
],
"interfaces-config": {
"interfaces": [
"boot",
"ipmi",
"modbus",
"onewire",
"ovirtmgmt",
"pdunet",
"switch",
"trendpoint"
],
"re-detect": true
},
"ip-reservations-unique": true,
"lease-database": {
"host": "mariadb.kea-cobbler.svc.cluster.local.",
"name": "kea",
"password": "PASSWORDWASHERE",
"type": "mysql",
"user": "kea"
},
"loggers": [
{
"debuglevel": 0,
"name": "kea-dhcp4",
"output_options": [
{
"flush": true,
"output": "stdout",
"pattern": "%-5p %m\n"
}
],
"severity": "INFO"
}
],
"match-client-id": true,
"multi-threading": {
"enable-multi-threading": true,
"packet-queue-size": 64,
"thread-pool-size": 16
},
"next-server": "0.0.0.0",
"option-data": [
{
"always-send": false,
"code": 15,
"csv-format": true,
"data": "omni",
"name": "domain-name",
"space": "dhcp4"
},
{
"always-send": false,
"code": 119,
"csv-format": true,
"data": "omni, crt.nersc.gov, nersc.gov",
"name": "domain-search",
"space": "dhcp4"
}
],
"option-def": [],
"parked-packet-limit": 256,
"rebind-timer": 1800,
"renew-timer": 900,
"reservations-global": false,
"reservations-in-subnet": true,
"reservations-lookup-first": false,
"reservations-out-of-pool": false,
"sanity-checks": {
"lease-checks": "warn"
},
"server-hostname": "",
"server-tag": "",
"shared-networks": [],
"statistic-default-sample-age": 0,
"statistic-default-sample-count": 20,
"store-extended-info": false,
"subnet4": [
{
"4o6-interface": "",
"4o6-interface-id": "",
"4o6-subnet": "",
"calculate-tee-times": false,
"id": 10,
"interface": "pdunet",
"max-valid-lifetime": 3600,
"min-valid-lifetime": 3600,
"option-data": [
{
"always-send": false,
"code": 4,
"csv-format": true,
"data": "192.168.88.2,192.168.88.3,192.168.88.4",
"name": "time-servers",
"space": "dhcp4"
},
{
"always-send": false,
"code": 6,
"csv-format": true,
"data": "192.168.88.2,192.168.88.3,192.168.88.4",
"name": "domain-name-servers",
"space": "dhcp4"
},
{
"always-send": false,
"code": 3,
"csv-format": true,
"data": "192.168.88.1",
"name": "routers",
"space": "dhcp4"
}
],
"pools": [
{
"option-data": [],
"pool": "192.168.91.33-192.168.91.192"
}
],
"rebind-timer": 1800,
"relay": {
"ip-addresses": []
},
"renew-timer": 900,
"reservations": [],
"reservations-global": false,
"reservations-in-subnet": true,
"reservations-out-of-pool": true,
"store-extended-info": false,
"subnet": "192.168.88.0/22",
"t1-percent": 0.5,
"t2-percent": 0.875,
"valid-lifetime": 3600
},
{
"4o6-interface": "",
"4o6-interface-id": "",
"4o6-subnet": "",
"calculate-tee-times": false,
"id": 20,
"interface": "ipmi",
"max-valid-lifetime": 3600,
"min-valid-lifetime": 3600,
"option-data": [
{
"always-send": false,
"code": 4,
"csv-format": true,
"data": "192.168.79.2,192.168.79.3,192.168.79.4",
"name": "time-servers",
"space": "dhcp4"
},
{
"always-send": false,
"code": 6,
"csv-format": true,
"data": "192.168.79.2,192.168.79.3,192.168.79.4",
"name": "domain-name-servers",
"space": "dhcp4"
},
{
"always-send": false,
"code": 3,
"csv-format": true,
"data": "192.168.79.1",
"name": "routers",
"space": "dhcp4"
}
],
"pools": [
{
"option-data": [],
"pool": "192.168.79.0/25"
}
],
"rebind-timer": 1800,
"relay": {
"ip-addresses": []
},
"renew-timer": 900,
"reservations": [],
"reservations-global": false,
"reservations-in-subnet": true,
"reservations-out-of-pool": true,
"store-extended-info": false,
"subnet": "192.168.76.0/22",
"t1-percent": 0.5,
"t2-percent": 0.875,
"valid-lifetime": 3600
},
{
"4o6-interface": "",
"4o6-interface-id": "",
"4o6-subnet": "",
"calculate-tee-times": false,
"id": 30,
"interface": "modbus",
"max-valid-lifetime": 3600,
"min-valid-lifetime": 3600,
"option-data": [
{
"always-send": false,
"code": 4,
"csv-format": true,
"data": "192.168.94.2,192.168.94.3,192.168.94.4",
"name": "time-servers",
"space": "dhcp4"
},
{
"always-send": false,
"code": 6,
"csv-format": true,
"data": "192.168.94.2,192.168.94.3,192.168.94.4",
"name": "domain-name-servers",
"space": "dhcp4"
},
{
"always-send": false,
"code": 3,
"csv-format": true,
"data": "192.168.94.1",
"name": "routers",
"space": "dhcp4"
}
],
"pools": [
{
"option-data": [],
"pool": "192.168.94.70-192.168.94.92"
}
],
"rebind-timer": 1800,
"relay": {
"ip-addresses": []
},
"renew-timer": 900,
"reservations": [],
"reservations-global": false,
"reservations-in-subnet": true,
"reservations-out-of-pool": true,
"store-extended-info": false,
"subnet": "192.168.94.0/24",
"t1-percent": 0.5,
"t2-percent": 0.875,
"valid-lifetime": 3600
},
{
"4o6-interface": "",
"4o6-interface-id": "",
"4o6-subnet": "",
"calculate-tee-times": false,
"id": 40,
"interface": "onewire",
"max-valid-lifetime": 3600,
"min-valid-lifetime": 3600,
"option-data": [
{
"always-send": false,
"code": 4,
"csv-format": true,
"data": "192.168.93.2,192.168.93.3,192.168.93.4",
"name": "time-servers",
"space": "dhcp4"
},
{
"always-send": false,
"code": 6,
"csv-format": true,
"data": "192.168.93.2,192.168.93.3,192.168.93.4",
"name": "domain-name-servers",
"space": "dhcp4"
},
{
"always-send": false,
"code": 3,
"csv-format": true,
"data": "192.168.93.2",
"name": "routers",
"space": "dhcp4"
}
],
"pools": [
{
"option-data": [],
"pool": "192.168.93.224-192.168.93.254"
}
],
"rebind-timer": 1800,
"relay": {
"ip-addresses": []
},
"renew-timer": 900,
"reservations": [],
"store-extended-info": false,
"subnet": "192.168.93.0/24",
"t1-percent": 0.5,
"t2-percent": 0.875,
"valid-lifetime": 3600
},
{
"4o6-interface": "",
"4o6-interface-id": "",
"4o6-subnet": "",
"boot-file-name": "ipxe-x86_64.efi",
"calculate-tee-times": false,
"id": 50,
"interface": "ovirtmgmt",
"max-valid-lifetime": 3600,
"min-valid-lifetime": 3600,
"next-server": "192.168.84.6",
"option-data": [
{
"always-send": false,
"code": 42,
"csv-format": true,
"data": "192.168.84.2,192.168.84.3,192.168.84.4",
"name": "ntp-servers",
"space": "dhcp4"
},
{
"always-send": false,
"code": 6,
"csv-format": true,
"data": "192.168.84.2,192.168.84.3",
"name": "domain-name-servers",
"space": "dhcp4"
},
{
"always-send": false,
"code": 3,
"csv-format": true,
"data": "192.168.84.1",
"name": "routers",
"space": "dhcp4"
}
],
"pools": [
{
"client-class": "ovirtmgmt_iPXE",
"option-data": [],
"pool": "192.168.87.16/28"
},
{
"option-data": [],
"pool": "192.168.87.32-192.168.87.192"
}
],
"rebind-timer": 1800,
"relay": {
"ip-addresses": []
},
"renew-timer": 900,
"reservations": [],
"reservations-global": false,
"reservations-in-subnet": true,
"reservations-out-of-pool": true,
"store-extended-info": false,
"subnet": "192.168.84.0/22",
"t1-percent": 0.5,
"t2-percent": 0.875,
"valid-lifetime": 3600
},
{
"4o6-interface": "",
"4o6-interface-id": "",
"4o6-subnet": "",
"boot-file-name": "ipxe-x86_64.efi",
"calculate-tee-times": false,
"id": 60,
"interface": "boot",
"max-valid-lifetime": 3600,
"min-valid-lifetime": 3600,
"next-server": "192.168.97.6",
"option-data": [
{
"always-send": false,
"code": 6,
"csv-format": true,
"data": "192.168.97.2",
"name": "domain-name-servers",
"space": "dhcp4"
},
{
"always-send": false,
"code": 3,
"csv-format": true,
"data": "192.168.97.1",
"name": "routers",
"space": "dhcp4"
}
],
"pools": [
{
"client-class": "boot_iPXE",
"option-data": [],
"pool": "192.168.97.64/26"
},
{
"option-data": [],
"pool": "192.168.97.128-192.168.97.192"
}
],
"rebind-timer": 1800,
"relay": {
"ip-addresses": []
},
"renew-timer": 900,
"reservations": [],
"reservations-global": false,
"reservations-in-subnet": true,
"reservations-out-of-pool": true,
"store-extended-info": false,
"subnet": "192.168.97.0/24",
"t1-percent": 0.5,
"t2-percent": 0.875,
"valid-lifetime": 3600
},
{
"4o6-interface": "",
"4o6-interface-id": "",
"4o6-subnet": "",
"calculate-tee-times": false,
"id": 70,
"interface": "switch",
"max-valid-lifetime": 3600,
"min-valid-lifetime": 3600,
"option-data": [
{
"always-send": false,
"code": 6,
"csv-format": true,
"data": "192.168.96.1",
"name": "domain-name-servers",
"space": "dhcp4"
},
{
"always-send": false,
"code": 67,
"csv-format": true,
"data": "http://192.168.96.6/sonic/ztp.json",
"name": "boot-file-name",
"space": "dhcp4"
},
{
"always-send": false,
"code": 3,
"csv-format": true,
"data": "192.168.96.2",
"name": "routers",
"space": "dhcp4"
}
],
"pools": [
{
"option-data": [],
"pool": "192.168.96.192-192.168.96.253"
}
],
"rebind-timer": 1800,
"relay": {
"ip-addresses": []
},
"renew-timer": 900,
"reservations": [],
"reservations-global": false,
"reservations-in-subnet": true,
"reservations-out-of-pool": true,
"store-extended-info": false,
"subnet": "192.168.96.0/24",
"t1-percent": 0.5,
"t2-percent": 0.875,
"valid-lifetime": 3600
},
{
"4o6-interface": "",
"4o6-interface-id": "",
"4o6-subnet": "",
"calculate-tee-times": false,
"id": 75,
"interface": "trendpoint",
"max-valid-lifetime": 3600,
"min-valid-lifetime": 3600,
"option-data": [
{
"always-send": false,
"code": 6,
"csv-format": true,
"data": "192.168.98.2, 192.168.98.3, 192.168.98.4",
"name": "domain-name-servers",
"space": "dhcp4"
},
{
"always-send": false,
"code": 3,
"csv-format": true,
"data": "192.168.98.1",
"name": "routers",
"space": "dhcp4"
}
],
"pools": [
{
"option-data": [],
"pool": "192.168.98.221-192.168.98.253"
}
],
"rebind-timer": 1800,
"relay": {
"ip-addresses": []
},
"renew-timer": 900,
"reservations": [],
"reservations-global": false,
"reservations-in-subnet": true,
"reservations-out-of-pool": true,
"store-extended-info": false,
"subnet": "192.168.98.0/24",
"t1-percent": 0.5,
"t2-percent": 0.875,
"valid-lifetime": 3600
}
],
"t1-percent": 0.5,
"t2-percent": 0.875,
"valid-lifetime": 3600
}
},
"result": 0
}
]
Wow I can't believe someone is using this already!
Does the DHCPv4 leases view work?
What's the output when you do
curl -H 'Content-Type: application/json' --data '{"command":"status-get","service":["dhcp4","dhcp6"]}' <YOUR SERVER>
I get the following when DHCPv6 is not configured:
[
{
"arguments": {
"multi-threading-enabled": false,
"pid": 1,
"reload": 34933,
"sockets": {
"status": "ready"
},
"uptime": 34933
},
"result": 0
},
{
"result": 1,
"text": "forwarding socket is not configured for the server type dhcp6"
}
]
I think I'll add a toggle for DHCPv4/v6 to hide/disable the features.
Found this when I was looking for kea/netbox integrations.. There are several others, but they failed to work with the HA setup we have - you can't rewrite the config when HA is running.
The Dhcp4 subnets/reservations tabs work great, other than we use FQDN's which don't match up with the netbox device names.
well, when you do the config-get, if you don't see the 'Dhcp4' or 'Dhcp6' array item, you then know what the server supports. You can then also not show the tabs for that supported service; ie, if it's Dhcp4 only, then no Dhcp6 tabs, and vice-a-versa.
[tdavis@mouse-r11 ~]$ curl -s -H 'Content-Type: application/json' --data '{"command":"status-get","service":["dhcp4","dhcp6"]}' mouse-r11:8001 | jq
[
{
"arguments": {
"high-availability": [
{
"ha-mode": "hot-standby",
"ha-servers": {
"local": {
"role": "standby",
"scopes": [],
"state": "hot-standby"
},
"remote": {
"age": 9,
"analyzed-packets": 0,
"communication-interrupted": false,
"connecting-clients": 0,
"in-touch": true,
"last-scopes": [
"cobbler"
],
"last-state": "hot-standby",
"role": "primary",
"unacked-clients": 0,
"unacked-clients-left": 0
}
}
}
],
"multi-threading-enabled": true,
"packet-queue-size": 64,
"packet-queue-statistics": [
1.00001,
1.00819,
1.01175
],
"pid": 110,
"reload": 1642757,
"sockets": {
"status": "ready"
},
"thread-pool-size": 16,
"uptime": 1642758
},
"result": 0
}
]
It doesn't matter what you ask for it's the same output everytime.
Dang it, wrong server above.. this is the primary results, above is a hot-standby server.
[tdavis@mouse-r11 ~]$ curl -s -H 'Content-Type: application/json' --data '{"command":"status-get","service":["dhcp4","dhcp6"]}' cobbler:8001 | jq
[
{
"arguments": {
"high-availability": [
{
"ha-mode": "hot-standby",
"ha-servers": {
"local": {
"role": "primary",
"scopes": [
"cobbler"
],
"state": "hot-standby"
},
"remote": {
"age": 4,
"analyzed-packets": 0,
"communication-interrupted": false,
"connecting-clients": 0,
"in-touch": true,
"last-scopes": [],
"last-state": "hot-standby",
"role": "standby",
"unacked-clients": 0,
"unacked-clients-left": 0
}
}
}
],
"multi-threading-enabled": true,
"packet-queue-size": 64,
"packet-queue-statistics": [
1.0,
1.00011,
1.00261
],
"pid": 55,
"reload": 529164,
"sockets": {
"status": "ready"
},
"thread-pool-size": 16,
"uptime": 529165
},
"result": 0
}
]
and a 3rd server type we run, which is a backup server aka, we are running a primary-secondary-backup setup here.
[tdavis@mouse-r11 ~]$ curl -s -H 'Content-Type: application/json' --data '{"command":"status-get","service":["dhcp4","dhcp6"]}' mouse-r12:8001 | jq
[
{
"arguments": {
"high-availability": [
{
"ha-mode": "hot-standby",
"ha-servers": {
"local": {
"role": "backup",
"scopes": [],
"state": "backup"
}
}
}
],
"multi-threading-enabled": true,
"packet-queue-size": 64,
"packet-queue-statistics": [
0.0,
0.0,
0.0
],
"pid": 20,
"reload": 1814925,
"thread-pool-size": 16,
"uptime": 1814925
},
"result": 0
}
]
We run kea in a HA setup, with no control-agent, dhcp4 only.
I wasn't aware that you can do that. I assume that you're using the setup described here with http-dedicated-listener
?
I don't think that sending non-HA commands on a dedicated listener is a supported config: https://gitlab.isc.org/isc-projects/kea/-/issues/2062 and "Note the commands should still be sent via CA. The dedicated listener is specifically for HA updates only." from https://kea.readthedocs.io/en/latest/arm/config-templates.html?highlight=dedicated-listener#id2
you can't rewrite the config when HA is running.
Hmmm I have a script that pushes a config to a hot-standby pair and it seems to work fine.
@ThomasADavis could you try the latest master and run ./manage.py migrate
it'll add a DHCPv4/6 field to the server which you can toggle. Let me know if this works for you.
it works.
btw, we run kea-dhcp4 only, in a pod with host network/privileged execution, read-only fs with the leases/reservations in a mysql db; the configurations are supplied by configmap, so no changing it via API.. This plugin at least lets us see the leases and status of the server, except I haven't tried it to see what happens if the daemon is down.
We run kea in a HA setup, with no control-agent, dhcp4 only. Yes, this is a feature of v2.2. No dhcp6.
Looking at the status page gives an error, which when netbox debug is turned on this stack dump:
with this from the netbox debug page
The dhcp6 subnet tab also crashes, with this: