Skip to content

Commit fe6f783

Browse files
zhangeamonzhangeamon
authored andcommitted
2 parents 6a02513 + 1b980ad commit fe6f783

10 files changed

Lines changed: 294 additions & 34 deletions

File tree

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ ENV PATH "/usr/local/python/bin:${PATH}"
6969

7070
ADD requirements.txt /tmp/requirements.txt
7171

72-
RUN UPX_VERSION=4.1.0; \
72+
RUN UPX_VERSION=5.0.2; \
7373
OS_ARCH=$(dpkg --print-architecture); \
7474
wget https://github.com/upx/upx/releases/download/v${UPX_VERSION}/upx-${UPX_VERSION}-${OS_ARCH}_linux.tar.xz; \
7575
tar -Jxvf upx-${UPX_VERSION}-${OS_ARCH}_linux.tar.xz; \

scripts/checker.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
"name": "jmx_exporter",
6161
"type": "github",
6262
"owner": "prometheus",
63-
"match": "^parent-[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$",
63+
"match": "^[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$",
6464
},
6565
"caddy": {
6666
"name": "caddy",
@@ -158,18 +158,6 @@
158158
"owner": "kubernetes",
159159
"match": "^kubernetes-[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$",
160160
},
161-
"mc": {
162-
"name": "mc",
163-
"type": "github",
164-
"owner": "minio",
165-
"match": "^RELEASE\.[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2}Z$",
166-
},
167-
"minio": {
168-
"name": "minio",
169-
"type": "github",
170-
"owner": "minio",
171-
"match": "^RELEASE\.[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2}Z$",
172-
},
173161
"nginx": {
174162
"name": "nginx",
175163
"type": "github",
@@ -224,6 +212,12 @@
224212
"owner": "rabbitmq",
225213
"match": "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$",
226214
},
215+
"rclone": {
216+
"name": "rclone",
217+
"type": "github",
218+
"owner": "rclone",
219+
"match": "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$",
220+
},
227221
"redis": {
228222
"name": "redis",
229223
"type": "github",
@@ -374,8 +368,14 @@
374368
"owner": "opensearch-project",
375369
"match": "^[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$",
376370
},
371+
"rustfs": {
372+
"name": "rustfs",
373+
"type": "github",
374+
"owner": "rustfs",
375+
"match": "^[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$",
376+
},
377377
"opentelemetry-collector": {
378-
"name": "opentelemetry-collector",
378+
"name": "opentelemetry-collector-releases",
379379
"type": "github",
380380
"owner": "open-telemetry",
381381
"match": "^v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$",
@@ -458,6 +458,18 @@
458458
"owner": "drycc-addons",
459459
"match": "v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$",
460460
},
461+
"headscale": {
462+
"name": "headscale",
463+
"type": "github",
464+
"owner": "juanfont",
465+
"match": "v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$",
466+
},
467+
"tailscale": {
468+
"name": "tailscale",
469+
"type": "github",
470+
"owner": "tailscale",
471+
"match": "v[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$",
472+
},
461473
}
462474

463475

scripts/cleaner.py

Lines changed: 183 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
#!/usr/bin/env python3
22
"""
3-
Git Repository Cleaner
3+
Git Repository Cleaner and OSS Stack Cleaner
44
5-
This script provides various cleanup operations for git repositories and GitHub issues.
5+
This script provides various cleanup operations for git repositories, GitHub issues,
6+
and OSS stack files.
67
78
Usage:
89
python cleaner.py tags -n 3 [--dry-run] [--confirm]
910
python cleaner.py issues --max-issues 100 [--dry-run]
11+
python cleaner.py oss-stacks -n 3 [--dry-run]
1012
"""
1113

1214
import argparse
1315
import subprocess
1416
import sys
1517
import os
1618
import requests
19+
import oss2
20+
import re
1721
from collections import defaultdict
1822
from typing import List, Dict, Tuple
23+
from packaging import version
1924

2025

2126
def run_command(command: List[str], dry_run: bool = False) -> str:
@@ -286,6 +291,164 @@ def _close_issue(issue_number: int, issue_title: str, headers: Dict[str, str]) -
286291
print(f"Error closing issue #{issue_number}: {e}")
287292

288293

