[#389] GVM target import: gvm-script (gmp.send_command, lxml parse) + IANA port-list injection; feed jq rewrite (record-bound, no IFS collapse)
ci / audit (push) Successful in 24s
ci / audit (push) Successful in 24s
63/63 GLPI targets imported into gvmd (0 failures). Admin creds in ~/.creds/gvm-test.env. Import is idempotent (deletes glpi-* first). https://projects.knownelement.com/issues/389
This commit is contained in:
+13
-22
@@ -56,34 +56,25 @@ else
|
||||
fetch_inventory > "$INVENTORY_JSON" || exit 1
|
||||
fi
|
||||
|
||||
# Normalize: one record per line with parsed IPs
|
||||
NORMALIZED=$(jq -r '
|
||||
.[]
|
||||
| select( ($ONLY_DYNAMIC == 0 or .is_dynamic == 1) )
|
||||
| ( .comment // "" ) as $c
|
||||
| ( [$c | scan("ts=([0-9.]+)")] | first | first // "" ) as $ts
|
||||
| ( [$c | scan("mgmt[ =]([0-9.]+)")] | first | first // "" ) as $mgmt
|
||||
| select( $INCLUDE_NO_IP == 1 or $ts != "" or $mgmt != "" )
|
||||
| [ (.id|tostring), .name, $ts, $mgmt, (.serial // "-"),
|
||||
(.last_inventory_update // "-"), ((.is_dynamic // 0)|tostring) ]
|
||||
| @tsv' --argjson ONLY_DYNAMIC "$ONLY_DYNAMIC" --argjson INCLUDE_NO_IP "$INCLUDE_NO_IP" "$INVENTORY_JSON")
|
||||
|
||||
[ -n "$NORMALIZED" ] || { echo "no scan targets parsed from GLPI" >&2; exit 2; }
|
||||
|
||||
case "$FORMAT" in
|
||||
csv)
|
||||
printf 'glpi_id,name,ts_ip,mgmt_ip,serial,last_inventory,agent_fed\n'
|
||||
printf '%s\n' "$NORMALIZED"
|
||||
jq -r '
|
||||
.[]
|
||||
| select( ($ONLY_DYNAMIC == 0 or .is_dynamic == 1) )
|
||||
| ( .comment // "" ) as $c
|
||||
| ( [$c | scan("ts=([0-9.]+)")] | first | first // "" ) as $ts
|
||||
| ( [$c | scan("mgmt[ =]([0-9.]+)")] | first | first // "" ) as $mgmt
|
||||
| select( $INCLUDE_NO_IP == 1 or $ts != "" or $mgmt != "" )
|
||||
| [ (.id|tostring), .name, $ts, $mgmt, (.serial // ""),
|
||||
(.last_inventory_update // ""), ((.is_dynamic // 0)|tostring) ]
|
||||
| @csv' --argjson ONLY_DYNAMIC "$ONLY_DYNAMIC" --argjson INCLUDE_NO_IP "$INCLUDE_NO_IP" "$INVENTORY_JSON"
|
||||
;;
|
||||
gmp)
|
||||
printf '<!-- GMP create_target fragments generated from GLPI CMDB %s. Review hosts before importing. -->\n' "$(date -Is)"
|
||||
printf '%s\n' "$NORMALIZED" | while IFS="$(printf '\t')" read -r id name ts mgmt _serial inv dyn; do
|
||||
hosts="$ts"
|
||||
if [ -n "$mgmt" ]; then hosts="${hosts:+$hosts,}$mgmt"; fi
|
||||
[ -n "$hosts" ] || continue
|
||||
printf '<create_target><name>glpi-%s-%s</name><hosts>%s</hosts><comment>GLPI #%s inv=%s agent=%s</comment><alive_tests>Scan Config Default</alive_tests></create_target>\n' \
|
||||
"$id" "$(printf '%s' "$name" | tr -c '[:alnum:].-' '-')" "$hosts" "$id" "$inv" "$dyn"
|
||||
done
|
||||
# jq emits the complete element per record (host list built in jq — avoids
|
||||
# bash read() IFS-collapse on empty TSV fields; record bound via . as $rec)
|
||||
jq -r ' .[] | . as $rec | ( $rec.comment // "" ) as $c | ( [$c | scan("ts=([0-9.]+)")] | first | first // "" ) as $ts | ( [$c | scan("mgmt[ =]([0-9.]+)")] | first | first // "" ) as $mgmt | [ $ts, $mgmt ] | map(select(length > 0)) | join(",") as $hosts | select( $hosts != "" ) | $rec.name as $n | "<create_target><name>glpi-\($rec.id)-\($n | gsub("[^a-zA-Z0-9.-]"; "-"))</name><hosts>\($hosts)</hosts><comment>GLPI #\($rec.id) agent=\($rec.is_dynamic // 0)</comment></create_target>"' --argjson ONLY_DYNAMIC "$ONLY_DYNAMIC" --argjson INCLUDE_NO_IP "$INCLUDE_NO_IP" "$INVENTORY_JSON"
|
||||
;;
|
||||
*) echo "bad format: $FORMAT" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import re
|
||||
from lxml import etree
|
||||
data = open('/tmp/targets.gmp').read()
|
||||
cmds = re.findall(r'<create_target>.*?</create_target>', data, re.S)
|
||||
|
||||
pl = etree.fromstring(gmp.send_command('<get_port_lists filter="rows=-1"/>').encode())
|
||||
plist_id = None
|
||||
for p in pl.findall('.//port_list'):
|
||||
if 'All IANA assigned TCP' in (p.findtext('name') or ''):
|
||||
plist_id = p.get('id')
|
||||
break
|
||||
if not plist_id:
|
||||
raise SystemExit('no IANA TCP port list found')
|
||||
|
||||
# clean previous glpi-* targets (idempotent re-import)
|
||||
existing = etree.fromstring(gmp.send_command('<get_targets filter="rows=-1"/>').encode())
|
||||
for t in existing.findall('.//target'):
|
||||
if (t.findtext('name') or '').startswith('glpi-'):
|
||||
gmp.send_command(f'<delete_target target_id="{t.get("id")}"/>')
|
||||
|
||||
ok = fail = 0
|
||||
for c in cmds:
|
||||
frag = etree.fromstring(c.encode())
|
||||
el = etree.SubElement(frag, 'port_list')
|
||||
el.set('id', plist_id)
|
||||
root = etree.fromstring(gmp.send_command(etree.tostring(frag).decode()).encode())
|
||||
st = root.get('status')
|
||||
if st == '201':
|
||||
ok += 1
|
||||
else:
|
||||
fail += 1
|
||||
if fail <= 3:
|
||||
resp = root.findtext('.//response')
|
||||
print('FAIL', st, (resp or etree.tostring(root).decode())[:180])
|
||||
print(f'imported={ok} failed={fail}')
|
||||
Reference in New Issue
Block a user