ipmg 2.3.0__tar.gz → 2.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ipmg-2.3.0/src/ipmg.egg-info → ipmg-2.4.0}/PKG-INFO +108 -6
- {ipmg-2.3.0 → ipmg-2.4.0}/README.md +106 -5
- {ipmg-2.3.0 → ipmg-2.4.0}/pyproject.toml +4 -1
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/__init__.py +1 -1
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/cli/commands.py +11 -2
- ipmg-2.4.0/src/ipmg/cli/config.py +410 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/cli/parser.py +40 -6
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/exceptions.py +4 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/infrastructure/file_io.py +91 -5
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/infrastructure/incremental.py +10 -0
- ipmg-2.4.0/src/ipmg/reporting/machine.py +88 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/reporting/ui.py +13 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/services/scan_service.py +69 -16
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/utils/helpers.py +10 -7
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/web/app.py +14 -33
- {ipmg-2.3.0 → ipmg-2.4.0/src/ipmg.egg-info}/PKG-INFO +108 -6
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg.egg-info/SOURCES.txt +4 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg.egg-info/requires.txt +3 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_commands.py +1 -1
- ipmg-2.4.0/tests/test_config.py +402 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_file_io.py +146 -2
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_incremental.py +8 -7
- ipmg-2.4.0/tests/test_machine_output.py +147 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_parser.py +17 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_scan_service.py +44 -10
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_web_api.py +10 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/LICENSE +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/setup.cfg +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/__main__.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/cli/__init__.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/core/__init__.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/core/diff.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/core/discovery.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/core/engine.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/core/health.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/core/ping.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/core/portscan.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/core/security.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/infrastructure/__init__.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/infrastructure/database.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/infrastructure/notify.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/reporting/__init__.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/reporting/diff_report.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/reporting/frames.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/reporting/live.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/reporting/summary.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/services/__init__.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/services/history_service.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/utils/__init__.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/web/__init__.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/web/db.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/web/manager.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/web/schemas.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/web/server.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/web/static/css/app.css +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/web/static/index.html +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/web/static/js/api.js +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/web/static/js/app.js +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/web/static/js/charts.js +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/web/static/js/demo.js +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg/web/static/js/views.js +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg.egg-info/dependency_links.txt +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg.egg-info/entry_points.txt +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/src/ipmg.egg-info/top_level.txt +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_api_contract.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_database_history.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_diff.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_diff_report.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_discover.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_engine.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_health.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_history_service.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_live.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_notify.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_ping.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_ping_command.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_portscan.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_ui.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_utils.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_web_db.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_web_manager.py +0 -0
- {ipmg-2.3.0 → ipmg-2.4.0}/tests/test_web_server.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ipmg
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: IP Management & Ping Monitoring CLI Tool
|
|
5
5
|
Author: Sameer Alam
|
|
6
6
|
Maintainer-email: Sameer Alam <sameeralam3127@gmail.com>
|
|
@@ -37,6 +37,7 @@ Requires-Dist: pydantic>=2.7
|
|
|
37
37
|
Requires-Dist: uvicorn>=0.27
|
|
38
38
|
Requires-Dist: websockets>=12
|
|
39
39
|
Requires-Dist: python-multipart>=0.0.9
|
|
40
|
+
Requires-Dist: tomli>=2.0.1; python_version < "3.11"
|
|
40
41
|
Provides-Extra: dev
|
|
41
42
|
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
42
43
|
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
@@ -331,8 +332,10 @@ Or pick a ready-made command:
|
|
|
331
332
|
| --- | --- |
|
|
332
333
|
| Scan the network I am on | `ipmg --discover` |
|
|
333
334
|
| Scan hosts listed in a file | `ipmg --input targets.txt` |
|
|
335
|
+
| Scan a file plus a few extra hosts | `ipmg --input targets.txt 10.0.0.0/30 10.0.0.5` |
|
|
334
336
|
| Get names, not just IP addresses | `ipmg --input targets.txt --resolve` |
|
|
335
337
|
| Get a report I can send to someone | `ipmg --input targets.txt --formats md csv` |
|
|
338
|
+
| Pipe the results into a script | `ipmg --input targets.txt --json \| jq .` |
|
|
336
339
|
| See hosts appear as they answer | `ipmg --input 192.168.1.0/24 --stream` |
|
|
337
340
|
| See what changed since last time | `ipmg --input targets.txt --compare` |
|
|
338
341
|
| Check which services are listening | `ipmg --input targets.txt --scan-ports` |
|
|
@@ -534,9 +537,32 @@ Anywhere IPMG takes `--input`, you can give it any of these:
|
|
|
534
537
|
| 192.168.1.1 |
|
|
535
538
|
| 10.0.1.0/30 |
|
|
536
539
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
+
- **A JSON file** (`.json`) — a list of addresses, a list of objects keyed by
|
|
541
|
+
`IP Address`, `ip`, or `target`, or an object with a `targets` or `ips` array:
|
|
542
|
+
|
|
543
|
+
```json
|
|
544
|
+
["192.168.1.1", "10.0.1.0/30"]
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
Because `IP Address` is one of the keys it accepts, a report IPMG wrote with
|
|
548
|
+
`--formats json` can be fed straight back in:
|
|
549
|
+
|
|
550
|
+
```bash
|
|
551
|
+
ipmg --input results_20260628_120000.json
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
`--input` takes as many of these as you like, in any mix, and may also be
|
|
555
|
+
repeated:
|
|
556
|
+
|
|
557
|
+
```bash
|
|
558
|
+
ipmg --input targets.txt 10.0.0.0/30 10.0.0.5
|
|
559
|
+
ipmg --input targets.txt --input 10.0.0.5 # the same thing
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
Duplicate targets are removed automatically — across sources too, so a host
|
|
563
|
+
that is both in the file and on the command line is scanned once — and one scan
|
|
564
|
+
expands to at most 65,536 hosts in total. Larger CIDR blocks, ranges, or
|
|
565
|
+
combinations are rejected up front, before the scan starts.
|
|
540
566
|
|
|
541
567
|
---
|
|
542
568
|
|
|
@@ -586,6 +612,22 @@ preferring `jsonl` or `csv` (current to the last host) over `json` or `xlsx`
|
|
|
586
612
|
(current to the last autosave). Hosts dropped from the target list since are
|
|
587
613
|
left out of the finished report.
|
|
588
614
|
|
|
615
|
+
**Piping results into a script.** `--json` prints the finished scan to stdout as
|
|
616
|
+
a JSON array, and `--jsonl` prints one object per host the moment its probe
|
|
617
|
+
finishes. The human output moves to stderr, so stdout is nothing but data and no
|
|
618
|
+
temp file or glob is needed:
|
|
619
|
+
|
|
620
|
+
```bash
|
|
621
|
+
ipmg --input 10.0.0.0/24 --json | jq '.[] | select(.Status == "Active")'
|
|
622
|
+
ipmg --input 10.0.0.0/24 --jsonl | while read -r host; do notify "$host"; done
|
|
623
|
+
ipmg --input 10.0.0.0/24 --json 2>/dev/null > hosts.json # data only
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
The field names are the report columns above, and both flags print a host
|
|
627
|
+
identically — `--json` is what `--jsonl` prints, gathered into an array. Unless
|
|
628
|
+
you ask for `--formats` explicitly, a piped scan writes no report file at all.
|
|
629
|
+
Exit codes are unchanged.
|
|
630
|
+
|
|
589
631
|
**Open ports.** `Open Ports` is only populated when `--scan-ports` is set: for
|
|
590
632
|
each host that answers, IPMG probes a list of common TCP ports (SSH, HTTP,
|
|
591
633
|
HTTPS, RDP, SMB, FTP, SMTP, DNS, MSSQL, MySQL, PostgreSQL by default)
|
|
@@ -602,6 +644,61 @@ them — so piping IPMG into a file or a log gives you clean text.
|
|
|
602
644
|
|
|
603
645
|
---
|
|
604
646
|
|
|
647
|
+
## Default options in a file
|
|
648
|
+
|
|
649
|
+
If every run repeats the same flags, put them in **`ipmg.toml`** next to your
|
|
650
|
+
work instead:
|
|
651
|
+
|
|
652
|
+
```toml
|
|
653
|
+
threads = 200
|
|
654
|
+
timeout = 1
|
|
655
|
+
resolve = true
|
|
656
|
+
formats = ["md", "csv"]
|
|
657
|
+
|
|
658
|
+
[profile.datacenter]
|
|
659
|
+
threads = 400
|
|
660
|
+
scan-ports = true
|
|
661
|
+
ports = "22,80,443"
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
```bash
|
|
665
|
+
ipmg --input targets.txt # uses the file's defaults
|
|
666
|
+
ipmg --input targets.txt --profile datacenter # and the profile on top
|
|
667
|
+
ipmg --input targets.txt --threads 20 # a flag always wins
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
Any long flag can be a key, written as the flag is (`scan-ports`) or with
|
|
671
|
+
underscores (`scan_ports`). A switch takes `true` to mean "as if the flag were
|
|
672
|
+
passed" — `no-history = true` is `--no-history`. Files are read from
|
|
673
|
+
`~/.config/ipmg/config.toml` first (or `$XDG_CONFIG_HOME`), then `./ipmg.toml`
|
|
674
|
+
on top, so a project can override your global defaults:
|
|
675
|
+
|
|
676
|
+
| Flag | What it does |
|
|
677
|
+
| --- | --- |
|
|
678
|
+
| `--config PATH` | Read that file instead of searching |
|
|
679
|
+
| `--no-config` | Ignore every file and use the built-in defaults |
|
|
680
|
+
| `--profile NAME` | Apply the `[profile.NAME]` section as well |
|
|
681
|
+
|
|
682
|
+
**The command line always wins.** A flag that appears on it ignores the file
|
|
683
|
+
entirely for that flag — including `--input`, which merges several sources on
|
|
684
|
+
one command line but replaces the file's list rather than adding to it.
|
|
685
|
+
|
|
686
|
+
A key that is not a flag, a value of the wrong type, or a value outside a
|
|
687
|
+
flag's choices is an error naming the key and the file it came from:
|
|
688
|
+
|
|
689
|
+
```text
|
|
690
|
+
✗ Unknown option 'thredas' in ipmg.toml. Did you mean 'threads'?
|
|
691
|
+
✗ 'formats' in ipmg.toml: 'pdf' is not one of xlsx, csv, json, jsonl, md.
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
A project's `./ipmg.toml` comes with whatever directory you scan from,
|
|
695
|
+
including a repository you just cloned, so it cannot say where results are
|
|
696
|
+
sent: the `--notify-*` destinations and `--smtp-*` settings are only read from
|
|
697
|
+
`~/.config/ipmg/config.toml` or a file you pass with `--config`. A file also
|
|
698
|
+
cannot combine flags that exclude each other, such as `json` and `jsonl`.
|
|
699
|
+
|
|
700
|
+
---
|
|
701
|
+
|
|
605
702
|
## All options
|
|
606
703
|
|
|
607
704
|
`ipmg --help` always lists the current set. Grouped for reading:
|
|
@@ -610,10 +707,12 @@ them — so piping IPMG into a file or a log gives you clean text.
|
|
|
610
707
|
|
|
611
708
|
| Flag | Default | Description |
|
|
612
709
|
| --- | --- | --- |
|
|
613
|
-
| `--input` | `ip_list.xlsx` | What to scan:
|
|
710
|
+
| `--input` | `ip_list.xlsx` | What to scan: one or more files (`.xlsx`, `.xls`, `.csv`, `.json`, `.txt`, `.list`), IPs, CIDR blocks, or ranges (`10.0.0.1-10.0.0.50`), merged and de-duplicated |
|
|
614
711
|
| `--discover` | off | Auto-detect and scan the local subnet instead |
|
|
615
712
|
| `--output` | `results` | Report file name prefix |
|
|
616
|
-
| `--formats` | `xlsx` | One or more of `xlsx`, `csv`, `json`, `jsonl`, `md` |
|
|
713
|
+
| `--formats` | `xlsx` | One or more of `xlsx`, `csv`, `json`, `jsonl`, `md` (no file at all with `--json`/`--jsonl`) |
|
|
714
|
+
| `--json` | off | Print the finished scan to stdout as a JSON array, human output on stderr |
|
|
715
|
+
| `--jsonl` | off | Stream one JSON object per host to stdout as each probe finishes |
|
|
617
716
|
| `--no-incremental` | off | Only write the report once the scan has finished |
|
|
618
717
|
| `--autosave` | `30` | How often a running scan re-saves `xlsx`, `json`, and `md` |
|
|
619
718
|
| `--resume` | off | Finish an interrupted scan from its partial report (newest one, or the path given) |
|
|
@@ -645,6 +744,9 @@ them — so piping IPMG into a file or a log gives you clean text.
|
|
|
645
744
|
| `--stream-all` | off | Stream every result, including hosts that did not answer (implies `--stream`) |
|
|
646
745
|
| `--stream-refresh` | `0.25` | Seconds between progress-bar redraws while streaming (0.05-5) |
|
|
647
746
|
| `--verbose` | off | Debug logging |
|
|
747
|
+
| `--config` | search | Read defaults from this file instead of searching for `ipmg.toml` |
|
|
748
|
+
| `--no-config` | off | Ignore every configuration file |
|
|
749
|
+
| `--profile` | none | Apply a `[profile.NAME]` section from the configuration file |
|
|
648
750
|
|
|
649
751
|
**Exit status**
|
|
650
752
|
|
|
@@ -283,8 +283,10 @@ Or pick a ready-made command:
|
|
|
283
283
|
| --- | --- |
|
|
284
284
|
| Scan the network I am on | `ipmg --discover` |
|
|
285
285
|
| Scan hosts listed in a file | `ipmg --input targets.txt` |
|
|
286
|
+
| Scan a file plus a few extra hosts | `ipmg --input targets.txt 10.0.0.0/30 10.0.0.5` |
|
|
286
287
|
| Get names, not just IP addresses | `ipmg --input targets.txt --resolve` |
|
|
287
288
|
| Get a report I can send to someone | `ipmg --input targets.txt --formats md csv` |
|
|
289
|
+
| Pipe the results into a script | `ipmg --input targets.txt --json \| jq .` |
|
|
288
290
|
| See hosts appear as they answer | `ipmg --input 192.168.1.0/24 --stream` |
|
|
289
291
|
| See what changed since last time | `ipmg --input targets.txt --compare` |
|
|
290
292
|
| Check which services are listening | `ipmg --input targets.txt --scan-ports` |
|
|
@@ -486,9 +488,32 @@ Anywhere IPMG takes `--input`, you can give it any of these:
|
|
|
486
488
|
| 192.168.1.1 |
|
|
487
489
|
| 10.0.1.0/30 |
|
|
488
490
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
491
|
+
- **A JSON file** (`.json`) — a list of addresses, a list of objects keyed by
|
|
492
|
+
`IP Address`, `ip`, or `target`, or an object with a `targets` or `ips` array:
|
|
493
|
+
|
|
494
|
+
```json
|
|
495
|
+
["192.168.1.1", "10.0.1.0/30"]
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
Because `IP Address` is one of the keys it accepts, a report IPMG wrote with
|
|
499
|
+
`--formats json` can be fed straight back in:
|
|
500
|
+
|
|
501
|
+
```bash
|
|
502
|
+
ipmg --input results_20260628_120000.json
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
`--input` takes as many of these as you like, in any mix, and may also be
|
|
506
|
+
repeated:
|
|
507
|
+
|
|
508
|
+
```bash
|
|
509
|
+
ipmg --input targets.txt 10.0.0.0/30 10.0.0.5
|
|
510
|
+
ipmg --input targets.txt --input 10.0.0.5 # the same thing
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
Duplicate targets are removed automatically — across sources too, so a host
|
|
514
|
+
that is both in the file and on the command line is scanned once — and one scan
|
|
515
|
+
expands to at most 65,536 hosts in total. Larger CIDR blocks, ranges, or
|
|
516
|
+
combinations are rejected up front, before the scan starts.
|
|
492
517
|
|
|
493
518
|
---
|
|
494
519
|
|
|
@@ -538,6 +563,22 @@ preferring `jsonl` or `csv` (current to the last host) over `json` or `xlsx`
|
|
|
538
563
|
(current to the last autosave). Hosts dropped from the target list since are
|
|
539
564
|
left out of the finished report.
|
|
540
565
|
|
|
566
|
+
**Piping results into a script.** `--json` prints the finished scan to stdout as
|
|
567
|
+
a JSON array, and `--jsonl` prints one object per host the moment its probe
|
|
568
|
+
finishes. The human output moves to stderr, so stdout is nothing but data and no
|
|
569
|
+
temp file or glob is needed:
|
|
570
|
+
|
|
571
|
+
```bash
|
|
572
|
+
ipmg --input 10.0.0.0/24 --json | jq '.[] | select(.Status == "Active")'
|
|
573
|
+
ipmg --input 10.0.0.0/24 --jsonl | while read -r host; do notify "$host"; done
|
|
574
|
+
ipmg --input 10.0.0.0/24 --json 2>/dev/null > hosts.json # data only
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
The field names are the report columns above, and both flags print a host
|
|
578
|
+
identically — `--json` is what `--jsonl` prints, gathered into an array. Unless
|
|
579
|
+
you ask for `--formats` explicitly, a piped scan writes no report file at all.
|
|
580
|
+
Exit codes are unchanged.
|
|
581
|
+
|
|
541
582
|
**Open ports.** `Open Ports` is only populated when `--scan-ports` is set: for
|
|
542
583
|
each host that answers, IPMG probes a list of common TCP ports (SSH, HTTP,
|
|
543
584
|
HTTPS, RDP, SMB, FTP, SMTP, DNS, MSSQL, MySQL, PostgreSQL by default)
|
|
@@ -554,6 +595,61 @@ them — so piping IPMG into a file or a log gives you clean text.
|
|
|
554
595
|
|
|
555
596
|
---
|
|
556
597
|
|
|
598
|
+
## Default options in a file
|
|
599
|
+
|
|
600
|
+
If every run repeats the same flags, put them in **`ipmg.toml`** next to your
|
|
601
|
+
work instead:
|
|
602
|
+
|
|
603
|
+
```toml
|
|
604
|
+
threads = 200
|
|
605
|
+
timeout = 1
|
|
606
|
+
resolve = true
|
|
607
|
+
formats = ["md", "csv"]
|
|
608
|
+
|
|
609
|
+
[profile.datacenter]
|
|
610
|
+
threads = 400
|
|
611
|
+
scan-ports = true
|
|
612
|
+
ports = "22,80,443"
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
```bash
|
|
616
|
+
ipmg --input targets.txt # uses the file's defaults
|
|
617
|
+
ipmg --input targets.txt --profile datacenter # and the profile on top
|
|
618
|
+
ipmg --input targets.txt --threads 20 # a flag always wins
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
Any long flag can be a key, written as the flag is (`scan-ports`) or with
|
|
622
|
+
underscores (`scan_ports`). A switch takes `true` to mean "as if the flag were
|
|
623
|
+
passed" — `no-history = true` is `--no-history`. Files are read from
|
|
624
|
+
`~/.config/ipmg/config.toml` first (or `$XDG_CONFIG_HOME`), then `./ipmg.toml`
|
|
625
|
+
on top, so a project can override your global defaults:
|
|
626
|
+
|
|
627
|
+
| Flag | What it does |
|
|
628
|
+
| --- | --- |
|
|
629
|
+
| `--config PATH` | Read that file instead of searching |
|
|
630
|
+
| `--no-config` | Ignore every file and use the built-in defaults |
|
|
631
|
+
| `--profile NAME` | Apply the `[profile.NAME]` section as well |
|
|
632
|
+
|
|
633
|
+
**The command line always wins.** A flag that appears on it ignores the file
|
|
634
|
+
entirely for that flag — including `--input`, which merges several sources on
|
|
635
|
+
one command line but replaces the file's list rather than adding to it.
|
|
636
|
+
|
|
637
|
+
A key that is not a flag, a value of the wrong type, or a value outside a
|
|
638
|
+
flag's choices is an error naming the key and the file it came from:
|
|
639
|
+
|
|
640
|
+
```text
|
|
641
|
+
✗ Unknown option 'thredas' in ipmg.toml. Did you mean 'threads'?
|
|
642
|
+
✗ 'formats' in ipmg.toml: 'pdf' is not one of xlsx, csv, json, jsonl, md.
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
A project's `./ipmg.toml` comes with whatever directory you scan from,
|
|
646
|
+
including a repository you just cloned, so it cannot say where results are
|
|
647
|
+
sent: the `--notify-*` destinations and `--smtp-*` settings are only read from
|
|
648
|
+
`~/.config/ipmg/config.toml` or a file you pass with `--config`. A file also
|
|
649
|
+
cannot combine flags that exclude each other, such as `json` and `jsonl`.
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
557
653
|
## All options
|
|
558
654
|
|
|
559
655
|
`ipmg --help` always lists the current set. Grouped for reading:
|
|
@@ -562,10 +658,12 @@ them — so piping IPMG into a file or a log gives you clean text.
|
|
|
562
658
|
|
|
563
659
|
| Flag | Default | Description |
|
|
564
660
|
| --- | --- | --- |
|
|
565
|
-
| `--input` | `ip_list.xlsx` | What to scan:
|
|
661
|
+
| `--input` | `ip_list.xlsx` | What to scan: one or more files (`.xlsx`, `.xls`, `.csv`, `.json`, `.txt`, `.list`), IPs, CIDR blocks, or ranges (`10.0.0.1-10.0.0.50`), merged and de-duplicated |
|
|
566
662
|
| `--discover` | off | Auto-detect and scan the local subnet instead |
|
|
567
663
|
| `--output` | `results` | Report file name prefix |
|
|
568
|
-
| `--formats` | `xlsx` | One or more of `xlsx`, `csv`, `json`, `jsonl`, `md` |
|
|
664
|
+
| `--formats` | `xlsx` | One or more of `xlsx`, `csv`, `json`, `jsonl`, `md` (no file at all with `--json`/`--jsonl`) |
|
|
665
|
+
| `--json` | off | Print the finished scan to stdout as a JSON array, human output on stderr |
|
|
666
|
+
| `--jsonl` | off | Stream one JSON object per host to stdout as each probe finishes |
|
|
569
667
|
| `--no-incremental` | off | Only write the report once the scan has finished |
|
|
570
668
|
| `--autosave` | `30` | How often a running scan re-saves `xlsx`, `json`, and `md` |
|
|
571
669
|
| `--resume` | off | Finish an interrupted scan from its partial report (newest one, or the path given) |
|
|
@@ -597,6 +695,9 @@ them — so piping IPMG into a file or a log gives you clean text.
|
|
|
597
695
|
| `--stream-all` | off | Stream every result, including hosts that did not answer (implies `--stream`) |
|
|
598
696
|
| `--stream-refresh` | `0.25` | Seconds between progress-bar redraws while streaming (0.05-5) |
|
|
599
697
|
| `--verbose` | off | Debug logging |
|
|
698
|
+
| `--config` | search | Read defaults from this file instead of searching for `ipmg.toml` |
|
|
699
|
+
| `--no-config` | off | Ignore every configuration file |
|
|
700
|
+
| `--profile` | none | Apply a `[profile.NAME]` section from the configuration file |
|
|
600
701
|
|
|
601
702
|
**Exit status**
|
|
602
703
|
|
|
@@ -13,7 +13,7 @@ build-backend = "setuptools.build_meta"
|
|
|
13
13
|
|
|
14
14
|
[project]
|
|
15
15
|
name = "ipmg"
|
|
16
|
-
version = "2.
|
|
16
|
+
version = "2.4.0" # Managed automatically by semantic-release
|
|
17
17
|
description = "IP Management & Ping Monitoring CLI Tool"
|
|
18
18
|
readme = "README.md"
|
|
19
19
|
requires-python = ">=3.9"
|
|
@@ -57,6 +57,9 @@ dependencies = [
|
|
|
57
57
|
"uvicorn>=0.27",
|
|
58
58
|
"websockets>=12",
|
|
59
59
|
"python-multipart>=0.0.9",
|
|
60
|
+
# tomllib is in the standard library from 3.11; tomli 2.x is the same
|
|
61
|
+
# parser with the same API, so the floor must not drop below it.
|
|
62
|
+
"tomli>=2.0.1; python_version < '3.11'",
|
|
60
63
|
]
|
|
61
64
|
|
|
62
65
|
[project.urls]
|
|
@@ -6,6 +6,7 @@ import logging
|
|
|
6
6
|
import sys
|
|
7
7
|
from typing import Callable, Dict, List, Optional
|
|
8
8
|
|
|
9
|
+
from ipmg.cli import config
|
|
9
10
|
from ipmg.cli.parser import (
|
|
10
11
|
build_diff_parser,
|
|
11
12
|
build_history_parser,
|
|
@@ -21,7 +22,7 @@ from ipmg.reporting import ui
|
|
|
21
22
|
from ipmg.reporting.diff_report import export_diff, print_diff
|
|
22
23
|
from ipmg.reporting.summary import print_scan_history
|
|
23
24
|
from ipmg.services.history_service import HistoryService
|
|
24
|
-
from ipmg.services.scan_service import run_scan
|
|
25
|
+
from ipmg.services.scan_service import machine_output, run_scan
|
|
25
26
|
from ipmg.utils.helpers import configure_logging
|
|
26
27
|
|
|
27
28
|
EXIT_OK = 0
|
|
@@ -34,8 +35,16 @@ log = logging.getLogger(__name__)
|
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
def _scan_command(argv: List[str]) -> int:
|
|
37
|
-
|
|
38
|
+
parser = build_parser()
|
|
39
|
+
# Before parsing: the file supplies the defaults, so anything on the
|
|
40
|
+
# command line still overrides it.
|
|
41
|
+
config.apply(parser, build_parser, argv)
|
|
42
|
+
args = parser.parse_args(argv)
|
|
38
43
|
configure_logging(args.verbose)
|
|
44
|
+
if machine_output(args).enabled:
|
|
45
|
+
# Before the banner: with --json or --jsonl stdout carries the results
|
|
46
|
+
# and nothing else, so every line a person reads goes to stderr.
|
|
47
|
+
ui.use_stderr()
|
|
39
48
|
ui.header("scan")
|
|
40
49
|
print_disclaimer_once()
|
|
41
50
|
run_scan(args)
|