Added config file to configure Profiler Tool
This CL adds a configuration file that acts as the user interface to the
Node Profiler tool. It also adds a function that parses user input from
the configuration file to a Logger Option structure. Changes needed in the
cloudlogger package are reflected in this CL.
BUG=b/196059500
Change-Id: I4d96500f4985b9191b8f29f0cfb48837dd0cc8a6
Reviewed-on: https://cos-review.googlesource.com/c/cos/tools/+/21010
Reviewed-by: Dexter Rivera <riverade@google.com>
Tested-by: Dexter Rivera <riverade@google.com>
Cloud-Build: GCB Service account <228075978874@cloudbuild.gserviceaccount.com>
diff --git a/src/cmd/nodeprofiler/main.go b/src/cmd/nodeprofiler/main.go
index 89c4c97..9237c81 100644
--- a/src/cmd/nodeprofiler/main.go
+++ b/src/cmd/nodeprofiler/main.go
@@ -7,23 +7,44 @@
import (
"context"
+ "encoding/json"
"flag"
+ "fmt"
+ "os"
"time"
"cloud.google.com/go/logging"
"cos.googlesource.com/cos/tools.git/src/pkg/nodeprofiler/cloudlogger"
"cos.googlesource.com/cos/tools.git/src/pkg/nodeprofiler/profiler"
+
log "github.com/sirupsen/logrus"
)
const cloudLoggerName = "cos_node_profiler"
-var projID, command *string
-var profilerCount, profilerInterval, cmdCount, cmdInterval, cmdTimeOut *int
+var (
+ configFile = flag.String("config-file", "", "specifies the path of the configuration file. If path is not set, then it is assumed that command line flags will be passed to configure the Node Profiler.")
+ projID = flag.String("project", "", "specifies the GCP project where logs will be added.")
+ command = flag.String("cmd", "", "specifies raw commands for which to log output.")
+ cmdCount = flag.Int("cmd-count", 0, "specifies the number of times to run an arbitrary shell command.")
+ cmdInterval = flag.Int("cmd-interval", 0, "specifies the interval (in seconds) separating the number of times the user runs an arbitrary shell command.")
+ cmdTimeOut = flag.Int("cmd-timeout", 300, "specifies the amount of time (in seconds) it will take for the a raw command to timeout and be killed.")
+ profilerCount = flag.Int("profiler-count", 1, "specifies the number of times to collect USE Report.")
+ profilerInterval = flag.Int("profiler-interval", 0, "specifies the interval (in seconds) separating the number of times the user collects USE Report.")
+)
func main() {
- // Retrieving user input from command line flags.
- opts := loadFlags()
+ var opts *cloudlogger.LoggerOpts
+ var err error
+ flag.Parse()
+ if *configFile != "" {
+ opts, err = loadConfig(*configFile)
+ if err != nil {
+ log.Fatalf("%v", err)
+ }
+ } else {
+ opts = loadFlags()
+ }
// [START client setup]
ctx := context.Background()
client, err := logging.NewClient(ctx, opts.ProjID)
@@ -45,33 +66,6 @@
log.Info("Successfully logged profiler report.")
}
-// loadflags helps to load user command line flags to run the profiler tool.
-func loadFlags() *cloudlogger.LoggerOpts {
- projID = flag.String("project", "", "specifies the GCP project where logs will be added.")
- command = flag.String("cmd", "", "specifies raw commands for which to log output.")
- profilerCount = flag.Int("profiler-count", 1, "specifies the number of times to run the profiler.")
- profilerInterval = flag.Int("profiler-interval", 0, "specifies the interval (in seconds) separating the number of times the user runs the profiler.")
- cmdCount = flag.Int("cmd-count", 0, "specifies the number of times to run an arbitrary shell command.")
- cmdInterval = flag.Int("cmd-interval", 0, "specifies the interval (in seconds) separating the number of times the user runs an arbitrary shell command.")
- cmdTimeOut = flag.Int("cmd-timeout", 300, "specifies the amount of time (in seconds) it will take for the a raw command to timeout and be killed.")
- flag.Parse()
- // Getting Profiler Options.
- components, commands := generateProfilerOpts()
- // populating LoggerOpts struct with configurations from user.
- opts := &cloudlogger.LoggerOpts{
- ProjID: *projID,
- Command: *command,
- CmdCount: *cmdCount,
- CmdInterval: time.Duration(*cmdInterval) * time.Second,
- CmdTimeOut: time.Duration(*cmdTimeOut) * time.Second,
- ProfilerCount: *profilerCount,
- ProfilerInterval: time.Duration(*profilerInterval) * time.Second,
- Components: components,
- ProfilerCmds: commands,
- }
- return opts
-}
-
// generateProfilerOpts is a helper function used to generate the components
// array as well as the profiler options used to call the
// profiler.GenerateUSEReport function from the profiler package.
@@ -81,15 +75,66 @@
cpu := profiler.NewCPU("CPU")
memcap := profiler.NewMemCap("MemCap")
sDevIO := profiler.NewStorageDevIO("StorageDevIO")
- components := []profiler.Component{cpu, memcap, sDevIO}
+ sCap := profiler.NewStorageCap("StorageCap")
+ components := []profiler.Component{cpu, memcap, sDevIO, sCap}
// End Getting Components
// Getting Commands
vmstat := profiler.NewVMStat("vmstat", 1, 5, []string{"us", "sy", "st", "si", "so", "r"})
lscpu := profiler.NewLscpu("lscpu", []string{"CPU(s)"})
free := profiler.NewFree("free", []string{"Mem:used", "Mem:total", "Swap:used", "Swap:total"})
iostat := profiler.NewIOStat("iostat", "-xdz", 1, 5, []string{"aqu-sz", "%util"})
- commands := []profiler.Command{vmstat, lscpu, free, iostat}
+ df := profiler.NewDF("df", "-k", []string{})
+ commands := []profiler.Command{vmstat, lscpu, free, iostat, df}
// End Getting Commands
// [End generating ProfilerOpts from Profiler Package]
return components, commands
}
+
+// loadflags helps to use command line flags as configuration to the Node
+// Profiler tool.
+func loadFlags() *cloudlogger.LoggerOpts {
+ // Getting Profiler Options.
+ components, commands := generateProfilerOpts()
+ shCmds := []cloudlogger.ShellCmdOpts{
+ cloudlogger.ShellCmdOpts{
+ Command: *command,
+ CmdCount: *cmdCount,
+ CmdInterval: time.Duration(*cmdInterval) * time.Second,
+ CmdTimeOut: time.Duration(*cmdTimeOut) * time.Second,
+ },
+ }
+ // populating LoggerOpts struct with configurations from user.
+ opts := &cloudlogger.LoggerOpts{
+ ProjID: *projID,
+ ShCmds: shCmds,
+ ProfilerCount: *profilerCount,
+ ProfilerInterval: time.Duration(*profilerInterval) * time.Second,
+ Components: components,
+ ProfilerCmds: commands,
+ }
+ return opts
+}
+
+// loadConfig helps to use a json configuration file in the current directory
+// as configuration to the Node Profiler Tool.
+func loadConfig(filename string) (*cloudlogger.LoggerOpts, error) {
+ var logger cloudlogger.LoggerOpts
+ configFile, err := os.Open(filename)
+ defer configFile.Close()
+ if err != nil {
+ return &logger, fmt.Errorf("failed to open config file %v: %v", filename, err)
+ }
+ jsonParser := json.NewDecoder(configFile)
+ if err = jsonParser.Decode(&logger); err != nil {
+ return &logger, fmt.Errorf("failed to parse config file %v: %v", filename, err)
+ }
+ for i := 0; i < len(logger.ShCmds); i++ {
+ logger.ShCmds[i].CmdInterval = logger.ShCmds[i].CmdInterval * time.Second
+ logger.ShCmds[i].CmdTimeOut = logger.ShCmds[i].CmdTimeOut * time.Second
+ }
+ logger.ProfilerInterval = logger.ProfilerInterval * time.Second
+ components, commands := generateProfilerOpts()
+ logger.Components = components
+ logger.ProfilerCmds = commands
+ return &logger, err
+}
diff --git a/src/cmd/nodeprofiler/sample_config.json b/src/cmd/nodeprofiler/sample_config.json
new file mode 100644
index 0000000..53f0e07
--- /dev/null
+++ b/src/cmd/nodeprofiler/sample_config.json
@@ -0,0 +1,19 @@
+{
+ "ProjID":"cos-interns-playground",
+ "ShCmds":[
+ {
+ "Command":"lscpu",
+ "CmdCount":2,
+ "CmdInterval":1,
+ "CmdTimeOut":5
+ },
+ {
+ "Command":"vmstat",
+ "CmdCount":3,
+ "CmdInterval":1,
+ "CmdTimeOut": 5
+ }
+ ],
+ "ProfilerCount":2,
+ "ProfilerInterval":2
+}
diff --git a/src/pkg/nodeprofiler/cloudlogger/cloudlogger.go b/src/pkg/nodeprofiler/cloudlogger/cloudlogger.go
index 351d6ab..6ee0530 100644
--- a/src/pkg/nodeprofiler/cloudlogger/cloudlogger.go
+++ b/src/pkg/nodeprofiler/cloudlogger/cloudlogger.go
@@ -26,25 +26,32 @@
Additional string
}
+// ShellCmdOpts contains the options that each arbitrary shell command should
+// be mapped to.
+type ShellCmdOpts struct {
+ // Specifies raw commands for which to log output.
+ Command string `json:"Command"`
+ // Specifies the number of times to run an arbitrary shell command.
+ CmdCount int `json:"CmdCount"`
+ // Specifies the interval separating the number of times the user runs
+ // an arbitrary shell command.
+ CmdInterval time.Duration `json:"CmdInterval"`
+ // Specifies the amount of time it will take for the a raw shell command to
+ // timeout.
+ CmdTimeOut time.Duration `json: "CmdTimeOut"`
+}
+
// LoggerOpts contains the options supported when logging the Profiler Report
// to Google Cloud Logging backend.
type LoggerOpts struct {
// Specifies the project ID to write logs to.
- ProjID string
- // Specifies raw commands for which to log output.
- Command string
- // Specifies the number of times to run an arbitrary shell command.
- CmdCount int
- // Specifies the interval separating the number of times the user runs
- // an arbitrary shell command.
- CmdInterval time.Duration
- // Specifies the amount of time it will take for the a raw shell command to
- // timeout.
- CmdTimeOut time.Duration
+ ProjID string `json:"ProjID"`
+ // Specifies the commands to run mapped with their options.
+ ShCmds []ShellCmdOpts `json:"ShCmds"`
// Specifies the number of times to run the profiler.
- ProfilerCount int
+ ProfilerCount int `json: "ProfilerCount"`
// Specifies the interval the profiler will run.
- ProfilerInterval time.Duration
+ ProfilerInterval time.Duration `json: "ProfilerInterval"`
// Components on which to run profiler. It may contain CPU(s), Memory, etc.
Components []profiler.Component
// ProfilerCmds field specifies additional options needed to run the profiler
@@ -84,29 +91,34 @@
if l.ProfilerCount == 0 && l.ProfilerInterval != 0 {
return fmt.Errorf("invalid Logger options: cannot set ProfilerInterval if ProfilerCount is not set")
}
- // if the command configuration is nil, ensure CmdCount, CmdInterval, and
- // CmdTimeOut configurations are all 0.
- if l.Command == "" {
- if l.CmdCount != 0 || l.CmdInterval != 0 || l.CmdTimeOut != 0 {
- return fmt.Errorf("invalid Logger options: CmdCount, CmdInterval and CmdTimeout should not be set if Command is not set")
+ for _, shCmd := range l.ShCmds {
+ // if the command configuration is nil, ensure CmdCount, CmdInterval, and
+ // CmdTimeOut configurations are all 0.
+ if shCmd.Command == "" {
+ if shCmd.CmdCount != 0 || shCmd.CmdInterval != 0 || shCmd.CmdTimeOut != 0 {
+ return fmt.Errorf("invalid Logger options: CmdCount, CmdInterval and CmdTimeout should not be set if Command is not set")
+ }
+ } else {
+ // if the the command configuration was set, but the user did not specify
+ // when the command will timeout, then the CmdTimeOut configuration will be
+ // set to defaultCommandTimeout, which is 300 seconds.
+ if shCmd.CmdTimeOut == 0 {
+ shCmd.CmdTimeOut = defaultCommandTimeout
+ }
+
+ // if CmdCount config is not set, then CmdInterval must not be set.
+ if shCmd.CmdCount == 0 && shCmd.CmdInterval != 0 {
+ return fmt.Errorf("invalid Logger options: cannot set CmdInterval if CmdCount is not set")
+ }
+ // if the command configuration is set but no other options is set, run the
+ // command once.
+ if shCmd.CmdCount == 0 && shCmd.CmdInterval == 0 {
+ shCmd.CmdCount = 1
+ }
}
- } else {
- // if the the command configuration was set, but the user did not specify
- // when the command will timeout, then the CmdTimeOut configuration will be
- // set to defaultCommandTimeout, which is 300 seconds.
- if l.CmdTimeOut == 0 {
- l.CmdTimeOut = defaultCommandTimeout
- }
- // if CmdCount config is not set, then CmdInterval must not be set.
- if l.CmdCount == 0 && l.CmdInterval != 0 {
- return fmt.Errorf("invalid Logger options: cannot set CmdInterval if CmdCount is not set")
- }
- // if the command configuration is set but no other options is set, run the
- // command once.
- if l.CmdCount == 0 && l.CmdInterval == 0 {
- l.CmdCount = 1
- }
+
}
+
return nil
}
@@ -219,30 +231,34 @@
return err
}
log.Info("Done validating logger options.")
- log.Info("Running Profiler . . .")
// Ensure logging entries are written to the cloud logging backend.
defer g.Flush()
- // Only log shell command if the user specified a command.
- if len(opts.Command) == 0 {
- emptyCmd = true
- } else {
- emptyCmd = false
- log.Info("Running shell command . . .")
- // Fetching command from user input and populating the cmdArray
- // with the main command and its flags.
- cmdArray := strings.Split(opts.Command, " ")
- usrMainCmd := cmdArray[0]
- usrMainCmdFlags := cmdArray[1:]
- for i := 0; i < opts.CmdCount; i++ {
- if err := logShellCommand(g, opts.CmdTimeOut, usrMainCmd, usrMainCmdFlags...); err != nil {
- errArr = append(errArr, err)
- continue
+ for _, shCmd := range opts.ShCmds {
+ // Only log shell command if the user specified a command.
+ if len(shCmd.Command) == 0 {
+ emptyCmd = true
+ } else {
+ emptyCmd = false
+ log.Infof("Running %v . . .", shCmd.Command)
+ // Fetching command from user input and populating the cmdArray
+ // with the main command and its flags.
+ cmdArray := strings.Split(shCmd.Command, " ")
+ usrMainCmd := cmdArray[0]
+ usrMainCmdFlags := cmdArray[1:]
+ for i := 0; i < shCmd.CmdCount; i++ {
+ if err := logShellCommand(g, shCmd.CmdTimeOut, usrMainCmd, usrMainCmdFlags...); err != nil {
+ errArr = append(errArr, err)
+ continue
+ }
+ // Delaying execution by cmdInterval seconds.
+ time.Sleep(shCmd.CmdInterval)
+
}
- // Delaying execution by cmdInterval seconds.
- time.Sleep(opts.CmdInterval)
+ log.Infof("Done running %v\n", shCmd.Command)
+
}
- log.Infof("Done running shell command.")
}
+ log.Info("Running Profiler . . .")
// Run the profiler profCount times. The default value is 1 time unless user
// set the counter to a different number.
for i := 0; i < opts.ProfilerCount; i++ {
diff --git a/src/pkg/nodeprofiler/cloudlogger/cloudlogger_test.go b/src/pkg/nodeprofiler/cloudlogger/cloudlogger_test.go
index f36214d..c8eacdf 100644
--- a/src/pkg/nodeprofiler/cloudlogger/cloudlogger_test.go
+++ b/src/pkg/nodeprofiler/cloudlogger/cloudlogger_test.go
@@ -208,18 +208,22 @@
t.Errorf("LogText(%v, %v) = %v, wantErr %t", f, test.input, err, test.wantErr)
}
- if diff := cmp.Diff(test.wantOutput, f.logged); diff != "" {
- t.Errorf("ran logText(fakeTextLogger, %+v), but got mismatch between got and want (-got, +want): \n diff %s", test.input, diff)
+ if diff := cmp.Diff(f.logged, test.wantOutput); diff != "" {
+ t.Errorf("ran LogText(fakeTextLogger, %+v), but got mismatch between got and want (-got, +want): \n diff %s", test.input, diff)
}
}
}
func TestTableLogProfilerReport(t *testing.T) {
// Retrieving testing data.
- inputFile := "testdata/testdata.txt"
- inputFileData, err := ioutil.ReadFile(inputFile)
+ inputFile1, inputFile2 := "testdata/testdata.txt", "testdata/testdata2.txt"
+ inputFileData1, err := ioutil.ReadFile(inputFile1)
if err != nil {
- t.Errorf("failed to open testing input file: %v\n", err)
+ t.Errorf("failed to open testing input file %v: %v\n", inputFile1, err)
+ }
+ inputFileData2, err := ioutil.ReadFile(inputFile2)
+ if err != nil {
+ t.Errorf("failed to open testing input file %v: %v\n", inputFile2, err)
}
// Retrieving profiler components and commands.
components, cmds := generateFakeProfilerOpts()
@@ -241,6 +245,7 @@
for _, c := range useReport.Components {
cInfos = append(cInfos, componentInfo{Name: c.Name(), Metrics: expected.Metrics, Additional: c.AdditionalInformation()})
}
+
var tests = []struct {
name string
input *LoggerOpts
@@ -250,11 +255,15 @@
{
name: "valid logger options and non-empty json payload log.",
input: &LoggerOpts{
- ProjID: "cos-interns-playground",
- Command: "bash testdata/testcmd.sh",
- CmdCount: 1,
- CmdInterval: 0 * time.Second,
- CmdTimeOut: 3 * time.Second,
+ ProjID: "cos-interns-playground",
+ ShCmds: []ShellCmdOpts{
+ ShellCmdOpts{
+ Command: "bash testdata/testcmd.sh",
+ CmdCount: 1,
+ CmdInterval: 0 * time.Second,
+ CmdTimeOut: 3 * time.Second,
+ },
+ },
ProfilerCount: 1,
ProfilerInterval: 0 * time.Second,
Components: components,
@@ -267,7 +276,7 @@
CommandOutput string
}{
CommandName: "bash testdata/testcmd.sh",
- CommandOutput: string(inputFileData),
+ CommandOutput: string(inputFileData1),
},
Severity: logging.Debug,
},
@@ -287,11 +296,20 @@
{
name: "multiple commands executions and multiple profiler runs non-empty json payload log.",
input: &LoggerOpts{
- ProjID: "cos-interns-playground",
- Command: "bash testdata/testcmd.sh",
- CmdCount: 3,
- CmdInterval: 0 * time.Second,
- CmdTimeOut: 3 * time.Second,
+ ProjID: "cos-interns-playground",
+ ShCmds: []ShellCmdOpts{
+ ShellCmdOpts{
+ Command: "bash testdata/testcmd.sh",
+ CmdCount: 1,
+ CmdInterval: 0 * time.Second,
+ CmdTimeOut: 3 * time.Second,
+ }, ShellCmdOpts{
+ Command: "bash testdata/testhello.sh",
+ CmdCount: 1,
+ CmdInterval: 0 * time.Second,
+ CmdTimeOut: 3 * time.Second,
+ },
+ },
ProfilerCount: 2,
ProfilerInterval: 0 * time.Second,
Components: components,
@@ -304,25 +322,18 @@
CommandOutput string
}{
CommandName: "bash testdata/testcmd.sh",
- CommandOutput: string(inputFileData),
+ CommandOutput: string(inputFileData1),
},
Severity: logging.Debug,
- }, {
+ },
+
+ {
Payload: struct {
CommandName string
CommandOutput string
}{
- CommandName: "bash testdata/testcmd.sh",
- CommandOutput: string(inputFileData),
- },
- Severity: logging.Debug,
- }, {
- Payload: struct {
- CommandName string
- CommandOutput string
- }{
- CommandName: "bash testdata/testcmd.sh",
- CommandOutput: string(inputFileData),
+ CommandName: "bash testdata/testhello.sh",
+ CommandOutput: string(inputFileData2),
},
Severity: logging.Debug,
},
@@ -348,15 +359,18 @@
}},
wantErr: false,
},
-
{
name: "invalid logger options payload log: empty command with CmdCount and/or CmdInterval.",
input: &LoggerOpts{
- ProjID: "cos-interns-playground",
- Command: "",
- CmdCount: 1,
- CmdInterval: 0 * time.Second,
- CmdTimeOut: 3 * time.Second,
+ ProjID: "cos-interns-playground",
+ ShCmds: []ShellCmdOpts{
+ ShellCmdOpts{
+ Command: "",
+ CmdCount: 1,
+ CmdInterval: 0 * time.Second,
+ CmdTimeOut: 3 * time.Second,
+ },
+ },
ProfilerCount: 1,
ProfilerInterval: 0 * time.Second,
Components: components,
@@ -368,11 +382,15 @@
{
name: "invalid logger options payload log: inconsistent CmdCount and CmdInterval.",
input: &LoggerOpts{
- ProjID: "cos-interns-playground",
- Command: "bash testdata/testcmd.sh",
- CmdCount: 0,
- CmdInterval: 3 * time.Second,
- CmdTimeOut: 3 * time.Second,
+ ProjID: "cos-interns-playground",
+ ShCmds: []ShellCmdOpts{
+ ShellCmdOpts{
+ Command: "bash testdata/testcmd.sh",
+ CmdCount: 0,
+ CmdInterval: 3 * time.Second,
+ CmdTimeOut: 3 * time.Second,
+ },
+ },
ProfilerCount: 1,
ProfilerInterval: 0 * time.Second,
Components: components,
@@ -384,11 +402,15 @@
{
name: "invalid logger options payload log: inconsistent ProfilerCount and ProfilerInterval.",
input: &LoggerOpts{
- ProjID: "",
- Command: "bash testdata/testcmd.sh",
- CmdCount: 1,
- CmdInterval: 1 * time.Second,
- CmdTimeOut: 3 * time.Second,
+ ProjID: "cos-interns-playground",
+ ShCmds: []ShellCmdOpts{
+ ShellCmdOpts{
+ Command: "bash testdata/testcmd.sh",
+ CmdCount: 0,
+ CmdInterval: 3 * time.Second,
+ CmdTimeOut: 3 * time.Second,
+ },
+ },
ProfilerCount: 0,
ProfilerInterval: 4 * time.Second,
Components: components,
@@ -398,13 +420,17 @@
wantErr: true,
},
{
- name: "invalid logger options payload log: no project ID.",
+ name: "invalid logger options payload log: no project ID/invalid project ID.",
input: &LoggerOpts{
- ProjID: "",
- Command: "bash testdata/testcmd.sh",
- CmdCount: 0,
- CmdInterval: 3 * time.Second,
- CmdTimeOut: 3 * time.Second,
+ ProjID: "",
+ ShCmds: []ShellCmdOpts{
+ ShellCmdOpts{
+ Command: "bash testdata/testcmd.sh",
+ CmdCount: 0,
+ CmdInterval: 3 * time.Second,
+ CmdTimeOut: 3 * time.Second,
+ },
+ },
ProfilerCount: 1,
ProfilerInterval: 0 * time.Second,
Components: components,
diff --git a/src/pkg/nodeprofiler/cloudlogger/testdata/testdata2.txt b/src/pkg/nodeprofiler/cloudlogger/testdata/testdata2.txt
new file mode 100644
index 0000000..a58b168
--- /dev/null
+++ b/src/pkg/nodeprofiler/cloudlogger/testdata/testdata2.txt
@@ -0,0 +1 @@
+ Hello world !
diff --git a/src/pkg/nodeprofiler/cloudlogger/testdata/testhello.sh b/src/pkg/nodeprofiler/cloudlogger/testdata/testhello.sh
new file mode 100755
index 0000000..6e2bdf5
--- /dev/null
+++ b/src/pkg/nodeprofiler/cloudlogger/testdata/testhello.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+main() {
+ cat <<EOF
+ Hello world !
+EOF
+}
+main "$#"
diff --git a/src/pkg/nodeprofiler/profiler/commands.go b/src/pkg/nodeprofiler/profiler/commands.go
index b310d79..5d21fac 100644
--- a/src/pkg/nodeprofiler/profiler/commands.go
+++ b/src/pkg/nodeprofiler/profiler/commands.go
@@ -236,6 +236,15 @@
titles []string
}
+// NewDF function helps to initialize a df structure.
+func NewDF(name string, flags string, titles []string) *df {
+ return &df{
+ name: name,
+ flags: flags,
+ titles: titles,
+ }
+}
+
// Name returns the name for the 'df' command
func (fs *df) Name() string {
return fs.name
@@ -245,9 +254,9 @@
// map of title(s) to their values.
func (fs *df) Run() (map[string][]string, error) {
// get output in 1K size to make summing values direct
- out, err := utils.RunCommand(fs.Name(), "-k", fs.flags)
+ out, err := utils.RunCommand(fs.Name(), fs.flags)
if err != nil {
- cmd := fs.Name() + " " + "-k"
+ cmd := fs.Name() + " " + fs.flags
return nil, fmt.Errorf("failed to run the command %q: %v",
cmd, err)
}
diff --git a/src/pkg/nodeprofiler/profiler/commands_test.go b/src/pkg/nodeprofiler/profiler/commands_test.go
index 5c80495..a396c3a 100644
--- a/src/pkg/nodeprofiler/profiler/commands_test.go
+++ b/src/pkg/nodeprofiler/profiler/commands_test.go
@@ -76,7 +76,7 @@
name: "df",
fakeCmd: &df{
name: "testdata/df.sh",
- flags: "1",
+ flags: "-k",
titles: []string{"Use%"},
},
want: map[string][]string{
@@ -87,7 +87,7 @@
name: "df's output with column titles mixed up",
fakeCmd: &df{
name: "testdata/df.sh",
- flags: "2",
+ flags: "-h",
titles: []string{"Mounted on"},
},
want: map[string][]string{
diff --git a/src/pkg/nodeprofiler/profiler/components.go b/src/pkg/nodeprofiler/profiler/components.go
index 2fdb23d..bfa8df1 100644
--- a/src/pkg/nodeprofiler/profiler/components.go
+++ b/src/pkg/nodeprofiler/profiler/components.go
@@ -8,7 +8,6 @@
"time"
"cos.googlesource.com/cos/tools.git/src/pkg/nodeprofiler/utils"
-
log "github.com/sirupsen/logrus"
)
@@ -47,7 +46,6 @@
// this can be used to initialize CPU outside of the
// profiler package.
func NewCPU(name string) *CPU {
-
return &CPU{
name: name,
metrics: &USEMetrics{},
@@ -94,7 +92,6 @@
if !stPresent {
return fmt.Errorf("missing vmstat column 'st'")
}
-
if len(us) == 0 {
return fmt.Errorf("no vmstat report collected")
} else if len(us) == 1 {
@@ -102,13 +99,11 @@
" reflecting current conditions of component, additional reports are needed"
return fmt.Errorf(err)
}
-
// ignore the first values of 'us', 'sy' and 'st' since they reflect averages
// since last reboot and can bring averages down
us = us[1:]
sy = sy[1:]
st = st[1:]
-
columns := [][]string{us, sy, st}
var total int
// loop over us, sy, st columns and sum their values
@@ -120,7 +115,6 @@
total += sum
}
count := len(us)
-
c.metrics.Utilization = math.Round((float64(total)/float64(count))*100) / 100
return nil
}
@@ -160,7 +154,6 @@
if !present {
return fmt.Errorf("missing vmstat column 'r'")
}
-
if len(running) == 0 {
return fmt.Errorf("no vmstat report collected")
} else if len(running) == 1 {
@@ -168,7 +161,6 @@
" reflecting current conditions of component, additional reports are needed"
return fmt.Errorf(err)
}
-
// ignore the first values of 'r' since they reflect averages since last
// reboot and can bring the average down
running = running[1:]
@@ -177,7 +169,6 @@
if err != nil {
return err
}
-
num := len(running)
runningProcs := sum / num
count, err := c.calculateCPUCount(outputs)
@@ -205,7 +196,6 @@
// this can be used to initialize MemCap outside of the
// profiler package.
func NewMemCap(name string) *MemCap {
-
return &MemCap{
name: name,
metrics: &USEMetrics{},
@@ -366,7 +356,6 @@
// this can be used to initialize Storage device I/O outside of the
// profiler package.
func NewStorageDevIO(name string) *StorageDevIO {
-
return &StorageDevIO{
name: name,
metrics: &USEMetrics{},
@@ -377,7 +366,6 @@
// the StorageDevIO component.
func (d *StorageDevIO) AdditionalInformation() string {
return ""
-
}
// Name returns the name of the Storage device I/O component.
@@ -403,7 +391,6 @@
if !ok {
return fmt.Errorf("mising iostat column util")
}
-
total, err := utils.SumParseFloat(util)
if err != nil {
return err
@@ -434,7 +421,6 @@
}
average := total / float64(len(queue))
d.metrics.Saturation = average > 1
-
return nil
}
@@ -456,7 +442,6 @@
// this can be used to initialize StorageCap outside of the
// profiler package.
func NewStorageCap(name string) *StorageCap {
-
return &StorageCap{
name: name,
metrics: &USEMetrics{},
@@ -490,7 +475,6 @@
func (s *StorageCap) CollectUtilization(outputs map[string]utils.ParsedOutput) error {
// if devices are not set
s.setDefaults()
-
dfCmd := "df"
parsedOutput, ok := outputs[dfCmd]
if !ok {
@@ -526,7 +510,6 @@
return fmt.Errorf("failed to convert %q to int: %v", val, err)
}
fUsed += val
-
s = totalBlocks[index]
val, err = strconv.Atoi(s)
if err != nil {
@@ -544,7 +527,6 @@
}
util := (float64(fUsed) / float64(fSize)) * 100
fsUtilization := math.Round((util)*100) / 100
-
s.metrics.Utilization = fsUtilization
return nil
}
@@ -560,11 +542,9 @@
// Not yet implemented
return nil
}
-
func (s *StorageCap) USEMetrics() *USEMetrics {
return s.metrics
}
-
func (s *StorageCap) Name() string {
return s.name
}
@@ -572,11 +552,9 @@
// CollectUSEMetrics collects USE Metrics for the component specified. It does this by calling
// the necessary methods to collect utilization, saturation and errors.
func CollectUSEMetrics(component Component, outputs map[string]utils.ParsedOutput) error {
-
metrics := component.USEMetrics()
metrics.Timestamp = time.Now()
start := metrics.Timestamp
-
var gotErr bool
if err := component.CollectUtilization(outputs); err != nil {
gotErr = true
@@ -588,7 +566,6 @@
}
end := time.Now()
metrics.Interval = end.Sub(start)
-
if gotErr {
err := "failed to collect all USE metrics for %q. " +
"Please check the logs for more information"
diff --git a/src/pkg/nodeprofiler/profiler/testdata/df.sh b/src/pkg/nodeprofiler/profiler/testdata/df.sh
index 5d82228..7621b4d 100755
--- a/src/pkg/nodeprofiler/profiler/testdata/df.sh
+++ b/src/pkg/nodeprofiler/profiler/testdata/df.sh
@@ -1,8 +1,8 @@
#!/bin/bash
main() {
- case "$2" in
- "1")
+ case "$1" in
+ "-k")
cat <<EOF
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/vdb 7864320 5401876 1738492 76% /
@@ -11,7 +11,7 @@
/dev/root 176176 173936 0 100% /dev/.ssh/sshd_config
EOF
;;
- "2")
+ "-h")
cat <<EOF
1K-blocks Filesystem Used Available Use% Mounted on
/dev/vdb 7864320 5401876 1738492 76% /
@@ -24,4 +24,4 @@
esac
}
-main "$@"
\ No newline at end of file
+main "$@"