99 "net/url"
1010 "slices"
1111 "strings"
12+ "regexp"
1213
1314 "github.com/pkg/errors"
1415 "github.com/sirupsen/logrus"
@@ -137,7 +138,8 @@ func discoverAPIGroups(coreClient clientset.Interface) (sets.Set[string], error)
137138// discoverFeatureGates discovers feature gates in the cluster
138139func discoverFeatureGates (configClient configclient.Interface , clusterVersion * configv1.ClusterVersion ) (enabled , disabled sets.Set [string ], err error ) {
139140 logrus .Debugf ("Discovering feature gates..." )
140- featureGate , err := configClient .ConfigV1 ().FeatureGates ().Get (context .Background (), "cluster" , metav1.GetOptions {})
141+ ctx := context .Background ()
142+ featureGate , err := configClient .ConfigV1 ().FeatureGates ().Get (ctx , "cluster" , metav1.GetOptions {})
141143 if err != nil {
142144 return nil , nil , errors .WithMessage (err , "encountered an error while discovering feature gates" )
143145 }
@@ -163,8 +165,14 @@ func discoverFeatureGates(configClient configclient.Interface, clusterVersion *c
163165 break
164166 }
165167
166- sortedEnabledGates := enabled .UnsortedList ()
168+ featureGatesEnabledAPI , err := getFeatureGatesAPIServerMetrics (ctx , configClient )
169+ if err != nil {
170+ return nil , nil , errors .WithMessage (err , "couldn't determine FeatureGates from API /metrics" )
171+ }
172+
173+ sortedEnabledGates := append (enabled .UnsortedList (), featureGatesEnabledAPI ... )
167174 slices .Sort (sortedEnabledGates )
175+ sortedEnabledGates = slices .Compact (sortedEnabledGates )
168176
169177 logrus .WithField ("featureGates" , strings .Join (sortedEnabledGates , ", " )).
170178 Debugf ("Discovered %d enabled feature gates" , len (sortedEnabledGates ))
@@ -381,3 +389,25 @@ func LoadConfig(state *ClusterState) (*ClusterConfiguration, error) {
381389
382390 return config , nil
383391}
392+
393+ // getFeatureGatesAPIServerMetrics extracts enabled feature gates from the API server metrics endpoint.
394+ // It returns a list of feature gate names that are enabled.
395+ func getFeatureGatesAPIServerMetrics (ctx context.Context , configClient configclient.Interface ) ([]string , error ) {
396+ rsp , err := configClient .ConfigV1 ().RESTClient ().Get ().AbsPath ("/metrics" ).Do (ctx ).Raw ()
397+ if err != nil {
398+ return nil , err
399+ }
400+ featureGates := sets .NewString ()
401+ lines := strings .Split (string (rsp ), "\n " )
402+ re := regexp .MustCompile (`kubernetes_feature_enabled\{name="([^"]+)".*\} 1` )
403+ for _ , line := range lines {
404+ if strings .HasPrefix (line , "kubernetes_feature_enabled{" ) && strings .HasSuffix (line , "} 1" ) {
405+ matches := re .FindStringSubmatch (line )
406+ if len (matches ) == 2 {
407+ featureGates .Insert (matches [1 ])
408+ }
409+ }
410+ }
411+ logrus .Infof ("Enabled feature gates from API server metrics: %v" , featureGates .List ())
412+ return featureGates .List (), nil
413+ }
0 commit comments