Skip to content

Commit 634129d

Browse files
List and cache InstanceGroupManagers instead of getting them separately to improve node pool reconciliation time (#15086)
1 parent 84686f1 commit 634129d

File tree

1 file changed

+100
-10
lines changed

1 file changed

+100
-10
lines changed

mmv1/third_party/terraform/services/container/resource_container_node_pool.go.tmpl

Lines changed: 100 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package container
22

33
import (
4+
{{- if ne $.TargetVersionName `ga` }}
5+
"context"
6+
{{- end }}
47
"fmt"
58
"log"
69
"regexp"
@@ -22,6 +25,7 @@ import (
2225
{{ if eq $.TargetVersionName `ga` }}
2326
"google.golang.org/api/container/v1"
2427
{{- else }}
28+
compute "google.golang.org/api/compute/v0.beta"
2529
container "google.golang.org/api/container/v1beta1"
2630
{{- end }}
2731
)
@@ -51,13 +55,13 @@ func (nodePoolCache *nodePoolCache) get(nodePool string) (*container.NodePool, e
5155
}
5256

5357
func (nodePoolCache *nodePoolCache) refreshIfNeeded(d *schema.ResourceData, config *transport_tpg.Config, userAgent string, nodePoolInfo *NodePoolInformation, name string) error {
58+
nodePoolCache.mutex.Lock()
59+
defer nodePoolCache.mutex.Unlock()
60+
5461
if !nodePoolCache.needsRefresh(nodePoolInfo.fullyQualifiedName(name)) {
5562
return nil
5663
}
5764

58-
nodePoolCache.mutex.Lock()
59-
defer nodePoolCache.mutex.Unlock()
60-
6165
parent := fmt.Sprintf("projects/%s/locations/%s/clusters/%s", nodePoolInfo.project, nodePoolInfo.location, nodePoolInfo.cluster)
6266
clusterNodePoolsListCall := config.NewContainerClient(userAgent).Projects.Locations.Clusters.NodePools.List(parent)
6367
if config.UserProjectOverride {
@@ -79,8 +83,6 @@ func (nodePoolCache *nodePoolCache) refreshIfNeeded(d *schema.ResourceData, conf
7983
}
8084

8185
func (nodePoolCache *nodePoolCache) needsRefresh(nodePool string) bool {
82-
nodePoolCache.mutex.RLock()
83-
defer nodePoolCache.mutex.RUnlock()
8486
np, ok := nodePoolCache.nodePools[nodePool]
8587
if !ok {
8688
return true
@@ -94,10 +96,79 @@ func (nodePoolCache *nodePoolCache) remove(nodePool string) {
9496
delete(nodePoolCache.nodePools, nodePool)
9597
}
9698

97-
var npCache = &nodePoolCache{
98-
nodePools: make(map[string]*nodePoolWithUpdateTime),
99-
ttl: 30 * time.Second,
99+
type instanceGroupManagerWithUpdateTime struct {
100+
instanceGroupManager *compute.InstanceGroupManager
101+
updateTime time.Time
102+
}
103+
104+
type instanceGroupManagerCache struct {
105+
instanceGroupManagers map[string]*instanceGroupManagerWithUpdateTime
106+
ttl time.Duration
107+
mutex sync.RWMutex
100108
}
109+
110+
func (instanceGroupManagerCache *instanceGroupManagerCache) get(fullyQualifiedName string) (*compute.InstanceGroupManager, bool) {
111+
instanceGroupManagerCache.mutex.RLock()
112+
defer instanceGroupManagerCache.mutex.RUnlock()
113+
igm, ok := instanceGroupManagerCache.instanceGroupManagers[fullyQualifiedName]
114+
if !ok {
115+
return nil, false
116+
}
117+
return igm.instanceGroupManager, true
118+
}
119+
120+
func (instanceGroupManagerCache *instanceGroupManagerCache) refreshIfNeeded(d *schema.ResourceData, config *transport_tpg.Config, userAgent string, npName string, igmUrl string) error {
121+
instanceGroupManagerCache.mutex.Lock()
122+
defer instanceGroupManagerCache.mutex.Unlock()
123+
124+
matches := instanceGroupManagerURL.FindStringSubmatch(igmUrl)
125+
if len(matches) < 4 {
126+
return fmt.Errorf("Error reading instance group manager URL %q", igmUrl)
127+
}
128+
129+
if !instanceGroupManagerCache.needsRefresh(matches[0]) {
130+
return nil
131+
}
132+
133+
updateTime := time.Now()
134+
err := config.NewComputeClient(userAgent).InstanceGroupManagers.List(matches[1], matches[2]).Pages(context.Background(), instanceGroupManagerCache.processList(updateTime))
135+
if err != nil {
136+
return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("InstanceGroupManagers for node pool %q", npName))
137+
}
138+
return nil
139+
}
140+
141+
func (instanceGroupManagerCache *instanceGroupManagerCache) processList(updateTime time.Time) func(*compute.InstanceGroupManagerList) error {
142+
return func(igmList *compute.InstanceGroupManagerList) error {
143+
for _, instanceGroupManager := range igmList.Items {
144+
fullyQualifiedName := instanceGroupManagerURL.FindString(instanceGroupManager.SelfLink)
145+
instanceGroupManagerCache.instanceGroupManagers[fullyQualifiedName] = &instanceGroupManagerWithUpdateTime{
146+
instanceGroupManager: instanceGroupManager,
147+
updateTime: updateTime,
148+
}
149+
}
150+
return nil
151+
}
152+
}
153+
154+
func (instanceGroupManagerCache *instanceGroupManagerCache) needsRefresh(fullyQualifiedName string) bool {
155+
igm, ok := instanceGroupManagerCache.instanceGroupManagers[fullyQualifiedName]
156+
if !ok {
157+
return true
158+
}
159+
return time.Since(igm.updateTime) > instanceGroupManagerCache.ttl
160+
}
161+
162+
var (
163+
npCache = &nodePoolCache{
164+
nodePools: make(map[string]*nodePoolWithUpdateTime),
165+
ttl: 30 * time.Second,
166+
}
167+
igmCache = &instanceGroupManagerCache{
168+
instanceGroupManagers: make(map[string]*instanceGroupManagerWithUpdateTime),
169+
ttl: 30 * time.Second,
170+
}
171+
)
101172
{{- end }}
102173

103174
func ResourceContainerNodePool() *schema.Resource {
@@ -794,7 +865,9 @@ func resourceContainerNodePoolRead(d *schema.ResourceData, meta interface{}) err
794865
}
795866

796867
{{- else }}
797-
npCache.refreshIfNeeded(d, config, userAgent, nodePoolInfo, name)
868+
if err := npCache.refreshIfNeeded(d, config, userAgent, nodePoolInfo, name); err != nil {
869+
return err
870+
}
798871
nodePool, err := npCache.get(nodePoolInfo.fullyQualifiedName(name))
799872
if err != nil {
800873
log.Printf("[WARN] Removing %s because it's gone", fmt.Sprintf("NodePool %q from cluster %q", name, nodePoolInfo.cluster))
@@ -976,7 +1049,9 @@ func resourceContainerNodePoolExists(d *schema.ResourceData, meta interface{}) (
9761049
return true, err
9771050
}
9781051
{{- else }}
979-
npCache.refreshIfNeeded(d, config, userAgent, nodePoolInfo, name)
1052+
if err := npCache.refreshIfNeeded(d, config, userAgent, nodePoolInfo, name); err != nil {
1053+
return false, err
1054+
}
9801055
_, err = npCache.get(nodePoolInfo.fullyQualifiedName(name))
9811056
if err != nil {
9821057
log.Printf("[WARN] Removing %s because it's gone", fmt.Sprintf("NodePool %q from cluster %q", name, nodePoolInfo.cluster))
@@ -1239,6 +1314,7 @@ func flattenNodePool(d *schema.ResourceData, config *transport_tpg.Config, np *c
12391314
if len(matches) < 4 {
12401315
return nil, fmt.Errorf("Error reading instance group manage URL '%q'", url)
12411316
}
1317+
{{- if eq $.TargetVersionName `ga` }}
12421318
igm, err := config.NewComputeClient(userAgent).InstanceGroupManagers.Get(matches[1], matches[2], matches[3]).Do()
12431319
if transport_tpg.IsGoogleApiErrorWithCode(err, 404) {
12441320
// The IGM URL in is stale; don't include it
@@ -1247,6 +1323,20 @@ func flattenNodePool(d *schema.ResourceData, config *transport_tpg.Config, np *c
12471323
if err != nil {
12481324
return nil, fmt.Errorf("Error reading instance group manager returned as an instance group URL: %q", err)
12491325
}
1326+
{{- else }}
1327+
if strings.HasPrefix("gk3", matches[3]) {
1328+
// IGM is autopilot so we know it will not be found, skip it
1329+
continue
1330+
}
1331+
if err := igmCache.refreshIfNeeded(d, config, userAgent, np.Name, url); err != nil {
1332+
return nil, err
1333+
}
1334+
igm, ok := igmCache.get(matches[0])
1335+
if !ok {
1336+
// The IGM URL is stale; don't include it
1337+
continue
1338+
}
1339+
{{- end }}
12501340
size += int(igm.TargetSize)
12511341
igmUrls = append(igmUrls, url)
12521342
managedIgmUrls = append(managedIgmUrls, igm.InstanceGroup)

0 commit comments

Comments
 (0)