Skip to content

Commit

Permalink
deps: Upgrade opamp v0.17.0 (#1906)
Browse files Browse the repository at this point in the history
* update opamp to v0.14.0

* properly handle agent ID

* Pass to bindplane with header specifying format

* Bump opamp-go to v0.17.0

* bump to opamp-go v0.17.0

* add reports heartbeat capability

* Add tests for agent ID parsing

* lint

* Remove reports heartbeat capability
  • Loading branch information
BinaryFissionGames authored Oct 24, 2024
1 parent 60b47c4 commit f37e810
Show file tree
Hide file tree
Showing 15 changed files with 415 additions and 116 deletions.
30 changes: 23 additions & 7 deletions cmd/collector/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ import (
"strconv"
_ "time/tzdata"

"github.com/google/uuid"
"github.com/observiq/bindplane-agent/collector"
"github.com/observiq/bindplane-agent/internal/logging"
"github.com/observiq/bindplane-agent/internal/service"
"github.com/observiq/bindplane-agent/internal/version"
"github.com/observiq/bindplane-agent/opamp"
"github.com/oklog/ulid/v2"
"github.com/spf13/pflag"
"go.uber.org/zap"
"gopkg.in/yaml.v3"
Expand Down Expand Up @@ -179,9 +179,19 @@ func checkManagerConfig(configPath *string) error {
return statErr
}

newConfig.AgentID, ok = os.LookupEnv(agentIDENV)
if !ok {
newConfig.AgentID = ulid.Make().String()
if envString, ok := os.LookupEnv(agentIDENV); ok {
var err error
newConfig.AgentID, err = opamp.ParseAgentID(envString)
if err != nil {
return fmt.Errorf("invalid agent ID in env %q: %w", agentIDENV, err)
}
} else {
u, err := uuid.NewV7()
if err != nil {
return fmt.Errorf("new uuidv7: %w", err)
}

newConfig.AgentID = opamp.AgentIDFromUUID(u)
}

if sk, ok := os.LookupEnv(secretkeyENV); ok {
Expand Down Expand Up @@ -231,12 +241,18 @@ func ensureIdentity(configPath string) error {
return fmt.Errorf("unable to interpret config file: %w", err)
}

// If the AgentID is not a ULID (legacy ID or empty) then we need to generate a ULID as the AgentID.
if _, err := ulid.Parse(candidateConfig.AgentID); err == nil {
// If the AgentID is empty then we need to generate a new ID as the AgentID.
if candidateConfig.AgentID != opamp.EmptyAgentID {
return nil
}

candidateConfig.AgentID = ulid.Make().String()
u, err := uuid.NewV7()
if err != nil {
return fmt.Errorf("new uuidv7: %w", err)
}

candidateConfig.AgentID = opamp.AgentIDFromUUID(u)

newBytes, err := yaml.Marshal(candidateConfig)
if err != nil {
return fmt.Errorf("failed to marshal sanitized config: %w", err)
Expand Down
32 changes: 17 additions & 15 deletions cmd/collector/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package main
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
Expand All @@ -30,6 +29,14 @@ import (
"gopkg.in/yaml.v3"
)

// Must is a helper function for tests that panics if there is an error creating the object of type T
func Must[T any](t T, err error) T {
if err != nil {
panic(err)
}
return t
}

func TestGetDefaultCollectorConfigPathENV(t *testing.T) {
fakeConfigPath := "./fake/path/config.yaml"

Expand Down Expand Up @@ -99,7 +106,7 @@ func TestCheckManagerConfigNoFile(t *testing.T) {

t.Setenv(agentNameENV, "agent name")

t.Setenv(agentIDENV, "agent ID")
t.Setenv(agentIDENV, "01HX2DWEQZ045KQR3VG0EYEZ94")

t.Setenv(secretkeyENV, "secretKey")

Expand All @@ -113,7 +120,7 @@ func TestCheckManagerConfigNoFile(t *testing.T) {
actual, _ := opamp.ParseConfig(manager)
expected := &opamp.Config{
Endpoint: "0.0.0.0",
AgentID: "agent ID",
AgentID: Must(opamp.ParseAgentID("01HX2DWEQZ045KQR3VG0EYEZ94")),
AgentName: new(string),
SecretKey: new(string),
Labels: new(string),
Expand Down Expand Up @@ -244,23 +251,20 @@ func TestManagerConfigNoAgentIDWillSet(t *testing.T) {
err := checkManagerConfig(&manager)
require.NoError(t, err)

cfgBytes, err := ioutil.ReadFile(manager)
cfgBytes, err := os.ReadFile(manager)
require.NoError(t, err)

var config opamp.Config
require.NoError(t, yaml.Unmarshal(cfgBytes, &config))
require.NotEmpty(t, config.AgentID)
ulidID, err := ulid.Parse(config.AgentID)
require.NoError(t, err)
require.NotEmpty(t, ulidID)
require.NotEqual(t, opamp.EmptyAgentID, config.AgentID)
}

// TestManagerConfigWillNotOverwriteCurrentAgentID tests that if the agent ID is a ULID it will not overwrite it
func TestManagerConfigWillNotOverwriteCurrentAgentID(t *testing.T) {
tmpDir := t.TempDir()
manager := filepath.Join(tmpDir, "manager.yaml")

id := ulid.Make().String()
id := ulid.Make()
data := []byte(fmt.Sprintf(`
---
agent_id: %s
Expand All @@ -269,12 +273,12 @@ agent_id: %s
err := checkManagerConfig(&manager)
require.NoError(t, err)

cfgBytes, err := ioutil.ReadFile(manager)
cfgBytes, err := os.ReadFile(manager)
require.NoError(t, err)

var config opamp.Config
require.NoError(t, yaml.Unmarshal(cfgBytes, &config))
require.Equal(t, config.AgentID, id)
require.Equal(t, config.AgentID.String(), id.String())
}

// TestManagerConfigWillUpdateLegacyAgentID tests that if the agent ID is a Legacy ID (UUID format) it will overwrite with a new ULID
Expand All @@ -291,14 +295,12 @@ agent_id: %s
err := checkManagerConfig(&manager)
require.NoError(t, err)

cfgBytes, err := ioutil.ReadFile(manager)
cfgBytes, err := os.ReadFile(manager)
require.NoError(t, err)

var config opamp.Config
require.NoError(t, yaml.Unmarshal(cfgBytes, &config))
_, err = ulid.Parse(config.AgentID)
require.NoError(t, err)
require.NotEqual(t, config.AgentID, legacyID)
require.NotEqual(t, opamp.EmptyAgentID, config.AgentID)
}

func TestManagerConfigWillErrorOnInvalidOpAmpConfig(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ require (
github.com/observiq/bindplane-agent/receiver/sapnetweaverreceiver v1.63.0
github.com/observiq/bindplane-agent/receiver/telemetrygeneratorreceiver v1.63.0
github.com/oklog/ulid/v2 v2.1.0
github.com/open-telemetry/opamp-go v0.14.0
github.com/open-telemetry/opamp-go v0.17.0
github.com/open-telemetry/opentelemetry-collector-contrib/connector/countconnector v0.111.0
github.com/open-telemetry/opentelemetry-collector-contrib/connector/routingconnector v0.111.0
github.com/open-telemetry/opentelemetry-collector-contrib/connector/servicegraphconnector v0.111.0
Expand Down Expand Up @@ -592,7 +592,7 @@ require (
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
github.com/gophercloud/gophercloud v1.13.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/gosnmp/gosnmp v1.38.0 // indirect
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect
github.com/grobie/gomemcache v0.0.0-20230213081705-239240bbc445 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1511,8 +1511,8 @@ github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7Fsg
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gosnmp/gosnmp v1.38.0 h1:I5ZOMR8kb0DXAFg/88ACurnuwGwYkXWq3eLpJPHMEYc=
github.com/gosnmp/gosnmp v1.38.0/go.mod h1:FE+PEZvKrFz9afP9ii1W3cprXuVZ17ypCcyyfYuu5LY=
github.com/grafana/loki/pkg/push v0.0.0-20240514112848-a1b1eeb09583 h1:dN3eF1S5fvVu2l9WoqYSvmNmPK8Uh2vjE4yUsBq80l4=
Expand Down Expand Up @@ -1914,8 +1914,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/open-telemetry/opamp-go v0.14.0 h1:KoziIK+wsFojhUXNTkCSTnCPf0eCMqFAaccOs0HrWIY=
github.com/open-telemetry/opamp-go v0.14.0/go.mod h1:XOGCigljsLSTZ8FfLwvat0M1QDj3conIIgRa77BWrKs=
github.com/open-telemetry/opamp-go v0.17.0 h1:3R4+B/6Sy8mknLBbzO3gqloqwTT02rCSRcr4ac2B124=
github.com/open-telemetry/opamp-go v0.17.0/go.mod h1:SGDhUoAx7uGutO4ENNMQla/tiSujxgZmMPJXIOPGBdk=
github.com/open-telemetry/opentelemetry-collector-contrib/connector/countconnector v0.111.0 h1:YRtg8O1y//TsNeVaQcorIL6ha0NnTKdma9Tux8pfklg=
github.com/open-telemetry/opentelemetry-collector-contrib/connector/countconnector v0.111.0/go.mod h1:izISYDkhEvgYXi/8gQAJvXxkFThk5AvN5M5FdCmxtyA=
github.com/open-telemetry/opentelemetry-collector-contrib/connector/datadogconnector v0.111.0 h1:GZgIPUBQisxljpN9hLHD4X8eNUBOXZFP+4s3Hwn5YY4=
Expand Down
110 changes: 109 additions & 1 deletion opamp/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import (
"path/filepath"
"time"

"github.com/google/uuid"
"github.com/oklog/ulid/v2"
"github.com/open-telemetry/opamp-go/client/types"
"gopkg.in/yaml.v3"
)

Expand All @@ -47,11 +50,116 @@ var (
errInvalidCAFile = "failed to read TLS CA file"
)

type agentIDType string

const (
agentIDTypeULID agentIDType = "ULID"
agentIDTypeUUID agentIDType = "UUID"
)

// AgentID represents the ID of the agent
type AgentID struct {
by [16]byte
idType agentIDType
orig string
}

// EmptyAgentID represents an empty/unset agent ID.
var EmptyAgentID = AgentID{}

// ParseAgentID parses an agent ID from the given string
func ParseAgentID(s string) (AgentID, error) {
switch len(s) {
case 26:
// length 26 strings can't be UUID, so they must be ULID
u, err := ulid.Parse(s)
if err != nil {
return AgentID{}, fmt.Errorf("parse ulid: %w", err)
}
return AgentID{
by: u,
idType: agentIDTypeULID,
orig: s,
}, nil

default:
// Try parsing as a UUID. There are a couple forms of UUID supported for parsing, so they may be a couple different
// lengths
u, err := uuid.Parse(s)
if err != nil {
return AgentID{}, fmt.Errorf("parse uuid: %w", err)
}
return AgentID{
by: u,
idType: agentIDTypeUUID,
orig: s,
}, nil
}
}

// AgentIDFromUUID creates an agent ID from a generated UUID.
// See ParseAgentID for parsing a UUID string.
func AgentIDFromUUID(u uuid.UUID) AgentID {
return AgentID{
by: u,
idType: agentIDTypeUUID,
orig: u.String(),
}
}

// String returns a string representation of the agent ID
func (a AgentID) String() string {
return a.orig
}

// OpAMPInstanceUID returns the opamp representation of the agent ID
func (a AgentID) OpAMPInstanceUID() types.InstanceUid {
return types.InstanceUid(a.by)
}

// Type returns the string type of the agent ID (ULID, UUID) as it should
// be reported to BindPlane.
func (a AgentID) Type() string {
return string(a.idType)
}

// MarshalYAML implements the yaml.Marshaler interface
func (a AgentID) MarshalYAML() (any, error) {
return a.String(), nil
}

// UnmarshalYAML implements the yaml.Unmarshaler interface
func (a *AgentID) UnmarshalYAML(unmarshal func(any) error) error {
var s string

err := unmarshal(&s)
if err != nil {
return err
}

if s == "" {
// Empty string = keep the 0 value
return nil
}

u, err := ParseAgentID(s)
if err != nil {
// In order to maintain backwards compatability, we don't error here.
// Instead, in main, we will regenerate a new agent ID
*a = EmptyAgentID
return nil
}

*a = AgentID(u)

return nil
}

// Config contains the configuration for the collector to communicate with an OpAmp enabled platform.
type Config struct {
Endpoint string `yaml:"endpoint"`
SecretKey *string `yaml:"secret_key,omitempty"`
AgentID string `yaml:"agent_id"`
AgentID AgentID `yaml:"agent_id"`
TLS *TLSConfig `yaml:"tls_config,omitempty"`

// Updatable fields
Expand Down
Loading

0 comments on commit f37e810

Please sign in to comment.