@@ -25,21 +25,22 @@ import (
25
25
var (
26
26
// Command-line flags
27
27
outputFile = flag .String ("output" , "api/versions/coredns.go" , "Output file path" )
28
- minKubernetesVersion = flag .String ("min-kubernetes-version" , "v1.22" , "Minimum Kubernetes version to include (semver format)" )
28
+ minKubernetesVersion = flag .String ("min-kubernetes-version" , "v1.22.0 " , "Minimum Kubernetes version to include (semver format)" )
29
29
)
30
30
31
31
const (
32
32
constantsURLTemplate = "https://raw.githubusercontent.com/kubernetes/kubernetes/%s/cmd/kubeadm/app/constants/constants.go"
33
33
branchesAPIURL = "https://api.github.com/repos/kubernetes/kubernetes/branches?per_page=100&page=%d"
34
34
)
35
35
36
- var goTemplate = `
37
- // Copyright 2024 Nutanix. All rights reserved.
38
- // SPDX-License-Identifier: Apache-2.0
39
- // Code generated by script; DO NOT EDIT. Run 'make coredns.sync' instead
36
+ var goTemplate = `// Code generated by script; DO NOT EDIT. Run 'make coredns.sync' instead
40
37
41
38
package versions
42
39
40
+ import (
41
+ "golang.org/x/mod/semver"
42
+ )
43
+
43
44
// Kubernetes versions
44
45
const (
45
46
{{- range .KubernetesConstants }}
@@ -55,26 +56,40 @@ const (
55
56
)
56
57
57
58
// kubernetesToCoreDNSVersion maps Kubernetes versions to CoreDNS versions.
59
+ // This map is unexported to prevent external modification.
58
60
var kubernetesToCoreDNSVersion = map[string]string{
59
61
{{- range .VersionMap }}
60
62
{{ .KubernetesConst }}: {{ .CoreDNSConst }},
61
63
{{- end }}
62
64
}
63
65
64
66
// GetCoreDNSVersion returns the CoreDNS version for a given Kubernetes version.
67
+ // It accepts versions with or without the "v" prefix and handles full semver versions.
68
+ // The function maps based on the major and minor versions (e.g., "v1.27").
65
69
// If the Kubernetes version is not found, it returns an empty string and false.
66
70
func GetCoreDNSVersion(kubernetesVersion string) (string, bool) {
67
- version, found := kubernetesToCoreDNSVersion[kubernetesVersion]
71
+ // Normalize the version using semver
72
+ normalizedVersion := semver.Canonical(kubernetesVersion)
73
+ if normalizedVersion == "" {
74
+ // Handle invalid version strings
75
+ return "", false
76
+ }
77
+
78
+ // Extract major and minor versions
79
+ majorMinor := semver.MajorMinor(normalizedVersion) // e.g., "v1.27"
80
+
81
+ // Lookup the CoreDNS version using the major and minor version
82
+ version, found := kubernetesToCoreDNSVersion[majorMinor]
68
83
return version, found
69
84
}
70
85
71
86
// GetKubernetesToCoreDNSVersionMap returns a copy of the Kubernetes to CoreDNS version mapping.
87
+ // The map keys are Kubernetes versions in "vMAJOR.MINOR" format.
72
88
func GetKubernetesToCoreDNSVersionMap() map[string]string {
73
89
copyMap := make(map[string]string, len(kubernetesToCoreDNSVersion))
74
90
for k, v := range kubernetesToCoreDNSVersion {
75
91
copyMap[k] = v
76
92
}
77
-
78
93
return copyMap
79
94
}
80
95
`
@@ -86,6 +101,10 @@ func main() {
86
101
if ! strings .HasPrefix (* minKubernetesVersion , "v" ) {
87
102
* minKubernetesVersion = "v" + * minKubernetesVersion
88
103
}
104
+ // Ensure minKubernetesVersion has patch version
105
+ if semver .Prerelease (* minKubernetesVersion ) == "" && semver .Build (* minKubernetesVersion ) == "" && len (strings .Split (semver .Canonical (* minKubernetesVersion ), "." )) == 2 {
106
+ * minKubernetesVersion += ".0"
107
+ }
89
108
90
109
versions , err := fetchKubernetesVersions (* minKubernetesVersion )
91
110
if err != nil {
@@ -117,20 +136,24 @@ func fetchKubernetesVersions(minVersion string) ([]string, error) {
117
136
if err != nil {
118
137
return nil , err
119
138
}
139
+
120
140
if len (branchNames ) == 0 {
121
141
break
122
142
}
143
+
123
144
for _ , branch := range branchNames {
124
145
if strings .HasPrefix (branch , "release-1." ) {
125
146
version := strings .TrimPrefix (branch , "release-" )
126
- semverVersion := "v" + version
147
+ semverVersion := "v" + version + ".0"
127
148
if semver .Compare (semverVersion , minVersion ) >= 0 {
128
149
versions = append (versions , version )
129
150
}
130
151
}
131
152
}
153
+
132
154
page ++
133
155
}
156
+
134
157
if len (versions ) == 0 {
135
158
return nil , errors .New ("no Kubernetes versions found" )
136
159
}
@@ -139,13 +162,16 @@ func fetchKubernetesVersions(minVersion string) ([]string, error) {
139
162
for _ , v := range versions {
140
163
versionSet [v ] = struct {}{}
141
164
}
165
+
142
166
versions = nil
143
167
for v := range versionSet {
144
168
versions = append (versions , v )
145
169
}
170
+
146
171
sort .Slice (versions , func (i , j int ) bool {
147
- return semver .Compare ("v" + versions [i ], "v" + versions [j ]) < 0
172
+ return semver .Compare ("v" + versions [i ]+ ".0" , "v" + versions [j ]+ ".0" ) < 0
148
173
})
174
+
149
175
return versions , nil
150
176
}
151
177
@@ -155,6 +181,7 @@ func fetchBranchNames(url string) ([]string, error) {
155
181
if err != nil {
156
182
return nil , fmt .Errorf ("HTTP GET error: %w" , err )
157
183
}
184
+
158
185
defer resp .Body .Close ()
159
186
160
187
if resp .StatusCode != http .StatusOK {
@@ -164,6 +191,7 @@ func fetchBranchNames(url string) ([]string, error) {
164
191
var branches []struct {
165
192
Name string `json:"name"`
166
193
}
194
+
167
195
if err := json .NewDecoder (resp .Body ).Decode (& branches ); err != nil {
168
196
return nil , fmt .Errorf ("decoding JSON error: %w" , err )
169
197
}
@@ -172,13 +200,13 @@ func fetchBranchNames(url string) ([]string, error) {
172
200
for _ , branch := range branches {
173
201
branchNames = append (branchNames , branch .Name )
174
202
}
203
+
175
204
return branchNames , nil
176
205
}
177
206
178
207
func fetchCoreDNSVersions (versions []string ) (map [string ]string , error ) {
179
208
versionMap := make (map [string ]string )
180
209
re := regexp .MustCompile (`CoreDNSVersion\s*=\s*"([^"]+)"` )
181
-
182
210
for _ , k8sVersion := range versions {
183
211
branch := "release-" + k8sVersion
184
212
url := fmt .Sprintf (constantsURLTemplate , branch )
@@ -187,7 +215,17 @@ func fetchCoreDNSVersions(versions []string) (map[string]string, error) {
187
215
fmt .Fprintf (os .Stderr , "Warning: Failed for Kubernetes %s: %v\n " , k8sVersion , err )
188
216
continue
189
217
}
190
- versionMap [k8sVersion ] = coreDNSVersion
218
+
219
+ // Normalize CoreDNS version using semver
220
+ coreDNSVersion = semver .Canonical (coreDNSVersion )
221
+ if coreDNSVersion == "" {
222
+ fmt .Fprintf (os .Stderr , "Warning: Invalid CoreDNS version '%s' for Kubernetes %s\n " , coreDNSVersion , k8sVersion )
223
+ continue
224
+ }
225
+ // Prefix Kubernetes version with "v" and add ".0" for patch version
226
+ fullVersion := "v" + k8sVersion + ".0"
227
+ majorMinor := semver .MajorMinor (fullVersion )
228
+ versionMap [majorMinor ] = coreDNSVersion
191
229
}
192
230
193
231
if len (versionMap ) == 0 {
@@ -202,6 +240,7 @@ func extractCoreDNSVersion(url string, re *regexp.Regexp) (string, error) {
202
240
if err != nil {
203
241
return "" , fmt .Errorf ("HTTP GET error: %w" , err )
204
242
}
243
+
205
244
defer resp .Body .Close ()
206
245
207
246
if resp .StatusCode != http .StatusOK {
@@ -218,7 +257,13 @@ func extractCoreDNSVersion(url string, re *regexp.Regexp) (string, error) {
218
257
return "" , errors .New ("CoreDNSVersion not found" )
219
258
}
220
259
221
- return matches [1 ], nil
260
+ // Ensure CoreDNS version includes "v" prefix
261
+ coreDNSVersion := matches [1 ]
262
+ if ! strings .HasPrefix (coreDNSVersion , "v" ) {
263
+ coreDNSVersion = "v" + coreDNSVersion
264
+ }
265
+
266
+ return coreDNSVersion , nil
222
267
}
223
268
224
269
func generateGoFile (versionMap map [string ]string , outputPath string ) error {
@@ -255,13 +300,13 @@ func prepareTemplateData(versionMap map[string]string) map[string]interface{} {
255
300
Name string
256
301
Version string
257
302
}
258
- var k8sConstants []Const
259
- var coreDNSConstants []Const
303
+
260
304
type versionMapEntry struct {
261
305
KubernetesVersion string
262
306
KubernetesConst string
263
307
CoreDNSConst string
264
308
}
309
+
265
310
var versionMapList []versionMapEntry
266
311
267
312
// Maps for deduplication
@@ -274,46 +319,48 @@ func prepareTemplateData(versionMap map[string]string) map[string]interface{} {
274
319
uniqueCoreDNSVersions [coreDNSVersion ] = struct {}{}
275
320
}
276
321
277
- // Generate constants for Kubernetes versions
278
- for k8sVersion := range versionMap {
279
- constName := versionToConst ("Kubernetes" , k8sVersion )
280
- k8sConstMap [k8sVersion ] = constName
281
- }
282
-
322
+ var k8sConstants []Const
323
+ var coreDNSConstants []Const
283
324
// Generate constants for CoreDNS versions
284
325
for coreDNSVersion := range uniqueCoreDNSVersions {
285
326
constName := versionToConst ("CoreDNS" , coreDNSVersion )
286
327
coreDNSConstMap [coreDNSVersion ] = constName
328
+ coreDNSConstants = append (coreDNSConstants , Const {Name : constName , Version : coreDNSVersion })
287
329
}
288
330
289
- // Prepare constants slices
290
- for k8sVersion , constName := range k8sConstMap {
291
- k8sConstants = append (k8sConstants , Const {Name : constName , Version : k8sVersion })
331
+ // Generate constants and mapping for Kubernetes versions
332
+ for k8sVersion := range versionMap {
333
+ // Constants and mapping use major.minor versions
334
+ majorMinor := semver .MajorMinor (k8sVersion )
335
+ if _ , exists := k8sConstMap [majorMinor ]; ! exists {
336
+ constName := versionToConst ("Kubernetes" , majorMinor )
337
+ k8sConstMap [majorMinor ] = constName
338
+ k8sConstants = append (k8sConstants , Const {Name : constName , Version : majorMinor })
339
+ }
292
340
}
293
- for coreDNSVersion , constName := range coreDNSConstMap {
294
- coreDNSConstants = append (coreDNSConstants , Const {Name : constName , Version : coreDNSVersion })
341
+
342
+ // Map Kubernetes constants to CoreDNS constants
343
+ for k8sVersion , coreDNSVersion := range versionMap {
344
+ majorMinor := semver .MajorMinor (k8sVersion )
345
+ versionMapList = append (versionMapList , versionMapEntry {
346
+ KubernetesVersion : majorMinor ,
347
+ KubernetesConst : k8sConstMap [majorMinor ],
348
+ CoreDNSConst : coreDNSConstMap [coreDNSVersion ],
349
+ })
295
350
}
296
351
297
352
// Sort constants
298
353
sort .Slice (k8sConstants , func (i , j int ) bool {
299
- return semver .Compare ("v" + k8sConstants [i ].Version , "v" + k8sConstants [j ].Version ) < 0
354
+ return semver .Compare (k8sConstants [i ].Version , k8sConstants [j ].Version ) < 0
300
355
})
356
+
301
357
sort .Slice (coreDNSConstants , func (i , j int ) bool {
302
358
return semver .Compare (coreDNSConstants [i ].Version , coreDNSConstants [j ].Version ) < 0
303
359
})
304
360
305
- // Map Kubernetes constants to CoreDNS constants
306
- for k8sVersion , coreDNSVersion := range versionMap {
307
- versionMapList = append (versionMapList , versionMapEntry {
308
- KubernetesVersion : k8sVersion ,
309
- KubernetesConst : k8sConstMap [k8sVersion ],
310
- CoreDNSConst : coreDNSConstMap [coreDNSVersion ],
311
- })
312
- }
313
-
314
361
// Sort version map
315
362
sort .Slice (versionMapList , func (i , j int ) bool {
316
- return semver .Compare ("v" + versionMapList [i ].KubernetesVersion , "v" + versionMapList [j ].KubernetesVersion ) < 0
363
+ return semver .Compare (versionMapList [i ].KubernetesVersion , versionMapList [j ].KubernetesVersion ) < 0
317
364
})
318
365
319
366
data := map [string ]interface {}{
@@ -327,9 +374,9 @@ func prepareTemplateData(versionMap map[string]string) map[string]interface{} {
327
374
328
375
func versionToConst (prefix , version string ) string {
329
376
// Remove 'v' prefix if present
330
- version = strings .TrimPrefix (version , "v" )
377
+ versionNoV : = strings .TrimPrefix (version , "v" )
331
378
// Replace dots with underscores
332
- version = strings .ReplaceAll (version , "." , "_" )
379
+ versionNoV = strings .ReplaceAll (versionNoV , "." , "_" )
333
380
// Prepend the prefix and 'V'
334
- return prefix + "_V" + version
381
+ return prefix + "_V" + versionNoV
335
382
}
0 commit comments