Skip to content
This repository was archived by the owner on Mar 25, 2025. It is now read-only.

Commit a7ed8a2

Browse files
committed
refactored and kept some debug-toolkit utils
1 parent 8fd8401 commit a7ed8a2

14 files changed

+475
-17
lines changed

build_on_apple_m1.sh

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
docker buildx build \
2+
--platform linux/amd64 \
3+
--tag $IMAGE \
4+
--push \
5+
$BUILD_CONTEXT

cloudbuild.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
steps:
22
- name: 'gcr.io/cloud-builders/docker'
3-
args: ['build', '-t', 'gcr.io/genuine-flight-317411/java-toolkit-aux/jtk-11', '.']
3+
args: ['build', '-t', 'gcr.io/genuine-flight-317411/java-toolkit/jtk-11', '.']
44
- name: 'gcr.io/cloud-builders/docker'
5-
args: ['push', 'gcr.io/genuine-flight-317411/java-toolkit-aux/jtk-11']
6-
images: ['gcr.io/genuine-flight-317411/java-toolkit-aux/jtk-11']
5+
args: ['push', 'gcr.io/genuine-flight-317411/java-toolkit/jtk-11']
6+
images: ['gcr.io/genuine-flight-317411/java-toolkit/jtk-11']

configs.json

-9
This file was deleted.

debugger-pod.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ spec:
2424
type: Directory
2525
containers:
2626
- name: java-tk-11
27-
image: gcr.io/genuine-flight-317411/java-toolkit-aux/jtk-11
27+
image: gcr.io/genuine-flight-317411/java-toolkit/jtk-11
2828
imagePullPolicy: Always
2929
volumeMounts:
3030
- name: host-disk

dockerfile

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
FROM adoptopenjdk/openjdk11-openj9:jdk-11.0.13_8_openj9-0.29.0-debian
2+
RUN mkdir /app
3+
RUN cp -R /opt/java/openjdk /app
4+
5+
FROM python:3.8-slim-buster
26

