Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a script to auto add Kubernetes patch versions #4660

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 204 additions & 0 deletions .pipelines/scripts/auto_add_k8s_patch_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import json
import os
import urllib
import urllib.request

COMPONENTS_JSON_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../parts/linux/cloud-init/artifacts/components.json')


def main():
version_map = get_all_supported_k8s_patch_versions()
current_kube_proxy_image_tags = load_curent_kube_proxy_image_tags()
update_components_json_file_kubernetes_binaries(version_map)
update_components_json_file_kube_proxy_image_tags(version_map, current_kube_proxy_image_tags)
update_generate_windows_vhd_configuration_ps1(version_map)


def get_all_supported_k8s_patch_versions():
"""return a dict with major_minor version as key and all supported patch versions as value"""
return { k : [f'{k}.{patch}' for patch in calculate_supported_patches(k)] for k in load_curent_k8s_major_minor_versions()}


def get_kube_proxy_latest_image_tag(version):
with urllib.request.urlopen(f'https://azcu.azurewebsites.net/api/latest/oss/kubernetes/kube-proxy/v{version}', timeout=10) as resp:
data = resp.read().decode('utf-8')
return data


# Get the latest patch version for the given major.minor version, e.g. 1.30
def get_kube_proxy_latest_patch(major_minor_version):
latest_img_tag = get_kube_proxy_latest_image_tag(major_minor_version)
v = latest_img_tag.split('-')[0]
v_parts = v.split('.')
if len(v_parts) != 3:
raise ValueError(f'Invalid version format: {v}')
print(f'latest patch version for {major_minor_version} is {v}')
return int(v_parts[2])


# Load the current k8s major_minor versions from manifest.json file
def load_curent_k8s_major_minor_versions():
print(f'Loading current k8s major_minor versions from {COMPONENTS_JSON_FILE}')
with open(COMPONENTS_JSON_FILE) as f:
components = json.load(f)
major_minor_versions = set()
for package in components['Packages']:
if package['name'] == 'kubernetes-binaries':
for version in package['downloadURIs']['default']['current']['versions']:
major_minor_versions.add('.'.join(version.split('.')[:2]))
break
major_minor_versions = sorted(major_minor_versions)
print(f"found {len(major_minor_versions)} major_minor versions: {', '.join(major_minor_versions)}")
return major_minor_versions


def load_curent_kube_proxy_image_tags():
with open(COMPONENTS_JSON_FILE) as f:
components = json.load(f)
current_kube_proxy_image_tags = []
for container_image in components['ContainerImages']:
if container_image['downloadURL'] == 'mcr.microsoft.com/oss/kubernetes/kube-proxy:*':
for img in container_image['multiArchVersions']:
current_kube_proxy_image_tags.append(img)
break
return current_kube_proxy_image_tags


# we keep 3 latest patch version so we always have the latest 2 cached in VHD
# even RP didn't add the latest patch version yet
def update_components_json_file_kubernetes_binaries(version_map):
print(f"updating kubernetes-binaries in {COMPONENTS_JSON_FILE}")
versions = get_latest_n_patch_versions(version_map, 3)
for v in versions:
_make_sure_k8s_tar_exist(v)
tmp_file = COMPONENTS_JSON_FILE + '.tmp'
with open(COMPONENTS_JSON_FILE) as f, open(tmp_file, 'w') as tmp:
components = json.load(f)
kubernetes_binaries_index = -1
for idx, package in enumerate(components['Packages']):
if package['name'] == 'kubernetes-binaries':
kubernetes_binaries_index = idx
components['Packages'][kubernetes_binaries_index]['downloadURIs']['default']['current']['versions'] = versions
json.dump(components, tmp, indent=2)
tmp.write('\n')
os.replace(tmp_file, COMPONENTS_JSON_FILE)


def update_components_json_file_kube_proxy_image_tags(version_map, current_kube_proxy_image_tags):
print(f"updating kubernetes-proxy in {COMPONENTS_JSON_FILE}")
versions_need_cache = get_latest_n_patch_versions(version_map, 3)
current_kube_proxy_versions = set([_img_tag_to_version(img) for img in current_kube_proxy_image_tags])
tmp_file = COMPONENTS_JSON_FILE + '.tmp'
with open(COMPONENTS_JSON_FILE) as f, open(tmp_file, 'w') as tmp:
components = json.load(f)
kube_proxy_container_image_index = -1
for idx, container_image in enumerate(components['ContainerImages']):
if container_image['downloadURL'] == 'mcr.microsoft.com/oss/kubernetes/kube-proxy:*':
kube_proxy_container_image_index = idx
break

