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

Adds helm chart to app version matrix #1714

Merged
merged 5 commits into from
Jan 3, 2024
Merged
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ node_modules
.DS_Store
tmp
.idea
bin
bin/htmltest
12 changes: 11 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ serve-api.linkerd.io: build-api.linkerd.io
&& python3 -m http.server 9999

.PHONY: build-linkerd.io
build-linkerd.io: get-versions tmp/linkerd.io
build-linkerd.io: build-release-matrix get-versions tmp/linkerd.io
@# Build linkerd.io
ifndef HAS_HUGO
@printf "Install hugo first. For OSX: brew install hugo\n"; exit 1
Expand Down Expand Up @@ -140,10 +140,20 @@ replace-env-%: has-env-% tmp-sites
sed 's/$*/$($*)/g' < $$fname > /tmp/__sed && mv /tmp/__sed $$fname; \
done

.PHONY: build-release-matrix
build-release-matrix:
@# Build release matrix
./bin/generate_release_matrix.py --release_type=stable --format=json > linkerd.io/data/releases/release_matrix.json
./bin/generate_release_matrix.py --release_type=stable --format=yaml > linkerd.io/content/releases/release_matrix.yaml
cp linkerd.io/data/releases/release_matrix.json linkerd.io/content/releases/release_matrix.json


.PHONY: has-env-%
has-env-%:
@if [ ! $${$*:-} ]; then printf "You must define: $*\n" && exit 1; fi

.PHONY: clean
clean:
rm -rf tmp


292 changes: 292 additions & 0 deletions bin/generate_release_matrix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
#!/usr/bin/env python3
# Author: Corey Osman <[email protected]>
# Purpose: Geneate a list in specified format of all the linkerd charts by app version
# Usage: ./generate_release_matrix.py [--format=json|table|yaml] [--update_repo]
# Notes: Help determine which charts go with which app versions
# Notes: This is primary aimed at the stable release only, although a slight modification
# could yeild support for edge and Enterprise releases too. Right now edge versions
# follow date schemes and the manual mappings do not work


import subprocess
import json
import yaml
import argparse


charts = [
# "linkerd2", # This makes the search return results for everything
"linkerd2-cni",
"linkerd-viz",
"linkerd-control-plane",
"linkerd-jaeger",
"linkerd-multicluster",
"linkerd-failover",
]

# these versions are old and do not have the proper mappings anyways
ignored_y_versions = [6, 7, 8, 9]

# Manually map in the old chart, otherwise we get duplicates mixed in
linkerd2_map = {
'2.11': {
"linkerd2": {
"chart_name": "linkerd2",
"chart_version": "2.11.5",
"chart_url": "https://artifacthub.io/packages/helm/linkerd2/linkerd2/2.11.5"
}
},
'2.10': {
"linkerd2": {
"chart_name": "linkerd2",
"chart_version": "2.10.2",
"chart_url": "https://artifacthub.io/packages/helm/linkerd2/linkerd2/2.10.2"
}
}
}
# Manually map in the crds because there is no app version associated with them
crds_map = {
"2.12": {
"linkerd-crds": {
"chart_name": "linkerd-crds",
"chart_version": "1.6.1",
"chart_url": "https://artifacthub.io/packages/helm/linkerd2/linkerd-crds/1.6.1"
}
},
"2.13": {
"linkerd-crds": {
"chart_name": "linkerd-crds",
"chart_version": "1.6.1",
"chart_url": "https://artifacthub.io/packages/helm/linkerd2/linkerd-crds/1.6.1"
}
},
"2.14": {
"linkerd-crds": {
"chart_name": "linkerd-crds",
"chart_version": "1.8.0",
"chart_url": "https://artifacthub.io/packages/helm/linkerd2/linkerd-crds/1.8.0"
}
},
}


def find_newest_versions(versions):
"""
Finds the newest version with the highest X value for a given Y version

Parameters:
versions (list): A list of version objects
Example: [('linkerd2/linkerd2', '2.11.5', 'stable-2.11.5'), ('linkerd2/linkerd2', '2.11.4', 'stable-2.11.4')

Returns:
list: A list of version objects
Example: [('linkerd2/linkerd2', '2.11.5', 'stable-2.11.5'),
('linkerd2/linkerd2', '2.10.2', 'stable-2.10.2'),
('linkerd2/linkerd2', '30.12.1', 'stable-2.14.3'),
('linkerd2/linkerd2', '30.8.5', 'stable-2.13.7'),
('linkerd2/linkerd2', '30.3.8', 'stable-2.12.6'),
('linkerd2/linkerd2', '2.11.5', 'stable-2.11.5'),
('linkerd2/linkerd2', '2.10.2', 'stable-2.10.2')]

"""
winners = {}
for entry in versions:
_, _, version, _ = entry
try:
x, y, z = map(int, version.split("-")[1].split("."))
if not y in ignored_y_versions:
current_winner = winners.get(
f"{x}.{y}.Z", {"x": x, "y": y, "z": z, version: version}
)
if current_winner["y"] == y and z >= current_winner["z"]:
# new winner
winners[f"{x}.{y}.Z"] = {"x": x, "y": y, "z": z, "version": version}

except IndexError:
next
except UnboundLocalError:
next

latest_versions = [v["version"] for v in winners.values()]
common_versions = []

for version in versions:
if version[2] in latest_versions:
common_versions.append(version)

return common_versions