294+
def parse_oss_filename(filename: str) -> Tuple[str, str, str]:
295+
s0, s1 = filename.split("/")[-1].split("-linux-")
296+
def parse_version(full_name):
297+
parts = full_name.split('-')
298+
for i in range(len(parts)):
299+
potential_version = '-'.join(parts[i:])
300+
try:
301+
version.parse(potential_version)
302+
software_name = '-'.join(parts[:i]) if i > 0 else None
303+
return software_name, potential_version
304+
except version.InvalidVersion:
305+
continue
306+
raise ValueError(f"Could not parse version from {full_name}")
307+
os_name = s1.rstrip('.tar.gz')
308+
stack_name, stack_version = parse_version(s0)
309+
return stack_name, stack_version, os_name
310+
311+
312+
def clean_oss_stacks(args):
313+
"""Clean up old OSS stack files, keeping only the latest n versions per stack per OS."""
314+
# Initialize OSS bucket
315+
try:
316+
bucket = oss2.Bucket(
317+
oss2.Auth(
318+
os.environ.get("OSS_ACCESS_KEY_ID"),
319+
os.environ.get("OSS_ACCESS_KEY_SECRET"),
320+
),
321+
os.environ.get("OSS_ENDPOINT", "http://oss-accelerate.aliyuncs.com"),
322+
'drycc'
323+
)
324+
except Exception as e:
325+
print(f"Error initializing OSS bucket: {e}")
326+
sys.exit(1)
327+
328+
# List all objects in the stacks directory
329+
print("Listing OSS objects...")
330+
object_keys = []
331+
try:
332+
for obj in oss2.ObjectIterator(bucket, prefix='stacks/'):
333+
if obj.key.endswith('.tar.gz'):
334+
object_keys.append(obj.key)
335+
except Exception as e:
336+
print(f"Error listing OSS objects: {e}")
337+
sys.exit(1)
338+
339+
if not object_keys:
340+
print("No stack files found in OSS")
341+
return
342+
343+
print(f"Found {len(object_keys)} stack files")
344+
345+
# Handle suffix-based deletion
346+
if hasattr(args, 'subfix') and args.subfix is not None:
347+
print(f"OSS Stack Cleaner - Deleting files with suffix: {args.subfix}")
348+
349+
# Find files matching the suffix
350+
files_to_delete = []
351+
for obj_key in object_keys:
352+
# Check if the filename ends with the specified suffix
353+
filename = obj_key.split('/')[-1] # Get just the filename part
354+
if filename.endswith(args.subfix):
355+
files_to_delete.append(obj_key)
356+
357+
if not files_to_delete:
358+
print(f"No files found matching suffix: {args.subfix}")
359+
return
360+
361+
print(f"\nFound {len(files_to_delete)} files to delete:")
362+
for obj_key in sorted(files_to_delete):
363+
print(f" - {obj_key}")
364+
365+
# Confirm deletion
366+
if not args.dry_run:
367+
response = input(f"\nDelete these {len(files_to_delete)} files? (y/N): ")
368+
if response.lower() != 'y':
369+
print("Aborted by user")
370+
return
371+
372+
# Delete files
373+
success_count = 0
374+
for obj_key in files_to_delete:
375+
try:
376+
if args.dry_run:
377+
print(f"[DRY RUN] Would delete: {obj_key}")
378+
else:
379+
bucket.delete_object(obj_key)
380+
print(f"Deleted: {obj_key}")
381+
success_count += 1
382+
except Exception as e:
383+
print(f"Error deleting {obj_key}: {e}", file=sys.stderr)
384+
385+
print(f"\nCompleted: {success_count}/{len(files_to_delete)} files processed")
386+
return
387+
388+
# Handle keep-count based deletion (existing logic)
389+
if hasattr(args, 'keep_count') and args.keep_count is not None:
390+
if args.keep_count < 1:
391+
print("Error: keep-count must be at least 1", file=sys.stderr)
392+
sys.exit(1)
393+
print(f"OSS Stack Cleaner - Keeping {args.keep_count} latest versions per stack per OS")
394+
395+
# Parse and group files by stack and OS
396+
stack_os_files = defaultdict(list)
397+
398+
for obj_key in object_keys:
399+
try:
400+
stack_name, stack_version, os_name = parse_oss_filename(obj_key)
401+
package_version = version.parse(stack_version)
402+
main_version = f"{package_version.major}.{package_version.micro}"
403+
stack_os_files[(stack_name, os_name, main_version)].append((obj_key, stack_version))
404+
except ValueError as e:
405+
print(f"Warning: Skipping invalid filename {obj_key}: {e}")
406+
continue
407+
408+
# Sort versions for each stack-OS combination (newest first)
409+
for key in stack_os_files:
410+
stack_os_files[key].sort(key=lambda x: version.parse(x[1]), reverse=True)
411+
412+
# Determine which files to delete
413+
files_to_delete = []
414+
415+
for (stack_name, os_name, _), files in stack_os_files.items():
416+
if len(files) > args.keep_count:
417+
# Keep the first n files (newest), delete the rest
418+
files_to_delete.extend([file_info[0] for file_info in files[args.keep_count:]])
419+
print(f"Stack '{stack_name}' OS '{os_name}': keeping {args.keep_count} versions, deleting {len(files) - args.keep_count}")
420+
421+
if not files_to_delete:
422+
print("No files to delete - all stacks have <= {} versions per OS".format(args.keep_count))
423+
return
424+
425+
print(f"\nFound {len(files_to_delete)} files to delete:")
426+
for obj_key in sorted(files_to_delete):
427+
print(f" - {obj_key}")
428+
429+
# Confirm deletion
430+
if not args.dry_run:
431+
response = input(f"\nDelete these {len(files_to_delete)} files? (y/N): ")
432+
if response.lower() != 'y':
433+
print("Aborted by user")
434+
return
435+
436+
# Delete files
437+
success_count = 0
438+
for obj_key in files_to_delete:
439+
try:
440+
if args.dry_run:
441+
print(f"[DRY RUN] Would delete: {obj_key}")
442+
else:
443+
bucket.delete_object(obj_key)
444+
print(f"Deleted: {obj_key}")
445+
success_count += 1
446+
except Exception as e:
447+
print(f"Error deleting {obj_key}: {e}", file=sys.stderr)
448+
449+
print(f"\nCompleted: {success_count}/{len(files_to_delete)} files processed")
450+
451+
289452
def main():
290453
parser = argparse.ArgumentParser(
291454
description='Git repository cleaner with various cleanup operations',
@@ -297,6 +460,10 @@ def main():
297460
python cleaner.py tags -n 2 --confirm # Skip confirmation prompt
298461
python cleaner.py issues --max-issues 50 # Keep 50 most recent issues
299462
python cleaner.py issues --dry-run # Preview issue cleanup
463+
python cleaner.py oss-stacks -n 3 # Keep 3 latest versions per stack per OS
464+
python cleaner.py oss-stacks -n 2 --dry-run # Preview OSS stack cleanup
465+
python cleaner.py oss-stacks -s linux-arm64-debian-12.tar.gz # Delete files with specific suffix
466+
python cleaner.py oss-stacks -s linux-amd64-debian-12.tar.gz --dry-run # Preview suffix-based deletion
300467
301468
Note: Issues cleanup requires admin permissions to delete issues.
302469
If deletion fails, issues will be closed instead.
@@ -321,6 +488,18 @@ def main():
321488
issues_parser.add_argument('--dry-run', action='store_true',
322489
help='Only print commands without executing them')
323490

491+
# OSS stacks cleanup parser
492+
oss_parser = subparsers.add_parser('oss-stacks', help='Clean up old OSS stack files')
493+
oss_parser.add_argument('--dry-run', action='store_true',
494+
help='Only print commands without executing them')
495+
496+
# Make -n and -s mutually exclusive
497+
oss_group = oss_parser.add_mutually_exclusive_group(required=True)
498+
oss_group.add_argument('-n', '--keep-count', type=int,
499+
help='Number of latest versions to keep for each stack per OS')
500+
oss_group.add_argument('-s', '--subfix', type=str,
501+
help='Suffix pattern to match files for deletion (e.g., linux-arm64-debian-12.tar.gz)')
502+
324503
args = parser.parse_args()
325504

326505
if not args.action:
@@ -331,6 +510,8 @@ def main():
331510
clean_tags(args)
332511
elif args.action == 'issues':
333512
clean_github_issues(args)
513+
elif args.action == 'oss-stacks':
514+
clean_oss_stacks(args)
334515
else:
335516
parser.error(f"Unknown action: {args.action}")
336517

scripts/storage.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,34 @@ def upload_list(stack_name, dist_dir):
4949

5050

5151
def symlink(stack_name, version):
52+
53+
def get_system_version(obj_key):
54+
_, system, system_version = obj_key.strip(".tar.gz").rsplit("-", 2)
55+
return f"{system}-{system_version}"
56+
5257
object_list = [
5358
obj.key for obj in bucket.list_objects(
5459
f"stacks/{stack_name}/{stack_name}-{version}.").object_list
5560
]
5661
prefix = f"stacks/{stack_name}/{stack_name}-"
57-
version_list = sorted(
58-
[obj.replace(prefix, "").split("-", 1)[0] for obj in object_list],
59-
key=parse,
60-
reverse=True,
61-
)
62+
# Build a map of system-version to object keys
63+
version_map = {}
64+
for obj in object_list:
65+
system = get_system_version(obj)
66+
if system not in version_map:
67+
version_map[system] = [obj]
68+
else:
69+
version_map[system].append(obj)
70+
for key, value in version_map.items():
71+
version_list = sorted(
72+
[obj.replace(prefix, "").split("-", 1)[0] for obj in value],
73+
key=parse,
74+
reverse=True,
75+
)
76+
version_map[key] = version_list
77+
6278
for obj in object_list:
79+
version_list = version_map[get_system_version(obj)]
6380
if obj.startswith(f"{prefix}{version_list[0]}-"):
6481
symlink = re.sub(r"%s.([0-9]\.?){1,}" % f"{prefix}{version}", f"{prefix}{version}", obj)
6582
bucket.put_symlink(obj, symlink)
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ function build() {
88
generate-stack-path
99
BIN_DIR="${DATA_DIR}"/bin
1010
mkdir -p "${BIN_DIR}"
11-
version=$(echo ${STACK_VERSION} | awk -F "." '{print "RELEASE."$1"-"$2"-"$3"T"$4"-"$5"-"$6"Z"}')
12-
curl -fsSL -o "${BIN_DIR}"/"${STACK_NAME}" https://dl.min.io/client/mc/release/linux-${OS_ARCH}/archive/mc.${version}
11+
curl -fsSL "https://github.com/juanfont/headscale/releases/download/v${STACK_VERSION}/headscale_${STACK_VERSION}_linux_${OS_ARCH}" -o "${BIN_DIR}/${STACK_NAME}"
1312
chmod +x "${BIN_DIR}"/"${STACK_NAME}"
13+
# upx
14+
upx --lzma --best "${BIN_DIR}"/*
1415
}
1516

1617
# call build stack

stacks/jmx_exporter/build.sh

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ function build() {
88
generate-stack-path
99
BIN_DIR="${DATA_DIR}"/bin
1010
mkdir -p "${BIN_DIR}"
11-
curl -fsSL -o tmp.tar.gz https://github.com/prometheus/jmx_exporter/archive/refs/tags/parent-${STACK_VERSION}.tar.gz
11+
curl -fsSL -o tmp.tar.gz https://github.com/prometheus/jmx_exporter/archive/refs/tags/${STACK_VERSION}.tar.gz
1212
tar -xzf tmp.tar.gz
13-
mv jmx_exporter-parent-${STACK_VERSION}/example_configs/ "${DATA_DIR}"
14-
rm -rf jmx_exporter-parent-${STACK_VERSION} jmx_exporter-${STACK_VERSION}.linux-${OS_ARCH} tmp.tar.gz
15-
curl -fsSL -o "${DATA_DIR}"/jmx_prometheus_httpserver.jar https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_httpserver/${STACK_VERSION}/jmx_prometheus_httpserver-${STACK_VERSION}.jar
16-
curl -fsSL -o "${DATA_DIR}"/jmx_prometheus_javaagent.jar https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/${STACK_VERSION}/jmx_prometheus_javaagent-${STACK_VERSION}.jar
13+
mv jmx_exporter-${STACK_VERSION}/examples/ "${DATA_DIR}"
14+
rm -rf jmx_exporter-${STACK_VERSION} jmx_exporter-${STACK_VERSION}.linux-${OS_ARCH} tmp.tar.gz
15+
curl -fsSL -o "${DATA_DIR}"/jmx_prometheus_standalone.jar https://github.com/prometheus/jmx_exporter/releases/download/${STACK_VERSION}/jmx_prometheus_standalone-${STACK_VERSION}.jar
16+
curl -fsSL -o "${DATA_DIR}"/jmx_prometheus_javaagent.jar https://github.com/prometheus/jmx_exporter/releases/download/${STACK_VERSION}/jmx_prometheus_javaagent-${STACK_VERSION}.jar
17+
curl -fsSL -o "${DATA_DIR}"/jmx_prometheus_isolator_javaagent.jar https://github.com/prometheus/jmx_exporter/releases/download/${STACK_VERSION}/jmx_prometheus_isolator_javaagent-${STACK_VERSION}.jar
1718
}
1819

1920
# call build stack

0 commit comments

Comments
 (0)