Skip to content

Commit f662fb2

Browse files
committed
update too add url params, output params and engine info
1 parent 0f6ea20 commit f662fb2

File tree

4 files changed

+388
-71
lines changed

4 files changed

+388
-71
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
################################################################################
2+
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
3+
################################################################################
4+
5+
/.vs

EnumEnvVars.py

Lines changed: 179 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,191 @@
1-
import requests
1+
#!/usr/bin/env python3
2+
import argparse
23
import json
4+
import sys
5+
from pathlib import Path
6+
7+
import requests
8+
from alive_progress import alive_bar
9+
10+
11+
DEFAULT_URL = "http://localhost:2375" # Docker Engine API (no auth; enable with care)
12+
13+
14+
def fmt_bytes(n: int) -> str:
15+
"""Human-friendly bytes."""
16+
units = ["B", "KB", "MB", "GB", "TB", "PB"]
17+
size = float(n)
18+
for u in units:
19+
if size < 1024.0:
20+
return f"{size:.1f} {u}"
21+
size /= 1024.0
22+
return f"{size:.1f} EB"
23+
324

4-
# Docker API URL (assuming Docker is running locally)
5-
DOCKER_API_URL = "http://localhost:2375"
25+
def get_engine_info(base_url: str, timeout: int = 10) -> dict:
26+
"""Return Docker Engine info from /info."""
27+
try:
28+
resp = requests.get(f"{base_url.rstrip('/')}/info", timeout=timeout)
29+
resp.raise_for_status()
30+
return resp.json()
31+
except requests.RequestException as e:
32+
print(f"[!] Failed to get engine info from {base_url}: {e}", file=sys.stderr)
33+
return {}
634

7-
def get_containers():
8-
# Get list of all containers
9-
response = requests.get(f"{DOCKER_API_URL}/containers/json?all=true")
10-
if response.status_code != 200:
11-
print("Failed to get containers")
35+
36+
def get_containers(base_url: str, timeout: int = 10):
37+
"""Return list of container summary objects (like `docker ps -a`)."""
38+
try:
39+
resp = requests.get(f"{base_url.rstrip('/')}/containers/json?all=true", timeout=timeout)
40+
resp.raise_for_status()
41+
return resp.json()
42+
except requests.RequestException as e:
43+
print(f"[!] Failed to get containers from {base_url}: {e}", file=sys.stderr)
1244
return []
13-
return response.json()
1445

15-
def get_container_env(container_id):
16-
# Get environment variables for a specific container
17-
response = requests.get(f"{DOCKER_API_URL}/containers/{container_id}/json")
18-
if response.status_code != 200:
19-
print(f"Failed to get info for container {container_id}")
46+
47+
def get_container_env(base_url: str, container_id: str, timeout: int = 10):
48+
"""Return list of Env strings for a container (e.g., ['KEY=VALUE', ...])."""
49+
try:
50+
resp = requests.get(f"{base_url.rstrip('/')}/containers/{container_id}/json", timeout=timeout)
51+
resp.raise_for_status()
52+
data = resp.json()
53+
return data.get("Config", {}).get("Env", []) or []
54+
except requests.RequestException as e:
55+
print(f"[!] Failed to get info for container {container_id[:12]}: {e}", file=sys.stderr)
2056
return []
21-
22-
container_data = response.json()
23-
env_vars = container_data.get('Config', {}).get('Env', [])
24-
return env_vars
57+
58+
59+
def parse_args():
60+
p = argparse.ArgumentParser(
61+
description="Enumerate Docker containers and print their environment variables."
62+
)
63+
p.add_argument(
64+
"--url",
65+
default=DEFAULT_URL,
66+
help=f"Docker Engine API base URL (default: {DEFAULT_URL})",
67+
)
68+
p.add_argument(
69+
"--out",
70+
metavar="FILE",
71+
help="Optional path to save results as JSON (e.g., results.json)",
72+
)
73+
p.add_argument(
74+
"--timeout",
75+
type=int,
76+
default=10,
77+
help="HTTP timeout in seconds (default: 10)",
78+
)
79+
p.add_argument(
80+
"--show-info-json",
81+
action="store_true",
82+
help="Also print the full /info JSON after the overview.",
83+
)
84+
return p.parse_args()
85+
86+
87+
def print_engine_overview(info: dict):
88+
"""Pretty, concise overview of key /info fields."""
89+
if not info:
90+
print("Engine Info: (unavailable)")
91+
return
92+
93+
server_ver = info.get("ServerVersion")
94+
os_name = info.get("OperatingSystem")
95+
os_type = info.get("OSType")
96+
arch = info.get("Architecture")
97+
ncpu = info.get("NCPU")
98+
mem = info.get("MemTotal")
99+
containers = info.get("Containers")
100+
images = info.get("Images")
101+
driver = info.get("Driver")
102+
swarm = info.get("Swarm", {})
103+
swarm_state = (swarm.get("LocalNodeState") or "inactive").lower()
104+
105+
print("=== Docker Engine Overview (/info) ===")
106+
print(f"Server Version : {server_ver}")
107+
print(f"OS / Arch : {os_name} ({os_type}/{arch})")
108+
print(f"CPUs / Memory : {ncpu} / {fmt_bytes(mem) if isinstance(mem, int) else mem}")
109+
print(f"Storage Driver : {driver}")
110+
print(f"Containers : {containers}")
111+
print(f"Images : {images}")
112+
print(f"Swarm State : {swarm_state}")
113+
if info.get("RegistryConfig", {}).get("InsecureRegistryCIDRs"):
114+
print("Insecure Registries configured")
115+
if info.get("ExperimentalBuild"):
116+
print("Experimental features: enabled")
117+
print("=" * 36)
118+
25119

