Skip to content

Commit b533601

Browse files
authored
Merge pull request #2 from kahirokunn/index-v0.21.2
🌱 Update helm chart index.yaml to v0.21.2
2 parents c773386 + 3be163b commit b533601

File tree

4 files changed

+324
-42
lines changed

4 files changed

+324
-42
lines changed

.github/workflows/smoke-test.yaml

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
name: Smoke Test
2+
3+
on:
4+
pull_request:
5+
branches: [main, 'release-*']
6+
push:
7+
branches: [main]
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: read
12+
13+
env:
14+
CLUSTER_NAME: capi-quickstart
15+
KIND_CLUSTER_NAME: capi-operator-smoke-test
16+
KUBERNETES_VERSION: v1.33.0
17+
CONTROLLER_IMG: cluster-api-operator
18+
TAG: smoke-test
19+
20+
jobs:
21+
smoke-test:
22+
runs-on: ubuntu-latest
23+
steps:
24+
- name: Checkout code
25+
uses: actions/checkout@v4
26+
with:
27+
fetch-depth: 0
28+
29+
- name: Set up Go
30+
uses: actions/setup-go@v5
31+
with:
32+
go-version-file: 'go.mod'
33+
34+
- name: Install tools
35+
run: |
36+
# kubectl
37+
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
38+
chmod +x kubectl && sudo mv kubectl /usr/local/bin/
39+
40+
# yq
41+
wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O yq
42+
chmod +x yq && sudo mv yq /usr/local/bin/
43+
44+
# helm
45+
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
46+
47+
# clusterctl
48+
curl -L https://github.com/kubernetes-sigs/cluster-api/releases/latest/download/clusterctl-linux-amd64 -o clusterctl
49+
chmod +x clusterctl && sudo mv clusterctl /usr/local/bin/
50+
51+
- name: Build Docker image
52+
run: |
53+
make docker-build
54+
docker tag ${CONTROLLER_IMG}-amd64:${TAG} ${CONTROLLER_IMG}:${TAG}
55+
56+
- name: Build charts
57+
run: |
58+
make release-chart
59+
echo "HELM_CHART_TAG=$(make -s -f Makefile -p | grep '^HELM_CHART_TAG :=' | cut -d' ' -f3)" >> $GITHUB_ENV
60+
61+
- name: Create kind cluster
62+
run: |
63+
chmod +x ./hack/ensure-kind.sh
64+
./hack/ensure-kind.sh
65+
66+
cat <<EOF > /tmp/kind-config.yaml
67+
kind: Cluster
68+
apiVersion: kind.x-k8s.io/v1alpha4
69+
networking:
70+
ipFamily: ipv4
71+
nodes:
72+
- role: control-plane
73+
extraMounts:
74+
- hostPath: /var/run/docker.sock
75+
containerPath: /var/run/docker.sock
76+
containerdConfigPatches:
77+
- |-
78+
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
79+
endpoint = ["https://mirror.gcr.io", "https://registry-1.docker.io"]
80+
EOF
81+
82+
kind create cluster --name ${KIND_CLUSTER_NAME} --config /tmp/kind-config.yaml --wait 5m
83+
kind load docker-image ${CONTROLLER_IMG}:${TAG} --name ${KIND_CLUSTER_NAME}
84+
85+
- name: Install cert-manager
86+
run: |
87+
helm repo add jetstack https://charts.jetstack.io
88+
helm repo update
89+
helm install cert-manager jetstack/cert-manager \
90+
--namespace cert-manager \
91+
--create-namespace \
92+
--set installCRDs=true \
93+
--wait \
94+
--timeout 5m
95+
96+
- name: Install Cluster API Operator
97+
run: |
98+
CHART_PACKAGE="out/package/cluster-api-operator-${HELM_CHART_TAG}.tgz"
99+
helm install capi-operator "$CHART_PACKAGE" \
100+
--create-namespace \
101+
-n capi-operator-system \
102+
--set image.manager.repository=${CONTROLLER_IMG} \
103+
--set image.manager.tag=${TAG} \
104+
--set image.manager.pullPolicy=IfNotPresent \
105+
--wait \
106+
--timeout 90s
107+
108+
- name: Deploy providers
109+
run: |
110+
cat <<EOF > /tmp/providers-values.yaml
111+
core:
112+
cluster-api:
113+
namespace: capi-system
114+
bootstrap:
115+
kubeadm:
116+
namespace: capi-kubeadm-bootstrap-system
117+
controlPlane:
118+
kubeadm:
119+
namespace: capi-kubeadm-control-plane-system
120+
infrastructure:
121+
docker:
122+
namespace: capd-system
123+
manager:
124+
featureGates:
125+
core:
126+
ClusterTopology: true
127+
ClusterResourceSet: true
128+
MachinePool: true
129+
kubeadm:
130+
ClusterTopology: true
131+
MachinePool: true
132+
docker:
133+
ClusterTopology: true
134+
EOF
135+
136+
PROVIDERS_CHART_PACKAGE="out/package/cluster-api-operator-providers-${HELM_CHART_TAG}.tgz"
137+
helm install capi-providers "$PROVIDERS_CHART_PACKAGE" -f /tmp/providers-values.yaml --wait
138+
139+
- name: Wait for providers
140+
run: |
141+
kubectl wait --for=condition=Ready --timeout=300s -n capi-system coreprovider/cluster-api
142+
kubectl wait --for=condition=Ready --timeout=300s -n capi-kubeadm-bootstrap-system bootstrapprovider/kubeadm
143+
kubectl wait --for=condition=Ready --timeout=300s -n capi-kubeadm-control-plane-system controlplaneprovider/kubeadm
144+
kubectl wait --for=condition=Ready --timeout=300s -n capd-system infrastructureprovider/docker
145+
146+
kubectl wait --for=condition=Available --timeout=300s -n capi-system deployment/capi-controller-manager
147+
kubectl wait --for=condition=Available --timeout=300s -n capi-kubeadm-bootstrap-system deployment/capi-kubeadm-bootstrap-controller-manager
148+
kubectl wait --for=condition=Available --timeout=300s -n capi-kubeadm-control-plane-system deployment/capi-kubeadm-control-plane-controller-manager
149+
kubectl wait --for=condition=Available --timeout=300s -n capd-system deployment/capd-controller-manager
150+
151+
- name: Verify providers
152+
run: |
153+
kubectl get coreprovider,bootstrapprovider,controlplaneprovider,infrastructureprovider -A
154+
kubectl get pods -A | grep -E "(capi-|capd-)"
155+
156+
- name: Create workload cluster
157+
run: |
158+
clusterctl generate cluster ${CLUSTER_NAME} \
159+
--infrastructure docker:v1.10.0 \
160+
--flavor development \
161+
--kubernetes-version ${KUBERNETES_VERSION} \
162+
--control-plane-machine-count=1 \
163+
--worker-machine-count=2 \
164+
> capi-quickstart.yaml
165+
166+
kubectl apply -f capi-quickstart.yaml
167+
168+
- name: Get workload cluster kubeconfig
169+
run: |
170+
timeout 300s bash -c "until kubectl get secret ${CLUSTER_NAME}-kubeconfig -n default &>/dev/null; do sleep 2; done"
171+
clusterctl get kubeconfig ${CLUSTER_NAME} --namespace default > ${CLUSTER_NAME}.kubeconfig
172+
echo "KUBECONFIG=$(pwd)/${CLUSTER_NAME}.kubeconfig" >> $GITHUB_ENV
173+
174+
- name: Wait for workload cluster API server
175+
run: |
176+
timeout 300s bash -c "until kubectl cluster-info &>/dev/null; do sleep 5; done"
177+
178+
- name: Install CNI
179+
run: |
180+
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml
181+
kubectl wait --for=condition=Ready --timeout=300s pods -n tigera-operator -l app.kubernetes.io/name=tigera-operator || true
182+
kubectl wait --for=condition=Ready --timeout=300s pods -n calico-system --all || true
183+
184+
- name: Wait for nodes
185+
run: |
186+
kubectl wait --for=condition=Ready --timeout=300s nodes --all
187+
kubectl get nodes -o wide
188+
189+
- name: Verify cluster
190+
run: |
191+
kubectl get po -A
192+
kubectl wait --for=condition=Ready --timeout=300s pods -n kube-system -l k8s-app=kube-proxy
193+
kubectl wait --for=condition=Ready --timeout=300s pods -n kube-system -l component=kube-apiserver
194+
kubectl wait --for=condition=Ready --timeout=300s pods -n kube-system -l component=kube-controller-manager
195+
kubectl wait --for=condition=Ready --timeout=300s pods -n kube-system -l component=kube-scheduler
196+
197+
- name: Collect logs on failure
198+
if: failure()
199+
run: |
200+
echo "=== Recent Events ==="
201+
kubectl get events -A --sort-by='.lastTimestamp' | tail -50
202+
203+
echo -e "\n=== Provider Logs ==="
204+
kubectl logs -n capi-operator-system deployment/capi-operator-cluster-api-operator --tail=50 || true
205+
kubectl logs -n capi-system deployment/capi-controller-manager --tail=50 || true
206+
kubectl logs -n capd-system deployment/capd-controller-manager --tail=50 || true
207+
208+
echo -e "\n=== Cluster Resources ==="
209+
kubectl get cluster,dockercluster,kubeadmcontrolplane,machine,dockermachine -A -o wide || true
210+
211+
echo -e "\n=== Failed Pods ==="
212+
kubectl get pods -A | grep -v Running | grep -v Completed || true
213+
214+
if [ -f "${CLUSTER_NAME}.kubeconfig" ]; then
215+
export KUBECONFIG=$(pwd)/${CLUSTER_NAME}.kubeconfig
216+
echo -e "\n=== Workload Cluster Status ==="
217+
kubectl get nodes -o wide || true
218+
kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded || true
219+
fi
220+
221+
- name: Cleanup
222+
if: always()
223+
run: |
224+
kind delete cluster --name ${CLUSTER_NAME} || true
225+
kind delete cluster --name ${KIND_CLUSTER_NAME} || true

