1
0
mirror of https://github.com/openshift/installer.git synced 2026-02-05 06:46:36 +01:00

Support for External LB as Tech Preview

This commit is contained in:
Emilien Macchi
2023-01-27 10:40:55 -05:00
committed by Emilien Macchi
parent c8c5d5973c
commit 625932f5c3
32 changed files with 997 additions and 49 deletions

View File

@@ -2225,6 +2225,28 @@ spec:
must be reachable from the host where the installer is run.
Default is qemu:///system
type: string
loadBalancer:
description: LoadBalancer defines how the load balancer used by
the cluster is configured. LoadBalancer is available in TechPreview.
properties:
type:
default: OpenShiftManagedDefault
description: type defines the type of load balancer used by
the cluster on BareMetal platform which can be a user-managed
or openshift-managed load balancer that is to be used for
the OpenShift API and Ingress endpoints. When set to OpenShiftManagedDefault
the static pods in charge of API and Ingress traffic load-balancing
defined in the machine config operator will be deployed.
When set to UserManaged these static pods will not be deployed
and it is expected that the load balancer is configured
out of band by the deployer. When omitted, this means no
opinion and the platform is left to choose a reasonable
default. The default value is OpenShiftManagedDefault.
enum:
- OpenShiftManagedDefault
- UserManaged
type: string
type: object
provisioningBridge:
description: Provisioning bridge is used for provisioning nodes,
on the host that will run the bootstrap VM.
@@ -2627,6 +2649,28 @@ spec:
maxItems: 2
type: array
uniqueItems: true
loadBalancer:
description: LoadBalancer defines how the load balancer used by
the cluster is configured. LoadBalancer is available in TechPreview.
properties:
type:
default: OpenShiftManagedDefault
description: type defines the type of load balancer used by
the cluster on Nutanix platform which can be a user-managed
or openshift-managed load balancer that is to be used for
the OpenShift API and Ingress endpoints. When set to OpenShiftManagedDefault
the static pods in charge of API and Ingress traffic load-balancing
defined in the machine config operator will be deployed.
When set to UserManaged these static pods will not be deployed
and it is expected that the load balancer is configured
out of band by the deployer. When omitted, this means no
opinion and the platform is left to choose a reasonable
default. The default value is OpenShiftManagedDefault.
enum:
- OpenShiftManagedDefault
- UserManaged
type: string
type: object
prismCentral:
description: PrismCentral is the endpoint (address and port) and
credentials to connect to the Prism Central.
@@ -2871,6 +2915,28 @@ spec:
IP in your OpenStack cluster to associate with the OpenShift
load balancer. Deprecated: this value has been renamed to apiFloatingIP.'
type: string
loadBalancer:
description: LoadBalancer defines how the load balancer used by
the cluster is configured. LoadBalancer is available in TechPreview.
properties:
type:
default: OpenShiftManagedDefault
description: type defines the type of load balancer used by
the cluster on OpenStack platform which can be a user-managed
or openshift-managed load balancer that is to be used for
the OpenShift API and Ingress endpoints. When set to OpenShiftManagedDefault
the static pods in charge of API and Ingress traffic load-balancing
defined in the machine config operator will be deployed.
When set to UserManaged these static pods will not be deployed
and it is expected that the load balancer is configured
out of band by the deployer. When omitted, this means no
opinion and the platform is left to choose a reasonable
default. The default value is OpenShiftManagedDefault.
enum:
- OpenShiftManagedDefault
- UserManaged
type: string
type: object
machinesSubnet:
description: MachinesSubnet is the UUIDv4 of an openstack subnet.
This subnet will be used by all nodes created by the installer.
@@ -3065,6 +3131,28 @@ spec:
maxItems: 2
type: array
uniqueItems: true
loadBalancer:
description: LoadBalancer defines how the load balancer used by
the cluster is configured. LoadBalancer is available in TechPreview.
properties:
type:
default: OpenShiftManagedDefault
description: type defines the type of load balancer used by
the cluster on Ovirt platform which can be a user-managed
or openshift-managed load balancer that is to be used for
the OpenShift API and Ingress endpoints. When set to OpenShiftManagedDefault
the static pods in charge of API and Ingress traffic load-balancing
defined in the machine config operator will be deployed.
When set to UserManaged these static pods will not be deployed
and it is expected that the load balancer is configured
out of band by the deployer. When omitted, this means no
opinion and the platform is left to choose a reasonable
default. The default value is OpenShiftManagedDefault.
enum:
- OpenShiftManagedDefault
- UserManaged
type: string
type: object
ovirt_cluster_id:
description: The target cluster under which all VMs will run
type: string
@@ -3372,6 +3460,28 @@ spec:
maxItems: 2
type: array
uniqueItems: true
loadBalancer:
description: LoadBalancer defines how the load balancer used by
the cluster is configured. LoadBalancer is available in TechPreview.
properties:
type:
default: OpenShiftManagedDefault
description: type defines the type of load balancer used by
the cluster on VSphere platform which can be a user-managed
or openshift-managed load balancer that is to be used for
the OpenShift API and Ingress endpoints. When set to OpenShiftManagedDefault
the static pods in charge of API and Ingress traffic load-balancing
defined in the machine config operator will be deployed.
When set to UserManaged these static pods will not be deployed
and it is expected that the load balancer is configured
out of band by the deployer. When omitted, this means no
opinion and the platform is left to choose a reasonable
default. The default value is OpenShiftManagedDefault.
enum:
- OpenShiftManagedDefault
- UserManaged
type: string
type: object
network:
description: 'Network specifies the name of the network to be
used by the cluster. Deprecated: Use FailureDomains.Topology.Network'

View File

