From 118520448534bf184d8519ea61310defcf515523 Mon Sep 17 00:00:00 2001 From: Nico Grashoff Date: Sun, 4 Apr 2021 17:01:20 +0200 Subject: [PATCH] Refactor API --- ftl | 6 ++- ftl.go | 35 +++++++++++++- log.go | 72 ----------------------------- log/log.go | 92 ++++++++++++++++++++++++++++++++++++ ops.go => ops/ops.go | 108 +++++++++++++------------------------------ plans/docker_plan.go | 31 +++++-------- 6 files changed, 173 insertions(+), 171 deletions(-) delete mode 100644 log.go create mode 100644 log/log.go rename ops.go => ops/ops.go (50%) diff --git a/ftl b/ftl index 8b4a9fd..de39d20 100755 --- a/ftl +++ b/ftl @@ -1,9 +1,11 @@ #!/usr/bin/env sh set -x -e -u -ssh $1 mkdir -p /root/go/src/github.com/ftlops/ftl +ssh $1 rm -rf /root/go/src/github.com/ftlops/ftl/ +ssh $1 mkdir -p /root/go/src/github.com/ftlops/ftl/{log,ops} scp *.go $1:/root/go/src/github.com/ftlops/ftl/ - +scp log/*.go $1:/root/go/src/github.com/ftlops/ftl/log +scp ops/*.go $1:/root/go/src/github.com/ftlops/ftl/ops date=$(date +%s) dst=/var/log/ftl/$date/plans diff --git a/ftl.go b/ftl.go index 67eaa4d..1b52ed4 100644 --- a/ftl.go +++ b/ftl.go @@ -1,7 +1,38 @@ package ftl -var DefaultOps = Ops{&LogLog{}} +import ( + "fmt" + + "github.com/ftlops/ftl/log" + "github.com/ftlops/ftl/ops" +) + +func init() { + ops.Logger = &log.DefaultLogger +} + +type State int + +const ( + StateUnchanged State = iota + StateChanged +) + +func (s State) String() string { + switch s { + case StateUnchanged: + return "unchanged" + case StateChanged: + return "changed" + default: + return fmt.Sprintf("unknown (%d)", s) + } +} + +type StepFunc func() State func Step(name string, f StepFunc) { - DefaultOps.Step(name, f) + log.BeginStep(name) + state := f() + log.EndStep(state.String()) } diff --git a/log.go b/log.go deleted file mode 100644 index 3cbf58e..0000000 --- a/log.go +++ /dev/null @@ -1,72 +0,0 @@ -package ftl - -import ( - "fmt" - "log" - "strings" -) - -type LogLog struct { - stack []string - lastFullStack string -} - -func (ll *LogLog) BeginStep(name string) { - ll.stack = append(ll.stack, name) - - ll.printf("(((", []interface{}{}) -} - -func (ll *LogLog) EndStep(st State) { - ll.printf(")))", []interface{}{"->", st}) - ll.stack = ll.stack[:len(ll.stack)-1] -} - -func (ll *LogLog) Error(v ...interface{}) { - ll.printf("ERR", v) -} - -func (ll *LogLog) Info(v ...interface{}) { - ll.printf("INF", v) -} - -func (ll *LogLog) Debug(v ...interface{}) { - ll.printf("DBG", v) -} - -func (ll *LogLog) Trace(v ...interface{}) { - ll.printf("TRC", v) -} - -func (ll *LogLog) printf(lvl string, v []interface{}) { - fullStack := ll.fmtStack() - if ll.lastFullStack != fullStack { - log.Println(ll.fmt(lvl, fullStack, v)...) - ll.lastFullStack = fullStack - } else { - shortStack := "[" - prefix := "... > " - basename := ll.stack[len(ll.stack)-1] - padLeft := len(fullStack) - len(basename) - len(prefix) - 2 - for i := 0; i < padLeft; i++ { - shortStack += " " - } - if padLeft > 0 { - shortStack += prefix - } - shortStack += basename + "]" - log.Println(ll.fmt(lvl, shortStack, v)...) - } -} - -func (ll *LogLog) fmt(lvl, stack string, v []interface{}) []interface{} { - var vs []interface{} - vs = append(vs, lvl) - vs = append(vs, stack) - vs = append(vs, v...) - return vs -} - -func (ll *LogLog) fmtStack() string { - return fmt.Sprintf("[%s]", strings.Join(ll.stack, " > ")) -} diff --git a/log/log.go b/log/log.go new file mode 100644 index 0000000..3850498 --- /dev/null +++ b/log/log.go @@ -0,0 +1,92 @@ +package log + +import ( + "fmt" + "log" + "os" + "runtime/debug" + "strings" +) + +var DefaultLogger = Logger{} + +func BeginStep(name string) { DefaultLogger.BeginStep(name) } +func EndStep(result string) { DefaultLogger.EndStep(result) } +func Fatal(v ...interface{}) { DefaultLogger.Fatal(v...) } +func Error(v ...interface{}) { DefaultLogger.Error(v...) } +func Info(v ...interface{}) { DefaultLogger.Info(v...) } +func Debug(v ...interface{}) { DefaultLogger.Debug(v...) } +func Trace(v ...interface{}) { DefaultLogger.Trace(v...) } + +type Logger struct { + stack []string + lastFul string +} + +func (l *Logger) BeginStep(name string) { + l.stack = append(l.stack, name) + + l.printf("(((", []interface{}{}) +} + +func (l *Logger) EndStep(result string) { + l.printf(")))", []interface{}{"->", result}) + l.stack = l.stack[:len(l.stack)-1] +} + +func (l *Logger) Fatal(v ...interface{}) { + l.printf("FTL", v) + debug.PrintStack() + os.Exit(1) +} + +func (l *Logger) Error(v ...interface{}) { + l.printf("ERR", v) +} + +func (l *Logger) Info(v ...interface{}) { + l.printf("INF", v) +} + +func (l *Logger) Debug(v ...interface{}) { + l.printf("DBG", v) +} + +func (l *Logger) Trace(v ...interface{}) { + l.printf("TRC", v) +} + +func (l *Logger) printf(lvl string, v []interface{}) { + full := l.fmtStack() + if l.lastFul != full { + log.Println(l.fmt(lvl, full, v)...) + l.lastFul = full + } else { + shortStack := "[" + prefix := "... > " + basename := l.stack[len(l.stack)-1] + padLeft := len(full) - len(basename) - len(prefix) - 2 + for i := 0; i < padLeft; i++ { + shortStack += " " + } + if padLeft > 0 { + shortStack += prefix + } + shortStack += basename + "]" + log.Println(l.fmt(lvl, shortStack, v)...) + } +} + +func (l *Logger) fmt(lvl, stack string, v []interface{}) []interface{} { + var vs []interface{} + vs = append(vs, lvl) + vs = append(vs, stack) + for _, x := range v { + vs = append(vs, x) + } + return vs +} + +func (l *Logger) fmtStack() string { + return fmt.Sprintf("[%s]", strings.Join(l.stack, " > ")) +} diff --git a/ops.go b/ops/ops.go similarity index 50% rename from ops.go rename to ops/ops.go index 38db828..3e5a19f 100644 --- a/ops.go +++ b/ops/ops.go @@ -1,62 +1,23 @@ -package ftl +package ops import ( "bufio" "bytes" - "fmt" "net/http" - "os" "os/exec" - "runtime/debug" "strings" ) type Log interface { - BeginStep(name string) - EndStep(State) + Fatal(v ...interface{}) Error(v ...interface{}) - Info(v ...interface{}) Debug(v ...interface{}) Trace(v ...interface{}) } -type Ops struct { - Log Log -} - -type State int - -const ( - StateUnchanged State = iota - StateChanged -) - -func (s State) String() string { - switch s { - case StateUnchanged: - return "unchanged" - case StateChanged: - return "changed" - default: - return fmt.Sprintf("unknown (%d)", s) - } -} +var Logger Log -type StepFunc func(*Ops) State - -func (op *Ops) Step(name string, f StepFunc) { - op.Log.BeginStep(name) - state := f(op) - op.Log.EndStep(state) -} - -func (op *Ops) Error(opName string, err error) { - op.Log.Error(opName, err) - debug.PrintStack() - os.Exit(1) -} - -func (op *Ops) Installed(name string) bool { +func Installed(name string) bool { cmd := exec.Command("dpkg-query", "--show", "--showformat='${db:Status-Status}'", name) out, err := cmd.CombinedOutput() @@ -67,84 +28,79 @@ func (op *Ops) Installed(name string) bool { } } - op.Error("Ops.Installed", err) - return false + Logger.Fatal("ops.Installed:", err) } return string(out) == "'installed'" } -func (op *Ops) UpdateRepos() { +func UpdateRepos() { + Logger.Debug("ops.UpdateRepos") cmd := exec.Command("apt-get", "update") if err := cmd.Run(); err != nil { - op.Error("Ops.UpdateRepos", err) - return + Logger.Fatal("ops.UpdateRepos:", err) } } -func (op *Ops) MissingPackage(name string) bool { - return len(op.MissingPackages(name)) > 0 +func MissingPackage(name string) bool { + return len(MissingPackages(name)) > 0 } -func (op *Ops) MissingPackages(name ...string) []string { +func MissingPackages(name ...string) []string { var missing []string for _, n := range name { - if !op.Installed(n) { + if !Installed(n) { missing = append(missing, n) } } return missing } -func (op *Ops) Install(names ...string) { - op.Log.Debug("Ops.Install:", strings.Join(names, ", ")) +func Install(names ...string) { + Logger.Debug("ops.Install:", strings.Join(names, ", ")) cmd := exec.Command("apt-get", append([]string{"install", "--yes"}, names...)...) - if err := cmd.Run(); err != nil { - op.Error("Ops.Install", err) - return + if out, err := cmd.CombinedOutput(); err != nil { + Logger.Debug("ops.Install: combined output:\n\n", string(out)) + + Logger.Fatal("ops.Install:", err) } } -func (op *Ops) DistroCodename() string { +func DistroCodename() string { cmd := exec.Command("lsb_release", "--short", "--codename") var out bytes.Buffer cmd.Stdout = &out if err := cmd.Run(); err != nil { - op.Error("Ops.DistroCodename", err) - return "" + Logger.Fatal("ops.DistroCodename:", err) } return strings.Trim(out.String(), "\n") } -func (op *Ops) AddRepo(repo, pubKey string) { +func AddRepo(repo, pubKey string) { resp, err := http.Get(pubKey) if err != nil { - op.Error("Ops.AddRepo", err) - return + Logger.Fatal("ops.AddRepo:", err) } defer resp.Body.Close() cmd := exec.Command("apt-key", "add", "-") cmd.Stdin = resp.Body if err := cmd.Run(); err != nil { - op.Error("Ops.AddRepo", err) - return + Logger.Fatal("ops.AddRepo:", err) } cmd = exec.Command("add-apt-repository", "--update", repo) if err := cmd.Run(); err != nil { - op.Error("Ops.AddRepo", err) - return + Logger.Fatal("ops.AddRepo:", err) } } -func (op *Ops) ListRepos() []string { +func ListRepos() []string { cmd := exec.Command("grep", "--recursive", "--no-filename", "--include", "*.list", "^deb ", "/etc/apt/sources.list", "/etc/apt/sources.list.d/") out, err := cmd.CombinedOutput() if err != nil { - op.Error("Ops.AddRepo", err) - return []string{} + Logger.Fatal("ops.ListRepos:", err) } var repos []string @@ -156,19 +112,19 @@ func (op *Ops) ListRepos() []string { return repos } -func (op *Ops) MissingRepo(name string) bool { - return len(op.MissingRepos(name)) > 0 +func MissingRepo(name string) bool { + return len(MissingRepos(name)) > 0 } -func (op *Ops) MissingRepos(name ...string) []string { +func MissingRepos(name ...string) []string { var missing []string - existing := op.ListRepos() + existing := ListRepos() for _, n := range name { - op.Log.Trace("Ops.MissingRepos: looking for:", n) + Logger.Trace("ops.MissingRepos: looking for:", n) var found bool for _, e := range existing { - op.Log.Trace("Ops.MissingRepos: comparing with:", e) + Logger.Trace("ops.MissingRepos: comparing with:", e) if n == e { found = true break diff --git a/plans/docker_plan.go b/plans/docker_plan.go index 7bfae4c..3bc98c5 100644 --- a/plans/docker_plan.go +++ b/plans/docker_plan.go @@ -4,50 +4,43 @@ import ( "fmt" "github.com/ftlops/ftl" + "github.com/ftlops/ftl/ops" ) func main() { - installDocker() -} - -func installDocker() { - - ftl.Step("install docker", func(op *ftl.Ops) ftl.State { - if !op.MissingPackage("docker-ce") { + ftl.Step("install docker", func() ftl.State { + if !ops.MissingPackage("docker-ce") { return ftl.StateUnchanged } - op.Step("install prereqs", func(op *ftl.Ops) ftl.State { + ftl.Step("install prereqs", func() ftl.State { prereqs := []string{ "apt-transport-https", "ca-certificates", "gnupg", "lsb-release", } - missing := op.MissingPackages(prereqs...) + missing := ops.MissingPackages(prereqs...) if len(missing) == 0 { return ftl.StateUnchanged } - op.Log.Info("update repos") - op.UpdateRepos() - op.Log.Info("install prerequisites") - op.Install(missing...) + ops.UpdateRepos() + ops.Install(missing...) return ftl.StateChanged }) - op.Step("add repo", func(op *ftl.Ops) ftl.State { - codename := op.DistroCodename() + ftl.Step("add repo", func() ftl.State { + codename := ops.DistroCodename() repo := fmt.Sprintf("deb [arch=amd64] https://download.docker.com/linux/ubuntu %s stable", codename) - if !op.MissingRepo(repo) { + if !ops.MissingRepo(repo) { return ftl.StateUnchanged } - op.AddRepo(repo, "https://download.docker.com/linux/ubuntu/gpg") + ops.AddRepo(repo, "https://download.docker.com/linux/ubuntu/gpg") return ftl.StateChanged }) - op.Log.Info("install docker-ce") - op.Install("docker-ce") + ops.Install("docker-ce") return ftl.StateChanged }) }