Skip to content

Commit

Permalink
feat(config): ad volumes field for VolumeConfig manifest
Browse files Browse the repository at this point in the history
Signed-off-by: budimanjojo <budimanjojo@gmail.com>
  • Loading branch information
budimanjojo committed Jan 2, 2025
1 parent 7efa54c commit b21318c
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 2 deletions.
11 changes: 9 additions & 2 deletions example/talconfig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ nodes:
mountPath: /usr/local/etc/nut/upsmon.conf
environment:
- UPS_NAME=ups
volumes:
- name: EPHEMERAL
provisioning:
diskSelector:
match: disk.transport == "nvme"
maxSize: 50GiB
ingressFirewall:
defaultAction: block
rules:
Expand Down Expand Up @@ -74,8 +80,9 @@ nodes:
installDiskSelector:
size: 4GB
model: WDC*
name: /sys/block/sda/device/name
busPath: /pci0000:00/0000:00:17.0/ata1/host0/target0:0:0/0:0:0:0
# TODO: broken since Talos 1.9 and I need to investigate
# name: /sys/block/sda/device/name
# busPath: /pci0000:00/0000:00:17.0/ata1/host0/target0:0:0/0:0:0:0
nodeLabels:
rack: rack1a
zone: us-east-1a
Expand Down
7 changes: 7 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package config

import (
"github.com/siderolabs/image-factory/pkg/schematic"
"github.com/siderolabs/talos/pkg/machinery/config/types/block"
"github.com/siderolabs/talos/pkg/machinery/config/types/network"
"github.com/siderolabs/talos/pkg/machinery/config/types/runtime/extensions"
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1"
Expand Down Expand Up @@ -59,6 +60,7 @@ type NodeConfigs struct {
MachineSpec MachineSpec `yaml:"machineSpec,omitempty" jsonschema:"description=Machine hardware specification"`
IngressFirewall *IngressFirewall `yaml:"ingressFirewall,omitempty" jsonschema:"description=Machine firewall specification"`
ExtensionServices []*ExtensionService `yaml:"extensionServices,omitempty" jsonschema:"description=Machine extension services specification"`
Volumes []*Volume `yaml:"volumes,omitempty" jsonschema:"description=Machine volume configs specification"`
}

type ImageFactory struct {
Expand Down Expand Up @@ -92,3 +94,8 @@ type ExtensionService struct {
ConfigFiles extensions.ConfigFileList `yaml:"configFiles,omitempty" jsonschema:"description=The config files for the extension service"`
Environment []string `yaml:"environment,omitempty" jsonschema:"description=The environment for the extension service"`
}

type Volume struct {
Name string `yaml:"name" jsonschema:"description=Name of the volume config"`
Provisioning block.ProvisioningSpec `yaml:"provisioning" jsonschema:"description=Provisioning spec of the volume config"`
}
9 changes: 9 additions & 0 deletions pkg/generate/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ func GenerateConfig(c *config.TalhelperConfig, dryRun bool, outDir, secretFile,
cfg = append(cfg, ext...)
}

if len(node.Volumes) > 0 {
slog.Debug(fmt.Sprintf("generating volume config for %s", node.Hostname))
vc, err := talos.GenerateVolumeConfigBytes(node.Volumes, mode)
if err != nil {
return err
}
cfg = append(cfg, vc...)
}

if len(node.ExtraManifests) > 0 {
slog.Debug(fmt.Sprintf("generating extra manifests for %s", node.Hostname))
content, err := combineExtraManifests(node.ExtraManifests)
Expand Down
60 changes: 60 additions & 0 deletions pkg/talos/volumeconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package talos

import (
"fmt"
"slices"

"github.com/budimanjojo/talhelper/v3/pkg/config"
"github.com/siderolabs/talos/pkg/machinery/config/types/block"
)

func GenerateVolumeConfigBytes(cfgs []*config.Volume, mode string) ([]byte, error) {
var result [][]byte

vcs, err := GenerateVolumeConfig(cfgs, mode)
if err != nil {
return nil, err
}

for _, vc := range vcs {
vcByte, err := marshalYaml(vc)
if err != nil {
return nil, err
}

result = append(result, vcByte)
}

return CombineYamlBytes(result), nil
}

func GenerateVolumeConfig(cfgs []*config.Volume, mode string) ([]*block.VolumeConfigV1Alpha1, error) {
var (
// I suppose we shouldn't allow same volume names?
names []string
result []*block.VolumeConfigV1Alpha1
)

m, err := parseMode(mode)
if err != nil {
return nil, err
}

for _, v := range cfgs {
if slices.Index(names, v.Name) != -1 {
return nil, fmt.Errorf("duplicated volume config name found: %s", v.Name)
}
names = append(names, v.Name)
vc := block.NewVolumeConfigV1Alpha1()
vc.MetaName = v.Name
vc.ProvisioningSpec = v.Provisioning

if _, err := vc.Validate(m); err != nil {
return nil, err
}

result = append(result, vc)
}

return result, nil
}
54 changes: 54 additions & 0 deletions pkg/talos/volumeconfig_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package talos

import (
"testing"

"github.com/budimanjojo/talhelper/v3/pkg/config"
"github.com/siderolabs/talos/pkg/machinery/cel"
"github.com/siderolabs/talos/pkg/machinery/cel/celenv"
"github.com/siderolabs/talos/pkg/machinery/config/types/block"
"gopkg.in/yaml.v3"
)

func TestGenerateNodeVolumeConfig(t *testing.T) {
data := []byte(`nodes:
- hostname: node1
volumes:
- name: EPHEMERAL
provisioning:
diskSelector:
match: disk.transport == "nvme"
maxSize: 50GiB
- name: IMAGECACHE
provisioning:
diskSelector:
match: disk.size > 120u * GB && disk.size < 1u * TB`)
var m config.TalhelperConfig
if err := yaml.Unmarshal(data, &m); err != nil {
t.Fatal(err)
}

expectedVolume1Name := "EPHEMERAL"
expectedVolume1Provisioning := block.ProvisioningSpec{
DiskSelectorSpec: block.DiskSelector{
Match: cel.MustExpression(cel.ParseBooleanExpression(`disk.transport == "nvme"`, celenv.DiskLocator())),
},
ProvisioningMaxSize: block.MustByteSize("50GiB"),
}
expectedVolume2Name := "IMAGECACHE"
expectedVolume2Provisioning := block.ProvisioningSpec{
DiskSelectorSpec: block.DiskSelector{
Match: cel.MustExpression(cel.ParseBooleanExpression(`disk.size > 120u * GB && disk.size < 1u * TB`, celenv.DiskLocator())),
},
}

result, err := GenerateVolumeConfig(m.Nodes[0].Volumes, "metal")
if err != nil {
t.Fatal(err)
}

compare(result[0].Name(), expectedVolume1Name, t)
compare(result[0].ProvisioningSpec, expectedVolume1Provisioning, t)
compare(result[1].Name(), expectedVolume2Name, t)
compare(result[1].ProvisioningSpec, expectedVolume2Provisioning, t)
}

0 comments on commit b21318c

Please sign in to comment.