def combine_charts_by_app_version(versions):
"""
Gathers all charts tuples under a single app version

Parameters:
versions (list): Raw list of versions tuples
[('linkerd2/linkerd-control-plane', '1.12.7', 'stable-2.13.7'),
('linkerd2/linkerd-control-plane', '1.16.4', 'stable-2.14.3'),
('linkerd2/linkerd-control-plane', '1.9.8', 'stable-2.12.6')]

Returns:
dict: versions object after combing under an app version.
{'stable-2.13.7':
{'linkerd2-crds':
{'chart_name': 'linkerd2/linkerd2-crds', 'chart_version': '1.6.1'},
'linkerd-jaeger': {
'chart_name': 'linkerd2/linkerd-jaeger', 'chart_version': '30.8.7'}
}
}

"""
combined_charts = {}
for chart, version, app_version, link in versions:
name = chart # chart.split("/")[1]

if not app_version:
app_version = version
if not combined_charts.get(app_version):
combined_charts[app_version] = {}

combined_charts[app_version][name] = {
"chart_name": chart,
"chart_version": version,
"chart_url": link
}
# merge in the crds chart info if it exist for the version
x, y, z = map(int, app_version.split("-")[1].split("."))
try:
if y > 11 and x == 2:
combined_charts[app_version] = {**combined_charts[app_version], **crds_map[f"{x}.{y}"]}
elif x == 2:
combined_charts[app_version] = {**combined_charts[app_version], **linkerd2_map[f"{x}.{y}"]}
except KeyError as e:
print(e)

# sorted(combined_charts.items(), key=lambda x: x[0] != "stable-2.11.5")
return combined_charts

def find_repo_name(release_type):
if release_type == "stable":
repo_name = "linkerd2"
elif release_type == "edge":
repo_name = "linkerd2-edge"
else:
repo_name = "linkerd2"

return repo_name

def add_repo(release_type, helm_url, repo_name):
command = ["helm", "repo", "add", repo_name, f"{helm_url}/{release_type}"]

try:
process = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
)
stdout, stderr = process.communicate()

except OSError as e:
print(f"Error: {e}")

return repo_name


def update_repo(release_type, helm_url, repo_name):
add_repo(release_type, helm_url, repo_name)

command = ["helm", "repo", "update", repo_name]

try:
process = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
)
stdout, stderr = process.communicate()

except OSError as e:
print(f"Error: {e}")

return repo_name

def list_chart_versions(charts, repo_name, latest_only=True):
"""
Fetches all the linkerd charts

Parameters:
charts (list): A list of chart names to fetch

Returns:
dict: A list of chart version tuples
Example: {('linkerd2/linkerd2', '2.11.5', 'stable-2.11.5')}

"""
all_versions = set()


for chart in charts:
# helm repo update linkerd2
search_term = f"{repo_name}/{chart}"
command = ["helm", "search", "repo", search_term, "--versions", "--output", "json"]
try:
process = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
)
stdout, stderr = process.communicate()

if process.returncode == 0:
chart_data = json.loads(stdout)
versions = [
(chart, item["version"], item["app_version"], f"https://artifacthub.io/packages/helm/{repo_name}/{chart}/{item['version']}") for item in chart_data
]
if latest_only:
latest_versions = find_newest_versions(versions)
else:
latest_versions = versions

all_versions.update(latest_versions)
else:
print(f"Error: Failed to list chart versions for {chart}")
print(stderr)
except OSError as e:
print(f"Error: {e}")

return sorted(all_versions)


def print_output(data, format):
if format == "json":
print(json.dumps(data, indent=4))
elif format == "yaml":
print(yaml.dump(data, indent=4))
else:
try:
from tabulate import tabulate
except ImportError as e:
print("Please install tabulate: pip3 install tabulate")
exit(1)
headers = ["App Version", "Chart Name", "Chart Version"]
table = []
for app_version, charts in sorted(
data.items(), reverse=True
):
for chart_name, chart_data in charts.items():
table.append(
[app_version, chart_data["chart_name"], chart_data["chart_version"]]
)
print(tabulate(table, headers=headers, tablefmt="github"))
print("\n")
table = []


parser = argparse.ArgumentParser(description="List linkerd chart versions in various formats")
parser.add_argument(
"--format", default="table", choices=["table", "json", "yaml"], help="Desired Output format, defaults to table"
)
parser.add_argument('--release_type', choices=["stable", "edge"], default="stable", help="Use the specific release type, defaults to stable")
parser.add_argument('--helm_url', choices=["https://helm.linkerd.io"], default="https://helm.linkerd.io", help="The helm url to use" )
args = parser.parse_args()

repo_name = find_repo_name(args.release_type)
update_repo(args.release_type, args.helm_url, repo_name)

all_versions = list_chart_versions(charts, repo_name)
combined_charts_by_app_version = combine_charts_by_app_version(all_versions)
print_output(combined_charts_by_app_version, args.format)
12 changes: 12 additions & 0 deletions linkerd.io/content/releases/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ bugfixes or enhancements.
Commercial providers of Linkerd (e.g. [Buoyant](https://buoyant.io)) may
provide stronger support guarantees.

## Helm Version Matrix

The following version matrices include only the latest versions of the stable
releases along with corresponding app and helm versions for linkerd and
extensions. Use these to guide you to the right helm chart version or to
automate workflows you might have.

* [YAML matrix](./release_matrix.yaml)
* [JSON matrix](./release_matrix.json)

{{< release-data-table />}}

## Edge (latest version: {{% latestedge %}})

Edge releases are frequent (usually, weekly) and can be used to work with the
Expand Down
Loading
Loading