Skip to content

Commit

Permalink
OTA-1010: pull GetImplicitlyEnabledCapabilities from the cvo repo
Browse files Browse the repository at this point in the history
  • Loading branch information
hongkailiu committed Dec 12, 2024
1 parent b9df8bb commit 9cbf3c7
Show file tree
Hide file tree
Showing 3 changed files with 333 additions and 1 deletion.
135 changes: 135 additions & 0 deletions pkg/capability/capability.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package capability

import (
"sort"

configv1 "github.com/openshift/api/config/v1"
)

type ClusterCapabilities struct {
KnownCapabilities map[configv1.ClusterVersionCapability]struct{}
EnabledCapabilities map[configv1.ClusterVersionCapability]struct{}
ImplicitlyEnabledCapabilities []configv1.ClusterVersionCapability
}

// GetImplicitlyEnabledCapabilities filters out from a set of capabilities
// the ones that
// - are not in the list enabledCapabilities of clusterCapabilities
// - are not the keys of clusterCapabilities.EnabledCapabilities
// - are not in the list clusterCapabilities.ImplicitlyEnabledCapabilities
// The returned list is the implicitly enabled capabilities.
func GetImplicitlyEnabledCapabilities(enabledCapabilities []configv1.ClusterVersionCapability,
capabilities []configv1.ClusterVersionCapability,
clusterCapabilities ClusterCapabilities) []configv1.ClusterVersionCapability {
var caps []configv1.ClusterVersionCapability
for _, c := range capabilities {
if contains(enabledCapabilities, c) {
continue
}
if _, ok := clusterCapabilities.EnabledCapabilities[c]; !ok {
if !contains(clusterCapabilities.ImplicitlyEnabledCapabilities, c) {
caps = append(caps, c)
}
}
}
sort.Sort(capabilitiesSort(caps))
return caps
}

func contains(caps []configv1.ClusterVersionCapability, capability configv1.ClusterVersionCapability) bool {
for _, c := range caps {
if capability == c {
return true
}
}
return false
}

type capabilitiesSort []configv1.ClusterVersionCapability

func (caps capabilitiesSort) Len() int { return len(caps) }
func (caps capabilitiesSort) Swap(i, j int) { caps[i], caps[j] = caps[j], caps[i] }
func (caps capabilitiesSort) Less(i, j int) bool { return string(caps[i]) < string(caps[j]) }

// SetCapabilities populates and returns cluster clusterCapabilities from ClusterVersion clusterCapabilities spec. This method also
// ensures that no previously enabled capability is now disabled and returns any such implicitly enabled clusterCapabilities.
func SetCapabilities(config *configv1.ClusterVersion,
existingEnabled, alwaysEnabled map[configv1.ClusterVersionCapability]struct{}) ClusterCapabilities {

var capabilities ClusterCapabilities
capabilities.KnownCapabilities = setKnownCapabilities()

capabilities.EnabledCapabilities, capabilities.ImplicitlyEnabledCapabilities = setEnabledCapabilities(config.Spec.Capabilities,
existingEnabled, alwaysEnabled)

return capabilities
}

// setKnownCapabilities populates a map keyed by capability from all known clusterCapabilities as defined in ClusterVersion.
func setKnownCapabilities() map[configv1.ClusterVersionCapability]struct{} {
known := make(map[configv1.ClusterVersionCapability]struct{})

for _, v := range configv1.ClusterVersionCapabilitySets {
for _, capability := range v {
if _, ok := known[capability]; ok {
continue
}
known[capability] = struct{}{}
}
}
return known
}

const (
DefaultCapabilitySet = configv1.ClusterVersionCapabilitySetCurrent
)

// setEnabledCapabilities populates a map keyed by capability from all enabled clusterCapabilities as defined in ClusterVersion.
// DefaultCapabilitySet is used if a baseline capability set is not defined by ClusterVersion. A check is then made to
// ensure that no previously enabled capability is now disabled and if any such clusterCapabilities are found each is enabled,
// saved, and returned.
// The required clusterCapabilities are added to the implicitly enabled.
func setEnabledCapabilities(capabilitiesSpec *configv1.ClusterVersionCapabilitiesSpec,
priorEnabled, alwaysEnabled map[configv1.ClusterVersionCapability]struct{}) (map[configv1.ClusterVersionCapability]struct{},
[]configv1.ClusterVersionCapability) {

capSet := DefaultCapabilitySet

if capabilitiesSpec != nil && len(capabilitiesSpec.BaselineCapabilitySet) > 0 {
capSet = capabilitiesSpec.BaselineCapabilitySet
}
enabled := GetCapabilitiesAsMap(configv1.ClusterVersionCapabilitySets[capSet])

if capabilitiesSpec != nil {
for _, v := range capabilitiesSpec.AdditionalEnabledCapabilities {
if _, ok := enabled[v]; ok {
continue
}
enabled[v] = struct{}{}
}
}
var implicitlyEnabled []configv1.ClusterVersionCapability
for k := range priorEnabled {
if _, ok := enabled[k]; !ok {
implicitlyEnabled = append(implicitlyEnabled, k)
enabled[k] = struct{}{}
}
}
for k := range alwaysEnabled {
if _, ok := enabled[k]; !ok {
implicitlyEnabled = append(implicitlyEnabled, k)
enabled[k] = struct{}{}
}
}
sort.Sort(capabilitiesSort(implicitlyEnabled))
return enabled, implicitlyEnabled
}

