Compare commits
4 Commits
336b6b7ca4
...
78e52933eb
Author | SHA1 | Date | |
---|---|---|---|
78e52933eb | |||
9c0ec52560 | |||
05b229d500 | |||
3ef1915ab7 |
@ -24,12 +24,13 @@ type CommandArg string
|
|||||||
type Command struct {
|
type Command struct {
|
||||||
Path string `json:"path" yaml:"path"`
|
Path string `json:"path" yaml:"path"`
|
||||||
Args []CommandArg `json:"args" yaml:"args"`
|
Args []CommandArg `json:"args" yaml:"args"`
|
||||||
|
Split bool `json:"split" yaml:"split`
|
||||||
Executor CommandExecutor `json:"-" yaml:"-"`
|
Executor CommandExecutor `json:"-" yaml:"-"`
|
||||||
Extractor CommandExtractAttributes `json:"-" yaml:"-"`
|
Extractor CommandExtractAttributes `json:"-" yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCommand() *Command {
|
func NewCommand() *Command {
|
||||||
c := &Command{}
|
c := &Command{ Split: true }
|
||||||
c.Executor = func(value any) ([]byte, error) {
|
c.Executor = func(value any) ([]byte, error) {
|
||||||
args, err := c.Template(value)
|
args, err := c.Template(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -88,7 +89,12 @@ func (c *Command) Template(value any) ([]string, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if commandLineArg.Len() > 0 {
|
if commandLineArg.Len() > 0 {
|
||||||
splitArg := strings.Split(commandLineArg.String(), " ")
|
var splitArg []string
|
||||||
|
if c.Split {
|
||||||
|
splitArg = strings.Split(commandLineArg.String(), " ")
|
||||||
|
} else {
|
||||||
|
splitArg = []string{commandLineArg.String()}
|
||||||
|
}
|
||||||
slog.Info("Template()", "split", splitArg, "len", len(splitArg))
|
slog.Info("Template()", "split", splitArg, "len", len(splitArg))
|
||||||
args = append(args, splitArg...)
|
args = append(args, splitArg...)
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ type ContainerNetworkClient interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ContainerNetwork struct {
|
type ContainerNetwork struct {
|
||||||
|
stater machine.Stater `json:"-" yaml:"-"`
|
||||||
Id string `json:"ID,omitempty" yaml:"ID,omitempty"`
|
Id string `json:"ID,omitempty" yaml:"ID,omitempty"`
|
||||||
Name string `json:"name" yaml:"name"`
|
Name string `json:"name" yaml:"name"`
|
||||||
|
|
||||||
@ -71,7 +72,26 @@ func (n *ContainerNetwork) Clone() Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *ContainerNetwork) StateMachine() machine.Stater {
|
func (n *ContainerNetwork) StateMachine() machine.Stater {
|
||||||
return StorageMachine()
|
if n.stater == nil {
|
||||||
|
n.stater = StorageMachine(n)
|
||||||
|
}
|
||||||
|
return n.stater
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *ContainerNetwork) Notify(m *machine.EventMessage) {
|
||||||
|
ctx := context.Background()
|
||||||
|
switch m.On {
|
||||||
|
case machine.ENTERSTATEEVENT:
|
||||||
|
switch m.Dest {
|
||||||
|
case "start_create":
|
||||||
|
if e := n.Create(ctx); e != nil {
|
||||||
|
n.stater.Trigger("created")
|
||||||
|
}
|
||||||
|
case "present":
|
||||||
|
n.State = "present"
|
||||||
|
}
|
||||||
|
case machine.EXITSTATEEVENT:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *ContainerNetwork) URI() string {
|
func (n *ContainerNetwork) URI() string {
|
||||||
|
@ -39,6 +39,7 @@ func NewDeclaration() *Declaration {
|
|||||||
func (d *Declaration) Clone() *Declaration {
|
func (d *Declaration) Clone() *Declaration {
|
||||||
return &Declaration {
|
return &Declaration {
|
||||||
Type: d.Type,
|
Type: d.Type,
|
||||||
|
Transition: d.Transition,
|
||||||
Attributes: d.Attributes.Clone(),
|
Attributes: d.Attributes.Clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,7 +67,14 @@ func (d *Declaration) Resource() Resource {
|
|||||||
|
|
||||||
func (d *Declaration) Apply() error {
|
func (d *Declaration) Apply() error {
|
||||||
stater := d.Attributes.StateMachine()
|
stater := d.Attributes.StateMachine()
|
||||||
return stater.Trigger(d.Transition)
|
switch d.Transition {
|
||||||
|
case "absent":
|
||||||
|
default:
|
||||||
|
fallthrough
|
||||||
|
case "create", "present":
|
||||||
|
return stater.Trigger("create")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Declaration) SetURI(uri string) error {
|
func (d *Declaration) SetURI(uri string) error {
|
||||||
|
@ -111,3 +111,24 @@ func TestDeclarationJson(t *testing.T) {
|
|||||||
assert.Equal(t, "10012", userResourceDeclaration.Attributes.(*User).UID)
|
assert.Equal(t, "10012", userResourceDeclaration.Attributes.(*User).UID)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeclarationTransition(t *testing.T) {
|
||||||
|
fileName := filepath.Join(TempDir, "testdecl.txt")
|
||||||
|
fileDeclJson := fmt.Sprintf(`
|
||||||
|
{
|
||||||
|
"type": "file",
|
||||||
|
"transition": "present",
|
||||||
|
"attributes": {
|
||||||
|
"path": "%s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, fileName)
|
||||||
|
|
||||||
|
resourceDeclaration := NewDeclaration()
|
||||||
|
e := json.Unmarshal([]byte(fileDeclJson), resourceDeclaration)
|
||||||
|
assert.Nil(t, e)
|
||||||
|
assert.Equal(t, TypeName("file"), resourceDeclaration.Type)
|
||||||
|
assert.Equal(t, fileName, resourceDeclaration.Attributes.(*File).Path)
|
||||||
|
resourceDeclaration.Apply()
|
||||||
|
assert.FileExists(t, fileName)
|
||||||
|
}
|
||||||
|
@ -122,6 +122,7 @@ func (d *Document) YAML() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Document) Diff(with *Document, output io.Writer) (string, error) {
|
func (d *Document) Diff(with *Document, output io.Writer) (string, error) {
|
||||||
|
slog.Info("Document.Diff()")
|
||||||
opts := []yamldiff.DoOptionFunc{}
|
opts := []yamldiff.DoOptionFunc{}
|
||||||
if output == nil {
|
if output == nil {
|
||||||
output = &strings.Builder{}
|
output = &strings.Builder{}
|
||||||
@ -130,7 +131,6 @@ func (d *Document) Diff(with *Document, output io.Writer) (string, error) {
|
|||||||
if yerr != nil {
|
if yerr != nil {
|
||||||
return "", yerr
|
return "", yerr
|
||||||
}
|
}
|
||||||
|
|
||||||
yamlDiff,yamlDiffErr := yamldiff.Load(string(ydata))
|
yamlDiff,yamlDiffErr := yamldiff.Load(string(ydata))
|
||||||
if yamlDiffErr != nil {
|
if yamlDiffErr != nil {
|
||||||
return "", yamlDiffErr
|
return "", yamlDiffErr
|
||||||
@ -145,9 +145,9 @@ func (d *Document) Diff(with *Document, output io.Writer) (string, error) {
|
|||||||
return "", withDiffErr
|
return "", withDiffErr
|
||||||
}
|
}
|
||||||
|
|
||||||
for _,diff := range yamldiff.Do(yamlDiff, withDiff, opts...) {
|
for _,docDiffResults := range yamldiff.Do(yamlDiff, withDiff, opts...) {
|
||||||
slog.Info("Diff()", "diff", diff)
|
slog.Info("Diff()", "diff", docDiffResults, "dump", docDiffResults.Dump())
|
||||||
_,e := output.Write([]byte(diff.Dump()))
|
_,e := output.Write([]byte(docDiffResults.Dump()))
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return "", e
|
return "", e
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@ func init() {
|
|||||||
|
|
||||||
// Manage the state of file system objects
|
// Manage the state of file system objects
|
||||||
type File struct {
|
type File struct {
|
||||||
|
stater machine.Stater `json:"-" yaml:"-"`
|
||||||
normalizePath bool `json:"-" yaml:"-"`
|
normalizePath bool `json:"-" yaml:"-"`
|
||||||
Path string `json:"path" yaml:"path"`
|
Path string `json:"path" yaml:"path"`
|
||||||
Owner string `json:"owner" yaml:"owner"`
|
Owner string `json:"owner" yaml:"owner"`
|
||||||
@ -105,7 +106,26 @@ func (f *File) Clone() Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) StateMachine() machine.Stater {
|
func (f *File) StateMachine() machine.Stater {
|
||||||
return StorageMachine()
|
if f.stater == nil {
|
||||||
|
f.stater = StorageMachine(f)
|
||||||
|
}
|
||||||
|
return f.stater
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *File) Notify(m *machine.EventMessage) {
|
||||||
|
ctx := context.Background()
|
||||||
|
switch m.On {
|
||||||
|
case machine.ENTERSTATEEVENT:
|
||||||
|
switch m.Dest {
|
||||||
|
case "start_create":
|
||||||
|
if e := f.Create(ctx); e != nil {
|
||||||
|
f.stater.Trigger("created")
|
||||||
|
}
|
||||||
|
case "present":
|
||||||
|
f.State = "present"
|
||||||
|
}
|
||||||
|
case machine.EXITSTATEEVENT:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) URI() string {
|
func (f *File) URI() string {
|
||||||
@ -139,63 +159,7 @@ func (f *File) Apply() error {
|
|||||||
return removeErr
|
return removeErr
|
||||||
}
|
}
|
||||||
case "present":
|
case "present":
|
||||||
{
|
return f.Create(context.Background())
|
||||||
uid, uidErr := LookupUID(f.Owner)
|
|
||||||
if uidErr != nil {
|
|
||||||
return fmt.Errorf("%w: unkwnon user %d", ErrInvalidFileOwner, uid)
|
|
||||||
}
|
|
||||||
|
|
||||||
gid, gidErr := LookupGID(f.Group)
|
|
||||||
if gidErr != nil {
|
|
||||||
return gidErr
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Info("File.Mode", "mode", f.Mode)
|
|
||||||
mode, modeErr := strconv.ParseInt(f.Mode, 8, 64)
|
|
||||||
if modeErr != nil {
|
|
||||||
return fmt.Errorf("%w: invalid mode %d", ErrInvalidFileMode, mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
//e := os.Stat(f.path)
|
|
||||||
//if os.IsNotExist(e) {
|
|
||||||
switch f.FileType {
|
|
||||||
case SymbolicLinkFile:
|
|
||||||
linkErr := os.Symlink(f.Target, f.Path)
|
|
||||||
if linkErr != nil {
|
|
||||||
return linkErr
|
|
||||||
}
|
|
||||||
case DirectoryFile:
|
|
||||||
if mkdirErr := os.MkdirAll(f.Path, os.FileMode(mode)); mkdirErr != nil {
|
|
||||||
return mkdirErr
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
fallthrough
|
|
||||||
case RegularFile:
|
|
||||||
createdFile, e := os.Create(f.Path)
|
|
||||||
if e != nil {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
defer createdFile.Close()
|
|
||||||
|
|
||||||
if chmodErr := createdFile.Chmod(os.FileMode(mode)); chmodErr != nil {
|
|
||||||
return chmodErr
|
|
||||||
}
|
|
||||||
_, writeErr := createdFile.Write([]byte(f.Content))
|
|
||||||
if writeErr != nil {
|
|
||||||
return writeErr
|
|
||||||
}
|
|
||||||
if !f.Mtime.IsZero() && !f.Atime.IsZero() {
|
|
||||||
if chtimesErr := os.Chtimes(f.Path, f.Atime, f.Mtime); chtimesErr != nil {
|
|
||||||
return chtimesErr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if chownErr := os.Chown(f.Path, uid, gid); chownErr != nil {
|
|
||||||
return chownErr
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -263,6 +227,58 @@ func (f *ResourceFileInfo) Sys() any {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *File) Create(ctx context.Context) error {
|
||||||
|
uid, uidErr := LookupUID(f.Owner)
|
||||||
|
if uidErr != nil {
|
||||||
|
return fmt.Errorf("%w: unkwnon user %d", ErrInvalidFileOwner, uid)
|
||||||
|
}
|
||||||
|
gid, gidErr := LookupGID(f.Group)
|
||||||
|
if gidErr != nil {
|
||||||
|
return gidErr
|
||||||
|
}
|
||||||
|
mode, modeErr := strconv.ParseInt(f.Mode, 8, 64)
|
||||||
|
if modeErr != nil {
|
||||||
|
return fmt.Errorf("%w: invalid mode %d", ErrInvalidFileMode, mode)
|
||||||
|
}
|
||||||
|
//e := os.Stat(f.path)
|
||||||
|
//if os.IsNotExist(e) {
|
||||||
|
switch f.FileType {
|
||||||
|
case SymbolicLinkFile:
|
||||||
|
linkErr := os.Symlink(f.Target, f.Path)
|
||||||
|
if linkErr != nil {
|
||||||
|
return linkErr
|
||||||
|
}
|
||||||
|
case DirectoryFile:
|
||||||
|
if mkdirErr := os.MkdirAll(f.Path, os.FileMode(mode)); mkdirErr != nil {
|
||||||
|
return mkdirErr
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fallthrough
|
||||||
|
case RegularFile:
|
||||||
|
createdFile, e := os.Create(f.Path)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
defer createdFile.Close()
|
||||||
|
if chmodErr := createdFile.Chmod(os.FileMode(mode)); chmodErr != nil {
|
||||||
|
return chmodErr
|
||||||
|
}
|
||||||
|
_, writeErr := createdFile.Write([]byte(f.Content))
|
||||||
|
if writeErr != nil {
|
||||||
|
return writeErr
|
||||||
|
}
|
||||||
|
if !f.Mtime.IsZero() && !f.Atime.IsZero() {
|
||||||
|
if chtimesErr := os.Chtimes(f.Path, f.Atime, f.Mtime); chtimesErr != nil {
|
||||||
|
return chtimesErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if chownErr := os.Chown(f.Path, uid, gid); chownErr != nil {
|
||||||
|
return chownErr
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f *File) UpdateContentAttributes() {
|
func (f *File) UpdateContentAttributes() {
|
||||||
f.Size = int64(len(f.Content))
|
f.Size = int64(len(f.Content))
|
||||||
f.Sha256 = fmt.Sprintf("%x", sha256.Sum256([]byte(f.Content)))
|
f.Sha256 = fmt.Sprintf("%x", sha256.Sum256([]byte(f.Content)))
|
||||||
|
@ -35,6 +35,7 @@ type HTTPHeader struct {
|
|||||||
|
|
||||||
// Manage the state of an HTTP endpoint
|
// Manage the state of an HTTP endpoint
|
||||||
type HTTP struct {
|
type HTTP struct {
|
||||||
|
stater machine.Stater `yaml:"-" json:"-"`
|
||||||
client *http.Client `yaml:"-" json:"-"`
|
client *http.Client `yaml:"-" json:"-"`
|
||||||
Endpoint string `yaml:"endpoint" json:"endpoint"`
|
Endpoint string `yaml:"endpoint" json:"endpoint"`
|
||||||
Headers []HTTPHeader `yaml:"headers,omitempty" json:"headers,omitempty"`
|
Headers []HTTPHeader `yaml:"headers,omitempty" json:"headers,omitempty"`
|
||||||
@ -57,7 +58,26 @@ func (h *HTTP) Clone() Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTP) StateMachine() machine.Stater {
|
func (h *HTTP) StateMachine() machine.Stater {
|
||||||
return StorageMachine()
|
if h.stater == nil {
|
||||||
|
h.stater = StorageMachine(h)
|
||||||
|
}
|
||||||
|
return h.stater
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HTTP) Notify(m *machine.EventMessage) {
|
||||||
|
ctx := context.Background()
|
||||||
|
switch m.On {
|
||||||
|
case machine.ENTERSTATEEVENT:
|
||||||
|
switch m.Dest {
|
||||||
|
case "start_create":
|
||||||
|
if e := h.Create(ctx); e != nil {
|
||||||
|
h.stater.Trigger("created")
|
||||||
|
}
|
||||||
|
case "present":
|
||||||
|
h.State = "present"
|
||||||
|
}
|
||||||
|
case machine.EXITSTATEEVENT:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTP) URI() string {
|
func (h *HTTP) URI() string {
|
||||||
@ -112,7 +132,7 @@ func (h *HTTP) ResolveId(ctx context.Context) string {
|
|||||||
return h.Endpoint
|
return h.Endpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTP) Create() error {
|
func (h *HTTP) Create(ctx context.Context) error {
|
||||||
body := strings.NewReader(h.Body)
|
body := strings.NewReader(h.Body)
|
||||||
req, reqErr := http.NewRequest("POST", h.Endpoint, body)
|
req, reqErr := http.NewRequest("POST", h.Endpoint, body)
|
||||||
if reqErr != nil {
|
if reqErr != nil {
|
||||||
|
@ -67,6 +67,7 @@ endpoint: "%s/resource/user/foo"
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestHTTPCreate(t *testing.T) {
|
func TestHTTPCreate(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
userdecl := `
|
userdecl := `
|
||||||
type: "user"
|
type: "user"
|
||||||
attributes:
|
attributes:
|
||||||
@ -96,6 +97,6 @@ body: |
|
|||||||
`, server.URL, re.ReplaceAllString(userdecl, " $1"))
|
`, server.URL, re.ReplaceAllString(userdecl, " $1"))
|
||||||
assert.Nil(t, h.LoadDecl(decl))
|
assert.Nil(t, h.LoadDecl(decl))
|
||||||
assert.Greater(t, len(h.Body), 0)
|
assert.Greater(t, len(h.Body), 0)
|
||||||
e := h.Create()
|
e := h.Create(ctx)
|
||||||
assert.Nil(t, e)
|
assert.Nil(t, e)
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,7 @@ const (
|
|||||||
// Manage the state of iptables rules
|
// Manage the state of iptables rules
|
||||||
// iptable://filter/INPUT/0
|
// iptable://filter/INPUT/0
|
||||||
type Iptable struct {
|
type Iptable struct {
|
||||||
|
stater machine.Stater `json:"-" yaml:"-"`
|
||||||
Id uint `json:"id,omitempty" yaml:"id,omitempty"`
|
Id uint `json:"id,omitempty" yaml:"id,omitempty"`
|
||||||
Table IptableName `json:"table" yaml:"table"`
|
Table IptableName `json:"table" yaml:"table"`
|
||||||
Chain IptableChain `json:"chain" yaml:"chain"`
|
Chain IptableChain `json:"chain" yaml:"chain"`
|
||||||
@ -151,7 +152,26 @@ func (i *Iptable) Clone() Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *Iptable) StateMachine() machine.Stater {
|
func (i *Iptable) StateMachine() machine.Stater {
|
||||||
return StorageMachine()
|
if i.stater == nil {
|
||||||
|
i.stater = StorageMachine(i)
|
||||||
|
}
|
||||||
|
return i.stater
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Iptable) Notify(m *machine.EventMessage) {
|
||||||
|
ctx := context.Background()
|
||||||
|
switch m.On {
|
||||||
|
case machine.ENTERSTATEEVENT:
|
||||||
|
switch m.Dest {
|
||||||
|
case "start_create":
|
||||||
|
if e := i.Create(ctx); e != nil {
|
||||||
|
i.stater.Trigger("created")
|
||||||
|
}
|
||||||
|
case "present":
|
||||||
|
i.State = "present"
|
||||||
|
}
|
||||||
|
case machine.EXITSTATEEVENT:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Iptable) URI() string {
|
func (i *Iptable) URI() string {
|
||||||
|
@ -108,6 +108,7 @@ const (
|
|||||||
|
|
||||||
// Manage the state of network routes
|
// Manage the state of network routes
|
||||||
type NetworkRoute struct {
|
type NetworkRoute struct {
|
||||||
|
stater machine.Stater `json:"-" yaml:"-"`
|
||||||
Id string
|
Id string
|
||||||
To string `json:"to" yaml:"to"`
|
To string `json:"to" yaml:"to"`
|
||||||
Interface string `json:"interface" yaml:"interface"`
|
Interface string `json:"interface" yaml:"interface"`
|
||||||
@ -140,7 +141,30 @@ func (n *NetworkRoute) Clone() Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *NetworkRoute) StateMachine() machine.Stater {
|
func (n *NetworkRoute) StateMachine() machine.Stater {
|
||||||
return StorageMachine()
|
if n.stater == nil {
|
||||||
|
n.stater = StorageMachine(n)
|
||||||
|
}
|
||||||
|
return n.stater
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRoute) Notify(m *machine.EventMessage) {
|
||||||
|
ctx := context.Background()
|
||||||
|
switch m.On {
|
||||||
|
case machine.ENTERSTATEEVENT:
|
||||||
|
switch m.Dest {
|
||||||
|
case "start_create":
|
||||||
|
if e := n.Create(ctx); e != nil {
|
||||||
|
n.stater.Trigger("created")
|
||||||
|
}
|
||||||
|
case "present":
|
||||||
|
n.State = "present"
|
||||||
|
}
|
||||||
|
case machine.EXITSTATEEVENT:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkRoute) Create(ctx context.Context) error {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NetworkRoute) URI() string {
|
func (n *NetworkRoute) URI() string {
|
||||||
|
@ -31,9 +31,10 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Package struct {
|
type Package struct {
|
||||||
|
stater machine.Stater `yaml:"-" json:"-"`
|
||||||
Name string `yaml:"name" json:"name"`
|
Name string `yaml:"name" json:"name"`
|
||||||
Required string `json:"required" yaml:"required"`
|
Required string `json:"required,omitempty" yaml:"required,omitempty"`
|
||||||
Version string `yaml:"version" json:"version"`
|
Version string `yaml:"version,omitempty" json:"version,omitempty"`
|
||||||
PackageType PackageType `yaml:"type" json:"type"`
|
PackageType PackageType `yaml:"type" json:"type"`
|
||||||
|
|
||||||
CreateCommand *Command `yaml:"-" json:"-"`
|
CreateCommand *Command `yaml:"-" json:"-"`
|
||||||
@ -41,7 +42,7 @@ type Package struct {
|
|||||||
UpdateCommand *Command `yaml:"-" json:"-"`
|
UpdateCommand *Command `yaml:"-" json:"-"`
|
||||||
DeleteCommand *Command `yaml:"-" json:"-"`
|
DeleteCommand *Command `yaml:"-" json:"-"`
|
||||||
// state attributes
|
// state attributes
|
||||||
State string `yaml:"state" json:"state"`
|
State string `yaml:"state,omitempty" json:"state,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -80,7 +81,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewPackage() *Package {
|
func NewPackage() *Package {
|
||||||
return &Package{}
|
return &Package{ PackageType: PackageTypeApk }
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Package) Clone() Resource {
|
func (p *Package) Clone() Resource {
|
||||||
@ -96,7 +97,26 @@ func (p *Package) Clone() Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Package) StateMachine() machine.Stater {
|
func (p *Package) StateMachine() machine.Stater {
|
||||||
return StorageMachine()
|
if p.stater == nil {
|
||||||
|
p.stater = StorageMachine(p)
|
||||||
|
}
|
||||||
|
return p.stater
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Package) Notify(m *machine.EventMessage) {
|
||||||
|
ctx := context.Background()
|
||||||
|
switch m.On {
|
||||||
|
case machine.ENTERSTATEEVENT:
|
||||||
|
switch m.Dest {
|
||||||
|
case "start_create":
|
||||||
|
if e := p.Create(ctx); e != nil {
|
||||||
|
p.stater.Trigger("created")
|
||||||
|
}
|
||||||
|
case "present":
|
||||||
|
p.State = "present"
|
||||||
|
}
|
||||||
|
case machine.EXITSTATEEVENT:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Package) URI() string {
|
func (p *Package) URI() string {
|
||||||
@ -140,6 +160,18 @@ func (p *Package) ResolveId(ctx context.Context) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Package) Create(ctx context.Context) error {
|
||||||
|
if p.Version == "latest" {
|
||||||
|
p.Version = ""
|
||||||
|
}
|
||||||
|
_, err := p.CreateCommand.Execute(p)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_,e := p.Read(ctx)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Package) Apply() error {
|
func (p *Package) Apply() error {
|
||||||
if p.Version == "latest" {
|
if p.Version == "latest" {
|
||||||
p.Version = ""
|
p.Version = ""
|
||||||
@ -292,10 +324,11 @@ func NewApkDeleteCommand() *Command {
|
|||||||
func NewAptCreateCommand() *Command {
|
func NewAptCreateCommand() *Command {
|
||||||
c := NewCommand()
|
c := NewCommand()
|
||||||
c.Path = "apt-get"
|
c.Path = "apt-get"
|
||||||
|
c.Split = false
|
||||||
c.Args = []CommandArg{
|
c.Args = []CommandArg{
|
||||||
CommandArg("satisfy"),
|
CommandArg("satisfy"),
|
||||||
CommandArg("-y"),
|
CommandArg("-y"),
|
||||||
CommandArg("{{ .Name }} ({{ .Required }})"),
|
CommandArg("{{ .Name }} ({{ if .Required }}{{ .Required }}{{ else }}>=0.0.0{{ end }})"),
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
@ -58,17 +58,21 @@ func NewResource(uri string) Resource {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func StorageMachine() machine.Stater {
|
func StorageMachine(sub machine.Subscriber) machine.Stater {
|
||||||
// start_destroy -> absent -> start_create -> present -> start_destroy
|
// start_destroy -> absent -> start_create -> present -> start_destroy
|
||||||
stater := machine.New("absent")
|
stater := machine.New("absent")
|
||||||
stater.AddStates("absent", "start_create", "present", "start_delete", "start_read", "start_update")
|
stater.AddStates("absent", "start_create", "present", "start_delete", "start_read", "start_update")
|
||||||
stater.AddTransition("create", "absent", "start_create")
|
stater.AddTransition("create", "absent", "start_create")
|
||||||
|
stater.AddSubscription("create", sub)
|
||||||
stater.AddTransition("created", "start_create", "present")
|
stater.AddTransition("created", "start_create", "present")
|
||||||
stater.AddTransition("read", "*", "start_read")
|
stater.AddTransition("read", "*", "start_read")
|
||||||
|
stater.AddSubscription("read", sub)
|
||||||
stater.AddTransition("state_read", "start_read", "present")
|
stater.AddTransition("state_read", "start_read", "present")
|
||||||
stater.AddTransition("update", "*", "start_update")
|
stater.AddTransition("update", "*", "start_update")
|
||||||
|
stater.AddSubscription("update", sub)
|
||||||
stater.AddTransition("updated", "start_update", "present")
|
stater.AddTransition("updated", "start_update", "present")
|
||||||
stater.AddTransition("delete", "*", "start_delete")
|
stater.AddTransition("delete", "*", "start_delete")
|
||||||
|
stater.AddSubscription("delete", sub)
|
||||||
stater.AddTransition("deleted", "start_delete", "absent")
|
stater.AddTransition("deleted", "start_delete", "absent")
|
||||||
return stater
|
return stater
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,12 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^[a-zA-Z0-9][a-zA-Z0-9+.-_]+$"
|
"pattern": "^[a-zA-Z0-9][-a-zA-Z0-9+._]+$"
|
||||||
},
|
},
|
||||||
"required": {
|
"required": {
|
||||||
"description": "version requirement",
|
"description": "version requirement",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^([><~=]{0,1}[-_a-zA-Z0-9+.]+|)$"
|
"pattern": "^([><~=]{0,2}[-_a-zA-Z0-9+.]+|)$"
|
||||||
},
|
},
|
||||||
"version": {
|
"version": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -28,6 +28,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
|
stater machine.Stater `json:"-" yaml:"-"`
|
||||||
Name string `json:"name" yaml:"name"`
|
Name string `json:"name" yaml:"name"`
|
||||||
UID string `json:"uid,omitempty" yaml:"uid,omitempty"`
|
UID string `json:"uid,omitempty" yaml:"uid,omitempty"`
|
||||||
Group string `json:"group,omitempty" yaml:"group,omitempty"`
|
Group string `json:"group,omitempty" yaml:"group,omitempty"`
|
||||||
@ -83,7 +84,26 @@ func (u *User) Clone() Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) StateMachine() machine.Stater {
|
func (u *User) StateMachine() machine.Stater {
|
||||||
return StorageMachine()
|
if u.stater == nil {
|
||||||
|
u.stater = StorageMachine(u)
|
||||||
|
}
|
||||||
|
return u.stater
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) Notify(m *machine.EventMessage) {
|
||||||
|
ctx := context.Background()
|
||||||
|
switch m.On {
|
||||||
|
case machine.ENTERSTATEEVENT:
|
||||||
|
switch m.Dest {
|
||||||
|
case "start_create":
|
||||||
|
if e := u.Create(ctx); e != nil {
|
||||||
|
u.stater.Trigger("created")
|
||||||
|
}
|
||||||
|
case "present":
|
||||||
|
u.State = "present"
|
||||||
|
}
|
||||||
|
case machine.EXITSTATEEVENT:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) SetURI(uri string) error {
|
func (u *User) SetURI(uri string) error {
|
||||||
|
BIN
md-images/jx-diff.gif
Normal file
BIN
md-images/jx-diff.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.6 MiB |
Loading…
Reference in New Issue
Block a user