-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathget_ocp_range.go
138 lines (119 loc) · 5.01 KB
/
get_ocp_range.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// This package creates a CLI that allows to derive a range of OCP versions from a given range of
// Kubernetes versions. It uses Mastermind/semver/v3 under the hood.
package getocprange
import (
"embed"
"fmt"
"strings"
"github.com/Masterminds/semver/v3"
"gopkg.in/yaml.v3"
)
//go:embed kubeOpenShiftVersionMap.yaml
var content embed.FS
type versionMap struct {
Versions []*versionMapping `yaml:"versions"`
}
type versionMapping struct {
KubeVersion string `yaml:"kube-version"`
OcpVersion string `yaml:"ocp-version"`
}
// Maps a Kubernetes version to its corresponding OCP version.
var kubeOpenShiftVersionMap map[string]string
// Contains the highest known Kubernetes version. Used to determine if the provided Kubernetes
// range is open-ended.
var upperKubeVersion *semver.Version
// Upon initialization of this package, the kubeOpenShiftVersionMap variable is populated with the
// content of kubeOpenShiftVersionMap.yaml.
func init() {
kubeOpenShiftVersionMap = make(map[string]string)
yamlFile, err := content.ReadFile("kubeOpenShiftVersionMap.yaml")
if err != nil {
panic(fmt.Sprintf("Error reading content of kubeOpenShiftVersionMap.yaml: %v", err))
}
versions := versionMap{}
err = yaml.Unmarshal(yamlFile, &versions)
if err != nil {
panic(fmt.Sprintf("Error reading content of kubeOpenShiftVersionMap.yaml: %v", err))
}
upperKubeVersion, _ = semver.NewVersion("0.0")
for _, versionMap := range versions.Versions {
// Register the highest known Kubernetes version.
kubeVersion, err := semver.NewVersion(versionMap.KubeVersion)
if err != nil {
panic(fmt.Sprintf("Error reading content of kubeOpenShiftVersionMap.yaml: %v", err))
}
if kubeVersion.GreaterThan(upperKubeVersion) {
upperKubeVersion = kubeVersion
}
// Build Kubernetes version to OCP version mapping.
kubeOpenShiftVersionMap[versionMap.KubeVersion] = versionMap.OcpVersion
}
}
// GetOCPRange derives a range of OCP versions given a range of Kubernetes versions.
//
// To do so, it first ensures that the provided range of Kubernetes versions is a valid SemVer
// constraint using Mastermind/semver/v3. It then checks which of the known Kubernetes versions
// validate the Constraint, and registers the corresponding minimum and maximum OCP versions.
// Finally, it builds the resulting range of OCP versions.
//
// This function currently doesn't support the || operator for the provided range of Kubernetes
// versions.
func GetOCPRange(kubeVersionRange string) (string, error) {
// Return an error if the provided range of Kubernetes versions contains unsupported operators.
if strings.Contains(kubeVersionRange, "||") {
return "", fmt.Errorf("Range %s contains unsupported operator ||", kubeVersionRange)
}
minOCPRange, _ := semver.NewVersion("9.9")
maxOCPRange, _ := semver.NewVersion("0.0")
// Ensure that the provided range of Kubernetes versions is a valid SemVer constraint.
kubeVersionRangeConstraint, err := semver.NewConstraint(kubeVersionRange)
if err != nil {
return "", fmt.Errorf("Error converting %s to Constraint: %v", kubeVersionRange, err)
}
for kubeVersionString, OCPVersionString := range kubeOpenShiftVersionMap {
// Check which of the known Kubernetes versions validate the Constraint.
kubeVersionObj, err := semver.NewVersion(kubeVersionString)
if err != nil {
return "", fmt.Errorf("Error converting %s to Version: %v", kubeVersionString, err)
}
isInRange, _ := kubeVersionRangeConstraint.Validate(kubeVersionObj)
if isInRange {
// Register the corresponding minimum and maximum OCP versions.
OCPVersionObj, err := semver.NewVersion(OCPVersionString)
if err != nil {
return "", fmt.Errorf("Error converting %s to Version: %v", OCPVersionString, err)
}
if OCPVersionObj.LessThan(minOCPRange) {
minOCPRange = OCPVersionObj
}
if OCPVersionObj.GreaterThan(maxOCPRange) {
maxOCPRange = OCPVersionObj
}
}
}
// Build the resulting range of OCP versions.
if minOCPRange.Original() == "9.9" {
// If the minimum was never set, it means we didn't match any known Kubernetes version.
return "", fmt.Errorf("Failed to match any known Kubernetes version to the provided range %s", kubeVersionRange)
}
if isRangeOpenEnded(kubeVersionRangeConstraint) {
// If the provided range is open-ended, the result range should also be open-ended.
return ">=" + minOCPRange.Original(), nil
}
if minOCPRange.Equal(maxOCPRange) {
return minOCPRange.Original(), nil
}
return ">=" + minOCPRange.Original() + " <=" + maxOCPRange.Original(), nil
}
// isRangeOpenEnded returns a boolean set to True if the provided range of Kubernetes versions is
// open-ended (e.g. ">=1.13").
//
// To do so, we incremente the Patch value of the highest known Kubernetes Version, and check if it
// belongs to the range.
//
// TODO: This also returns True on ">=1.13 <=1.30" when upperKubeVersion=1.26.
func isRangeOpenEnded(kubeVersionRangeConstraint *semver.Constraints) bool {
nextUpperKubeVersion := upperKubeVersion.IncMinor()
isOpenEnded, _ := kubeVersionRangeConstraint.Validate(&nextUpperKubeVersion)
return isOpenEnded
}