jx/internal/resource/declaration.go

250 lines
6.4 KiB
Go
Raw Normal View History

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 (
_ "errors"
2024-03-25 20:31:06 +00:00
"context"
"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-05-24 05:11:51 +00:00
_ "gitea.rosskeen.house/rosskeen.house/machine"
"gitea.rosskeen.house/pylon/luaruntime"
"decl/internal/codec"
"decl/internal/config"
2024-03-20 19:23:31 +00:00
)
type ConfigName string
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"`
Config ConfigName `json:"config,omitempty" yaml:"config,omitempty"`
}
2024-03-20 19:23:31 +00:00
type Declaration struct {
Type TypeName `json:"type" yaml:"type"`
2024-04-21 06:13:17 +00:00
Transition string `json:"transition,omitempty" yaml:"transition,omitempty"`
Attributes Resource `json:"attributes" yaml:"attributes"`
Config ConfigName `json:"config,omitempty" yaml:"config,omitempty"`
2024-05-24 05:11:51 +00:00
runtime luaruntime.LuaRunner
document *Document
configBlock *config.Block
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
}
func (d *Declaration) SetDocument(newDocument *Document) {
d.document = newDocument
}
2024-05-24 05:11:51 +00:00
func (d *Declaration) ResolveId(ctx context.Context) string {
defer func() {
if r := recover(); r != nil {
slog.Info("Declaration.ResolveId() - panic", "recover", r, "state", d.Attributes.StateMachine())
2024-05-26 09:14:16 +00:00
if triggerErr := d.Attributes.StateMachine().Trigger("notexists"); triggerErr != nil {
panic(triggerErr)
}
2024-05-24 05:11:51 +00:00
}
}()
slog.Info("Declaration.ResolveId()")
id := d.Attributes.ResolveId(ctx)
return id
}
2024-04-19 07:52:10 +00:00
func (d *Declaration) Clone() *Declaration {
return &Declaration {
Type: d.Type,
2024-05-09 07:39:45 +00:00
Transition: d.Transition,
2024-04-19 07:52:10 +00:00
Attributes: d.Attributes.Clone(),
2024-05-24 05:11:51 +00:00
runtime: luaruntime.New(),
Config: d.Config,
2024-04-19 07:52:10 +00:00
}
}
2024-04-05 17:22:17 +00:00
func (d *Declaration) Load(r io.Reader) error {
return codec.NewYAMLDecoder(r).Decode(d)
2024-04-05 17:22:17 +00:00
}
2024-03-20 19:23:31 +00:00
func (d *Declaration) LoadDecl(yamlResourceDeclaration string) error {
return codec.NewYAMLStringDecoder(yamlResourceDeclaration).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)
d.Attributes = newResource
2024-03-25 20:31:06 +00:00
return err
2024-03-20 19:23:31 +00:00
}
func (d *Declaration) Resource() Resource {
return d.Attributes
2024-03-20 19:23:31 +00:00
}
2024-05-24 05:11:51 +00:00
func (d *Declaration) Apply() (result error) {
defer func() {
if r := recover(); r != nil {
result = fmt.Errorf("%s", r)
}
}()
2024-05-06 00:48:54 +00:00
stater := d.Attributes.StateMachine()
2024-05-09 07:39:45 +00:00
switch d.Transition {
2024-05-24 05:11:51 +00:00
case "read":
result = stater.Trigger("read")
case "delete", "absent":
slog.Info("Declaration.Apply()", "machine", stater, "machine.state", stater.CurrentState(), "uri", d.Attributes.URI())
if stater.CurrentState() == "present" {
result = stater.Trigger("delete")
}
2024-05-09 07:39:45 +00:00
default:
fallthrough
case "create", "present":
2024-05-24 05:11:51 +00:00
slog.Info("Declaration.Apply()", "machine", stater, "machine.state", stater.CurrentState(), "uri", d.Attributes.URI())
if stater.CurrentState() == "absent" || stater.CurrentState() == "unknown" {
if result = stater.Trigger("create"); result != nil {
return result
}
}
result = stater.Trigger("read")
2024-05-09 07:39:45 +00:00
}
2024-05-24 05:11:51 +00:00
return result
2024-05-06 00:48:54 +00:00
}
func (d *Declaration) SetConfig(configDoc *config.Document) {
if configDoc != nil {
if configDoc.Has(string(d.Config)) {
d.configBlock = configDoc.Get(string(d.Config))
d.Attributes.UseConfig(d.configBlock)
}
}
}
func (d *Declaration) SetURI(uri string) error {
slog.Info("Declaration.SetURI()", "uri", uri, "declaration", d)
d.Attributes = NewResource(uri)
if d.Attributes == nil {
2024-05-26 09:30:31 +00:00
return ErrUnknownResourceType
2024-03-25 20:31:06 +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-05-24 05:11:51 +00:00
func (d *Declaration) UnmarshalValue(value *DeclarationType) error {
d.Type = value.Type
d.Transition = value.Transition
d.Config = value.Config
2024-05-24 05:11:51 +00:00
newResource, resourceErr := ResourceTypes.New(fmt.Sprintf("%s://", value.Type))
if resourceErr != nil {
return resourceErr
}
d.Attributes = newResource
return nil
}
func (d *Declaration) UnmarshalYAML(value *yaml.Node) error {
t := &DeclarationType{}
if unmarshalResourceTypeErr := value.Decode(t); unmarshalResourceTypeErr != nil {
return unmarshalResourceTypeErr
}
2024-05-24 05:11:51 +00:00
if err := d.UnmarshalValue(t); err != nil {
return err
}
2024-05-24 05:11:51 +00:00
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
}
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-05-24 05:11:51 +00:00
if err := d.UnmarshalValue(t); err != nil {
return err
}
resourceAttrs := struct {
Attributes Resource `json:"attributes"`
2024-05-24 05:11:51 +00:00
}{Attributes: d.Attributes}
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
}
/*
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
}
2024-05-24 05:11:51 +00:00
/*
func (l *LuaWorker) Receive(m message.Envelope) {
s := m.Sender()
switch b := m.Body().(type) {
case *message.Error:
// case *worker.Terminated:
case *CodeExecute:
stackSize := l.runtime.Api().GetTop()
if e := l.runtime.LoadScriptFromString(b.Code); e != nil {
s.Send(message.New(&message.Error{ E: e }, l))
}
returnsCount := l.runtime.Api().GetTop() - stackSize
if len(b.Entrypoint) == 0 {
if ! l.runtime.Api().IsNil(-1) {
if returnsCount == 0 {
s.Send(message.New(&CodeResult{ Result: []interface{}{ 0 } }, l))
} else {
lr,le := l.runtime.CopyReturnValuesFromCall(int(returnsCount))
if le != nil {
s.Send(message.New(&message.Error{ E: le }, l))
} else {
s.Send(message.New(&CodeResult{ Result: lr }, l))
}
}
}
} else {
r,ce := l.runtime.CallFunction(b.Entrypoint, b.Args)
if ce != nil {
s.Send(message.New(&message.Error{ E: ce }, l))
}
s.Send(message.New(&CodeResult{ Result: r }, l))
}
}
}
*/