Skip to content
This repository has been archived by the owner on Oct 23, 2024. It is now read-only.

Commit

Permalink
Facilitate External Agent Compilation (#1118)
Browse files Browse the repository at this point in the history
- Move `internal/` to `pkg/`
 - Commit generated code
 - Make agent main code importable

Co-authored-by: Ben Keith <[email protected]>
  • Loading branch information
benkeith-splunk authored Dec 17, 2019
1 parent 5e854d2 commit c295133
Show file tree
Hide file tree
Showing 808 changed files with 18,219 additions and 1,571 deletions.
4 changes: 2 additions & 2 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ signalfx-agent*
tmp/**
local-etc/**
build/**
internal/monitors/**/template.go
internal/monitors/collectd/collectd.conf.go
pkg/monitors/**/template.go
pkg/monitors/collectd/collectd.conf.go
packaging/*/output
tests/**/__pycache__
**/.pytest_cache/**
Expand Down
6 changes: 1 addition & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,7 @@
/agent
/collectd
/debug
/internal/core/common/constants/versions.go
/internal/monitors/**/genmetadata.go
/internal/monitors/**/template.go
/internal/monitors/collectd/collectd.conf.go
internal/monitors/zcodegen/monitorcodegen
pkg/monitors/zcodegen/monitorcodegen
/packaging/*/output
/signalfx-agent
/vendor.orig/
Expand Down
4 changes: 2 additions & 2 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ issues:
linters:
- gosec

- path: internal/monitors/kubernetes/cluster/metrics
- path: pkg/monitors/kubernetes/cluster/metrics
linters:
- goconst

Expand Down Expand Up @@ -65,7 +65,7 @@ linters-settings:
settings:
printf:
funcs:
- (github.com/signalfx/signalfx-agent/internal/utils.ThrottledLogger).ThrottledWarning
- (github.com/signalfx/signalfx-agent/pkg/utils.ThrottledLogger).ThrottledWarning

run:
modules-download-mode: readonly
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ RUN go mod download
COPY cmd/ ./cmd/
COPY scripts/collectd-template-to-go scripts/make-versions ./scripts/
COPY Makefile .
COPY internal/ ./internal/
COPY pkg/ ./pkg/

ARG collectd_version=""
ARG agent_version="latest"
Expand Down Expand Up @@ -371,7 +371,7 @@ COPY --from=extra-packages /opt/root/bin/ /bin/
COPY --from=collectd /usr/share/collectd/postgresql_default.conf /postgresql_default.conf
COPY --from=collectd /usr/share/collectd/types.db /types.db
COPY --from=collectd /usr/share/collectd/java/ /collectd-java/
COPY internal/monitors/collectd/signalfx_types.db /collectd-java/signalfx_types_db
COPY pkg/monitors/collectd/signalfx_types.db /collectd-java/signalfx_types_db

# Pull in Python collectd plugin scripts
COPY --from=python-plugins /opt/collectd-python/ /collectd-python/
Expand Down
10 changes: 5 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ NUM_CORES ?= $(shell getconf _NPROCESSORS_ONLN)

.PHONY: clean
clean:
rm -f internal/core/constants/versions.go
find internal/monitors -name "genmetadata.go" -delete
find internal/monitors -name "template.go" -delete
rm -f internal/monitors/collectd/collectd.conf.go
rm -f internal/monitors/zcodegen/monitorcodegen
rm -f pkg/core/constants/versions.go
find pkg/monitors -name "genmetadata.go" -delete
find pkg/monitors -name "template.go" -delete
rm -f pkg/monitors/collectd/collectd.conf.go
rm -f pkg/monitors/zcodegen/monitorcodegen
rm -f signalfx-agent

.PHONY: check
Expand Down
284 changes: 284 additions & 0 deletions cmd/agent/agentmain/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
package agentmain

import (
"context"
"flag"
"fmt"
"io"
"os"
"os/signal"
"runtime"
"strings"
"syscall"
"time"

"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"

"github.com/signalfx/signalfx-agent/pkg/core"
"github.com/signalfx/signalfx-agent/pkg/core/common/constants"
"github.com/signalfx/signalfx-agent/pkg/selfdescribe"

prefixed "github.com/x-cray/logrus-prefixed-formatter"
)

func init() {
log.SetFormatter(&prefixed.TextFormatter{})
log.SetLevel(log.InfoLevel)
log.SetOutput(os.Stdout)
}

const windowsOS = "windows"

func getDefaultConfigPath() string {
if runtime.GOOS == windowsOS {
return "\\ProgramData\\SignalFxAgent\\agent.yaml"
}
return "/etc/signalfx/agent.yaml"
}

// Set an envvar with the agent's version so that plugins can have easy access
// to it (e.g. metadata plugin).
func setVersionEnvvar() {
os.Setenv(constants.AgentVersionEnvVar, constants.Version)
}

// Set an envvar with the collectd version so that plugins have easy access to it
func setCollectdVersionEnvvar() {
os.Setenv(constants.CollectdVersionEnvVar, constants.CollectdVersion)
}

// Print out status about an existing instance of the agent.
func doStatus() {
set := flag.NewFlagSet("status", flag.ExitOnError)
configPath := set.String("config", getDefaultConfigPath(), "agent config path")
set.Usage = func() {
fmt.Fprintf(set.Output(), "Usage: signalfx-agent status [all | monitors | config | endpoints]\n\n"+
" The optional section arg can be one of the following:\n"+
" all - Dump everything available\n"+
" monitors - Show information about all active monitors\n"+
" config - Show the fully resolved configuration currently in use by the agent\n"+
" endpoints - Show the discovered endpoints available to discovery rules\n"+
" If no section arg is provided, a short summary of the agent is output\n\n")
set.PrintDefaults()
}

_ = set.Parse(os.Args[2:])

log.SetLevel(log.ErrorLevel)

var section string
if len(set.Args()) == 1 {
section = set.Args()[0]
} else if len(set.Args()) > 1 {
set.Usage()
os.Exit(4)
}

status, err := core.Status(*configPath, section)
if err != nil {
fmt.Printf("Could not get status: %s\nAre you sure the agent is currently running?\n", err)
os.Exit(1)
}
fmt.Print(string(status))
fmt.Println("")
}

// Print out agent self-description of config/metadata
func doSelfDescribe() {
log.SetOutput(os.Stderr)
selfdescribe.JSON(os.Stdout)
}

var dpTapUsage = `
If no filters are specified, all datapoints will be output.
Examples:
Get all metrics that start with 'ps_' that have a plugin_instance dimension that starts with 'java':
signalfx-agent tap-dps -metric 'ps_*' -dims '{plugin_instance: java*}'
`

func doDatapointTap() {
set := flag.NewFlagSet("tap-dps", flag.ExitOnError)
set.Usage = func() {
fmt.Fprintf(set.Output(), "Usage of %s tap-dps:\n", os.Args[0])
set.PrintDefaults()
fmt.Fprint(set.Output(), dpTapUsage)
}

configPath := set.String("config", getDefaultConfigPath(), "agent config path")
metric := set.String("metric", "", "metric name filter string -- accepts globs")
dims := set.String("dims", "", "dimension filter string in compact YAML map notation -- dimension values can be globbed")

if err := set.Parse(os.Args[2:]); err != nil {
set.Usage()
os.Exit(1)
}

stream, err := core.StreamDatapoints(*configPath, *metric, *dims)
if err != nil {
fmt.Printf("Could not stream datapoints: %v", err)
return
}

_, err = io.Copy(os.Stdout, stream)
if err != io.EOF && err != nil {
fmt.Printf("Error streaming datapoints: %v", err)
}
}

// glog is a transitive dependency of the agent and puts a bunch of flags in
// the flag package. We don't really ever need to have users override these,
// but we would like ERROR messages going to stderr of the agent instead of to
// a temporary file.
func fixGlogFlags() {
os.Args = os.Args[:1]
flag.Parse()
_ = flag.Set("logtostderr", "true")
}

// flags is used to store parsed flag values
type flags struct {
// configPath is a string flag for specifying the agent.yaml config file
configPath string
// service is a string flag used for starting, stopping, installing or
// uninstalling the agent as a windows service (windows only)
service string
// logEvents is a bool flag for logging events to the Windows Application Event log.
// This flag is only intended to be used when the agent is launched as a Windows Service.
logEvents bool
// version is a bool flag for printing the agent version string
version bool
// debug is a bool flag for printing debug level information
debug bool
}

// getFlags retrieves flags passed to the agent at runtime and return them in a flags struct
func getFlags() *flags {
flags := &flags{}
set := flag.NewFlagSet(os.Args[0], flag.ExitOnError)

set.BoolVar(&flags.version, "version", false, "print agent version")
set.StringVar(&flags.configPath, "config", getDefaultConfigPath(), "agent config path")
set.BoolVar(&flags.debug, "debug", false, "print debugging output")

// service is a windows only feature and should only be added to the flag set on windows
if runtime.GOOS == windowsOS {
set.StringVar(&flags.service, "service", "", "'start', 'stop', 'install' or 'uninstall' agent as a windows service. You may specify an alternate config file path with the -config flag when installing the service.")
set.BoolVar(&flags.logEvents, "logEvents", false, "copy log events from the agent to the Windows Application Event Log. This is only used when the agent is deployed as a Windows service. The agent will write to stdout under all other deployment scenarios.")
}

// The set is configured to exit on errors so we don't need to check the
// return value here.
_ = set.Parse(os.Args[1:])
if len(set.Args()) > 0 {
os.Stderr.WriteString("Non-flag parameters are not accepted\n")
set.Usage()
os.Exit(2)
}
fixGlogFlags()
return flags
}

func runAgent(flags *flags, interruptCh chan os.Signal, exit chan struct{}) {
var shutdown context.CancelFunc
var shutdownComplete <-chan struct{}
init := func() {
logrus.Info("Starting up agent version " + constants.Version)
shutdown, shutdownComplete = core.Startup(flags.configPath)
}

init()

go func() {
<-interruptCh
logrus.Info("Interrupt signal received, stopping agent")
shutdown()
select {
case <-shutdownComplete:
break
case <-time.After(10 * time.Second):
logrus.Error("Shutdown timed out, forcing process down")
break
}
close(exit)
}()

hupCh := make(chan os.Signal, 1)
signal.Notify(hupCh, syscall.SIGHUP)
go func() {
for range hupCh {
logrus.Info("Forcing agent reset")
shutdown()
<-shutdownComplete
init()
}
}()

<-exit
}

// Run is the primary entrypoint for the agent. It handles all of the command
// line processing and starts up the agent. It will block until the agent
// shuts down.
func Run() {
setVersionEnvvar()
setCollectdVersionEnvvar()

// set the agent version string
core.VersionLine = fmt.Sprintf("agent-version: %s, collectd-version: %s\n",
constants.Version, constants.CollectdVersion)

// Make it so the symlink from agent-status to this binary invokes the
// status command
if strings.HasSuffix(os.Args[0], "agent-status") {
os.Args = append([]string{os.Args[0], "status"}, os.Args[1:]...)
}

var firstArg string
if len(os.Args) >= 2 {
firstArg = os.Args[1]
}

switch firstArg {
case "status":
doStatus()
case "selfdescribe":
doSelfDescribe()
case "tap-dps":
doDatapointTap()
default:
if firstArg != "" && !strings.HasPrefix(firstArg, "-") {
log.Errorf("Unknown subcommand '%s'", firstArg)
os.Exit(127)
}

// fetch the commandline flags passed in at runtime
flags := getFlags()

if flags.debug {
log.SetLevel(log.DebugLevel)
}

if flags.version {
fmt.Printf(core.VersionLine)
os.Exit(0)
}

// set up interrupt channel
interruptCh := make(chan os.Signal, 1)
signal.Notify(interruptCh, os.Interrupt)
signal.Notify(interruptCh, syscall.SIGTERM)

// create the exit channel that will block until agent is shutdown
exitCh := make(chan struct{}, 1)
// On windows we start the agent through the package github.com/kardianos/service.
// The package provides hooks for installing and managing the agent as a windows service.
runAgentPlatformSpecific(flags, interruptCh, exitCh)
}

os.Exit(0)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// +build !windows

package main
package agentmain

import (
"os"
Expand Down
2 changes: 1 addition & 1 deletion cmd/agent/windows.go → cmd/agent/agentmain/windows.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// +build windows

package main
package agentmain

import (
"os"
Expand Down
Loading

0 comments on commit c295133

Please sign in to comment.