Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion hack/cluster-version-util/task_graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/spf13/cobra"

"github.com/openshift/cluster-version-operator/lib/capability"
"github.com/openshift/cluster-version-operator/pkg/payload"
)

Expand All @@ -30,7 +31,7 @@ func newTaskGraphCmd() *cobra.Command {

func runTaskGraphCmd(cmd *cobra.Command, args []string) error {
manifestDir := args[0]
release, err := payload.LoadUpdate(manifestDir, "", "", false, payload.DefaultClusterProfile)
release, err := payload.LoadUpdate(manifestDir, "", "", false, payload.DefaultClusterProfile, capability.ClusterCapabilities{})
if err != nil {
return err
}
Expand Down
111 changes: 111 additions & 0 deletions lib/capability/capability.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package capability

import (
"fmt"
"strings"

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

const (
CapabilityAnnotation = "capability.openshift.io/name"

DefaultCapabilitySet = configv1.ClusterVersionCapabilitySetCurrent
)

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

// SetCapabilities populates and returns cluster capabilities from ClusterVersion capabilities spec.
func SetCapabilities(config *configv1.ClusterVersion) ClusterCapabilities {
var capabilities ClusterCapabilities
capabilities.KnownCapabilities = setKnownCapabilities(config)
capabilities.EnabledCapabilities = setEnabledCapabilities(config)
return capabilities
}

// GetCapabilitiesStatus populates and returns ClusterVersion capabilities status from given capabilities.
func GetCapabilitiesStatus(capabilities ClusterCapabilities) configv1.ClusterVersionCapabilitiesStatus {
var status configv1.ClusterVersionCapabilitiesStatus
for k := range capabilities.EnabledCapabilities {
status.EnabledCapabilities = append(status.EnabledCapabilities, k)
}
for k := range capabilities.KnownCapabilities {
status.KnownCapabilities = append(status.KnownCapabilities, k)
}
return status
}

// CheckResourceEnablement, given resource annotations and defined cluster capabilities, checks if the capability
// annotation exists. If so, each capability name is validated against the known set of capabilities. Each valid
// capability is then checked if it is disabled. If any invalid capabilities are found an error is returned listing
// all invalid capabilities. Otherwise, if any disabled capabilities are found an error is returned listing all
// disabled capabilities.
func CheckResourceEnablement(annotations map[string]string, capabilities ClusterCapabilities) error {
val, ok := annotations[CapabilityAnnotation]
if !ok {
return nil
}
caps := strings.Split(val, "+")
numCaps := len(caps)
unknownCaps := make([]string, 0, numCaps)
disabledCaps := make([]string, 0, numCaps)

for _, c := range caps {
if _, ok = capabilities.KnownCapabilities[configv1.ClusterVersionCapability(c)]; !ok {
unknownCaps = append(unknownCaps, c)
} else if _, ok = capabilities.EnabledCapabilities[configv1.ClusterVersionCapability(c)]; !ok {
disabledCaps = append(disabledCaps, c)
}
}
if len(unknownCaps) > 0 {
return fmt.Errorf("unrecognized capability names: %s", strings.Join(unknownCaps, ", "))
}
if len(disabledCaps) > 0 {
return fmt.Errorf("disabled capabilities: %s", strings.Join(disabledCaps, ", "))
}
return nil
}

// setKnownCapabilities populates a map keyed by capability from all known capabilities as defined in ClusterVersion.
func setKnownCapabilities(config *configv1.ClusterVersion) 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
}

// setEnabledCapabilities populates a map keyed by capability from all enabled capabilities as defined in ClusterVersion.
// DefaultCapabilitySet is used if a baseline capability set is not defined by ClusterVersion.
func setEnabledCapabilities(config *configv1.ClusterVersion) map[configv1.ClusterVersionCapability]struct{} {
enabled := make(map[configv1.ClusterVersionCapability]struct{})

capSet := DefaultCapabilitySet

if config.Spec.Capabilities != nil && len(config.Spec.Capabilities.BaselineCapabilitySet) > 0 {
capSet = config.Spec.Capabilities.BaselineCapabilitySet
}

for _, v := range configv1.ClusterVersionCapabilitySets[capSet] {
enabled[v] = struct{}{}
}

if config.Spec.Capabilities != nil {
for _, v := range config.Spec.Capabilities.AdditionalEnabledCapabilities {
if _, ok := enabled[v]; ok {
continue
}
enabled[v] = struct{}{}
}
}
return enabled
}
Loading