From 69510991dc04e02033e64b823abeac452f72e615 Mon Sep 17 00:00:00 2001 From: Matthew Rich Date: Thu, 19 Sep 2024 08:05:29 +0000 Subject: [PATCH] add more state handling to exec resource --- internal/resource/exec.go | 99 +++++++++++++++++++++++++++++----- internal/resource/exec_test.go | 2 +- 2 files changed, 87 insertions(+), 14 deletions(-) diff --git a/internal/resource/exec.go b/internal/resource/exec.go index eacedf3..bb2142b 100644 --- a/internal/resource/exec.go +++ b/internal/resource/exec.go @@ -11,15 +11,23 @@ import ( "net/url" _ "os" _ "os/exec" - "path/filepath" _ "strings" "io" "gitea.rosskeen.house/rosskeen.house/machine" "decl/internal/codec" "decl/internal/command" + "decl/internal/data" + "decl/internal/folio" + "errors" + "log/slog" +) + +const ( + ExecTypeName TypeName = "exec" ) type Exec struct { + *Common `yaml:",inline" json:",inline"` stater machine.Stater `yaml:"-" json:"-"` Id string `yaml:"id,omitempty" json:"id,omitempty"` CreateTemplate *command.Command `yaml:"create,omitempty" json:"create,omitempty"` @@ -27,27 +35,27 @@ type Exec struct { UpdateTemplate *command.Command `yaml:"update,omitempty" json:"update,omitempty"` DeleteTemplate *command.Command `yaml:"delete,omitempty" json:"delete,omitempty"` - config ConfigurationValueGetter - Resources ResourceMapper `yaml:"-" json:"-"` + Resources data.ResourceMapper `yaml:"-" json:"-"` } func init() { - ResourceTypes.Register([]string{"exec"}, func(u *url.URL) Resource { + folio.DocumentRegistry.ResourceTypes.Register([]string{"exec"}, func(u *url.URL) data.Resource { x := NewExec() return x }) } func NewExec() *Exec { - return &Exec{} + return &Exec{ Common: &Common{ includeQueryParamsInURI: true, resourceType: ExecTypeName } } } -func (x *Exec) SetResourceMapper(resources ResourceMapper) { +func (x *Exec) SetResourceMapper(resources data.ResourceMapper) { x.Resources = resources } -func (x *Exec) Clone() Resource { +func (x *Exec) Clone() data.Resource { return &Exec { + Common: x.Common, Id: x.Id, CreateTemplate: x.CreateTemplate, ReadTemplate: x.ReadTemplate, @@ -67,6 +75,19 @@ func (x *Exec) URI() string { return fmt.Sprintf("exec://%s", x.Id) } +func (x *Exec) SetURI(uri string) (err error) { + err = x.Common.SetURI(uri) + x.Id = x.Common.Path + return +} + +func (x *Exec) SetParsedURI(uri *url.URL) (err error) { + err = x.Common.SetParsedURI(uri) + x.Id = x.Common.Path + return +} + +/* func (x *Exec) SetURI(uri string) error { resourceUri, e := url.Parse(uri) if e == nil { @@ -79,13 +100,14 @@ func (x *Exec) SetURI(uri string) error { return e } -func (x *Exec) UseConfig(config ConfigurationValueGetter) { +func (x *Exec) UseConfig(config data.ConfigurationValueGetter) { x.config = config } func (x *Exec) ResolveId(ctx context.Context) string { return "" } +*/ func (x *Exec) Validate() (err error) { var execJson []byte @@ -102,27 +124,68 @@ func (x *Exec) Apply() error { func (x *Exec) Notify(m *machine.EventMessage) { ctx := context.Background() + slog.Info("Notify()", "exec", x, "m", m) switch m.On { case machine.ENTERSTATEEVENT: switch m.Dest { + case "start_read": + if _, readErr := x.Read(ctx); readErr == nil { + if triggerErr := x.StateMachine().Trigger("state_read"); triggerErr == nil { + return + } else { + x.State = "absent" + panic(triggerErr) + } + } else { + x.State = "absent" + if ! errors.Is(readErr, ErrResourceStateAbsent) { + panic(readErr) + } + } case "start_create": if e := x.Create(ctx); e == nil { if triggerErr := x.stater.Trigger("created"); triggerErr == nil { return } } - case "present": + case "start_delete": + if deleteErr := x.Delete(ctx); deleteErr == nil { + if triggerErr := x.StateMachine().Trigger("deleted"); triggerErr == nil { + return + } else { + x.State = "present" + panic(triggerErr) + } + } else { + x.State = "present" + panic(deleteErr) + } + case "absent": + x.State = "absent" + case "present", "created", "read": + x.State = "present" } case machine.EXITSTATEEVENT: } } -func (x *Exec) Load(r io.Reader) error { - return codec.NewYAMLDecoder(r).Decode(x) +func (x *Exec) Load(docData []byte, f codec.Format) (err error) { + err = f.StringDecoder(string(docData)).Decode(x) + return +} + +func (x *Exec) LoadReader(r io.ReadCloser, f codec.Format) (err error) { + err = f.Decoder(r).Decode(x) + return +} + +func (x *Exec) LoadString(docData string, f codec.Format) (err error) { + err = f.StringDecoder(docData).Decode(x) + return } func (x *Exec) LoadDecl(yamlResourceDeclaration string) error { - return codec.NewYAMLStringDecoder(yamlResourceDeclaration).Decode(x) + return x.LoadString(yamlResourceDeclaration, codec.FormatYaml) } func (x *Exec) JSON() ([]byte, error) { @@ -134,10 +197,20 @@ func (x *Exec) Type() string { return "exec" } func (x *Exec) Create(ctx context.Context) (err error) { x.CreateTemplate.Defaults() _, err = x.CreateTemplate.Execute(x) + slog.Info("Exec.Create()", "resource", x, "error", err) return err } func (x *Exec) Read(ctx context.Context) ([]byte, error) { - x.ReadTemplate.Defaults() + if x.ReadTemplate != nil { + x.ReadTemplate.Defaults() + } return yaml.Marshal(x) } +func (x *Exec) Update(ctx context.Context) (err error) { + return +} + +func (x *Exec) Delete(ctx context.Context) (err error) { + return +} diff --git a/internal/resource/exec_test.go b/internal/resource/exec_test.go index df12a05..20a992e 100644 --- a/internal/resource/exec_test.go +++ b/internal/resource/exec_test.go @@ -60,5 +60,5 @@ func TestExecSetURI(t *testing.T) { e := x.SetURI("exec://" + "12345_key") assert.Nil(t, e) assert.Equal(t, "exec", x.Type()) - assert.Equal(t, "12345_key", x.Id) + assert.Equal(t, "12345_key", x.Path) }