Skip to content

Commit

Permalink
OpenStack: Set minimum disk of a flavor to 100 GB
Browse files Browse the repository at this point in the history
Other platforms require at least 100 GB of disk size and we've updated
openshift-docs to reflect that in OpenStack too. Seems like we forgot to
update flavor validation code and docs in the installer. This commit
fixes this.
  • Loading branch information
dulek committed Aug 30, 2022
1 parent 1c8e79b commit 4e4b17a
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 30 deletions.
8 changes: 4 additions & 4 deletions docs/user/openstack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ For a successful installation it is required:
- Server Groups: 2, plus one per additional Availability zone in each machine-pool
- RAM: 112 GB
- vCPUs: 28
- Volume Storage: 175 GB
- Volume Storage: 700 GB
- Instances: 7
- Depending on the type of [image registry backend](#image-registry-requirements) either 1 Swift container or an additional 100 GB volume.
- OpenStack resource tagging
Expand All @@ -97,21 +97,21 @@ Once you configure the quota for your project, please ensure that the user for t

### Master Nodes

The default deployment stands up 3 master nodes, which is the minimum amount required for a cluster. For each master node you stand up, you will need 1 instance, and 1 port available in your quota. They should be assigned a flavor with at least 16 GB RAM, 4 vCPUs, and 25 GB Disk (or Root Volume). It is theoretically possible to run with a smaller flavor, but be aware that if it takes too long to stand up services, or certain essential services crash, the installer could time out, leading to a failed install.
The default deployment stands up 3 master nodes, which is the minimum amount required for a cluster. For each master node you stand up, you will need 1 instance, and 1 port available in your quota. They should be assigned a flavor with at least 16 GB RAM, 4 vCPUs, and 100 GB Disk (or Root Volume). It is theoretically possible to run with a smaller flavor, but be aware that if it takes too long to stand up services, or certain essential services crash, the installer could time out, leading to a failed install.

The master nodes are placed in a single Server group with "soft anti-affinity" policy by default; the machines will therefore be created on separate hosts when possible.

### Worker Nodes

The default deployment stands up 3 worker nodes. Worker nodes host the applications you run on OpenShift. The flavor assigned to the worker nodes should have at least 2 vCPUs, 8 GB RAM and 25 GB Disk (or Root Volume). However, if you are experiencing `Out Of Memory` issues, or your installs are timing out, try increasing the size of your flavor to match the master nodes: 4 vCPUs and 16 GB RAM.
The default deployment stands up 3 worker nodes. Worker nodes host the applications you run on OpenShift. The flavor assigned to the worker nodes should have at least 2 vCPUs, 8 GB RAM and 100 GB Disk (or Root Volume). However, if you are experiencing `Out Of Memory` issues, or your installs are timing out, try increasing the size of your flavor to match the master nodes: 4 vCPUs and 16 GB RAM.

The worker nodes are placed in a single Server group with "soft anti-affinity" policy by default; the machines will therefore be created on separate hosts when possible.

See the [OpenShift documentation](https://docs.openshift.com/container-platform/4.4/architecture/control-plane.html#defining-workers_control-plane) for more information on the worker nodes.

### Bootstrap Node

The bootstrap node is a temporary node that is responsible for standing up the control plane on the masters. Only one bootstrap node will be stood up and it will be deprovisioned once the production control plane is ready. To do so, you need 1 instance, and 1 port. We recommend a flavor with a minimum of 16 GB RAM, 4 vCPUs, and 25 GB Disk (or Root Volume).
The bootstrap node is a temporary node that is responsible for standing up the control plane on the masters. Only one bootstrap node will be stood up and it will be deprovisioned once the production control plane is ready. To do so, you need 1 instance, and 1 port. We recommend a flavor with a minimum of 16 GB RAM, 4 vCPUs, and 100 GB Disk (or Root Volume).

### Image Registry Requirements

Expand Down
2 changes: 1 addition & 1 deletion docs/user/openstack/deploy_sriov_workers.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ in OpenShift, and that your tenant has access to them. Your OpenStack cluster mu
- One instance from the RHOSP quota
- One port attached to the machines subnet
- One port for each SR-IOV Virtual Function
- A flavor with at least 16 GB memory, 4 vCPUs, and 25 GB storage space
- A flavor with at least 16 GB memory, 4 vCPUs, and 100 GB storage space

For all clusters that use single-root input/output virtualization (SR-IOV), RHOSP compute nodes require a flavor that supports [huge pages][huge-pages].
Deploying worker nodes with SR-IOV networks is supported as a post-install operation for both IPI and UPI workflows. After you verify that your OpenStack cluster can support SR-IOV in OpenShift and you install an OpenShift cluster that meets the [minimum requirements](README.md#openstack-requirements), use the following steps and examples to create worker nodes with SR-IOV NICs.
Expand Down
33 changes: 22 additions & 11 deletions pkg/asset/installconfig/openstack/validation/machinepool.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package validation
import (
"fmt"

"github.com/sirupsen/logrus"

"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field"

Expand All @@ -11,23 +13,26 @@ import (
)

type flavorRequirements struct {
RAM, VCPUs, Disk int
RAM, VCPUs, Disk, RecommendedDisk int
}

const (
minimumStorage = 25
minimumStorage = 25
recommendedStorage = 100
)

var (
ctrlPlaneFlavorMinimums = flavorRequirements{
RAM: 16384,
VCPUs: 4,
Disk: minimumStorage,
RAM: 16384,
VCPUs: 4,
Disk: minimumStorage,
RecommendedDisk: recommendedStorage,
}
computeFlavorMinimums = flavorRequirements{
RAM: 8192,
VCPUs: 2,
Disk: minimumStorage,
RAM: 8192,
VCPUs: 2,
Disk: minimumStorage,
RecommendedDisk: recommendedStorage,
}
)

Expand All @@ -40,7 +45,9 @@ func ValidateMachinePool(p *openstack.MachinePool, ci *CloudInfo, controlPlane b
if p.RootVolume != nil {
allErrs = append(allErrs, validateVolumeTypes(p.RootVolume.Type, ci.VolumeTypes, fldPath.Child("rootVolume").Child("type"))...)
if p.RootVolume.Size < minimumStorage {
allErrs = append(allErrs, field.Invalid(fldPath.Child("rootVolume").Child("size"), p.RootVolume.Size, fmt.Sprintf("Volume size must be greater than %d to use root volumes, had %d", minimumStorage, p.RootVolume.Size)))
allErrs = append(allErrs, field.Invalid(fldPath.Child("rootVolume").Child("size"), p.RootVolume.Size, fmt.Sprintf("Volume size must be greater than %d GB to use root volumes, had %d GB", minimumStorage, p.RootVolume.Size)))
} else if p.RootVolume.Size < recommendedStorage {
logrus.Warnf("Volume size is recommended to be greater than %d GB to use root volumes, had %d GB", recommendedStorage, p.RootVolume.Size)
}

allErrs = append(allErrs, validateZones(p.RootVolume.Zones, ci.VolumeZones, fldPath.Child("rootVolume").Child("zones"))...)
Expand Down Expand Up @@ -149,8 +156,12 @@ func validateFlavor(flavorName string, ci *CloudInfo, req flavorRequirements, fl
if flavor.VCPUs < req.VCPUs {
errs = append(errs, fmt.Sprintf("Must have minimum of %d VCPUs, had %d", req.VCPUs, flavor.VCPUs))
}
if flavor.Disk < req.Disk && storage {
errs = append(errs, fmt.Sprintf("Must have minimum of %d GB Disk, had %d GB", req.Disk, flavor.Disk))
if storage {
if flavor.Disk < req.Disk {
errs = append(errs, fmt.Sprintf("Must have minimum of %d GB Disk, had %d GB", req.Disk, flavor.Disk))
} else if flavor.Disk < req.RecommendedDisk {
logrus.Warnf("Flavor does not meet the following recommended requirements: It is recommended to have %d GB Disk, had %d GB", req.RecommendedDisk, flavor.Disk)
}
}

if len(errs) == 0 {
Expand Down
98 changes: 84 additions & 14 deletions pkg/asset/installconfig/openstack/validation/machinepool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"testing"

"github.com/openshift/installer/pkg/types/openstack"
logrusTest "github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/util/validation/field"

Expand All @@ -21,13 +22,16 @@ const (

invalidComputeFlavor = "invalid-compute-flavor"
invalidCtrlPlaneFlavor = "invalid-control-plane-flavor"
warningComputeFlavor = "warning-compute-flavor"
warningCtrlPlaneFlavor = "warning-control-plane-flavor"

baremetalFlavor = "baremetal-flavor"

volumeType = "performance"
invalidType = "invalid-type"
volumeSmallSize = 10
volumeLargeSize = 25
volumeType = "performance"
invalidType = "invalid-type"
volumeSmallSize = 10
volumeMediumSize = 40
volumeLargeSize = 100
)

func validMachinePool() *openstack.MachinePool {
Expand All @@ -49,6 +53,18 @@ func invalidMachinePoolSmallVolume() *openstack.MachinePool {
}
}

func warningMachinePoolMediumVolume() *openstack.MachinePool {
return &openstack.MachinePool{
FlavorName: validCtrlPlaneFlavor,
Zones: []string{""},
RootVolume: &openstack.RootVolume{
Type: volumeType,
Size: volumeMediumSize,
Zones: []string{""},
},
}
}

func validMachinePoolLargeVolume() *openstack.MachinePool {
return &openstack.MachinePool{
FlavorName: validCtrlPlaneFlavor,
Expand All @@ -68,23 +84,23 @@ func validMpoolCloudInfo() *CloudInfo {
Flavor: flavors.Flavor{
Name: validCtrlPlaneFlavor,
RAM: 16384,
Disk: 25,
Disk: 100,
VCPUs: 4,
},
},
validComputeFlavor: {
Flavor: flavors.Flavor{
Name: validComputeFlavor,
RAM: 8192,
Disk: 25,
Disk: 100,
VCPUs: 2,
},
},
invalidCtrlPlaneFlavor: {
Flavor: flavors.Flavor{
Name: invalidCtrlPlaneFlavor,
RAM: 8192, // too low
Disk: 25,
Disk: 100,
VCPUs: 2, // too low
},
},
Expand All @@ -96,6 +112,22 @@ func validMpoolCloudInfo() *CloudInfo {
VCPUs: 2,
},
},
warningCtrlPlaneFlavor: {
Flavor: flavors.Flavor{
Name: warningCtrlPlaneFlavor,
RAM: 16384,
Disk: 40, // not recommended
VCPUs: 4,
},
},
warningComputeFlavor: {
Flavor: flavors.Flavor{
Name: invalidComputeFlavor,
RAM: 8192,
Disk: 40, // not recommended
VCPUs: 2,
},
},
baremetalFlavor: {
Flavor: flavors.Flavor{
Name: baremetalFlavor,
Expand All @@ -120,12 +152,13 @@ func validMpoolCloudInfo() *CloudInfo {

func TestOpenStackMachinepoolValidation(t *testing.T) {
cases := []struct {
name string
controlPlane bool // only matters for flavor
mpool *openstack.MachinePool
cloudInfo *CloudInfo
expectedError bool
expectedErrMsg string // NOTE: this is a REGEXP
name string
controlPlane bool // only matters for flavor
mpool *openstack.MachinePool
cloudInfo *CloudInfo
expectedError bool
expectedErrMsg string // NOTE: this is a REGEXP
expectedWarnMsg string //NOTE: this is a REGEXP
}{
{
name: "valid control plane",
Expand Down Expand Up @@ -232,6 +265,28 @@ func TestOpenStackMachinepoolValidation(t *testing.T) {
expectedError: true,
expectedErrMsg: `compute\[0\].platform.openstack.type: Invalid value: "invalid-compute-flavor": Flavor did not meet the following minimum requirements: Must have minimum of 25 GB Disk, had 10 GB`,
},
{
name: "warning control plane flavorName",
controlPlane: true,
mpool: func() *openstack.MachinePool {
mp := validMachinePool()
mp.FlavorName = warningCtrlPlaneFlavor
return mp
}(),
cloudInfo: validMpoolCloudInfo(),
expectedWarnMsg: `Flavor does not meet the following recommended requirements: It is recommended to have 100 GB Disk, had 40 GB`,
},
{
name: "warning compute flavorName",
controlPlane: false,
mpool: func() *openstack.MachinePool {
mp := validMachinePool()
mp.FlavorName = warningComputeFlavor
return mp
}(),
cloudInfo: validMpoolCloudInfo(),
expectedWarnMsg: `Flavor does not meet the following recommended requirements: It is recommended to have 100 GB Disk, had 40 GB`,
},
{
name: "valid baremetal compute",
controlPlane: false,
Expand All @@ -254,7 +309,18 @@ func TestOpenStackMachinepoolValidation(t *testing.T) {
}(),
cloudInfo: validMpoolCloudInfo(),
expectedError: true,
expectedErrMsg: "Volume size must be greater than 25 to use root volumes, had 10",
expectedErrMsg: "Volume size must be greater than 25 GB to use root volumes, had 10 GB",
},
{
name: "volume not recommended",
controlPlane: false,
mpool: func() *openstack.MachinePool {
mp := warningMachinePoolMediumVolume()
mp.FlavorName = invalidCtrlPlaneFlavor
return mp
}(),
cloudInfo: validMpoolCloudInfo(),
expectedWarnMsg: "Volume size is recommended to be greater than 100 GB to use root volumes, had 40 GB",
},
{
name: "volume big enough",
Expand Down Expand Up @@ -338,12 +404,16 @@ func TestOpenStackMachinepoolValidation(t *testing.T) {
fieldPath = field.NewPath("compute").Index(0).Child("platform", "openstack")
}

hook := logrusTest.NewGlobal()
aggregatedErrors := ValidateMachinePool(tc.mpool, tc.cloudInfo, tc.controlPlane, fieldPath).ToAggregate()
if tc.expectedError {
assert.Regexp(t, tc.expectedErrMsg, aggregatedErrors)
} else {
assert.NoError(t, aggregatedErrors)
}
if len(tc.expectedWarnMsg) > 0 {
assert.Regexp(t, tc.expectedWarnMsg, hook.LastEntry().Message)
}
})
}
}

0 comments on commit 4e4b17a

Please sign in to comment.