Skip to content

Commit

Permalink
Detect the managed instance group that created a VM
Browse files Browse the repository at this point in the history
  • Loading branch information
quentinmit committed Sep 24, 2024
1 parent bfca671 commit bb8d9a8
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 2 deletions.
41 changes: 40 additions & 1 deletion detectors/gcp/gce.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,19 @@ package gcp

import (
"fmt"
"regexp"
"strings"

"cloud.google.com/go/compute/metadata"
)

// See the available GCE instance metadata:
// https://cloud.google.com/compute/docs/metadata/default-metadata-values#vm_instance_metadata
// https://cloud.google.com/compute/docs/metadata/predefined-metadata-keys#instance-metadata
const machineTypeMetadataAttr = "instance/machine-type"

// https://cloud.google.com/compute/docs/instance-groups/getting-info-about-migs#checking_if_a_vm_instance_is_part_of_a_mig
const createdByMetadataAttr = "instance/created-by"

func (d *Detector) onGCE() bool {
_, err := d.metadata.Get(machineTypeMetadataAttr)
return err == nil
Expand Down Expand Up @@ -73,3 +79,36 @@ func (d *Detector) GCEAvailabilityZoneAndRegion() (string, string, error) {
}
return zone, strings.Join(splitZone[0:2], "-"), nil
}

type ManagedInstanceGroup struct {
Name string
Location string
Type LocationType
}

var createdByMIGRE = regexp.MustCompile(`^projects/[^/]+/(zones|regions)/([^/]+)/instanceGroupManagers/([^/]+)$`)

func (d *Detector) GCEManagedInstanceGroup() (ManagedInstanceGroup, error) {
createdBy, err := d.metadata.Get(createdByMetadataAttr)
if _, ok := err.(metadata.NotDefinedError); ok {
return ManagedInstanceGroup{}, nil

Check warning on line 94 in detectors/gcp/gce.go

View check run for this annotation

Codecov / codecov/patch

detectors/gcp/gce.go#L94

Added line #L94 was not covered by tests
} else if err != nil {
return ManagedInstanceGroup{}, err
}
matches := createdByMIGRE.FindStringSubmatch(createdBy)
if matches == nil {
return ManagedInstanceGroup{}, nil
}

mig := ManagedInstanceGroup{
Name: matches[3],
Location: matches[2],
}
switch matches[1] {
case "zones":
mig.Type = Zone
case "regions":
mig.Type = Region
}
return mig, nil
}
57 changes: 56 additions & 1 deletion detectors/gcp/gce_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func TestGCEAvaiabilityZoneAndRegionNoZone(t *testing.T) {
assert.Equal(t, region, "")
}

func TestGCEAvaiabilityZoneAndRegionErr(t *testing.T) {
func TestGCEAvailabilityZoneAndRegionErr(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{
Err: fmt.Errorf("fake error"),
}, &FakeOSProvider{})
Expand All @@ -133,3 +133,58 @@ func TestGCEAvaiabilityZoneAndRegionErr(t *testing.T) {
assert.Equal(t, zone, "")
assert.Equal(t, region, "")
}

func TestGCEManagedInstanceGroup(t *testing.T) {
for _, test := range []struct {
createdBy string
mig *ManagedInstanceGroup
}{
{
"projects/123456789012/zones/us-central1-f/instanceGroupManagers/igm-metadata",
&ManagedInstanceGroup{
Name: "igm-metadata",
Location: "us-central1-f",
Type: Zone,
},
},
{
"projects/123456789012/regions/us-central1-f/instanceGroupManagers/igm-metadata",
&ManagedInstanceGroup{
Name: "igm-metadata",
Location: "us-central1-f",
Type: Region,
},
},
{
"projects/123456789012/zones/us-central1-f/someOtherInstanceGroup/igm-metadata",
&ManagedInstanceGroup{},
},
{
"",
&ManagedInstanceGroup{},
},
{
"",
nil,
},
} {
t.Run(test.createdBy, func(t *testing.T) {
fmp := &FakeMetadataProvider{
Attributes: map[string]string{},
}
if test.createdBy != "" {
fmp.Attributes[createdByMetadataAttr] = test.createdBy
}
if test.mig == nil {
fmp.Err = fmt.Errorf("fake error")
}
d := NewTestDetector(fmp, &FakeOSProvider{})
mig, err := d.GCEManagedInstanceGroup()
if test.mig == nil {
assert.Error(t, err)
} else {
assert.Equal(t, mig, *test.mig)
}
})
}
}

0 comments on commit bb8d9a8

Please sign in to comment.