mirror of
https://github.com/siderolabs/omni.git
synced 2026-05-05 14:46:12 +02:00
Refactor for code simplicity. Signed-off-by: Pranav Patil <pranavppatil767@gmail.com> Signed-off-by: Utku Ozdemir <utku.ozdemir@siderolabs.com>
165 lines
4.2 KiB
Go
165 lines
4.2 KiB
Go
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
package models
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/cosi-project/runtime/pkg/resource"
|
|
"github.com/hashicorp/go-multierror"
|
|
"github.com/siderolabs/gen/pair"
|
|
"go.yaml.in/yaml/v4"
|
|
|
|
"github.com/siderolabs/omni/client/pkg/omni/resources/omni"
|
|
)
|
|
|
|
// PatchList is a list of patches.
|
|
type PatchList []Patch
|
|
|
|
// Patch is a Talos machine configuration patch.
|
|
type Patch struct { //nolint:govet
|
|
// Name of the patch.
|
|
//
|
|
// Optional for 'path' patches, mandatory for 'inline' patches if idOverride is not set.
|
|
Name string `yaml:"name,omitempty"`
|
|
|
|
// IDOverride overrides the ID of the patch. When set, the ID will not be generated using the name and/or the file path.
|
|
IDOverride string `yaml:"idOverride,omitempty"`
|
|
|
|
// Descriptors are the user descriptors to apply to the resource.
|
|
Descriptors Descriptors `yaml:",inline"`
|
|
|
|
// File path to the file containing the patch.
|
|
//
|
|
// Mutually exclusive with `inline:`.
|
|
File string `yaml:"file,omitempty"`
|
|
|
|
// Inline patch content.
|
|
Inline map[string]any `yaml:"inline,omitempty"`
|
|
}
|
|
|
|
// Validate the model.
|
|
func (l PatchList) Validate() error {
|
|
var multiErr error
|
|
|
|
for _, patch := range l {
|
|
multiErr = joinErrors(multiErr, patch.Validate())
|
|
}
|
|
|
|
return multiErr
|
|
}
|
|
|
|
// Translate the list of patches into a list of resources.
|
|
func (l PatchList) Translate(prefix string, baseWeight int, labels ...pair.Pair[string, string]) ([]resource.Resource, error) {
|
|
resources := make([]resource.Resource, 0, len(l))
|
|
|
|
for i, patch := range l {
|
|
r, err := patch.Translate(prefix, baseWeight+i, labels...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
resources = append(resources, r)
|
|
}
|
|
|
|
return resources, nil
|
|
}
|
|
|
|
// Validate the model.
|
|
func (patch *Patch) Validate() error {
|
|
var multiErr error
|
|
|
|
name := patch.Name
|
|
if name == "" {
|
|
name = patch.File
|
|
}
|
|
|
|
if err := patch.Descriptors.Validate(); err != nil {
|
|
multiErr = multierror.Append(multiErr, err)
|
|
}
|
|
|
|
if patch.File != "" && patch.Inline != nil {
|
|
multiErr = multierror.Append(multiErr, fmt.Errorf("path and inline are mutually exclusive"))
|
|
}
|
|
|
|
if patch.File == "" && patch.Inline == nil {
|
|
multiErr = multierror.Append(multiErr, fmt.Errorf("path or inline is required"))
|
|
}
|
|
|
|
switch {
|
|
case patch.File != "":
|
|
raw, err := os.ReadFile(patch.File)
|
|
if err != nil {
|
|
multiErr = multierror.Append(multiErr, fmt.Errorf("failed to access %q: %w", patch.File, err))
|
|
} else {
|
|
if err = omni.ValidateConfigPatch(raw); err != nil {
|
|
multiErr = multierror.Append(multiErr, fmt.Errorf("failed to validate patch %q: %w", patch.File, err))
|
|
}
|
|
}
|
|
case patch.Inline != nil:
|
|
if patch.Name == "" && patch.IDOverride == "" {
|
|
multiErr = multierror.Append(multiErr, fmt.Errorf("either name or idOverride is required for inline patches"))
|
|
}
|
|
|
|
raw, err := yaml.Marshal(patch.Inline)
|
|
if err != nil {
|
|
multiErr = multierror.Append(multiErr, fmt.Errorf("failed to marshal inline patch %q: %w", name, err))
|
|
} else {
|
|
if err = omni.ValidateConfigPatch(raw); err != nil {
|
|
multiErr = multierror.Append(multiErr, fmt.Errorf("failed to validate inline patch %q: %w", name, err))
|
|
}
|
|
}
|
|
}
|
|
|
|
if multiErr != nil {
|
|
return fmt.Errorf("patch %q is invalid: %w", name, multiErr)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Translate the model into a resource.
|
|
func (patch *Patch) Translate(prefix string, weight int, labels ...pair.Pair[string, string]) (*omni.ConfigPatch, error) {
|
|
name := patch.Name
|
|
if name == "" {
|
|
name = patch.File
|
|
}
|
|
|
|
id := patch.IDOverride
|
|
if id == "" {
|
|
id = fmt.Sprintf("%03d-%s-%s", weight, prefix, name)
|
|
}
|
|
|
|
var (
|
|
raw []byte
|
|
err error
|
|
)
|
|
|
|
switch {
|
|
case patch.File != "":
|
|
raw, err = os.ReadFile(patch.File)
|
|
case patch.Inline != nil:
|
|
raw, err = yaml.Marshal(patch.Inline)
|
|
default:
|
|
panic("missing patch contents?")
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read patch %q: %w", name, err)
|
|
}
|
|
|
|
patchResource := omni.NewConfigPatch(id, labels...)
|
|
patchResource.Metadata().Annotations().Set("name", name)
|
|
|
|
patch.Descriptors.Apply(patchResource)
|
|
|
|
if err = patchResource.TypedSpec().Value.SetUncompressedData(raw); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return patchResource, nil
|
|
}
|