Skip to content

Commit

Permalink
NR-288387 feat: config option to disable container decoration (#1888)
Browse files Browse the repository at this point in the history
* NR-288387 feat: config option to disable container decoration

* container sampler enabled if no config

* remove deprecated macos GH runner

* fix test in darwin
  • Loading branch information
rubenruizdegauna authored Jul 9, 2024
1 parent dc896c4 commit 1673648
Show file tree
Hide file tree
Showing 11 changed files with 243 additions and 13 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/component_macos_harvest_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ macos-11, macos-12 ]
os: [ macos-12, macos-13, macos-14 ]
steps:
- uses: actions/checkout@v2

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/component_macos_linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:

run-lint:
name: Lint tests
runs-on: macos-11
runs-on: macos-latest
continue-on-error: true

steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/component_macos_unit_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ env:
jobs:
unit-test-macos:
name: unit tests
runs-on: macos-11
runs-on: macos-latest

steps:
- uses: actions/checkout@v2
Expand Down
6 changes: 6 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -1272,6 +1272,11 @@ type Config struct {
// Default (Windows): C:\ProgramData\New Relic\newrelic-infra\tmp
// Public: No
AgentTempDir string `envconfig:"agent_temp_dir" yaml:"agent_temp_dir"`

// ProcessContainerDecoration controls if the ProcessSample gets decorated with Container Information
// Default: true
// Public: Yes
ProcessContainerDecoration bool `envconfig:"process_container_decoration" yaml:"process_container_decoration"`
}

// KeyValMap is used whenever a key value pair configuration is required.
Expand Down Expand Up @@ -1896,6 +1901,7 @@ func NewConfig() *Config {
NtpMetrics: NewNtpConfig(),
Http: NewHttpConfig(),
AgentTempDir: defaultAgentTempDir,
ProcessContainerDecoration: defaultProcessContainerDecoration,
}
}

Expand Down
1 change: 1 addition & 0 deletions pkg/config/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ var (
defaultNtpEnabled = false
defaultNtpInterval = uint(15) // minutes
defaultNtpTimeout = uint(5) // seconds
defaultProcessContainerDecoration = true
)

