2024-03-20 19:23:31 +00:00
|
|
|
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
2024-03-22 17:39:06 +00:00
|
|
|
|
2024-03-20 19:23:31 +00:00
|
|
|
package resource
|
|
|
|
|
|
|
|
import (
|
2024-03-25 20:31:06 +00:00
|
|
|
"context"
|
2024-04-03 16:54:50 +00:00
|
|
|
"encoding/json"
|
2024-03-25 20:31:06 +00:00
|
|
|
"fmt"
|
2024-04-05 17:22:17 +00:00
|
|
|
"io"
|
2024-03-25 20:31:06 +00:00
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
"log/slog"
|
2024-04-21 06:13:17 +00:00
|
|
|
"gitea.rosskeen.house/rosskeen.house/machine"
|
2024-03-20 19:23:31 +00:00
|
|
|
)
|
|
|
|
|
2024-04-03 16:54:50 +00:00
|
|
|
type DeclarationType struct {
|
|
|
|
Type TypeName `json:"type" yaml:"type"`
|
2024-05-06 00:48:54 +00:00
|
|
|
Transition string `json:"transition,omitempty" yaml:"transition,omitempty"`
|
2024-04-03 16:54:50 +00:00
|
|
|
}
|
|
|
|
|
2024-03-20 19:23:31 +00:00
|
|
|
type Declaration struct {
|
2024-04-21 06:13:17 +00:00
|
|
|
StateMatchine machine.Stater `json:"-" yaml:"-"`
|
2024-04-03 16:54:50 +00:00
|
|
|
Type TypeName `json:"type" yaml:"type"`
|
2024-04-21 06:13:17 +00:00
|
|
|
Transition string `json:"transition,omitempty" yaml:"transition,omitempty"`
|
2024-04-03 16:54:50 +00:00
|
|
|
Attributes Resource `json:"attributes" yaml:"attributes"`
|
2024-03-20 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type ResourceLoader interface {
|
2024-03-25 20:31:06 +00:00
|
|
|
LoadDecl(string) error
|
2024-03-20 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type StateTransformer interface {
|
2024-03-25 20:31:06 +00:00
|
|
|
Apply() error
|
2024-03-20 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewDeclaration() *Declaration {
|
2024-03-25 20:31:06 +00:00
|
|
|
return &Declaration{}
|
2024-03-20 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
2024-04-19 07:52:10 +00:00
|
|
|
func (d *Declaration) Clone() *Declaration {
|
|
|
|
return &Declaration {
|
|
|
|
Type: d.Type,
|
|
|
|
Attributes: d.Attributes.Clone(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-05 17:22:17 +00:00
|
|
|
func (d *Declaration) Load(r io.Reader) error {
|
|
|
|
c := NewYAMLDecoder(r)
|
|
|
|
return c.Decode(d)
|
|
|
|
}
|
|
|
|
|
2024-03-20 19:23:31 +00:00
|
|
|
func (d *Declaration) LoadDecl(yamlResourceDeclaration string) error {
|
2024-04-05 17:22:17 +00:00
|
|
|
c := NewYAMLStringDecoder(yamlResourceDeclaration)
|
|
|
|
return c.Decode(d)
|
2024-03-20 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (d *Declaration) NewResource() error {
|
2024-03-25 20:31:06 +00:00
|
|
|
uri := fmt.Sprintf("%s://", d.Type)
|
|
|
|
newResource, err := ResourceTypes.New(uri)
|
2024-04-03 16:54:50 +00:00
|
|
|
d.Attributes = newResource
|
2024-03-25 20:31:06 +00:00
|
|
|
return err
|
2024-03-20 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
2024-04-03 16:54:50 +00:00
|
|
|
func (d *Declaration) Resource() Resource {
|
|
|
|
return d.Attributes
|
2024-03-20 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
2024-05-06 00:48:54 +00:00
|
|
|
func (d *Declaration) Apply() error {
|
|
|
|
stater := d.Attributes.StateMachine()
|
|
|
|
stater.Trigger(d.Transition)
|
|
|
|
}
|
|
|
|
|
2024-04-03 16:54:50 +00:00
|
|
|
func (d *Declaration) SetURI(uri string) error {
|
2024-04-12 16:08:08 +00:00
|
|
|
slog.Info("Declaration.SetURI()", "uri", uri, "declaration", d)
|
2024-04-03 16:54:50 +00:00
|
|
|
d.Attributes = NewResource(uri)
|
|
|
|
if d.Attributes == nil {
|
|
|
|
panic("unknown resource")
|
2024-03-25 20:31:06 +00:00
|
|
|
}
|
2024-04-03 16:54:50 +00:00
|
|
|
d.Type = TypeName(d.Attributes.Type())
|
2024-04-03 19:27:16 +00:00
|
|
|
_,e := d.Attributes.Read(context.Background()) // fix context
|
|
|
|
return e
|
2024-03-20 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
2024-04-03 16:54:50 +00:00
|
|
|
func (d *Declaration) UnmarshalYAML(value *yaml.Node) error {
|
|
|
|
t := &DeclarationType{}
|
|
|
|
if unmarshalResourceTypeErr := value.Decode(t); unmarshalResourceTypeErr != nil {
|
|
|
|
return unmarshalResourceTypeErr
|
|
|
|
}
|
|
|
|
|
|
|
|
d.Type = t.Type
|
2024-04-21 06:13:17 +00:00
|
|
|
d.Transition = t.Transition
|
2024-04-03 16:54:50 +00:00
|
|
|
newResource, resourceErr := ResourceTypes.New(fmt.Sprintf("%s://", d.Type))
|
|
|
|
if resourceErr != nil {
|
|
|
|
return resourceErr
|
|
|
|
}
|
|
|
|
d.Attributes = newResource
|
|
|
|
resourceAttrs := struct {
|
|
|
|
Attributes yaml.Node `json:"attributes"`
|
|
|
|
}{}
|
|
|
|
if unmarshalAttributesErr := value.Decode(&resourceAttrs); unmarshalAttributesErr != nil {
|
|
|
|
return unmarshalAttributesErr
|
|
|
|
}
|
|
|
|
if unmarshalResourceErr := resourceAttrs.Attributes.Decode(d.Attributes); unmarshalResourceErr != nil {
|
|
|
|
return unmarshalResourceErr
|
|
|
|
}
|
|
|
|
return nil
|
2024-03-20 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
2024-04-03 16:54:50 +00:00
|
|
|
func (d *Declaration) UnmarshalJSON(data []byte) error {
|
|
|
|
t := &DeclarationType{}
|
|
|
|
if unmarshalResourceTypeErr := json.Unmarshal(data, t); unmarshalResourceTypeErr != nil {
|
|
|
|
return unmarshalResourceTypeErr
|
2024-03-25 20:31:06 +00:00
|
|
|
}
|
2024-04-03 16:54:50 +00:00
|
|
|
|
|
|
|
d.Type = t.Type
|
2024-04-21 06:13:17 +00:00
|
|
|
d.Transition = t.Transition
|
2024-04-03 16:54:50 +00:00
|
|
|
|
|
|
|
newResource, resourceErr := ResourceTypes.New(fmt.Sprintf("%s://", d.Type))
|
|
|
|
if resourceErr != nil {
|
|
|
|
return resourceErr
|
|
|
|
}
|
|
|
|
d.Attributes = newResource
|
|
|
|
|
|
|
|
resourceAttrs := struct {
|
|
|
|
Attributes Resource `json:"attributes"`
|
|
|
|
}{Attributes: newResource}
|
|
|
|
if unmarshalAttributesErr := json.Unmarshal(data, &resourceAttrs); unmarshalAttributesErr != nil {
|
|
|
|
return unmarshalAttributesErr
|
|
|
|
}
|
|
|
|
|
2024-03-25 20:31:06 +00:00
|
|
|
return nil
|
2024-03-20 19:23:31 +00:00
|
|
|
}
|
2024-04-03 16:54:50 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
func (d *Declaration) MarshalJSON() ([]byte, error) {
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
buf.WriteByte('"')
|
|
|
|
buf.WriteString("value"))
|
|
|
|
buf.WriteByte('"')
|
|
|
|
return buf.Bytes(), nil
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
func (d *Declaration) MarshalYAML() (any, error) {
|
|
|
|
return d, nil
|
|
|
|
}
|