forked from newrelic/infrastructure-agent
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add config Protocol (newrelic#472)
* feat: Add config protocol package * Add config context * integrate config protocol into manager * feat: add recurisive spawn test * test: add v4 payload test * feat: implement builder pattern to support multiple versiconfig protocol versions * feat: implement builder pattern to support multiple versiconfig protocol versions * feat: add performance tests & making use of json unmarshal instead of the regExp pattern * fix: return config entry array * test: skip manager test if windows * feat: add validate function to cfg protocol * core: move protocol example to v1 * test: add protocol validate ut * core: improve log naming * test: add handlelines UT * Implement config repository, by adding the below features: - It provides a cache implementation to skip duplicated definitions per config. - Children processes are kiled when the parent is terminated. * feat: add support for update the set of definitions for a cofnig * feat: add support for identify which definition must be deleted * feat: terminate integrations from handler * fix: hash the identifiers component of the definition * core: fix import order * test: add handler UT * fix: race condition on cache * refactor: cache interface func * test: fix test race condition * test: skip runner test for windows * refactor: rename YAMLConfig variable * doc: adds description to cache package Co-authored-by: ivancorrales <[email protected]>
- Loading branch information
1 parent
baf8142
commit 2d9ceb2
Showing
29 changed files
with
1,174 additions
and
102 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
// Copyright 2020 New Relic Corporation. All rights reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
package cache | ||
|
||
import ( | ||
"sync" | ||
|
||
"github.com/newrelic/infrastructure-agent/internal/integrations/v4/integration" | ||
) | ||
|
||
// Cache stores integrations definitions grouped by a Config Name. | ||
type Cache interface { | ||
GetDefinitions(cfgName string) []integration.Definition | ||
ListConfigNames() []string | ||
ApplyConfig(cfgDefinitions *ConfigDefinitions) []string | ||
TakeConfig(cfgName string) *ConfigDefinitions | ||
} | ||
|
||
type ConfigDefinitions struct { | ||
cfgName string | ||
added map[string]integration.Definition | ||
current map[string]struct{} | ||
} | ||
|
||
func (cfgDefinition *ConfigDefinitions) Add(def integration.Definition) bool { | ||
dh := def.Hash() | ||
cfgDefinition.added[dh] = def | ||
_, ok := cfgDefinition.current[dh] | ||
return !ok | ||
} | ||
|
||
// cache implements Cache to store integrations definitions by config protocols request names | ||
type cache struct { | ||
lock sync.RWMutex | ||
hashes map[string]map[string]struct{} | ||
definitions map[string]integration.Definition | ||
} | ||
|
||
// CreateCache initialize and return an empty cache | ||
func CreateCache() Cache { | ||
return &cache{ | ||
hashes: make(map[string]map[string]struct{}), | ||
definitions: make(map[string]integration.Definition), | ||
} | ||
} | ||
|
||
// addDefinition adds a integration definition to a cfg name group, returns false if already exists. | ||
func (c *cache) addDefinition(cfgName string, definition integration.Definition) bool { | ||
hash := definition.Hash() | ||
if _, ok := c.hashes[cfgName][hash]; ok { | ||
return false | ||
} | ||
if _, ok := c.hashes[cfgName]; !ok { | ||
c.hashes[cfgName] = make(map[string]struct{}) | ||
} | ||
c.hashes[cfgName][hash] = struct{}{} | ||
c.definitions[hash] = definition | ||
return true | ||
} | ||
|
||
// ListConfigNames returns a list of config names | ||
func (c *cache) ListConfigNames() []string { | ||
c.lock.RLock() | ||
defer c.lock.RUnlock() | ||
output := make([]string, len(c.hashes)) | ||
i := 0 | ||
for cfgName := range c.hashes { | ||
output[i] = cfgName | ||
i++ | ||
} | ||
return output | ||
} | ||
|
||
func (c *cache) getHashes(cfgName string) map[string]struct{} { | ||
return c.hashes[cfgName] | ||
} | ||
|
||
// GetDefinitions returns a list of integration definitions for a particular config name. | ||
func (c *cache) GetDefinitions(cfgName string) []integration.Definition { | ||
c.lock.RLock() | ||
defer c.lock.RUnlock() | ||
cfg := c.hashes[cfgName] | ||
output := make([]integration.Definition, len(cfg)) | ||
i := 0 | ||
for hash := range cfg { | ||
output[i] = c.definitions[hash] | ||
i++ | ||
} | ||
return output | ||
} | ||
|
||
// ApplyConfig sync the integrations definitions for a particular config name with the added definitions in cfgDefinitions. | ||
// returns a list of removed definitions for the config name. | ||
func (c *cache) ApplyConfig(cfgDefinitions *ConfigDefinitions) []string { | ||
c.lock.Lock() | ||
defer c.lock.Unlock() | ||
toBeDeleted := make([]string, 0) | ||
for hash, definition := range cfgDefinitions.added { | ||
if _, ok := c.hashes[cfgDefinitions.cfgName][hash]; !ok { | ||
c.addDefinition(cfgDefinitions.cfgName, definition) | ||
} | ||
} | ||
for hash := range cfgDefinitions.current { | ||
if _, ok := cfgDefinitions.added[hash]; !ok { | ||
delete(c.definitions, hash) | ||
delete(c.hashes[cfgDefinitions.cfgName], hash) | ||
toBeDeleted = append(toBeDeleted, hash) | ||
} | ||
} | ||
return toBeDeleted | ||
} | ||
|
||
// TakeConfig returns a ConfigDefinitions initialized for a particular config name | ||
func (c *cache) TakeConfig(cfgName string) *ConfigDefinitions { | ||
c.lock.RLock() | ||
defer c.lock.RUnlock() | ||
return &ConfigDefinitions{ | ||
cfgName: cfgName, | ||
added: make(map[string]integration.Definition), | ||
current: c.getHashes(cfgName), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package cache | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/newrelic/infrastructure-agent/internal/integrations/v4/integration" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func createIntegrationDefinition(name string) integration.Definition { | ||
return integration.Definition{ | ||
Name: name, | ||
} | ||
} | ||
|
||
func Test_createCache(t *testing.T) { | ||
c := CreateCache() | ||
assert.NotNil(t, c) | ||
assert.Empty(t, c.ListConfigNames()) | ||
assert.Empty(t, c.GetDefinitions("cfg")) | ||
|
||
def := createIntegrationDefinition("def") | ||
initialCfg := &ConfigDefinitions{ | ||
cfgName: "cfg", | ||
added: map[string]integration.Definition{ | ||
def.Hash(): def, | ||
}, | ||
} | ||
|
||
assert.Empty(t, c.ApplyConfig(initialCfg)) | ||
definitions := c.GetDefinitions("cfg") | ||
require.Len(t, definitions, 1) | ||
assert.Equal(t, "def", definitions[0].Name) | ||
|
||
cd := c.TakeConfig("cfg") | ||
for hash := range cd.current { | ||
assert.Equal(t, def.Hash(), hash) | ||
} | ||
|
||
} | ||
|
||
func Test_definitionsChange(t *testing.T) { | ||
c := CreateCache() | ||
def := createIntegrationDefinition("def") | ||
def2 := createIntegrationDefinition("def2") | ||
def3 := createIntegrationDefinition("def3") | ||
def4 := createIntegrationDefinition("def4") | ||
|
||
initialCfg := &ConfigDefinitions{ | ||
cfgName: "cfg1", | ||
added: map[string]integration.Definition{ | ||
def.Hash(): def, | ||
def2.Hash(): def2, | ||
def3.Hash(): def3, | ||
}, | ||
} | ||
assert.Empty(t, c.ApplyConfig(initialCfg)) | ||
definitionsList := c.GetDefinitions("cfg1") | ||
for _, def := range c.GetDefinitions("cfg1") { | ||
assert.Contains(t, []string{"def", "def2", "def3"}, def.Name) | ||
} | ||
assert.Len(t, definitionsList, 3) | ||
|
||
cfgDefinitions := c.TakeConfig("cfg1") | ||
assert.False(t, cfgDefinitions.Add(def)) | ||
assert.False(t, cfgDefinitions.Add(def2)) | ||
assert.True(t, cfgDefinitions.Add(def4)) | ||
|
||
toBeDeleted := c.ApplyConfig(cfgDefinitions) | ||
definitionsList = c.GetDefinitions("cfg1") | ||
assert.Len(t, definitionsList, 3) | ||
for _, def := range c.GetDefinitions("cfg1") { | ||
assert.Contains(t, []string{"def", "def2", "def4"}, def.Name) | ||
} | ||
assert.Equal(t, []string{def3.Hash()}, toBeDeleted) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/usr/bin/env sh | ||
|
||
echo $STDOUT_STRING | ||
>&2 echo $STDERR_STRING |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.