Refactor ignition support during dracut
- Control root device using the node/profile root field - Add support for `/warewulf/wwinit.d` to run scripts during first stage - Move first-stage ignition support to `/warewulf/wwinit.d/` - Add `wwctl <node|profile> set --parttype` - Add overlay template functions `SystemdEscape` and `SystemdEscapePath` - Support configuring ignition with resources Signed-off-by: Jonathon Anderson <janderson@ciq.com>
This commit is contained in:
@@ -194,3 +194,16 @@ func (config *NodesYaml) FindDiscoverableNode() (Node, string, error) {
|
||||
|
||||
return EmptyNode(), "", ErrNoUnconfigured
|
||||
}
|
||||
|
||||
func (node *Node) SetIds(id string) {
|
||||
node.id = id
|
||||
for diskId, disk := range node.Disks {
|
||||
disk.id = diskId
|
||||
for partitionId, partition := range disk.Partitions {
|
||||
partition.id = partitionId
|
||||
}
|
||||
}
|
||||
for fsId, fs := range node.FileSystems {
|
||||
fs.id = fsId
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@ type NetDev struct {
|
||||
Holds the disks of a node
|
||||
*/
|
||||
type Disk struct {
|
||||
id string `yaml:"-" json:"-"`
|
||||
WipeTable bool `yaml:"wipe_table,omitempty" json:"wipe_table,omitempty" lopt:"diskwipe" comment:"whether or not the partition tables shall be wiped"`
|
||||
Partitions map[string]*Partition `yaml:"partitions,omitempty" json:"partitions,omitempty"`
|
||||
}
|
||||
@@ -101,13 +102,14 @@ partition definition, the label must be uniq so its used as the key in the
|
||||
Partitions map
|
||||
*/
|
||||
type Partition struct {
|
||||
Number string `yaml:"number,omitempty" json:"number,omitempty" lopt:"partnumber" comment:"set the partition number, if not set next free slot is used" type:"uint"`
|
||||
SizeMiB string `yaml:"size_mib,omitempty" json:"size_mib,omitempty" lopt:"partsize" comment:"set the size of the partition, if not set maximal possible size is used" type:"uint"`
|
||||
id string `yaml:"-" json:"-"`
|
||||
Number string `yaml:"number,omitempty" json:"number,omitempty" lopt:"partnumber" comment:"Set the partition number, if not set next free slot is used" type:"uint"`
|
||||
SizeMiB string `yaml:"size_mib,omitempty" json:"size_mib,omitempty" lopt:"partsize" comment:"Set the size of the partition, if not set maximal possible size is used" type:"uint"`
|
||||
StartMiB string `yaml:"start_mib,omitempty" json:"start_mib,omitempty" comment:"the start of the partition" type:"uint"`
|
||||
TypeGuid string `yaml:"type_guid,omitempty" json:"type_guid,omitempty" comment:"Linux filesystem data will be used if empty"`
|
||||
TypeGuid string `yaml:"type_guid,omitempty" json:"type_guid,omitempty" lopt:"parttype" comment:"Set the partition type GUID"`
|
||||
Guid string `yaml:"guid,omitempty" json:"guid,omitempty" comment:"the GPT unique partition GUID"`
|
||||
WipePartitionEntry bool `yaml:"wipe_partition_entry,omitempty" json:"wipe_partition_entry,omitempty" comment:"if true, Ignition will clobber an existing partition if it does not match the config"`
|
||||
ShouldExist bool `yaml:"should_exist,omitempty" json:"should_exist,omitempty" lopt:"partcreate" comment:"create partition if not exist"`
|
||||
ShouldExist bool `yaml:"should_exist,omitempty" json:"should_exist,omitempty" lopt:"partcreate" comment:"Create partition if it does not exist"`
|
||||
Resize bool `yaml:"resize,omitempty" json:"resize,omitempty" comment:"whether or not the existing partition should be resize"`
|
||||
}
|
||||
|
||||
@@ -115,6 +117,7 @@ type Partition struct {
|
||||
Definition of a filesystem. The device is uniq so its used as key
|
||||
*/
|
||||
type FileSystem struct {
|
||||
id string `yaml:"-" json:"-"`
|
||||
Format string `yaml:"format,omitempty" json:"format,omitempty" lopt:"fsformat" comment:"format of the file system"`
|
||||
Path string `yaml:"path,omitempty" json:"path,omitempty" lopt:"fspath" comment:"the mount point of the file system"`
|
||||
WipeFileSystem bool `yaml:"wipe_filesystem,omitempty" json:"wipe_filesystem,omitempty" lopt:"fswipe" comment:"wipe file system at boot"`
|
||||
|
||||
@@ -157,7 +157,7 @@ func (config *NodesYaml) MergeNode(id string) (node Node, fields fieldMap, err e
|
||||
delete(fields, "Profiles")
|
||||
}
|
||||
|
||||
node.id = id
|
||||
node.SetIds(id)
|
||||
node.valid = true
|
||||
node.updatePrimaryNetDev()
|
||||
node.Profile.cleanLists()
|
||||
|
||||
@@ -10,10 +10,97 @@ import (
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func (node *Node) DiskList() (disks []*Disk) {
|
||||
names := make([]string, 0, len(node.Disks))
|
||||
for name := range node.Disks {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
for _, name := range names {
|
||||
disk := node.Disks[name]
|
||||
if disk != nil {
|
||||
disks = append(disks, disk)
|
||||
}
|
||||
}
|
||||
return disks
|
||||
}
|
||||
|
||||
func (node *Node) FileSystemList() (fs []*FileSystem) {
|
||||
names := make([]string, 0, len(node.FileSystems))
|
||||
for name := range node.FileSystems {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
for _, name := range names {
|
||||
fsys := node.FileSystems[name]
|
||||
if fsys != nil {
|
||||
fs = append(fs, fsys)
|
||||
}
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
func (disk *Disk) Id() string {
|
||||
return disk.id
|
||||
}
|
||||
|
||||
func (disk *Disk) PartitionList() (partitions []*Partition) {
|
||||
names := make([]string, 0, len(disk.Partitions))
|
||||
for name := range disk.Partitions {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.SliceStable(names, func(i, j int) bool {
|
||||
pi := disk.Partitions[names[i]]
|
||||
pj := disk.Partitions[names[j]]
|
||||
|
||||
// Try to compare by Number (as int)
|
||||
ni, erri := strconv.Atoi(pi.Number)
|
||||
nj, errj := strconv.Atoi(pj.Number)
|
||||
if erri == nil && errj == nil {
|
||||
if ni != nj {
|
||||
return ni < nj
|
||||
}
|
||||
} else if erri == nil {
|
||||
return true // i has a number, j does not
|
||||
} else if errj == nil {
|
||||
return false // j has a number, i does not
|
||||
}
|
||||
|
||||
// Next, compare by id if set
|
||||
if pi.id != "" && pj.id != "" {
|
||||
if pi.id != pj.id {
|
||||
return pi.id < pj.id
|
||||
}
|
||||
} else if pi.id != "" {
|
||||
return true // i has id, j does not
|
||||
} else if pj.id != "" {
|
||||
return false // j has id, i does not
|
||||
}
|
||||
|
||||
// Fallback: compare by name (map key)
|
||||
return names[i] < names[j]
|
||||
})
|
||||
for _, name := range names {
|
||||
part := disk.Partitions[name]
|
||||
if part != nil {
|
||||
partitions = append(partitions, part)
|
||||
}
|
||||
}
|
||||
return partitions
|
||||
}
|
||||
|
||||
func (partition *Partition) Id() string {
|
||||
return partition.id
|
||||
}
|
||||
|
||||
func (fs *FileSystem) Id() string {
|
||||
return fs.id
|
||||
}
|
||||
|
||||
/*
|
||||
Create a ignition struct class for ignition
|
||||
*/
|
||||
func (node *Node) GetStorage() (stor types_3_4.Storage, rep string, err error) {
|
||||
func (node *Node) GetIgnitionStorage() (stor types_3_4.Storage, rep string, err error) {
|
||||
var fileSystems []types_3_4.Filesystem
|
||||
for fsdevice, fs := range node.FileSystems {
|
||||
var mountOptions []types_3_4.MountOption
|
||||
@@ -141,8 +228,8 @@ type SimpleIgnitionConfig struct {
|
||||
/*
|
||||
Get a simple config which can be marshalled to json
|
||||
*/
|
||||
func (node *Node) GetConfig() (conf SimpleIgnitionConfig, rep string, err error) {
|
||||
conf.Storage, rep, err = node.GetStorage()
|
||||
func (node *Node) GetIgnitionConfig() (conf SimpleIgnitionConfig, rep string, err error) {
|
||||
conf.Storage, rep, err = node.GetIgnitionStorage()
|
||||
conf.Ignition.Version = "3.1.0"
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user