Skip to content

Commit 9cd9e07

Browse files
committed
OTA-1010: pull GetImplicitlyEnabledCapabilities from the cvo repo
1 parent b9df8bb commit 9cd9e07

File tree

3 files changed

+333
-1
lines changed

3 files changed

+333
-1
lines changed

pkg/capability/capability.go

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package capability
2+
3+
import (
4+
"sort"
5+
6+
configv1 "github.com/openshift/api/config/v1"
7+
)
8+
9+
type ClusterCapabilities struct {
10+
KnownCapabilities map[configv1.ClusterVersionCapability]struct{}
11+
EnabledCapabilities map[configv1.ClusterVersionCapability]struct{}
12+
ImplicitlyEnabledCapabilities []configv1.ClusterVersionCapability
13+
}
14+
15+
// GetImplicitlyEnabledCapabilities filters out from a set of clusterCapabilities
16+
// the ones that
17+
// - are not in the list enabledCapabilities of clusterCapabilities
18+
// - are not the keys of clusterCapabilities.EnabledCapabilities
19+
// - are not in the list clusterCapabilities.ImplicitlyEnabledCapabilities
20+
// The returned list are clusterCapabilities which must be implicitly enabled.
21+
func GetImplicitlyEnabledCapabilities(enabledCapabilities []configv1.ClusterVersionCapability,
22+
capabilities []configv1.ClusterVersionCapability,
23+
clusterCapabilities ClusterCapabilities) []configv1.ClusterVersionCapability {
24+
var caps []configv1.ClusterVersionCapability
25+
for _, c := range capabilities {
26+
if contains(enabledCapabilities, c) {
27+
continue
28+
}
29+
if _, ok := clusterCapabilities.EnabledCapabilities[c]; !ok {
30+
if !contains(clusterCapabilities.ImplicitlyEnabledCapabilities, c) {
31+
caps = append(caps, c)
32+
}
33+
}
34+
}
35+
sort.Sort(capabilitiesSort(caps))
36+
return caps
37+
}
38+
39+
func contains(caps []configv1.ClusterVersionCapability, capability configv1.ClusterVersionCapability) bool {
40+
for _, c := range caps {
41+
if capability == c {
42+
return true
43+
}
44+
}
45+
return false
46+
}
47+
48+
type capabilitiesSort []configv1.ClusterVersionCapability
49+
50+
func (caps capabilitiesSort) Len() int { return len(caps) }
51+
func (caps capabilitiesSort) Swap(i, j int) { caps[i], caps[j] = caps[j], caps[i] }
52+
func (caps capabilitiesSort) Less(i, j int) bool { return string(caps[i]) < string(caps[j]) }
53+
54+
// SetCapabilities populates and returns cluster clusterCapabilities from ClusterVersion clusterCapabilities spec. This method also
55+
// ensures that no previously enabled capability is now disabled and returns any such implicitly enabled clusterCapabilities.
56+
func SetCapabilities(config *configv1.ClusterVersion,
57+
existingEnabled, alwaysEnabled map[configv1.ClusterVersionCapability]struct{}) ClusterCapabilities {
58+
59+
var capabilities ClusterCapabilities
60+
capabilities.KnownCapabilities = setKnownCapabilities()
61+
62+
capabilities.EnabledCapabilities, capabilities.ImplicitlyEnabledCapabilities = setEnabledCapabilities(config.Spec.Capabilities,
63+
existingEnabled, alwaysEnabled)
64+
65+
return capabilities
66+
}
67+
68+
// setKnownCapabilities populates a map keyed by capability from all known clusterCapabilities as defined in ClusterVersion.
69+
func setKnownCapabilities() map[configv1.ClusterVersionCapability]struct{} {
70+
known := make(map[configv1.ClusterVersionCapability]struct{})
71+
72+
for _, v := range configv1.ClusterVersionCapabilitySets {
73+
for _, capability := range v {
74+
if _, ok := known[capability]; ok {
75+
continue
76+
}
77+
known[capability] = struct{}{}
78+
}
79+
}
80+
return known
81+
}
82+
83+
const (
84+
DefaultCapabilitySet = configv1.ClusterVersionCapabilitySetCurrent
85+
)
86+
87+
// setEnabledCapabilities populates a map keyed by capability from all enabled clusterCapabilities as defined in ClusterVersion.
88+
// DefaultCapabilitySet is used if a baseline capability set is not defined by ClusterVersion. A check is then made to
89+
// ensure that no previously enabled capability is now disabled and if any such clusterCapabilities are found each is enabled,
90+
// saved, and returned.
91+
// The required clusterCapabilities are added to the implicitly enabled.
92+
func setEnabledCapabilities(capabilitiesSpec *configv1.ClusterVersionCapabilitiesSpec,
93+
priorEnabled, alwaysEnabled map[configv1.ClusterVersionCapability]struct{}) (map[configv1.ClusterVersionCapability]struct{},
94+
[]configv1.ClusterVersionCapability) {
95+
96+
capSet := DefaultCapabilitySet
97+
98+
if capabilitiesSpec != nil && len(capabilitiesSpec.BaselineCapabilitySet) > 0 {
99+
capSet = capabilitiesSpec.BaselineCapabilitySet
100+
}
101+
enabled := GetCapabilitiesAsMap(configv1.ClusterVersionCapabilitySets[capSet])
102+
103+
if capabilitiesSpec != nil {
104+
for _, v := range capabilitiesSpec.AdditionalEnabledCapabilities {
105+
if _, ok := enabled[v]; ok {
106+
continue
107+
}
108+
enabled[v] = struct{}{}
109+
}
110+
}
111+
var implicitlyEnabled []configv1.ClusterVersionCapability
112+
for k := range priorEnabled {
113+
if _, ok := enabled[k]; !ok {
114+
implicitlyEnabled = append(implicitlyEnabled, k)
115+
enabled[k] = struct{}{}
116+
}
117+
}
118+
for k := range alwaysEnabled {
119+
if _, ok := enabled[k]; !ok {
120+
implicitlyEnabled = append(implicitlyEnabled, k)
121+
enabled[k] = struct{}{}
122+
}
123+
}
124+
sort.Sort(capabilitiesSort(implicitlyEnabled))
125+
return enabled, implicitlyEnabled
126+
}
127+
128+
// GetCapabilitiesAsMap returns the slice of clusterCapabilities as a map with default values.
129+
func GetCapabilitiesAsMap(capabilities []configv1.ClusterVersionCapability) map[configv1.ClusterVersionCapability]struct{} {
130+
caps := make(map[configv1.ClusterVersionCapability]struct{}, len(capabilities))
131+
for _, c := range capabilities {
132+
caps[c] = struct{}{}
133+
}
134+
return caps
135+
}

