Skip to content

Commit

Permalink
Add unmount-volume check. Add agent log file. Fix command.
Browse files Browse the repository at this point in the history
  • Loading branch information
adyatlov committed Sep 13, 2018
1 parent bbd106f commit 90fc858
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 15 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## v1.7.0 (12.09.2018)

### Enhancements

* New `unmount-volume` command checks if Mesos agent had problems unmounting local persistent volumes.
* New `FindFirstLine` function helps to search in logs.

### Bug fixes

* Bun launches a random subcommand instead of the specified one.

Kudos to Jan and Marvin for sponsoring this release with their company.

## v1.6.0 (10.09.2018)

### Enhancements
Expand Down
2 changes: 2 additions & 0 deletions bun/cmd/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
_ "github.com/adyatlov/bun/check/dcosversion"
_ "github.com/adyatlov/bun/check/health"
_ "github.com/adyatlov/bun/check/mesos/actormailboxes"
_ "github.com/adyatlov/bun/check/mesos/unmountvolume"
_ "github.com/adyatlov/bun/check/nodecount"
_ "github.com/adyatlov/bun/file/dcosversionfile"
_ "github.com/adyatlov/bun/file/healthfile"
_ "github.com/adyatlov/bun/file/mesos/actormailboxesfile"
_ "github.com/adyatlov/bun/file/mesos/agentlog"
)
11 changes: 6 additions & 5 deletions bun/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,22 @@ func init() {
rootCmd.PersistentFlags().BoolVarP(&printLong, "long", "l", false,
"print details")
// Adding registered checks as commands.
for _, check := range bun.Checks() {
for _, c := range bun.Checks() {
run := func(cmd *cobra.Command, args []string) {
check := bun.GetCheck(cmd.Use)
check.Run(*bundle)
printReport(check)
return
}
var cmd = &cobra.Command{
Use: check.Name,
Short: check.Description,
Long: check.Description,
Use: c.Name,
Short: c.Description,
Long: c.Description,
PreRun: preRun,
Run: run,
}
rootCmd.AddCommand(cmd)
rootCmd.ValidArgs = append(rootCmd.ValidArgs, check.Name)
rootCmd.ValidArgs = append(rootCmd.ValidArgs, cmd.Use)
rootCmd.PreRun = preRun
}
}
Expand Down
30 changes: 30 additions & 0 deletions check/mesos/unmountvolume/unmount_volume.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package unmountvolume

import (
"fmt"

"github.com/adyatlov/bun"
)

func init() {
builder := bun.CheckBuilder{
Name: "unmount-volume",
Description: "Checks if Mesos agents had problems unmounting local persistent volumes",
ForEachAgent: check,
ForEachPublicAgent: check,
}
builder.BuildAndRegister()
}

func check(host bun.Host) (ok bool, details interface{}, err error) {
line, n, err := host.FindFirstLine("mesos-agent-log", "Failed to destroy nested containers")
if err != nil {
return
}
if n != 0 {
details = fmt.Sprintf("%v: %v", n, line)
return
}
ok = true
return
}
17 changes: 17 additions & 0 deletions file/mesos/agentlog/agent_log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package agentlog

import "github.com/adyatlov/bun"

func init() {
f := bun.FileType{
Name: "mesos-agent-log",
ContentType: bun.Journal,
Paths: []string{
"dcos-mesos-slave.service",
"dcos-mesos-slave-public.service",
},
Description: "Mesos agent jounrald log",
HostTypes: map[bun.HostType]struct{}{bun.Agent: {}, bun.PublicAgent: {}},
}
bun.RegisterFileType(f)
}
47 changes: 37 additions & 10 deletions file_owner.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package bun

import (
"bufio"
"compress/gzip"
"encoding/json"
"errors"
Expand All @@ -17,6 +18,21 @@ type fileOwner struct {
Path string
}

type bulkCloser []io.Closer

func (bc bulkCloser) Close() error {
e := []string{}
for _, c := range bc {
if err := c.Close(); err != nil {
e = append(e, err.Error())
}
}
if len(e) > 0 {
return errors.New(strings.Join(e, "\n"))
}
return nil
}

// OpenFile opens the files of the typeName file type.
// If the file is not found, it tries to open it from a correspondent .gzip archive.
// If the .gzip archive is not found as well then returns an error.
Expand Down Expand Up @@ -45,14 +61,15 @@ func (fo fileOwner) OpenFile(typeName string) (File, error) {
notFound = append(notFound, filePath)
continue // not found
}
// found
r, err := gzip.NewReader(file)
if err != nil {
return nil, err // error
}
return struct {
io.Reader
io.Closer
}{io.Reader(r), bulkCloser{r, file}}, nil // found
}{io.Reader(r), bulkCloser{r, file}}, nil
}
return nil, fmt.Errorf("none of the following files are found:\n%v",
strings.Join(notFound, "\n"))
Expand All @@ -78,17 +95,27 @@ func (fo fileOwner) ReadJSON(typeName string, v interface{}) error {
return json.Unmarshal(data, v)
}

type bulkCloser []io.Closer
func (fo fileOwner) FindFirstLine(typeName string, substr string) (l string, n int, err error) {
file, err := fo.OpenFile(typeName)
if err != nil {
return
}
return findFirstLine(file, substr)
}

func (bc bulkCloser) Close() error {
e := []string{}
for _, c := range bc {
if err := c.Close(); err != nil {
e = append(e, err.Error())
func findFirstLine(r io.Reader, substr string) (l string, n int, err error) {
scanner := bufio.NewScanner(r)
for i := 1; scanner.Scan(); i++ {
line := scanner.Text()
if strings.Contains(line, substr) {
l = line
n = i
return
}
}
if len(e) > 0 {
return errors.New(strings.Join(e, "\n"))
if err = scanner.Err(); err != nil {
return
}
return nil
// Not found
return
}
28 changes: 28 additions & 0 deletions file_owner_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package bun

import (
"strings"
"testing"
)

const str = `“Would you tell me, please, which way I ought to go from here?”
“That depends a good deal on where you want to get to,” said the Cat.
“I don’t much care where-–” said Alice.
“Then it doesn’t matter which way you go,” said the Cat.
“-–so long as I get SOMEWHERE,” Alice added as an explanation.
“Oh, you’re sure to do that,” said the Cat, “if you only walk long enough.”`

func TestFindFirstLine(t *testing.T) {
r := strings.NewReader(str)
line, n, err := findFirstLine(r, "SOMEWHERE")
const expected = `“-–so long as I get SOMEWHERE,” Alice added as an explanation.`
if line != expected {
t.Errorf("Epected line = \"%v\", observed \"%v\"", expected, line)
}
if n != 5 {
t.Errorf("Expected n = 5, observed n = %v", n)
}
if err != nil {
t.Errorf("Expected err = nil, observed err = %v", err)
}
}

0 comments on commit 90fc858

Please sign in to comment.