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

     1  package cache
     2  
     3  import (
     4  	"encoding/json"
     5  	"sync"
     6  
     7  	defs "github.com/Axway/agent-sdk/pkg/apic/definitions"
     8  
     9  	v1 "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/api/v1"
    10  	"github.com/Axway/agent-sdk/pkg/cache"
    11  	"github.com/Axway/agent-sdk/pkg/config"
    12  	"github.com/Axway/agent-sdk/pkg/jobs"
    13  	"github.com/Axway/agent-sdk/pkg/util"
    14  	"github.com/Axway/agent-sdk/pkg/util/log"
    15  )
    16  
    17  const defaultCacheStoragePath = "./data/cache"
    18  
    19  // cache keys
    20  const (
    21  	apiServicesKey         = "apiServices"
    22  	apiServiceInstancesKey = "apiServiceInstances"
    23  	instanceCountKey       = "instanceCount"
    24  	credReqDefKey          = "credReqDef"
    25  	accReqDefKey           = "accReqDef"
    26  	teamsKey               = "teams"
    27  	managedAppKey          = "managedApp"
    28  	subscriptionsKey       = "subscriptions"
    29  	accReqKey              = "accReq"
    30  	watchSequenceKey       = "watchSequence"
    31  	watchResourceKey       = "watchResource"
    32  )
    33  
    34  // Manager - interface to manage agent resource
    35  type Manager interface {
    36  
    37  	// Cache management related methods
    38  	HasLoadedPersistedCache() bool
    39  	SaveCache()
    40  	Flush()
    41  
    42  	// API Service cache related methods
    43  	AddAPIService(resource *v1.ResourceInstance) error
    44  	GetAPIServiceCache() cache.Cache
    45  	GetAPIServiceKeys() []string
    46  	GetAPIServiceWithAPIID(apiID string) *v1.ResourceInstance
    47  	GetAPIServiceWithPrimaryKey(primaryKey string) *v1.ResourceInstance
    48  	GetAPIServiceWithName(apiName string) *v1.ResourceInstance
    49  	GetAPIServiceInstanceCount(apiName string) int
    50  	GetTeamsIDsInAPIServices() []string
    51  	DeleteAPIService(apiID string) error
    52  
    53  	// API service instance cache related methods
    54  	AddAPIServiceInstance(resource *v1.ResourceInstance)
    55  	GetAPIServiceInstanceKeys() []string
    56  	GetAPIServiceInstanceByID(id string) (*v1.ResourceInstance, error)
    57  	GetAPIServiceInstanceByName(apiName string) (*v1.ResourceInstance, error)
    58  	DeleteAPIServiceInstance(id string) error
    59  	DeleteAllAPIServiceInstance()
    60  	ListAPIServiceInstances() []*v1.ResourceInstance
    61  
    62  	// Team and ACL related cache methods
    63  	GetTeamCache() cache.Cache
    64  	AddTeam(team *defs.PlatformTeam)
    65  	GetTeamByName(name string) *defs.PlatformTeam
    66  	GetTeamByID(id string) *defs.PlatformTeam
    67  	GetDefaultTeam() *defs.PlatformTeam
    68  	SetAccessControlList(acl *v1.ResourceInstance)
    69  	GetAccessControlList() *v1.ResourceInstance
    70  	DeleteAccessControlList() error
    71  
    72  	// AccessRequestDefinition cache related methods
    73  	AddAccessRequestDefinition(resource *v1.ResourceInstance)
    74  	GetAccessRequestDefinitionKeys() []string
    75  	GetAccessRequestDefinitionByName(name string) (*v1.ResourceInstance, error)
    76  	GetAccessRequestDefinitionByID(id string) (*v1.ResourceInstance, error)
    77  	DeleteAccessRequestDefinition(id string) error
    78  
    79  	// CredentialRequestDefinition cache related methods
    80  	AddCredentialRequestDefinition(resource *v1.ResourceInstance)
    81  	GetCredentialRequestDefinitionKeys() []string
    82  	GetCredentialRequestDefinitionByName(name string) (*v1.ResourceInstance, error)
    83  	GetCredentialRequestDefinitionByID(id string) (*v1.ResourceInstance, error)
    84  	DeleteCredentialRequestDefinition(id string) error
    85  	ListCredentialRequestDefinitions() []*v1.ResourceInstance
    86  
    87  	// Watch Sequence cache related methods
    88  	AddSequence(watchTopicName string, sequenceID int64)
    89  	GetSequence(watchTopicName string) int64
    90  
    91  	// ManagedApplication cache related methods
    92  	GetManagedApplicationCacheKeys() []string
    93  	AddManagedApplication(resource *v1.ResourceInstance)
    94  	GetManagedApplication(id string) *v1.ResourceInstance
    95  	GetManagedApplicationByName(name string) *v1.ResourceInstance
    96  	DeleteManagedApplication(id string) error
    97  
    98  	// AccessRequest cache related methods
    99  	GetAccessRequestCacheKeys() []string
   100  	AddAccessRequest(resource *v1.ResourceInstance)
   101  	GetAccessRequestByAppAndAPI(managedAppName, remoteAPIID, remoteAPIStage string) *v1.ResourceInstance
   102  	GetAccessRequestByAppAndAPIStageVersion(managedAppName, remoteAPIID, remoteAPIStage, remoteAPIVersion string) *v1.ResourceInstance
   103  	GetAccessRequest(id string) *v1.ResourceInstance
   104  	GetAccessRequestsByApp(managedAppName string) []*v1.ResourceInstance
   105  	DeleteAccessRequest(id string) error
   106  	ListAccessRequests() []*v1.ResourceInstance
   107  
   108  	GetWatchResourceCacheKeys(group, kind string) []string
   109  	AddWatchResource(resource *v1.ResourceInstance)
   110  	GetWatchResourceByKey(key string) *v1.ResourceInstance
   111  	GetWatchResourceByID(group, kind, id string) *v1.ResourceInstance
   112  	GetWatchResourceByName(group, kind, name string) *v1.ResourceInstance
   113  	DeleteWatchResource(group, kind, id string) error
   114  
   115  	ApplyResourceReadLock()
   116  	ReleaseResourceReadLock()
   117  }
   118  
   119  type teamRefreshHandler func()
   120  type cacheManager struct {
   121  	jobs.Job
   122  	logger                  log.FieldLogger
   123  	apiMap                  cache.Cache
   124  	instanceCountMap        cache.Cache
   125  	instanceMap             cache.Cache
   126  	managedApplicationMap   cache.Cache
   127  	accessRequestMap        cache.Cache
   128  	watchResourceMap        cache.Cache
   129  	subscriptionMap         cache.Cache
   130  	sequenceCache           cache.Cache
   131  	resourceCacheReadLock   sync.Mutex
   132  	cacheLock               sync.Mutex
   133  	persistedCache          cache.Cache
   134  	teams                   cache.Cache
   135  	ardMap                  cache.Cache
   136  	crdMap                  cache.Cache
   137  	cacheFilename           string
   138  	isPersistedCacheLoaded  bool
   139  	isCacheUpdated          bool
   140  	isPersistedCacheEnabled bool
   141  	migrators               []cacheMigrate
   142  }
   143  
   144  // NewAgentCacheManager - Create a new agent cache manager
   145  func NewAgentCacheManager(cfg config.CentralConfig, persistCacheEnabled bool) Manager {
   146  	logger := log.NewFieldLogger().
   147  		WithComponent("cacheManager").
   148  		WithPackage("sdk.agent.cache")
   149  	m := &cacheManager{
   150  		isCacheUpdated:          false,
   151  		logger:                  logger,
   152  		isPersistedCacheEnabled: persistCacheEnabled,
   153  		migrators:               []cacheMigrate{},
   154  	}
   155  
   156  	if m.isPersistedCacheEnabled {
   157  		m.migrators = []cacheMigrate{
   158  			m.migrateAccessRequest,
   159  			m.migrateInstanceCount,
   160  		}
   161  	}
   162  	m.initializeCache(cfg)
   163  
   164  	return m
   165  }
   166  
   167  func (c *cacheManager) initializeCache(cfg config.CentralConfig) {
   168  	cacheMap := cache.New()
   169  	if c.isPersistedCacheEnabled {
   170  		c.cacheFilename = c.getCacheFileName(cfg)
   171  		cacheMap.Load(c.cacheFilename)
   172  	}
   173  
   174  	cacheKeys := map[string]func(cache.Cache){
   175  		apiServicesKey:         func(loaded cache.Cache) { c.apiMap = loaded },
   176  		apiServiceInstancesKey: func(loaded cache.Cache) { c.instanceMap = loaded },
   177  		instanceCountKey:       func(loaded cache.Cache) { c.instanceCountMap = loaded },
   178  		credReqDefKey:          func(loaded cache.Cache) { c.crdMap = loaded },
   179  		accReqDefKey:           func(loaded cache.Cache) { c.ardMap = loaded },
   180  		teamsKey:               func(loaded cache.Cache) { c.teams = loaded },
   181  		managedAppKey:          func(loaded cache.Cache) { c.managedApplicationMap = loaded },
   182  		subscriptionsKey:       func(loaded cache.Cache) { c.subscriptionMap = loaded },
   183  		accReqKey:              func(loaded cache.Cache) { c.accessRequestMap = loaded },
   184  		watchSequenceKey:       func(loaded cache.Cache) { c.sequenceCache = loaded },
   185  		watchResourceKey:       func(loaded cache.Cache) { c.watchResourceMap = loaded },
   186  	}
   187  
   188  	c.isPersistedCacheLoaded = true
   189  	c.isCacheUpdated = false
   190  	for key := range cacheKeys {
   191  		loadedMap, isNew := c.loadPersistedResourceInstanceCache(cacheMap, key)
   192  		if isNew {
   193  			c.isPersistedCacheLoaded = false
   194  		}
   195  		cacheKeys[key](loadedMap)
   196  	}
   197  
   198  	// after loading check for migrations
   199  	for key := range cacheKeys {
   200  		c.migratePersistentCache(key)
   201  	}
   202  
   203  	c.persistedCache = cacheMap
   204  	if c.isPersistedCacheEnabled && util.IsNotTest() {
   205  		jobs.RegisterIntervalJobWithName(c, cfg.GetCacheStorageInterval(), "Agent cache persistence")
   206  	}
   207  }
   208  
   209  func (c *cacheManager) getCacheFileName(cfg config.CentralConfig) string {
   210  	cachePath := cfg.GetCacheStoragePath()
   211  	if cachePath == "" {
   212  		cachePath = defaultCacheStoragePath
   213  	}
   214  	util.CreateDirIfNotExist(cachePath)
   215  	if cfg.GetAgentName() != "" {
   216  		return cachePath + "/" + cfg.GetAgentName() + ".cache"
   217  	}
   218  	return cachePath + "/" + cfg.GetEnvironmentName() + ".cache"
   219  }
   220  
   221  func (c *cacheManager) loadPersistedCache(cacheMap cache.Cache, key string) (cache.Cache, bool) {
   222  	itemCache, _ := cacheMap.Get(key)
   223  	if itemCache != nil {
   224  		raw, _ := json.Marshal(itemCache)
   225  		return cache.LoadFromBuffer(raw), false
   226  	}
   227  	return cache.New(), true
   228  }
   229  
   230  func (c *cacheManager) loadPersistedResourceInstanceCache(cacheMap cache.Cache, cacheKey string) (cache.Cache, bool) {
   231  	riCache, isNew := c.loadPersistedCache(cacheMap, cacheKey)
   232  	keys := riCache.GetKeys()
   233  	for _, key := range keys {
   234  		item, _ := riCache.Get(key)
   235  		rawResource, _ := json.Marshal(item)
   236  		// If instance count then use apiServiceToInstanceCount type
   237  		if cacheKey == instanceCountKey {
   238  			ic := apiServiceToInstanceCount{}
   239  			if err := json.Unmarshal(rawResource, &ic); err == nil {
   240  				riCache.Set(key, ic)
   241  			}
   242  		} else {
   243  			ri := &v1.ResourceInstance{}
   244  			if json.Unmarshal(rawResource, ri) == nil {
   245  				riCache.Set(key, ri)
   246  			}
   247  		}
   248  	}
   249  
   250  	cacheMap.Set(cacheKey, riCache)
   251  	return riCache, isNew
   252  }
   253  
   254  func (c *cacheManager) setCacheUpdated(updated bool) {
   255  	c.isCacheUpdated = updated
   256  }
   257  
   258  // Cache persistence job
   259  
   260  // Ready -
   261  func (c *cacheManager) Ready() bool {
   262  	return true
   263  }
   264  
   265  // Status -
   266  func (c *cacheManager) Status() error {
   267  	return nil
   268  }
   269  
   270  // Execute - persists the cache to file
   271  func (c *cacheManager) Execute() error {
   272  	if util.IsNotTest() && c.isCacheUpdated {
   273  		c.logger.Trace("executing cache persistence job")
   274  		c.SaveCache()
   275  	}
   276  	return nil
   277  }
   278  
   279  // Cache manager
   280  
   281  // HasLoadedPersistedCache - returns true if the caches are loaded from file
   282  func (c *cacheManager) HasLoadedPersistedCache() bool {
   283  	return c.isPersistedCacheLoaded
   284  }
   285  
   286  // SaveCache - writes the cache to a file
   287  func (c *cacheManager) SaveCache() {
   288  	if c.persistedCache != nil && c.isPersistedCacheEnabled {
   289  		c.cacheLock.Lock()
   290  		defer c.cacheLock.Unlock()
   291  		c.persistedCache.Save(c.cacheFilename)
   292  		c.setCacheUpdated(false)
   293  		c.logger.Debug("persistent cache has been saved")
   294  	}
   295  }
   296  
   297  // Watch Sequence cache
   298  
   299  // AddSequence - add/updates the sequenceID for the watch topic in cache
   300  func (c *cacheManager) AddSequence(watchTopicName string, sequenceID int64) {
   301  	defer c.setCacheUpdated(true)
   302  
   303  	c.sequenceCache.Set(watchTopicName, sequenceID)
   304  }
   305  
   306  // GetSequence - returns the sequenceID for the watch topic in cache
   307  func (c *cacheManager) GetSequence(watchTopicName string) int64 {
   308  	cachedSeqID, err := c.sequenceCache.Get(watchTopicName)
   309  	if err == nil {
   310  		if seqID, ok := cachedSeqID.(int64); ok {
   311  			return seqID
   312  		} else if seqID, ok := cachedSeqID.(float64); ok {
   313  			return int64(seqID)
   314  		}
   315  	}
   316  	return 0
   317  }
   318  
   319  func (c *cacheManager) ApplyResourceReadLock() {
   320  	c.resourceCacheReadLock.Lock()
   321  }
   322  
   323  func (c *cacheManager) ReleaseResourceReadLock() {
   324  	c.resourceCacheReadLock.Unlock()
   325  }
   326  
   327  // Flush empties the persistent cache and all internal caches
   328  func (c *cacheManager) Flush() {
   329  	c.ApplyResourceReadLock()
   330  	defer c.ReleaseResourceReadLock()
   331  	c.logger.Debug("resetting the persistent cache")
   332  
   333  	c.accessRequestMap.Flush()
   334  	c.apiMap.Flush()
   335  	c.ardMap.Flush()
   336  	c.crdMap.Flush()
   337  	c.instanceMap.Flush()
   338  	c.managedApplicationMap.Flush()
   339  	c.sequenceCache.Flush()
   340  	c.subscriptionMap.Flush()
   341  	c.watchResourceMap.Flush()
   342  	c.SaveCache()
   343  }