26120
def main():
27-
containers = get_containers()
121+
args = parse_args()
122+
123+
# 1) Capture and print /info first
124+
engine_info = get_engine_info(args.url, timeout=args.timeout)
125+
print_engine_overview(engine_info)
126+
if args.show_info_json and engine_info:
127+
print(json.dumps(engine_info, indent=2))
128+
129+
# 2) Enumerate containers with a progress bar
130+
containers = get_containers(args.url, timeout=args.timeout)
28131
if not containers:
29132
print("No containers found.")
30-
return
31-
32-
for container in containers:
33-
container_id = container['Id']
34-
container_name = container['Names'][0]
35-
print(f"\nContainer Name: {container_name}")
36-
print(f"Container ID: {container_id}")
37-
38-
env_vars = get_container_env(container_id)
39-
if env_vars:
40-
print("Environment Variables:")
41-
for env in env_vars:
42-
print(f" - {env}")
43-
else:
44-
print("No environment variables found.")
133+
results = {"engine_info": engine_info, "containers": []}
134+
if args.out:
135+
try:
136+
Path(args.out).write_text(json.dumps(results, indent=2))
137+
print(f"\nSaved results to {Path(args.out).resolve()}")
138+
except Exception as e:
139+
print(f"[!] Failed to write output file '{args.out}': {e}", file=sys.stderr)
140+
return 2
141+
return 0
142+
143+
results = {"engine_info": engine_info, "containers": []}
144+
145+
print(f"Found {len(containers)} containers. Inspecting…")
146+
with alive_bar(len(containers), title="Investigating containers") as bar:
147+
for c in containers:
148+
container_id = c.get("Id", "") or ""
149+
names = c.get("Names") or []
150+
name = names[0] if names else ""
151+
if name.startswith("/"):
152+
name = name[1:]
153+
154+
env_vars = get_container_env(args.url, container_id, timeout=args.timeout)
155+
156+
# Print to stdout
157+
print(f"\nContainer Name: {name or '(unnamed)'}")
158+
print(f"Container ID: {container_id}")
159+
if env_vars:
160+
print("Environment Variables:")
161+
for env in env_vars:
162+
print(f" - {env}")
163+
else:
164+
print("No environment variables found.")
165+
166+
# Append to results
167+
results["containers"].append(
168+
{
169+
"id": container_id,
170+
"name": name,
171+
"env": env_vars,
172+
}
173+
)
174+
175+
bar() # advance progress
176+
177+
# 3) Save if requested
178+
if args.out:
179+
try:
180+
out_path = Path(args.out)
181+
out_path.write_text(json.dumps(results, indent=2))
182+
print(f"\nSaved results to {out_path.resolve()}")
183+
except Exception as e:
184+
print(f"[!] Failed to write output file '{args.out}': {e}", file=sys.stderr)
185+
return 2
186+
187+
return 0
188+
45189

46190
if __name__ == "__main__":
47-
main()
191+
sys.exit(main())

0 commit comments

Comments
 (0)