Skip to content

Commit

Permalink
feat(sdl): "ram" storage class (#1925)
Browse files Browse the repository at this point in the history
* Add SDL support for `"ram"` storage class.
* `"ram"` volumes cannot be persistent or `ReadOnly`.

refs akash-network/support#179
  • Loading branch information
boz committed Feb 27, 2024
1 parent 2b47656 commit 23da352
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 36 deletions.
30 changes: 21 additions & 9 deletions sdl/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const (
StorageAttributeMount = "mount"
StorageAttributeReadOnly = "readOnly" // we might not need it at this point of time
StorageClassDefault = "default"
StorageClassRAM = "ram"
)

var (
Expand All @@ -25,6 +26,7 @@ var (
errStorageMultipleRootEphemeral = errors.New("sdl: multiple root ephemeral storages are not allowed")
errStorageDuplicatedVolumeName = errors.New("sdl: duplicated volume name")
errStorageEphemeralClass = errors.New("sdl: ephemeral storage should not set attribute class")
errStorageRAMClass = errors.New("sdl: ram storage class cannot be persistent")
)

type v2StorageAttributes types.Attributes
Expand All @@ -45,10 +47,11 @@ type v2ResourceStorageArray []v2ResourceStorage
type validateAttrFn func(string, *string) error

var allowedStorageClasses = map[string]bool{
"default": true,
"beta1": true,
"beta2": true,
"beta3": true,
"default": true,
"beta1": true,
"beta2": true,
"beta3": true,
StorageClassRAM: true,
}

var validateStorageAttributes = map[string]validateAttrFn{
Expand Down Expand Up @@ -162,11 +165,20 @@ func (sdl *v2StorageAttributes) UnmarshalYAML(node *yaml.Node) error {

persistent := res[StorageAttributePersistent]
class := res[StorageAttributeClass]
if persistent == valueFalse && class != "" {
return errStorageEphemeralClass
}
if persistent == valueTrue && class == "" {
res[StorageAttributeClass] = StorageClassDefault

switch class {
case "":
if persistent == valueTrue {
res[StorageAttributeClass] = StorageClassDefault
}
case StorageClassRAM:
if persistent != valueFalse {
return errStorageRAMClass
}
default:
if persistent == valueFalse {
return errStorageEphemeralClass
}
}

for k, v := range res {
Expand Down
32 changes: 32 additions & 0 deletions sdl/storage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,38 @@ func TestStorage_PersistentClass(t *testing.T) {
require.Equal(t, p[0].Attributes[0].Value, "beta1")
}

func TestStorage_RAMClass_Valid(t *testing.T) {
var stream = `
- size: 1Gi
attributes:
persistent: false
class: ram
`

var p v2ResourceStorageArray

err := yaml.Unmarshal([]byte(stream), &p)
require.NoError(t, err)
require.Len(t, p[0].Attributes, 2)

require.Equal(t, p[0].Attributes[0].Key, "class")
require.Equal(t, p[0].Attributes[0].Value, "ram")
}

func TestStorage_RamClass_Invalid(t *testing.T) {
var stream = `
- size: 1Gi
attributes:
persistent: true
class: ram
`

var p v2ResourceStorageArray

err := yaml.Unmarshal([]byte(stream), &p)
require.Error(t, err)
}

func TestStorage_StableSort(t *testing.T) {
storage := v2ResourceStorageArray{
{
Expand Down
65 changes: 38 additions & 27 deletions sdl/v2_1.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,12 +228,14 @@ func (sdl *v2_1) validate() error {
}
}

attr := make(map[string]string)
mounts := make(map[string]string)

if svc.Params != nil {
mounts := make(map[string]string)

for name, params := range svc.Params.Storage {
if _, exists := volumes[name]; !exists {

volume, exists := volumes[name]

if !exists {
return fmt.Errorf(
"%w: service \"%s\" references to no-existing compute volume named \"%s\"",
errSDLInvalid,
Expand All @@ -251,42 +253,51 @@ func (sdl *v2_1) validate() error {
)
}

attr[StorageAttributeMount] = params.Mount
attr[StorageAttributeReadOnly] = strconv.FormatBool(params.ReadOnly)

mount := attr[StorageAttributeMount]
if vlname, exists := mounts[mount]; exists {
if mount == "" {
if vlname, exists := mounts[params.Mount]; exists {
if params.Mount == "" {
return errStorageMultipleRootEphemeral
}

return fmt.Errorf(
"%w: mount %q already in use by volume %q",
errStorageDupMountPoint,
mount,
params.Mount,
vlname,
)
}

mounts[mount] = name
}
}
mounts[params.Mount] = name

for name, volume := range volumes {
for _, nd := range types.Attributes(volume.Attributes) {
attr[nd.Key] = nd.Value
}
attr := make(map[string]string)
attr[StorageAttributeMount] = params.Mount
attr[StorageAttributeReadOnly] = strconv.FormatBool(params.ReadOnly)

for _, nd := range types.Attributes(volume.Attributes) {
attr[nd.Key] = nd.Value
}

persistent, _ := strconv.ParseBool(attr[StorageAttributePersistent])
persistent, _ := strconv.ParseBool(attr[StorageAttributePersistent])
class := attr[StorageAttributeClass]

if persistent && attr[StorageAttributeMount] == "" {
return fmt.Errorf(
"%w: compute.storage.%s has persistent=true which requires service.%s.params.storage.%s to have mount",
errSDLInvalid,
name,
svcName,
name,
)
if persistent && params.Mount == "" {
return fmt.Errorf(
"%w: compute.storage.%s has persistent=true which requires service.%s.params.storage.%s to have mount",
errSDLInvalid,
name,
svcName,
name,
)
}

if class == StorageClassRAM && params.ReadOnly {
return fmt.Errorf(
"%w: services.%s.params.storage.%s has readOnly=true which is not allowed for storage class \"%s\"",
errSDLInvalid,
svcName,
name,
class,
)
}
}
}
}
Expand Down

0 comments on commit 23da352

Please sign in to comment.