...

Source file src/github.com/openshift/api/config/v1/types_feature.go

Documentation: github.com/openshift/api/config/v1

     1  package v1
     2  
     3  import (
     4  	"fmt"
     5  
     6  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     7  )
     8  
     9  // +genclient
    10  // +genclient:nonNamespaced
    11  // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
    12  
    13  // Feature holds cluster-wide information about feature gates.  The canonical name is `cluster`
    14  //
    15  // Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).
    16  // +openshift:compatibility-gen:level=1
    17  type FeatureGate struct {
    18  	metav1.TypeMeta `json:",inline"`
    19  
    20  	// metadata is the standard object's metadata.
    21  	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
    22  	metav1.ObjectMeta `json:"metadata,omitempty"`
    23  
    24  	// spec holds user settable values for configuration
    25  	// +kubebuilder:validation:Required
    26  	// +required
    27  	Spec FeatureGateSpec `json:"spec"`
    28  	// status holds observed values from the cluster. They may not be overridden.
    29  	// +optional
    30  	Status FeatureGateStatus `json:"status"`
    31  }
    32  
    33  type FeatureSet string
    34  
    35  var (
    36  	// Default feature set that allows upgrades.
    37  	Default FeatureSet = ""
    38  
    39  	// TechPreviewNoUpgrade turns on tech preview features that are not part of the normal supported platform. Turning
    40  	// this feature set on CANNOT BE UNDONE and PREVENTS UPGRADES.
    41  	TechPreviewNoUpgrade FeatureSet = "TechPreviewNoUpgrade"
    42  
    43  	// CustomNoUpgrade allows the enabling or disabling of any feature. Turning this feature set on IS NOT SUPPORTED, CANNOT BE UNDONE, and PREVENTS UPGRADES.
    44  	// Because of its nature, this setting cannot be validated.  If you have any typos or accidentally apply invalid combinations
    45  	// your cluster may fail in an unrecoverable way.
    46  	CustomNoUpgrade FeatureSet = "CustomNoUpgrade"
    47  
    48  	// TopologyManager enables ToplogyManager support. Upgrades are enabled with this feature.
    49  	LatencySensitive FeatureSet = "LatencySensitive"
    50  )
    51  
    52  type FeatureGateSpec struct {
    53  	FeatureGateSelection `json:",inline"`
    54  }
    55  
    56  // +union
    57  type FeatureGateSelection struct {
    58  	// featureSet changes the list of features in the cluster.  The default is empty.  Be very careful adjusting this setting.
    59  	// Turning on or off features may cause irreversible changes in your cluster which cannot be undone.
    60  	// +unionDiscriminator
    61  	// +optional
    62  	FeatureSet FeatureSet `json:"featureSet,omitempty"`
    63  
    64  	// customNoUpgrade allows the enabling or disabling of any feature. Turning this feature set on IS NOT SUPPORTED, CANNOT BE UNDONE, and PREVENTS UPGRADES.
    65  	// Because of its nature, this setting cannot be validated.  If you have any typos or accidentally apply invalid combinations
    66  	// your cluster may fail in an unrecoverable way.  featureSet must equal "CustomNoUpgrade" must be set to use this field.
    67  	// +optional
    68  	// +nullable
    69  	CustomNoUpgrade *CustomFeatureGates `json:"customNoUpgrade,omitempty"`
    70  }
    71  
    72  type CustomFeatureGates struct {
    73  	// enabled is a list of all feature gates that you want to force on
    74  	// +optional
    75  	Enabled []FeatureGateName `json:"enabled,omitempty"`
    76  	// disabled is a list of all feature gates that you want to force off
    77  	// +optional
    78  	Disabled []FeatureGateName `json:"disabled,omitempty"`
    79  }
    80  
    81  // FeatureGateName is a string to enforce patterns on the name of a FeatureGate
    82  // +kubebuilder:validation:Pattern=`^([A-Za-z0-9-]+\.)*[A-Za-z0-9-]+\.?$`
    83  type FeatureGateName string
    84  
    85  type FeatureGateStatus struct {
    86  	// conditions represent the observations of the current state.
    87  	// Known .status.conditions.type are: "DeterminationDegraded"
    88  	// +listType=map
    89  	// +listMapKey=type
    90  	Conditions []metav1.Condition `json:"conditions,omitempty"`
    91  
    92  	// featureGates contains a list of enabled and disabled featureGates that are keyed by payloadVersion.
    93  	// Operators other than the CVO and cluster-config-operator, must read the .status.featureGates, locate
    94  	// the version they are managing, find the enabled/disabled featuregates and make the operand and operator match.
    95  	// The enabled/disabled values for a particular version may change during the life of the cluster as various
    96  	// .spec.featureSet values are selected.
    97  	// Operators may choose to restart their processes to pick up these changes, but remembering past enable/disable
    98  	// lists is beyond the scope of this API and is the responsibility of individual operators.
    99  	// Only featureGates with .version in the ClusterVersion.status will be present in this list.
   100  	// +listType=map
   101  	// +listMapKey=version
   102  	FeatureGates []FeatureGateDetails `json:"featureGates"`
   103  }
   104  
   105  type FeatureGateDetails struct {
   106  	// version matches the version provided by the ClusterVersion and in the ClusterOperator.Status.Versions field.
   107  	// +kubebuilder:validation:Required
   108  	// +required
   109  	Version string `json:"version"`
   110  	// enabled is a list of all feature gates that are enabled in the cluster for the named version.
   111  	// +optional
   112  	Enabled []FeatureGateAttributes `json:"enabled"`
   113  	// disabled is a list of all feature gates that are disabled in the cluster for the named version.
   114  	// +optional
   115  	Disabled []FeatureGateAttributes `json:"disabled"`
   116  }
   117  
   118  type FeatureGateAttributes struct {
   119  	// name is the name of the FeatureGate.
   120  	// +kubebuilder:validation:Required
   121  	Name FeatureGateName `json:"name"`
   122  
   123  	// possible (probable?) future additions include
   124  	// 1. support level (Stable, ServiceDeliveryOnly, TechPreview, DevPreview)
   125  	// 2. description
   126  }
   127  
   128  // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
   129  
   130  // Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).
   131  // +openshift:compatibility-gen:level=1
   132  type FeatureGateList struct {
   133  	metav1.TypeMeta `json:",inline"`
   134  
   135  	// metadata is the standard list's metadata.
   136  	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
   137  	metav1.ListMeta `json:"metadata"`
   138  
   139  	Items []FeatureGate `json:"items"`
   140  }
   141  
   142  type FeatureGateEnabledDisabled struct {
   143  	Enabled  []FeatureGateDescription
   144  	Disabled []FeatureGateDescription
   145  }
   146  
   147  // FeatureSets Contains a map of Feature names to Enabled/Disabled Feature.
   148  //
   149  // NOTE: The caller needs to make sure to check for the existence of the value
   150  // using golang's existence field. A possible scenario is an upgrade where new
   151  // FeatureSets are added and a controller has not been upgraded with a newer
   152  // version of this file. In this upgrade scenario the map could return nil.
   153  //
   154  // example:
   155  //
   156  //	if featureSet, ok := FeatureSets["SomeNewFeature"]; ok { }
   157  //
   158  // If you put an item in either of these lists, put your area and name on it so we can find owners.
   159  var FeatureSets = map[FeatureSet]*FeatureGateEnabledDisabled{
   160  	Default: defaultFeatures,
   161  	CustomNoUpgrade: {
   162  		Enabled:  []FeatureGateDescription{},
   163  		Disabled: []FeatureGateDescription{},
   164  	},
   165  	TechPreviewNoUpgrade: newDefaultFeatures().
   166  		with(externalCloudProvider).
   167  		with(externalCloudProviderAzure).
   168  		with(externalCloudProviderGCP).
   169  		with(csiDriverSharedResource).
   170  		with(buildCSIVolumes).
   171  		with(nodeSwap).
   172  		with(machineAPIProviderOpenStack).
   173  		with(insightsConfigAPI).
   174  		with(matchLabelKeysInPodTopologySpread).
   175  		with(retroactiveDefaultStorageClass).
   176  		with(pdbUnhealthyPodEvictionPolicy).
   177  		with(dynamicResourceAllocation).
   178  		with(admissionWebhookMatchConditions).
   179  		with(azureWorkloadIdentity).
   180  		with(gateGatewayAPI).
   181  		toFeatures(defaultFeatures),
   182  	LatencySensitive: newDefaultFeatures().
   183  		toFeatures(defaultFeatures),
   184  }
   185  
   186  var defaultFeatures = &FeatureGateEnabledDisabled{
   187  	Enabled: []FeatureGateDescription{
   188  		openShiftPodSecurityAdmission,
   189  	},
   190  	Disabled: []FeatureGateDescription{
   191  		retroactiveDefaultStorageClass,
   192  	},
   193  }
   194  
   195  type featureSetBuilder struct {
   196  	forceOn  []FeatureGateDescription
   197  	forceOff []FeatureGateDescription
   198  }
   199  
   200  func newDefaultFeatures() *featureSetBuilder {
   201  	return &featureSetBuilder{}
   202  }
   203  
   204  func (f *featureSetBuilder) with(forceOn FeatureGateDescription) *featureSetBuilder {
   205  	for _, curr := range f.forceOn {
   206  		if curr.FeatureGateAttributes.Name == forceOn.FeatureGateAttributes.Name {
   207  			panic(fmt.Errorf("coding error: %q enabled twice", forceOn.FeatureGateAttributes.Name))
   208  		}
   209  	}
   210  	f.forceOn = append(f.forceOn, forceOn)
   211  	return f
   212  }
   213  
   214  func (f *featureSetBuilder) without(forceOff FeatureGateDescription) *featureSetBuilder {
   215  	for _, curr := range f.forceOff {
   216  		if curr.FeatureGateAttributes.Name == forceOff.FeatureGateAttributes.Name {
   217  			panic(fmt.Errorf("coding error: %q disabled twice", forceOff.FeatureGateAttributes.Name))
   218  		}
   219  	}
   220  	f.forceOff = append(f.forceOff, forceOff)
   221  	return f
   222  }
   223  
   224  func (f *featureSetBuilder) isForcedOff(needle FeatureGateDescription) bool {
   225  	for _, forcedOff := range f.forceOff {
   226  		if needle.FeatureGateAttributes.Name == forcedOff.FeatureGateAttributes.Name {
   227  			return true
   228  		}
   229  	}
   230  	return false
   231  }
   232  
   233  func (f *featureSetBuilder) isForcedOn(needle FeatureGateDescription) bool {
   234  	for _, forceOn := range f.forceOn {
   235  		if needle.FeatureGateAttributes.Name == forceOn.FeatureGateAttributes.Name {
   236  			return true
   237  		}
   238  	}
   239  	return false
   240  }
   241  
   242  func (f *featureSetBuilder) toFeatures(defaultFeatures *FeatureGateEnabledDisabled) *FeatureGateEnabledDisabled {
   243  	finalOn := []FeatureGateDescription{}
   244  	finalOff := []FeatureGateDescription{}
   245  
   246  	// only add the default enabled features if they haven't been explicitly set off
   247  	for _, defaultOn := range defaultFeatures.Enabled {
   248  		if !f.isForcedOff(defaultOn) {
   249  			finalOn = append(finalOn, defaultOn)
   250  		}
   251  	}
   252  	for _, currOn := range f.forceOn {
   253  		if f.isForcedOff(currOn) {
   254  			panic("coding error, you can't have features both on and off")
   255  		}
   256  		found := false
   257  		for _, alreadyOn := range finalOn {
   258  			if alreadyOn.FeatureGateAttributes.Name == currOn.FeatureGateAttributes.Name {
   259  				found = true
   260  			}
   261  		}
   262  		if found {
   263  			continue
   264  		}
   265  
   266  		finalOn = append(finalOn, currOn)
   267  	}
   268  
   269  	// only add the default disabled features if they haven't been explicitly set on
   270  	for _, defaultOff := range defaultFeatures.Disabled {
   271  		if !f.isForcedOn(defaultOff) {
   272  			finalOff = append(finalOff, defaultOff)
   273  		}
   274  	}
   275  	for _, currOff := range f.forceOff {
   276  		finalOff = append(finalOff, currOff)
   277  	}
   278  
   279  	return &FeatureGateEnabledDisabled{
   280  		Enabled:  finalOn,
   281  		Disabled: finalOff,
   282  	}
   283  }
   284  

View as plain text