add more state handling to exec resource
Some checks are pending
Lint / golangci-lint (push) Waiting to run
Declarative Tests / test (push) Waiting to run
Declarative Tests / build-fedora (push) Waiting to run
Declarative Tests / build-ubuntu-focal (push) Waiting to run

This commit is contained in:
Matthew Rich 2024-09-19 08:05:29 +00:00
parent c4afd77777
commit 69510991dc
2 changed files with 87 additions and 14 deletions

View File

@ -11,15 +11,23 @@ import (
"net/url" "net/url"
_ "os" _ "os"
_ "os/exec" _ "os/exec"
"path/filepath"
_ "strings" _ "strings"
"io" "io"
"gitea.rosskeen.house/rosskeen.house/machine" "gitea.rosskeen.house/rosskeen.house/machine"
"decl/internal/codec" "decl/internal/codec"
"decl/internal/command" "decl/internal/command"
"decl/internal/data"
"decl/internal/folio"
"errors"
"log/slog"
)
const (
ExecTypeName TypeName = "exec"
) )
type Exec struct { type Exec struct {
*Common `yaml:",inline" json:",inline"`
stater machine.Stater `yaml:"-" json:"-"` stater machine.Stater `yaml:"-" json:"-"`
Id string `yaml:"id,omitempty" json:"id,omitempty"` Id string `yaml:"id,omitempty" json:"id,omitempty"`
CreateTemplate *command.Command `yaml:"create,omitempty" json:"create,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"` UpdateTemplate *command.Command `yaml:"update,omitempty" json:"update,omitempty"`
DeleteTemplate *command.Command `yaml:"delete,omitempty" json:"delete,omitempty"` DeleteTemplate *command.Command `yaml:"delete,omitempty" json:"delete,omitempty"`
config ConfigurationValueGetter Resources data.ResourceMapper `yaml:"-" json:"-"`
Resources ResourceMapper `yaml:"-" json:"-"`
} }
func init() { 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() x := NewExec()
return x return x
}) })
} }
func NewExec() *Exec { 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 x.Resources = resources
} }
func (x *Exec) Clone() Resource { func (x *Exec) Clone() data.Resource {
return &Exec { return &Exec {
Common: x.Common,
Id: x.Id, Id: x.Id,
CreateTemplate: x.CreateTemplate, CreateTemplate: x.CreateTemplate,
ReadTemplate: x.ReadTemplate, ReadTemplate: x.ReadTemplate,
@ -67,6 +75,19 @@ func (x *Exec) URI() string {
return fmt.Sprintf("exec://%s", x.Id) 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 { func (x *Exec) SetURI(uri string) error {
resourceUri, e := url.Parse(uri) resourceUri, e := url.Parse(uri)
if e == nil { if e == nil {
@ -79,13 +100,14 @@ func (x *Exec) SetURI(uri string) error {
return e return e
} }
func (x *Exec) UseConfig(config ConfigurationValueGetter) { func (x *Exec) UseConfig(config data.ConfigurationValueGetter) {
x.config = config x.config = config
} }
func (x *Exec) ResolveId(ctx context.Context) string { func (x *Exec) ResolveId(ctx context.Context) string {
return "" return ""
} }
*/
func (x *Exec) Validate() (err error) { func (x *Exec) Validate() (err error) {
var execJson []byte var execJson []byte
@ -102,27 +124,68 @@ func (x *Exec) Apply() error {
func (x *Exec) Notify(m *machine.EventMessage) { func (x *Exec) Notify(m *machine.EventMessage) {
ctx := context.Background() ctx := context.Background()
slog.Info("Notify()", "exec", x, "m", m)
switch m.On { switch m.On {
case machine.ENTERSTATEEVENT: case machine.ENTERSTATEEVENT:
switch m.Dest { 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": case "start_create":
if e := x.Create(ctx); e == nil { if e := x.Create(ctx); e == nil {
if triggerErr := x.stater.Trigger("created"); triggerErr == nil { if triggerErr := x.stater.Trigger("created"); triggerErr == nil {
return 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: case machine.EXITSTATEEVENT:
} }
} }
func (x *Exec) Load(r io.Reader) error { func (x *Exec) Load(docData []byte, f codec.Format) (err error) {
return codec.NewYAMLDecoder(r).Decode(x) 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 { 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) { 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) { func (x *Exec) Create(ctx context.Context) (err error) {
x.CreateTemplate.Defaults() x.CreateTemplate.Defaults()
_, err = x.CreateTemplate.Execute(x) _, err = x.CreateTemplate.Execute(x)
slog.Info("Exec.Create()", "resource", x, "error", err)
return err return err
} }
func (x *Exec) Read(ctx context.Context) ([]byte, error) { func (x *Exec) Read(ctx context.Context) ([]byte, error) {
x.ReadTemplate.Defaults() if x.ReadTemplate != nil {
x.ReadTemplate.Defaults()
}
return yaml.Marshal(x) return yaml.Marshal(x)
} }
func (x *Exec) Update(ctx context.Context) (err error) {
return
}
func (x *Exec) Delete(ctx context.Context) (err error) {
return
}

View File

@ -60,5 +60,5 @@ func TestExecSetURI(t *testing.T) {
e := x.SetURI("exec://" + "12345_key") e := x.SetURI("exec://" + "12345_key")
assert.Nil(t, e) assert.Nil(t, e)
assert.Equal(t, "exec", x.Type()) assert.Equal(t, "exec", x.Type())
assert.Equal(t, "12345_key", x.Id) assert.Equal(t, "12345_key", x.Path)
} }