Skip to content

Commit

Permalink
Add listManagedInstancesResults to GceCache.
Browse files Browse the repository at this point in the history
  • Loading branch information
dsafdsa1 committed Mar 13, 2024
1 parent b8506af commit 2b4fa12
Show file tree
Hide file tree
Showing 7 changed files with 247 additions and 54 deletions.
15 changes: 15 additions & 0 deletions cluster-autoscaler/cloudprovider/gce/autoscaling_gce_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ type AutoscalingGceClient interface {
FetchAvailableCpuPlatforms() (map[string][]string, error)
FetchReservations() ([]*gce.Reservation, error)
FetchReservationsInProject(projectId string) ([]*gce.Reservation, error)
FetchListManagedInstancesResults(migRef GceRef) (string, error)

// modifying resources
ResizeMig(GceRef, int64) error
Expand Down Expand Up @@ -234,6 +235,20 @@ func (client *autoscalingGceClientV1) FetchMigBasename(migRef GceRef) (string, e
return igm.BaseInstanceName, nil
}

func (client *autoscalingGceClientV1) FetchListManagedInstancesResults(migRef GceRef) (string, error) {
registerRequest("instance_group_managers", "get")
igm, err := client.gceService.InstanceGroupManagers.Get(migRef.Project, migRef.Zone, migRef.Name).Fields("listManagedInstancesResults").Do()
if err != nil {
if err, ok := err.(*googleapi.Error); ok {
if err.Code == http.StatusNotFound {
return "", errors.NewAutoscalerError(errors.NodeGroupDoesNotExistError, "%s", err.Error())
}
}
return "", err
}
return igm.ListManagedInstancesResults, nil
}

func (client *autoscalingGceClientV1) ResizeMig(migRef GceRef, size int64) error {
registerRequest("instance_group_managers", "resize")
op, err := client.gceService.InstanceGroupManagers.Resize(migRef.Project, migRef.Zone, migRef.Name, size).Do()
Expand Down
74 changes: 49 additions & 25 deletions cluster-autoscaler/cloudprovider/gce/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,36 +56,38 @@ type GceCache struct {
cacheMutex sync.Mutex

// Cache content.
migs map[GceRef]Mig
instances map[GceRef][]GceInstance
instancesUpdateTime map[GceRef]time.Time
instancesToMig map[GceRef]GceRef
instancesFromUnknownMig map[GceRef]bool
resourceLimiter *cloudprovider.ResourceLimiter
autoscalingOptionsCache map[GceRef]map[string]string
machinesCache map[MachineTypeKey]MachineType
migTargetSizeCache map[GceRef]int64
migBaseNameCache map[GceRef]string
instanceTemplateNameCache map[GceRef]string
instanceTemplatesCache map[GceRef]*gce.InstanceTemplate
kubeEnvCache map[GceRef]KubeEnv
migs map[GceRef]Mig
instances map[GceRef][]GceInstance
instancesUpdateTime map[GceRef]time.Time
instancesToMig map[GceRef]GceRef
instancesFromUnknownMig map[GceRef]bool
resourceLimiter *cloudprovider.ResourceLimiter
autoscalingOptionsCache map[GceRef]map[string]string
machinesCache map[MachineTypeKey]MachineType
migTargetSizeCache map[GceRef]int64
migBaseNameCache map[GceRef]string
listManagedInstancesResultsCache map[GceRef]string
instanceTemplateNameCache map[GceRef]string
instanceTemplatesCache map[GceRef]*gce.InstanceTemplate
kubeEnvCache map[GceRef]KubeEnv
}

// NewGceCache creates empty GceCache.
func NewGceCache() *GceCache {
return &GceCache{
migs: map[GceRef]Mig{},
instances: map[GceRef][]GceInstance{},
instancesUpdateTime: map[GceRef]time.Time{},
instancesToMig: map[GceRef]GceRef{},
instancesFromUnknownMig: map[GceRef]bool{},
autoscalingOptionsCache: map[GceRef]map[string]string{},
machinesCache: map[MachineTypeKey]MachineType{},
migTargetSizeCache: map[GceRef]int64{},
migBaseNameCache: map[GceRef]string{},
instanceTemplateNameCache: map[GceRef]string{},
instanceTemplatesCache: map[GceRef]*gce.InstanceTemplate{},
kubeEnvCache: map[GceRef]KubeEnv{},
migs: map[GceRef]Mig{},
instances: map[GceRef][]GceInstance{},
instancesUpdateTime: map[GceRef]time.Time{},
instancesToMig: map[GceRef]GceRef{},
instancesFromUnknownMig: map[GceRef]bool{},
autoscalingOptionsCache: map[GceRef]map[string]string{},
machinesCache: map[MachineTypeKey]MachineType{},
migTargetSizeCache: map[GceRef]int64{},
migBaseNameCache: map[GceRef]string{},
listManagedInstancesResultsCache: map[GceRef]string{},
instanceTemplateNameCache: map[GceRef]string{},
instanceTemplatesCache: map[GceRef]*gce.InstanceTemplate{},
kubeEnvCache: map[GceRef]KubeEnv{},
}
}

Expand Down Expand Up @@ -515,3 +517,25 @@ func (gc *GceCache) InvalidateAllMigBasenames() {
defer gc.cacheMutex.Unlock()
gc.migBaseNameCache = make(map[GceRef]string)
}

// SetListManagedInstancesResults sets listManagedInstancesResults for a given mig in cache
func (gc *GceCache) SetListManagedInstancesResults(migRef GceRef, listManagedInstancesResults string) {
gc.cacheMutex.Lock()
defer gc.cacheMutex.Unlock()
gc.listManagedInstancesResultsCache[migRef] = listManagedInstancesResults
}

// GetListManagedInstancesResults gets listManagedInstancesResults for a given mig from cache.
func (gc *GceCache) GetListManagedInstancesResults(migRef GceRef) (string, bool) {
gc.cacheMutex.Lock()
defer gc.cacheMutex.Unlock()
listManagedInstancesResults, found := gc.listManagedInstancesResultsCache[migRef]
return listManagedInstancesResults, found
}

// InvalidateAllListManagedInstancesResults invalidates all listManagedInstancesResults entries.
func (gc *GceCache) InvalidateAllListManagedInstancesResults() {
gc.cacheMutex.Lock()
defer gc.cacheMutex.Unlock()
gc.listManagedInstancesResultsCache = make(map[GceRef]string)
}
26 changes: 26 additions & 0 deletions cluster-autoscaler/cloudprovider/gce/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,29 @@ func TestMachineCache(t *testing.T) {
})
}
}

