github.com/Axway/agent-sdk@v1.1.101/pkg/agent/agent.go (about)

     1  package agent
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"os/signal"
     8  	"runtime"
     9  	"runtime/pprof"
    10  	"strings"
    11  	"sync"
    12  	"syscall"
    13  	"time"
    14  
    15  	agentcache "github.com/Axway/agent-sdk/pkg/agent/cache"
    16  	"github.com/Axway/agent-sdk/pkg/agent/handler"
    17  	"github.com/Axway/agent-sdk/pkg/agent/resource"
    18  	"github.com/Axway/agent-sdk/pkg/agent/stream"
    19  	"github.com/Axway/agent-sdk/pkg/api"
    20  	"github.com/Axway/agent-sdk/pkg/apic"
    21  	apiV1 "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/api/v1"
    22  	"github.com/Axway/agent-sdk/pkg/apic/auth"
    23  	"github.com/Axway/agent-sdk/pkg/apic/provisioning"
    24  	"github.com/Axway/agent-sdk/pkg/authz/oauth"
    25  	"github.com/Axway/agent-sdk/pkg/cache"
    26  	"github.com/Axway/agent-sdk/pkg/config"
    27  	"github.com/Axway/agent-sdk/pkg/util"
    28  	hc "github.com/Axway/agent-sdk/pkg/util/healthcheck"
    29  	"github.com/Axway/agent-sdk/pkg/util/log"
    30  )
    31  
    32  // AgentStatus - status for Agent resource
    33  const (
    34  	AgentRunning   = "running"
    35  	AgentStopped   = "stopped"
    36  	AgentFailed    = "failed"
    37  	AgentUnhealthy = "unhealthy"
    38  	// CorsField -
    39  	CorsField = "cors"
    40  	// RedirectURLsField -
    41  	RedirectURLsField = "redirectURLs"
    42  )
    43  
    44  // AgentResourceType - Holds the type for agent resource in Central
    45  var AgentResourceType string
    46  
    47  // APIValidator - Callback for validating the API
    48  type APIValidator func(apiID, stageName string) bool
    49  
    50  // ConfigChangeHandler - Callback for Config change event
    51  type ConfigChangeHandler func()
    52  
    53  // ShutdownHandler - function that the agent may implement to be called when a shutdown request is received
    54  type ShutdownHandler func()
    55  
    56  type agentData struct {
    57  	agentResourceManager resource.Manager
    58  	teamJob              *centralTeamsCache
    59  	apicClient           apic.Client
    60  	cfg                  config.CentralConfig
    61  	agentFeaturesCfg     config.AgentFeaturesConfig
    62  	tokenRequester       auth.PlatformTokenGetter
    63  
    64  	teamMap                    cache.Cache
    65  	cacheManager               agentcache.Manager
    66  	apiValidator               APIValidator
    67  	apiValidatorLock           sync.Mutex
    68  	apiValidatorJobID          string
    69  	configChangeHandler        ConfigChangeHandler
    70  	agentResourceChangeHandler ConfigChangeHandler
    71  	agentShutdownHandler       ShutdownHandler
    72  	proxyResourceHandler       *handler.StreamWatchProxyHandler
    73  	isInitialized              bool
    74  
    75  	provisioner          provisioning.Provisioning
    76  	streamer             *stream.StreamerClient
    77  	authProviderRegistry oauth.ProviderRegistry
    78  
    79  	publishingLock *sync.Mutex
    80  	ardLock        sync.Mutex
    81  
    82  	status string
    83  
    84  	// profiling
    85  	profileDone chan struct{}
    86  }
    87  
    88  var agent agentData
    89  var agentMutex sync.RWMutex
    90  
    91  var logger log.FieldLogger
    92  
    93  func init() {
    94  	logger = log.NewFieldLogger().
    95  		WithPackage("sdk.agent").
    96  		WithComponent("agent")
    97  	agent.proxyResourceHandler = handler.NewStreamWatchProxyHandler()
    98  	agentMutex = sync.RWMutex{}
    99  	agent.publishingLock = &sync.Mutex{}
   100  }
   101  
   102  // Initialize - Initializes the agent
   103  func Initialize(centralCfg config.CentralConfig) error {
   104  	return InitializeWithAgentFeatures(centralCfg, config.NewAgentFeaturesConfiguration())
   105  }
   106  
   107  // InitializeWithAgentFeatures - Initializes the agent with agent features
   108  func InitializeWithAgentFeatures(centralCfg config.CentralConfig, agentFeaturesCfg config.AgentFeaturesConfig) error {
   109  	if agent.teamMap == nil {
   110  		agent.teamMap = cache.New()
   111  	}
   112  
   113  	err := checkRunningAgent()
   114  	if err != nil {
   115  		return err
   116  	}
   117  
   118  	err = config.ValidateConfig(agentFeaturesCfg)
   119  	if err != nil {
   120  		return err
   121  	}
   122  	agent.agentFeaturesCfg = agentFeaturesCfg
   123  
   124  	// validate the central config
   125  	if agentFeaturesCfg.ConnectionToCentralEnabled() {
   126  		err = config.ValidateConfig(centralCfg)
   127  		if err != nil {
   128  			return err
   129  		}
   130  	}
   131  
   132  	// check to confirm usagereporting.offline and agentfeatures.persistcache are not both set to true
   133  	if agentFeaturesCfg.PersistCacheEnabled() && centralCfg.GetUsageReportingConfig().IsOfflineMode() {
   134  		agentFeaturesCfg.SetPersistentCache(false)
   135  	}
   136  
   137  	// Only create the api map cache if it does not already exist
   138  	if agent.cacheManager == nil {
   139  		agent.cacheManager = agentcache.NewAgentCacheManager(centralCfg, agentFeaturesCfg.PersistCacheEnabled())
   140  	}
   141  
   142  	setCentralConfig(centralCfg)
   143  
   144  	if centralCfg.GetUsageReportingConfig().IsOfflineMode() {
   145  		// Offline mode does not need more initialization
   146  		return nil
   147  	}
   148  
   149  	singleEntryFilter := []string{
   150  		// Traceability host URL will be added by the traceability factory
   151  		centralCfg.GetURL(),
   152  		centralCfg.GetPlatformURL(),
   153  		centralCfg.GetAuthConfig().GetTokenURL(),
   154  		centralCfg.GetUsageReportingConfig().GetURL(),
   155  	}
   156  	api.SetConfigAgent(
   157  		GetUserAgent(),
   158  		centralCfg.GetSingleURL(),
   159  		singleEntryFilter)
   160  
   161  	if agentFeaturesCfg.ConnectionToCentralEnabled() {
   162  		err = handleCentralConfig(centralCfg)
   163  		if err != nil {
   164  			return err
   165  		}
   166  	}
   167  
   168  	if !agent.isInitialized {
   169  		err = handleInitialization()
   170  		if err != nil {
   171  			return err
   172  		}
   173  	}
   174  
   175  	agent.isInitialized = true
   176  	return nil
   177  }
   178  
   179  func handleCentralConfig(centralCfg config.CentralConfig) error {
   180  	err := initializeTokenRequester(centralCfg)
   181  	if err != nil {
   182  		return fmt.Errorf("could not authenticate to Amplify, please check your keys and key password")
   183  	}
   184  
   185  	// Init apic client when the agent starts, and on config change.
   186  	agent.apicClient = apic.New(centralCfg, agent.tokenRequester, agent.cacheManager)
   187  
   188  	if util.IsNotTest() {
   189  		err = initEnvResources(centralCfg, agent.apicClient)
   190  		if err != nil {
   191  			return err
   192  		}
   193  	}
   194  
   195  	if centralCfg.GetAgentName() != "" {
   196  		if agent.agentResourceManager == nil {
   197  			agent.agentResourceManager, err = resource.NewAgentResourceManager(
   198  				agent.cfg, agent.apicClient, agent.agentResourceChangeHandler,
   199  			)
   200  			if err != nil {
   201  				return err
   202  			}
   203  		} else {
   204  			agent.agentResourceManager.OnConfigChange(agent.cfg, agent.apicClient)
   205  		}
   206  	}
   207  
   208  	return nil
   209  }
   210  
   211  func handleInitialization() error {
   212  	setupSignalProcessor()
   213  	// only do the periodic health check stuff if NOT in unit tests and running binary agents
   214  	if util.IsNotTest() {
   215  		hc.StartPeriodicHealthCheck()
   216  	}
   217  
   218  	if util.IsNotTest() && agent.agentFeaturesCfg.ConnectionToCentralEnabled() {
   219  		// if credentials can expire and need to be deprovisioned then start the credential checker
   220  
   221  		registerCredentialChecker()
   222  
   223  		startTeamACLCache()
   224  	}
   225  
   226  	return nil
   227  }
   228  
   229  // InitializeProfiling - setup the CPU and Memory profiling if options given
   230  func InitializeProfiling(cpuProfile, memProfile string) {
   231  	if memProfile != "" || cpuProfile != "" {
   232  		setupProfileSignalProcessor(cpuProfile, memProfile)
   233  	}
   234  }
   235  
   236  func registerExternalIDPs() error {
   237  	if agent.cfg.GetAgentType() != config.TraceabilityAgent {
   238  		idPCfg := agent.agentFeaturesCfg.GetExternalIDPConfig()
   239  		if idPCfg == nil {
   240  			return nil
   241  		}
   242  
   243  		proxy := agent.cfg.GetProxyURL()
   244  		timeout := agent.cfg.GetClientTimeout()
   245  		for _, idp := range idPCfg.GetIDPList() {
   246  			tlsCfg := idp.GetTLSConfig()
   247  			if idp.GetTLSConfig() == nil {
   248  				tlsCfg = agent.cfg.GetTLSConfig()
   249  			}
   250  			err := registerCredentialProvider(idp, tlsCfg, proxy, timeout)
   251  			if err != nil {
   252  				return err
   253  			}
   254  		}
   255  	}
   256  	return nil
   257  }
   258  
   259  func registerCredentialProvider(idp config.IDPConfig, tlsCfg config.TLSConfig, proxyURL string, clientTimeout time.Duration) error {
   260  	err := GetAuthProviderRegistry().RegisterProvider(idp, tlsCfg, proxyURL, clientTimeout)
   261  	if err != nil {
   262  		logger.
   263  			WithField("name", idp.GetIDPName()).
   264  			WithField("type", idp.GetIDPType()).
   265  			WithField("metadata-url", idp.GetMetadataURL()).
   266  			Errorf("unable to register external IdP provider, any credential request to the IdP will not be processed. %s", err.Error())
   267  	}
   268  	crdName := idp.GetIDPName() + " " + provisioning.OAuthIDPCRD
   269  	provider, err := GetAuthProviderRegistry().GetProviderByName(idp.GetIDPName())
   270  	if err != nil {
   271  		return err
   272  	}
   273  	crd, err := NewOAuthCredentialRequestBuilder(
   274  		WithCRDName(crdName),
   275  		WithCRDForIDP(provider, provider.GetSupportedScopes()),
   276  		WithCRDOAuthSecret(),
   277  		WithCRDRequestSchemaProperty(getCorsSchemaPropertyBuilder()),
   278  		WithCRDRequestSchemaProperty(getAuthRedirectSchemaPropertyBuilder()),
   279  		WithCRDIsSuspendable(),
   280  	).Register()
   281  	if err != nil {
   282  		logger.
   283  			WithField("title", idp.GetIDPTitle()).
   284  			Errorf("unable to create and register credential request definition. %s", err.Error())
   285  	} else {
   286  		logger.
   287  			WithField("name", crd.Name).
   288  			WithField("title", idp.GetIDPTitle()).
   289  			Info("successfully created and registered credential request definition.")
   290  	}
   291  	return err
   292  }
   293  
   294  func getCorsSchemaPropertyBuilder() provisioning.PropertyBuilder {
   295  	// register the supported credential request defs
   296  	return provisioning.NewSchemaPropertyBuilder().
   297  		SetName(CorsField).
   298  		SetLabel("Javascript Origins").
   299  		IsArray().
   300  		AddItem(
   301  			provisioning.NewSchemaPropertyBuilder().
   302  				SetName("Origins").
   303  				IsString())
   304  }
   305  
   306  func getAuthRedirectSchemaPropertyBuilder() provisioning.PropertyBuilder {
   307  	return provisioning.NewSchemaPropertyBuilder().
   308  		SetName(RedirectURLsField).
   309  		SetLabel("Redirect URLs").
   310  		IsArray().
   311  		AddItem(
   312  			provisioning.NewSchemaPropertyBuilder().
   313  				SetName("URL").
   314  				IsString())
   315  }
   316  
   317  func initEnvResources(cfg config.CentralConfig, client apic.Client) error {
   318  	env, err := client.GetEnvironment()
   319  	if err != nil {
   320  		return err
   321  	}
   322  
   323  	cfg.SetAxwayManaged(env.Spec.AxwayManaged)
   324  	if cfg.GetEnvironmentID() == "" {
   325  		// need to save this ID for the traceability agent for later
   326  		cfg.SetEnvironmentID(env.Metadata.ID)
   327  	}
   328  
   329  	// Set up credential config from environment resource policies
   330  	cfg.GetCredentialConfig().SetShouldDeprovisionExpired(env.Policies.Credentials.Expiry.Action == "deprovision")
   331  	cfg.GetCredentialConfig().SetExpirationDays(int(env.Policies.Credentials.Expiry.Period))
   332  
   333  	if cfg.GetTeamID() == "" {
   334  		team, err := client.GetCentralTeamByName(cfg.GetTeamName())
   335  		if err != nil {
   336  			return err
   337  		}
   338  
   339  		cfg.SetTeamID(team.ID)
   340  	}
   341  
   342  	return nil
   343  }
   344  
   345  func checkRunningAgent() error {
   346  	// Check only on startup of binary agents
   347  	if !agent.isInitialized && util.IsNotTest() && !isRunningInDockerContainer() {
   348  		return hc.CheckIsRunning()
   349  	}
   350  	return nil
   351  }
   352  
   353  type TestOpt func(*testOpts)
   354  
   355  type testOpts struct {
   356  	marketplace bool
   357  	agentType   config.AgentType
   358  }
   359  
   360  // InitializeForTest - Initialize for test
   361  func InitializeForTest(apicClient apic.Client, opts ...TestOpt) {
   362  	agent.apicClient = apicClient
   363  	tOpts := &testOpts{}
   364  	for _, o := range opts {
   365  		o(tOpts)
   366  	}
   367  	if agent.cfg == nil {
   368  		agent.cfg = config.NewTestCentralConfig(tOpts.agentType)
   369  	}
   370  	agent.cacheManager = agentcache.NewAgentCacheManager(agent.cfg, false)
   371  	agent.agentFeaturesCfg = &config.AgentFeaturesConfiguration{
   372  		ConnectToCentral:     true,
   373  		ProcessSystemSignals: true,
   374  		VersionChecker:       true,
   375  		PersistCache:         true,
   376  		AgentStatusUpdates:   true,
   377  	}
   378  }
   379  
   380  func TestWithMarketplace() func(*testOpts) {
   381  	return func(o *testOpts) {
   382  		o.marketplace = true
   383  	}
   384  }
   385  
   386  func TestWithCentralConfig(cfg config.CentralConfig) func(*testOpts) {
   387  	return func(o *testOpts) {
   388  		agent.cfg = cfg
   389  	}
   390  }
   391  
   392  func TestWithAgentType(agentType config.AgentType) func(*testOpts) {
   393  	return func(o *testOpts) {
   394  		o.agentType = agentType
   395  	}
   396  }
   397  
   398  // GetConfigChangeHandler - returns registered config change handler
   399  func GetConfigChangeHandler() ConfigChangeHandler {
   400  	return agent.configChangeHandler
   401  }
   402  
   403  // OnConfigChange - Registers handler for config change event
   404  func OnConfigChange(configChangeHandler ConfigChangeHandler) {
   405  	agent.configChangeHandler = configChangeHandler
   406  }
   407  
   408  // OnAgentResourceChange - Registers handler for resource change event
   409  func OnAgentResourceChange(agentResourceChangeHandler ConfigChangeHandler) {
   410  	agent.agentResourceChangeHandler = agentResourceChangeHandler
   411  }
   412  
   413  // RegisterResourceEventHandler - Registers handler for resource events
   414  func RegisterResourceEventHandler(name string, resourceEventHandler handler.Handler) {
   415  	agent.proxyResourceHandler.RegisterTargetHandler(name, resourceEventHandler)
   416  }
   417  
   418  // UnregisterResourceEventHandler - removes the specified resource event handler
   419  func UnregisterResourceEventHandler(name string) {
   420  	agent.proxyResourceHandler.UnregisterTargetHandler(name)
   421  }
   422  
   423  // GetAuthProviderRegistry - Returns the auth provider registry
   424  func GetAuthProviderRegistry() oauth.ProviderRegistry {
   425  	if agent.authProviderRegistry == nil {
   426  		agent.authProviderRegistry = oauth.NewProviderRegistry()
   427  	}
   428  	return agent.authProviderRegistry
   429  }
   430  
   431  // RegisterShutdownHandler - Registers shutdown handler
   432  func RegisterShutdownHandler(handler ShutdownHandler) {
   433  	agent.agentShutdownHandler = handler
   434  }
   435  
   436  func startTeamACLCache() {
   437  	// Only discovery agents need to start the ACL handler
   438  	if agent.cfg.GetAgentType() == config.DiscoveryAgent {
   439  		registerAccessControlListHandler()
   440  	}
   441  
   442  	registerTeamMapCacheJob()
   443  }
   444  
   445  func isRunningInDockerContainer() bool {
   446  	// Within the cgroup file, if you are not in a docker container all entries are like these devices:/
   447  	// If in a docker container, entries are like this: devices:/docker/xxxxxxxxx.
   448  	// So, all we need to do is see if ":/docker" exists somewhere in the file.
   449  	bytes, err := os.ReadFile("/proc/1/cgroup")
   450  	if err != nil {
   451  		return false
   452  	}
   453  
   454  	// Convert []byte to string and print to screen
   455  	text := string(bytes)
   456  
   457  	return strings.Contains(text, ":/docker")
   458  }
   459  
   460  // initializeTokenRequester - Create a new auth token requester
   461  func initializeTokenRequester(centralCfg config.CentralConfig) error {
   462  	var err error
   463  	agent.tokenRequester = auth.NewPlatformTokenGetterWithCentralConfig(centralCfg)
   464  	if util.IsNotTest() {
   465  		_, err = agent.tokenRequester.GetToken()
   466  	}
   467  	return err
   468  }
   469  
   470  // GetCentralAuthToken - Returns the Auth token from AxwayID to make API call to Central
   471  func GetCentralAuthToken() (string, error) {
   472  	if agent.tokenRequester == nil {
   473  		return "", apic.ErrAuthenticationCall
   474  	}
   475  	return agent.tokenRequester.GetToken()
   476  }
   477  
   478  // GetCentralClient - Returns the APIC Client
   479  func GetCentralClient() apic.Client {
   480  	return agent.apicClient
   481  }
   482  
   483  // GetCentralConfig - Returns the APIC Client
   484  func GetCentralConfig() config.CentralConfig {
   485  	agentMutex.Lock()
   486  	defer agentMutex.Unlock()
   487  	return agent.cfg
   488  }
   489  
   490  func GetUserAgent() string {
   491  	envName := ""
   492  	agentName := ""
   493  	isGRPC := false
   494  	if agent.cfg != nil {
   495  		envName = agent.cfg.GetEnvironmentName()
   496  		agentName = agent.cfg.GetAgentName()
   497  		isGRPC = agent.cfg.IsUsingGRPC()
   498  	}
   499  	return util.FormatUserAgent(
   500  		config.AgentTypeName,
   501  		config.AgentVersion,
   502  		config.SDKVersion,
   503  		envName,
   504  		agentName,
   505  		isRunningInDockerContainer(),
   506  		isGRPC)
   507  }
   508  
   509  // setCentralConfig - Sets the central config
   510  func setCentralConfig(cfg config.CentralConfig) {
   511  	agentMutex.Lock()
   512  	defer agentMutex.Unlock()
   513  	agent.cfg = cfg
   514  }
   515  
   516  // GetAPICache - Returns the cache
   517  func GetAPICache() cache.Cache {
   518  	if agent.cacheManager == nil {
   519  		agent.cacheManager = agentcache.NewAgentCacheManager(agent.cfg, agent.agentFeaturesCfg.PersistCacheEnabled())
   520  	}
   521  	return agent.cacheManager.GetAPIServiceCache()
   522  }
   523  
   524  // GetCacheManager - Returns the cache
   525  func GetCacheManager() agentcache.Manager {
   526  	if agent.cacheManager == nil {
   527  		agent.cacheManager = agentcache.NewAgentCacheManager(agent.cfg, agent.agentFeaturesCfg.PersistCacheEnabled())
   528  	}
   529  	return agent.cacheManager
   530  }
   531  
   532  func GetResourceManager() resource.Manager {
   533  	if agent.agentResourceManager == nil {
   534  		return nil
   535  	}
   536  	return agent.agentResourceManager
   537  }
   538  
   539  // GetAgentResource - Returns Agent resource
   540  func GetAgentResource() *apiV1.ResourceInstance {
   541  	if agent.agentResourceManager == nil {
   542  		return nil
   543  	}
   544  	return agent.agentResourceManager.GetAgentResource()
   545  }
   546  
   547  // GetAgentResourceManager - Returns Agent resource
   548  func GetAgentResourceManager() resource.Manager {
   549  	return agent.agentResourceManager
   550  }
   551  
   552  // AddUpdateAgentDetails - Adds a new or Updates an existing key on the agent details sub resource
   553  func AddUpdateAgentDetails(key, value string) {
   554  	if agent.agentResourceManager != nil {
   555  		agent.agentResourceManager.AddUpdateAgentDetails(key, value)
   556  	}
   557  }
   558  
   559  // GetDetailFromAgentResource - gets the value of an agent detail from the resource
   560  func GetDetailFromAgentResource(key string) string {
   561  	if agent.agentResourceManager == nil {
   562  		return ""
   563  	}
   564  	val, _ := util.GetAgentDetailsValue(agent.agentResourceManager.GetAgentResource(), key)
   565  	return val
   566  }
   567  
   568  // GetStatus - get the last reported status
   569  func GetStatus() string {
   570  	return agent.status
   571  }
   572  
   573  // UpdateStatus - Updates the agent state
   574  func UpdateStatus(status, description string) {
   575  	UpdateStatusWithPrevious(status, status, description)
   576  }
   577  
   578  // UpdateStatusWithPrevious - Updates the agent state providing a previous state
   579  func UpdateStatusWithPrevious(status, prevStatus, description string) {
   580  	ctx := context.WithValue(context.Background(), ctxLogger, logger)
   581  	UpdateStatusWithContext(ctx, status, prevStatus, description)
   582  }
   583  
   584  // UpdateStatusWithContext - Updates the agent state providing a context
   585  func UpdateStatusWithContext(ctx context.Context, status, prevStatus, description string) {
   586  	agent.status = status
   587  	logger := ctx.Value(ctxLogger).(log.FieldLogger)
   588  	if agent.agentResourceManager != nil {
   589  		err := agent.agentResourceManager.UpdateAgentStatus(status, prevStatus, description)
   590  		if err != nil {
   591  			logger.WithError(err).Warnf("could not update the agent status reference")
   592  		}
   593  	}
   594  }
   595  
   596  func setupSignalProcessor() {
   597  	if !agent.agentFeaturesCfg.ProcessSystemSignalsEnabled() {
   598  		return
   599  	}
   600  	sigs := make(chan os.Signal, 1)
   601  	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
   602  	go func() {
   603  		<-sigs
   604  		logger.Info("Stopping agent")
   605  		if agent.profileDone != nil {
   606  			<-agent.profileDone
   607  		}
   608  
   609  		// call the agent shutdown handler
   610  		if agent.agentShutdownHandler != nil {
   611  			agent.agentShutdownHandler()
   612  		}
   613  
   614  		cleanUp()
   615  		agent.cacheManager.SaveCache()
   616  		os.Exit(0)
   617  	}()
   618  }
   619  
   620  func setupProfileSignalProcessor(cpuProfile, memProfile string) {
   621  	if agent.agentFeaturesCfg.ProcessSystemSignalsEnabled() {
   622  		// create channel for base signal processor
   623  		agent.profileDone = make(chan struct{})
   624  	}
   625  
   626  	// start the CPU profiling
   627  	var cpuFile *os.File
   628  	if cpuProfile != "" {
   629  		var err error
   630  		cpuFile, err = os.Create(cpuProfile)
   631  		if err != nil {
   632  			fmt.Printf("Error creating cpu profiling file: %v", err)
   633  		}
   634  		if err := pprof.StartCPUProfile(cpuFile); err != nil {
   635  			fmt.Printf("Error running the cpu profiling: %v", err)
   636  		}
   637  	}
   638  
   639  	// Listen for a system signal to stop the agent
   640  	sigs := make(chan os.Signal, 1)
   641  	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
   642  	go func() {
   643  		<-sigs
   644  
   645  		// stop cpu profiling if it was started
   646  		if cpuProfile != "" {
   647  			pprof.StopCPUProfile()
   648  			cpuFile.Close()
   649  		}
   650  
   651  		// run the memory profiling
   652  		if memProfile != "" {
   653  			memFile, err := os.Create(memProfile)
   654  			if err != nil {
   655  				fmt.Printf("Error creating memory profiling file: %v", err)
   656  			}
   657  			runtime.GC() // get up-to-date statistics
   658  			if err := pprof.WriteHeapProfile(memFile); err != nil {
   659  				fmt.Printf("Error running the memory profiling: %v", err)
   660  			}
   661  			memFile.Close() // error handling omitted for example
   662  		}
   663  
   664  		if agent.agentFeaturesCfg.ProcessSystemSignalsEnabled() {
   665  			// signal the base signal processor now that the profiling output is complete
   666  			agent.profileDone <- struct{}{}
   667  		}
   668  	}()
   669  }
   670  
   671  // cleanUp - AgentCleanup
   672  func cleanUp() {
   673  	UpdateStatusWithPrevious(AgentStopped, AgentRunning, "")
   674  }
   675  
   676  func newHandlers() []handler.Handler {
   677  	envName := GetCentralConfig().GetEnvironmentName()
   678  	handlers := []handler.Handler{
   679  		handler.NewAPISvcHandler(agent.cacheManager, envName),
   680  		handler.NewInstanceHandler(agent.cacheManager, envName),
   681  		handler.NewAgentResourceHandler(agent.agentResourceManager),
   682  		handler.NewWatchResourceHandler(agent.cacheManager, agent.cfg),
   683  		agent.proxyResourceHandler,
   684  	}
   685  
   686  	if agent.cfg.GetAgentType() == config.DiscoveryAgent {
   687  		handlers = append(
   688  			handlers,
   689  			handler.NewCRDHandler(agent.cacheManager),
   690  			handler.NewARDHandler(agent.cacheManager),
   691  			handler.NewEnvironmentHandler(agent.cacheManager, agent.cfg.GetCredentialConfig(), envName),
   692  		)
   693  	}
   694  
   695  	// Register managed application and access handler for traceability agent
   696  	// For discovery agent, the handlers gets registered while setting up provisioner
   697  	if agent.cfg.GetAgentType() == config.TraceabilityAgent {
   698  		handlers = append(
   699  			handlers,
   700  			handler.NewTraceAccessRequestHandler(agent.cacheManager, agent.apicClient),
   701  			handler.NewTraceManagedApplicationHandler(agent.cacheManager),
   702  		)
   703  	}
   704  
   705  	return handlers
   706  }