// GetCapabilitiesAsMap returns the slice of clusterCapabilities as a map with default values.
func GetCapabilitiesAsMap(capabilities []configv1.ClusterVersionCapability) map[configv1.ClusterVersionCapability]struct{} {
caps := make(map[configv1.ClusterVersionCapability]struct{}, len(capabilities))
for _, c := range capabilities {
caps[c] = struct{}{}
}
return caps
}
193 changes: 193 additions & 0 deletions pkg/capability/capability_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package capability

import (
"testing"

"github.com/google/go-cmp/cmp"

configv1 "github.com/openshift/api/config/v1"
)

func TestGetImplicitlyEnabledCapabilities(t *testing.T) {
tests := []struct {
name string
enabledCaps []configv1.ClusterVersionCapability
capabilities []configv1.ClusterVersionCapability
clusterCapabilities ClusterCapabilities
expected []configv1.ClusterVersionCapability
}{
{name: "implicitly enable capability",
enabledCaps: []configv1.ClusterVersionCapability{"cap1", "cap3"},
capabilities: []configv1.ClusterVersionCapability{"cap2"},
clusterCapabilities: ClusterCapabilities{
EnabledCapabilities: map[configv1.ClusterVersionCapability]struct{}{"cap1": {}},
},
expected: []configv1.ClusterVersionCapability{"cap2"},
},
{name: "no prior caps, implicitly enabled capability",
capabilities: []configv1.ClusterVersionCapability{"cap2"},
expected: []configv1.ClusterVersionCapability{"cap2"},
},
{name: "multiple implicitly enable capability",
enabledCaps: []configv1.ClusterVersionCapability{"cap1", "cap2", "cap3"},
capabilities: []configv1.ClusterVersionCapability{"cap4", "cap5", "cap6"},
expected: []configv1.ClusterVersionCapability{"cap4", "cap5", "cap6"},
},
{name: "no implicitly enable capability",
enabledCaps: []configv1.ClusterVersionCapability{"cap1", "cap3"},
capabilities: []configv1.ClusterVersionCapability{"cap1"},
clusterCapabilities: ClusterCapabilities{
EnabledCapabilities: map[configv1.ClusterVersionCapability]struct{}{"cap1": {}},
},
},
{name: "prior cap, no updated caps, no implicitly enabled capability",
enabledCaps: []configv1.ClusterVersionCapability{"cap1"},
},
{name: "no implicitly enable capability, already enabled",
enabledCaps: []configv1.ClusterVersionCapability{"cap1", "cap2"},
capabilities: []configv1.ClusterVersionCapability{"cap2"},
clusterCapabilities: ClusterCapabilities{
EnabledCapabilities: map[configv1.ClusterVersionCapability]struct{}{"cap1": {}, "cap2": {}},
},
},
{name: "no implicitly enable capability, new cap but already enabled",
enabledCaps: []configv1.ClusterVersionCapability{"cap1"},
capabilities: []configv1.ClusterVersionCapability{"cap2"},
clusterCapabilities: ClusterCapabilities{
EnabledCapabilities: map[configv1.ClusterVersionCapability]struct{}{"cap2": {}},
},
},
{name: "no implicitly enable capability, already implcitly enabled",
enabledCaps: []configv1.ClusterVersionCapability{"cap1"},
capabilities: []configv1.ClusterVersionCapability{"cap2"},
clusterCapabilities: ClusterCapabilities{
EnabledCapabilities: map[configv1.ClusterVersionCapability]struct{}{"cap2": {}},
ImplicitlyEnabledCapabilities: []configv1.ClusterVersionCapability{"cap2"},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
caps := GetImplicitlyEnabledCapabilities(test.enabledCaps, test.capabilities, test.clusterCapabilities)
if diff := cmp.Diff(test.expected, caps); diff != "" {
t.Errorf("%s: Returned capacities differ from expected:\n%s", test.name, diff)
}
})
}
}

