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

     1  package agent
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"time"
     7  
     8  	"github.com/Axway/agent-sdk/pkg/agent/events"
     9  	"github.com/Axway/agent-sdk/pkg/agent/poller"
    10  	"github.com/Axway/agent-sdk/pkg/agent/stream"
    11  	management "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/management/v1alpha1"
    12  	"github.com/Axway/agent-sdk/pkg/config"
    13  	"github.com/Axway/agent-sdk/pkg/harvester"
    14  	"github.com/Axway/agent-sdk/pkg/jobs"
    15  	"github.com/Axway/agent-sdk/pkg/migrate"
    16  	"github.com/Axway/agent-sdk/pkg/util"
    17  )
    18  
    19  // EventSync struct for syncing events from central
    20  type EventSync struct {
    21  	watchTopic     *management.WatchTopic
    22  	sequence       events.SequenceProvider
    23  	harvester      harvester.Harvest
    24  	discoveryCache *discoveryCache
    25  }
    26  
    27  // NewEventSync creates an EventSync
    28  func NewEventSync() (*EventSync, error) {
    29  	migrations := []migrate.Migrator{}
    30  
    31  	// Make sure only DA and Governance agents run migration processes
    32  	runMigrations := agent.cfg.GetAgentType() != config.TraceabilityAgent
    33  
    34  	if runMigrations {
    35  		// add attribute migration to migrations
    36  		attributeMigration := migrate.NewAttributeMigration(agent.apicClient, agent.cfg)
    37  		ardMigration := migrate.NewArdMigration(agent.apicClient, agent.cfg)
    38  		apisiMigration := migrate.NewAPISIMigration(agent.apicClient, agent.cfg)
    39  		instanceMigration := migrate.NewInstanceMigration(agent.apicClient, agent.cfg)
    40  		migrations = append(migrations, attributeMigration, ardMigration, apisiMigration, instanceMigration)
    41  
    42  	}
    43  
    44  	mig := migrate.NewMigrateAll(migrations...)
    45  
    46  	opts := []discoveryOpt{
    47  		withMigration(mig),
    48  	}
    49  
    50  	if agent.agentResourceManager != nil {
    51  		opts = append(opts, withAdditionalDiscoverFuncs(agent.agentResourceManager.FetchAgentResource))
    52  	}
    53  
    54  	wt, err := events.GetWatchTopic(agent.cfg, GetCentralClient())
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  
    59  	sequence := events.NewSequenceProvider(agent.cacheManager, wt.Name)
    60  	hCfg := harvester.NewConfig(agent.cfg, agent.tokenRequester, sequence)
    61  	hClient := harvester.NewClient(hCfg)
    62  
    63  	discoveryCache := newDiscoveryCache(
    64  		agent.cfg,
    65  		GetCentralClient(),
    66  		newHandlers(),
    67  		wt,
    68  		opts...,
    69  	)
    70  
    71  	return &EventSync{
    72  		watchTopic:     wt,
    73  		sequence:       sequence,
    74  		harvester:      hClient,
    75  		discoveryCache: discoveryCache,
    76  	}, nil
    77  }
    78  
    79  // SyncCache initializes agent cache and starts the agent in stream or poll mode
    80  func (es *EventSync) SyncCache() error {
    81  	if !agent.cacheManager.HasLoadedPersistedCache() {
    82  		if err := es.initCache(); err != nil {
    83  			return err
    84  		}
    85  	}
    86  
    87  	err := registerExternalIDPs()
    88  	if err != nil {
    89  		logger.WithError(err).Warn("failed to register CRDs for external IdP config")
    90  	}
    91  
    92  	err = es.startCentralEventProcessor()
    93  	if err != nil {
    94  		return err
    95  	}
    96  
    97  	return es.registerInstanceValidator()
    98  }
    99  
   100  func (es *EventSync) registerInstanceValidator() error {
   101  	if agent.apiValidatorJobID == "" && agent.cfg.GetAgentType() == config.DiscoveryAgent {
   102  		jobID, err := jobs.RegisterScheduledJobWithName(newInstanceValidator(), agent.cfg.GetAPIValidationCronSchedule(), "API service instance validator")
   103  		agent.apiValidatorJobID = jobID
   104  		return err
   105  	}
   106  	return nil
   107  }
   108  
   109  func (es *EventSync) initCache() error {
   110  	seqID, err := es.harvester.ReceiveSyncEvents(es.watchTopic.GetSelfLink(), 0, nil)
   111  	if err != nil {
   112  		return err
   113  	}
   114  	// event channel is not ready yet, so subtract one from the latest sequence id to process the event
   115  	// when the poll/stream client is ready
   116  	// when no events returned by harvester the seqID will be 0, so not updated in sequence manager
   117  	agent.cacheManager.Flush()
   118  	if seqID > 0 {
   119  		es.sequence.SetSequence(seqID - 1)
   120  	}
   121  	err = es.discoveryCache.execute()
   122  	if err != nil {
   123  		// flush cache again to clear out anything that may have been saved before the error to ensure a clean state for the next time through
   124  		agent.cacheManager.Flush()
   125  		return err
   126  	}
   127  	agent.cacheManager.SaveCache()
   128  
   129  	agentInstance := agent.agentResourceManager.GetAgentResource()
   130  
   131  	// add 7 days to the current date for the next rebuild cache
   132  	nextCacheUpdateTime := time.Now().Add(7 * 24 * time.Hour)
   133  
   134  	// persist cacheUpdateTime
   135  	util.SetAgentDetailsKey(agentInstance, "cacheUpdateTime", strconv.FormatInt(nextCacheUpdateTime.UnixNano(), 10))
   136  	agent.apicClient.CreateSubResource(agentInstance.ResourceMeta, util.GetSubResourceDetails(agentInstance))
   137  	logger.Tracef("setting next cache update time to - %s", time.Unix(0, nextCacheUpdateTime.UnixNano()).Format("2006-01-02 15:04:05.000000"))
   138  	return nil
   139  }
   140  
   141  func (es *EventSync) RebuildCache() {
   142  	// SDB - NOTE : Do we need to pause jobs.
   143  	logger.Info("rebuild cache")
   144  
   145  	// close window so discovery doesn't happen during this cache rebuild
   146  	PublishingLock()
   147  	defer PublishingUnlock()
   148  
   149  	if err := es.initCache(); err != nil {
   150  		logger.WithError(err).Error("failed to rebuild cache")
   151  	}
   152  }
   153  
   154  func (es *EventSync) startCentralEventProcessor() error {
   155  	if agent.cfg.IsUsingGRPC() {
   156  		return es.startStreamMode()
   157  	}
   158  	return es.startPollMode()
   159  }
   160  
   161  func (es *EventSync) startPollMode() error {
   162  	handlers := newHandlers()
   163  
   164  	pc, err := poller.NewPollClient(
   165  		agent.apicClient,
   166  		agent.cfg,
   167  		handlers,
   168  		poller.WithHarvester(es.harvester, es.sequence, es.watchTopic.GetSelfLink()),
   169  		poller.WithOnClientStop(es.RebuildCache),
   170  		poller.WithOnConnect(),
   171  	)
   172  
   173  	if err != nil {
   174  		return fmt.Errorf("could not start the harvester poll client: %s", err)
   175  	}
   176  
   177  	if util.IsNotTest() {
   178  		newEventProcessorJob(pc, "Poll Client")
   179  	}
   180  
   181  	return err
   182  }
   183  
   184  func (es *EventSync) startStreamMode() error {
   185  	handlers := newHandlers()
   186  
   187  	sc, err := stream.NewStreamerClient(
   188  		agent.apicClient,
   189  		agent.cfg,
   190  		agent.tokenRequester,
   191  		handlers,
   192  		stream.WithOnStreamConnection(),
   193  		stream.WithEventSyncError(es.RebuildCache),
   194  		stream.WithWatchTopic(es.watchTopic),
   195  		stream.WithHarvester(es.harvester, es.sequence),
   196  		stream.WithCacheManager(agent.cacheManager),
   197  		stream.WithUserAgent(GetUserAgent()),
   198  	)
   199  
   200  	if err != nil {
   201  		return fmt.Errorf("could not start the watch manager: %s", err)
   202  	}
   203  
   204  	agent.streamer = sc
   205  
   206  	if util.IsNotTest() {
   207  		newEventProcessorJob(sc, "Stream Client")
   208  	}
   209  
   210  	return err
   211  }