-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add node id/name to config #17750
Add node id/name to config #17750
Changes from 10 commits
45b1ceb
0701d01
507286f
1d0b2dd
f2eb143
6fd48dd
c70fe10
3f8550e
80ff6d3
896e04e
d50a6ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -313,9 +313,14 @@ func (t *TelemetryConfig) Enabled() (string, bool) { | |
} | ||
|
||
// DefaultLabels returns a set of <key, value> string pairs that must be added as attributes to all exported telemetry data. | ||
func (t *TelemetryConfig) DefaultLabels(nodeID string) map[string]string { | ||
labels := map[string]string{ | ||
"node_id": nodeID, // used to delineate Consul nodes in graphs | ||
func (t *TelemetryConfig) DefaultLabels(cfg config.CloudConfig) map[string]string { | ||
labels := make(map[string]string) | ||
jmurret marked this conversation as resolved.
Show resolved
Hide resolved
|
||
nodeID := string(cfg.NodeID) | ||
if nodeID != "" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: don't think this should ever be empty since it gets generated in setup.go! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah just being safe here. |
||
labels["node_id"] = nodeID | ||
} | ||
if cfg.NodeName != "" { | ||
labels["node_name"] = cfg.NodeName | ||
} | ||
|
||
for k, v := range t.Labels { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package client | ||
|
||
type MockMetricsClient struct { | ||
MetricsClient | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,7 +14,6 @@ import ( | |
"github.com/hashicorp/consul/agent/hcp/config" | ||
"github.com/hashicorp/consul/agent/hcp/scada" | ||
"github.com/hashicorp/consul/agent/hcp/telemetry" | ||
"github.com/hashicorp/consul/types" | ||
"github.com/hashicorp/go-hclog" | ||
) | ||
|
||
|
@@ -25,18 +24,28 @@ type Deps struct { | |
Sink metrics.MetricSink | ||
} | ||
|
||
func NewDeps(cfg config.CloudConfig, logger hclog.Logger, nodeID types.NodeID) (Deps, error) { | ||
func NewDeps(cfg config.CloudConfig, logger hclog.Logger) (Deps, error) { | ||
logger = logger.Named("sink") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: moving this up here would make the Scada init logs have a named prefix of |
||
ctx := context.Background() | ||
ctx = hclog.WithContext(ctx, logger) | ||
|
||
client, err := hcpclient.NewClient(cfg) | ||
if err != nil { | ||
return Deps{}, fmt.Errorf("failed to init client: %w:", err) | ||
return Deps{}, fmt.Errorf("failed to init client: %w", err) | ||
} | ||
|
||
provider, err := scada.New(cfg, logger.Named("scada")) | ||
if err != nil { | ||
return Deps{}, fmt.Errorf("failed to init scada: %w", err) | ||
} | ||
|
||
sink := sink(client, &cfg, logger.Named("sink"), nodeID) | ||
metricsClient, err := hcpclient.NewMetricsClient(ctx, &cfg) | ||
if err != nil { | ||
logger.Error("failed to init metrics client", "error", err) | ||
return Deps{}, fmt.Errorf("failed to init metrics client: %w", err) | ||
} | ||
|
||
sink := sink(ctx, client, metricsClient, cfg) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pulling out the metrics client instantion allows us to pass the configuration in as a CloudConfig instead of an interface as is done for the NewMetricsClient. This allows us to actually access configuration values stored in the config struct. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good. We could honestly even remove the interface for the MetricsClient. In my initial implementation, it felt like the easiest way to test, but I have some alternate ideas. We could do that in a follow up PR maybe! Ideally we also cleanup / refactor and test the config object (a rabbit hole :p)! |
||
|
||
return Deps{ | ||
Client: client, | ||
|
@@ -48,10 +57,13 @@ func NewDeps(cfg config.CloudConfig, logger hclog.Logger, nodeID types.NodeID) ( | |
// sink provides initializes an OTELSink which forwards Consul metrics to HCP. | ||
// The sink is only initialized if the server is registered with the management plane (CCM). | ||
// This step should not block server initialization, so errors are logged, but not returned. | ||
func sink(hcpClient hcpclient.Client, cfg hcpclient.CloudConfig, logger hclog.Logger, nodeID types.NodeID) metrics.MetricSink { | ||
ctx := context.Background() | ||
ctx = hclog.WithContext(ctx, logger) | ||
|
||
func sink( | ||
ctx context.Context, | ||
hcpClient hcpclient.Client, | ||
metricsClient hcpclient.MetricsClient, | ||
cfg config.CloudConfig, | ||
) metrics.MetricSink { | ||
logger := hclog.FromContext(ctx) | ||
reqCtx, cancel := context.WithTimeout(ctx, 5*time.Second) | ||
defer cancel() | ||
|
||
|
@@ -72,16 +84,10 @@ func sink(hcpClient hcpclient.Client, cfg hcpclient.CloudConfig, logger hclog.Lo | |
return nil | ||
} | ||
|
||
metricsClient, err := hcpclient.NewMetricsClient(cfg, ctx) | ||
if err != nil { | ||
logger.Error("failed to init metrics client", "error", err) | ||
return nil | ||
} | ||
|
||
sinkOpts := &telemetry.OTELSinkOpts{ | ||
Ctx: ctx, | ||
Reader: telemetry.NewOTELReader(metricsClient, u, telemetry.DefaultExportInterval), | ||
Labels: telemetryCfg.DefaultLabels(string(nodeID)), | ||
Labels: telemetryCfg.DefaultLabels(cfg), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this correct? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we build up the labels based off the configuration passed in. Likely we will need more configuration values in the future so I opted to pass the whole cfg object now so as more are requested we can just update the cfg and the key inside the DefaultLabels func |
||
Filters: telemetryCfg.MetricsConfig.Filters, | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,11 @@ | ||
package hcp | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/hashicorp/go-hclog" | ||
"github.com/hashicorp/consul/agent/hcp/config" | ||
"github.com/stretchr/testify/mock" | ||
"github.com/stretchr/testify/require" | ||
|
||
|
@@ -16,7 +17,7 @@ func TestSink(t *testing.T) { | |
t.Parallel() | ||
for name, test := range map[string]struct { | ||
expect func(*client.MockClient) | ||
mockCloudCfg client.CloudConfig | ||
cloudCfg config.CloudConfig | ||
expectedSink bool | ||
}{ | ||
"success": { | ||
|
@@ -28,7 +29,10 @@ func TestSink(t *testing.T) { | |
}, | ||
}, nil) | ||
}, | ||
mockCloudCfg: client.MockCloudCfg{}, | ||
cloudCfg: config.CloudConfig{ | ||
NodeID: types.NodeID("nodeyid"), | ||
NodeName: "nodey", | ||
}, | ||
expectedSink: true, | ||
}, | ||
"noSinkWhenServerNotRegisteredWithCCM": { | ||
|
@@ -40,26 +44,13 @@ func TestSink(t *testing.T) { | |
}, | ||
}, nil) | ||
}, | ||
mockCloudCfg: client.MockCloudCfg{}, | ||
cloudCfg: config.CloudConfig{}, | ||
}, | ||
"noSinkWhenCCMVerificationFails": { | ||
expect: func(mockClient *client.MockClient) { | ||
mockClient.EXPECT().FetchTelemetryConfig(mock.Anything).Return(nil, fmt.Errorf("fetch failed")) | ||
}, | ||
mockCloudCfg: client.MockCloudCfg{}, | ||
}, | ||
"noSinkWhenMetricsClientInitFails": { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This no longer applies since we don't initialize the metrics client inside the sink. |
||
mockCloudCfg: client.MockCloudCfg{ | ||
ConfigErr: fmt.Errorf("test bad hcp config"), | ||
}, | ||
expect: func(mockClient *client.MockClient) { | ||
mockClient.EXPECT().FetchTelemetryConfig(mock.Anything).Return(&client.TelemetryConfig{ | ||
Endpoint: "https://test.com", | ||
MetricsConfig: &client.MetricsConfig{ | ||
Endpoint: "", | ||
}, | ||
}, nil) | ||
}, | ||
cloudCfg: config.CloudConfig{}, | ||
}, | ||
"failsWithFetchTelemetryFailure": { | ||
expect: func(mockClient *client.MockClient) { | ||
|
@@ -93,14 +84,17 @@ func TestSink(t *testing.T) { | |
t.Run(name, func(t *testing.T) { | ||
t.Parallel() | ||
c := client.NewMockClient(t) | ||
l := hclog.NewNullLogger() | ||
mc := client.MockMetricsClient{} | ||
|
||
test.expect(c) | ||
sinkOpts := sink(c, test.mockCloudCfg, l, types.NodeID("server1234")) | ||
ctx := context.Background() | ||
|
||
s := sink(ctx, c, mc, test.cloudCfg) | ||
if !test.expectedSink { | ||
require.Nil(t, sinkOpts) | ||
require.Nil(t, s) | ||
return | ||
} | ||
require.NotNil(t, sinkOpts) | ||
require.NotNil(t, s) | ||
}) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tiny nit - feel free to ignore if preferred. Might be good to comment that this value gets overwritten and can change later on in
setup.go