lang: Add edges to lexer and parser
This adds some initial syntax for external edges to the language. There are still improvements which are necessary for send/recv.
This commit is contained in:
@@ -11,7 +11,7 @@ frontend. This guide describes some of the internals of the language.
|
|||||||
|
|
||||||
The mgmt language is a declarative (immutable) functional, reactive programming
|
The mgmt language is a declarative (immutable) functional, reactive programming
|
||||||
language. It is implemented in `golang`. A longer introduction to the language
|
language. It is implemented in `golang`. A longer introduction to the language
|
||||||
is coming soon!
|
is [available as a blog post here](https://purpleidea.com/blog/2018/02/05/mgmt-configuration-language/)!
|
||||||
|
|
||||||
### Types
|
### Types
|
||||||
|
|
||||||
@@ -83,10 +83,68 @@ These docs will be expanded on when things are more certain to be stable.
|
|||||||
|
|
||||||
### Statements
|
### Statements
|
||||||
|
|
||||||
Statements, and the `Stmt` interface need to be better documented. For now
|
There are a very small number of statements in our language. They include:
|
||||||
please consume
|
|
||||||
[lang/interfaces/ast.go](https://github.com/purpleidea/mgmt/tree/master/lang/interfaces/ast.go).
|
- **bind**: bind's an expression to a variable within that scope
|
||||||
These docs will be expanded on when things are more certain to be stable.
|
- eg: `$x = 42`
|
||||||
|
- **if**: produces up to one branch of statements based on a conditional
|
||||||
|
expression
|
||||||
|
|
||||||
|
```
|
||||||
|
if <conditional> {
|
||||||
|
<statements>
|
||||||
|
} else {
|
||||||
|
# the else branch is optional for if statements
|
||||||
|
<statements>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- **resource**: produces a resource
|
||||||
|
|
||||||
|
```
|
||||||
|
file "/tmp/hello" {
|
||||||
|
content => "world",
|
||||||
|
mode => "o=rwx",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- **edge**: produces an edge
|
||||||
|
|
||||||
|
```
|
||||||
|
File["/tmp/hello"] -> Print["alert4"]
|
||||||
|
```
|
||||||
|
|
||||||
|
All statements produce _output_. Output consists of between zero and more
|
||||||
|
`edges` and `resources`. A resource statement can produce a resource, whereas an
|
||||||
|
`if` statement produces whatever the chosen branch produces. Ultimately the goal
|
||||||
|
of executing our programs is to produce a list of `resources`, which along with
|
||||||
|
the produced `edges`, is built into a resource graph. This graph is then passed
|
||||||
|
to the engine for desired state application.
|
||||||
|
|
||||||
|
#### Bind
|
||||||
|
|
||||||
|
This section needs better documentation.
|
||||||
|
|
||||||
|
#### If
|
||||||
|
|
||||||
|
This section needs better documentation.
|
||||||
|
|
||||||
|
#### Resource
|
||||||
|
|
||||||
|
This section needs better documentation.
|
||||||
|
|
||||||
|
#### Edge
|
||||||
|
|
||||||
|
Edges express dependencies in the graph of resources which are output. They can
|
||||||
|
be chained as a pair, or in any greater number. For example, you may write:
|
||||||
|
|
||||||
|
```
|
||||||
|
Pkg["drbd"] -> File["/etc/drbd.conf"] -> Svc["drbd"]
|
||||||
|
```
|
||||||
|
|
||||||
|
to express a relationship between three resources. The first character in the
|
||||||
|
resource kind must be capitalized so that the parser can't ascertain
|
||||||
|
unambiguously that we are referring to a dependency relationship.
|
||||||
|
|
||||||
### Stages
|
### Stages
|
||||||
|
|
||||||
|
|||||||
14
examples/lang/edges0.mcl
Normal file
14
examples/lang/edges0.mcl
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
exec "exec0" {
|
||||||
|
cmd => "sleep 10s",
|
||||||
|
shell => "/bin/bash",
|
||||||
|
}
|
||||||
|
exec "exec1" {
|
||||||
|
cmd => "sleep 10s",
|
||||||
|
shell => "/bin/bash",
|
||||||
|
}
|
||||||
|
exec "exec2" {
|
||||||
|
cmd => "sleep 10s",
|
||||||
|
shell => "/bin/bash",
|
||||||
|
}
|
||||||
|
|
||||||
|
Exec["exec0"] -> Exec["exec1"] -> Exec["exec2"]
|
||||||
8
examples/lang/password0.mcl
Normal file
8
examples/lang/password0.mcl
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
password "pass0" {
|
||||||
|
length => 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
file "/tmp/mgmt/password" {
|
||||||
|
}
|
||||||
|
|
||||||
|
Password["pass0"].password -> File["/tmp/mgmt/password"].content
|
||||||
9
examples/lang/sendrecv0.mcl
Normal file
9
examples/lang/sendrecv0.mcl
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
exec "exec0" {
|
||||||
|
cmd => "echo hello world && echo goodbye world 1>&2", # to stdout && stderr
|
||||||
|
shell => "/bin/bash",
|
||||||
|
}
|
||||||
|
|
||||||
|
print "print0" {
|
||||||
|
}
|
||||||
|
|
||||||
|
Exec["exec0"].output -> Print["print0"].msg
|
||||||
14
examples/lang/sendrecv1.mcl
Normal file
14
examples/lang/sendrecv1.mcl
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
file "/tmp/mgmt/foo" {
|
||||||
|
content => "hello from foo\n",
|
||||||
|
}
|
||||||
|
|
||||||
|
print "print0" {
|
||||||
|
}
|
||||||
|
|
||||||
|
File["/tmp/mgmt/foo"].content -> Print["print0"].msg
|
||||||
|
|
||||||
|
print "print1" {
|
||||||
|
msg => "hello",
|
||||||
|
}
|
||||||
|
|
||||||
|
Print["print0"] -> Print["print1"]
|
||||||
8
examples/lang/sendrecv2.mcl
Normal file
8
examples/lang/sendrecv2.mcl
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
file "/tmp/mgmt/foo" {
|
||||||
|
content => "hello from foo\n",
|
||||||
|
}
|
||||||
|
|
||||||
|
file "/tmp/mgmt/bar" {
|
||||||
|
}
|
||||||
|
|
||||||
|
File["/tmp/mgmt/foo"].content -> File["/tmp/mgmt/bar"].content
|
||||||
21
examples/lang/sendrecv3.mcl
Normal file
21
examples/lang/sendrecv3.mcl
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
$ns = "estate"
|
||||||
|
$exchanged = kvlookup($ns)
|
||||||
|
$state = maplookup($exchanged, $hostname, "default")
|
||||||
|
|
||||||
|
exec "exec0" {
|
||||||
|
cmd => "echo hello world && echo goodbye world 1>&2", # to stdout && stderr
|
||||||
|
shell => "/bin/bash",
|
||||||
|
}
|
||||||
|
|
||||||
|
kv "kv0" {
|
||||||
|
key => $ns,
|
||||||
|
#value => "two",
|
||||||
|
}
|
||||||
|
|
||||||
|
Exec["exec0"].output -> Kv["kv0"].value
|
||||||
|
|
||||||
|
if $state != "default" {
|
||||||
|
file "/tmp/mgmt/state" {
|
||||||
|
content => printf("state: %s\n", $state),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,28 +8,43 @@ if $state == "one" || $state == "default" {
|
|||||||
file "/tmp/mgmt/state" {
|
file "/tmp/mgmt/state" {
|
||||||
content => "state: one\n",
|
content => "state: one\n",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exec "timer" {
|
||||||
|
cmd => "/usr/bin/sleep 1s",
|
||||||
|
}
|
||||||
kv "${ns}" {
|
kv "${ns}" {
|
||||||
key => $ns,
|
key => $ns,
|
||||||
value => "two",
|
value => "two",
|
||||||
}
|
}
|
||||||
|
Exec["timer"] -> Kv["${ns}"]
|
||||||
}
|
}
|
||||||
if $state == "two" {
|
if $state == "two" {
|
||||||
|
|
||||||
file "/tmp/mgmt/state" {
|
file "/tmp/mgmt/state" {
|
||||||
content => "state: two\n",
|
content => "state: two\n",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exec "timer" {
|
||||||
|
cmd => "/usr/bin/sleep 1s",
|
||||||
|
}
|
||||||
kv "${ns}" {
|
kv "${ns}" {
|
||||||
key => $ns,
|
key => $ns,
|
||||||
value => "three",
|
value => "three",
|
||||||
}
|
}
|
||||||
|
Exec["timer"] -> Kv["${ns}"]
|
||||||
}
|
}
|
||||||
if $state == "three" {
|
if $state == "three" {
|
||||||
|
|
||||||
file "/tmp/mgmt/state" {
|
file "/tmp/mgmt/state" {
|
||||||
content => "state: three\n",
|
content => "state: three\n",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exec "timer" {
|
||||||
|
cmd => "/usr/bin/sleep 1s",
|
||||||
|
}
|
||||||
kv "${ns}" {
|
kv "${ns}" {
|
||||||
key => $ns,
|
key => $ns,
|
||||||
value => "one",
|
value => "one",
|
||||||
}
|
}
|
||||||
|
Exec["timer"] -> Kv["${ns}"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -537,6 +537,43 @@ func TestAstInterpret0(t *testing.T) {
|
|||||||
graph: graph,
|
graph: graph,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
// FIXME: add a better vertexCmpFn so we can compare send/recv!
|
||||||
|
graph, _ := pgraph.NewGraph("g")
|
||||||
|
t1, _ := resources.NewNamedResource("test", "t1")
|
||||||
|
{
|
||||||
|
x := t1.(*resources.TestRes)
|
||||||
|
int64Ptr := int64(42)
|
||||||
|
x.Int64Ptr = &int64Ptr
|
||||||
|
graph.AddVertex(t1)
|
||||||
|
}
|
||||||
|
t2, _ := resources.NewNamedResource("test", "t2")
|
||||||
|
{
|
||||||
|
x := t2.(*resources.TestRes)
|
||||||
|
int64Ptr := int64(13)
|
||||||
|
x.Int64Ptr = &int64Ptr
|
||||||
|
graph.AddVertex(t2)
|
||||||
|
}
|
||||||
|
edge := &resources.Edge{
|
||||||
|
Name: fmt.Sprintf("%s -> %s", t1, t2),
|
||||||
|
Notify: false,
|
||||||
|
}
|
||||||
|
graph.AddEdge(t1, t2, edge)
|
||||||
|
values = append(values, test{
|
||||||
|
name: "two resources and send/recv edge",
|
||||||
|
code: `
|
||||||
|
test "t1" {
|
||||||
|
int64ptr => 42,
|
||||||
|
}
|
||||||
|
test "t2" {
|
||||||
|
int64ptr => 13,
|
||||||
|
}
|
||||||
|
|
||||||
|
Test["t1"].foosend -> Test["t2"].barrecv # send/recv
|
||||||
|
`,
|
||||||
|
graph: graph,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
for index, test := range values { // run all the tests
|
for index, test := range values { // run all the tests
|
||||||
name, code, fail, exp := test.name, test.code, test.fail, test.graph
|
name, code, fail, exp := test.name, test.code, test.fail, test.graph
|
||||||
|
|||||||
@@ -134,6 +134,16 @@
|
|||||||
lval.str = yylex.Text()
|
lval.str = yylex.Text()
|
||||||
return IN
|
return IN
|
||||||
}
|
}
|
||||||
|
/\->/ {
|
||||||
|
yylex.pos(lval) // our pos
|
||||||
|
lval.str = yylex.Text()
|
||||||
|
return ARROW
|
||||||
|
}
|
||||||
|
/\./ {
|
||||||
|
yylex.pos(lval) // our pos
|
||||||
|
lval.str = yylex.Text()
|
||||||
|
return DOT
|
||||||
|
}
|
||||||
/bool/ {
|
/bool/ {
|
||||||
yylex.pos(lval) // our pos
|
yylex.pos(lval) // our pos
|
||||||
lval.str = yylex.Text()
|
lval.str = yylex.Text()
|
||||||
@@ -295,6 +305,13 @@
|
|||||||
lval.str = s[1:len(s)] // remove the leading $
|
lval.str = s[1:len(s)] // remove the leading $
|
||||||
return VAR_IDENTIFIER
|
return VAR_IDENTIFIER
|
||||||
}
|
}
|
||||||
|
/[A-Z][a-z0-9]*/
|
||||||
|
{
|
||||||
|
yylex.pos(lval) // our pos
|
||||||
|
s := yylex.Text()
|
||||||
|
lval.str = strings.ToLower(s) // uncapitalize it
|
||||||
|
return CAPITALIZED_IDENTIFIER
|
||||||
|
}
|
||||||
/[a-z][a-z0-9]*/
|
/[a-z][a-z0-9]*/
|
||||||
{
|
{
|
||||||
yylex.pos(lval) // our pos
|
yylex.pos(lval) // our pos
|
||||||
|
|||||||
@@ -752,6 +752,73 @@ func TestLexParse0(t *testing.T) {
|
|||||||
exp: exp,
|
exp: exp,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
exp := &StmtProg{
|
||||||
|
Prog: []interfaces.Stmt{
|
||||||
|
&StmtRes{
|
||||||
|
Kind: "test",
|
||||||
|
Name: &ExprStr{
|
||||||
|
V: "t1",
|
||||||
|
},
|
||||||
|
Fields: []*StmtResField{
|
||||||
|
{
|
||||||
|
Field: "int64ptr",
|
||||||
|
Value: &ExprInt{
|
||||||
|
V: 42,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&StmtRes{
|
||||||
|
Kind: "test",
|
||||||
|
Name: &ExprStr{
|
||||||
|
V: "t2",
|
||||||
|
},
|
||||||
|
Fields: []*StmtResField{
|
||||||
|
{
|
||||||
|
Field: "int64ptr",
|
||||||
|
Value: &ExprInt{
|
||||||
|
V: 13,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&StmtEdge{
|
||||||
|
EdgeHalfList: []*StmtEdgeHalf{
|
||||||
|
{
|
||||||
|
Kind: "test",
|
||||||
|
Name: &ExprStr{
|
||||||
|
V: "t1",
|
||||||
|
},
|
||||||
|
SendRecv: "foosend",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Kind: "test",
|
||||||
|
Name: &ExprStr{
|
||||||
|
V: "t2",
|
||||||
|
},
|
||||||
|
SendRecv: "barrecv",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
values = append(values, test{
|
||||||
|
name: "edge stmt",
|
||||||
|
code: `
|
||||||
|
test "t1" {
|
||||||
|
int64ptr => 42,
|
||||||
|
}
|
||||||
|
test "t2" {
|
||||||
|
int64ptr => 13,
|
||||||
|
}
|
||||||
|
|
||||||
|
Test["t1"].foosend -> Test["t2"].barrecv # send/recv
|
||||||
|
`,
|
||||||
|
fail: false,
|
||||||
|
exp: exp,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
for index, test := range values { // run all the tests
|
for index, test := range values { // run all the tests
|
||||||
name, code, fail, exp := test.name, test.code, test.fail, test.exp
|
name, code, fail, exp := test.name, test.code, test.fail, test.exp
|
||||||
@@ -789,8 +856,8 @@ func TestLexParse0(t *testing.T) {
|
|||||||
if !reflect.DeepEqual(ast, exp) {
|
if !reflect.DeepEqual(ast, exp) {
|
||||||
t.Errorf("test #%d: AST did not match expected", index)
|
t.Errorf("test #%d: AST did not match expected", index)
|
||||||
// TODO: consider making our own recursive print function
|
// TODO: consider making our own recursive print function
|
||||||
t.Logf("test #%d: actual: \n%s", index, spew.Sdump(ast))
|
t.Logf("test #%d: actual: \n\n%s\n", index, spew.Sdump(ast))
|
||||||
t.Logf("test #%d: expected: \n%s", index, spew.Sdump(exp))
|
t.Logf("test #%d: expected: \n\n%s", index, spew.Sdump(exp))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ func init() {
|
|||||||
|
|
||||||
resFields []*StmtResField
|
resFields []*StmtResField
|
||||||
resField *StmtResField
|
resField *StmtResField
|
||||||
|
|
||||||
|
edgeHalfList []*StmtEdgeHalf
|
||||||
|
edgeHalf *StmtEdgeHalf
|
||||||
}
|
}
|
||||||
|
|
||||||
%token OPEN_CURLY CLOSE_CURLY
|
%token OPEN_CURLY CLOSE_CURLY
|
||||||
@@ -74,10 +77,10 @@ func init() {
|
|||||||
%token STRING BOOL INTEGER FLOAT
|
%token STRING BOOL INTEGER FLOAT
|
||||||
%token EQUALS
|
%token EQUALS
|
||||||
%token COMMA COLON SEMICOLON
|
%token COMMA COLON SEMICOLON
|
||||||
%token ROCKET
|
%token ROCKET ARROW DOT
|
||||||
%token STR_IDENTIFIER BOOL_IDENTIFIER INT_IDENTIFIER FLOAT_IDENTIFIER
|
%token STR_IDENTIFIER BOOL_IDENTIFIER INT_IDENTIFIER FLOAT_IDENTIFIER
|
||||||
%token STRUCT_IDENTIFIER VARIANT_IDENTIFIER VAR_IDENTIFIER IDENTIFIER
|
%token STRUCT_IDENTIFIER VARIANT_IDENTIFIER VAR_IDENTIFIER IDENTIFIER
|
||||||
%token VAR_IDENTIFIER_HX
|
%token VAR_IDENTIFIER_HX CAPITALIZED_IDENTIFIER
|
||||||
%token COMMENT ERROR
|
%token COMMENT ERROR
|
||||||
|
|
||||||
// precedence table
|
// precedence table
|
||||||
@@ -158,6 +161,11 @@ stmt:
|
|||||||
posLast(yylex, yyDollar) // our pos
|
posLast(yylex, yyDollar) // our pos
|
||||||
$$.stmt = $1.stmt
|
$$.stmt = $1.stmt
|
||||||
}
|
}
|
||||||
|
| edge
|
||||||
|
{
|
||||||
|
posLast(yylex, yyDollar) // our pos
|
||||||
|
$$.stmt = $1.stmt
|
||||||
|
}
|
||||||
| IF expr OPEN_CURLY prog CLOSE_CURLY
|
| IF expr OPEN_CURLY prog CLOSE_CURLY
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
posLast(yylex, yyDollar) // our pos
|
||||||
@@ -685,6 +693,67 @@ resource_field:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
edge:
|
||||||
|
// TODO: we could technically prevent single edge_half pieces from being
|
||||||
|
// parsed, but it's probably more work than is necessary...
|
||||||
|
// Test["t1"] -> Test["t2"] -> Test["t3"] # chain or pair
|
||||||
|
edge_half_list
|
||||||
|
{
|
||||||
|
posLast(yylex, yyDollar) // our pos
|
||||||
|
$$.stmt = &StmtEdge{
|
||||||
|
EdgeHalfList: $1.edgeHalfList,
|
||||||
|
//Notify: false, // unused here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Test["t1"].foo_send -> Test["t2"].blah_recv # send/recv
|
||||||
|
| edge_half_sendrecv ARROW edge_half_sendrecv
|
||||||
|
{
|
||||||
|
posLast(yylex, yyDollar) // our pos
|
||||||
|
$$.stmt = &StmtEdge{
|
||||||
|
EdgeHalfList: []*StmtEdgeHalf{
|
||||||
|
$1.edgeHalf,
|
||||||
|
$3.edgeHalf,
|
||||||
|
},
|
||||||
|
//Notify: false, // unused here, it is implied (i think)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
edge_half_list:
|
||||||
|
edge_half
|
||||||
|
{
|
||||||
|
posLast(yylex, yyDollar) // our pos
|
||||||
|
$$.edgeHalfList = []*StmtEdgeHalf{$1.edgeHalf}
|
||||||
|
}
|
||||||
|
| edge_half_list ARROW edge_half
|
||||||
|
{
|
||||||
|
posLast(yylex, yyDollar) // our pos
|
||||||
|
$$.edgeHalfList = append($1.edgeHalfList, $3.edgeHalf)
|
||||||
|
}
|
||||||
|
;
|
||||||
|
edge_half:
|
||||||
|
// eg: Test["t1"]
|
||||||
|
CAPITALIZED_IDENTIFIER OPEN_BRACK expr CLOSE_BRACK
|
||||||
|
{
|
||||||
|
posLast(yylex, yyDollar) // our pos
|
||||||
|
$$.edgeHalf = &StmtEdgeHalf{
|
||||||
|
Kind: $1.str,
|
||||||
|
Name: $3.expr,
|
||||||
|
//SendRecv: "", // unused
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
edge_half_sendrecv:
|
||||||
|
// eg: Test["t1"].foo_send
|
||||||
|
CAPITALIZED_IDENTIFIER OPEN_BRACK expr CLOSE_BRACK DOT IDENTIFIER
|
||||||
|
{
|
||||||
|
posLast(yylex, yyDollar) // our pos
|
||||||
|
$$.edgeHalf = &StmtEdgeHalf{
|
||||||
|
Kind: $1.str,
|
||||||
|
Name: $3.expr,
|
||||||
|
SendRecv: $6.str,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
type:
|
type:
|
||||||
BOOL_IDENTIFIER
|
BOOL_IDENTIFIER
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -836,6 +836,7 @@ func (obj *StmtProg) Graph() (*pgraph.Graph, error) {
|
|||||||
// called by this Output function if they are needed to produce the output.
|
// called by this Output function if they are needed to produce the output.
|
||||||
func (obj *StmtProg) Output() (*interfaces.Output, error) {
|
func (obj *StmtProg) Output() (*interfaces.Output, error) {
|
||||||
resources := []resources.Res{}
|
resources := []resources.Res{}
|
||||||
|
edges := []*interfaces.Edge{}
|
||||||
|
|
||||||
for _, stmt := range obj.Prog {
|
for _, stmt := range obj.Prog {
|
||||||
output, err := stmt.Output()
|
output, err := stmt.Output()
|
||||||
@@ -844,13 +845,13 @@ func (obj *StmtProg) Output() (*interfaces.Output, error) {
|
|||||||
}
|
}
|
||||||
if output != nil {
|
if output != nil {
|
||||||
resources = append(resources, output.Resources...)
|
resources = append(resources, output.Resources...)
|
||||||
//edges = append(edges, output.Edges)
|
edges = append(edges, output.Edges...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &interfaces.Output{
|
return &interfaces.Output{
|
||||||
Resources: resources,
|
Resources: resources,
|
||||||
//Edges: edges,
|
Edges: edges,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,11 @@ func (obj *PrintRes) Watch() error {
|
|||||||
// CheckApply method for Print resource. Does nothing, returns happy!
|
// CheckApply method for Print resource. Does nothing, returns happy!
|
||||||
func (obj *PrintRes) CheckApply(apply bool) (checkOK bool, err error) {
|
func (obj *PrintRes) CheckApply(apply bool) (checkOK bool, err error) {
|
||||||
log.Printf("%s: CheckApply: %t", obj, apply)
|
log.Printf("%s: CheckApply: %t", obj, apply)
|
||||||
|
if val, exists := obj.Recv["Msg"]; exists && val.Changed {
|
||||||
|
// if we received on Msg, and it changed, log message
|
||||||
|
log.Printf("CheckApply: Received `Msg` of: %s", obj.Msg)
|
||||||
|
}
|
||||||
|
|
||||||
if obj.Refresh() {
|
if obj.Refresh() {
|
||||||
log.Printf("%s: Received a notification!", obj)
|
log.Printf("%s: Received a notification!", obj)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user