@@ -52,8 +52,11 @@ resource "openstack_networking_port_v2" "bootstrap_port" {
subnet_id = var.nodes_subnet_id
}
allowed_address_pairs {
ip_address = var.openstack_api_int_ip
dynamic "allowed_address_pairs" {
for_each = var.openstack_user_managed_load_balancer ? [] : [1]
content {
ip_address = var.openstack_api_int_ip
}
}
depends_on = [var.master_port_ids]

View File

@@ -62,18 +62,25 @@ resource "openstack_networking_port_v2" "masters" {
subnet_id = local.nodes_subnet_id
}
allowed_address_pairs {
ip_address = var.openstack_api_int_ip
dynamic "allowed_address_pairs" {
for_each = var.openstack_user_managed_load_balancer ? [] : [1]
content {
ip_address = var.openstack_api_int_ip
}
}
allowed_address_pairs {
ip_address = var.openstack_ingress_ip
dynamic "allowed_address_pairs" {
for_each = var.openstack_user_managed_load_balancer ? [] : [1]
content {
ip_address = var.openstack_ingress_ip
}
}
depends_on = [openstack_networking_port_v2.api_port, openstack_networking_port_v2.ingress_port]
}
resource "openstack_networking_port_v2" "api_port" {
count = var.openstack_user_managed_load_balancer ? 0 : 1
name = "${var.cluster_id}-api-port"
description = local.description
@@ -89,6 +96,7 @@ resource "openstack_networking_port_v2" "api_port" {
}
resource "openstack_networking_port_v2" "ingress_port" {
count = var.openstack_user_managed_load_balancer ? 0 : 1
name = "${var.cluster_id}-ingress-port"
description = local.description
@@ -134,15 +142,15 @@ resource "openstack_networking_trunk_v2" "masters" {
// as expected.
resource "openstack_networking_floatingip_associate_v2" "api_fip" {
count = length(var.openstack_api_floating_ip) == 0 ? 0 : 1
port_id = openstack_networking_port_v2.api_port.id
count = (var.openstack_user_managed_load_balancer || length(var.openstack_api_floating_ip) == 0) ? 0 : 1
port_id = openstack_networking_port_v2.api_port[0].id
floating_ip = var.openstack_api_floating_ip
depends_on = [openstack_networking_router_interface_v2.nodes_router_interface]
}
resource "openstack_networking_floatingip_associate_v2" "ingress_fip" {
count = length(var.openstack_ingress_floating_ip) == 0 ? 0 : 1
port_id = openstack_networking_port_v2.ingress_port.id
count = (var.openstack_user_managed_load_balancer || length(var.openstack_ingress_floating_ip) == 0) ? 0 : 1
port_id = openstack_networking_port_v2.ingress_port[0].id
floating_ip = var.openstack_ingress_floating_ip
depends_on = [openstack_networking_router_interface_v2.nodes_router_interface]
}

View File

@@ -374,3 +374,8 @@ variable "openstack_worker_server_group_policy" {
type = string
description = "Policy of the server groups for the worker nodes."
}
variable "openstack_user_managed_load_balancer" {
type = bool
description = "True if the load balancer that is used for the control plane VIPs is managed by the user."
}

View File

@@ -27,7 +27,7 @@ func Validate(ic *types.InstallConfig) error {
allErrs = append(
allErrs,
validation.ValidatePlatform(ic.Platform.Ovirt, ovirtPlatformPath)...)
validation.ValidatePlatform(ic.Platform.Ovirt, ovirtPlatformPath, ic)...)
con, err := NewConnection()
if err != nil {

View File

@@ -59,7 +59,7 @@ func Validate(ic *types.InstallConfig) error {
if ic.Platform.VSphere == nil {
return errors.New(field.Required(field.NewPath("platform", "vsphere"), "vSphere validation requires a vSphere platform configuration").Error())
}
return validation.ValidatePlatform(ic.Platform.VSphere, field.NewPath("platform").Child("vsphere")).ToAggregate()
return validation.ValidatePlatform(ic.Platform.VSphere, field.NewPath("platform").Child("vsphere"), ic).ToAggregate()
}
func getVCenterClient(failureDomain vsphere.FailureDomain, ic *types.InstallConfig) (*validationContext, ClientLogout, error) {

View File

@@ -160,6 +160,7 @@ func (i *Infrastructure) Generate(dependencies asset.Parents) error {
IngressIP: installConfig.Config.Platform.BareMetal.IngressVIPs[0],
APIServerInternalIPs: installConfig.Config.Platform.BareMetal.APIVIPs,
IngressIPs: installConfig.Config.Platform.BareMetal.IngressVIPs,
LoadBalancer: installConfig.Config.Platform.BareMetal.LoadBalancer,
}
case gcp.Name:
config.Spec.PlatformSpec.Type = configv1.GCPPlatformType
@@ -210,6 +211,7 @@ func (i *Infrastructure) Generate(dependencies asset.Parents) error {
IngressIP: installConfig.Config.OpenStack.IngressVIPs[0],
APIServerInternalIPs: installConfig.Config.OpenStack.APIVIPs,
IngressIPs: installConfig.Config.OpenStack.IngressVIPs,
LoadBalancer: installConfig.Config.OpenStack.LoadBalancer,
}
case vsphere.Name:
config.Spec.PlatformSpec.Type = configv1.VSpherePlatformType
@@ -219,8 +221,10 @@ func (i *Infrastructure) Generate(dependencies asset.Parents) error {
IngressIP: installConfig.Config.VSphere.IngressVIPs[0],
APIServerInternalIPs: installConfig.Config.VSphere.APIVIPs,
IngressIPs: installConfig.Config.VSphere.IngressVIPs,
LoadBalancer: installConfig.Config.VSphere.LoadBalancer,
}
}
config.Spec.PlatformSpec.VSphere = vsphereinfra.GetInfraPlatformSpec(installConfig)
if _, exists := cloudproviderconfig.ConfigMap.Data["vsphere.conf"]; exists {
@@ -234,6 +238,7 @@ func (i *Infrastructure) Generate(dependencies asset.Parents) error {
IngressIP: installConfig.Config.Ovirt.IngressVIPs[0],
APIServerInternalIPs: installConfig.Config.Ovirt.APIVIPs,
IngressIPs: installConfig.Config.Ovirt.IngressVIPs,
LoadBalancer: installConfig.Config.Ovirt.LoadBalancer,
}
case powervs.Name:
config.Spec.PlatformSpec.Type = configv1.PowerVSPlatformType
@@ -303,6 +308,7 @@ func (i *Infrastructure) Generate(dependencies asset.Parents) error {
IngressIP: installConfig.Config.Nutanix.IngressVIPs[0],
APIServerInternalIPs: installConfig.Config.Nutanix.APIVIPs,
IngressIPs: installConfig.Config.Nutanix.IngressVIPs,
LoadBalancer: installConfig.Config.Nutanix.LoadBalancer,
}
}
default:

View File

@@ -12,6 +12,7 @@ import (
"github.com/gophercloud/gophercloud/openstack/networking/v2/subnets"
"github.com/gophercloud/utils/openstack/clientconfig"
configv1 "github.com/openshift/api/config/v1"
machinev1alpha1 "github.com/openshift/api/machine/v1alpha1"
"github.com/openshift/installer/pkg/asset/installconfig"
installconfig_openstack "github.com/openshift/installer/pkg/asset/installconfig/openstack"
@@ -95,6 +96,11 @@ func TFVars(
workermpool = installConfig.Config.Compute[0].Platform.OpenStack
}
var userManagedLoadBalancer bool
if lb := installConfig.Config.Platform.OpenStack.LoadBalancer; lb != nil && lb.Type == configv1.LoadBalancerTypeUserManaged {
userManagedLoadBalancer = true
}
var zones []string
{
seen := make(map[string]struct{})
@@ -211,6 +217,7 @@ func TFVars(
MachinesNetwork string `json:"openstack_machines_network_id,omitempty"`
MasterAvailabilityZones []string `json:"openstack_master_availability_zones,omitempty"`
MasterRootVolumeAvailabilityZones []string `json:"openstack_master_root_volume_availability_zones,omitempty"`
UserManagedLoadBalancer bool `json:"openstack_user_managed_load_balancer"`
}{
BaseImageName: imageName,
ExternalNetwork: installConfig.Config.Platform.OpenStack.ExternalNetwork,
@@ -236,6 +243,7 @@ func TFVars(
MachinesNetwork: machinesNetwork,
MasterAvailabilityZones: zones,
MasterRootVolumeAvailabilityZones: masterRootVolumeAvailabilityZones,
UserManagedLoadBalancer: userManagedLoadBalancer,
}, "", " ")
}

View File

@@ -3,6 +3,7 @@ package baremetal
import (
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
configv1 "github.com/openshift/api/config/v1"
"github.com/openshift/installer/pkg/ipnet"
)
@@ -226,4 +227,9 @@ type Platform struct {
// +kubebuilder:validation:Format=ip
// +optional
BootstrapExternalStaticGateway string `json:"bootstrapExternalStaticGateway,omitempty"`
// LoadBalancer defines how the load balancer used by the cluster is configured.
// LoadBalancer is available in TechPreview.
// +optional
LoadBalancer *configv1.BareMetalPlatformLoadBalancer `json:"loadBalancer,omitempty"`
}

View File

@@ -19,6 +19,7 @@ import (
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
configv1 "github.com/openshift/api/config/v1"
"github.com/openshift/installer/pkg/ipnet"
"github.com/openshift/installer/pkg/types"
"github.com/openshift/installer/pkg/types/baremetal"
@@ -425,9 +426,32 @@ func ValidatePlatform(p *baremetal.Platform, n *types.Networking, fldPath *field
allErrs = append(allErrs, validateHostsName(p.Hosts, fldPath.Child("Hosts"))...)
}
// Platform fields only allowed in TechPreviewNoUpgrade
if c.FeatureSet != configv1.TechPreviewNoUpgrade {
if c.BareMetal.LoadBalancer != nil {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("loadBalancer"), "load balancer is not supported in this feature set"))
}
}
if c.BareMetal.LoadBalancer != nil {
if !validateLoadBalancer(c.BareMetal.LoadBalancer.Type) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("loadBalancer", "type"), c.BareMetal.LoadBalancer.Type, "invalid load balancer type"))
}
}
return allErrs
}
// validateLoadBalancer returns an error if the load balancer is not valid.
func validateLoadBalancer(lbType configv1.PlatformLoadBalancerType) bool {
switch lbType {
case configv1.LoadBalancerTypeOpenShiftManagedDefault, configv1.LoadBalancerTypeUserManaged:
return true
default:
return false
}
}
// ValidateProvisioning checks that provisioning network requirements specified is valid.
func ValidateProvisioning(p *baremetal.Platform, n *types.Networking, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}

View File

@@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/util/validation/field"
configv1 "github.com/openshift/api/config/v1"
"github.com/openshift/installer/pkg/ipnet"
"github.com/openshift/installer/pkg/types"
"github.com/openshift/installer/pkg/types/baremetal"
@@ -180,6 +181,35 @@ func TestValidatePlatform(t *testing.T) {
ControlPlane(machinePool().Replicas(1)).build(),
expected: "baremetal.hosts\\[0\\].Name: Required value: missing Name",
},
{
name: "forbidden_feature_loadbalancer",
config: installConfig().
BareMetalPlatform(
platform().LoadBalancerType("OpenShiftManagedDefault")).build(),
expected: "baremetal.loadBalancer: Forbidden: load balancer is not supported in this feature set",
},
{
name: "allowed_feature_loadbalancer_openshift_managed_default",
config: installConfig().
BareMetalPlatform(
platform().LoadBalancerType("OpenShiftManagedDefault")).
FeatureSet(configv1.TechPreviewNoUpgrade).build(),
},
{
name: "allowed_feature_loadbalancer_user_managed",
config: installConfig().
BareMetalPlatform(
platform().LoadBalancerType("UserManaged")).
FeatureSet(configv1.TechPreviewNoUpgrade).build(),
},
{
name: "allowed_feature_loadbalancer_invalid",
config: installConfig().
BareMetalPlatform(
platform().LoadBalancerType("FooBar")).
FeatureSet(configv1.TechPreviewNoUpgrade).build(),
expected: "baremetal.loadBalancer.type: Invalid value: \"FooBar\": invalid load balancer type",
},
{
name: "missing_mac",
platform: platform().
@@ -312,7 +342,7 @@ interfaces:
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
//Build default wrapping installConfig
// Build default wrapping installConfig
if tc.config == nil {
tc.config = installConfig().build()
tc.config.BareMetal = tc.platform
@@ -656,7 +686,7 @@ func TestValidateProvisioning(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
//Build default wrapping installConfig
// Build default wrapping installConfig
if tc.config == nil {
tc.config = installConfig().build()
}
@@ -861,6 +891,13 @@ func (pb *platformBuilder) Hosts(builders ...*hostBuilder) *platformBuilder {
return pb
}
func (pb *platformBuilder) LoadBalancerType(value string) *platformBuilder {
pb.Platform.LoadBalancer = &configv1.BareMetalPlatformLoadBalancer{
Type: configv1.PlatformLoadBalancerType(value),
}
return pb
}
func (pb *platformBuilder) LibvirtURI(value string) *platformBuilder {
pb.Platform.LibvirtURI = value
return pb
@@ -916,6 +953,11 @@ func (icb *installConfigBuilder) BareMetalPlatform(builder *platformBuilder) *in
return icb
}
func (icb *installConfigBuilder) FeatureSet(value configv1.FeatureSet) *installConfigBuilder {
icb.InstallConfig.FeatureSet = value
return icb
}
func (icb *installConfigBuilder) ControlPlane(builder *machinePoolBuilder) *installConfigBuilder {
icb.InstallConfig.ControlPlane = builder.build()

View File

@@ -1,5 +1,9 @@
package nutanix
import (
configv1 "github.com/openshift/api/config/v1"
)
// Platform stores any global configuration used for Nutanix platforms.
type Platform struct {
// PrismCentral is the endpoint (address and port) and credentials to
@@ -56,6 +60,11 @@ type Platform struct {
// SubnetUUIDs identifies the network subnets to be used by the cluster.
// Currently we only support one subnet for an OpenShift cluster.
SubnetUUIDs []string `json:"subnetUUIDs"`
// LoadBalancer defines how the load balancer used by the cluster is configured.
// LoadBalancer is available in TechPreview.
// +optional
LoadBalancer *configv1.NutanixPlatformLoadBalancer `json:"loadBalancer,omitempty"`
}
// PrismCentral holds the endpoint and credentials data used to connect to the Prism Central

View File

@@ -3,13 +3,15 @@ package validation
import (
"k8s.io/apimachinery/pkg/util/validation/field"
configv1 "github.com/openshift/api/config/v1"
"github.com/openshift/installer/pkg/types"
"github.com/openshift/installer/pkg/types/nutanix"
"github.com/openshift/installer/pkg/validate"
)
// ValidatePlatform checks that the specified platform is valid.
// TODO(nutanix): Revisit for further expanding the validation logic
func ValidatePlatform(p *nutanix.Platform, fldPath *field.Path) field.ErrorList {
func ValidatePlatform(p *nutanix.Platform, fldPath *field.Path, c *types.InstallConfig) field.ErrorList {
allErrs := field.ErrorList{}
if len(p.PrismCentral.Endpoint.Address) == 0 {
@@ -69,5 +71,28 @@ func ValidatePlatform(p *nutanix.Platform, fldPath *field.Path) field.ErrorList
allErrs = append(allErrs, field.Required(fldPath.Child("subnet"), "must specify the subnet"))
}
// Platform fields only allowed in TechPreviewNoUpgrade
if c.FeatureSet != configv1.TechPreviewNoUpgrade {
if c.Nutanix.LoadBalancer != nil {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("loadBalancer"), "load balancer is not supported in this feature set"))
}
}
if c.Nutanix.LoadBalancer != nil {
if !validateLoadBalancer(c.Nutanix.LoadBalancer.Type) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("loadBalancer", "type"), c.Nutanix.LoadBalancer.Type, "invalid load balancer type"))
}
}
return allErrs
}
// validateLoadBalancer returns an error if the load balancer is not valid.
func validateLoadBalancer(lbType configv1.PlatformLoadBalancerType) bool {
switch lbType {
case configv1.LoadBalancerTypeOpenShiftManagedDefault, configv1.LoadBalancerTypeUserManaged:
return true
default:
return false
}
}

View File

@@ -6,6 +6,8 @@ import (
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/util/validation/field"
configv1 "github.com/openshift/api/config/v1"
"github.com/openshift/installer/pkg/types"
"github.com/openshift/installer/pkg/types/nutanix"
)
@@ -27,6 +29,7 @@ func validPlatform() *nutanix.Platform {
func TestValidatePlatform(t *testing.T) {
cases := []struct {
name string
config *types.InstallConfig
platform *nutanix.Platform
expectedError string
}{
@@ -43,6 +46,71 @@ func TestValidatePlatform(t *testing.T) {
}(),
expectedError: `^test-path\.prismCentral\.endpoint\.address: Required value: must specify the Prism Central endpoint address$`,
},
{
name: "forbidden load balancer field",
platform: validPlatform(),
config: &types.InstallConfig{
Platform: types.Platform{
Nutanix: func() *nutanix.Platform {
p := validPlatform()
p.LoadBalancer = &configv1.NutanixPlatformLoadBalancer{
Type: configv1.LoadBalancerTypeOpenShiftManagedDefault,
}
return p
}(),
},
},
expectedError: `^test-path\.loadBalancer: Forbidden: load balancer is not supported in this feature set`,
},
{
name: "allowed load balancer field with OpenShift managed default",
platform: validPlatform(),
config: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
Platform: types.Platform{
Nutanix: func() *nutanix.Platform {
p := validPlatform()
p.LoadBalancer = &configv1.NutanixPlatformLoadBalancer{
Type: configv1.LoadBalancerTypeOpenShiftManagedDefault,
}
return p
}(),
},
},
},
{
name: "allowed load balancer field with user-managed",
platform: validPlatform(),
config: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
Platform: types.Platform{
Nutanix: func() *nutanix.Platform {
p := validPlatform()
p.LoadBalancer = &configv1.NutanixPlatformLoadBalancer{
Type: configv1.LoadBalancerTypeUserManaged,
}
return p
}(),
},
},
},
{
name: "allowed load balancer field invalid type",
platform: validPlatform(),
config: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
Platform: types.Platform{
Nutanix: func() *nutanix.Platform {
p := validPlatform()
p.LoadBalancer = &configv1.NutanixPlatformLoadBalancer{
Type: "FooBar",
}
return p
}(),
},
},
expectedError: `^test-path\.loadBalancer.type: Invalid value: "FooBar": invalid load balancer type`,
},
{
name: "missing Prism Central username",
platform: func() *nutanix.Platform {
@@ -118,7 +186,12 @@ func TestValidatePlatform(t *testing.T) {
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
err := ValidatePlatform(tc.platform, field.NewPath("test-path")).ToAggregate()
// Build default wrapping installConfig
if tc.config == nil {
tc.config = installConfig().build()
tc.config.Nutanix = tc.platform
}
err := ValidatePlatform(tc.platform, field.NewPath("test-path"), tc.config).ToAggregate()
if tc.expectedError == "" {
assert.NoError(t, err)
} else {
@@ -127,3 +200,17 @@ func TestValidatePlatform(t *testing.T) {
})
}
}
type installConfigBuilder struct {
types.InstallConfig
}
func installConfig() *installConfigBuilder {
return &installConfigBuilder{
InstallConfig: types.InstallConfig{},
}
}
func (icb *installConfigBuilder) build() *types.InstallConfig {
return &icb.InstallConfig
}

View File

@@ -1,5 +1,9 @@
package openstack
import (
configv1 "github.com/openshift/api/config/v1"
)
// Platform stores all the global configuration that all
// machinesets use.
type Platform struct {
@@ -114,4 +118,9 @@ type Platform struct {
// The subnet and network specified in MachinesSubnet will not be deleted or modified by the installer.
// +optional
MachinesSubnet string `json:"machinesSubnet,omitempty"`
// LoadBalancer defines how the load balancer used by the cluster is configured.
// LoadBalancer is available in TechPreview.
// +optional
LoadBalancer *configv1.OpenStackPlatformLoadBalancer `json:"loadBalancer,omitempty"`
}

View File

@@ -3,6 +3,7 @@ package validation
import (
"k8s.io/apimachinery/pkg/util/validation/field"
configv1 "github.com/openshift/api/config/v1"
"github.com/openshift/installer/pkg/types"
"github.com/openshift/installer/pkg/types/openstack"
"github.com/openshift/installer/pkg/validate"
@@ -20,5 +21,28 @@ func ValidatePlatform(p *openstack.Platform, n *types.Networking, fldPath *field
allErrs = append(allErrs, ValidateMachinePool(p, p.DefaultMachinePlatform, "default", fldPath.Child("defaultMachinePlatform"))...)
// Platform fields only allowed in TechPreviewNoUpgrade
if c.FeatureSet != configv1.TechPreviewNoUpgrade {
if c.OpenStack.LoadBalancer != nil {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("loadBalancer"), "load balancer is not supported in this feature set"))
}
}
if c.OpenStack.LoadBalancer != nil {
if !validateLoadBalancer(c.OpenStack.LoadBalancer.Type) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("loadBalancer", "type"), c.OpenStack.LoadBalancer.Type, "invalid load balancer type"))
}
}
return allErrs
}
// validateLoadBalancer returns an error if the load balancer is not valid.
func validateLoadBalancer(lbType configv1.PlatformLoadBalancerType) bool {
switch lbType {
case configv1.LoadBalancerTypeOpenShiftManagedDefault, configv1.LoadBalancerTypeUserManaged:
return true
default:
return false
}
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/util/validation/field"
configv1 "github.com/openshift/api/config/v1"
"github.com/openshift/installer/pkg/ipnet"
"github.com/openshift/installer/pkg/types"
"github.com/openshift/installer/pkg/types/openstack"
@@ -33,6 +34,7 @@ func validNetworking() *types.Networking {
func TestValidatePlatform(t *testing.T) {
cases := []struct {
name string
config *types.InstallConfig
platform *openstack.Platform
networking *types.Networking
noClouds bool
@@ -41,6 +43,7 @@ func TestValidatePlatform(t *testing.T) {
validMachinesSubnet bool
invalidMachinesSubnet bool
valid bool
expectedError string
}{
{
name: "minimal",
@@ -48,6 +51,75 @@ func TestValidatePlatform(t *testing.T) {
networking: validNetworking(),
valid: true,
},
{
name: "forbidden load balancer field",
platform: validPlatform(),
config: &types.InstallConfig{
Platform: types.Platform{
OpenStack: func() *openstack.Platform {
p := validPlatform()
p.LoadBalancer = &configv1.OpenStackPlatformLoadBalancer{
Type: configv1.LoadBalancerTypeOpenShiftManagedDefault,
}
return p
}(),
},
},
valid: false,
expectedError: `^test-path\.loadBalancer: Forbidden: load balancer is not supported in this feature set`,
},
{
name: "allowed load balancer field with OpenShift managed default",
platform: validPlatform(),
config: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
Platform: types.Platform{
OpenStack: func() *openstack.Platform {
p := validPlatform()
p.LoadBalancer = &configv1.OpenStackPlatformLoadBalancer{
Type: configv1.LoadBalancerTypeOpenShiftManagedDefault,
}
return p
}(),
},
},
valid: true,
},
{
name: "allowed load balancer field with user-managed",
platform: validPlatform(),
config: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
Platform: types.Platform{
OpenStack: func() *openstack.Platform {
p := validPlatform()
p.LoadBalancer = &configv1.OpenStackPlatformLoadBalancer{
Type: configv1.LoadBalancerTypeUserManaged,
}
return p
}(),
},
},
valid: true,
},
{
name: "allowed load balancer field invalid type",
platform: validPlatform(),
config: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
Platform: types.Platform{
OpenStack: func() *openstack.Platform {
p := validPlatform()
p.LoadBalancer = &configv1.OpenStackPlatformLoadBalancer{
Type: "FooBar",
}
return p
}(),
},
},
expectedError: `^test-path\.loadBalancer.type: Invalid value: "FooBar": invalid load balancer type`,
valid: false,
},
{
name: "non IP external dns",
platform: func() *openstack.Platform {
@@ -57,8 +129,9 @@ func TestValidatePlatform(t *testing.T) {
}
return p
}(),
networking: validNetworking(),
valid: false,
networking: validNetworking(),
valid: false,
expectedError: `\"invalid\" is not a valid IP`,
},
{
name: "valid external dns",
@@ -75,15 +148,32 @@ func TestValidatePlatform(t *testing.T) {
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
testConfig := types.InstallConfig{}
testConfig.ObjectMeta.Name = "test"
// Build default wrapping installConfig
if tc.config == nil {
tc.config = installConfig().build()
tc.config.OpenStack = tc.platform
}
err := ValidatePlatform(tc.platform, tc.networking, field.NewPath("test-path"), &testConfig).ToAggregate()
if tc.valid {
err := ValidatePlatform(tc.platform, tc.networking, field.NewPath("test-path"), tc.config).ToAggregate()
if tc.expectedError == "" {
assert.NoError(t, err)
} else {
assert.Error(t, err)
assert.Regexp(t, tc.expectedError, err)
}
})
}
}
type installConfigBuilder struct {
types.InstallConfig
}
func installConfig() *installConfigBuilder {
return &installConfigBuilder{
InstallConfig: types.InstallConfig{},
}
}
func (icb *installConfigBuilder) build() *types.InstallConfig {
return &icb.InstallConfig
}

View File

@@ -1,5 +1,9 @@
package ovirt
import (
configv1 "github.com/openshift/api/config/v1"
)
// Platform stores all the global configuration that all
// machinesets use.
type Platform struct {
@@ -66,6 +70,11 @@ type Platform struct {
// AffinityGroups contains the RHV affinity groups that the installer will create.
// +optional
AffinityGroups []AffinityGroup `json:"affinityGroups"`
// LoadBalancer defines how the load balancer used by the cluster is configured.
// LoadBalancer is available in TechPreview.
// +optional
LoadBalancer *configv1.OvirtPlatformLoadBalancer `json:"loadBalancer,omitempty"`
}
// AffinityGroup defines the affinity group that the installer will create

View File

@@ -6,12 +6,14 @@ import (
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/util/validation/field"
configv1 "github.com/openshift/api/config/v1"
"github.com/openshift/installer/pkg/types"
"github.com/openshift/installer/pkg/types/ovirt"
"github.com/openshift/installer/pkg/validate"
)
// ValidatePlatform checks that the specified platform is valid.
func ValidatePlatform(p *ovirt.Platform, fldPath *field.Path) field.ErrorList {
func ValidatePlatform(p *ovirt.Platform, fldPath *field.Path, c *types.InstallConfig) field.ErrorList {
allErrs := field.ErrorList{}
if err := validate.UUID(p.ClusterID); err != nil {
allErrs = append(allErrs, field.Invalid(fldPath.Child("ovirt_cluster_id"), p.ClusterID, err.Error()))
@@ -32,6 +34,19 @@ func ValidatePlatform(p *ovirt.Platform, fldPath *field.Path) field.ErrorList {
allErrs = append(allErrs, ValidateMachinePool(p.DefaultMachinePlatform, fldPath.Child("defaultMachinePlatform"))...)
}
// Platform fields only allowed in TechPreviewNoUpgrade
if c.FeatureSet != configv1.TechPreviewNoUpgrade {
if c.Ovirt.LoadBalancer != nil {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("loadBalancer"), "load balancer is not supported in this feature set"))
}
}
if c.Ovirt.LoadBalancer != nil {
if !validateLoadBalancer(c.Ovirt.LoadBalancer.Type) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("loadBalancer", "type"), c.Ovirt.LoadBalancer.Type, "invalid load balancer type"))
}
}
return allErrs
}
@@ -78,3 +93,13 @@ func validateAffinityGroupDuplicate(agList []ovirt.AffinityGroup) field.ErrorLis
}
return allErrs
}
// validateLoadBalancer returns an error if the load balancer is not valid.
func validateLoadBalancer(lbType configv1.PlatformLoadBalancerType) bool {
switch lbType {
case configv1.LoadBalancerTypeOpenShiftManagedDefault, configv1.LoadBalancerTypeUserManaged:
return true
default:
return false
}
}