hack/chart-update/main.go

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,24 @@ const (
2424
repoName = "cluster-api-operator"
2525
)
2626

27+
// chartInfo represents information about a chart to be processed
28+
type chartInfo struct {
29+
name string
30+
description string
31+
}
32+
33+
// List of charts to process
34+
var charts = []chartInfo{
35+
{
36+
name: "cluster-api-operator",
37+
description: "Cluster API Operator",
38+
},
39+
{
40+
name: "cluster-api-operator-providers",
41+
description: "Cluster API Provider Custom Resources",
42+
},
43+
}
44+
2745
func main() {
2846
fmt.Println("🚀 Starting index.yaml update tool")
2947

@@ -38,45 +56,66 @@ func main() {
3856

3957
fmt.Println("⚙️ Loading index.yaml file from repo root directory")
4058

41-
indexFile := loadIndexFile(tag)
59+
indexFile := loadIndexFile()
60+
61+
fmt.Println("🔎 Finding chart archives in release assets")
4262

43-
fmt.Println("🔎 Finding chart archive in release assets")
63+
// Get all release assets once
64+
releaseAssets := getReleaseAssets(tag)
4465

45-
chartAsset := findChartReleaseAsset(tag)
66+
// Process each chart
67+
processedCharts := 0
68+
for _, chartInfo := range charts {
69+
fmt.Printf("\n📊 Processing chart: %s\n", chartInfo.name)
4670

47-
fmt.Println("📦 Downloading chart archive to a temp directory")
71+
// Check if chart already exists in index
72+
if _, err := indexFile.Get(chartInfo.name, tag[1:]); err == nil {
73+
fmt.Printf("✅ Chart %s already exists in index file, skipping\n", chartInfo.name)
74+
continue
75+
}
4876

49-
archivePath, chart := downloadChart(chartAsset)
77+
// Find chart asset
78+
chartAsset := findChartAsset(releaseAssets, chartInfo.name, tag)
79+
if chartAsset == nil {
80+
fmt.Printf("⚠️ Chart archive for %s not found in release assets, skipping\n", chartInfo.name)
81+
continue
82+
}
83+
84+
fmt.Printf("📦 Downloading %s chart archive to a temp directory\n", chartInfo.name)
85+
archivePath, chart := downloadChart(chartAsset)
86+
87+
fmt.Printf("👉🏻 Adding %s entry to index.yaml\n", chartInfo.name)
88+
addEntryToIndexFile(indexFile, chartAsset, archivePath, chart)
89+
90+
processedCharts++
91+
}
5092

51-
fmt.Println("👉🏻 Adding entry to index.yaml")
52-
addEntryToIndexFile(indexFile, chartAsset, archivePath, chart)
93+
if processedCharts == 0 {
94+
fmt.Println("\n⚠️ No new charts were added to index.yaml")
95+
os.Exit(0)
96+
}
5397

54-
fmt.Println("📝 Writing index.yaml file to repo root directory")
98+
fmt.Println("\n📝 Writing index.yaml file to repo root directory")
5599

56100
if err := indexFile.WriteFile(indexFilePath, 0644); err != nil {
57101
fmt.Println("❌ Error writing index file: ", err)
58102
os.Exit(1)
59103
}
60104

61-
fmt.Println("✅ Done updating index.yaml file")
105+
fmt.Printf("\n✅ Done updating index.yaml file. Added %d chart(s)\n", processedCharts)
62106
}
63107

64-
func loadIndexFile(tag string) *repo.IndexFile {
108+
func loadIndexFile() *repo.IndexFile {
65109
indexFile, err := repo.LoadIndexFile(indexFilePath)
66110
if err != nil {
67111
fmt.Println("❌ Error loading index file: ", err)
68112
os.Exit(1)
69113
}
70114

71-
if _, err := indexFile.Get(repoName, tag[1:]); err == nil {
72-
fmt.Println("✅ Chart already exists in index file, no need to update")
73-
os.Exit(0)
74-
}
75-
76115
return indexFile
77116
}
78117

79-
func findChartReleaseAsset(tag string) *github.ReleaseAsset {
118+
func getReleaseAssets(tag string) []*github.ReleaseAsset {
80119
ghClient := github.NewClient(nil)
81120

82121
release, _, err := ghClient.Repositories.GetReleaseByTag(context.TODO(), gitHubOrgName, repoName, tag)
@@ -85,22 +124,19 @@ func findChartReleaseAsset(tag string) *github.ReleaseAsset {
85124
os.Exit(1)
86125
}
87126

88-
chartAsset := &github.ReleaseAsset{}
89-
found := false
90-
for _, asset := range release.Assets {
91-
if *asset.Name == fmt.Sprintf("%s-%s.tgz", repoName, tag[1:]) {
92-
chartAsset = asset
93-
found = true
94-
break
95-
}
96-
}
127+
return release.Assets
128+
}
97129

98-
if !found {
99-
fmt.Printf("❌ Chart archive not found in release assets for release %s, please check if release was published correctly\n", tag)
100-
os.Exit(1)
130+
func findChartAsset(assets []*github.ReleaseAsset, chartName, tag string) *github.ReleaseAsset {
131+
expectedFileName := fmt.Sprintf("%s-%s.tgz", chartName, tag[1:])
132+
133+
for _, asset := range assets {
134+
if *asset.Name == expectedFileName {
135+
return asset
136+
}
101137
}
102138

103-
return chartAsset
139+
return nil
104140
}
105141

106142
func downloadChart(chartAsset *github.ReleaseAsset) (string, *chart.Chart) {

0 commit comments

Comments
 (0)