in internal/startdaemon/startdaemon.go [262:478]
func (d *Daemon) startServices(ctx context.Context, cancel context.CancelFunc, goos string, restarting bool) {
if d.config.GetCloudProperties() == nil {
log.Logger.Error("Cloud properties are not set, cannot start services.")
usagemetrics.Error(usagemetrics.CloudPropertiesNotSet)
return
}
shutdownch := make(chan os.Signal, 1)
signal.Notify(shutdownch, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
// When not collecting agent metrics and service health, the NullMonitor will provide
// sensible NOOPs. Downstream services can safely register and use the provided *Spec
// without fear nor penalty.
var healthMonitor agentmetrics.HealthMonitor = &heartbeat.NullMonitor{}
var err error
if d.config.GetCollectionConfiguration().GetCollectAgentMetrics() {
amCtx := log.SetCtx(ctx, "context", "AgentMetrics")
healthMonitor, err = startAgentMetricsService(amCtx, d.config)
if err != nil {
return
}
}
// Create channels to subscribe to collection definition updates.
chWLM := make(chan *cdpb.CollectionDefinition)
chs := []chan<- *cdpb.CollectionDefinition{chWLM}
cdCtx := log.SetCtx(ctx, "context", "CollectionDefinition")
cdHeartbeatSpec, err := healthMonitor.Register(collectionDefinitionName)
if err != nil {
log.CtxLogger(cdCtx).Errorw("Failed to register collection definition health monitor", "error", err)
usagemetrics.Error(usagemetrics.HeartbeatMonitorRegistrationFailure)
return
}
cd := collectiondefinition.Start(cdCtx, chs, collectiondefinition.StartOptions{
HeartbeatSpec: cdHeartbeatSpec,
LoadOptions: collectiondefinition.LoadOptions{
CollectionConfig: d.config.GetCollectionConfiguration(),
ReadFile: os.ReadFile,
OSType: goos,
Version: configuration.AgentVersion,
FetchOptions: collectiondefinition.FetchOptions{
OSType: goos,
Env: d.config.GetCollectionConfiguration().GetWorkloadValidationCollectionDefinition().GetConfigTargetEnvironment(),
Client: storage.NewClient,
CreateTemp: os.CreateTemp,
Execute: execute,
},
},
})
gceService, err := gce.NewGCEClient(ctx)
if err != nil {
log.Logger.Errorw("Failed to create GCE service", "error", err)
usagemetrics.Error(usagemetrics.GCEServiceCreateFailure)
return
}
wlmService, err := wlm.NewWLMClient(ctx, d.config.GetCollectionConfiguration().GetDataWarehouseEndpoint())
if err != nil {
log.Logger.Errorw("Error creating WLM Client", "error", err)
usagemetrics.Error(usagemetrics.WLMServiceCreateFailure)
return
}
// Start SAP System Discovery
ssdCtx := log.SetCtx(ctx, "context", "SAPSystemDiscovery")
systemDiscovery := &system.Discovery{
WlmService: wlmService,
AppsDiscovery: sapdiscovery.SAPApplications,
CloudDiscoveryInterface: &clouddiscovery.CloudDiscovery{
GceService: gceService,
HostResolver: net.LookupHost,
},
HostDiscoveryInterface: &hostdiscovery.HostDiscovery{
Exists: commandlineexecutor.CommandExists,
Execute: commandlineexecutor.ExecuteCommand,
},
SapDiscoveryInterface: &appsdiscovery.SapDiscovery{
Execute: commandlineexecutor.ExecuteCommand,
FileSystem: filesystem.Helper{},
},
OSStatReader: osStatReader,
FileReader: configFileReader,
}
if d.lp.CloudLoggingClient != nil {
systemDiscovery.CloudLogInterface = d.lp.CloudLoggingClient.Logger("google-cloud-sap-agent")
system.StartSAPSystemDiscovery(ssdCtx, d.config, systemDiscovery)
log.FlushCloudLog()
} else {
system.StartSAPSystemDiscovery(ssdCtx, d.config, systemDiscovery)
}
gceBetaService := &gcebeta.GCEBeta{}
if strings.Contains(d.config.GetServiceEndpointOverride(), "beta") {
gceBetaService, err = gcebeta.NewGCEClient(ctx)
if err != nil {
log.Logger.Errorw("Failed to create GCE beta service", "error", err)
usagemetrics.Error(usagemetrics.GCEServiceCreateFailure)
return
}
log.Logger.Infow("Service endpoint override", "endpoint", d.config.GetServiceEndpointOverride())
gceService.OverrideComputeBasePath(d.config.GetServiceEndpointOverride())
if gceBetaService != nil {
gceBetaService.OverrideComputeBasePath(d.config.GetServiceEndpointOverride())
}
}
ppr := &instanceinfo.PhysicalPathReader{OS: goos}
instanceInfoReader := instanceinfo.New(ppr, gceService)
ua := fmt.Sprintf("sap-core-eng/%s/%s.%s/wlmevaluation", configuration.AgentName, configuration.AgentVersion, configuration.AgentBuildChange)
clientOptions := []option.ClientOption{option.WithUserAgent(ua)}
wlmMetricClient, err := monitoring.NewMetricClient(ctx, clientOptions...)
if err != nil {
log.Logger.Errorw("Failed to create Cloud Monitoring metric client for workload manager evalution metrics", "error", err)
usagemetrics.Error(usagemetrics.MetricClientCreateFailure)
return
}
wlmHeartbeatSpec, err := healthMonitor.Register(workloadManagerServiceName)
if err != nil {
log.Logger.Error("Failed to register workload manager service", log.Error(err))
usagemetrics.Error(usagemetrics.HeartbeatMonitorRegistrationFailure)
return
}
wlmparams := workloadmanager.Parameters{
Config: d.config,
WorkloadConfig: cd.GetWorkloadValidation(),
WorkloadConfigCh: chWLM,
Remote: false,
TimeSeriesCreator: wlmMetricClient,
BackOffs: cloudmonitoring.NewDefaultBackOffIntervals(),
Execute: execute,
Exists: exists,
HeartbeatSpec: wlmHeartbeatSpec,
GCEService: gceService,
WLMService: wlmService,
Discovery: systemDiscovery,
}
if d.config.GetCollectionConfiguration().GetWorkloadValidationRemoteCollection() != nil {
// When set to collect workload manager metrics remotely then that is all this runtime will do.
wlmparams.Remote = true
log.Logger.Info("Collecting Workload Manager metrics remotely, will not start any other services")
wmCtx := log.SetCtx(ctx, "context", "WorkloadManagerMetrics")
workloadmanager.StartMetricsCollection(wmCtx, wlmparams)
waitForShutdown(ctx, shutdownch, cancel, restarting)
return
}
// The functions being called below should be asynchronous.
// A typical StartXXX() will do the necessary initialisation synchronously
// and start its own goroutines for the long running tasks. The control
// should be returned to main immediately after init succeeds.
// Start the SAP Host Metrics provider
mqc, err := monitoring.NewQueryClient(ctx)
if err != nil {
log.Logger.Errorw("Failed to create Cloud Monitoring query client", "error", err)
usagemetrics.Error(usagemetrics.QueryClientCreateFailure)
return
}
cmr := &cloudmetricreader.CloudMetricReader{
QueryClient: &cloudmetricreader.QueryClient{Client: mqc},
BackOffs: cloudmonitoring.NewDefaultBackOffIntervals(),
}
// start the Host Metrics Collection
hmCtx := log.SetCtx(ctx, "context", "HostMetrics")
hmp := HostMetricsParams{d.config, instanceInfoReader, cmr, healthMonitor}
hmp.startCollection(hmCtx, restarting)
// Start the Workload Manager metrics collection
wmCtx := log.SetCtx(ctx, "context", "WorkloadManagerMetrics")
wmp := WorkloadManagerParams{wlmparams, instanceInfoReader}
wmp.startCollection(wmCtx)
// Declaring pacemaker Params
pcmp := pacemaker.Parameters{
Config: d.config,
WorkloadConfig: cd.GetWorkloadValidation(),
ConfigFileReader: pacemaker.ConfigFileReader(configFileReader),
DefaultTokenGetter: pacemaker.DefaultTokenGetter(defaultTokenGetter),
JSONCredentialsGetter: pacemaker.JSONCredentialsGetter(jsonCredentialsGetter),
Execute: execute,
Exists: exists,
}
// Start Process Metrics Collection
pmCtx := log.SetCtx(ctx, "context", "ProcessMetrics")
pmp := ProcessMetricsParams{d.config, goos, healthMonitor, gceService, gceBetaService, systemDiscovery, pcmp}
pmp.startCollection(pmCtx)
// Start HANA Monitoring
hanaCtx := log.SetCtx(ctx, "context", "HANAMonitoring")
ua = fmt.Sprintf("sap-core-eng/%s/%s.%s/hanamonitoring", configuration.AgentName, configuration.AgentVersion, configuration.AgentBuildChange)
clientOptions = []option.ClientOption{option.WithUserAgent(ua)}
hanaMonitoringMetricClient, err := monitoring.NewMetricClient(ctx, clientOptions...)
if err != nil {
log.Logger.Errorw("Failed to create Cloud Monitoring metric client for HANA Monitoring metrics", "error", err)
usagemetrics.Error(usagemetrics.MetricClientCreateFailure)
return
}
hanamonitoring.Start(hanaCtx, hanamonitoring.Parameters{
Config: d.config,
GCEService: gceService,
BackOffs: cloudmonitoring.NewDefaultBackOffIntervals(),
TimeSeriesCreator: hanaMonitoringMetricClient,
HRC: sapdiscovery.HANAReplicationConfig,
SystemDiscovery: systemDiscovery,
ConnectionRetryInterval: 300 * time.Second,
})
// Start Status Collection
statusCtx := log.SetCtx(ctx, "context", "Status")
sp := StatusParams{&status.Status{ConfigFilePath: d.configFilePath, CloudProps: d.cloudProps}, healthMonitor}
sp.startCollection(statusCtx)
waitForShutdown(ctx, shutdownch, cancel, restarting)
}