View File

@@ -6,6 +6,8 @@ import (
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/util/validation/field"
configv1 "github.com/openshift/api/config/v1"
"github.com/openshift/installer/pkg/types"
"github.com/openshift/installer/pkg/types/ovirt"
)
@@ -23,15 +25,86 @@ func validPlatform() *ovirt.Platform {
func TestValidatePlatform(t *testing.T) {
cases := []struct {
name string
platform *ovirt.Platform
valid bool
name string
config *types.InstallConfig
platform *ovirt.Platform
valid bool
expectedError string
}{
{
name: "minimal",
platform: validPlatform(),
valid: true,
},
{
name: "forbidden load balancer field",
platform: validPlatform(),
config: &types.InstallConfig{
Platform: types.Platform{
Ovirt: func() *ovirt.Platform {
p := validPlatform()
p.LoadBalancer = &configv1.OvirtPlatformLoadBalancer{
Type: configv1.LoadBalancerTypeOpenShiftManagedDefault,
}
return p
}(),
},
},
valid: false,
expectedError: `^test-path\.loadBalancer: Forbidden: load balancer is not supported in this feature set`,
},
{
name: "allowed load balancer field with OpenShift managed default",
platform: validPlatform(),
config: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
Platform: types.Platform{
Ovirt: func() *ovirt.Platform {
p := validPlatform()
p.LoadBalancer = &configv1.OvirtPlatformLoadBalancer{
Type: configv1.LoadBalancerTypeOpenShiftManagedDefault,
}
return p
}(),
},
},
valid: true,
},
{
name: "allowed load balancer field with user-managed",
platform: validPlatform(),
config: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
Platform: types.Platform{
Ovirt: func() *ovirt.Platform {
p := validPlatform()
p.LoadBalancer = &configv1.OvirtPlatformLoadBalancer{
Type: configv1.LoadBalancerTypeUserManaged,
}
return p
}(),
},
},
valid: true,
},
{
name: "allowed load balancer field invalid type",
platform: validPlatform(),
config: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
Platform: types.Platform{
Ovirt: func() *ovirt.Platform {
p := validPlatform()
p.LoadBalancer = &configv1.OvirtPlatformLoadBalancer{
Type: "FooBar",
}
return p
}(),
},
},
expectedError: `^test-path\.loadBalancer.type: Invalid value: "FooBar": invalid load balancer type`,
valid: false,
},
{
name: "invalid when empty cluster ID",
platform: func() *ovirt.Platform {
@@ -39,7 +112,8 @@ func TestValidatePlatform(t *testing.T) {
p.ClusterID = ""
return p
}(),
valid: false,
expectedError: `^test-path.ovirt_cluster_id: Invalid value: "": invalid UUID length: 0`,
valid: false,
},
{
name: "invalid when empty storage ID",
@@ -48,7 +122,8 @@ func TestValidatePlatform(t *testing.T) {
p.StorageDomainID = ""
return p
}(),
valid: false,
expectedError: `^test-path.ovirt_storage_domain_id: Invalid value: "": invalid UUID length: 0`,
valid: false,
},
{
name: "malformed vnic profile id",
@@ -57,7 +132,8 @@ func TestValidatePlatform(t *testing.T) {
p.VNICProfileID = "abcd-sdf"
return p
}(),
valid: false,
expectedError: `^test-path.vnicProfileID: Invalid value: "abcd-sdf": invalid UUID length: 8`,
valid: false,
},
{
name: "valid empty vnic profile id",
@@ -80,12 +156,32 @@ func TestValidatePlatform(t *testing.T) {
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
err := ValidatePlatform(tc.platform, field.NewPath("test-path")).ToAggregate()
if tc.valid {
// Build default wrapping installConfig
if tc.config == nil {
tc.config = installConfig().build()
tc.config.Ovirt = tc.platform
}
err := ValidatePlatform(tc.platform, field.NewPath("test-path"), tc.config).ToAggregate()
if tc.expectedError == "" {
assert.NoError(t, err)
} else {
assert.Error(t, err)
assert.Regexp(t, tc.expectedError, err)
}
})
}
}
type installConfigBuilder struct {
types.InstallConfig
}
func installConfig() *installConfigBuilder {
return &installConfigBuilder{
InstallConfig: types.InstallConfig{},
}
}
func (icb *installConfigBuilder) build() *types.InstallConfig {
return &icb.InstallConfig
}

