Skip to content

Commit

Permalink
(feat): I finally solved the resize problem
Browse files Browse the repository at this point in the history
  • Loading branch information
lasith-kg committed Dec 25, 2023
1 parent 9cafa4d commit bcce1ff
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 28 deletions.
2 changes: 1 addition & 1 deletion configs/ubuntu.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
devices:
/dev/vdb:
fs: xfs
fs: ext4
label: external-vol
mountPoint: /mnt/app
group: ubuntu
Expand Down
9 changes: 3 additions & 6 deletions internal/backend/resize.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,9 @@ type BlockDeviceMetrics struct {
}

func (bdm *BlockDeviceMetrics) ShouldResize(threshold float64) bool {
// Handle edge case for dividing by zero
if bdm.BlockDeviceSize == 0 {
return false
}
utilisation := (float64(bdm.FileSystemSize) / float64(bdm.BlockDeviceSize)) * 100
return utilisation < threshold
// Minimum File System Size (mfss)
mfss := float64(bdm.BlockDeviceSize) * (threshold / 100)
return float64(bdm.FileSystemSize) < mfss
}

type DeviceResizeBackend interface {
Expand Down
15 changes: 3 additions & 12 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,7 @@ import (
)

const (
// DefaultResizeThreshold is the default threshold for triggering a filesystem resize.
// It is expressed as a percentage of the total filesystem size. If the used space
// is below this threshold, a resize operation will be initiated. The default value is
// set to 99.999% to account for occasional overhead that reduces the effective storage
// that can be used by the filesystem
DefaultResizeThreshold = 99.999
DefaultMountOptions = model.MountOptions("defaults")
DefaultMountOptions = model.MountOptions("defaults")
)

type Flag struct {
Expand Down Expand Up @@ -183,16 +177,13 @@ func (c *Config) GetResizeFs(name string) bool {
func (c *Config) GetResizeThreshold(name string) float64 {
cd, found := c.Devices[name]
if !found {
return DefaultResizeThreshold
return 0
}
if c.overrides.ResizeThreshold != 0 {
return c.overrides.ResizeThreshold
}
if cd.ResizeThreshold != 0 {
return cd.ResizeThreshold
}
if c.Defaults.ResizeThreshold != 0 {
return c.Defaults.ResizeThreshold
}
return DefaultResizeThreshold
return c.Defaults.ResizeThreshold
}
16 changes: 8 additions & 8 deletions internal/config/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (fsv *FileSystemValidator) Validate(c *Config) error {
for name, device := range c.Devices {
fs, err := model.ParseFileSystem(string(device.Fs))
if err != nil {
return fmt.Errorf("🔴 %s: %s is not a supported file system", name, fs)
return fmt.Errorf("🔴 %s: '%s' is not a supported file system", name, fs)
}
if fs == model.Unformatted {
return fmt.Errorf("🔴 %s: Must provide a supported file system", name)
Expand All @@ -62,13 +62,13 @@ func (fsv *ModeValidator) Validate(c *Config) error {
mode := string(c.Defaults.Mode)
_, err := model.ParseMode(mode)
if err != nil {
return fmt.Errorf("🔴 %s is not a supported global mode", mode)
return fmt.Errorf("🔴 '%s' (defaults) is not a global mode", mode)
}

mode = string(c.overrides.Mode)
_, err = model.ParseMode(mode)
if err != nil {
return fmt.Errorf("🔴 %s is not a supported overrides mode", mode)
return fmt.Errorf("🔴 '%s' (-mode) is not a supported mode", mode)
}

for name, device := range c.Devices {
Expand Down Expand Up @@ -111,11 +111,11 @@ func NewMountOptionsValidator() *MountOptionsValidator {
func (mov *MountOptionsValidator) Validate(c *Config) error {
mo := string(c.Defaults.MountOptions)
if err := mov.validate(mo); err != nil {
return fmt.Errorf("🔴 '%s' is not a supported global mode as %s", mo, err)
return fmt.Errorf("🔴 '%s' (defaults) is not a supported mode as %s", mo, err)
}
mo = string(c.overrides.MountOptions)
if err := mov.validate(mo); err != nil {
return fmt.Errorf("🔴 '%s' is not a supported overrides mode as %s", mo, err)
return fmt.Errorf("🔴 '%s' (-mount-options) is not a supported mode as %s", mo, err)
}
for name, device := range c.Devices {
mo := string(device.MountOptions)
Expand Down Expand Up @@ -172,14 +172,14 @@ func NewResizeThresholdValidator() *ResizeThresholdValidator {

func (rtv *ResizeThresholdValidator) Validate(c *Config) error {
if c.Defaults.ResizeThreshold < 0 || c.Defaults.ResizeThreshold > 100 {
return fmt.Errorf("🔴 '%g' (default) must be a floating point between 0 and 100", c.Defaults.ResizeThreshold)
return fmt.Errorf("🔴 '%g' (default) must be a floating point between (inclusive) 0 and 100", c.Defaults.ResizeThreshold)
}
if c.overrides.ResizeThreshold < 0 || c.overrides.ResizeThreshold > 100 {
return fmt.Errorf("🔴 '%g' (overrides) must be a floating point between 0 and 100", c.overrides.ResizeThreshold)
return fmt.Errorf("🔴 '%g' (-resize-threshold) must be a floating point between (inclusive) 0 and 100", c.overrides.ResizeThreshold)
}
for name, device := range c.Devices {
if device.ResizeThreshold < 0 || device.ResizeThreshold > 100 {
return fmt.Errorf("🔴 %s: '%g' must be a floating point between 0 and 100", name, device.ResizeThreshold)
return fmt.Errorf("🔴 %s: '%g' must be a floating point between (inclusive) 0 and 100", name, device.ResizeThreshold)
}
}
return nil
Expand Down
23 changes: 22 additions & 1 deletion internal/layer/resize.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package layer

import (
"fmt"

"github.com/reecetech/ebs-bootstrap/internal/action"
"github.com/reecetech/ebs-bootstrap/internal/backend"
"github.com/reecetech/ebs-bootstrap/internal/config"
Expand Down Expand Up @@ -35,7 +37,11 @@ func (fdl *ResizeDeviceLayer) Modify(c *config.Config) ([]action.Action, error)
return nil, err
}
mode := c.GetMode(name)
if rt := c.GetResizeThreshold(name); metrics.ShouldResize(rt) {
rt := c.GetResizeThreshold(name)
// If the resize threshold is set to 0, let us ensure that there is always
// an attempt to resize the block device. For the currently supported file systems
// xfs and ext4, the commands to resize the block device are idempotent
if rt == 0 || metrics.ShouldResize(rt) {
a, err := fdl.deviceResizeBackend.Resize(bd)
if err != nil {
return nil, err
Expand All @@ -48,6 +54,21 @@ func (fdl *ResizeDeviceLayer) Modify(c *config.Config) ([]action.Action, error)
}

func (fdl *ResizeDeviceLayer) Validate(c *config.Config) error {
for name := range c.Devices {
if !c.GetResizeFs(name) {
continue
}
metrics, err := fdl.deviceResizeBackend.GetBlockDeviceMetrics(name)
if err != nil {
return err
}
rt := c.GetResizeThreshold(name)
// If the resize threshold is 0, then the device would always be resized
// Therefore, lets ignore that case from our validation checks
if rt > 0 && metrics.ShouldResize(rt) {
return fmt.Errorf("🔴 %s: Failed to resize file system. File System=%d Block Device=%d (bytes)", name, metrics.FileSystemSize, metrics.BlockDeviceSize)
}
}
return nil
}

Expand Down

0 comments on commit bcce1ff

Please sign in to comment.