func()

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)
}