repo_description: Complete container management platform
repo_topics: cattle containers docker kubernetes orchestration rancher
code: package features
  
  import (
  	v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3"
  	"github.com/rancher/rancher/pkg/controllers/management/imported"
  	managementv3 "github.com/rancher/rancher/pkg/generated/controllers/management.cattle.io/v3"
  	v1 "github.com/rancher/wrangler/v3/pkg/generated/controllers/apiextensions.k8s.io/v1"
  	apierrors "k8s.io/apimachinery/pkg/api/errors"
  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  )
  
  var (
  	t = true
  )
  
  func MigrateFeatures(featuresClient managementv3.FeatureClient, crdClient v1.CustomResourceDefinitionClient, mgmtClusterClient managementv3.ClusterClient) error {
  	features, err := featuresClient.List(metav1.ListOptions{})
  	if err != nil {
  		return err
  	}
  	if len(features.Items) == 0 {
  		return nil
  	}
  
  	hasLegacy := false
  	for _, feature := range features.Items {
  		switch feature.Name {
  		case Legacy.Name():
  			hasLegacy = true
  		case MCM.Name():
  			if err := enableMCMIfPreviouslyEnabled(&feature, featuresClient, crdClient); err != nil {
  				return err
  			}
  		case RKE2.Name():
  			if err := enableRKE2IfClustersExist(&feature, featuresClient, mgmtClusterClient); err != nil {
  				return err
  			}
  		}
  	}
  
  	if !hasLegacy {
  		_, err = featuresClient.Create(&v3.Feature{
  			ObjectMeta: metav1.ObjectMeta{
  				Name: Legacy.Name(),
  			},
  			Spec: v3.FeatureSpec{
  				Value: &t,
  			},
  		})
  		return err
  	}
  
  	return nil
  }
  
  func enableMCMIfPreviouslyEnabled(feature *v3.Feature, featuresClient managementv3.FeatureClient, crdClient v1.CustomResourceDefinitionClient) error {
  	if feature.Spec.Value == nil || *feature.Spec.Value {
  		return nil
  	}
  
  	_, err := crdClient.Get("nodes.management.cattle.io", metav1.GetOptions{})
  	if apierrors.IsNotFound(err) {
  		return nil
  	} else if err != nil {
  		return err
  	}
  
  	return SetFeature(featuresClient, MCM.Name(), true)
  }
  
  func enableRKE2IfClustersExist(feature *v3.Feature, featuresClient managementv3.FeatureClient, mgmtClusterClient managementv3.ClusterClient) error {
  	if feature.Spec.Value == nil || *feature.Spec.Value {
  		return nil
  	}
  
  	clusters, err := mgmtClusterClient.List(metav1.ListOptions{})
  	if err != nil {
  		return err
  	}
  
  	for _, c := range clusters.Items {
  		if imported.IsAdministratedByProvisioningCluster(&c) {
  			feature = feature.DeepCopy()
  			feature.SetValue(true)
  			feature.Status.LockedValue = feature.Spec.Value
  
  			_, err = featuresClient.Update(feature)
  			return err
  		}
  	}
  
  	return nil
  }
  