From 21602689459a185ee389b4ea871b392de5a010ef Mon Sep 17 00:00:00 2001 From: Alexey Basinov Date: Thu, 25 Apr 2024 07:05:21 -0700 Subject: [PATCH] Add support for BMS machines to the resource detection library (#828) * Add support for Bare Metal Solution (BMS) machines * Update copyright year to 2024 * Update copyright year for bms_test.go * Update copyright year attempt #2 * Expand BMS abbreviation to Bare Metal Solution --- detectors/gcp/bms.go | 55 +++++++++++++++++++++++ detectors/gcp/bms_test.go | 81 ++++++++++++++++++++++++++++++++++ detectors/gcp/detector.go | 3 ++ detectors/gcp/detector_test.go | 12 +++++ 4 files changed, 151 insertions(+) create mode 100644 detectors/gcp/bms.go create mode 100644 detectors/gcp/bms_test.go diff --git a/detectors/gcp/bms.go b/detectors/gcp/bms.go new file mode 100644 index 000000000..d3992a4f7 --- /dev/null +++ b/detectors/gcp/bms.go @@ -0,0 +1,55 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gcp + +const ( + bmsProjectIDEnv = "BMS_PROJECT_ID" + bmsRegionEnv = "BMS_REGION" + bmsInstanceIDEnv = "BMS_INSTANCE_ID" +) + +// onBareMetalSolution checks if the code is running on a Google Cloud Bare Metal Solution (BMS) by verifying +// the presence and non-empty values of BMS_PROJECT_ID, BMS_REGION, and BMS_INSTANCE_ID environment variables. +// For more information on Google Cloud Bare Metal Solution, see: https://cloud.google.com/bare-metal/docs +func (d *Detector) onBareMetalSolution() bool { + projectID, projectIDExists := d.os.LookupEnv(bmsProjectIDEnv) + region, regionExists := d.os.LookupEnv(bmsRegionEnv) + instanceID, instanceIDExists := d.os.LookupEnv(bmsInstanceIDEnv) + return projectIDExists && regionExists && instanceIDExists && projectID != "" && region != "" && instanceID != "" +} + +// BareMetalSolutionInstanceID returns the instance ID from the BMS_INSTANCE_ID environment variable. +func (d *Detector) BareMetalSolutionInstanceID() (string, error) { + if instanceID, found := d.os.LookupEnv(bmsInstanceIDEnv); found { + return instanceID, nil + } + return "", errEnvVarNotFound +} + +// BareMetalSolutionCloudRegion returns the region from the BMS_REGION environment variable. +func (d *Detector) BareMetalSolutionCloudRegion() (string, error) { + if region, found := d.os.LookupEnv(bmsRegionEnv); found { + return region, nil + } + return "", errEnvVarNotFound +} + +// BareMetalSolutionProjectID returns the project ID from the BMS_PROJECT_ID environment variable. +func (d *Detector) BareMetalSolutionProjectID() (string, error) { + if project, found := d.os.LookupEnv(bmsProjectIDEnv); found { + return project, nil + } + return "", errEnvVarNotFound +} diff --git a/detectors/gcp/bms_test.go b/detectors/gcp/bms_test.go new file mode 100644 index 000000000..1ea3485e4 --- /dev/null +++ b/detectors/gcp/bms_test.go @@ -0,0 +1,81 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gcp + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBareMetalSolutionInstanceID(t *testing.T) { + d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{ + Vars: map[string]string{ + bmsInstanceIDEnv: "my-host-123", + }, + }) + instanceID, err := d.BareMetalSolutionInstanceID() + assert.NoError(t, err) + assert.Equal(t, instanceID, "my-host-123") +} + +func TestBareMetalSolutionInstanceIDErr(t *testing.T) { + d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{ + Vars: map[string]string{}, + }) + instanceID, err := d.BareMetalSolutionInstanceID() + assert.Error(t, err) + assert.Equal(t, instanceID, "") +} + +func TestBareMetalSolutionCloudRegion(t *testing.T) { + d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{ + Vars: map[string]string{ + bmsRegionEnv: "us-central1", + }, + }) + region, err := d.BareMetalSolutionCloudRegion() + assert.NoError(t, err) + assert.Equal(t, region, "us-central1") +} + +func TestBareMetalSolutionCloudRegionErr(t *testing.T) { + d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{ + Vars: map[string]string{}, + }) + region, err := d.BareMetalSolutionCloudRegion() + assert.Error(t, err) + assert.Equal(t, region, "") +} + +func TestBareMetalSolutionProjectID(t *testing.T) { + d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{ + Vars: map[string]string{ + bmsProjectIDEnv: "my-test-project", + }, + }) + projectID, err := d.BareMetalSolutionProjectID() + assert.NoError(t, err) + assert.Equal(t, projectID, "my-test-project") +} + +func TestBareMetalSolutionProjectIDErr(t *testing.T) { + d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{ + Vars: map[string]string{}, + }) + projectID, err := d.BareMetalSolutionProjectID() + assert.Error(t, err) + assert.Equal(t, projectID, "") +} diff --git a/detectors/gcp/detector.go b/detectors/gcp/detector.go index 372621553..2cc62de09 100644 --- a/detectors/gcp/detector.go +++ b/detectors/gcp/detector.go @@ -40,11 +40,14 @@ const ( CloudFunctions AppEngineStandard AppEngineFlex + BareMetalSolution ) // CloudPlatform returns the platform on which this program is running. func (d *Detector) CloudPlatform() Platform { switch { + case d.onBareMetalSolution(): + return BareMetalSolution case d.onGKE(): return GKE case d.onCloudFunctions(): diff --git a/detectors/gcp/detector_test.go b/detectors/gcp/detector_test.go index a513ba742..4008e0835 100644 --- a/detectors/gcp/detector_test.go +++ b/detectors/gcp/detector_test.go @@ -90,6 +90,18 @@ func TestCloudPlatformCloudFunctions(t *testing.T) { assert.Equal(t, platform, CloudFunctions) } +func TestCloudPlatformBareMetalSolution(t *testing.T) { + d := NewTestDetector(&FakeMetadataProvider{}, &FakeOSProvider{ + Vars: map[string]string{ + bmsInstanceIDEnv: "foo", + bmsProjectIDEnv: "bar", + bmsRegionEnv: "qux", + }, + }) + platform := d.CloudPlatform() + assert.Equal(t, platform, BareMetalSolution) +} + func TestProjectID(t *testing.T) { d := NewTestDetector(&FakeMetadataProvider{ Project: "my-project",