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 }