GH-20889 - put conditionals are hcp initialization for consul server (#20926)

* put conditionals are hcp initialization for consul server

* put more things behind configuration flags

* add changelog

* TestServer_hcpManager

* fix TestAgent_scadaProvider
This commit is contained in:
John Murret 2024-03-28 14:47:11 -06:00 committed by GitHub
parent 2a2e773908
commit 39112c7a98
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 81 additions and 67 deletions

3
.changelog/20926.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
error running consul server in 1.18.0: failed to configure SCADA provider user's home directory path: $HOME is not defined
```

View File

@ -1320,7 +1320,7 @@ func (a *Agent) listenHTTP() ([]apiServer, error) {
} }
httpAddrs := a.config.HTTPAddrs httpAddrs := a.config.HTTPAddrs
if a.scadaProvider != nil { if a.config.IsCloudEnabled() && a.scadaProvider != nil {
httpAddrs = append(httpAddrs, scada.CAPCoreAPI) httpAddrs = append(httpAddrs, scada.CAPCoreAPI)
} }

View File

@ -6341,6 +6341,7 @@ func TestAgent_scadaProvider(t *testing.T) {
pvd.EXPECT().Listen(scada.CAPCoreAPI.Capability()).Return(l, nil).Once() pvd.EXPECT().Listen(scada.CAPCoreAPI.Capability()).Return(l, nil).Once()
pvd.EXPECT().Stop().Return(nil).Once() pvd.EXPECT().Stop().Return(nil).Once()
a := TestAgent{ a := TestAgent{
HCL: `cloud = { resource_id = "test-resource-id" client_id = "test-client-id" client_secret = "test-client-secret" }`,
OverrideDeps: func(deps *BaseDeps) { OverrideDeps: func(deps *BaseDeps) {
deps.HCP.Provider = pvd deps.HCP.Provider = pvd
}, },

View File

@ -1114,8 +1114,8 @@ func (b *builder) build() (rt RuntimeConfig, err error) {
LocalProxyConfigResyncInterval: 30 * time.Second, LocalProxyConfigResyncInterval: 30 * time.Second,
} }
// host metrics are enabled by default to support HashiCorp Cloud Platform integration // host metrics are enabled if consul is configured with HashiCorp Cloud Platform integration
rt.Telemetry.EnableHostMetrics = boolValWithDefault(c.Telemetry.EnableHostMetrics, true) rt.Telemetry.EnableHostMetrics = boolValWithDefault(c.Telemetry.EnableHostMetrics, rt.IsCloudEnabled())
rt.TLS, err = b.buildTLSConfig(rt, c.TLS) rt.TLS, err = b.buildTLSConfig(rt, c.TLS)
if err != nil { if err != nil {

View File

@ -595,32 +595,34 @@ func NewServer(config *Config, flat Deps, externalGRPCServer *grpc.Server,
StorageBackend: s.raftStorageBackend, StorageBackend: s.raftStorageBackend,
}) })
s.hcpManager = hcp.NewManager(hcp.ManagerConfig{ if s.config.Cloud.IsConfigured() {
CloudConfig: flat.HCP.Config, s.hcpManager = hcp.NewManager(hcp.ManagerConfig{
StatusFn: s.hcpServerStatus(flat), CloudConfig: flat.HCP.Config,
Logger: logger.Named("hcp_manager"), StatusFn: s.hcpServerStatus(flat),
SCADAProvider: flat.HCP.Provider, Logger: logger.Named("hcp_manager"),
TelemetryProvider: flat.HCP.TelemetryProvider, SCADAProvider: flat.HCP.Provider,
ManagementTokenUpserterFn: func(name, secretId string) error { TelemetryProvider: flat.HCP.TelemetryProvider,
// Check the state of the server before attempting to upsert the token. Otherwise, ManagementTokenUpserterFn: func(name, secretId string) error {
// the upsert will fail and log errors that do not require action from the user. // Check the state of the server before attempting to upsert the token. Otherwise,
if s.config.ACLsEnabled && s.IsLeader() && s.InPrimaryDatacenter() { // the upsert will fail and log errors that do not require action from the user.
// Idea for improvement: Upsert a token with a well-known accessorId here instead if s.config.ACLsEnabled && s.IsLeader() && s.InPrimaryDatacenter() {
// of a randomly generated one. This would prevent any possible insertion collision between // Idea for improvement: Upsert a token with a well-known accessorId here instead
// this and the insertion that happens during the ACL initialization process (initializeACLs function) // of a randomly generated one. This would prevent any possible insertion collision between
return s.upsertManagementToken(name, secretId) // this and the insertion that happens during the ACL initialization process (initializeACLs function)
} return s.upsertManagementToken(name, secretId)
return nil }
}, return nil
ManagementTokenDeleterFn: func(secretId string) error { },
// Check the state of the server before attempting to delete the token.Otherwise, ManagementTokenDeleterFn: func(secretId string) error {
// the delete will fail and log errors that do not require action from the user. // Check the state of the server before attempting to delete the token.Otherwise,
if s.config.ACLsEnabled && s.IsLeader() && s.InPrimaryDatacenter() { // the delete will fail and log errors that do not require action from the user.
return s.deleteManagementToken(secretId) if s.config.ACLsEnabled && s.IsLeader() && s.InPrimaryDatacenter() {
} return s.deleteManagementToken(secretId)
return nil }
}, return nil
}) },
})
}
var recorder *middleware.RequestRecorder var recorder *middleware.RequestRecorder
if flat.NewRequestRecorderFunc != nil { if flat.NewRequestRecorderFunc != nil {
@ -890,22 +892,24 @@ func NewServer(config *Config, flat Deps, externalGRPCServer *grpc.Server,
// to enable RPC forwarding. // to enable RPC forwarding.
s.grpcLeaderForwarder = flat.LeaderForwarder s.grpcLeaderForwarder = flat.LeaderForwarder
// Start watching HCP Link resource. This needs to be created after if s.config.Cloud.IsConfigured() {
// the GRPC services are set up in order for the resource service client to // Start watching HCP Link resource. This needs to be created after
// function. This uses the insecure grpc channel so that it doesn't need to // the GRPC services are set up in order for the resource service client to
// present a valid ACL token. // function. This uses the insecure grpc channel so that it doesn't need to
go hcp.RunHCPLinkWatcher( // present a valid ACL token.
&lib.StopChannelContext{StopCh: shutdownCh}, go hcp.RunHCPLinkWatcher(
logger.Named("hcp-link-watcher"), &lib.StopChannelContext{StopCh: shutdownCh},
pbresource.NewResourceServiceClient(s.insecureSafeGRPCChan), logger.Named("hcp-link-watcher"),
hcp.HCPManagerLifecycleFn( pbresource.NewResourceServiceClient(s.insecureSafeGRPCChan),
s.hcpManager, hcp.HCPManagerLifecycleFn(
hcpclient.NewClient, s.hcpManager,
bootstrap.LoadManagementToken, hcpclient.NewClient,
flat.HCP.Config, bootstrap.LoadManagementToken,
flat.HCP.DataDir, flat.HCP.Config,
), flat.HCP.DataDir,
) ),
)
}
s.controllerManager = controller.NewManager( s.controllerManager = controller.NewManager(
// Usage of the insecure + unsafe grpc chan is required for the controller // Usage of the insecure + unsafe grpc chan is required for the controller
@ -1008,13 +1012,15 @@ func isV1CatalogRequest(rpcName string) bool {
} }
func (s *Server) registerControllers(deps Deps, proxyUpdater ProxyUpdater) error { func (s *Server) registerControllers(deps Deps, proxyUpdater ProxyUpdater) error {
hcpctl.RegisterControllers( if s.config.Cloud.IsConfigured() {
s.controllerManager, hcpctl.ControllerDependencies{ hcpctl.RegisterControllers(
ResourceApisEnabled: s.useV2Resources, s.controllerManager, hcpctl.ControllerDependencies{
HCPAllowV2ResourceApis: s.hcpAllowV2Resources, ResourceApisEnabled: s.useV2Resources,
CloudConfig: deps.HCP.Config, HCPAllowV2ResourceApis: s.hcpAllowV2Resources,
}, CloudConfig: deps.HCP.Config,
) },
)
}
// When not enabled, the v1 tenancy bridge is used by default. // When not enabled, the v1 tenancy bridge is used by default.
if s.useV2Tenancy { if s.useV2Tenancy {
@ -2075,8 +2081,10 @@ func (s *Server) trackLeaderChanges() {
s.raftStorageBackend.LeaderChanged() s.raftStorageBackend.LeaderChanged()
s.controllerManager.SetRaftLeader(s.IsLeader()) s.controllerManager.SetRaftLeader(s.IsLeader())
// Trigger sending an update to HCP status if s.config.Cloud.IsConfigured() {
s.hcpManager.SendUpdate() // Trigger sending an update to HCP status
s.hcpManager.SendUpdate()
}
case <-s.shutdownCh: case <-s.shutdownCh:
s.raft.DeregisterObserver(observer) s.raft.DeregisterObserver(observer)
return return

View File

@ -2100,6 +2100,9 @@ func TestServer_hcpManager(t *testing.T) {
// Configure the server for the StatusFn // Configure the server for the StatusFn
conf1.BootstrapExpect = 1 conf1.BootstrapExpect = 1
conf1.RPCAdvertise = &net.TCPAddr{IP: []byte{127, 0, 0, 2}, Port: conf1.RPCAddr.Port} conf1.RPCAdvertise = &net.TCPAddr{IP: []byte{127, 0, 0, 2}, Port: conf1.RPCAddr.Port}
conf1.Cloud.ClientID = "test-client-id"
conf1.Cloud.ResourceID = "test-resource-id"
conf1.Cloud.ClientSecret = "test-client-secret"
hcp1 := hcpclient.NewMockClient(t) hcp1 := hcpclient.NewMockClient(t)
hcp1.EXPECT().PushServerStatus(mock.Anything, mock.MatchedBy(func(status *hcpclient.ServerStatus) bool { hcp1.EXPECT().PushServerStatus(mock.Anything, mock.MatchedBy(func(status *hcpclient.ServerStatus) bool {
return status.ID == string(conf1.NodeID) return status.ID == string(conf1.NodeID)

View File

@ -138,15 +138,17 @@ func NewBaseDeps(configLoader ConfigLoader, logOut io.Writer, providedLogger hcl
cfg.Telemetry.PrometheusOpts.SummaryDefinitions = summaries cfg.Telemetry.PrometheusOpts.SummaryDefinitions = summaries
var extraSinks []metrics.MetricSink var extraSinks []metrics.MetricSink
// This values is set late within newNodeIDFromConfig above if cfg.IsCloudEnabled() {
cfg.Cloud.NodeID = cfg.NodeID // This values is set late within newNodeIDFromConfig above
cfg.Cloud.NodeID = cfg.NodeID
d.HCP, err = hcp.NewDeps(cfg.Cloud, d.Logger.Named("hcp"), cfg.DataDir) d.HCP, err = hcp.NewDeps(cfg.Cloud, d.Logger.Named("hcp"), cfg.DataDir)
if err != nil { if err != nil {
return d, err return d, err
} }
if d.HCP.Sink != nil { if d.HCP.Sink != nil {
extraSinks = append(extraSinks, d.HCP.Sink) extraSinks = append(extraSinks, d.HCP.Sink)
}
} }
d.MetricsConfig, err = lib.InitTelemetry(cfg.Telemetry, d.Logger, extraSinks...) d.MetricsConfig, err = lib.InitTelemetry(cfg.Telemetry, d.Logger, extraSinks...)

View File

@ -181,12 +181,9 @@ func (c *cmd) run(args []string) int {
ui.Error(err.Error()) ui.Error(err.Error())
return 1 return 1
} }
}
// We unconditionally add an Access Control header to our config in order to allow the HCP UI to work. loader = hcpbootstrap.AddAclPolicyAccessControlHeader(loader)
// We do this unconditionally because the cluster can be linked to HCP at any time (not just at startup) and this }
// is simpler than selectively reloading parts of config at runtime.
loader = hcpbootstrap.AddAclPolicyAccessControlHeader(loader)
bd, err := agent.NewBaseDeps(loader, logGate, nil) bd, err := agent.NewBaseDeps(loader, logGate, nil)
if err != nil { if err != nil {