func TestSetCapabilities(t *testing.T) {
tests := []struct {
name string
config *configv1.ClusterVersion
expected ClusterCapabilities
}{
{name: "capabilities nil",
config: &configv1.ClusterVersion{},
expected: ClusterCapabilities{
KnownCapabilities: GetCapabilitiesAsMap(configv1.KnownClusterVersionCapabilities),
EnabledCapabilities: GetCapabilitiesAsMap(configv1.ClusterVersionCapabilitySets[DefaultCapabilitySet]),
},
},
{name: "capabilities set not set",
config: &configv1.ClusterVersion{
Spec: configv1.ClusterVersionSpec{
Capabilities: &configv1.ClusterVersionCapabilitiesSpec{},
},
},
expected: ClusterCapabilities{
KnownCapabilities: GetCapabilitiesAsMap(configv1.KnownClusterVersionCapabilities),
EnabledCapabilities: GetCapabilitiesAsMap(configv1.ClusterVersionCapabilitySets[DefaultCapabilitySet]),
},
},
{name: "set capabilities None",
config: &configv1.ClusterVersion{
Spec: configv1.ClusterVersionSpec{
Capabilities: &configv1.ClusterVersionCapabilitiesSpec{
BaselineCapabilitySet: configv1.ClusterVersionCapabilitySetNone,
},
},
},
expected: ClusterCapabilities{
KnownCapabilities: GetCapabilitiesAsMap(configv1.KnownClusterVersionCapabilities),
EnabledCapabilities: GetCapabilitiesAsMap([]configv1.ClusterVersionCapability{}),
},
},
{name: "set capabilities 4_11",
config: &configv1.ClusterVersion{
Spec: configv1.ClusterVersionSpec{
Capabilities: &configv1.ClusterVersionCapabilitiesSpec{
BaselineCapabilitySet: configv1.ClusterVersionCapabilitySet4_11,
AdditionalEnabledCapabilities: []configv1.ClusterVersionCapability{},
},
},
},
expected: ClusterCapabilities{
KnownCapabilities: GetCapabilitiesAsMap(configv1.KnownClusterVersionCapabilities),
EnabledCapabilities: GetCapabilitiesAsMap([]configv1.ClusterVersionCapability{
configv1.ClusterVersionCapabilityBaremetal,
configv1.ClusterVersionCapabilityMarketplace,
configv1.ClusterVersionCapabilityOpenShiftSamples,
configv1.ClusterVersionCapabilityMachineAPI,
}),
},
},
{name: "set capabilities vCurrent",
config: &configv1.ClusterVersion{
Spec: configv1.ClusterVersionSpec{
Capabilities: &configv1.ClusterVersionCapabilitiesSpec{
BaselineCapabilitySet: configv1.ClusterVersionCapabilitySetCurrent,
AdditionalEnabledCapabilities: []configv1.ClusterVersionCapability{},
},
},
},
expected: ClusterCapabilities{
KnownCapabilities: GetCapabilitiesAsMap(configv1.KnownClusterVersionCapabilities),
EnabledCapabilities: GetCapabilitiesAsMap(configv1.ClusterVersionCapabilitySets[configv1.ClusterVersionCapabilitySetCurrent]),
},
},
{name: "set capabilities None with additional",
config: &configv1.ClusterVersion{
Spec: configv1.ClusterVersionSpec{
Capabilities: &configv1.ClusterVersionCapabilitiesSpec{
BaselineCapabilitySet: configv1.ClusterVersionCapabilitySetNone,
AdditionalEnabledCapabilities: []configv1.ClusterVersionCapability{"cap1", "cap2", "cap3"},
},
},
},
expected: ClusterCapabilities{
KnownCapabilities: GetCapabilitiesAsMap(configv1.KnownClusterVersionCapabilities),
EnabledCapabilities: GetCapabilitiesAsMap([]configv1.ClusterVersionCapability{"cap1", "cap2", "cap3"}),
},
},
{name: "set capabilities 4_11 with additional",
config: &configv1.ClusterVersion{
Spec: configv1.ClusterVersionSpec{
Capabilities: &configv1.ClusterVersionCapabilitiesSpec{
BaselineCapabilitySet: configv1.ClusterVersionCapabilitySet4_11,
AdditionalEnabledCapabilities: []configv1.ClusterVersionCapability{"cap1", "cap2", "cap3"},
},
},
},
expected: ClusterCapabilities{
KnownCapabilities: GetCapabilitiesAsMap(configv1.KnownClusterVersionCapabilities),
EnabledCapabilities: GetCapabilitiesAsMap([]configv1.ClusterVersionCapability{
configv1.ClusterVersionCapabilityBaremetal,
configv1.ClusterVersionCapabilityMarketplace,
configv1.ClusterVersionCapabilityOpenShiftSamples,
configv1.ClusterVersionCapabilityMachineAPI,
"cap1",
"cap2",
"cap3"}),
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
caps := SetCapabilities(test.config, nil, nil)
if diff := cmp.Diff(test.expected, caps); diff != "" {
t.Errorf("%s: Returned capacities differ from expected:\n%s", test.name, diff)
}
})
}
}
6 changes: 5 additions & 1 deletion pkg/manifest/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,14 @@ func (m *Manifest) String() string {
return m.id.String()
}

func (m Manifest) SameResourceID(manifest Manifest) bool {
func (m *Manifest) SameResourceID(manifest Manifest) bool {
return m.id.equal(manifest.id)
}

func (m *Manifest) GetManifestResourceId() string {
return m.id.String()
}

// UnmarshalJSON implements the json.Unmarshaler interface for the Manifest
// type. It unmarshals bytes of a single kubernetes object to Manifest.
func (m *Manifest) UnmarshalJSON(in []byte) error {
Expand Down

0 comments on commit 9cbf3c7

Please sign in to comment.