Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect the managed instance group that created a VM #897

Merged
merged 12 commits into from
Sep 30, 2024
Merged
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ generate: $(STRINGER) $(PROTOC)

.PHONY: fieldalignment
fieldalignment: $(FIELDALIGNMENT)
$(MAKE) for-all-package CMD="$(FIELDALIGNMENT) -fix ."
$(MAKE) for-all-package CMD="$(FIELDALIGNMENT) -fix -test=false ."


.PHONY: for-all-mod
Expand Down
4 changes: 3 additions & 1 deletion detectors/gcp/app_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

package gcp

import "context"

const (
// See https://cloud.google.com/appengine/docs/flexible/python/migrating#modules
// for the environment variables available in GAE environments.
Expand Down Expand Up @@ -67,7 +69,7 @@ func (d *Detector) AppEngineFlexAvailabilityZoneAndRegion() (string, string, err

// AppEngineStandardAvailabilityZone returns the zone the app engine service is running in.
func (d *Detector) AppEngineStandardAvailabilityZone() (string, error) {
return d.metadata.Zone()
return d.metadata.ZoneWithContext(context.TODO())
}

// AppEngineStandardCloudRegion returns the region the app engine service is running in.
Expand Down
82 changes: 40 additions & 42 deletions detectors/gcp/app_engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,137 +22,135 @@ import (
)

func TestAppEngineServiceName(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{
d := NewTestDetector(newFakeMetadataTransport(t), &FakeOSProvider{
Vars: map[string]string{
gaeServiceEnv: "my-service",
},
})
serviceName, err := d.AppEngineServiceName()
assert.NoError(t, err)
assert.Equal(t, serviceName, "my-service")
assert.Equal(t, "my-service", serviceName)
}

func TestAppEngineServiceNameErr(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{
d := NewTestDetector(newFakeMetadataTransport(t), &FakeOSProvider{
Vars: map[string]string{},
})
name, err := d.AppEngineServiceName()
assert.Error(t, err)
assert.Equal(t, name, "")
assert.Equal(t, "", name)
}

func TestAppEngineServiceVersion(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{
d := NewTestDetector(newFakeMetadataTransport(t), &FakeOSProvider{
Vars: map[string]string{
gaeVersionEnv: "my-version",
},
})
version, err := d.AppEngineServiceVersion()
assert.NoError(t, err)
assert.Equal(t, version, "my-version")
assert.Equal(t, "my-version", version)
}

func TestAppEngineServiceVersionErr(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{
d := NewTestDetector(newFakeMetadataTransport(t), &FakeOSProvider{
Vars: map[string]string{},
})
version, err := d.AppEngineServiceVersion()
assert.Error(t, err)
assert.Equal(t, version, "")
assert.Equal(t, "", version)
}

func TestAppEngineServiceInstance(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{
d := NewTestDetector(newFakeMetadataTransport(t), &FakeOSProvider{
Vars: map[string]string{
gaeInstanceEnv: "instance-123",
},
})
instance, err := d.AppEngineServiceInstance()
assert.NoError(t, err)
assert.Equal(t, instance, "instance-123")
assert.Equal(t, "instance-123", instance)
}

func TestAppEngineServiceInstanceErr(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{
d := NewTestDetector(newFakeMetadataTransport(t), &FakeOSProvider{
Vars: map[string]string{},
})
instance, err := d.AppEngineServiceInstance()
assert.Error(t, err)
assert.Equal(t, instance, "")
assert.Equal(t, "", instance)
}

func TestAppEngineStandardAvailabilityZone(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{
FakeZone: "us16",
}, &FakeOSProvider{})
d := NewTestDetector(newFakeMetadataTransport(t,
"instance/zone", "us16",
), &FakeOSProvider{})
zone, err := d.AppEngineStandardAvailabilityZone()
assert.NoError(t, err)
assert.Equal(t, zone, "us16")
assert.Equal(t, "us16", zone)
}

func TestAppEngineStandardAvailabilityZoneErr(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{
d := NewTestDetector(&FakeMetadataTransport{
Err: fmt.Errorf("fake error"),
}, &FakeOSProvider{})
zone, err := d.AppEngineStandardAvailabilityZone()
assert.Error(t, err)
assert.Equal(t, zone, "")
assert.Equal(t, "", zone)
}

func TestAppEngineStandardCloudRegion(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{
Attributes: map[string]string{regionMetadataAttr: "/projects/123/regions/us-central1"},
}, &FakeOSProvider{})
d := NewTestDetector(newFakeMetadataTransport(t,
regionMetadataAttr, "/projects/123/regions/us-central1",
), &FakeOSProvider{})
instance, err := d.AppEngineStandardCloudRegion()
assert.NoError(t, err)
assert.Equal(t, instance, "us-central1")
assert.Equal(t, "us-central1", instance)
}

func TestAppEngineStandardCloudRegionErr(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{
d := NewTestDetector(&FakeMetadataTransport{
Err: fmt.Errorf("fake error"),
}, &FakeOSProvider{})
instance, err := d.AppEngineStandardCloudRegion()
assert.Error(t, err)
assert.Equal(t, instance, "")
assert.Equal(t, "", instance)
}

func TestAppEngineFlexAvailabilityZoneAndRegion(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{
FakeZone: "us-central1-c",
}, &FakeOSProvider{})
d := NewTestDetector(newFakeMetadataTransport(t), &FakeOSProvider{})
zone, region, err := d.AppEngineFlexAvailabilityZoneAndRegion()
assert.NoError(t, err)
assert.Equal(t, zone, "us-central1-c")
assert.Equal(t, region, "us-central1")
assert.Equal(t, fakeZone, zone)
assert.Equal(t, fakeRegion, region)
}

func TestAppEngineFlexAvailabilityZoneAndRegionMalformedZone(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{
FakeZone: "us-central1",
}, &FakeOSProvider{})
d := NewTestDetector(newFakeMetadataTransport(t,
"instance/zone", "us-central1",
), &FakeOSProvider{})
zone, region, err := d.AppEngineFlexAvailabilityZoneAndRegion()
assert.Error(t, err)
assert.Equal(t, zone, "")
assert.Equal(t, region, "")
assert.Equal(t, "", zone)
assert.Equal(t, "", region)
}

func TestAppEngineFlexAvailabilityZoneAndRegionNoZone(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{
FakeZone: "",
}, &FakeOSProvider{})
d := NewTestDetector(newFakeMetadataTransport(t,
"instance/zone", "",
), &FakeOSProvider{})
zone, region, err := d.AppEngineFlexAvailabilityZoneAndRegion()
assert.Error(t, err)
assert.Equal(t, zone, "")
assert.Equal(t, region, "")
assert.Equal(t, "", zone)
assert.Equal(t, "", region)
}

func TestAppEngineFlexAvailabilityZoneAndRegionErr(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{
d := NewTestDetector(&FakeMetadataTransport{
Err: fmt.Errorf("fake error"),
}, &FakeOSProvider{})
zone, region, err := d.AppEngineFlexAvailabilityZoneAndRegion()
assert.Error(t, err)
assert.Equal(t, zone, "")
assert.Equal(t, region, "")
assert.Equal(t, "", zone)
assert.Equal(t, "", region)
}
24 changes: 12 additions & 12 deletions detectors/gcp/bms_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,61 +21,61 @@ import (
)

func TestBareMetalSolutionInstanceID(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{
d := NewTestDetector(&FakeMetadataTransport{}, &FakeOSProvider{
Vars: map[string]string{
bmsInstanceIDEnv: "my-host-123",
},
})
instanceID, err := d.BareMetalSolutionInstanceID()
assert.NoError(t, err)
assert.Equal(t, instanceID, "my-host-123")
assert.Equal(t, "my-host-123", instanceID)
}

func TestBareMetalSolutionInstanceIDErr(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{
d := NewTestDetector(&FakeMetadataTransport{}, &FakeOSProvider{
Vars: map[string]string{},
})
instanceID, err := d.BareMetalSolutionInstanceID()
assert.Error(t, err)
assert.Equal(t, instanceID, "")
assert.Equal(t, "", instanceID)
}

func TestBareMetalSolutionCloudRegion(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{
d := NewTestDetector(&FakeMetadataTransport{}, &FakeOSProvider{
Vars: map[string]string{
bmsRegionEnv: "us-central1",
},
})
region, err := d.BareMetalSolutionCloudRegion()
assert.NoError(t, err)
assert.Equal(t, region, "us-central1")
assert.Equal(t, "us-central1", region)
}

func TestBareMetalSolutionCloudRegionErr(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{
d := NewTestDetector(&FakeMetadataTransport{}, &FakeOSProvider{
Vars: map[string]string{},
})
region, err := d.BareMetalSolutionCloudRegion()
assert.Error(t, err)
assert.Equal(t, region, "")
assert.Equal(t, "", region)
}

func TestBareMetalSolutionProjectID(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{
d := NewTestDetector(&FakeMetadataTransport{}, &FakeOSProvider{
Vars: map[string]string{
bmsProjectIDEnv: "my-test-project",
},
})
projectID, err := d.BareMetalSolutionProjectID()
assert.NoError(t, err)
assert.Equal(t, projectID, "my-test-project")
assert.Equal(t, "my-test-project", projectID)
}

func TestBareMetalSolutionProjectIDErr(t *testing.T) {
d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{
d := NewTestDetector(&FakeMetadataTransport{}, &FakeOSProvider{
Vars: map[string]string{},
})
projectID, err := d.BareMetalSolutionProjectID()
assert.Error(t, err)
assert.Equal(t, projectID, "")
assert.Equal(t, "", projectID)
}
27 changes: 13 additions & 14 deletions detectors/gcp/detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
package gcp

import (
"context"
"errors"
"os"
"strings"

"cloud.google.com/go/compute/metadata"
)
Expand Down Expand Up @@ -68,27 +70,24 @@ func (d *Detector) CloudPlatform() Platform {

// ProjectID returns the ID of the project in which this program is running.
func (d *Detector) ProjectID() (string, error) {
return d.metadata.ProjectID()
// N.B. d.metadata.ProjectIDWithContext(context.TODO()) is cached globally, so if we use it here it's untestable.
s, err := d.metadata.GetWithContext(context.TODO(), "project/project-id")
return strings.TrimSpace(s), err
}

// instanceID returns the ID of the project in which this program is running.
func (d *Detector) instanceID() (string, error) {
// N.B. d.metadata.InstanceIDWithContext(context.TODO()) is cached globally, so if we use it here it's untestable.
s, err := d.metadata.GetWithContext(context.TODO(), "instance/id")
return strings.TrimSpace(s), err
}

// Detector collects resource information for all GCP platforms.
type Detector struct {
metadata metadataProvider
metadata *metadata.Client
os osProvider
}

// metadataProvider contains the subset of the metadata.Client functions used
// by this resource Detector to allow testing with a fake implementation.
type metadataProvider interface {
ProjectID() (string, error)
InstanceID() (string, error)
Get(string) (string, error)
InstanceName() (string, error)
Hostname() (string, error)
Zone() (string, error)
InstanceAttributeValue(string) (string, error)
}

// osProvider contains the subset of the os package functions used by.
type osProvider interface {
LookupEnv(string) (string, bool)
Expand Down
Loading
Loading