37
RUN apt-get update \
48
&& apt-get install -y --no-install-recommends procps gdb git curl inotify-tools \
59
&& apt-get purge -y --auto-remove \
610
&& rm -rf /var/lib/apt/lists/*
711

12+
RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py | python -
13+
RUN /root/.local/bin/poetry config virtualenvs.create false
14+
COPY poetry.lock pyproject.toml /app/
815
WORKDIR /app/
9-
COPY ../../src /app/src
10-
CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait"
16+
RUN /root/.local/bin/poetry install --no-interaction --no-root
17+
18+
COPY src /app/src
19+
RUN /root/.local/bin/poetry install
1120

1221
#run on jenkens

poetry.lock

+300
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
[tool.poetry]
2-
name = "java-toolkit"
2+
name = "java_toolkit"
33
version = "0.1.0"
44
description = ""
55
authors = ["Avi <[email protected]>"]
6+
packages = [
7+
{ include = "java_toolkit", from = "src" },
8+
]
9+
10+
[tool.poetry.scripts]
11+
java-toolkit = "java_toolkit.main:app"
612

713
[tool.poetry.dependencies]
814
python = "^3.8"
15+
typer = "^0.4.0"
16+
psutil = "^5.9.0"
17+
pydantic = "^1.9.0"
918

1019
[tool.poetry.dev-dependencies]
1120
pytest = "^5.2"

src/java_toolkit/__init__.py

-1
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
__version__ = '0.1.0'

src/java_toolkit/configs.json

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"JDK_PATH": "/app/openjdk",
3+
"MKDIR_POD_CMD": "mkdir {DST_MOUNT_PATH}",
4+
"RMDIR_POD_CMD": "rm -R {DST_MOUNT_PATH}",
5+
"DST_MOUNT_PATH": "/proc/{PID}/cwd/mnt/robusta",
6+
"COPY_CMD": "cp -R {JDK_PATH} {DST_MOUNT_PATH}",
7+
"JDK_NAME": "openjdk",
8+
"JMAP_CMD": "{JDK_PATH}/bin/jmap -J-Xshareclasses:nonfatal -histo {LOCAL_PID}",
9+
"JSTACK_CMD": "{JDK_PATH}/bin/jstack -J-Xshareclasses:nonfatal -l {LOCAL_PID}",
10+
"NSENTER_CMD": "nsenter -t {PID} -p -m {CMD}"
11+
}

src/java_toolkit/main.py

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/usr/local/bin/python3
2+
import subprocess
3+
import typer
4+
from .utils.pod_ps import get_pod_processes
5+
import json
6+
from os.path import join
7+
8+
app = typer.Typer()
9+
app_configs = {}
10+
11+
12+
class JDKMounter:
13+
mnt_path =""
14+
verbose = False
15+
16+
def __init__(self, pid: str, verbose: bool):
17+
self.verbose = verbose
18+
self.mnt_path = app_configs['DST_MOUNT_PATH'].format(PID=pid)
19+
mkdir_cmd = app_configs['MKDIR_POD_CMD'].format(self.mnt_path)
20+
run_command(mkdir_cmd, verbose)
21+
22+
def get_mounted_jdk_dir(self):
23+
return join(self.mnt_path, app_configs['JDK_NAME'] )
24+
25+
def __del__(self):
26+
rm_dir_cmd = app_configs['RMDIR_POD_CMD'].format(self.mnt_path)
27+
run_command(rm_dir_cmd, self.verbose)
28+
29+
def run_cmd_in_proc_namespace(pid, command_to_run, verbose):
30+
nsenter_cmd_formatted = app_configs['NSENTER_CMD'].format(pid, command_to_run)
31+
run_command(nsenter_cmd_formatted, verbose)
32+
33+
def run_command(cmd: str, verbose: bool):
34+
if verbose:
35+
typer.echo(f"running {cmd}")
36+
output = subprocess.check_output(
37+
cmd, shell=True, stdin=subprocess.PIPE, stderr=subprocess.STDOUT
38+
)
39+
if verbose:
40+
typer.echo(output.decode())
41+
42+
def get_java_toolkit_configs():
43+
with open ('configs.json', "r") as json_file:
44+
return json.loads(json_file.read())
45+
46+
@app.command()
47+
def pod_ps(pod_uid: str):
48+
typer.echo(get_pod_processes(pod_uid).json())
49+
50+
@app.command()
51+
def find_pid(pod_uid: str, cmdline: str, exe: str):
52+
for proc in get_pod_processes(pod_uid).processes:
53+
if cmdline in " ".join(proc.cmdline) and exe in proc.exe:
54+
typer.echo(proc.pid)
55+
56+
@app.command()
57+
def jmap(pid: int, verbose: bool = False):
58+
with JDKMounter(pid, verbose) as jdk_mounter:
59+
jstack_cmd = app_configs['JMAP_CMD'].format(JDK_PATH=jdk_mounter.get_mounted_jdk_dir(), LOCAL_PID=1)
60+
run_cmd_in_proc_namespace(pid, jstack_cmd, verbose)
61+
62+
63+
@app.command()
64+
def jstack(pid: int, verbose: bool = False):
65+
with JDKMounter(pid, verbose) as jdk_mounter:
66+
jstack_cmd = app_configs['JSTACK_CMD'].format(JDK_PATH=jdk_mounter.get_mounted_jdk_dir(), LOCAL_PID=1)
67+
run_cmd_in_proc_namespace(pid, jstack_cmd, verbose)
68+
69+
if __name__ == "__main__":
70+
app_configs = get_java_toolkit_configs()
71+
app()
File renamed without changes.

src/java_toolkit/utils/pod_ps.py

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/usr/local/bin/python3
2+
import re
3+
from typing import List
4+
5+
import psutil
6+
import typer
7+
from pydantic import BaseModel
8+
9+
kube_regex = re.compile(r"\d+:.+:/kubepods/[^/]+/pod([^/]+)/([0-9a-f]{64})")
10+
docker_regex = re.compile(r"\d+:.+:/docker/pod([^/]+)/([0-9a-f]{64})")
11+
other_regex = re.compile(r"\d+:.+:/docker/.*/pod([^/]+)/([0-9a-f]{64})")
12+
other_regex2 = re.compile(r"\d+:.+:/kubepods/.*/pod([^/]+)/([0-9a-f]{64})")
13+
other_regex3 = re.compile(
14+
r"\d+:.+:/kubepods\.slice/kubepods-[^/]+\.slice/kubepods-[^/]+-pod([^/]+)\.slice/docker-([0-9a-f]{64})"
15+
)
16+
17+
app = typer.Typer()
18+
19+
20+
# TODO: split to pod and python subcommands
21+
22+
23+
class Process(BaseModel):
24+
pid: int
25+
exe: str
26+
cmdline: List[str]
27+
28+
29+
class ProcessList(BaseModel):
30+
processes: List[Process]
31+
32+
33+
def get_process_details(pid: int):
34+
# see https://man7.org/linux/man-pages/man7/cgroups.7.html
35+
try:
36+
path = "/proc/%d/cgroup" % (pid,)
37+
with open(path, "r") as f:
38+
lines = f.readlines()
39+
for line in lines:
40+
match = (
41+
kube_regex.match(line)
42+
or docker_regex.match(line)
43+
or other_regex.match(line)
44+
or other_regex2.match(line)
45+
or other_regex3.match(line)
46+
)
47+
if match is not None:
48+
# pod, container
49+
return match.group(1).replace("_", "-"), match.group(2)
50+
except Exception as e:
51+
print("exception:", e)
52+
return None, None
53+
54+
55+
def get_pod_processes(pod_uid: str) -> ProcessList:
56+
processes = []
57+
for pid in psutil.pids():
58+
this_pod_uid, container_uid = get_process_details(pid)
59+
if this_pod_uid is not None and this_pod_uid.lower() == pod_uid.lower():
60+
proc = psutil.Process(pid)
61+
processes.append(Process(pid=pid, exe=proc.exe(), cmdline=proc.cmdline()))
62+
return ProcessList(processes=processes)
63+

src/tests/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)