goal_image_tags = []
# delete patches that are not latest 3 patches
for img in current_kube_proxy_image_tags:
if _img_tag_to_version(img) in versions_need_cache:
goal_image_tags.append(img)
# add new if not exist
for v in versions_need_cache:
if v not in current_kube_proxy_versions:
latest_img = get_kube_proxy_latest_image_tag(v)
goal_image_tags.append(latest_img)
goal_image_tags.sort(key=lambda x: tuple(map(int, _img_tag_to_version(x).split('.'))))

components['ContainerImages'][kube_proxy_container_image_index]['multiArchVersions'] = goal_image_tags
json.dump(components, tmp, indent=2)
tmp.write('\n')
os.replace(tmp_file, COMPONENTS_JSON_FILE)


def calculate_supported_patches(major_minor_version):
"""
we start to support all patch versions since 1.27.13, 1.28.9, 1.29.4 and 1.30+ clusters,
before that, we support:
1.27: [1, 3, 7, 9, 13]
1.28: [0, 3, 5, 9]
1.29: [0, 2, 4]
"""
part_supported_patches = {
'1.27': [1, 3, 7, 9, 13],
'1.28': [0, 3, 5, 9],
'1.29': [0, 2, 4],
}
# extend to latest patch version
latest_patch = get_kube_proxy_latest_patch(major_minor_version)
if major_minor_version in part_supported_patches:
supported_patches = part_supported_patches[major_minor_version]
for patch in range(supported_patches[-1] + 1, latest_patch + 1):
supported_patches.append(patch)
else:
supported_patches = list(range(0, latest_patch + 1))
return supported_patches


def get_latest_n_patch_versions(version_map, n):
"""return the latest n patch versions from version_map"""
versions = []
for patches in version_map.values():
lastest_n = patches[-n:]
versions.extend(lastest_n)
return sorted(versions, key=lambda x: tuple(map(int, x.split('.'))))


def update_generate_windows_vhd_configuration_ps1(version_map):
"""
update ../../vhdbuilder/packer/generate-windows-vhd-configuration.ps1, replace content between '__AUTO_ADD_START_' and 'AUTO_ADD_END__' lines with:
"https://acs-mirror.azureedge.net/kubernetes/v{version}/windowszip/v{version}-1int.zip",
where version is from versions list
we keep 4 latest patch versions in windows vhd
"""
print("updating generate-windows-vhd-configuration.ps1 file")
versions = get_latest_n_patch_versions(version_map, 4)
for v in versions:
_make_sure_windowszip_exist(v)
ps1_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../vhdbuilder/packer/generate-windows-vhd-configuration.ps1')
# open a temp file to write the updated content, then replace the original file
tmp_file = ps1_file + '.tmp'
with open(ps1_file) as f, open(tmp_file, 'w') as tmp:
for line in f:
if '__AUTO_ADD_START__' in line:
tmp.write(line)
tmp.write(' ')
tmp.write(',\n '.join([f'"https://acs-mirror.azureedge.net/kubernetes/v{version}/windowszip/v{version}-1int.zip"' for version in versions]))
line = f.readline()
while '__AUTO_ADD_END__' not in line:
line = f.readline()
pass
tmp.write('\n')
tmp.write(line)
else:
tmp.write(line)
os.replace(tmp_file, ps1_file)


def _img_tag_to_version(img_tag):
return img_tag.split('-')[0].lstrip('v')

def _make_sure_k8s_tar_exist(version):
print(f'checking k8s tar file for version {version}')
url = f'https://acs-mirror.azureedge.net/kubernetes/v{version}/binaries/kubernetes-node-linux-amd64.tar.gz'
if _http_head_request_status_code(url) != 200:
raise ValueError(f'k8s tar file not found for version {version}')

