mirror of
https://github.com/siderolabs/omni.git
synced 2026-05-05 06:36:12 +02:00
Now inline supports all three variants: - a single inline map (backward compatibility for config patches). - a list of inline maps - raw bytes, that can also contain multiple documents. `omnictl cluster template export` command was updated to export config patches/manifests as raw bytes to ensure that multiple values are properly supported. Fixes: https://github.com/siderolabs/omni/issues/2683 Signed-off-by: Artem Chernyshev <artem.chernyshev@talos-systems.com>
126 lines
2.6 KiB
Go
126 lines
2.6 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 (
|
|
"bytes"
|
|
"fmt"
|
|
|
|
"go.yaml.in/yaml/v4"
|
|
)
|
|
|
|
// InlineContent represents inline YAML content embedded into a template.
|
|
//
|
|
// It accepts three input forms:
|
|
// - a single YAML mapping,
|
|
// - a sequence of YAML mappings (multi-document),
|
|
// - a raw YAML literal block scalar (bytes).
|
|
//
|
|
//nolint:recvcheck
|
|
type InlineContent struct {
|
|
raw []byte
|
|
docs []map[string]any
|
|
}
|
|
|
|
// NewInlineContent builds InlineContent from one or more YAML mappings.
|
|
func NewInlineContent(docs ...map[string]any) *InlineContent {
|
|
return &InlineContent{docs: docs}
|
|
}
|
|
|
|
// NewInlineContentBytes builds InlineContent from raw YAML bytes.
|
|
func NewInlineContentBytes(raw []byte) *InlineContent {
|
|
return &InlineContent{raw: raw}
|
|
}
|
|
|
|
// IsZero reports whether the InlineContent is empty.
|
|
func (i InlineContent) IsZero() bool {
|
|
return i.raw == nil && len(i.docs) == 0
|
|
}
|
|
|
|
// Bytes returns the YAML-encoded inline content.
|
|
//
|
|
// Multi-document content is encoded with the standard YAML multi-document framing.
|
|
func (i InlineContent) Bytes() ([]byte, error) {
|
|
if i.raw != nil {
|
|
return i.raw, nil
|
|
}
|
|
|
|
if len(i.docs) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
|
|
encoder := yaml.NewEncoder(&buf)
|
|
|
|
for _, doc := range i.docs {
|
|
if err := encoder.Encode(doc); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if err := encoder.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
// UnmarshalYAML implements yaml.Unmarshaler.
|
|
func (i *InlineContent) UnmarshalYAML(node *yaml.Node) error {
|
|
//nolint:exhaustive
|
|
switch node.Kind {
|
|
case yaml.ScalarNode:
|
|
// Only allow explicit strings
|
|
if node.Tag != "!!str" {
|
|
return fmt.Errorf("expected string, but got %s", node.Tag)
|
|
}
|
|
|
|
i.raw = []byte(node.Value)
|
|
|
|
return nil
|
|
case yaml.MappingNode:
|
|
var m map[string]any
|
|
|
|
if err := node.Decode(&m); err != nil {
|
|
return err
|
|
}
|
|
|
|
i.docs = []map[string]any{m}
|
|
|
|
return nil
|
|
case yaml.SequenceNode:
|
|
var s []map[string]any
|
|
|
|
if err := node.Decode(&s); err != nil {
|
|
return err
|
|
}
|
|
|
|
i.docs = s
|
|
|
|
return nil
|
|
default:
|
|
return fmt.Errorf("unsupported inline node kind %d", node.Kind)
|
|
}
|
|
}
|
|
|
|
// MarshalYAML implements yaml.Marshaler.
|
|
func (i InlineContent) MarshalYAML() (any, error) {
|
|
switch {
|
|
case i.raw != nil:
|
|
return &yaml.Node{
|
|
Kind: yaml.ScalarNode,
|
|
Style: yaml.LiteralStyle,
|
|
Value: string(i.raw),
|
|
}, nil
|
|
case len(i.docs) == 1:
|
|
return i.docs[0], nil
|
|
case len(i.docs) > 1:
|
|
return i.docs, nil
|
|
default:
|
|
return nil, nil //nolint:nilnil
|
|
}
|
|
}
|