View File

@@ -722,7 +722,7 @@ func validatePlatform(platform *types.Platform, fldPath *field.Path, network *ty
}
if platform.VSphere != nil {
validate(vsphere.Name, platform.VSphere, func(f *field.Path) field.ErrorList {
return vspherevalidation.ValidatePlatform(platform.VSphere, f)
return vspherevalidation.ValidatePlatform(platform.VSphere, f, c)
})
}
if platform.BareMetal != nil {
@@ -732,12 +732,12 @@ func validatePlatform(platform *types.Platform, fldPath *field.Path, network *ty
}
if platform.Ovirt != nil {
validate(ovirt.Name, platform.Ovirt, func(f *field.Path) field.ErrorList {
return ovirtvalidation.ValidatePlatform(platform.Ovirt, f)
return ovirtvalidation.ValidatePlatform(platform.Ovirt, f, c)
})
}
if platform.Nutanix != nil {
validate(nutanix.Name, platform.Nutanix, func(f *field.Path) field.ErrorList {
return nutanixvalidation.ValidatePlatform(platform.Nutanix, f)
return nutanixvalidation.ValidatePlatform(platform.Nutanix, f, c)
})
}
return allErrs

View File

@@ -1,5 +1,9 @@
package vsphere
import (
configv1 "github.com/openshift/api/config/v1"
)
// DiskType is a disk provisioning type for vsphere.
// +kubebuilder:validation:Enum="";thin;thick;eagerZeroedThick
type DiskType string
@@ -116,6 +120,11 @@ type Platform struct {
// If this is omitted failure domains (regions and zones) will not be used.
// +kubebuilder:validation:Optional
FailureDomains []FailureDomain `json:"failureDomains,omitempty"`
// LoadBalancer defines how the load balancer used by the cluster is configured.
// LoadBalancer is available in TechPreview.
// +optional
LoadBalancer *configv1.VSpherePlatformLoadBalancer `json:"loadBalancer,omitempty"`
}
// FailureDomain holds the region and zone failure domain and

View File

@@ -9,13 +9,14 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field"
configv1 "github.com/openshift/api/config/v1"
"github.com/openshift/installer/pkg/types"
"github.com/openshift/installer/pkg/types/vsphere"
"github.com/openshift/installer/pkg/validate"
)
// ValidatePlatform checks that the specified platform is valid.
func ValidatePlatform(p *vsphere.Platform, fldPath *field.Path) field.ErrorList {
func ValidatePlatform(p *vsphere.Platform, fldPath *field.Path, c *types.InstallConfig) field.ErrorList {
isLegacyUpi := false
// This is to cover existing UPI non-zonal case
// where neither network or cluster is required.
@@ -44,6 +45,19 @@ func ValidatePlatform(p *vsphere.Platform, fldPath *field.Path) field.ErrorList
allErrs = append(allErrs, validateFailureDomains(p, fldPath.Child("failureDomains"), isLegacyUpi)...)
}
// Platform fields only allowed in TechPreviewNoUpgrade
if c.FeatureSet != configv1.TechPreviewNoUpgrade {
if c.VSphere.LoadBalancer != nil {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("loadBalancer"), "load balancer is not supported in this feature set"))
}
}
if c.VSphere.LoadBalancer != nil {
if !validateLoadBalancer(c.VSphere.LoadBalancer.Type) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("loadBalancer", "type"), c.VSphere.LoadBalancer.Type, "invalid load balancer type"))
}
}
return allErrs
}
@@ -197,3 +211,13 @@ func validateDiskType(p *vsphere.Platform, fldPath *field.Path) field.ErrorList
return allErrs
}
// validateLoadBalancer returns an error if the load balancer is not valid.
func validateLoadBalancer(lbType configv1.PlatformLoadBalancerType) bool {
switch lbType {
case configv1.LoadBalancerTypeOpenShiftManagedDefault, configv1.LoadBalancerTypeUserManaged:
return true
default:
return false
}
}

