resources: Unify resource creation and kind setting

This removes the duplication of the kind string and cleans up things for
resource creation.
This commit is contained in:
James Shubin
2017-06-07 02:26:14 -04:00
parent 2f6c77fba2
commit b8ff6938df
30 changed files with 60 additions and 108 deletions

View File

@@ -73,14 +73,13 @@ Init() error
``` ```
This is called to initialize the resource. If something goes wrong, it should This is called to initialize the resource. If something goes wrong, it should
return an error. It should set the resource `kind`, do any resource specific return an error. It should do any resource specific work, and finish by calling
work, and finish by calling the `Init` method of the base resource. the `Init` method of the base resource.
#### Example #### Example
```golang ```golang
// Init initializes the Foo resource. // Init initializes the Foo resource.
func (obj *FooRes) Init() error { func (obj *FooRes) Init() error {
obj.BaseRes.Kind = "foo" // must lower case resource kind
// run the resource specific initialization, and error if anything fails // run the resource specific initialization, and error if anything fails
if some_error { if some_error {
return err // something went wrong! return err // something went wrong!
@@ -399,9 +398,9 @@ UnmarshalYAML(unmarshal func(interface{}) error) error // optional
``` ```
This is optional, but recommended for any resource that will have a YAML This is optional, but recommended for any resource that will have a YAML
accessible struct, and an entry in the `GraphConfig` struct. It is not required accessible struct. It is not required because to do so would mean that
because to do so would mean that third-party or custom resources (such as those third-party or custom resources (such as those someone writes to use with
someone writes to use with `libmgmt`) would have to implement this needlessly. `libmgmt`) would have to implement this needlessly.
The signature intentionally matches what is required to satisfy the `go-yaml` The signature intentionally matches what is required to satisfy the `go-yaml`
[Unmarshaler](https://godoc.org/gopkg.in/yaml.v2#Unmarshaler) interface. [Unmarshaler](https://godoc.org/gopkg.in/yaml.v2#Unmarshaler) interface.
@@ -453,35 +452,15 @@ type FooRes struct {
} }
``` ```
### YAML ### Resource registration
In addition to labelling your resource struct with YAML fields, you must also All resources must be registered with the engine so that they can be found. This
add an entry to the internal `GraphConfig` struct. It is a fairly straight also ensures they can be encoded and decoded. Make sure to include the following
forward one line patch. code snippet for this to work.
```golang ```golang
type GraphConfig struct {
// [snip...]
Resources struct {
Noop []*resources.NoopRes `yaml:"noop"`
File []*resources.FileRes `yaml:"file"`
// [snip...]
Foo []*resources.FooRes `yaml:"foo"` // tada :)
}
}
```
It's also recommended that you add the [UnmarshalYAML](#unmarshalyaml) method to
your resources so that unspecified values are given sane defaults.
### Gob registration
All resources must be registered with the `golang` _gob_ module so that they can
be encoded and decoded. Make sure to include the following code snippet for this
to work.
```golang
import "encoding/gob"
func init() { // special golang method that runs once func init() { // special golang method that runs once
gob.Register(&FooRes{}) // substitude your resource here // set your resource kind and struct here (the kind must be lower case)
RegisterResource("foo", func() Res { return &FooRes{} })
} }
``` ```

View File

@@ -171,7 +171,6 @@ func GetResources(obj *EmbdEtcd, hostnameFilter, kindFilter []string) ([]resourc
} }
if obj, err := resources.B64ToRes(val); err == nil { if obj, err := resources.B64ToRes(val); err == nil {
obj.SetKind(kind) // cheap init
log.Printf("Etcd: Get: (Hostname, Kind, Name): (%s, %s, %s)", hostname, kind, name) log.Printf("Etcd: Get: (Hostname, Kind, Name): (%s, %s, %s)", hostname, kind, name)
resourceList = append(resourceList, obj) resourceList = append(resourceList, obj)
} else { } else {

View File

@@ -61,12 +61,12 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
return nil, err return nil, err
} }
// FIXME: these are being specified temporarily until it's the default!
metaparams := resources.DefaultMetaParams metaparams := resources.DefaultMetaParams
exec1 := &resources.ExecRes{ exec1 := &resources.ExecRes{
BaseRes: resources.BaseRes{ BaseRes: resources.BaseRes{
Name: "exec1", Name: "exec1",
Kind: "exec",
MetaParams: metaparams, MetaParams: metaparams,
}, },
Cmd: "echo hello world && echo goodbye world 1>&2", // to stdout && stderr Cmd: "echo hello world && echo goodbye world 1>&2", // to stdout && stderr
@@ -77,6 +77,7 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
output := &resources.FileRes{ output := &resources.FileRes{
BaseRes: resources.BaseRes{ BaseRes: resources.BaseRes{
Name: "output", Name: "output",
Kind: "file",
MetaParams: metaparams, MetaParams: metaparams,
// send->recv! // send->recv!
Recv: map[string]*resources.Send{ Recv: map[string]*resources.Send{
@@ -92,6 +93,7 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
stdout := &resources.FileRes{ stdout := &resources.FileRes{
BaseRes: resources.BaseRes{ BaseRes: resources.BaseRes{
Name: "stdout", Name: "stdout",
Kind: "file",
MetaParams: metaparams, MetaParams: metaparams,
// send->recv! // send->recv!
Recv: map[string]*resources.Send{ Recv: map[string]*resources.Send{
@@ -107,6 +109,7 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
stderr := &resources.FileRes{ stderr := &resources.FileRes{
BaseRes: resources.BaseRes{ BaseRes: resources.BaseRes{
Name: "stderr", Name: "stderr",
Kind: "file",
MetaParams: metaparams, MetaParams: metaparams,
// send->recv! // send->recv!
Recv: map[string]*resources.Send{ Recv: map[string]*resources.Send{

View File

@@ -63,6 +63,7 @@ func (obj *MyGAPI) subGraph() (*pgraph.Graph, error) {
f1 := &resources.FileRes{ f1 := &resources.FileRes{
BaseRes: resources.BaseRes{ BaseRes: resources.BaseRes{
Name: "file1", Name: "file1",
Kind: "file",
MetaParams: metaparams, MetaParams: metaparams,
}, },
Path: "/tmp/mgmt/sub1", Path: "/tmp/mgmt/sub1",
@@ -74,6 +75,7 @@ func (obj *MyGAPI) subGraph() (*pgraph.Graph, error) {
n1 := &resources.NoopRes{ n1 := &resources.NoopRes{
BaseRes: resources.BaseRes{ BaseRes: resources.BaseRes{
Name: "noop1", Name: "noop1",
Kind: "noop",
MetaParams: metaparams, MetaParams: metaparams,
}, },
} }
@@ -93,7 +95,6 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
return nil, err return nil, err
} }
// FIXME: these are being specified temporarily until it's the default!
metaparams := resources.DefaultMetaParams metaparams := resources.DefaultMetaParams
content := "I created a subgraph!\n" content := "I created a subgraph!\n"

View File

@@ -61,13 +61,13 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
return nil, err return nil, err
} }
// FIXME: these are being specified temporarily until it's the default!
metaparams := resources.DefaultMetaParams metaparams := resources.DefaultMetaParams
content := "I created a subgraph!\n" content := "I created a subgraph!\n"
f0 := &resources.FileRes{ f0 := &resources.FileRes{
BaseRes: resources.BaseRes{ BaseRes: resources.BaseRes{
Name: "README", Name: "README",
Kind: "file",
MetaParams: metaparams, MetaParams: metaparams,
}, },
Path: "/tmp/mgmt/README", Path: "/tmp/mgmt/README",
@@ -86,6 +86,7 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
f1 := &resources.FileRes{ f1 := &resources.FileRes{
BaseRes: resources.BaseRes{ BaseRes: resources.BaseRes{
Name: "file1", Name: "file1",
Kind: "file",
MetaParams: metaparams, MetaParams: metaparams,
}, },
Path: "/tmp/mgmt/sub1", Path: "/tmp/mgmt/sub1",
@@ -97,6 +98,7 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
n1 := &resources.NoopRes{ n1 := &resources.NoopRes{
BaseRes: resources.BaseRes{ BaseRes: resources.BaseRes{
Name: "noop1", Name: "noop1",
Kind: "noop",
MetaParams: metaparams, MetaParams: metaparams,
}, },
} }
@@ -110,6 +112,7 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
subGraphRes0 := &resources.GraphRes{ // TODO: should we name this SubGraphRes ? subGraphRes0 := &resources.GraphRes{ // TODO: should we name this SubGraphRes ?
BaseRes: resources.BaseRes{ BaseRes: resources.BaseRes{
Name: "subgraph1", Name: "subgraph1",
Kind: "graph",
MetaParams: metaparams, MetaParams: metaparams,
}, },
Graph: subGraph, Graph: subGraph,

View File

@@ -57,9 +57,11 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
return nil, fmt.Errorf("libmgmt: MyGAPI is not initialized") return nil, fmt.Errorf("libmgmt: MyGAPI is not initialized")
} }
// TODO: this method of instantiation is deprecated, use: NewResource
n1 := &resources.NoopRes{ n1 := &resources.NoopRes{
BaseRes: resources.BaseRes{ BaseRes: resources.BaseRes{
Name: "noop1", Name: "noop1",
Kind: "noop",
MetaParams: resources.DefaultMetaParams, MetaParams: resources.DefaultMetaParams,
}, },
} }

View File

@@ -65,12 +65,11 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
} }
var vertex pgraph.Vertex var vertex pgraph.Vertex
for i := uint(0); i < obj.Count; i++ { for i := uint(0); i < obj.Count; i++ {
n := &resources.NoopRes{ n, err := resources.NewResource("noop")
BaseRes: resources.BaseRes{ if err != nil {
Name: fmt.Sprintf("noop%d", i), return nil, err
MetaParams: resources.DefaultMetaParams,
},
} }
n.SetName(fmt.Sprintf("noop%d", i))
g.AddVertex(n) g.AddVertex(n)
if i > 0 { if i > 0 {
g.AddEdge(vertex, n, &resources.Edge{Name: fmt.Sprintf("e%d", i)}) g.AddEdge(vertex, n, &resources.Edge{Name: fmt.Sprintf("e%d", i)})

View File

@@ -61,13 +61,13 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
return nil, err return nil, err
} }
// FIXME: these are being specified temporarily until it's the default!
metaparams := resources.DefaultMetaParams metaparams := resources.DefaultMetaParams
content := "Delete me to trigger a notification!\n" content := "Delete me to trigger a notification!\n"
f0 := &resources.FileRes{ f0 := &resources.FileRes{
BaseRes: resources.BaseRes{ BaseRes: resources.BaseRes{
Name: "README", Name: "README",
Kind: "file",
MetaParams: metaparams, MetaParams: metaparams,
}, },
Path: "/tmp/mgmt/README", Path: "/tmp/mgmt/README",
@@ -80,6 +80,7 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
p1 := &resources.PasswordRes{ p1 := &resources.PasswordRes{
BaseRes: resources.BaseRes{ BaseRes: resources.BaseRes{
Name: "password1", Name: "password1",
Kind: "password",
MetaParams: metaparams, MetaParams: metaparams,
}, },
Length: 8, // generated string will have this many characters Length: 8, // generated string will have this many characters
@@ -90,6 +91,7 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
f1 := &resources.FileRes{ f1 := &resources.FileRes{
BaseRes: resources.BaseRes{ BaseRes: resources.BaseRes{
Name: "file1", Name: "file1",
Kind: "file",
MetaParams: metaparams, MetaParams: metaparams,
// send->recv! // send->recv!
Recv: map[string]*resources.Send{ Recv: map[string]*resources.Send{
@@ -106,6 +108,7 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
n1 := &resources.NoopRes{ n1 := &resources.NoopRes{
BaseRes: resources.BaseRes{ BaseRes: resources.BaseRes{
Name: "noop1", Name: "noop1",
Kind: "noop",
MetaParams: metaparams, MetaParams: metaparams,
}, },
} }

View File

@@ -19,7 +19,6 @@
package resources package resources
import ( import (
"encoding/gob"
"fmt" "fmt"
"log" "log"
"os" "os"
@@ -39,7 +38,6 @@ const (
) )
func init() { func init() {
gob.Register(&AugeasRes{})
RegisterResource("augeas", func() Res { return &AugeasRes{} }) RegisterResource("augeas", func() Res { return &AugeasRes{} })
} }
@@ -94,7 +92,6 @@ func (obj *AugeasRes) Validate() error {
// Init initiates the resource. // Init initiates the resource.
func (obj *AugeasRes) Init() error { func (obj *AugeasRes) Init() error {
obj.BaseRes.Kind = "augeas"
return obj.BaseRes.Init() // call base init, b/c we're overriding return obj.BaseRes.Init() // call base init, b/c we're overriding
} }

View File

@@ -108,6 +108,7 @@ func NewNoopResTest(name string) *NoopResTest {
NoopRes: NoopRes{ NoopRes: NoopRes{
BaseRes: BaseRes{ BaseRes: BaseRes{
Name: name, Name: name,
Kind: "noop",
MetaParams: MetaParams{ MetaParams: MetaParams{
AutoGroup: true, // always autogroup AutoGroup: true, // always autogroup
}, },

View File

@@ -20,7 +20,6 @@ package resources
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"encoding/gob"
"fmt" "fmt"
"log" "log"
"os/exec" "os/exec"
@@ -34,7 +33,6 @@ import (
) )
func init() { func init() {
gob.Register(&ExecRes{})
RegisterResource("exec", func() Res { return &ExecRes{} }) RegisterResource("exec", func() Res { return &ExecRes{} })
} }
@@ -73,7 +71,6 @@ func (obj *ExecRes) Validate() error {
// Init runs some startup code for this resource. // Init runs some startup code for this resource.
func (obj *ExecRes) Init() error { func (obj *ExecRes) Init() error {
obj.BaseRes.Kind = "exec"
return obj.BaseRes.Init() // call base init, b/c we're overriding return obj.BaseRes.Init() // call base init, b/c we're overriding
} }

View File

@@ -25,6 +25,7 @@ func TestExecSendRecv1(t *testing.T) {
r1 := &ExecRes{ r1 := &ExecRes{
BaseRes: BaseRes{ BaseRes: BaseRes{
Name: "exec1", Name: "exec1",
Kind: "exec",
//MetaParams: MetaParams, //MetaParams: MetaParams,
}, },
Cmd: "echo hello world", Cmd: "echo hello world",
@@ -71,6 +72,7 @@ func TestExecSendRecv2(t *testing.T) {
r1 := &ExecRes{ r1 := &ExecRes{
BaseRes: BaseRes{ BaseRes: BaseRes{
Name: "exec1", Name: "exec1",
Kind: "exec",
//MetaParams: MetaParams, //MetaParams: MetaParams,
}, },
Cmd: "echo hello world 1>&2", // to stderr Cmd: "echo hello world 1>&2", // to stderr
@@ -117,6 +119,7 @@ func TestExecSendRecv3(t *testing.T) {
r1 := &ExecRes{ r1 := &ExecRes{
BaseRes: BaseRes{ BaseRes: BaseRes{
Name: "exec1", Name: "exec1",
Kind: "exec",
//MetaParams: MetaParams, //MetaParams: MetaParams,
}, },
Cmd: "echo hello world && echo goodbye world 1>&2", // to stdout && stderr Cmd: "echo hello world && echo goodbye world 1>&2", // to stdout && stderr

View File

@@ -20,7 +20,6 @@ package resources
import ( import (
"bytes" "bytes"
"crypto/sha256" "crypto/sha256"
"encoding/gob"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"io" "io"
@@ -41,7 +40,6 @@ import (
) )
func init() { func init() {
gob.Register(&FileRes{})
RegisterResource("file", func() Res { return &FileRes{} }) RegisterResource("file", func() Res { return &FileRes{} })
} }
@@ -148,7 +146,6 @@ func (obj *FileRes) Init() error {
obj.path = obj.GetPath() // compute once obj.path = obj.GetPath() // compute once
obj.isDir = strings.HasSuffix(obj.path, "/") // dirs have trailing slashes obj.isDir = strings.HasSuffix(obj.path, "/") // dirs have trailing slashes
obj.BaseRes.Kind = "file"
return obj.BaseRes.Init() // call base init, b/c we're overriding return obj.BaseRes.Init() // call base init, b/c we're overriding
} }

View File

@@ -18,7 +18,6 @@
package resources package resources
import ( import (
"encoding/gob"
"fmt" "fmt"
"github.com/purpleidea/mgmt/pgraph" "github.com/purpleidea/mgmt/pgraph"
@@ -29,7 +28,6 @@ import (
func init() { func init() {
RegisterResource("graph", func() Res { return &GraphRes{} }) RegisterResource("graph", func() Res { return &GraphRes{} })
gob.Register(&GraphRes{})
} }
// GraphRes is a resource that recursively runs a sub graph of resources. // GraphRes is a resource that recursively runs a sub graph of resources.
@@ -89,7 +87,6 @@ func (obj *GraphRes) Init() error {
} }
} }
obj.BaseRes.Kind = "graph"
return obj.BaseRes.Init() // call base init, b/c we're overrriding return obj.BaseRes.Init() // call base init, b/c we're overrriding
} }

View File

@@ -18,7 +18,6 @@
package resources package resources
import ( import (
"encoding/gob"
"errors" "errors"
"fmt" "fmt"
"log" "log"
@@ -36,7 +35,6 @@ var ErrResourceInsufficientParameters = errors.New(
func init() { func init() {
RegisterResource("hostname", func() Res { return &HostnameRes{} }) RegisterResource("hostname", func() Res { return &HostnameRes{} })
gob.Register(&HostnameRes{})
} }
const ( const (
@@ -88,7 +86,6 @@ func (obj *HostnameRes) Validate() error {
// Init runs some startup code for this resource. // Init runs some startup code for this resource.
func (obj *HostnameRes) Init() error { func (obj *HostnameRes) Init() error {
obj.BaseRes.Kind = "hostname"
if obj.PrettyHostname == "" { if obj.PrettyHostname == "" {
obj.PrettyHostname = obj.Hostname obj.PrettyHostname = obj.Hostname
} }

View File

@@ -18,7 +18,6 @@
package resources package resources
import ( import (
"encoding/gob"
"fmt" "fmt"
"log" "log"
"strconv" "strconv"
@@ -28,7 +27,6 @@ import (
func init() { func init() {
RegisterResource("kv", func() Res { return &KVRes{} }) RegisterResource("kv", func() Res { return &KVRes{} })
gob.Register(&KVRes{})
} }
// KVResSkipCmpStyle represents the different styles of comparison when using SkipLessThan. // KVResSkipCmpStyle represents the different styles of comparison when using SkipLessThan.
@@ -89,7 +87,6 @@ func (obj *KVRes) Validate() error {
// Init initializes the resource. // Init initializes the resource.
func (obj *KVRes) Init() error { func (obj *KVRes) Init() error {
obj.BaseRes.Kind = "kv"
return obj.BaseRes.Init() // call base init, b/c we're overriding return obj.BaseRes.Init() // call base init, b/c we're overriding
} }

View File

@@ -18,7 +18,6 @@
package resources package resources
import ( import (
"encoding/gob"
"fmt" "fmt"
"log" "log"
"regexp" "regexp"
@@ -29,7 +28,6 @@ import (
func init() { func init() {
RegisterResource("msg", func() Res { return &MsgRes{} }) RegisterResource("msg", func() Res { return &MsgRes{} })
gob.Register(&MsgRes{})
} }
// MsgRes is a resource that writes messages to logs. // MsgRes is a resource that writes messages to logs.
@@ -76,7 +74,6 @@ func (obj *MsgRes) Validate() error {
// Init runs some startup code for this resource. // Init runs some startup code for this resource.
func (obj *MsgRes) Init() error { func (obj *MsgRes) Init() error {
obj.BaseRes.Kind = "msg"
return obj.BaseRes.Init() // call base init, b/c we're overrriding return obj.BaseRes.Init() // call base init, b/c we're overrriding
} }

View File

@@ -18,14 +18,12 @@
package resources package resources
import ( import (
"encoding/gob"
"fmt" "fmt"
"log" "log"
) )
func init() { func init() {
RegisterResource("noop", func() Res { return &NoopRes{} }) RegisterResource("noop", func() Res { return &NoopRes{} })
gob.Register(&NoopRes{})
} }
// NoopRes is a no-op resource that does nothing. // NoopRes is a no-op resource that does nothing.
@@ -50,7 +48,6 @@ func (obj *NoopRes) Validate() error {
// Init runs some startup code for this resource. // Init runs some startup code for this resource.
func (obj *NoopRes) Init() error { func (obj *NoopRes) Init() error {
obj.BaseRes.Kind = "noop"
return obj.BaseRes.Init() // call base init, b/c we're overriding return obj.BaseRes.Init() // call base init, b/c we're overriding
} }

View File

@@ -18,7 +18,6 @@
package resources package resources
import ( import (
"encoding/gob"
"errors" "errors"
"fmt" "fmt"
"log" "log"
@@ -42,7 +41,6 @@ const (
func init() { func init() {
RegisterResource("nspawn", func() Res { return &NspawnRes{} }) RegisterResource("nspawn", func() Res { return &NspawnRes{} })
gob.Register(&NspawnRes{})
} }
// NspawnRes is an nspawn container resource. // NspawnRes is an nspawn container resource.
@@ -93,7 +91,6 @@ func (obj *NspawnRes) Init() error {
if err := obj.svc.Init(); err != nil { if err := obj.svc.Init(); err != nil {
return err return err
} }
obj.BaseRes.Kind = "nspawn"
return obj.BaseRes.Init() return obj.BaseRes.Init()
} }

View File

@@ -19,7 +19,6 @@ package resources
import ( import (
"crypto/rand" "crypto/rand"
"encoding/gob"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
@@ -35,7 +34,6 @@ import (
func init() { func init() {
RegisterResource("password", func() Res { return &PasswordRes{} }) RegisterResource("password", func() Res { return &PasswordRes{} })
gob.Register(&PasswordRes{})
} }
const ( const (
@@ -74,7 +72,6 @@ func (obj *PasswordRes) Validate() error {
// Init generates a new password for this resource if one was not provided. It // Init generates a new password for this resource if one was not provided. It
// will save this into a local file. It will load it back in from previous runs. // will save this into a local file. It will load it back in from previous runs.
func (obj *PasswordRes) Init() error { func (obj *PasswordRes) Init() error {
obj.BaseRes.Kind = "password" // must be set before using VarDir
dir, err := obj.VarDir("") dir, err := obj.VarDir("")
if err != nil { if err != nil {

View File

@@ -18,7 +18,6 @@
package resources package resources
import ( import (
"encoding/gob"
"fmt" "fmt"
"log" "log"
"path" "path"
@@ -32,7 +31,6 @@ import (
func init() { func init() {
RegisterResource("pkg", func() Res { return &PkgRes{} }) RegisterResource("pkg", func() Res { return &PkgRes{} })
gob.Register(&PkgRes{})
} }
// PkgRes is a package resource for packagekit. // PkgRes is a package resource for packagekit.
@@ -67,7 +65,6 @@ func (obj *PkgRes) Validate() error {
// Init runs some startup code for this resource. // Init runs some startup code for this resource.
func (obj *PkgRes) Init() error { func (obj *PkgRes) Init() error {
obj.BaseRes.Kind = "pkg"
if err := obj.BaseRes.Init(); err != nil { // call base init, b/c we're overriding if err := obj.BaseRes.Init(); err != nil { // call base init, b/c we're overriding
return err return err
} }

View File

@@ -19,6 +19,7 @@
package resources package resources
import ( import (
"encoding/gob"
"fmt" "fmt"
"log" "log"
"math" "math"
@@ -43,18 +44,21 @@ var registeredResources = map[string]func() Res{}
// RegisterResource registers a new resource by providing a constructor // RegisterResource registers a new resource by providing a constructor
// function that returns a resource object ready to be unmarshalled from YAML. // function that returns a resource object ready to be unmarshalled from YAML.
func RegisterResource(name string, creator func() Res) { func RegisterResource(kind string, fn func() Res) {
registeredResources[name] = creator gob.Register(fn())
registeredResources[kind] = fn
} }
// NewEmptyNamedResource returns an empty resource object from a registered // NewResource returns an empty resource object from a registered kind.
// type, ready to be unmarshalled. func NewResource(kind string) (Res, error) {
func NewEmptyNamedResource(name string) (Res, error) { fn, ok := registeredResources[kind]
fn, ok := registeredResources[name]
if !ok { if !ok {
return nil, fmt.Errorf("no resource named %s available", name) return nil, fmt.Errorf("no resource kind `%s` available", kind)
} }
return fn(), nil res := fn().Default()
res.SetKind(kind)
//*res.Meta() = DefaultMetaParams // TODO: centralize this here?
return res, nil
} }
//go:generate stringer -type=ResState -output=resstate_stringer.go //go:generate stringer -type=ResState -output=resstate_stringer.go

View File

@@ -42,6 +42,7 @@ func TestCompare2(t *testing.T) {
r1 := &NoopRes{ r1 := &NoopRes{
BaseRes: BaseRes{ BaseRes: BaseRes{
Name: "noop1", Name: "noop1",
Kind: "noop",
MetaParams: MetaParams{ MetaParams: MetaParams{
Noop: true, Noop: true,
}, },
@@ -49,7 +50,8 @@ func TestCompare2(t *testing.T) {
} }
r2 := &NoopRes{ r2 := &NoopRes{
BaseRes: BaseRes{ BaseRes: BaseRes{
Name: "noop1", // same nampe Name: "noop1", // same name
Kind: "noop",
MetaParams: MetaParams{ MetaParams: MetaParams{
Noop: false, // different noop Noop: false, // different noop
}, },
@@ -111,12 +113,9 @@ func TestMiscEncodeDecode1(t *testing.T) {
func TestMiscEncodeDecode2(t *testing.T) { func TestMiscEncodeDecode2(t *testing.T) {
var err error var err error
//gob.Register( &NoopRes{} ) // happens in noop.go : init()
//gob.Register( &FileRes{} ) // happens in file.go : init()
// ...
// encode // encode
var input Res = &FileRes{} input, _ := NewResource("file")
b64, err := ResToB64(input) b64, err := ResToB64(input)
if err != nil { if err != nil {

View File

@@ -41,6 +41,7 @@ func NewNoopResTestSema(name string, semas []string) *NoopResTest {
NoopRes: NoopRes{ NoopRes: NoopRes{
BaseRes: BaseRes{ BaseRes: BaseRes{
Name: name, Name: name,
Kind: "noop",
MetaParams: MetaParams{ MetaParams: MetaParams{
AutoGroup: true, // always autogroup AutoGroup: true, // always autogroup
Sema: semas, Sema: semas,

View File

@@ -20,7 +20,6 @@
package resources package resources
import ( import (
"encoding/gob"
"fmt" "fmt"
"log" "log"
@@ -34,7 +33,6 @@ import (
func init() { func init() {
RegisterResource("svc", func() Res { return &SvcRes{} }) RegisterResource("svc", func() Res { return &SvcRes{} })
gob.Register(&SvcRes{})
} }
// SvcRes is a service resource for systemd units. // SvcRes is a service resource for systemd units.
@@ -67,7 +65,6 @@ func (obj *SvcRes) Validate() error {
// Init runs some startup code for this resource. // Init runs some startup code for this resource.
func (obj *SvcRes) Init() error { func (obj *SvcRes) Init() error {
obj.BaseRes.Kind = "svc"
return obj.BaseRes.Init() // call base init, b/c we're overriding return obj.BaseRes.Init() // call base init, b/c we're overriding
} }

View File

@@ -18,7 +18,6 @@
package resources package resources
import ( import (
"encoding/gob"
"fmt" "fmt"
"log" "log"
"time" "time"
@@ -26,7 +25,6 @@ import (
func init() { func init() {
RegisterResource("timer", func() Res { return &TimerRes{} }) RegisterResource("timer", func() Res { return &TimerRes{} })
gob.Register(&TimerRes{})
} }
// TimerRes is a timer resource for time based events. // TimerRes is a timer resource for time based events.
@@ -59,7 +57,6 @@ func (obj *TimerRes) Validate() error {
// Init runs some startup code for this resource. // Init runs some startup code for this resource.
func (obj *TimerRes) Init() error { func (obj *TimerRes) Init() error {
obj.BaseRes.Kind = "timer"
return obj.BaseRes.Init() // call base init, b/c we're overrriding return obj.BaseRes.Init() // call base init, b/c we're overrriding
} }

View File

@@ -52,7 +52,7 @@ func B64ToRes(str string) (Res, error) {
} }
res, ok := output.(Res) res, ok := output.(Res)
if !ok { if !ok {
return nil, fmt.Errorf("Output %v is not a Res", res) return nil, fmt.Errorf("output `%v` is not a Res", output)
} }
return res, nil return res, nil

View File

@@ -19,7 +19,6 @@
package resources package resources
import ( import (
"encoding/gob"
"fmt" "fmt"
"log" "log"
"math/rand" "math/rand"
@@ -38,7 +37,6 @@ import (
func init() { func init() {
RegisterResource("virt", func() Res { return &VirtRes{} }) RegisterResource("virt", func() Res { return &VirtRes{} })
gob.Register(&VirtRes{})
} }
const ( const (
@@ -192,7 +190,6 @@ func (obj *VirtRes) Init() error {
} }
} }
obj.wg = &sync.WaitGroup{} obj.wg = &sync.WaitGroup{}
obj.BaseRes.Kind = "virt"
return obj.BaseRes.Init() // call base init, b/c we're overriding return obj.BaseRes.Init() // call base init, b/c we're overriding
} }

View File

@@ -55,19 +55,18 @@ func (obj *MyGAPI) Graph() (*pgraph.Graph, error) {
if !obj.initialized { if !obj.initialized {
return nil, fmt.Errorf("%s: MyGAPI is not initialized", obj.Name) return nil, fmt.Errorf("%s: MyGAPI is not initialized", obj.Name)
} }
// FIXME: these are being specified temporarily until it's the default!
metaparams := resources.DefaultMetaParams var err error
g, err := pgraph.NewGraph(obj.Name) g, err := pgraph.NewGraph(obj.Name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
n0 := &resources.NoopRes{ n0, err := resources.NewResource("noop")
BaseRes: resources.BaseRes{ if err != nil {
Name: "noop1", return nil, err
MetaParams: metaparams,
},
} }
n0.SetName("noop1")
g.AddVertex(n0) g.AddVertex(n0)
//g, err := config.NewGraphFromConfig(obj.data.Hostname, obj.data.World, obj.data.Noop) //g, err := config.NewGraphFromConfig(obj.data.Hostname, obj.data.World, obj.data.Noop)

View File

@@ -122,7 +122,7 @@ func (r *Resource) UnmarshalYAML(unmarshal func(interface{}) error) error {
// Decode is the second stage for unmarshaling of resources (knowing their // Decode is the second stage for unmarshaling of resources (knowing their
// kind). // kind).
func (r *Resource) Decode(kind string) (err error) { func (r *Resource) Decode(kind string) (err error) {
r.resource, err = resources.NewEmptyNamedResource(kind) r.resource, err = resources.NewResource(kind)
if err != nil { if err != nil {
return err return err
} }
@@ -134,7 +134,6 @@ func (r *Resource) Decode(kind string) (err error) {
// Set resource name, meta and kind // Set resource name, meta and kind
r.resource.SetName(r.Name) r.resource.SetName(r.Name)
r.resource.SetKind(strings.ToLower(kind))
meta := r.resource.Meta() meta := r.resource.Meta()
*meta = r.Meta *meta = r.Meta
return return
@@ -199,7 +198,6 @@ func (c *GraphConfig) NewGraphFromConfig(hostname string, world resources.World,
} else if !noop { // do not export any resources if noop } else if !noop { // do not export any resources if noop
// store for addition to backend storage... // store for addition to backend storage...
res.SetName(res.GetName()[2:]) // slice off @@ res.SetName(res.GetName()[2:]) // slice off @@
res.SetKind(kind) // cheap init
resourceList = append(resourceList, res) resourceList = append(resourceList, res)
} }
} }