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 }