github.com/openshift/installer@v1.4.17/pkg/types/conversion/installconfig.go (about)

     1  package conversion
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"k8s.io/apimachinery/pkg/util/validation/field"
     8  	utilsslice "k8s.io/utils/strings/slices"
     9  
    10  	operv1 "github.com/openshift/api/operator/v1"
    11  	"github.com/openshift/installer/pkg/ipnet"
    12  	"github.com/openshift/installer/pkg/types"
    13  	"github.com/openshift/installer/pkg/types/aws"
    14  	"github.com/openshift/installer/pkg/types/baremetal"
    15  	"github.com/openshift/installer/pkg/types/nutanix"
    16  	"github.com/openshift/installer/pkg/types/openstack"
    17  	"github.com/openshift/installer/pkg/types/ovirt"
    18  	"github.com/openshift/installer/pkg/types/vsphere"
    19  	vsphereconversion "github.com/openshift/installer/pkg/types/vsphere/conversion"
    20  )
    21  
    22  // ConvertInstallConfig is modeled after the k8s conversion schemes, which is
    23  // how deprecated values are upconverted.
    24  // This updates the APIVersion to reflect the fact that we've internally
    25  // upconverted.
    26  func ConvertInstallConfig(config *types.InstallConfig) error {
    27  	// check that the version is convertible
    28  	switch config.APIVersion {
    29  	case types.InstallConfigVersion, "v1beta3", "v1beta4":
    30  		// works
    31  	case "":
    32  		return field.Required(field.NewPath("apiVersion"), "no version was provided")
    33  	default:
    34  		return field.Invalid(field.NewPath("apiVersion"), config.APIVersion, fmt.Sprintf("cannot upconvert from version %s", config.APIVersion))
    35  	}
    36  	convertNetworking(config)
    37  	switch config.Platform.Name() {
    38  	case baremetal.Name:
    39  		if err := convertBaremetal(config); err != nil {
    40  			return err
    41  		}
    42  	case nutanix.Name:
    43  		if err := convertNutanix(config); err != nil {
    44  			return err
    45  		}
    46  	case openstack.Name:
    47  		if err := convertOpenStack(config); err != nil {
    48  			return err
    49  		}
    50  	case aws.Name:
    51  		if err := convertAWS(config); err != nil {
    52  			return err
    53  		}
    54  	case vsphere.Name:
    55  		if err := vsphereconversion.ConvertInstallConfig(config); err != nil {
    56  			return err
    57  		}
    58  		if err := convertVSphere(config); err != nil {
    59  			return err
    60  		}
    61  	case ovirt.Name:
    62  		if err := convertOVirt(config); err != nil {
    63  			return err
    64  		}
    65  	}
    66  
    67  	config.APIVersion = types.InstallConfigVersion
    68  	return nil
    69  }
    70  
    71  // convertNetworking upconverts deprecated fields in networking
    72  func convertNetworking(config *types.InstallConfig) {
    73  	if config.Networking == nil {
    74  		return
    75  	}
    76  
    77  	netconf := config.Networking
    78  
    79  	if len(netconf.ClusterNetwork) == 0 {
    80  		netconf.ClusterNetwork = netconf.DeprecatedClusterNetworks
    81  	}
    82  
    83  	if len(netconf.MachineNetwork) == 0 && netconf.DeprecatedMachineCIDR != nil {
    84  		netconf.MachineNetwork = []types.MachineNetworkEntry{
    85  			{CIDR: *netconf.DeprecatedMachineCIDR},
    86  		}
    87  	}
    88  
    89  	if len(netconf.ServiceNetwork) == 0 && netconf.DeprecatedServiceCIDR != nil {
    90  		netconf.ServiceNetwork = []ipnet.IPNet{*netconf.DeprecatedServiceCIDR}
    91  	}
    92  
    93  	// Convert type to networkType if the latter is missing
    94  	if netconf.NetworkType == "" {
    95  		netconf.NetworkType = netconf.DeprecatedType
    96  	}
    97  
    98  	// Recognize the OpenShiftSDN network plugin name regardless of capitalization, for
    99  	// backward compatibility
   100  	if strings.ToLower(netconf.NetworkType) == strings.ToLower(string(operv1.NetworkTypeOpenShiftSDN)) {
   101  		netconf.NetworkType = string(operv1.NetworkTypeOpenShiftSDN)
   102  	}
   103  
   104  	// Convert hostSubnetLength to hostPrefix
   105  	for i, entry := range netconf.ClusterNetwork {
   106  		if entry.HostPrefix == 0 && entry.DeprecatedHostSubnetLength != 0 {
   107  			_, size := entry.CIDR.Mask.Size()
   108  			netconf.ClusterNetwork[i].HostPrefix = int32(size) - entry.DeprecatedHostSubnetLength
   109  		}
   110  	}
   111  }
   112  
   113  // convertBaremetal upconverts deprecated fields in the baremetal platform.
   114  // ProvisioningDHCPExternal has been replaced by setting the ProvisioningNetwork
   115  // field to "Unmanaged", ProvisioningHostIP has been replaced by
   116  // ClusterProvisioningIP, apiVIP has been replaced by apiVIPs and ingressVIP has
   117  // been replaced by ingressVIPs.
   118  func convertBaremetal(config *types.InstallConfig) error {
   119  	if config.Platform.BareMetal.DeprecatedProvisioningDHCPExternal && config.Platform.BareMetal.ProvisioningNetwork == "" {
   120  		config.Platform.BareMetal.ProvisioningNetwork = baremetal.UnmanagedProvisioningNetwork
   121  	}
   122  
   123  	if config.Platform.BareMetal.DeprecatedProvisioningHostIP != "" && config.Platform.BareMetal.ClusterProvisioningIP == "" {
   124  		config.Platform.BareMetal.ClusterProvisioningIP = config.Platform.BareMetal.DeprecatedProvisioningHostIP
   125  	}
   126  
   127  	// If user specified both, but they aren't equal, let them know they are the same field
   128  	if config.Platform.BareMetal.DeprecatedProvisioningHostIP != "" &&
   129  		config.Platform.BareMetal.DeprecatedProvisioningHostIP != config.Platform.BareMetal.ClusterProvisioningIP {
   130  		return field.Invalid(field.NewPath("platform").Child("baremetal").Child("provisioningHostIP"),
   131  			config.Platform.BareMetal.DeprecatedProvisioningHostIP, "provisioningHostIP is deprecated; only clusterProvisioningIP needs to be specified")
   132  	}
   133  
   134  	if err := upconvertVIP(&config.Platform.BareMetal.APIVIPs, config.Platform.BareMetal.DeprecatedAPIVIP, "apiVIP", "apiVIPs", field.NewPath("platform").Child("baremetal")); err != nil {
   135  		return err
   136  	}
   137  
   138  	if err := upconvertVIP(&config.Platform.BareMetal.IngressVIPs, config.Platform.BareMetal.DeprecatedIngressVIP, "ingressVIP", "ingressVIPs", field.NewPath("platform").Child("baremetal")); err != nil {
   139  		return err
   140  	}
   141  
   142  	return nil
   143  }
   144  
   145  // convertOpenStack upconverts deprecated fields in the OpenStack platform.
   146  func convertOpenStack(config *types.InstallConfig) error {
   147  	// LbFloatingIP has been renamed to APIFloatingIP
   148  	if config.Platform.OpenStack.DeprecatedLbFloatingIP != "" {
   149  		if config.Platform.OpenStack.APIFloatingIP == "" {
   150  			config.Platform.OpenStack.APIFloatingIP = config.Platform.OpenStack.DeprecatedLbFloatingIP
   151  		} else if config.Platform.OpenStack.DeprecatedLbFloatingIP != config.Platform.OpenStack.APIFloatingIP {
   152  			// Return error if both LbFloatingIP and APIFloatingIP are specified in the config
   153  			return field.Forbidden(field.NewPath("platform").Child("openstack").Child("lbFloatingIP"), "cannot specify lbFloatingIP and apiFloatingIP together")
   154  		}
   155  	}
   156  
   157  	// computeFlavor has been deprecated in favor of type in defaultMachinePlatform.
   158  	if config.Platform.OpenStack.DeprecatedFlavorName != "" {
   159  		if config.Platform.OpenStack.DefaultMachinePlatform == nil {
   160  			config.Platform.OpenStack.DefaultMachinePlatform = &openstack.MachinePool{}
   161  		}
   162  
   163  		if config.Platform.OpenStack.DefaultMachinePlatform.FlavorName != "" && config.Platform.OpenStack.DefaultMachinePlatform.FlavorName != config.Platform.OpenStack.DeprecatedFlavorName {
   164  			// Return error if both computeFlavor and type of defaultMachinePlatform are specified in the config
   165  			return field.Forbidden(field.NewPath("platform").Child("openstack").Child("computeFlavor"), "cannot specify computeFlavor and type in defaultMachinePlatform together")
   166  		}
   167  
   168  		config.Platform.OpenStack.DefaultMachinePlatform.FlavorName = config.Platform.OpenStack.DeprecatedFlavorName
   169  	}
   170  
   171  	// type has been deprecated in favor of types in the machinePools.
   172  	if config.ControlPlane != nil &&
   173  		config.ControlPlane.Platform.OpenStack != nil &&
   174  		config.ControlPlane.Platform.OpenStack.RootVolume != nil &&
   175  		config.ControlPlane.Platform.OpenStack.RootVolume.DeprecatedType != "" {
   176  		if len(config.ControlPlane.Platform.OpenStack.RootVolume.Types) > 0 {
   177  			// Return error if both type and types of rootVolume are specified in the config
   178  			return field.Forbidden(field.NewPath("controlPlane").Child("platform").Child("openstack").Child("rootVolume").Child("type"), "cannot specify type and types in rootVolume together")
   179  		}
   180  		config.ControlPlane.Platform.OpenStack.RootVolume.Types = []string{config.ControlPlane.Platform.OpenStack.RootVolume.DeprecatedType}
   181  		config.ControlPlane.Platform.OpenStack.RootVolume.DeprecatedType = ""
   182  	}
   183  	for _, pool := range config.Compute {
   184  		mpool := pool.Platform.OpenStack
   185  		if mpool != nil && mpool.RootVolume != nil && mpool.RootVolume.DeprecatedType != "" {
   186  			if mpool.RootVolume.Types != nil && len(mpool.RootVolume.Types) > 0 {
   187  				// Return error if both type and types of rootVolume are specified in the config
   188  				return field.Forbidden(field.NewPath("compute").Child("platform").Child("openstack").Child("rootVolume").Child("type"), "cannot specify type and types in rootVolume together")
   189  			}
   190  			mpool.RootVolume.Types = []string{mpool.RootVolume.DeprecatedType}
   191  			mpool.RootVolume.DeprecatedType = ""
   192  		}
   193  	}
   194  	if config.Platform.OpenStack.DefaultMachinePlatform != nil && config.Platform.OpenStack.DefaultMachinePlatform.RootVolume != nil && config.Platform.OpenStack.DefaultMachinePlatform.RootVolume.DeprecatedType != "" {
   195  		if len(config.Platform.OpenStack.DefaultMachinePlatform.RootVolume.Types) > 0 {
   196  			// Return error if both type and types of defaultMachinePlatform are specified in the config
   197  			return field.Forbidden(field.NewPath("platform").Child("openstack").Child("type"), "cannot specify type and types in defaultMachinePlatform together")
   198  		}
   199  		config.Platform.OpenStack.DefaultMachinePlatform.RootVolume.Types = []string{config.Platform.OpenStack.DefaultMachinePlatform.RootVolume.DeprecatedType}
   200  		config.Platform.OpenStack.DefaultMachinePlatform.RootVolume.DeprecatedType = ""
   201  	}
   202  
   203  	if err := upconvertVIP(&config.Platform.OpenStack.APIVIPs, config.Platform.OpenStack.DeprecatedAPIVIP, "apiVIP", "apiVIPs", field.NewPath("platform").Child("openstack")); err != nil {
   204  		return err
   205  	}
   206  
   207  	if err := upconvertVIP(&config.Platform.OpenStack.IngressVIPs, config.Platform.OpenStack.DeprecatedIngressVIP, "ingressVIP", "ingressVIPs", field.NewPath("platform").Child("openstack")); err != nil {
   208  		return err
   209  	}
   210  
   211  	// machinesSubnet has been deprecated in favor of ControlPlanePort
   212  	controlPlanePort := config.Platform.OpenStack.ControlPlanePort
   213  	deprecatedMachinesSubnet := config.Platform.OpenStack.DeprecatedMachinesSubnet
   214  	if deprecatedMachinesSubnet != "" && controlPlanePort == nil {
   215  		fixedIPs := []openstack.FixedIP{{Subnet: openstack.SubnetFilter{ID: deprecatedMachinesSubnet}}}
   216  		config.Platform.OpenStack.ControlPlanePort = &openstack.PortTarget{FixedIPs: fixedIPs}
   217  	} else if deprecatedMachinesSubnet != "" &&
   218  		controlPlanePort != nil {
   219  		if !(len(controlPlanePort.FixedIPs) == 1 && controlPlanePort.FixedIPs[0].Subnet.ID == deprecatedMachinesSubnet) {
   220  			return field.Invalid(field.NewPath("platform").Child("openstack").Child("machinesSubnet"), deprecatedMachinesSubnet, fmt.Sprintf("%s is deprecated; only %s needs to be specified", "machinesSubnet", "controlPlanePort"))
   221  		}
   222  	}
   223  
   224  	return nil
   225  }
   226  
   227  // convertNutanix upconverts deprecated fields in the Nutanix platform.
   228  func convertNutanix(config *types.InstallConfig) error {
   229  	if err := upconvertVIP(&config.Platform.Nutanix.APIVIPs, config.Platform.Nutanix.DeprecatedAPIVIP, "apiVIP", "apiVIPs", field.NewPath("platform").Child("nutanix")); err != nil {
   230  		return err
   231  	}
   232  
   233  	if err := upconvertVIP(&config.Platform.Nutanix.IngressVIPs, config.Platform.Nutanix.DeprecatedIngressVIP, "ingressVIP", "ingressVIPs", field.NewPath("platform").Child("nutanix")); err != nil {
   234  		return err
   235  	}
   236  
   237  	return nil
   238  }
   239  
   240  // convertVSphere upconverts deprecated fields in the VSphere platform.
   241  func convertVSphere(config *types.InstallConfig) error {
   242  	if err := upconvertVIP(&config.Platform.VSphere.APIVIPs, config.Platform.VSphere.DeprecatedAPIVIP, "apiVIP", "apiVIPs", field.NewPath("platform").Child("vsphere")); err != nil {
   243  		return err
   244  	}
   245  
   246  	if err := upconvertVIP(&config.Platform.VSphere.IngressVIPs, config.Platform.VSphere.DeprecatedIngressVIP, "ingressVIP", "ingressVIPs", field.NewPath("platform").Child("vsphere")); err != nil {
   247  		return err
   248  	}
   249  
   250  	return nil
   251  }
   252  
   253  // convertOVirt upconverts deprecated fields in the OVirt platform.
   254  func convertOVirt(config *types.InstallConfig) error {
   255  	if err := upconvertVIP(&config.Platform.Ovirt.APIVIPs, config.Platform.Ovirt.DeprecatedAPIVIP, "api_vip", "api_vips", field.NewPath("platform").Child("ovirt")); err != nil {
   256  		return err
   257  	}
   258  
   259  	if err := upconvertVIP(&config.Platform.Ovirt.IngressVIPs, config.Platform.Ovirt.DeprecatedIngressVIP, "ingress_vip", "ingress_vips", field.NewPath("platform").Child("ovirt")); err != nil {
   260  		return err
   261  	}
   262  
   263  	return nil
   264  }
   265  
   266  // upconvertVIP upconverts the deprecated VIP (oldVIPValue) to the new VIPs
   267  // slice (newVIPValues). It returns errors, if both fields are set and all
   268  // contain unique values
   269  func upconvertVIP(newVIPValues *[]string, oldVIPValue, newFieldName, oldFieldName string, fldPath *field.Path) error {
   270  	if oldVIPValue != "" && len(*newVIPValues) == 0 {
   271  		*newVIPValues = []string{oldVIPValue}
   272  	} else if oldVIPValue != "" &&
   273  		len(*newVIPValues) > 0 &&
   274  		!utilsslice.Contains(*newVIPValues, oldVIPValue) {
   275  
   276  		return field.Invalid(fldPath.Child(oldFieldName), oldVIPValue, fmt.Sprintf("%s is deprecated; only %s needs to be specified", oldFieldName, newFieldName))
   277  	}
   278  
   279  	return nil
   280  }
   281  
   282  // convertAWS upconverts deprecated fields in the AWS platform.
   283  func convertAWS(config *types.InstallConfig) error {
   284  	// Deprecated ExperimentalPropagateUserTag takes precedence when set
   285  	if config.Platform.AWS.ExperimentalPropagateUserTag != nil {
   286  		config.Platform.AWS.PropagateUserTag = *config.Platform.AWS.ExperimentalPropagateUserTag
   287  	}
   288  	// BestEffortDeleteIgnition takes precedence when set
   289  	if !config.AWS.BestEffortDeleteIgnition {
   290  		config.AWS.BestEffortDeleteIgnition = config.AWS.PreserveBootstrapIgnition
   291  	}
   292  	if ami := config.AWS.AMIID; len(ami) > 0 {
   293  		if config.AWS.DefaultMachinePlatform == nil {
   294  			config.AWS.DefaultMachinePlatform = &aws.MachinePool{}
   295  		}
   296  		// DefaultMachinePlatform.AMIID takes precedence in the machine manifest code anyway
   297  		if len(config.AWS.DefaultMachinePlatform.AMIID) == 0 {
   298  			config.AWS.DefaultMachinePlatform.AMIID = ami
   299  		}
   300  	}
   301  	return nil
   302  }