internal/utils/controller/cache_helper.go (86 lines of code) (raw):
package controller
import (
"crypto/sha256"
"encoding/hex"
"math/rand"
"sort"
"strings"
"time"
"github.com/samber/lo"
corev1 "k8s.io/api/core/v1"
"github.com/Azure/operation-cache-controller/api/v1alpha1"
)
type CacheHelper struct{}
func NewCacheHelper() CacheHelper { return CacheHelper{} }
func (c CacheHelper) RandomSelectCachedOperation(cache *v1alpha1.Cache) string {
if len(cache.Status.AvailableCaches) == 0 {
return ""
}
// nolint:gosec, G404 // this is expected PRNG usage
return cache.Status.AvailableCaches[rand.Intn(len(cache.Status.AvailableCaches))]
}
func (c CacheHelper) DefaultCacheExpireTime() string {
// cache expire after 2 hours
return time.Now().Add(2 * time.Hour).Format(time.RFC3339)
}
type AppCacheField struct {
Name string
Image string
Command []string
Args []string
WorkingDir string
Env []corev1.EnvVar
Dependencies []string
}
func (c *AppCacheField) NewCacheKey() string {
hasher := sha256.New()
hasher.Write([]byte(c.Name))
hasher.Write([]byte(c.Image))
hasher.Write([]byte(strings.Join(c.Command, " ")))
hasher.Write([]byte(strings.Join(c.Args, " ")))
hasher.Write([]byte(c.WorkingDir))
// Sort environment variables to ensure consistent hashing
sort.Slice(c.Env, func(i, j int) bool {
return c.Env[i].Name < c.Env[j].Name
})
for _, env := range c.Env {
hasher.Write([]byte(env.Name + "=" + env.Value))
}
// Sort dependencies to ensure consistent hashing
sort.Strings(c.Dependencies)
for _, dep := range c.Dependencies {
hasher.Write([]byte(dep))
}
return hex.EncodeToString(hasher.Sum(nil))
}
func (c CacheHelper) NewCacheKeyFromApplications(apps []v1alpha1.ApplicationSpec) string {
// sort the apps by name to ensure consistent hashing
sort.Slice(apps, func(i, j int) bool {
return apps[i].Name < apps[j].Name
})
srcCacheKeys := lo.Reduce(apps, func(acc []string, app v1alpha1.ApplicationSpec, index int) []string {
return append(acc, c.AppCacheFieldFromApplicationProvision(app).NewCacheKey())
}, []string{})
// get the cache id for the source
hasher := sha256.New()
for _, id := range srcCacheKeys {
hasher.Write([]byte(id))
}
return hex.EncodeToString(hasher.Sum(nil))
}
func (c CacheHelper) AppCacheFieldFromApplicationProvision(app v1alpha1.ApplicationSpec) *AppCacheField {
return &AppCacheField{
Name: app.Name,
Image: app.Provision.Template.Spec.Containers[0].Image,
Command: app.Provision.Template.Spec.Containers[0].Command,
Args: app.Provision.Template.Spec.Containers[0].Args,
WorkingDir: app.Provision.Template.Spec.Containers[0].WorkingDir,
Env: app.Provision.Template.Spec.Containers[0].Env,
Dependencies: app.Dependencies,
}
}
func (c CacheHelper) AppCacheFieldFromApplicationTeardown(app v1alpha1.ApplicationSpec) *AppCacheField {
return &AppCacheField{
Name: app.Name,
Image: app.Teardown.Template.Spec.Containers[0].Image,
Command: app.Teardown.Template.Spec.Containers[0].Command,
Args: app.Teardown.Template.Spec.Containers[0].Args,
WorkingDir: app.Teardown.Template.Spec.Containers[0].WorkingDir,
Env: app.Teardown.Template.Spec.Containers[0].Env,
Dependencies: app.Dependencies,
}
}