Skip to content

Commit 59d10df

Browse files
omerdemirokactions-user
authored andcommitted
feat: add instance group manager adapter (#1341)
Resolves https://github.com/overmindtech/workspace/issues/1297 Features: Implements GCP Compute Instance Group Manager adapter Ensures adapter is tested GitOrigin-RevId: 1c3c1c6862c0820dba0e50cf0e7819734504a8f5
1 parent 0a20eb3 commit 59d10df

10 files changed

+909
-80
lines changed

sources/gcp/adapters/adapters.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ func Adapters(ctx context.Context, projectID string, regions []string, zones []s
5050
return nil, err
5151
}
5252

53+
instanceGroupManagerCli, err := compute.NewInstanceGroupManagersRESTClient(ctx)
54+
if err != nil {
55+
return nil, err
56+
}
57+
5358
var adapters []discovery.Adapter
5459

5560
for _, region := range regions {
@@ -64,6 +69,7 @@ func Adapters(ctx context.Context, projectID string, regions []string, zones []s
6469
sources.WrapperToAdapter(NewComputeInstance(shared.NewComputeInstanceClient(instanceCli), projectID, zone)),
6570
sources.WrapperToAdapter(NewComputeAutoscaler(shared.NewComputeAutoscalerClient(autoscalerCli), projectID, zone)),
6671
sources.WrapperToAdapter(NewComputeInstanceGroup(shared.NewComputeInstanceGroupsClient(instanceGroupCli), projectID, zone)),
72+
sources.WrapperToAdapter(NewComputeInstanceGroupManager(shared.NewComputeInstanceGroupManagerClient(instanceGroupManagerCli), projectID, zone)),
6773
)
6874
}
6975

sources/gcp/adapters/compute-autoscaler.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ var (
1818
ComputeAutoscaler = shared.NewItemType(gcpshared.GCP, gcpshared.Compute, gcpshared.Autoscaler)
1919

2020
ComputeAutoscalerLookupByName = shared.NewItemTypeLookup("name", ComputeAutoscaler)
21-
22-
// TODO: Move to instance group manager adapter
23-
ComputeInstanceGroupManager = shared.NewItemType(gcpshared.GCP, gcpshared.Compute, gcpshared.InstanceGroupManager)
2421
)
2522

2623
type computeAutoscalerWrapper struct {
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
package adapters
2+
3+
import (
4+
"context"
5+
"errors"
6+
7+
"cloud.google.com/go/compute/apiv1/computepb"
8+
"google.golang.org/api/iterator"
9+
10+
"github.com/overmindtech/cli/sdp-go"
11+
"github.com/overmindtech/cli/sources"
12+
gcpshared "github.com/overmindtech/cli/sources/gcp/shared"
13+
"github.com/overmindtech/cli/sources/shared"
14+
)
15+
16+
var (
17+
ComputeInstanceGroupManager = shared.NewItemType(gcpshared.GCP, gcpshared.Compute, gcpshared.InstanceGroupManager)
18+
ComputeInstanceTemplate = shared.NewItemType(gcpshared.GCP, gcpshared.Compute, gcpshared.InstanceTemplate)
19+
ComputeRegionInstanceTemplate = shared.NewItemType(gcpshared.GCP, gcpshared.Compute, gcpshared.RegionalInstanceTemplate)
20+
ComputeTargetPool = shared.NewItemType(gcpshared.GCP, gcpshared.Compute, gcpshared.TargetPool)
21+
ComputeResourcePolicy = shared.NewItemType(gcpshared.GCP, gcpshared.Compute, gcpshared.ResourcePolicy)
22+
23+
ComputeInstanceGroupManagerLookupByName = shared.NewItemTypeLookup("name", ComputeInstanceGroupManager)
24+
)
25+
26+
type computeInstanceGroupManagerWrapper struct {
27+
client gcpshared.ComputeInstanceGroupManagerClient
28+
29+
*gcpshared.ZoneBase
30+
}
31+
32+
// NewComputeInstanceGroupManager creates a new computeInstanceGroupManagerWrapper
33+
func NewComputeInstanceGroupManager(client gcpshared.ComputeInstanceGroupManagerClient, projectID, zone string) sources.ListableWrapper {
34+
return &computeInstanceGroupManagerWrapper{
35+
client: client,
36+
ZoneBase: gcpshared.NewZoneBase(
37+
projectID,
38+
zone,
39+
sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION,
40+
ComputeInstanceGroupManager,
41+
),
42+
}
43+
}
44+
45+
// PotentialLinks returns the potential links for the compute instance group manager wrapper
46+
func (c computeInstanceGroupManagerWrapper) PotentialLinks() map[shared.ItemType]bool {
47+
return shared.NewItemTypesSet(
48+
ComputeInstanceTemplate,
49+
ComputeRegionInstanceTemplate,
50+
ComputeInstanceGroup,
51+
ComputeTargetPool,
52+
ComputeResourcePolicy,
53+
ComputeAutoscaler,
54+
)
55+
}
56+
57+
// TerraformMappings returns the Terraform mappings for the compute instance group manager wrapper
58+
func (c computeInstanceGroupManagerWrapper) TerraformMappings() []*sdp.TerraformMapping {
59+
return []*sdp.TerraformMapping{
60+
{
61+
TerraformMethod: sdp.QueryMethod_GET,
62+
TerraformQueryMap: "google_compute_instance_group_manager.name",
63+
},
64+
}
65+
}
66+
67+
// GetLookups returns the lookups for the compute instance group manager wrapper
68+
func (c computeInstanceGroupManagerWrapper) GetLookups() sources.ItemTypeLookups {
69+
return sources.ItemTypeLookups{
70+
ComputeInstanceGroupManagerLookupByName,
71+
}
72+
}
73+
74+
// Get retrieves a compute instance group manager by its name
75+
func (c computeInstanceGroupManagerWrapper) Get(ctx context.Context, queryParts ...string) (*sdp.Item, *sdp.QueryError) {
76+
req := &computepb.GetInstanceGroupManagerRequest{
77+
Project: c.ProjectID(),
78+
Zone: c.Zone(),
79+
InstanceGroupManager: queryParts[0],
80+
}
81+
82+
instanceGroupManager, err := c.client.Get(ctx, req)
83+
if err != nil {
84+
return nil, gcpshared.QueryError(err)
85+
}
86+
87+
var sdpErr *sdp.QueryError
88+
var item *sdp.Item
89+
item, sdpErr = c.gcpInstanceGroupManagerToSDPItem(instanceGroupManager)
90+
if sdpErr != nil {
91+
return nil, sdpErr
92+
}
93+
94+
return item, nil
95+
}
96+
97+
// List lists compute instance group managers and converts them to sdp.Items.
98+
func (c computeInstanceGroupManagerWrapper) List(ctx context.Context) ([]*sdp.Item, *sdp.QueryError) {
99+
it := c.client.List(ctx, &computepb.ListInstanceGroupManagersRequest{
100+
Project: c.ProjectID(),
101+
Zone: c.Zone(),
102+
})
103+
104+
var items []*sdp.Item
105+
for {
106+
instanceGroupManager, err := it.Next()
107+
if errors.Is(err, iterator.Done) {
108+
break
109+
}
110+
if err != nil {
111+
return nil, gcpshared.QueryError(err)
112+
}
113+
114+
var sdpErr *sdp.QueryError
115+
var item *sdp.Item
116+
item, sdpErr = c.gcpInstanceGroupManagerToSDPItem(instanceGroupManager)
117+
if sdpErr != nil {
118+
return nil, sdpErr
119+
}
120+
121+
items = append(items, item)
122+
}
123+
124+
return items, nil
125+
}
126+
127+
func (c computeInstanceGroupManagerWrapper) gcpInstanceGroupManagerToSDPItem(instanceGroupManager *computepb.InstanceGroupManager) (*sdp.Item, *sdp.QueryError) {
128+
attributes, err := shared.ToAttributesWithExclude(instanceGroupManager)
129+
if err != nil {
130+
return nil, &sdp.QueryError{
131+
ErrorType: sdp.QueryError_OTHER,
132+
ErrorString: err.Error(),
133+
}
134+
}
135+
136+
sdpItem := &sdp.Item{
137+
Type: ComputeInstanceGroupManager.String(),
138+
UniqueAttribute: "name",
139+
Attributes: attributes,
140+
Scope: c.DefaultScope(),
141+
}
142+
143+
//Deleting the Instance Group Manager:
144+
//If the IGM is deleted, the associated instances are also deleted, but the instance template remains unaffected.
145+
//The instance template can still be used by other IGMs or for creating standalone instances.
146+
//Deleting an instance template also doesn't not delete the IGM.
147+
if instanceTemplate := instanceGroupManager.GetInstanceTemplate(); instanceTemplate != "" {
148+
instanceTemplateName := gcpshared.LastPathComponent(instanceTemplate)
149+
region := gcpshared.ExtractRegion(instanceTemplate)
150+
//Set type as ComputeRegionInstanceTemplate if this is a regional template
151+
if region != "" {
152+
sdpItem.LinkedItemQueries = append(sdpItem.LinkedItemQueries, &sdp.LinkedItemQuery{
153+
Query: &sdp.Query{
154+
Type: ComputeRegionInstanceTemplate.String(),
155+
Method: sdp.QueryMethod_GET,
156+
Query: instanceTemplateName,
157+
Scope: gcpshared.RegionalScope(c.ProjectID(), region),
158+
},
159+
BlastPropagation: &sdp.BlastPropagation{In: true, Out: false},
160+
})
161+
//Set type as ComputeInstanceTemplate if this is a global template
162+
} else {
163+
sdpItem.LinkedItemQueries = append(sdpItem.LinkedItemQueries, &sdp.LinkedItemQuery{
164+
Query: &sdp.Query{
165+
Type: ComputeInstanceTemplate.String(),
166+
Method: sdp.QueryMethod_GET,
167+
Query: instanceTemplateName,
168+
Scope: c.ProjectID(),
169+
},
170+
BlastPropagation: &sdp.BlastPropagation{In: true, Out: false},
171+
})
172+
}
173+
}
174+
175+
if group := instanceGroupManager.GetInstanceGroup(); group != "" {
176+
instanceGroupName := gcpshared.LastPathComponent(group)
177+
zone := gcpshared.ExtractZone(group)
178+
if zone != "" {
179+
sdpItem.LinkedItemQueries = append(sdpItem.LinkedItemQueries, &sdp.LinkedItemQuery{
180+
Query: &sdp.Query{
181+
Type: ComputeInstanceGroup.String(),
182+
Method: sdp.QueryMethod_GET,
183+
Query: instanceGroupName,
184+
Scope: gcpshared.ZonalScope(c.ProjectID(), zone),
185+
},
186+
BlastPropagation: &sdp.BlastPropagation{In: true, Out: true},
187+
})
188+
}
189+
}
190+
191+
for _, targetPool := range instanceGroupManager.GetTargetPools() {
192+
targetPoolName := gcpshared.LastPathComponent(targetPool)
193+
region := gcpshared.ExtractRegion(targetPool)
194+
if region != "" {
195+
sdpItem.LinkedItemQueries = append(sdpItem.LinkedItemQueries, &sdp.LinkedItemQuery{
196+
Query: &sdp.Query{
197+
Type: ComputeTargetPool.String(),
198+
Method: sdp.QueryMethod_GET,
199+
Query: targetPoolName,
200+
Scope: gcpshared.RegionalScope(c.ProjectID(), region),
201+
},
202+
BlastPropagation: &sdp.BlastPropagation{In: true, Out: true},
203+
})
204+
}
205+
}
206+
207+
if instanceGroupManager.GetResourcePolicies() != nil {
208+
resourcePolicy := instanceGroupManager.GetResourcePolicies().GetWorkloadPolicy()
209+
//Deleting the Instance Group Manager does not affect the the Resource Policy.
210+
//Deleting the Resource Policy doesn't stop the Instance Group Manager from running but makes it lose the policy’s scheduled effects.
211+
if resourcePolicy != "" {
212+
resourcePolicyName := gcpshared.LastPathComponent(string(resourcePolicy))
213+
if resourcePolicyName != "" {
214+
sdpItem.LinkedItemQueries = append(sdpItem.LinkedItemQueries, &sdp.LinkedItemQuery{
215+
Query: &sdp.Query{
216+
Type: ComputeResourcePolicy.String(),
217+
Method: sdp.QueryMethod_GET,
218+
Query: resourcePolicyName,
219+
Scope: c.ProjectID(),
220+
},
221+
BlastPropagation: &sdp.BlastPropagation{In: true, Out: false},
222+
})
223+
}
224+
}
225+
}
226+
227+
// Autoscalers set the Instance Group Manager target size
228+
// InstanceGroupManagers orphans the autoscaler when deleted
229+
if status := instanceGroupManager.GetStatus(); status != nil {
230+
if autoscalerURL := status.GetAutoscaler(); autoscalerURL != "" {
231+
autoscalerName := gcpshared.LastPathComponent(autoscalerURL)
232+
zone := gcpshared.ExtractZone(autoscalerURL)
233+
if autoscalerName != "" && zone != "" {
234+
sdpItem.LinkedItemQueries = append(sdpItem.LinkedItemQueries, &sdp.LinkedItemQuery{
235+
Query: &sdp.Query{
236+
Type: ComputeAutoscaler.String(),
237+
Method: sdp.QueryMethod_GET,
238+
Query: autoscalerName,
239+
Scope: gcpshared.ZonalScope(c.ProjectID(), zone),
240+
},
241+
BlastPropagation: &sdp.BlastPropagation{In: true, Out: true},
242+
})
243+
}
244+
}
245+
}
246+
247+
switch {
248+
case instanceGroupManager.GetStatus() != nil && instanceGroupManager.GetStatus().GetIsStable():
249+
sdpItem.Health = sdp.Health_HEALTH_OK.Enum()
250+
default:
251+
sdpItem.Health = sdp.Health_HEALTH_UNKNOWN.Enum()
252+
}
253+
254+
return sdpItem, nil
255+
256+
}

0 commit comments

Comments
 (0)