aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Cholewiński <harry666t@gmail.com>2018-01-04 00:20:49 +0100
committerKamil Cholewiński <harry666t@gmail.com>2018-01-04 00:45:40 +0100
commitbdd6fe797625f3b5a8adba831e8310c118e5147d (patch)
tree29eb0401e72bccb0b8c380a51dd6fe2c4588eaf8
parent5bac082c48d647edabe12c8dbe6df276094c874b (diff)
downloadjudo-bdd6fe797625f3b5a8adba831e8310c118e5147d.zip
judo-bdd6fe797625f3b5a8adba831e8310c118e5147d.tar.gz
judo-bdd6fe797625f3b5a8adba831e8310c118e5147d.tar.bz2
Making golint happy: docstrings, visibility
-rw-r--r--host.go9
-rw-r--r--inventory.go9
-rw-r--r--job.go24
-rw-r--r--logger.go8
-rw-r--r--main.go16
-rw-r--r--main_test.go14
-rw-r--r--proc.go16
-rw-r--r--seen.go5
-rw-r--r--transport.go7
9 files changed, 87 insertions, 21 deletions
diff --git a/host.go b/host.go
index 2dda640..76fd2b3 100644
--- a/host.go
+++ b/host.go
@@ -7,7 +7,7 @@ import (
"path"
)
-// Represents a single host (invocation target)
+// Host represents a single host (invocation target)
type Host struct {
Name string
Env map[string]string
@@ -18,6 +18,7 @@ type Host struct {
logger *log.Logger
}
+// NewHost creates a new Host struct with default values.
func NewHost(name string) (host *Host) {
env := make(map[string]string)
env["HOSTNAME"] = name
@@ -31,6 +32,9 @@ func NewHost(name string) (host *Host) {
}
}
+// SendRemoteAndRun establishes a connection to the host, sends off
+// and executes the given job, and returns any possible resulting
+// error.
func (host *Host) SendRemoteAndRun(job *Job) (err error) {
// speedify!
host.StartMaster()
@@ -87,10 +91,13 @@ func (host *Host) SendRemoteAndRun(job *Job) (err error) {
return errJob
}
+// RunRemote runs the given job on the host, assuming the connection
+// has been already established, and job files copied over.
func (host *Host) RunRemote(job *Job) (err error) {
return host.SSH(job, job.Command.cmd)
}
+// Cancel execution of code on the remote end.
func (host *Host) Cancel() {
go func() {
// kill up to two: master and currently running
diff --git a/inventory.go b/inventory.go
index 97fae31..49b82a7 100644
--- a/inventory.go
+++ b/inventory.go
@@ -12,6 +12,7 @@ import (
var inventoryLine = regexp.MustCompile("^[^# ]+")
+// Inventory is a collection of managed hosts.
type Inventory struct {
hosts []*Host
s *SeenString
@@ -19,6 +20,7 @@ type Inventory struct {
logger Logger
}
+// NewInventory creates a new Inventory.
func NewInventory() *Inventory {
return &Inventory{
hosts: []*Host{},
@@ -28,6 +30,12 @@ func NewInventory() *Inventory {
}
}
+// Populate the inventory with given names. Each name is resolved -
+// the process consists of looking up potential group and host names;
+// e.g. if you have a group named "foo" with hosts "a" and "b" in it,
+// the inventory will be populated with hosts "a" and "b". If the
+// hosts already exist in the inventory, they will be updated to
+// reflect group membership.
func (inventory *Inventory) Populate(names []string) {
for _, name := range names {
for host := range inventory.resolveNames(name) {
@@ -36,6 +44,7 @@ func (inventory *Inventory) Populate(names []string) {
}
}
+// GetHosts iterates over all hosts in the inventory.
func (inventory *Inventory) GetHosts() (ch chan *Host) {
ch = make(chan *Host)
go func() {
diff --git a/job.go b/job.go
index 6763e7e..55310bd 100644
--- a/job.go
+++ b/job.go
@@ -8,18 +8,21 @@ import (
"time"
)
-// file/directory to be sent to the remote Host for execution
+// Script represents the file/directory to be sent to the remote Host
+// for execution, potentially as a part of a Job.
type Script struct {
fname string
dirmode bool
}
-// ad-hoc command to be executed on the remote Host
+// Command represents an ad-hoc command to be executed on the remote
+// Host, potentially as a part of a Job.
type Command struct {
cmd string
}
-// a set of Hosts on which to run Scripts/Commands
+// Job is a container for the host inventory and the script/commands
+// to run on them.
type Job struct {
*Inventory
*Script
@@ -29,9 +32,10 @@ type Job struct {
signals chan os.Signal
}
-// Holds the result of executing a Job
+// JobResult holds the per-host results of executing a Job.
type JobResult map[*Host]error
+// Report groups the result into successful and failed host names.
func (result *JobResult) Report() (successful []string, failful map[string]error) {
failful = make(map[string]error)
for host := range *result {
@@ -45,10 +49,14 @@ func (result *JobResult) Report() (successful []string, failful map[string]error
return successful, failful
}
+// NewCommand creates a Command.
func NewCommand(cmd string) (command *Command) {
return &Command{cmd}
}
+// NewScript creates a script. The named file/directory must exist and
+// be either a regular, executable file, or a "dirmode" style
+// directory (with an executable file named "script" inside).
func NewScript(fname string) (script *Script, err error) {
script = &Script{fname: fname, dirmode: false}
stat, err := os.Stat(script.fname)
@@ -66,10 +74,12 @@ func NewScript(fname string) (script *Script, err error) {
return script, nil
}
+// IsDirMode reports whether we're executing in dirmode.
func (script *Script) IsDirMode() bool {
return script.dirmode
}
+// NewJob creates a new Job object.
func NewJob(
inventory *Inventory, script *Script, command *Command,
env map[string]string, timeout uint64) (job *Job) {
@@ -85,6 +95,8 @@ func NewJob(
}
}
+// InstallSignalHandlers installs a signal handler, which will catch
+// interrupt requests, and cancel pending jobs.
func (job Job) InstallSignalHandlers() {
signal.Notify(job.signals, os.Interrupt)
go func() {
@@ -97,6 +109,9 @@ func (job Job) InstallSignalHandlers() {
}()
}
+// PopulateInventory populates the inventory according to rules
+// explained therein; and associate environment overrides with the
+// hosts.
func (job Job) PopulateInventory(names []string) {
job.Inventory.Populate(names)
for host := range job.GetHosts() {
@@ -109,6 +124,7 @@ func (job Job) PopulateInventory(names []string) {
}
}
+// Execute is the entry point of a Job.
func (job *Job) Execute() *JobResult {
// The heart of judo, run the Job on remote Hosts
diff --git a/logger.go b/logger.go
index ce532f1..7f659cc 100644
--- a/logger.go
+++ b/logger.go
@@ -6,27 +6,33 @@ import (
"sync"
)
+// Logger encapsulates the basic functionality present in the "log"
+// package, allowing pluggable implementations.
type Logger interface {
Print(v ...interface{})
Printf(format string, v ...interface{})
Println(v ...interface{})
}
+// NilLogger is a Logger that does nothing.
type NilLogger struct{}
+// Print does nothing.
func (l *NilLogger) Print(v ...interface{}) {
}
+// Printf does nothing.
func (l *NilLogger) Printf(format string, v ...interface{}) {
}
+// Println does nothing.
func (l *NilLogger) Println(v ...interface{}) {
}
var debugLogger Logger = &NilLogger{}
var onceEnableDebugLogging *sync.Once = &sync.Once{}
-func MoreDebugLogging() {
+func moreDebugLogging() {
onceEnableDebugLogging.Do(func() {
debugLogger = log.New(os.Stderr, "debug: ", 0)
})
diff --git a/main.go b/main.go
index 9e17fcf..716dce1 100644
--- a/main.go
+++ b/main.go
@@ -20,7 +20,7 @@ common flags:
const version = "judo 0.2-dev"
-func ParseArgs(args []string) (
+func parseArgs(args []string) (
job *Job, names []string, msg string,
status int, err error) {
@@ -58,12 +58,12 @@ func ParseArgs(args []string) (
return nil, nil, usage, 111, err
}
case "-e":
- err = ParseEnvArg(opt.Arg(), env)
+ err = parseEnvArg(opt.Arg(), env)
if err != nil {
return nil, nil, usage, 111, err
}
case "-d":
- MoreDebugLogging()
+ moreDebugLogging()
}
}
@@ -78,15 +78,15 @@ func ParseArgs(args []string) (
return job, names, "", 0, nil
}
-type ArgumentError struct {
+type argumentError struct {
Message string
}
-func (e ArgumentError) Error() string {
+func (e argumentError) Error() string {
return fmt.Sprintf("Bad argument: %s", e.Message)
}
-func ParseEnvArg(arg string, env map[string]string) error {
+func parseEnvArg(arg string, env map[string]string) error {
elems := strings.SplitN(arg, "=", 2)
key := elems[0]
var value string
@@ -97,7 +97,7 @@ func ParseEnvArg(arg string, env map[string]string) error {
case 1:
value, has = os.LookupEnv(key)
if !has {
- return ArgumentError{
+ return argumentError{
Message: fmt.Sprintf("%s not set", key),
}
}
@@ -111,7 +111,7 @@ func ParseEnvArg(arg string, env map[string]string) error {
}
func main() {
- job, names, msg, status, err := ParseArgs(os.Args[1:])
+ job, names, msg, status, err := parseArgs(os.Args[1:])
if err != nil {
log.Fatal(err)
os.Exit(111)
diff --git a/main_test.go b/main_test.go
index 51755a1..7dbffb7 100644
--- a/main_test.go
+++ b/main_test.go
@@ -5,7 +5,7 @@ import (
)
func TestMainParseHelp(t *testing.T) {
- _, _, msg, status, err := ParseArgs([]string{})
+ _, _, msg, status, err := parseArgs([]string{})
if err != nil {
t.Error("err not nil")
}
@@ -16,7 +16,7 @@ func TestMainParseHelp(t *testing.T) {
t.Error("no error status")
}
- _, _, msg, status, err = ParseArgs([]string{"-h"})
+ _, _, msg, status, err = parseArgs([]string{"-h"})
if err != nil {
t.Error("err not nil")
}
@@ -27,7 +27,7 @@ func TestMainParseHelp(t *testing.T) {
t.Error("unexpected error status")
}
- _, _, msg, status, err = ParseArgs([]string{"-v"})
+ _, _, msg, status, err = parseArgs([]string{"-v"})
if err != nil {
t.Error("err not nil")
}
@@ -40,7 +40,7 @@ func TestMainParseHelp(t *testing.T) {
}
func TestMainParseCommand(t *testing.T) {
- job, _, _, _, err := ParseArgs([]string{"-c", "true"})
+ job, _, _, _, err := parseArgs([]string{"-c", "true"})
if job == nil {
t.Error("job nil")
}
@@ -56,7 +56,7 @@ func TestMainParseCommand(t *testing.T) {
}
func TestMainParseScriptNotExistent(t *testing.T) {
- job, _, msg, _, _ := ParseArgs([]string{"-s", "examples/notfound.sh"})
+ job, _, msg, _, _ := parseArgs([]string{"-s", "examples/notfound.sh"})
if msg == "" {
t.Error("no message")
}
@@ -66,7 +66,7 @@ func TestMainParseScriptNotExistent(t *testing.T) {
}
func TestMainParseScript(t *testing.T) {
- job, _, _, _, err := ParseArgs([]string{"-s", "examples/hello.sh"})
+ job, _, _, _, err := parseArgs([]string{"-s", "examples/hello.sh"})
if err != nil {
t.Error("err not nil")
}
@@ -86,7 +86,7 @@ func TestMainParseScript(t *testing.T) {
}
func TestMainParseScriptDirMode(t *testing.T) {
- job, _, _, _, err := ParseArgs([]string{"-s", "examples/bootstrap"})
+ job, _, _, _, err := parseArgs([]string{"-s", "examples/bootstrap"})
if err != nil {
t.Error("err not nil")
}
diff --git a/proc.go b/proc.go
index 840e88c..8937fb2 100644
--- a/proc.go
+++ b/proc.go
@@ -7,6 +7,8 @@ import (
"os/exec"
)
+// Proc wraps an OS process with a friendly, channel-based interface
+// and line buffering.
type Proc struct {
stdin chan string
stdout chan string
@@ -16,22 +18,33 @@ type Proc struct {
cmd *exec.Cmd
}
+// Done returns a channel, on which the caller should wait for the
+// process to complete. The channel will return an error status
+// corresponding to the process' exit code. Only one caller can wait
+// on this channel.
func (proc *Proc) Done() <-chan error {
return proc.done
}
+// Stdin returns a channel, which can be used to send input lines to
+// the process. The channel is shared between callers.
func (proc *Proc) Stdin() chan<- string {
return proc.stdin
}
+// Stdout returns a channel, on which successive lines from process'
+// stdout can be received. The channel is shared between callers.
func (proc *Proc) Stdout() <-chan string {
return proc.stdout
}
+// Stderr returns a channel, on which successive lines from process'
+// stderr can be received. The channel is shared between callers.
func (proc *Proc) Stderr() <-chan string {
return proc.stderr
}
+// CloseStdin closes the standard input of the process.
func (proc *Proc) CloseStdin() {
close(proc.stdin)
}
@@ -62,6 +75,7 @@ func writeLines(w io.WriteCloser, ch <-chan string, done chan<- interface{}) {
}
}
+// NewProc allocates and starts a new Proc.
func NewProc(name string, args ...string) (proc *Proc, err error) {
bufsz := 0
proc = &Proc{
@@ -94,10 +108,12 @@ func NewProc(name string, args ...string) (proc *Proc, err error) {
return
}
+// IsAlive reports whether the process is still running.
func (proc Proc) IsAlive() bool {
return proc.cmd == nil
}
+// Signal sends the given signal to proc.
func (proc Proc) Signal(sig os.Signal) error {
if !proc.IsAlive() {
panic("process already dead")
diff --git a/seen.go b/seen.go
index ccd4d25..277b1a4 100644
--- a/seen.go
+++ b/seen.go
@@ -4,11 +4,14 @@ import (
"sync"
)
+// SeenString is a synchronized set of strings. Once See is called
+// with a string, SeenBefore will report that it has been seen.
type SeenString struct {
seen map[string]bool
m *sync.Mutex
}
+// NewSeenString creates a new SeenString
func NewSeenString() *SeenString {
return &SeenString{
seen: make(map[string]bool),
@@ -16,6 +19,7 @@ func NewSeenString() *SeenString {
}
}
+// SeenBefore reports whether given string was seen before.
func (s *SeenString) SeenBefore(name string) bool {
s.m.Lock()
defer s.m.Unlock()
@@ -26,6 +30,7 @@ func (s *SeenString) SeenBefore(name string) bool {
return true
}
+// See marks the string as seen.
func (s *SeenString) See(name string) {
s.m.Lock()
defer s.m.Unlock()
diff --git a/transport.go b/transport.go
index 35691e4..7971906 100644
--- a/transport.go
+++ b/transport.go
@@ -55,6 +55,8 @@ func (host *Host) startSSH(job *Job, command string) (proc *Proc, err error) {
return NewProc("ssh", sshArgs...)
}
+// SSH executes the given shell command on the remote host, and
+// reports exist status.
func (host *Host) SSH(job *Job, command string) (err error) {
proc, err := host.startSSH(job, command)
close(proc.Stdin())
@@ -83,6 +85,8 @@ func (host *Host) SSH(job *Job, command string) (err error) {
}
}
+// SSHRead executes the given shell command on the remote host, and
+// returns its output together with exit status.
func (host *Host) SSHRead(job *Job, command string) (out string, err error) {
proc, err := host.startSSH(job, command)
close(proc.Stdin())
@@ -111,6 +115,8 @@ func (host *Host) SSHRead(job *Job, command string) (out string, err error) {
}
}
+// StartMaster starts the SSH master process for this host, to speed
+// up execution of consecutive SSH requests.
func (host *Host) StartMaster() (err error) {
if host.master != nil {
panic("there already is a master")
@@ -147,6 +153,7 @@ func (host *Host) StartMaster() (err error) {
return
}
+// StopMaster kills the master process.
func (host *Host) StopMaster() error {
if host.master == nil || !host.master.IsAlive() {
host.logger.Println("there was no master to stop")