@@ -25,21 +25,22 @@ import (
2525var (
2626 // Command-line flags
2727 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)" )
2929)
3030
3131const (
3232 constantsURLTemplate = "https://raw.githubusercontent.com/kubernetes/kubernetes/%s/cmd/kubeadm/app/constants/constants.go"
3333 branchesAPIURL = "https://api.github.com/repos/kubernetes/kubernetes/branches?per_page=100&page=%d"
3434)
3535
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
4037
4138package versions
4239
40+ import (
41+ "golang.org/x/mod/semver"
42+ )
43+
4344// Kubernetes versions
4445const (
4546{{- range .KubernetesConstants }}
@@ -55,26 +56,40 @@ const (
5556)
5657
5758// kubernetesToCoreDNSVersion maps Kubernetes versions to CoreDNS versions.
59+ // This map is unexported to prevent external modification.
5860var kubernetesToCoreDNSVersion = map[string]string{
5961{{- range .VersionMap }}
6062 {{ .KubernetesConst }}: {{ .CoreDNSConst }},
6163{{- end }}
6264}
6365
6466// 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").
6569// If the Kubernetes version is not found, it returns an empty string and false.
6670func 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]
6883 return version, found
6984}
7085
7186// GetKubernetesToCoreDNSVersionMap returns a copy of the Kubernetes to CoreDNS version mapping.
87+ // The map keys are Kubernetes versions in "vMAJOR.MINOR" format.
7288func GetKubernetesToCoreDNSVersionMap() map[string]string {
7389 copyMap := make(map[string]string, len(kubernetesToCoreDNSVersion))
7490 for k, v := range kubernetesToCoreDNSVersion {
7591 copyMap[k] = v
7692 }
77-
7893 return copyMap
7994}
8095`
@@ -86,6 +101,10 @@ func main() {
86101 if ! strings .HasPrefix (* minKubernetesVersion , "v" ) {
87102 * minKubernetesVersion = "v" + * minKubernetesVersion
88103 }
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+ }
89108
90109 versions , err := fetchKubernetesVersions (* minKubernetesVersion )
91110 if err != nil {
@@ -117,20 +136,24 @@ func fetchKubernetesVersions(minVersion string) ([]string, error) {
117136 if err != nil {
118137 return nil , err
119138 }
139+
120140 if len (branchNames ) == 0 {
121141 break
122142 }
143+
123144 for _ , branch := range branchNames {
124145 if strings .HasPrefix (branch , "release-1." ) {
125146 version := strings .TrimPrefix (branch , "release-" )
126- semverVersion := "v" + version
147+ semverVersion := "v" + version + ".0"
127148 if semver .Compare (semverVersion , minVersion ) >= 0 {
128149 versions = append (versions , version )
129150 }
130151 }
131152 }
153+
132154 page ++
133155 }
156+
134157 if len (versions ) == 0 {
135158 return nil , errors .New ("no Kubernetes versions found" )
136159 }
@@ -139,13 +162,16 @@ func fetchKubernetesVersions(minVersion string) ([]string, error) {
139162 for _ , v := range versions {
140163 versionSet [v ] = struct {}{}
141164 }
165+
142166 versions = nil
143167 for v := range versionSet {
144168 versions = append (versions , v )
145169 }
170+
146171 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
148173 })
174+
149175 return versions , nil
150176}
151177
@@ -155,6 +181,7 @@ func fetchBranchNames(url string) ([]string, error) {
155181 if err != nil {
156182 return nil , fmt .Errorf ("HTTP GET error: %w" , err )
157183 }
184+
158185 defer resp .Body .Close ()
159186
160187 if resp .StatusCode != http .StatusOK {
@@ -164,6 +191,7 @@ func fetchBranchNames(url string) ([]string, error) {
164191 var branches []struct {
165192 Name string `json:"name"`
166193 }
194+
167195 if err := json .NewDecoder (resp .Body ).Decode (& branches ); err != nil {
168196 return nil , fmt .Errorf ("decoding JSON error: %w" , err )
169197 }
@@ -172,13 +200,13 @@ func fetchBranchNames(url string) ([]string, error) {
172200 for _ , branch := range branches {
173201 branchNames = append (branchNames , branch .Name )
174202 }
203+
175204 return branchNames , nil
176205}
177206
178207func fetchCoreDNSVersions (versions []string ) (map [string ]string , error ) {
179208 versionMap := make (map [string ]string )
180209 re := regexp .MustCompile (`CoreDNSVersion\s*=\s*"([^"]+)"` )
181-
182210 for _ , k8sVersion := range versions {
183211 branch := "release-" + k8sVersion
184212 url := fmt .Sprintf (constantsURLTemplate , branch )
@@ -187,7 +215,17 @@ func fetchCoreDNSVersions(versions []string) (map[string]string, error) {
187215 fmt .Fprintf (os .Stderr , "Warning: Failed for Kubernetes %s: %v\n " , k8sVersion , err )
188216 continue
189217 }
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
191229 }
192230
193231 if len (versionMap ) == 0 {
@@ -202,6 +240,7 @@ func extractCoreDNSVersion(url string, re *regexp.Regexp) (string, error) {
202240 if err != nil {
203241 return "" , fmt .Errorf ("HTTP GET error: %w" , err )
204242 }
243+
205244 defer resp .Body .Close ()
206245
207246 if resp .StatusCode != http .StatusOK {
@@ -218,7 +257,13 @@ func extractCoreDNSVersion(url string, re *regexp.Regexp) (string, error) {
218257 return "" , errors .New ("CoreDNSVersion not found" )
219258 }
220259
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
222267}
223268
224269func generateGoFile (versionMap map [string ]string , outputPath string ) error {
@@ -255,13 +300,13 @@ func prepareTemplateData(versionMap map[string]string) map[string]interface{} {
255300 Name string
256301 Version string
257302 }
258- var k8sConstants []Const
259- var coreDNSConstants []Const
303+
260304 type versionMapEntry struct {
261305 KubernetesVersion string
262306 KubernetesConst string
263307 CoreDNSConst string
264308 }
309+
265310 var versionMapList []versionMapEntry
266311
267312 // Maps for deduplication
@@ -274,46 +319,48 @@ func prepareTemplateData(versionMap map[string]string) map[string]interface{} {
274319 uniqueCoreDNSVersions [coreDNSVersion ] = struct {}{}
275320 }
276321
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
283324 // Generate constants for CoreDNS versions
284325 for coreDNSVersion := range uniqueCoreDNSVersions {
285326 constName := versionToConst ("CoreDNS" , coreDNSVersion )
286327 coreDNSConstMap [coreDNSVersion ] = constName
328+ coreDNSConstants = append (coreDNSConstants , Const {Name : constName , Version : coreDNSVersion })
287329 }
288330
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+ }
292340 }
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+ })
295350 }
296351
297352 // Sort constants
298353 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
300355 })
356+
301357 sort .Slice (coreDNSConstants , func (i , j int ) bool {
302358 return semver .Compare (coreDNSConstants [i ].Version , coreDNSConstants [j ].Version ) < 0
303359 })
304360
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-
314361 // Sort version map
315362 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
317364 })
318365
319366 data := map [string ]interface {}{
@@ -327,9 +374,9 @@ func prepareTemplateData(versionMap map[string]string) map[string]interface{} {
327374
328375func versionToConst (prefix , version string ) string {
329376 // Remove 'v' prefix if present
330- version = strings .TrimPrefix (version , "v" )
377+ versionNoV : = strings .TrimPrefix (version , "v" )
331378 // Replace dots with underscores
332- version = strings .ReplaceAll (version , "." , "_" )
379+ versionNoV = strings .ReplaceAll (versionNoV , "." , "_" )
333380 // Prepend the prefix and 'V'
334- return prefix + "_V" + version
381+ return prefix + "_V" + versionNoV
335382}
0 commit comments