ceph: allow passing 'osd-crush-initial-weight'

Ceph support the option '--osd-crush-initial-weight' upon OSD start,
which sets an explicit weight (in TiB units) to specific OSD. Allow
passing this option all the way from the user (similar to
'DeviceClass'), for the special case where end users wants it cluster
to have non-even balance over specific OSDs (e.g., one of the OSDs is
placed over a partition alongside OS-partition).

ROOK issue: https://github.com/rook/rook/issues/7448

Signed-off-by: Shachar Sharon <ssharon@redhat.com>
This commit is contained in:
Shachar Sharon
2021-04-20 20:50:54 +03:00
parent 8c1ac86325
commit 9766e9b8fb
12 changed files with 70 additions and 0 deletions
@@ -3160,6 +3160,10 @@ spec:
crushDeviceClass:
description: CrushDeviceClass represents the crush device class for an OSD
type: string
crushInitialWeight:
description: CrushInitialWeight represents initial OSD weight in TiB units
pattern: ^([0-9]*[.])?[0-9]$
type: string
encrypted:
description: Whether to encrypt the deviceSet
type: boolean
@@ -3162,6 +3162,10 @@ spec:
crushDeviceClass:
description: CrushDeviceClass represents the crush device class for an OSD
type: string
crushInitialWeight:
description: CrushInitialWeight represents initial OSD weight in TiB units
pattern: ^([0-9]*[.])?[0-9]$
type: string
encrypted:
description: Whether to encrypt the deviceSet
type: boolean
+2
View File
@@ -118,6 +118,7 @@ func addOSDConfigFlags(command *cobra.Command) {
command.Flags().IntVar(&cfg.storeConfig.OSDsPerDevice, "osds-per-device", 1, "the number of OSDs per device")
command.Flags().BoolVar(&cfg.storeConfig.EncryptedDevice, "encrypted-device", false, "whether to encrypt the OSD with dmcrypt")
command.Flags().StringVar(&cfg.storeConfig.DeviceClass, "osd-crush-device-class", "", "The device class for all OSDs configured on this node")
command.Flags().StringVar(&cfg.storeConfig.InitialWeight, "osd-crush-initial-weight", "", "The initial weight of OSD in TiB units")
}
func init() {
@@ -303,6 +304,7 @@ func parseDevices(devices string) ([]osddaemon.DesiredDevice, error) {
d.OSDsPerDevice = cd.StoreConfig.OSDsPerDevice
d.DatabaseSizeMB = cd.StoreConfig.DatabaseSizeMB
d.DeviceClass = cd.StoreConfig.DeviceClass
d.InitialWeight = cd.StoreConfig.InitialWeight
d.MetadataDevice = cd.StoreConfig.MetadataDevice
if d.OSDsPerDevice < 1 {
+4
View File
@@ -217,6 +217,10 @@ type VolumeSource struct {
// CrushDeviceClass represents the crush device class for an OSD
// +optional
CrushDeviceClass string `json:"crushDeviceClass,omitempty"`
// CrushInitialWeight represents initial OSD weight in TiB units
// +kubebuilder:validation:Pattern=`^([0-9]*[.])?[0-9]$`
// +optional
CrushInitialWeight string `json:"crushInitialWeight,omitempty"`
// Size represents the size requested for the PVC
Size string `json:"size"`
// Resources requests/limits for the devices
+1
View File
@@ -42,6 +42,7 @@ type DesiredDevice struct {
MetadataDevice string
DatabaseSizeMB int
DeviceClass string
InitialWeight string
IsFilter bool
IsDevicePathFilter bool
}
@@ -29,6 +29,7 @@ const (
EncryptedDeviceKey = "encryptedDevice"
MetadataDeviceKey = "metadataDevice"
DeviceClassKey = "deviceClass"
InitialWeightKey = "initialWeight"
)
// StoreConfig represents the configuration of an OSD on a device.
@@ -39,6 +40,7 @@ type StoreConfig struct {
EncryptedDevice bool `json:"encryptedDevice,omitempty"`
MetadataDevice string `json:"metadataDevice,omitempty"`
DeviceClass string `json:"deviceClass,omitempty"`
InitialWeight string `json:"initialWeight,omitempty"`
}
// NewStoreConfig returns a StoreConfig with proper defaults set.
@@ -68,6 +70,8 @@ func ToStoreConfig(config map[string]string) StoreConfig {
storeConfig.MetadataDevice = v
case DeviceClassKey:
storeConfig.DeviceClass = v
case InitialWeightKey:
storeConfig.InitialWeight = v
}
}
@@ -96,6 +96,7 @@ func (c *Cluster) createDeviceSetPVCsForIndex(deviceSet rookv1.StorageClassDevic
var dataSize string
var crushDeviceClass string
var crushInitialWeight string
typesFound := util.NewSet()
for _, pvcTemplate := range deviceSet.VolumeClaimTemplates {
if pvcTemplate.Name == "" {
@@ -126,6 +127,8 @@ func (c *Cluster) createDeviceSetPVCsForIndex(deviceSet rookv1.StorageClassDevic
dataSize = pvcSize.String()
crushDeviceClass = pvcTemplate.Annotations["crushDeviceClass"]
}
crushInitialWeight = pvcTemplate.Annotations["crushInitialWeight"]
pvcSources[pvcType] = v1.PersistentVolumeClaimVolumeSource{
ClaimName: pvc.GetName(),
ReadOnly: false,
@@ -145,6 +148,7 @@ func (c *Cluster) createDeviceSetPVCsForIndex(deviceSet rookv1.StorageClassDevic
TuneFastDeviceClass: deviceSet.TuneFastDeviceClass,
SchedulerName: deviceSet.SchedulerName,
CrushDeviceClass: crushDeviceClass,
CrushInitialWeight: crushInitialWeight,
Encrypted: deviceSet.Encrypted,
}
}
@@ -269,3 +269,37 @@ func TestUpdatePVCSize(t *testing.T) {
assert.True(t, ok)
assert.Equal(t, "6Gi", result.String())
}
func TestPrepareDeviceSetsWithCrushParams(t *testing.T) {
ctx := context.TODO()
clientset := testexec.New(t, 1)
context := &clusterd.Context{
Clientset: clientset,
}
deviceSet := rookv1.StorageClassDeviceSet{
Name: "datawithcrushparams1",
Count: 1,
VolumeClaimTemplates: []corev1.PersistentVolumeClaim{testVolumeClaim("testwithcrushparams1")},
SchedulerName: "custom-scheduler",
}
deviceSet.VolumeClaimTemplates[0].Annotations = map[string]string{"crushDeviceClass": "ssd", "crushInitialWeight": "0.75"}
spec := cephv1.ClusterSpec{
Storage: rookv1.StorageScopeSpec{StorageClassDeviceSets: []rookv1.StorageClassDeviceSet{deviceSet}},
}
cluster := &Cluster{
context: context,
clusterInfo: client.AdminClusterInfo("testns"),
spec: spec,
}
config := newProvisionErrors()
volumeSources := cluster.prepareStorageClassDeviceSets(config)
assert.Equal(t, 1, len(volumeSources))
assert.Equal(t, volumeSources[0].CrushDeviceClass, "ssd")
assert.Equal(t, volumeSources[0].CrushInitialWeight, "0.75")
pvcs, err := clientset.CoreV1().PersistentVolumeClaims(cluster.clusterInfo.Namespace).List(ctx, metav1.ListOptions{})
assert.NoError(t, err)
assert.Equal(t, 1, len(pvcs.Items))
}
+5
View File
@@ -45,6 +45,7 @@ const (
cvModeVarName = "ROOK_CV_MODE"
lvBackedPVVarName = "ROOK_LV_BACKED_PV"
CrushDeviceClassVarName = "ROOK_OSD_CRUSH_DEVICE_CLASS"
CrushInitialWeightVarName = "ROOK_OSD_CRUSH_INITIAL_WEIGHT"
CrushRootVarName = "ROOK_CRUSHMAP_ROOT"
tcmallocMaxTotalThreadCacheBytesEnv = "TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES"
)
@@ -159,6 +160,10 @@ func crushDeviceClassEnvVar(crushDeviceClass string) v1.EnvVar {
return v1.EnvVar{Name: CrushDeviceClassVarName, Value: crushDeviceClass}
}
func crushInitialWeightEnvVar(crushInitialWeight string) v1.EnvVar {
return v1.EnvVar{Name: CrushInitialWeightVarName, Value: crushInitialWeight}
}
func encryptedDeviceEnvVar(encryptedDevice bool) v1.EnvVar {
return v1.EnvVar{Name: EncryptedDeviceEnvVarName, Value: strconv.FormatBool(encryptedDevice)}
}
+2
View File
@@ -363,6 +363,8 @@ func (c *Cluster) getOSDPropsForPVC(pvcName string) (osdProperties, error) {
encrypted: volumeSource.Encrypted,
deviceSetName: volumeSource.Name,
}
osdProps.storeConfig.InitialWeight = volumeSource.CrushInitialWeight
// If OSD isn't portable, we're getting the host name either from the osd deployment that was already initialized
// or from the osd prepare job from initial creation.
if !volumeSource.Portable {
@@ -229,6 +229,7 @@ func (c *Cluster) provisionOSDContainer(osdProps osdProperties, copyBinariesMoun
}
envVars = append(envVars, v1.EnvVar{Name: "ROOK_CEPH_VERSION", Value: c.clusterInfo.CephVersion.CephVersionFormatted()})
envVars = append(envVars, crushDeviceClassEnvVar(osdProps.storeConfig.DeviceClass))
envVars = append(envVars, crushInitialWeightEnvVar(osdProps.storeConfig.InitialWeight))
if osdProps.metadataDevice != "" {
envVars = append(envVars, metadataDeviceEnvVar(osdProps.metadataDevice))
+5
View File
@@ -404,6 +404,11 @@ func (c *Cluster) makeDeployment(osdProps osdProperties, osd OSDInfo, provisionC
}
}
// Ceph expects initial weight as float value in tera-bytes units
if osdProps.storeConfig.InitialWeight != "" {
args = append(args, fmt.Sprintf("--osd-crush-initial-weight=%s", osdProps.storeConfig.InitialWeight))
}
// If the OSD runs on PVC
if osdProps.onPVC() {
// add the PVC size to the pod spec so that if the size changes the OSD will be restarted and pick up the change