View File

@@ -7,6 +7,8 @@ import (
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/util/validation/field"
configv1 "github.com/openshift/api/config/v1"
"github.com/openshift/installer/pkg/types"
"github.com/openshift/installer/pkg/types/vsphere"
)
@@ -57,10 +59,10 @@ func validPlatform() *vsphere.Platform {
func TestValidatePlatform(t *testing.T) {
cases := []struct {
name string
platform *vsphere.Platform
postValidationFunction func(*vsphere.Platform) error
expectedError string
name string
config *types.InstallConfig
platform *vsphere.Platform
expectedError string
}{
{
name: "Valid diskType",
@@ -213,21 +215,99 @@ func TestValidatePlatform(t *testing.T) {
}(),
expectedError: `^test-path\.failureDomains\.zone: Required value: must specify zone tag value`,
},
{
name: "forbidden load balancer field",
platform: validPlatform(),
config: &types.InstallConfig{
Platform: types.Platform{
VSphere: func() *vsphere.Platform {
p := validPlatform()
p.LoadBalancer = &configv1.VSpherePlatformLoadBalancer{
Type: configv1.LoadBalancerTypeOpenShiftManagedDefault,
}
return p
}(),
},
},
expectedError: `^test-path\.loadBalancer: Forbidden: load balancer is not supported in this feature set`,
},
{
name: "allowed load balancer field with OpenShift managed default",
platform: validPlatform(),
config: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
Platform: types.Platform{
VSphere: func() *vsphere.Platform {
p := validPlatform()
p.LoadBalancer = &configv1.VSpherePlatformLoadBalancer{
Type: configv1.LoadBalancerTypeOpenShiftManagedDefault,
}
return p
}(),
},
},
},
{
name: "allowed load balancer field with user-managed",
platform: validPlatform(),
config: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
Platform: types.Platform{
VSphere: func() *vsphere.Platform {
p := validPlatform()
p.LoadBalancer = &configv1.VSpherePlatformLoadBalancer{
Type: configv1.LoadBalancerTypeUserManaged,
}
return p
}(),
},
},
},
{
name: "allowed load balancer field invalid type",
platform: validPlatform(),
config: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
Platform: types.Platform{
VSphere: func() *vsphere.Platform {
p := validPlatform()
p.LoadBalancer = &configv1.VSpherePlatformLoadBalancer{
Type: "FooBar",
}
return p
}(),
},
},
expectedError: `^test-path\.loadBalancer.type: Invalid value: "FooBar": invalid load balancer type`,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
err := ValidatePlatform(tc.platform, field.NewPath("test-path")).ToAggregate()
// Build default wrapping installConfig
if tc.config == nil {
tc.config = installConfig().build()
tc.config.VSphere = tc.platform
}
err := ValidatePlatform(tc.platform, field.NewPath("test-path"), tc.config).ToAggregate()
if tc.expectedError == "" {
assert.NoError(t, err)
} else {
assert.Regexp(t, regexp.MustCompile(tc.expectedError), err)
}
if tc.postValidationFunction != nil {
err := tc.postValidationFunction(tc.platform)
if err != nil {
assert.NoError(t, err)
}
}
})
}
}
type installConfigBuilder struct {
types.InstallConfig
}
func installConfig() *installConfigBuilder {
return &installConfigBuilder{
InstallConfig: types.InstallConfig{},
}
}
func (icb *installConfigBuilder) build() *types.InstallConfig {
return &icb.InstallConfig
}

