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:
42
config.go
42
config.go
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
3
etcd.go
3
etcd.go
@@ -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
17
examples/graph7.yaml
Normal 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
61
examples/graph8.yaml
Normal 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
333
exec.go
Normal 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
19
file.go
@@ -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
20
main.go
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
26
service.go
26
service.go
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user