pkg/capability/capability_test.go

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
package capability
2+
3+
import (
4+
"testing"
5+
6+
"github.com/google/go-cmp/cmp"
7+
8+
configv1 "github.com/openshift/api/config/v1"
9+
)
10+
11+
func TestGetImplicitlyEnabledCapabilities(t *testing.T) {
12+
tests := []struct {
13+
name string
14+
enabledCaps []configv1.ClusterVersionCapability
15+
capabilities []configv1.ClusterVersionCapability
16+
clusterCapabilities ClusterCapabilities
17+
expected []configv1.ClusterVersionCapability
18+
}{
19+
{name: "implicitly enable capability",
20+
enabledCaps: []configv1.ClusterVersionCapability{"cap1", "cap3"},
21+
capabilities: []configv1.ClusterVersionCapability{"cap2"},
22+
clusterCapabilities: ClusterCapabilities{
23+
EnabledCapabilities: map[configv1.ClusterVersionCapability]struct{}{"cap1": {}},
24+
},
25+
expected: []configv1.ClusterVersionCapability{"cap2"},
26+
},
27+
{name: "no prior caps, implicitly enabled capability",
28+
capabilities: []configv1.ClusterVersionCapability{"cap2"},
29+
expected: []configv1.ClusterVersionCapability{"cap2"},
30+
},
31+
{name: "multiple implicitly enable capability",
32+
enabledCaps: []configv1.ClusterVersionCapability{"cap1", "cap2", "cap3"},
33+
capabilities: []configv1.ClusterVersionCapability{"cap4", "cap5", "cap6"},
34+
expected: []configv1.ClusterVersionCapability{"cap4", "cap5", "cap6"},
35+
},
36+
{name: "no implicitly enable capability",
37+
enabledCaps: []configv1.ClusterVersionCapability{"cap1", "cap3"},
38+
capabilities: []configv1.ClusterVersionCapability{"cap1"},
39+
clusterCapabilities: ClusterCapabilities{
40+
EnabledCapabilities: map[configv1.ClusterVersionCapability]struct{}{"cap1": {}},
41+
},
42+
},
43+
{name: "prior cap, no updated caps, no implicitly enabled capability",
44+
enabledCaps: []configv1.ClusterVersionCapability{"cap1"},
45+
},
46+
{name: "no implicitly enable capability, already enabled",
47+
enabledCaps: []configv1.ClusterVersionCapability{"cap1", "cap2"},
48+
capabilities: []configv1.ClusterVersionCapability{"cap2"},
49+
clusterCapabilities: ClusterCapabilities{
50+
EnabledCapabilities: map[configv1.ClusterVersionCapability]struct{}{"cap1": {}, "cap2": {}},
51+
},
52+
},
53+
{name: "no implicitly enable capability, new cap but already enabled",
54+
enabledCaps: []configv1.ClusterVersionCapability{"cap1"},
55+
capabilities: []configv1.ClusterVersionCapability{"cap2"},
56+
clusterCapabilities: ClusterCapabilities{
57+
EnabledCapabilities: map[configv1.ClusterVersionCapability]struct{}{"cap2": {}},
58+
},
59+
},
60+
{name: "no implicitly enable capability, already implcitly enabled",
61+
enabledCaps: []configv1.ClusterVersionCapability{"cap1"},
62+
capabilities: []configv1.ClusterVersionCapability{"cap2"},
63+
clusterCapabilities: ClusterCapabilities{
64+
EnabledCapabilities: map[configv1.ClusterVersionCapability]struct{}{"cap2": {}},
65+
ImplicitlyEnabledCapabilities: []configv1.ClusterVersionCapability{"cap2"},
66+
},
67+
},
68+
}
69+
for _, test := range tests {
70+
t.Run(test.name, func(t *testing.T) {
71+
caps := GetImplicitlyEnabledCapabilities(test.enabledCaps, test.capabilities, test.clusterCapabilities)
72+
if diff := cmp.Diff(test.expected, caps); diff != "" {
73+
t.Errorf("%s: Returned capacities differ from expected:\n%s", test.name, diff)
74+
}
75+
})
76+
}
77+
}
78+
79+
func TestSetCapabilities(t *testing.T) {
80+
tests := []struct {
81+
name string
82+
config *configv1.ClusterVersion
83+
expected ClusterCapabilities
84+
}{
85+
{name: "capabilities nil",
86+
config: &configv1.ClusterVersion{},
87+
expected: ClusterCapabilities{
88+
KnownCapabilities: GetCapabilitiesAsMap(configv1.KnownClusterVersionCapabilities),
89+
EnabledCapabilities: GetCapabilitiesAsMap(configv1.ClusterVersionCapabilitySets[DefaultCapabilitySet]),
90+
},
91+
},
92+
{name: "capabilities set not set",
93+
config: &configv1.ClusterVersion{
94+
Spec: configv1.ClusterVersionSpec{
95+
Capabilities: &configv1.ClusterVersionCapabilitiesSpec{},
96+
},
97+
},
98+
expected: ClusterCapabilities{
99+
KnownCapabilities: GetCapabilitiesAsMap(configv1.KnownClusterVersionCapabilities),
100+
EnabledCapabilities: GetCapabilitiesAsMap(configv1.ClusterVersionCapabilitySets[DefaultCapabilitySet]),
101+
},
102+
},
103+
{name: "set capabilities None",
104+
config: &configv1.ClusterVersion{
105+
Spec: configv1.ClusterVersionSpec{
106+
Capabilities: &configv1.ClusterVersionCapabilitiesSpec{
107+
BaselineCapabilitySet: configv1.ClusterVersionCapabilitySetNone,
108+
},
109+
},
110+
},
111+
expected: ClusterCapabilities{
112+
KnownCapabilities: GetCapabilitiesAsMap(configv1.KnownClusterVersionCapabilities),
113+
EnabledCapabilities: GetCapabilitiesAsMap([]configv1.ClusterVersionCapability{}),
114+
},
115+
},
116+
{name: "set capabilities 4_11",
117+
config: &configv1.ClusterVersion{
118+
Spec: configv1.ClusterVersionSpec{
119+
Capabilities: &configv1.ClusterVersionCapabilitiesSpec{
120+
BaselineCapabilitySet: configv1.ClusterVersionCapabilitySet4_11,
121+
AdditionalEnabledCapabilities: []configv1.ClusterVersionCapability{},
122+
},
123+
},
124+
},
125+
expected: ClusterCapabilities{
126+
KnownCapabilities: GetCapabilitiesAsMap(configv1.KnownClusterVersionCapabilities),
127+
EnabledCapabilities: GetCapabilitiesAsMap([]configv1.ClusterVersionCapability{
128+
configv1.ClusterVersionCapabilityBaremetal,
129+
configv1.ClusterVersionCapabilityMarketplace,
130+
configv1.ClusterVersionCapabilityOpenShiftSamples,
131+
configv1.ClusterVersionCapabilityMachineAPI,
132+
}),
133+
},
134+
},
135+
{name: "set capabilities vCurrent",
136+
config: &configv1.ClusterVersion{
137+
Spec: configv1.ClusterVersionSpec{
138+
Capabilities: &configv1.ClusterVersionCapabilitiesSpec{
139+
BaselineCapabilitySet: configv1.ClusterVersionCapabilitySetCurrent,
140+
AdditionalEnabledCapabilities: []configv1.ClusterVersionCapability{},
141+
},
142+
},
143+
},
144+
expected: ClusterCapabilities{
145+
KnownCapabilities: GetCapabilitiesAsMap(configv1.KnownClusterVersionCapabilities),
146+
EnabledCapabilities: GetCapabilitiesAsMap(configv1.ClusterVersionCapabilitySets[configv1.ClusterVersionCapabilitySetCurrent]),
147+
},
148+
},
149+
{name: "set capabilities None with additional",
150+
config: &configv1.ClusterVersion{
151+
Spec: configv1.ClusterVersionSpec{
152+
Capabilities: &configv1.ClusterVersionCapabilitiesSpec{
153+
BaselineCapabilitySet: configv1.ClusterVersionCapabilitySetNone,
154+
AdditionalEnabledCapabilities: []configv1.ClusterVersionCapability{"cap1", "cap2", "cap3"},
155+
},
156+
},
157+
},
158+
expected: ClusterCapabilities{
159+
KnownCapabilities: GetCapabilitiesAsMap(configv1.KnownClusterVersionCapabilities),
160+
EnabledCapabilities: GetCapabilitiesAsMap([]configv1.ClusterVersionCapability{"cap1", "cap2", "cap3"}),
161+
},
162+
},
163+
{name: "set capabilities 4_11 with additional",
164+
config: &configv1.ClusterVersion{
165+
Spec: configv1.ClusterVersionSpec{
166+
Capabilities: &configv1.ClusterVersionCapabilitiesSpec{
167+
BaselineCapabilitySet: configv1.ClusterVersionCapabilitySet4_11,
168+
AdditionalEnabledCapabilities: []configv1.ClusterVersionCapability{"cap1", "cap2", "cap3"},
169+
},
170+
},
171+
},
172+
expected: ClusterCapabilities{
173+
KnownCapabilities: GetCapabilitiesAsMap(configv1.KnownClusterVersionCapabilities),
174+
EnabledCapabilities: GetCapabilitiesAsMap([]configv1.ClusterVersionCapability{
175+
configv1.ClusterVersionCapabilityBaremetal,
176+
configv1.ClusterVersionCapabilityMarketplace,
177+
configv1.ClusterVersionCapabilityOpenShiftSamples,
178+
configv1.ClusterVersionCapabilityMachineAPI,
179+
"cap1",
180+
"cap2",
181+
"cap3"}),
182+
},
183+
},
184+
}
185+
for _, test := range tests {
186+
t.Run(test.name, func(t *testing.T) {
187+
caps := SetCapabilities(test.config, nil, nil)
188+
if diff := cmp.Diff(test.expected, caps); diff != "" {
189+
t.Errorf("%s: Returned capacities differ from expected:\n%s", test.name, diff)
190+
}
191+
})
192+
}
193+
}

pkg/manifest/manifest.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,14 @@ func (m *Manifest) String() string {
105105
return m.id.String()
106106
}
107107

108-
func (m Manifest) SameResourceID(manifest Manifest) bool {
108+
func (m *Manifest) SameResourceID(manifest Manifest) bool {
109109
return m.id.equal(manifest.id)
110110
}
111111

112+
func (m *Manifest) GetManifestResourceId() string {
113+
return m.id.String()
114+
}
115+
112116
// UnmarshalJSON implements the json.Unmarshaler interface for the Manifest
113117
// type. It unmarshals bytes of a single kubernetes object to Manifest.
114118
func (m *Manifest) UnmarshalJSON(in []byte) error {

0 commit comments

Comments
 (0)