View File

@@ -0,0 +1,31 @@
apiVersion: v1
baseDomain: shiftstack.example.com
controlPlane:
hyperthreading: Enabled
architecture: amd64
name: master
platform:
openstack:
type: ${COMPUTE_FLAVOR}
replicas: 3
compute:
- name: worker
platform:
openstack:
type: ${COMPUTE_FLAVOR}
replicas: 3
metadata:
name: manifests1
networking:
clusterNetwork:
- cidr: 10.128.0.0/14
hostPrefix: 23
machineNetwork:
- cidr: 10.0.128.0/17
networkType: OVNKubernetes
serviceNetwork:
- 172.30.0.0/16
platform:
openstack:
cloud: ${OS_CLOUD}
pullSecret: ${PULL_SECRET}

View File

@@ -0,0 +1,27 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import unittest
import sys
import glob
import yaml
ASSETS_DIR = ""
class TestClusterInfraObject(unittest.TestCase):
def setUp(self):
"""Parse the Cluster Infrastructure object into a Python data structure."""
self.machines = []
cluster_infra = f'{ASSETS_DIR}/manifests/cluster-infrastructure-02-config.yml'
with open(cluster_infra) as f:
self.cluster_infra = yaml.load(f, Loader=yaml.FullLoader)
def test_load_balancer(self):
"""Assert that the Cluster infrastructure object does not contain the LoadBalancer configuration."""
self.assertNotIn("loadBalancer", self.cluster_infra["status"]["platformStatus"]["openstack"])
if __name__ == '__main__':
ASSETS_DIR = sys.argv.pop()
unittest.main(verbosity=2)

