Skip to content

Commit

Permalink
[process-agent] Add check subcommand and deprecate --check (#11358)
Browse files Browse the repository at this point in the history
* [process-agent] Add check subcommand and deprecate --check

* Address review feedback

* Address review feedback - remove a comment + update list of checks in help
  • Loading branch information
xornivore authored Mar 18, 2022
1 parent 50643f5 commit f24ac02
Show file tree
Hide file tree
Showing 8 changed files with 399 additions and 172 deletions.
186 changes: 186 additions & 0 deletions cmd/process-agent/app/check.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.

package app

import (
"context"
"encoding/json"
"fmt"
"time"

"github.com/spf13/cobra"

"github.com/DataDog/agent-payload/v5/process"
"github.com/DataDog/datadog-agent/cmd/process-agent/flags"
sysconfig "github.com/DataDog/datadog-agent/cmd/system-probe/config"
ddconfig "github.com/DataDog/datadog-agent/pkg/config"
"github.com/DataDog/datadog-agent/pkg/metadata/host"
"github.com/DataDog/datadog-agent/pkg/process/checks"
"github.com/DataDog/datadog-agent/pkg/process/config"
"github.com/DataDog/datadog-agent/pkg/tagger"
"github.com/DataDog/datadog-agent/pkg/tagger/local"
"github.com/DataDog/datadog-agent/pkg/tagger/remote"
"github.com/DataDog/datadog-agent/pkg/util/log"
"github.com/DataDog/datadog-agent/pkg/version"
"github.com/DataDog/datadog-agent/pkg/workloadmeta"
)

// CheckCmd is a command that runs the process-agent version data
var CheckCmd = &cobra.Command{
Use: "check",
Short: "Run a specific check and print the results. Choose from: process, rtprocess, container, rtcontainer, connections, process_discovery",
Args: cobra.ExactArgs(1),
RunE: runCheckCmd,
SilenceUsage: true,
}

const loggerName ddconfig.LoggerName = "PROCESS"

func runCheckCmd(cmd *cobra.Command, args []string) error {
// We need to load in the system probe environment variables before we load the config, otherwise an
// "Unknown environment variable" warning will show up whenever valid system probe environment variables are defined.
ddconfig.InitSystemProbeConfig(ddconfig.Datadog)

configPath := cmd.Flag(flags.CfgPath).Value.String()
sysprobePath := cmd.Flag(flags.SysProbeConfig).Value.String()

if err := config.LoadConfigIfExists(configPath); err != nil {
return log.Criticalf("Error parsing config: %s", err)
}

// For system probe, there is an additional config file that is shared with the system-probe
syscfg, err := sysconfig.Merge(sysprobePath)
if err != nil {
return log.Critical(err)
}

cfg, err := config.NewAgentConfig(loggerName, configPath, syscfg)
if err != nil {
return log.Criticalf("Error parsing config: %s", err)
}

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// Now that the logger is configured log host info
hostInfo := host.GetStatusInformation()
log.Infof("running on platform: %s", hostInfo.Platform)
agentVersion, _ := version.Agent()
log.Infof("running version: %s", agentVersion.GetNumberAndPre())

// Start workload metadata store before tagger (used for containerCollection)
store := workloadmeta.GetGlobalStore()
store.Start(ctx)

// Tagger must be initialized after agent config has been setup
var t tagger.Tagger
if ddconfig.Datadog.GetBool("process_config.remote_tagger") {
t = remote.NewTagger()
} else {
t = local.NewTagger(store)
}
tagger.SetDefaultTagger(t)
err = tagger.Init(ctx)
if err != nil {
log.Errorf("failed to start the tagger: %s", err)
}
defer tagger.Stop() //nolint:errcheck

sysInfo, err := checks.CollectSystemInfo(cfg)
if err != nil {
log.Errorf("failed to collect system info: %s", err)
}

check := args[0]

// Connections check requires process-check to have occurred first (for process creation ts),
if check == checks.Connections.Name() {
checks.Process.Init(cfg, sysInfo)
checks.Process.Run(cfg, 0) //nolint:errcheck
}

names := make([]string, 0, len(checks.All))
for _, ch := range checks.All {
names = append(names, ch.Name())

if ch.Name() == check {
ch.Init(cfg, sysInfo)
return runCheck(cfg, ch)
}

withRealTime, ok := ch.(checks.CheckWithRealTime)
if ok && withRealTime.RealTimeName() == check {
withRealTime.Init(cfg, sysInfo)
return runCheckAsRealTime(cfg, withRealTime)
}
}
return log.Errorf("invalid check '%s', choose from: %v", check, names)
}

func runCheck(cfg *config.AgentConfig, ch checks.Check) error {
// Run the check once to prime the cache.
if _, err := ch.Run(cfg, 0); err != nil {
return fmt.Errorf("collection error: %s", err)
}

time.Sleep(1 * time.Second)

printResultsBanner(ch.Name())

msgs, err := ch.Run(cfg, 1)
if err != nil {
return fmt.Errorf("collection error: %s", err)
}
return printResults(msgs)
}

func runCheckAsRealTime(cfg *config.AgentConfig, ch checks.CheckWithRealTime) error {
options := checks.RunOptions{
RunStandard: true,
RunRealTime: true,
}
var (
groupID int32
nextGroupID = func() int32 {
groupID++
return groupID
}
)

// We need to run the check twice in order to initialize the stats
// Rate calculations rely on having two datapoints
if _, err := ch.RunWithOptions(cfg, nextGroupID, options); err != nil {
return fmt.Errorf("collection error: %s", err)
}

time.Sleep(1 * time.Second)

printResultsBanner(ch.RealTimeName())

run, err := ch.RunWithOptions(cfg, nextGroupID, options)
if err != nil {
return fmt.Errorf("collection error: %s", err)
}

return printResults(run.RealTime)
}

func printResultsBanner(name string) {
fmt.Printf("-----------------------------\n\n")
fmt.Printf("\nResults for check %s\n", name)
fmt.Printf("-----------------------------\n\n")
}

func printResults(msgs []process.MessageBody) error {
for _, m := range msgs {
b, err := json.MarshalIndent(m, "", " ")
if err != nil {
return fmt.Errorf("marshal error: %s", err)
}
fmt.Println(string(b))
}
return nil
}
17 changes: 8 additions & 9 deletions cmd/process-agent/app/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/spf13/cobra"

"github.com/DataDog/datadog-agent/cmd/process-agent/api"
"github.com/DataDog/datadog-agent/cmd/process-agent/flags"
apiutil "github.com/DataDog/datadog-agent/pkg/api/util"
ddconfig "github.com/DataDog/datadog-agent/pkg/config"
"github.com/DataDog/datadog-agent/pkg/process/config"
Expand Down Expand Up @@ -126,18 +127,16 @@ func getStatusURL() (string, error) {
return fmt.Sprintf("http://%s/agent/status", addressPort), nil
}

// StatusCmd returns a cobra command that prints the current status
func StatusCmd() *cobra.Command {
return &cobra.Command{
Use: "status",
Short: "Print the current status",
Long: ``,
RunE: runStatus,
}
// StatusCmd is a cobra command that prints the current status
var StatusCmd = &cobra.Command{
Use: "status",
Short: "Print the current status",
Long: ``,
RunE: runStatus,
}

func runStatus(cmd *cobra.Command, _ []string) error {
err := config.LoadConfigIfExists(cmd.Flag("cfgpath").Value.String())
err := config.LoadConfigIfExists(cmd.Flag(flags.CfgPath).Value.String())
if err != nil {
writeError(os.Stdout, err)
return err
Expand Down
13 changes: 13 additions & 0 deletions cmd/process-agent/flags/flags_common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.

package flags

const (
// CfgPath defines the cfgpath flag
CfgPath = "cfgpath"
// SysProbeConfig defines the sysprobe-config flag
SysProbeConfig = "sysprobe-config"
)
12 changes: 6 additions & 6 deletions cmd/process-agent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,19 @@ func rootCmdRun(cmd *cobra.Command, args []string) {
}

func main() {
rootCmd.PersistentFlags().StringVar(&opts.configPath, "cfgpath", flags.DefaultConfPath, "Path to datadog.yaml config")
rootCmd.PersistentFlags().StringVar(&opts.configPath, flags.CfgPath, flags.DefaultConfPath, "Path to datadog.yaml config")

if flags.DefaultSysProbeConfPath != "" {
rootCmd.PersistentFlags().StringVar(&opts.sysProbeConfigPath, "sysprobe-config", flags.DefaultSysProbeConfPath, "Path to system-probe.yaml config")
rootCmd.PersistentFlags().StringVar(&opts.sysProbeConfigPath, flags.SysProbeConfig, flags.DefaultSysProbeConfPath, "Path to system-probe.yaml config")
}

rootCmd.PersistentFlags().StringVarP(&opts.pidfilePath, "pid", "p", "", "Path to set pidfile for process")
rootCmd.PersistentFlags().BoolVarP(&opts.info, "info", "i", false, "Show info about running process agent and exit")
rootCmd.PersistentFlags().BoolVarP(&opts.version, "version", "v", false, "Print the version and exit")
rootCmd.PersistentFlags().StringVar(&opts.check, "check", "",
"Run a specific check and print the results. Choose from: process, connections, realtime, process_discovery")
rootCmd.PersistentFlags().BoolP("version", "v", false, "[deprecated] Print the version and exit")
rootCmd.PersistentFlags().String("check", "",
"[deprecated] Run a specific check and print the results. Choose from: process, rtprocess, container, rtcontainer, connections, process_discovery")

fixDeprecatedFlags(os.Args, os.Stdout)
os.Args = fixDeprecatedFlags(os.Args, os.Stdout)
if err := rootCmd.Execute(); err != nil {
os.Exit(-1)
}
Expand Down
Loading

0 comments on commit f24ac02

Please sign in to comment.