Add exec type and fix up a few other things

* Add exec type
* Switch erroneous use of fmt to log instead
* Check for edge existence for safety before using
* Avoid recalling etcd channel maker
* Clean up logging output
This commit is contained in:
James Shubin
2016-01-08 04:08:08 -05:00
parent 45ff3b6aa4
commit ea7fd76f93
11 changed files with 492 additions and 44 deletions

View File

@@ -47,6 +47,7 @@ type graphConfig struct {
Noop []NoopType `yaml:"noop"`
File []FileType `yaml:"file"`
Service []ServiceType `yaml:"service"`
Exec []ExecType `yaml:"exec"`
} `yaml:"types"`
Collector []collectorTypeConfig `yaml:"collect"`
Edges []edgeConfig `yaml:"edges"`
@@ -79,18 +80,31 @@ func ParseConfigFromFile(filename string) *graphConfig {
return &config
}
func UpdateGraphFromConfig(config *graphConfig, hostname string, g *Graph, etcdO *EtcdWObject) {
// XXX: we need to fix this function so that it either fails without modifying
// the graph, passes successfully and modifies it, or basically panics i guess
// this way an invalid compilation can leave the old graph running, and we we
// don't modify a partial graph. so we really need to validate, and then perform
// whatever actions are necessary
// finding some way to do this on a copy of the graph, and then do a graph diff
// and merge the new data into the old graph would be more appropriate, in
// particular if we can ensure the graph merge can't fail. As for the putting
// of stuff into etcd, we should probably store the operations to complete in
// the new graph, and keep retrying until it succeeds, thus blocking any new
// etcd operations until that time.
func UpdateGraphFromConfig(config *graphConfig, hostname string, g *Graph, etcdO *EtcdWObject) bool {
var NoopMap map[string]*Vertex = make(map[string]*Vertex)
var FileMap map[string]*Vertex = make(map[string]*Vertex)
var ServiceMap map[string]*Vertex = make(map[string]*Vertex)
var ExecMap map[string]*Vertex = make(map[string]*Vertex)
var lookup map[string]map[string]*Vertex = make(map[string]map[string]*Vertex)
lookup["noop"] = NoopMap
lookup["file"] = FileMap
lookup["service"] = ServiceMap
lookup["exec"] = ExecMap
//fmt.Printf("%+v\n", config) // debug
//log.Printf("%+v", config) // debug
g.SetName(config.Graph) // set graph name
@@ -140,6 +154,17 @@ func UpdateGraphFromConfig(config *graphConfig, hostname string, g *Graph, etcdO
keep = append(keep, v) // append
}
for _, t := range config.Types.Exec {
obj := NewExecType(t.Name, t.Cmd, t.Shell, t.Timeout, t.WatchCmd, t.WatchShell, t.IfCmd, t.IfShell, t.PollInt, t.State)
v := g.GetVertexMatch(obj)
if v == nil { // no match found
v = NewVertex(obj)
g.AddVertex(v) // call standalone in case not part of an edge
}
ExecMap[obj.Name] = v // used for constructing edges
keep = append(keep, v) // append
}
// lookup from etcd graph
// do all the graph look ups in one single step, so that if the etcd
// database changes, we don't have a partial state of affairs...
@@ -186,6 +211,19 @@ func UpdateGraphFromConfig(config *graphConfig, hostname string, g *Graph, etcdO
}
for _, e := range config.Edges {
if _, ok := lookup[e.From.Type]; !ok {
return false
}
if _, ok := lookup[e.To.Type]; !ok {
return false
}
if _, ok := lookup[e.From.Type][e.From.Name]; !ok {
return false
}
if _, ok := lookup[e.To.Type][e.To.Name]; !ok {
return false
}
g.AddEdge(lookup[e.From.Type][e.From.Name], lookup[e.To.Type][e.To.Name], NewEdge(e.Name))
}
return true
}

View File

@@ -51,7 +51,7 @@ func ConfigWatch(file string) chan bool {
if current == "" { // the empty string top is the root dir ("/")
current = "/"
}
log.Printf("Watching: %v\n", current) // attempting to watch...
log.Printf("Watching: %v", current) // attempting to watch...
// initialize in the loop so that we can reset on rm-ed handles
err = watcher.Add(current)
@@ -61,10 +61,10 @@ func ConfigWatch(file string) chan bool {
} else if err == syscall.ENOSPC {
// XXX: occasionally: no space left on device,
// XXX: probably due to lack of inotify watches
log.Printf("Lack of watches for config(%v) error: %+v\n", file, err.Error) // 0x408da0
log.Printf("Lack of watches for config(%v) error: %+v", file, err.Error) // 0x408da0
log.Fatal(err)
} else {
log.Printf("Unknown config(%v) error:\n", file)
log.Printf("Unknown config(%v) error:", file)
log.Fatal(err)
}
index = int(math.Max(1, float64(index)))
@@ -92,7 +92,7 @@ func ConfigWatch(file string) chan bool {
// event.Name: /tmp/mgmt/f3 and current: /tmp/mgmt/f2
continue
}
//log.Printf("The delta depth is: %v\n", delta_depth)
//log.Printf("The delta depth is: %v", delta_depth)
// if we have what we wanted, awesome, send an event...
if event.Name == safename {

View File

@@ -127,12 +127,13 @@ func (etcdO *EtcdWObject) EtcdWatch() chan etcdMsg {
tmult := 2 // multiplier for exponential delay
tmax := 16000 // max delay
watcher := kapi.Watcher("/exported/", &etcd.WatcherOptions{Recursive: true})
etcdch := etcdO.EtcdChannelWatch(watcher, etcd_context.Background())
for {
log.Printf("Etcd: Watching...")
var resp *etcd.Response = nil
var err error = nil
select {
case out := <-etcdO.EtcdChannelWatch(watcher, etcd_context.Background()):
case out := <-etcdch:
etcdO.SetState(etcdNil)
resp, err = out.resp, out.err

17
examples/graph7.yaml Normal file
View File

@@ -0,0 +1,17 @@
---
graph: mygraph
types:
noop:
- name: noop1
exec:
- name: exec1
cmd: sleep 10s
shell: ''
timeout: 0
watchcmd: ''
watchshell: ''
ifcmd: ''
ifshell: ''
pollint: 0
state: present
edges:

61
examples/graph8.yaml Normal file
View File

@@ -0,0 +1,61 @@
---
graph: mygraph
types:
noop:
- name: noop1
exec:
- name: exec1
cmd: sleep 10s
shell: ''
timeout: 0
watchcmd: ''
watchshell: ''
ifcmd: ''
ifshell: ''
pollint: 0
state: present
- name: exec2
cmd: sleep 10s
shell: ''
timeout: 0
watchcmd: ''
watchshell: ''
ifcmd: ''
ifshell: ''
pollint: 0
state: present
- name: exec3
cmd: sleep 10s
shell: ''
timeout: 0
watchcmd: ''
watchshell: ''
ifcmd: ''
ifshell: ''
pollint: 0
state: present
- name: exec4
cmd: sleep 10s
shell: ''
timeout: 0
watchcmd: ''
watchshell: ''
ifcmd: ''
ifshell: ''
pollint: 0
state: present
edges:
- name: e1
from:
type: exec
name: exec1
to:
type: exec
name: exec2
- name: e2
from:
type: exec
name: exec2
to:
type: exec
name: exec3

333
exec.go Normal file
View File

@@ -0,0 +1,333 @@
// Mgmt
// Copyright (C) 2013-2016+ James Shubin and the project contributors
// Written by James Shubin <james@shubin.ca> and the project contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"bufio"
"bytes"
"log"
"os/exec"
"strings"
)
type ExecType struct {
BaseType `yaml:",inline"`
State string `yaml:"state"` // state: exists/present?, absent, (undefined?)
Cmd string `yaml:"cmd"` // the command to run
Shell string `yaml:"shell"` // the (optional) shell to use to run the cmd
Timeout int `yaml:"timeout"` // the cmd timeout in seconds
WatchCmd string `yaml:"watchcmd"` // the watch command to run
WatchShell string `yaml:"watchshell"` // the (optional) shell to use to run the watch cmd
IfCmd string `yaml:"ifcmd"` // the if command to run
IfShell string `yaml:"ifshell"` // the (optional) shell to use to run the if cmd
PollInt int `yaml:"pollint"` // the poll interval for the ifcmd
isStateOK bool // whether the state is okay based on events or not
}
func NewExecType(name, cmd, shell string, timeout int, watchcmd, watchshell, ifcmd, ifshell string, pollint int, state string) *ExecType {
// FIXME if path = nil, path = name ...
return &ExecType{
BaseType: BaseType{
Name: name,
events: make(chan Event),
vertex: nil,
},
Cmd: cmd,
Shell: shell,
Timeout: timeout,
WatchCmd: watchcmd,
WatchShell: watchshell,
IfCmd: ifcmd,
IfShell: ifshell,
PollInt: pollint,
State: state,
}
}
func (obj *ExecType) GetType() string {
return "Exec"
}
// validate if the params passed in are valid data
// FIXME: where should this get called ?
func (obj *ExecType) Validate() bool {
if obj.Cmd == "" { // this is the only thing that is really required
return false
}
// if we have a watch command, then we don't poll with the if command!
if obj.WatchCmd != "" && obj.PollInt > 0 {
return false
}
return true
}
// wraps the scanner output in a channel
func (obj *ExecType) BufioChanScanner(scanner *bufio.Scanner) (chan string, chan error) {
ch, errch := make(chan string), make(chan error)
go func() {
for scanner.Scan() {
ch <- scanner.Text() // blocks here ?
if e := scanner.Err(); e != nil {
errch <- e // send any misc errors we encounter
//break // TODO ?
}
}
close(ch)
errch <- scanner.Err() // eof or some err
close(errch)
}()
return ch, errch
}
// Exec watcher
func (obj *ExecType) Watch() {
if obj.IsWatching() {
return
}
obj.SetWatching(true)
defer obj.SetWatching(false)
var send = false // send event?
bufioch, errch := make(chan string), make(chan error)
//vertex := obj.GetVertex() // stored with SetVertex
if obj.WatchCmd != "" {
var cmdName string
var cmdArgs []string
if obj.WatchShell == "" {
// call without a shell
// FIXME: are there still whitespace splitting issues?
split := strings.Fields(obj.WatchCmd)
cmdName = split[0]
//d, _ := os.Getwd() // TODO: how does this ever error ?
//cmdName = path.Join(d, cmdName)
cmdArgs = split[1:len(split)]
} else {
cmdName = obj.Shell // usually bash, or sh
cmdArgs = []string{"-c", obj.WatchCmd}
}
cmd := exec.Command(cmdName, cmdArgs...)
//cmd.Dir = "" // look for program in pwd ?
cmdReader, err := cmd.StdoutPipe()
if err != nil {
log.Printf("%v[%v]: Error creating StdoutPipe for Cmd: %v", obj.GetType(), obj.GetName(), err)
log.Fatal(err) // XXX: how should we handle errors?
}
scanner := bufio.NewScanner(cmdReader)
defer cmd.Wait() // XXX: is this necessary?
defer cmd.Process.Kill() // TODO: is this necessary?
if err := cmd.Start(); err != nil {
log.Printf("%v[%v]: Error starting Cmd: %v", obj.GetType(), obj.GetName(), err)
log.Fatal(err) // XXX: how should we handle errors?
}
bufioch, errch = obj.BufioChanScanner(scanner)
}
for {
select {
case text := <-bufioch:
obj.SetState(typeNil)
// each time we get a line of output, we loop!
log.Printf("%v[%v]: Watch output: %s", obj.GetType(), obj.GetName(), text)
if text != "" {
send = true
}
case err := <-errch:
obj.SetState(typeNil) // XXX ?
if err == nil { // EOF
// FIXME: add an "if watch command ends/crashes"
// restart or generate error option
log.Printf("%v[%v]: Reached EOF", obj.GetType(), obj.GetName())
return
}
log.Printf("%v[%v]: Error reading input?: %v", obj.GetType(), obj.GetName(), err)
log.Fatal(err)
// XXX: how should we handle errors?
case event := <-obj.events:
obj.SetState(typeNil)
if ok := obj.ReadEvent(&event); !ok {
return // exit
}
send = true
case _ = <-TimeAfterOrBlock(obj.ctimeout):
obj.SetState(typeConvergedTimeout)
obj.converged <- true
continue
}
// do all our event sending all together to avoid duplicate msgs
if send {
send = false
obj.isStateOK = false // something made state dirty
obj.Process(obj) // XXX: rename this function
}
}
}
// TODO: expand the IfCmd to be a list of commands
func (obj *ExecType) StateOK() bool {
// if there is a watch command, but no if command, run based on state
if b := obj.isStateOK; obj.WatchCmd != "" && obj.IfCmd == "" {
obj.isStateOK = true // reset
//if !obj.isStateOK { obj.isStateOK = true; return false }
return b
// if there is no watcher, but there is an onlyif check, run it to see
} else if obj.IfCmd != "" { // && obj.WatchCmd == ""
// there is a watcher, but there is also an if command
//} else if obj.IfCmd != "" && obj.WatchCmd != "" {
if obj.PollInt > 0 { // && obj.WatchCmd == ""
// XXX have the Watch() command output onlyif poll events...
// XXX we can optimize by saving those results for returning here
// return XXX
}
var cmdName string
var cmdArgs []string
if obj.IfShell == "" {
// call without a shell
// FIXME: are there still whitespace splitting issues?
split := strings.Fields(obj.IfCmd)
cmdName = split[0]
//d, _ := os.Getwd() // TODO: how does this ever error ?
//cmdName = path.Join(d, cmdName)
cmdArgs = split[1:len(split)]
} else {
cmdName = obj.IfShell // usually bash, or sh
cmdArgs = []string{"-c", obj.IfCmd}
}
err := exec.Command(cmdName, cmdArgs...).Run()
if err != nil {
// TODO: check exit value
return true // don't run
}
return false // just run
// if there is no watcher and no onlyif check, assume we should run
} else { // if obj.WatchCmd == "" && obj.IfCmd == "" {
return false // just run
}
}
func (obj *ExecType) Apply() bool {
log.Printf("%v[%v]: Apply", obj.GetType(), obj.GetName())
var cmdName string
var cmdArgs []string
if obj.Shell == "" {
// call without a shell
// FIXME: are there still whitespace splitting issues?
// TODO: we could make the split character user selectable...!
split := strings.Fields(obj.Cmd)
cmdName = split[0]
//d, _ := os.Getwd() // TODO: how does this ever error ?
//cmdName = path.Join(d, cmdName)
cmdArgs = split[1:len(split)]
} else {
cmdName = obj.Shell // usually bash, or sh
cmdArgs = []string{"-c", obj.Cmd}
}
cmd := exec.Command(cmdName, cmdArgs...)
//cmd.Dir = "" // look for program in pwd ?
var out bytes.Buffer
cmd.Stdout = &out
if err := cmd.Start(); err != nil {
log.Printf("%v[%v]: Error starting Cmd: %v", obj.GetType(), obj.GetName(), err)
return false
}
timeout := obj.Timeout
if timeout == 0 { // zero timeout means no timer, so disable it
timeout = -1
}
done := make(chan error)
go func() { done <- cmd.Wait() }()
select {
case err := <-done:
if err != nil {
log.Printf("%v[%v]: Error waiting for Cmd: %v", obj.GetType(), obj.GetName(), err)
return false
}
case <-TimeAfterOrBlock(timeout):
log.Printf("%v[%v]: Timeout waiting for Cmd", obj.GetType(), obj.GetName())
//cmd.Process.Kill() // TODO: is this necessary?
return false
}
// TODO: if we printed the stdout while the command is running, this
// would be nice, but it would require terminal log output that doesn't
// interleave all the parallel parts which would mix it all up...
if s := out.String(); s == "" {
log.Printf("Exec[%v]: Command output is empty!", obj.Name)
} else {
log.Printf("Exec[%v]: Command output is:", obj.Name)
log.Printf(out.String())
}
// XXX: return based on exit value!!
return true
}
func (obj *ExecType) Compare(typ Type) bool {
switch typ.(type) {
case *ExecType:
typ := typ.(*ExecType)
if obj.Name != typ.Name {
return false
}
if obj.Cmd != typ.Cmd {
return false
}
if obj.Shell != typ.Shell {
return false
}
if obj.Timeout != typ.Timeout {
return false
}
if obj.WatchCmd != typ.WatchCmd {
return false
}
if obj.WatchShell != typ.WatchShell {
return false
}
if obj.IfCmd != typ.IfCmd {
return false
}
if obj.PollInt != typ.PollInt {
return false
}
if obj.State != typ.State {
return false
}
default:
return false
}
return true
}

19
file.go
View File

@@ -20,7 +20,6 @@ package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"gopkg.in/fsnotify.v1"
//"github.com/go-fsnotify/fsnotify" // git master of "gopkg.in/fsnotify.v1"
"io"
@@ -106,7 +105,7 @@ func (obj *FileType) Watch() {
//var recursive bool = false
//var isdir = (obj.GetPath()[len(obj.GetPath())-1:] == "/") // dirs have trailing slashes
//fmt.Printf("IsDirectory: %v\n", isdir)
//log.Printf("IsDirectory: %v", isdir)
//vertex := obj.GetVertex() // stored with SetVertex
var safename = path.Clean(obj.GetPath()) // no trailing slash
@@ -127,7 +126,7 @@ func (obj *FileType) Watch() {
if current == "" { // the empty string top is the root dir ("/")
current = "/"
}
log.Printf("Watching: %v\n", current) // attempting to watch...
log.Printf("Watching: %v", current) // attempting to watch...
// initialize in the loop so that we can reset on rm-ed handles
err = watcher.Add(current)
@@ -137,10 +136,10 @@ func (obj *FileType) Watch() {
} else if err == syscall.ENOSPC {
// XXX: occasionally: no space left on device,
// XXX: probably due to lack of inotify watches
log.Printf("Lack of watches for file[%v] error: %+v\n", obj.Name, err.Error) // 0x408da0
log.Printf("Lack of watches for file[%v] error: %+v", obj.Name, err.Error) // 0x408da0
log.Fatal(err)
} else {
log.Printf("Unknown file[%v] error:\n", obj.Name)
log.Printf("Unknown file[%v] error:", obj.Name)
log.Fatal(err)
}
index = int(math.Max(1, float64(index)))
@@ -169,7 +168,7 @@ func (obj *FileType) Watch() {
// event.Name: /tmp/mgmt/f3 and current: /tmp/mgmt/f2
continue
}
//log.Printf("The delta depth is: %v\n", delta_depth)
//log.Printf("The delta depth is: %v", delta_depth)
// if we have what we wanted, awesome, send an event...
if event.Name == safename {
@@ -294,7 +293,7 @@ func (obj *FileType) StateOKFile() bool {
}
sha256sum := hex.EncodeToString(hash.Sum(nil))
//fmt.Printf("sha256sum: %v\n", sha256sum)
//log.Printf("sha256sum: %v", sha256sum)
if obj.HashSHA256fromContent() == sha256sum {
return true
@@ -314,7 +313,7 @@ func (obj *FileType) StateOKDir() bool {
}
func (obj *FileType) Apply() bool {
fmt.Printf("Apply->File[%v]\n", obj.Name)
log.Printf("%v[%v]: Apply", obj.GetType(), obj.GetName())
if PathIsDir(obj.GetPath()) {
return obj.ApplyDir()
@@ -330,7 +329,7 @@ func (obj *FileType) ApplyFile() bool {
}
if obj.State == "absent" {
log.Printf("About to remove: %v\n", obj.GetPath())
log.Printf("About to remove: %v", obj.GetPath())
err := os.Remove(obj.GetPath())
if err != nil {
return false
@@ -338,7 +337,7 @@ func (obj *FileType) ApplyFile() bool {
return true
}
//fmt.Println("writing: " + filename)
//log.Println("writing: " + filename)
f, err := os.Create(obj.GetPath())
if err != nil {
log.Println("error:", err)

20
main.go
View File

@@ -18,7 +18,6 @@
package main
import (
"fmt"
"github.com/codegangsta/cli"
"log"
"os"
@@ -49,7 +48,6 @@ func waitForSignal(exit chan bool) {
select {
case e := <-signals: // any signal will do
if e == os.Interrupt {
fmt.Println() // put ^C char from terminal on its own line
log.Println("Interrupted by ^C")
} else {
log.Println("Interrupted by signal")
@@ -64,8 +62,8 @@ func run(c *cli.Context) {
var wg sync.WaitGroup
exit := make(chan bool) // exit signal
converged := make(chan bool) // converged signal
log.Printf("This is: %v, version: %v\n", program, version)
log.Printf("Start: %v\n", start)
log.Printf("This is: %v, version: %v", program, version)
log.Printf("Main: Start: %v", start)
G := NewGraph("Graph") // give graph a default name
// exit after `max-runtime` seconds for no reason at all...
@@ -102,7 +100,7 @@ func run(c *cli.Context) {
go func() { startchan <- struct{}{} }()
file := c.String("file")
configchan := ConfigWatch(file)
log.Printf("Starting etcd...\n")
log.Printf("Etcd: Starting...")
etcdchan := etcdO.EtcdWatch()
first := true // first loop or not
for {
@@ -144,8 +142,10 @@ func run(c *cli.Context) {
// build the graph from a config file
// build the graph on events (eg: from etcd)
UpdateGraphFromConfig(config, hostname, G, etcdO)
log.Printf("Graph: %v\n", G) // show graph
if !UpdateGraphFromConfig(config, hostname, G, etcdO) {
log.Fatal("Config: We borked the graph.") // XXX
}
log.Printf("Graph: %v", G) // show graph
err := G.ExecGraphviz(c.String("graphviz-filter"), c.String("graphviz"))
if err != nil {
log.Printf("Graphviz: %v", err)
@@ -200,7 +200,7 @@ func run(c *cli.Context) {
}()
}
log.Println("Running...")
log.Println("Main: Running...")
waitForSignal(exit) // pass in exit channel to watch
@@ -208,9 +208,9 @@ func run(c *cli.Context) {
if DEBUG {
for i := range G.GetVerticesChan() {
fmt.Printf("Vertex: %v\n", i)
log.Printf("Vertex: %v", i)
}
fmt.Printf("Graph: %v\n", G)
log.Printf("Graph: %v", G)
}
wg.Wait() // wait for primary go routines to exit

View File

@@ -373,7 +373,7 @@ func (g *Graph) FilterGraph(name string, vertices []*Vertex) *Graph {
for k1, x := range g.Adjacency {
for k2, e := range x {
//fmt.Printf("Filter: %v -> %v # %v\n", k1.Name, k2.Name, e.Name)
//log.Printf("Filter: %v -> %v # %v", k1.Name, k2.Name, e.Name)
if Contains(vertices, k1) || Contains(vertices, k2) {
newgraph.AddEdge(k1, k2, e)
}
@@ -548,7 +548,7 @@ func (g *Graph) Start(wg *sync.WaitGroup) { // start or continue
go func(vv *Vertex) {
defer wg.Done()
vv.Type.Watch()
log.Printf("Finish: %v", vv.GetName())
log.Printf("%v[%v]: Exited", vv.GetType(), vv.GetName())
}(v)
}

View File

@@ -98,14 +98,14 @@ func (obj *ServiceType) Watch() {
// firstly, does service even exist or not?
loadstate, err := conn.GetUnitProperty(service, "LoadState")
if err != nil {
log.Printf("Failed to get property: %v\n", err)
log.Printf("Failed to get property: %v", err)
invalid = true
}
if !invalid {
var notFound = (loadstate.Value == dbus.MakeVariant("not-found"))
if notFound { // XXX: in the loop we'll handle changes better...
log.Printf("Failed to find service: %v\n", service)
log.Printf("Failed to find service: %v", service)
invalid = true // XXX ?
}
}
@@ -115,7 +115,7 @@ func (obj *ServiceType) Watch() {
}
if invalid {
log.Printf("Waiting for: %v\n", service) // waiting for service to appear...
log.Printf("Waiting for: %v", service) // waiting for service to appear...
if activeSet {
activeSet = false
set.Remove(service) // no return value should ever occur
@@ -125,7 +125,7 @@ func (obj *ServiceType) Watch() {
case _ = <-buschan: // XXX wait for new units event to unstick
obj.SetState(typeNil)
// loop so that we can see the changed invalid signal
log.Printf("Service[%v]->DaemonReload()\n", service)
log.Printf("Service[%v]->DaemonReload()", service)
case event := <-obj.events:
obj.SetState(typeNil)
@@ -144,24 +144,24 @@ func (obj *ServiceType) Watch() {
set.Add(service) // no return value should ever occur
}
log.Printf("Watching: %v\n", service) // attempting to watch...
log.Printf("Watching: %v", service) // attempting to watch...
select {
case event := <-subChannel:
log.Printf("Service event: %+v\n", event)
log.Printf("Service event: %+v", event)
// NOTE: the value returned is a map for some reason...
if event[service] != nil {
// event[service].ActiveState is not nil
if event[service].ActiveState == "active" {
log.Printf("Service[%v]->Started()\n", service)
log.Printf("Service[%v]->Started()", service)
} else if event[service].ActiveState == "inactive" {
log.Printf("Service[%v]->Stopped!()\n", service)
log.Printf("Service[%v]->Stopped!()", service)
} else {
log.Fatal("Unknown service state: ", event[service].ActiveState)
}
} else {
// service stopped (and ActiveState is nil...)
log.Printf("Service[%v]->Stopped\n", service)
log.Printf("Service[%v]->Stopped", service)
}
send = true
@@ -204,14 +204,14 @@ func (obj *ServiceType) StateOK() bool {
loadstate, err := conn.GetUnitProperty(service, "LoadState")
if err != nil {
log.Printf("Failed to get load state: %v\n", err)
log.Printf("Failed to get load state: %v", err)
return false
}
// NOTE: we have to compare variants with other variants, they are really strings...
var notFound = (loadstate.Value == dbus.MakeVariant("not-found"))
if notFound {
log.Printf("Failed to find service: %v\n", service)
log.Printf("Failed to find service: %v", service)
return false
}
@@ -241,7 +241,7 @@ func (obj *ServiceType) StateOK() bool {
}
func (obj *ServiceType) Apply() bool {
fmt.Printf("Apply->Service[%v]\n", obj.Name)
log.Printf("%v[%v]: Apply", obj.GetType(), obj.GetName())
if !util.IsRunningSystemd() {
log.Fatal("Systemd is not running.")
@@ -264,7 +264,7 @@ func (obj *ServiceType) Apply() bool {
err = nil
}
if err != nil {
log.Printf("Unable to change startup status: %v\n", err)
log.Printf("Unable to change startup status: %v", err)
return false
}

View File

@@ -18,7 +18,6 @@
package main
import (
"fmt"
"log"
"time"
)
@@ -286,7 +285,7 @@ func (obj *NoopType) StateOK() bool {
}
func (obj *NoopType) Apply() bool {
fmt.Printf("Apply->Noop[%v]\n", obj.Name)
log.Printf("%v[%v]: Apply", obj.GetType(), obj.GetName())
return true
}