-
-
Notifications
You must be signed in to change notification settings - Fork 127
Expand file tree
/
Copy patheol_checker.py
More file actions
148 lines (119 loc) · 4.53 KB
/
Copy patheol_checker.py
File metadata and controls
148 lines (119 loc) · 4.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/env python3
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Fetch EOL dates from endoflife.date API for base images."""
import re
import sys
import urllib.request
import json
from datetime import date, datetime
ENDOFLIFE_API = "https://endoflife.date/api"
# Map os config values to endoflife.date product names
OS_TO_PRODUCT = {
"ubuntu": "ubuntu",
"alpine-linux": "alpine",
"ubi-minimal": "rhel",
}
# Regex to extract version from image string (e.g. "ubuntu:26.04" -> "26.04",
# "redhat/ubi9-minimal" -> "9", "alpine:3.24" -> "3.24")
IMAGE_VERSION_PATTERNS = [
# standard image:tag format
re.compile(r":(\d[\d.]*)$"),
# UBI images like redhat/ubi9-minimal -> extract major version
re.compile(r"/ubi(\d+)"),
]
def _extract_cycle(image):
"""Extract the version/cycle string from a Docker image reference."""
for pattern in IMAGE_VERSION_PATTERNS:
m = pattern.search(image)
if m:
return m.group(1)
return None
def fetch_eol_date(product, cycle):
"""Fetch the EOL date for a product cycle from endoflife.date.
Returns a date object or None if the lookup fails.
"""
url = f"{ENDOFLIFE_API}/{product}/{cycle}.json"
try:
req = urllib.request.Request(url, headers={"User-Agent": "Adoptium EOL Checker"})
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read().decode("utf-8"))
eol = data.get("eol")
if isinstance(eol, bool):
# Some products return eol: false (meaning not yet EOL)
return None
if eol:
return datetime.strptime(eol, "%Y-%m-%d").date()
except Exception:
pass
return None
def get_eol_date(configuration):
"""Get the EOL date for a configuration entry.
Priority:
1. Hardcoded 'eol' field in the config (as fallback/override)
2. Lookup from endoflife.date API based on os + image
"""
# Check for hardcoded override first
eol_str = configuration.get("eol")
if eol_str:
if isinstance(eol_str, date):
return eol_str
return datetime.strptime(str(eol_str), "%Y-%m-%d").date()
os_name = configuration.get("os", "")
image = configuration.get("image", "")
product = OS_TO_PRODUCT.get(os_name)
if not product:
return None
cycle = _extract_cycle(image)
if not cycle:
return None
return fetch_eol_date(product, cycle)
def check_eol_configs(config):
"""Check all configurations for EOL status.
Returns a list of (configuration, eol_date) tuples for entries past EOL.
"""
today = date.today()
expired = []
for os_family, configurations in config.get("configurations", {}).items():
for cfg in configurations:
eol_date = get_eol_date(cfg)
if eol_date and eol_date <= today:
expired.append((cfg, eol_date))
return expired
def print_eol_warnings(config, file=sys.stderr):
"""Print warnings for any expired distros. Returns the list of expired entries."""
expired = check_eol_configs(config)
if expired:
print(f"\n⚠ {len(expired)} distro(s) past EOL:", file=file)
for cfg, eol_date in expired:
image = cfg.get("image", cfg.get("directory", "unknown"))
directory = cfg.get("directory", "")
print(f" - {image} ({directory}) expired {eol_date}", file=file)
return expired
if __name__ == "__main__":
import yaml
with open("config/temurin.yml") as f:
config = yaml.safe_load(f)
print("Distro EOL dates:")
for os_family, configurations in config.get("configurations", {}).items():
for cfg in configurations:
image = cfg.get("image", cfg.get("directory", "unknown"))
eol = get_eol_date(cfg)
eol_str = str(eol) if eol else "unknown"
print(f" {image}: {eol_str}")
print()
expired = print_eol_warnings(config, file=sys.stdout)
if not expired:
print("All distros are within their EOL dates.")
sys.exit(1 if expired else 0)