View File

@@ -0,0 +1,32 @@
apiVersion: v1
baseDomain: shiftstack.example.com
controlPlane:
hyperthreading: Enabled
architecture: amd64
name: master
platform:
openstack:
type: ${COMPUTE_FLAVOR}
replicas: 3
compute:
- name: worker
platform:
openstack:
type: ${COMPUTE_FLAVOR}
replicas: 3
metadata:
name: manifests1
networking:
clusterNetwork:
- cidr: 10.128.0.0/14
hostPrefix: 23
machineNetwork:
- cidr: 10.0.128.0/17
networkType: OVNKubernetes
serviceNetwork:
- 172.30.0.0/16
platform:
openstack:
cloud: ${OS_CLOUD}
featureSet: TechPreviewNoUpgrade
pullSecret: ${PULL_SECRET}

View File

@@ -0,0 +1,27 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import unittest
import sys
import glob
import yaml
ASSETS_DIR = ""
class TestClusterInfraObject(unittest.TestCase):
def setUp(self):
"""Parse the Cluster Infrastructure object into a Python data structure."""
self.machines = []
cluster_infra = f'{ASSETS_DIR}/manifests/cluster-infrastructure-02-config.yml'
with open(cluster_infra) as f:
self.cluster_infra = yaml.load(f, Loader=yaml.FullLoader)
def test_load_balancer(self):
"""Assert that the Cluster infrastructure object does not contain the LoadBalancer configuration."""
self.assertNotIn("loadBalancer", self.cluster_infra["status"]["platformStatus"]["openstack"])
if __name__ == '__main__':
ASSETS_DIR = sys.argv.pop()
unittest.main(verbosity=2)