def _make_sure_windowszip_exist(version):
print(f'checking windows zip file for version {version}')
url = f'https://acs-mirror.azureedge.net/kubernetes/v{version}/windowszip/v{version}-1int.zip'
if _http_head_request_status_code(url) != 200:
raise ValueError(f'windows zip file not found for version {version}')

def _http_head_request_status_code(url):
req = urllib.request.Request(url, method='HEAD')
resp = urllib.request.urlopen(req, timeout=10)
return resp.status


if __name__ == '__main__':
main()
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -220,4 +220,8 @@ unit-tests:
validate-components:
@./hack/tools/bin/cue vet -c ./schemas/components.cue ./vhdbuilder/packer/components.json

.PHONY: auto-add-k8s-patch-versions
auto-add-k8s-patch-versions:
python3 ./.pipelines/scripts/auto_add_k8s_patch_version.py

include versioning.mk
21 changes: 10 additions & 11 deletions parts/linux/cloud-init/artifacts/components.json
Original file line number Diff line number Diff line change
Expand Up @@ -388,20 +388,18 @@
"downloadURL": "mcr.microsoft.com/oss/kubernetes/kube-proxy:*",
"amd64OnlyVersions": [],
"multiArchVersions": [
"v1.27.13",
"v1.27.13-2",
"v1.27.14-1",
"v1.27.15",
"v1.27.16",
"v1.28.10-1",
"v1.28.9",
"v1.28.9-1",
"v1.28.11",
"v1.29.4",
"v1.29.4-1",
"v1.28.12",
"v1.29.5-1",
"v1.29.6",
"v1.29.7",
"v1.30.1-1",
"v1.30.2-hotfix.20240613"
"v1.30.2-hotfix.20240613",
"v1.30.3"
]
}
],
Expand Down Expand Up @@ -518,17 +516,18 @@
"default": {
"current": {
"versions": [
"1.27.13",
"1.27.14",
"1.27.15",
"1.28.9",
"1.27.16",
"1.28.10",
"1.28.11",
"1.29.4",
"1.28.12",
"1.29.5",
"1.29.6",
"1.29.7",
"1.30.1",
"1.30.2"
"1.30.2",
"1.30.3"
],
"downloadURL": "https://acs-mirror.azureedge.net/kubernetes/v${version}/binaries/kubernetes-node-linux-${CPU_ARCH}.tar.gz"
}
Expand Down
15 changes: 11 additions & 4 deletions vhdbuilder/packer/generate-windows-vhd-configuration.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -167,20 +167,27 @@ $global:map = @{
# 2. Keep 1.18.10, 1.18.14, 1.18.17, 1.18.18
# 3. Keep v1.18.17-hotfix.20210322 when adding v1.18.17-hotfix.20210505
"c:\akse-cache\win-k8s\" = @(
"https://acs-mirror.azureedge.net/kubernetes/v1.27.9/windowszip/v1.27.9-1int.zip",
# latest unsupported minor versions, if we have enough space in vhd, keep 2 latest patches
# supported minor versions, keep 4 latest patches:
# __AUTO_ADD_START__
"https://acs-mirror.azureedge.net/kubernetes/v1.27.13/windowszip/v1.27.13-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.27.14/windowszip/v1.27.14-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.27.15/windowszip/v1.27.15-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.28.5/windowszip/v1.28.5-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.27.16/windowszip/v1.27.16-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.28.9/windowszip/v1.28.9-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.28.10/windowszip/v1.28.10-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.28.11/windowszip/v1.28.11-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.29.2/windowszip/v1.29.2-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.28.12/windowszip/v1.28.12-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.29.4/windowszip/v1.29.4-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.29.5/windowszip/v1.29.5-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.29.6/windowszip/v1.29.6-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.29.7/windowszip/v1.29.7-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.30.0/windowszip/v1.30.0-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.30.1/windowszip/v1.30.1-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.30.2/windowszip/v1.30.2-1int.zip"
"https://acs-mirror.azureedge.net/kubernetes/v1.30.2/windowszip/v1.30.2-1int.zip",
"https://acs-mirror.azureedge.net/kubernetes/v1.30.3/windowszip/v1.30.3-1int.zip"
# __AUTO_ADD_END__
# hotfix versions:
);
"c:\akse-cache\win-vnet-cni\" = @(
# Azure CNI v1 (legacy)
Expand Down
Loading