// Default internal values
Expand Down
10 changes: 8 additions & 2 deletions pkg/metrics/process/sampler_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type processSampler struct {
var (
_ sampler.Sampler = (*processSampler)(nil) // static interface assertion
containerNotRunningErrs = map[string]struct{}{}
containerSamplerGetter = metrics.GetContainerSamplers //nolint:gochecknoglobals
)

// NewProcessSampler creates and returns a new process Sampler, given an agent context.
Expand All @@ -38,17 +39,22 @@ func NewProcessSampler(ctx agent.AgentContext) sampler.Sampler {

ttlSecs := config.DefaultContainerCacheMetadataLimit
apiVersion := ""
interval := config.FREQ_INTERVAL_FLOOR_PROCESS_METRICS
dockerContainerdNamespace := ""
interval := config.FREQ_INTERVAL_FLOOR_PROCESS_METRICS
var containerSamplers []metrics.ContainerSampler
if hasConfig {
cfg := ctx.Config()
ttlSecs = cfg.ContainerMetadataCacheLimit
apiVersion = cfg.DockerApiVersion
dockerContainerdNamespace = cfg.DockerContainerdNamespace
interval = cfg.MetricsProcessSampleRate
}

if (hasConfig && ctx.Config().ProcessContainerDecoration) || !hasConfig {
containerSamplers = containerSamplerGetter(time.Duration(ttlSecs)*time.Second, apiVersion, dockerContainerdNamespace)
}

harvester := newHarvester(ctx)
containerSamplers := metrics.GetContainerSamplers(time.Duration(ttlSecs)*time.Second, apiVersion, dockerContainerdNamespace)

return &processSampler{
harvest: harvester,
Expand Down
70 changes: 65 additions & 5 deletions pkg/metrics/process/sampler_darwin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ package process

import (
"errors"
"testing"

"github.com/newrelic/infrastructure-agent/pkg/metrics"
"testing"
"time"

"github.com/newrelic/infrastructure-agent/internal/agent/mocks"
"github.com/newrelic/infrastructure-agent/pkg/config"
Expand All @@ -18,7 +18,7 @@ import (
func TestProcessSampler_Sample(t *testing.T) {
ctx := new(mocks.AgentContext)
cfg := &config.Config{RunMode: config.ModeRoot}
ctx.On("Config").Times(3).Return(cfg)
ctx.On("Config").Times(4).Return(cfg)

harvester := &HarvesterMock{}
sampler := NewProcessSampler(ctx).(*processSampler)
Expand Down Expand Up @@ -61,7 +61,7 @@ func TestProcessSampler_Sample(t *testing.T) {
func TestProcessSampler_Sample_ErrorOnProcessShouldNotStop(t *testing.T) {
ctx := new(mocks.AgentContext)
cfg := &config.Config{RunMode: config.ModeRoot}
ctx.On("Config").Times(3).Return(cfg)
ctx.On("Config").Times(4).Return(cfg)

harvester := &HarvesterMock{}
sampler := NewProcessSampler(ctx).(*processSampler)
Expand Down Expand Up @@ -108,7 +108,7 @@ func TestProcessSampler_Sample_ErrorOnProcessShouldNotStop(t *testing.T) {
func TestProcessSampler_Sample_DockerDecorator(t *testing.T) {
ctx := new(mocks.AgentContext)
cfg := &config.Config{RunMode: config.ModeRoot}
ctx.On("Config").Times(3).Return(cfg)
ctx.On("Config").Times(4).Return(cfg)

harvester := &HarvesterMock{}
sampler := NewProcessSampler(ctx).(*processSampler)
Expand Down Expand Up @@ -153,3 +153,63 @@ func TestProcessSampler_Sample_DockerDecorator(t *testing.T) {

mock.AssertExpectationsForObjects(t, ctx, harvester)
}

//nolint:paralleltest
func TestProcessSampler_Sample_DisabledDockerDecorator(t *testing.T) {
ctx := new(mocks.AgentContext)
cfg := config.NewConfig()
cfg.ProcessContainerDecoration = false
ctx.On("Config").Times(4).Return(cfg)

// The container sampler getter should not be called
containerSamplerGetter = func(cacheTTL time.Duration, dockerAPIVersion, dockerContainerdNamespace string) []metrics.ContainerSampler {
t.Errorf("containerSamplerGetter should not be called")

return nil
}

defer func() {
containerSamplerGetter = metrics.GetContainerSamplers
}()

var expected []metrics.ContainerSampler
sampler := NewProcessSampler(ctx).(*processSampler) //nolint:forcetypeassert
assert.Equal(t, expected, sampler.containerSamplers)
}

//nolint:paralleltest
func TestProcessSampler_Sample_DockerDecoratorEnabledByDefault(t *testing.T) {
ctx := new(mocks.AgentContext)
cfg := config.NewConfig()
ctx.On("Config").Times(4).Return(cfg)

containerSamplerGetter = func(cacheTTL time.Duration, dockerAPIVersion, dockerContainerdNamespace string) []metrics.ContainerSampler {
return []metrics.ContainerSampler{&fakeContainerSampler{}}
}

defer func() {
containerSamplerGetter = metrics.GetContainerSamplers
}()

expected := []metrics.ContainerSampler{&fakeContainerSampler{}}
sampler := NewProcessSampler(ctx).(*processSampler) //nolint:forcetypeassert
assert.Equal(t, expected, sampler.containerSamplers)
}

//nolint:paralleltest
func TestProcessSampler_Sample_DockerDecoratorEnabledWithNoConfig(t *testing.T) {
ctx := new(mocks.AgentContext)
ctx.On("Config").Times(2).Return(nil)

containerSamplerGetter = func(cacheTTL time.Duration, dockerAPIVersion, dockerContainerdNamespace string) []metrics.ContainerSampler {
return []metrics.ContainerSampler{&fakeContainerSampler{}}
}

defer func() {
containerSamplerGetter = metrics.GetContainerSamplers
}()

expected := []metrics.ContainerSampler{&fakeContainerSampler{}}
sampler := NewProcessSampler(ctx).(*processSampler) //nolint:forcetypeassert
assert.Equal(t, expected, sampler.containerSamplers)
}
8 changes: 7 additions & 1 deletion pkg/metrics/process/sampler_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type processSampler struct {
var (
_ sampler.Sampler = (*processSampler)(nil) // static interface assertion
containerNotRunningErrs = map[string]struct{}{}
containerSamplerGetter = metrics.GetContainerSamplers //nolint:gochecknoglobals
)

// NewProcessSampler creates and returns a new process Sampler, given an agent context.
Expand All @@ -41,16 +42,21 @@ func NewProcessSampler(ctx agent.AgentContext) sampler.Sampler {
apiVersion := ""
dockerContainerdNamespace := ""
interval := config.FREQ_INTERVAL_FLOOR_PROCESS_METRICS
var containerSamplers []metrics.ContainerSampler
if hasConfig {
cfg := ctx.Config()
ttlSecs = cfg.ContainerMetadataCacheLimit
apiVersion = cfg.DockerApiVersion
dockerContainerdNamespace = cfg.DockerContainerdNamespace
interval = cfg.MetricsProcessSampleRate
}

if (hasConfig && ctx.Config().ProcessContainerDecoration) || !hasConfig {
containerSamplers = containerSamplerGetter(time.Duration(ttlSecs)*time.Second, apiVersion, dockerContainerdNamespace)
}

cache := newCache()
harvest := newHarvester(ctx, &cache)
containerSamplers := metrics.GetContainerSamplers(time.Duration(ttlSecs)*time.Second, apiVersion, dockerContainerdNamespace)

return &processSampler{
harvest: harvest,
Expand Down
61 changes: 61 additions & 0 deletions pkg/metrics/process/sampler_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
Expand Down Expand Up @@ -67,6 +68,66 @@ func TestProcessSampler_DockerDecorator(t *testing.T) {
}
}

//nolint:paralleltest
func TestProcessSampler_Sample_DisabledDockerDecorator(t *testing.T) {
ctx := new(mocks.AgentContext)
cfg := config.NewConfig()
cfg.ProcessContainerDecoration = false
ctx.On("Config").Times(4).Return(cfg)

// The container sampler getter should not be called
containerSamplerGetter = func(cacheTTL time.Duration, dockerAPIVersion, dockerContainerdNamespace string) []metrics.ContainerSampler {
t.Errorf("containerSamplerGetter should not be called")

return nil
}

defer func() {
containerSamplerGetter = metrics.GetContainerSamplers
}()

var expected []metrics.ContainerSampler
sampler := NewProcessSampler(ctx).(*processSampler) //nolint:forcetypeassert
assert.Equal(t, expected, sampler.containerSamplers)
}

//nolint:paralleltest
func TestProcessSampler_Sample_DockerDecoratorEnabledByDefault(t *testing.T) {
ctx := new(mocks.AgentContext)
cfg := config.NewConfig()
ctx.On("Config").Times(4).Return(cfg)

containerSamplerGetter = func(cacheTTL time.Duration, dockerAPIVersion, dockerContainerdNamespace string) []metrics.ContainerSampler {
return []metrics.ContainerSampler{&fakeContainerSampler{}}
}

defer func() {
containerSamplerGetter = metrics.GetContainerSamplers
}()

expected := []metrics.ContainerSampler{&fakeContainerSampler{}}
sampler := NewProcessSampler(ctx).(*processSampler) //nolint:forcetypeassert
assert.Equal(t, expected, sampler.containerSamplers)
}

//nolint:paralleltest
func TestProcessSampler_Sample_DockerDecoratorEnabledWithNoConfig(t *testing.T) {
ctx := new(mocks.AgentContext)
ctx.On("Config").Times(2).Return(nil)

containerSamplerGetter = func(cacheTTL time.Duration, dockerAPIVersion, dockerContainerdNamespace string) []metrics.ContainerSampler {
return []metrics.ContainerSampler{&fakeContainerSampler{}}
}

defer func() {
containerSamplerGetter = metrics.GetContainerSamplers
}()

expected := []metrics.ContainerSampler{&fakeContainerSampler{}}
sampler := NewProcessSampler(ctx).(*processSampler) //nolint:forcetypeassert
assert.Equal(t, expected, sampler.containerSamplers)
}

type harvesterMock struct {
samples map[int32]*types.ProcessSample
}
Expand Down
13 changes: 11 additions & 2 deletions pkg/metrics/procs_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ var (
// https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-queryfullprocessimagenamew
queryFullProcessImageName = modkernel32.NewProc("QueryFullProcessImageNameW")
containerNotRunningErrs = map[string]struct{}{}
containerSamplerGetter = GetContainerSamplers //nolint:gochecknoglobals
)

const (
Expand Down Expand Up @@ -347,7 +348,10 @@ func NewProcsMonitor(context agent.AgentContext) *ProcsMonitor {
)
ttlSecs := config.DefaultContainerCacheMetadataLimit
getProcFunc := getWin32Proc
if context != nil && context.Config() != nil {
var containerSamplers []ContainerSampler
hasConfig := context != nil && context.Config() != nil

if hasConfig {
if len(context.Config().AllowedListProcessSample) > 0 {
allowedListProcessing = true
for _, processName := range context.Config().AllowedListProcessSample {
Expand All @@ -362,10 +366,15 @@ func NewProcsMonitor(context agent.AgentContext) *ProcsMonitor {
getProcFunc = getWin32ProcFromWMI
}
}

if (hasConfig && context.Config().ProcessContainerDecoration) || !hasConfig {
containerSamplers = containerSamplerGetter(time.Duration(ttlSecs)*time.Second, apiVersion, dockerContainerdNamespace)
}

return &ProcsMonitor{
context: context,
procCache: make(map[string]*ProcessCacheEntry),
containerSamplers: GetContainerSamplers(time.Duration(ttlSecs)*time.Second, apiVersion, dockerContainerdNamespace),
containerSamplers: containerSamplers,
previousProcessTimes: make(map[string]*SystemTimes),
processInterrogator: NewInternalProcessInterrogator(true),
waitForCleanup: &sync.WaitGroup{},
Expand Down
Loading

0 comments on commit 1673648

Please sign in to comment.