View File

@@ -0,0 +1,34 @@
apiVersion: v1
baseDomain: shiftstack.example.com
controlPlane:
hyperthreading: Enabled
architecture: amd64
name: master
platform:
openstack:
type: ${COMPUTE_FLAVOR}
replicas: 3
compute:
- name: worker
platform:
openstack:
type: ${COMPUTE_FLAVOR}
replicas: 3
metadata:
name: manifests1
networking:
clusterNetwork:
- cidr: 10.128.0.0/14
hostPrefix: 23
machineNetwork:
- cidr: 10.0.128.0/17
networkType: OVNKubernetes
serviceNetwork:
- 172.30.0.0/16
platform:
openstack:
cloud: ${OS_CLOUD}
loadBalancer:
type: OpenShiftManagedDefault
featureSet: TechPreviewNoUpgrade
pullSecret: ${PULL_SECRET}

View File

@@ -0,0 +1,32 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import unittest
import sys
import glob
import yaml
ASSETS_DIR = ""
class TestClusterInfraObject(unittest.TestCase):
def setUp(self):
"""Parse the Cluster Infrastructure object into a Python data structure."""
self.machines = []
cluster_infra = f'{ASSETS_DIR}/manifests/cluster-infrastructure-02-config.yml'
with open(cluster_infra) as f:
self.cluster_infra = yaml.load(f, Loader=yaml.FullLoader)
def test_load_balancer(self):
"""Assert that the Cluster infrastructure object contains the LoadBalancer configuration."""
self.assertIn("loadBalancer", self.cluster_infra["status"]["platformStatus"]["openstack"])
loadBalancer = self.cluster_infra["status"]["platformStatus"]["openstack"]["loadBalancer"]
self.assertIn("type", loadBalancer)
self.assertEqual("OpenShiftManagedDefault", loadBalancer["type"])
if __name__ == '__main__':
ASSETS_DIR = sys.argv.pop()
unittest.main(verbosity=2)

View File

@@ -0,0 +1,34 @@
apiVersion: v1
baseDomain: shiftstack.example.com
controlPlane:
hyperthreading: Enabled
architecture: amd64
name: master
platform:
openstack:
type: ${COMPUTE_FLAVOR}
replicas: 3
compute:
- name: worker
platform:
openstack:
type: ${COMPUTE_FLAVOR}
replicas: 3
metadata:
name: manifests1
networking:
clusterNetwork:
- cidr: 10.128.0.0/14
hostPrefix: 23
machineNetwork:
- cidr: 10.0.128.0/17
networkType: OVNKubernetes
serviceNetwork:
- 172.30.0.0/16
platform:
openstack:
cloud: ${OS_CLOUD}
loadBalancer:
type: UserManaged
featureSet: TechPreviewNoUpgrade
pullSecret: ${PULL_SECRET}

View File

@@ -0,0 +1,32 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import unittest
import sys
import glob
import yaml
ASSETS_DIR = ""
class TestClusterInfraObject(unittest.TestCase):
def setUp(self):
"""Parse the Cluster Infrastructure object into a Python data structure."""
self.machines = []
cluster_infra = f'{ASSETS_DIR}/manifests/cluster-infrastructure-02-config.yml'
with open(cluster_infra) as f:
self.cluster_infra = yaml.load(f, Loader=yaml.FullLoader)
def test_load_balancer(self):
"""Assert that the Cluster infrastructure object contains the LoadBalancer configuration."""
self.assertIn("loadBalancer", self.cluster_infra["status"]["platformStatus"]["openstack"])
loadBalancer = self.cluster_infra["status"]["platformStatus"]["openstack"]["loadBalancer"]
self.assertIn("type", loadBalancer)
self.assertEqual("UserManaged", loadBalancer["type"])
if __name__ == '__main__':
ASSETS_DIR = sys.argv.pop()
unittest.main(verbosity=2)