func TestListManagedInstancesResultsCache(t *testing.T) {
checkInCache := func(c *GceCache, migRef GceRef, expectedResults string) {
result, found := c.GetListManagedInstancesResults(migRef)
if !found {
t.Errorf("Results not found for MIG ref: %s", migRef.String())
}
if result != expectedResults {
t.Errorf("Expected results %s for MIG ref: %s, but got: %s", expectedResults, migRef.String(), result)
}
}
migRef := GceRef{
Project: "project",
Zone: "us-test1",
Name: "mig",
}
c := NewGceCache()
c.SetListManagedInstancesResults(migRef, "PAGINATED")
checkInCache(c, migRef, "PAGINATED")
c.SetListManagedInstancesResults(migRef, "PAGELESS")
checkInCache(c, migRef, "PAGELESS")
c.InvalidateAllListManagedInstancesResults()
if cacheSize := len(c.listManagedInstancesResultsCache); cacheSize > 0 {
t.Errorf("Expected listManagedInstancesResultsCache to be empty, but it still contains %d entries", cacheSize)
}
}
1 change: 1 addition & 0 deletions cluster-autoscaler/cloudprovider/gce/gce_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ func (m *gceManagerImpl) Refresh() error {
m.cache.InvalidateAllMigInstances()
m.cache.InvalidateAllMigTargetSizes()
m.cache.InvalidateAllMigBasenames()
m.cache.InvalidateAllListManagedInstancesResults()
m.cache.InvalidateAllMigInstanceTemplateNames()
if m.lastRefresh.Add(refreshInterval).After(time.Now()) {
return nil
Expand Down
11 changes: 6 additions & 5 deletions cluster-autoscaler/cloudprovider/gce/gce_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,11 +343,12 @@ func newTestGceManager(t *testing.T, testServerURL string, regional bool) *gceMa
{"us-central1-c", "n1-standard-1"}: {Name: "n1-standard-1", CPU: 1, Memory: 1},
{"us-central1-f", "n1-standard-1"}: {Name: "n1-standard-1", CPU: 1, Memory: 1},
},
migTargetSizeCache: map[GceRef]int64{},
instanceTemplateNameCache: map[GceRef]string{},
instanceTemplatesCache: map[GceRef]*gce.InstanceTemplate{},
kubeEnvCache: map[GceRef]KubeEnv{},
migBaseNameCache: map[GceRef]string{},
migTargetSizeCache: map[GceRef]int64{},
instanceTemplateNameCache: map[GceRef]string{},
instanceTemplatesCache: map[GceRef]*gce.InstanceTemplate{},
kubeEnvCache: map[GceRef]KubeEnv{},
migBaseNameCache: map[GceRef]string{},
listManagedInstancesResultsCache: map[GceRef]string{},
}
migLister := NewMigLister(cache)
manager := &gceManagerImpl{
Expand Down
28 changes: 28 additions & 0 deletions cluster-autoscaler/cloudprovider/gce/mig_info_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ type MigInfoProvider interface {
// For custom machines cpu and memory information is based on parsing
// machine name. For standard types it's retrieved from GCE API.
GetMigMachineType(migRef GceRef) (MachineType, error)
// Returns the pagination behavior of the listManagedInstances API method for a given MIG ref
GetListManagedInstancesResults(migRef GceRef) (string, error)
}

type timeProvider interface {
Expand Down Expand Up @@ -356,6 +358,7 @@ func (c *cachingMigInfoProvider) fillMigInfoCache() error {
if registeredMigRefs[zoneMigRef] {
c.cache.SetMigTargetSize(zoneMigRef, zoneMig.TargetSize)
c.cache.SetMigBasename(zoneMigRef, zoneMig.BaseInstanceName)
c.cache.SetListManagedInstancesResults(zoneMigRef, zoneMig.ListManagedInstancesResults)

templateUrl, err := url.Parse(zoneMig.InstanceTemplate)
if err == nil {
Expand Down Expand Up @@ -411,3 +414,28 @@ func (c *cachingMigInfoProvider) GetMigMachineType(migRef GceRef) (MachineType,
}
return machine, nil
}

func (c *cachingMigInfoProvider) GetListManagedInstancesResults(migRef GceRef) (string, error) {
c.migInfoMutex.Lock()
defer c.migInfoMutex.Unlock()

listManagedInstancesResults, found := c.cache.GetListManagedInstancesResults(migRef)
if found {
return listManagedInstancesResults, nil
}

err := c.fillMigInfoCache()
listManagedInstancesResults, found = c.cache.GetListManagedInstancesResults(migRef)
if err == nil && found {
return listManagedInstancesResults, nil
}

// fallback to querying for a single mig
listManagedInstancesResults, err = c.gceClient.FetchListManagedInstancesResults(migRef)
if err != nil {
c.migLister.HandleMigIssue(migRef, err)
return "", err
}
c.cache.SetListManagedInstancesResults(migRef, listManagedInstancesResults)
return listManagedInstancesResults, nil
}
Loading

0 comments on commit 2b4fa12

Please sign in to comment.