Skip to content
This repository has been archived by the owner on May 30, 2022. It is now read-only.

Detect aws and gcp clouds in the agent #466

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 60 additions & 8 deletions internal/cloud/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ package cloud

import (
"os/exec"
"regexp"
"strings"

log "github.com/sirupsen/logrus"
)

const (
Azure = "azure"
Aws = "aws"
Gcp = "gcp"
// DMI chassis asset tag for Azure machines, needed to identify wether or not we are running on Azure
// This is actually ASCII-encoded, the decoding into a string results in "MSFT AZURE VM"
azureDmiTag = "7783-7084-3265-9085-8269-3286-77"
Expand All @@ -23,25 +26,74 @@ type CustomCommand func(name string, arg ...string) *exec.Cmd

var customExecCommand CustomCommand = exec.Command

func IdentifyCloudProvider() (string, error) {
log.Info("Identifying if the VM is running in a cloud environment...")
// All these detection methods are based in crmsh code, which has been refined over the years
// https://github.com/ClusterLabs/crmsh/blob/master/crmsh/utils.py#L2009

func identifyAzure() (bool, error) {
log.Debug("Checking if the VM is running on Azure...")
output, err := customExecCommand("dmidecode", "-s", "chassis-asset-tag").Output()
if err != nil {
return "", err
return false, err
}

provider := strings.TrimSpace(string(output))
log.Debugf("dmidecode output: %s", provider)

return provider == azureDmiTag, nil
}

func identifyAws() (bool, error) {
log.Debug("Checking if the VM is running on Aws...")
output, err := customExecCommand("dmidecode", "-s", "system-version").Output()
if err != nil {
return false, err
}

provider := strings.TrimSpace(string(output))
log.Debugf("dmidecode output: %s", provider)

return regexp.MatchString(".*amazon.*", provider)
}

func identifyGcp() (bool, error) {
log.Debug("Checking if the VM is running on Gcp...")
output, err := customExecCommand("dmidecode", "-s", "bios-vendor").Output()
if err != nil {
return false, err
}

provider := strings.TrimSpace(string(output))
log.Debugf("dmidecode output: %s", provider)

switch string(provider) {
case azureDmiTag:
return regexp.MatchString(".*Google.*", provider)
}

func IdentifyCloudProvider() (string, error) {
log.Info("Identifying if the VM is running in a cloud environment...")

if result, err := identifyAzure(); err != nil {
return "", err
} else if result {
log.Infof("VM is running on %s", Azure)
return Azure, nil
default:
log.Info("VM is not running in any recognized cloud provider")
return "", nil
}

if result, err := identifyAws(); err != nil {
return "", err
} else if result {
log.Infof("VM is running on %s", Aws)
return Aws, nil
}

if result, err := identifyGcp(); err != nil {
return "", err
} else if result {
log.Infof("VM is running on %s", Gcp)
return Gcp, nil
}

log.Info("VM is not running in any recognized cloud provider")
return "", nil
}

func NewCloudInstance() (*CloudInstance, error) {
Expand Down
66 changes: 66 additions & 0 deletions internal/cloud/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,56 @@ func TestIdentifyCloudProviderAzure(t *testing.T) {
assert.NoError(t, err)
}

func mockDmidecodeAws() *exec.Cmd {
return exec.Command("echo", "4.11.amazon")
}

func TestIdentifyCloudProviderAws(t *testing.T) {
mockCommand := new(mocks.CustomCommand)

customExecCommand = mockCommand.Execute

mockCommand.On("Execute", "dmidecode", "-s", "chassis-asset-tag").Return(
mockDmidecodeNoCloud(),
)

mockCommand.On("Execute", "dmidecode", "-s", "system-version").Return(
mockDmidecodeAws(),
)

provider, err := IdentifyCloudProvider()

assert.Equal(t, "aws", provider)
assert.NoError(t, err)
}

func mockDmidecodeGcp() *exec.Cmd {
return exec.Command("echo", "Google")
}

func TestIdentifyCloudProviderGcp(t *testing.T) {
mockCommand := new(mocks.CustomCommand)

customExecCommand = mockCommand.Execute

mockCommand.On("Execute", "dmidecode", "-s", "chassis-asset-tag").Return(
mockDmidecodeNoCloud(),
)

mockCommand.On("Execute", "dmidecode", "-s", "system-version").Return(
mockDmidecodeNoCloud(),
)

mockCommand.On("Execute", "dmidecode", "-s", "bios-vendor").Return(
mockDmidecodeGcp(),
)

provider, err := IdentifyCloudProvider()

assert.Equal(t, "gcp", provider)
assert.NoError(t, err)
}

func mockDmidecodeNoCloud() *exec.Cmd {
return exec.Command("echo", "")
}
Expand All @@ -63,6 +113,14 @@ func TestIdentifyCloudProviderNoCloud(t *testing.T) {
mockDmidecodeNoCloud(),
)

mockCommand.On("Execute", "dmidecode", "-s", "system-version").Return(
mockDmidecodeNoCloud(),
)

mockCommand.On("Execute", "dmidecode", "-s", "bios-vendor").Return(
mockDmidecodeNoCloud(),
)

provider, err := IdentifyCloudProvider()

assert.Equal(t, "", provider)
Expand Down Expand Up @@ -110,6 +168,14 @@ func TestNewCloudInstanceNoCloud(t *testing.T) {
mockDmidecodeNoCloud(),
)

mockCommand.On("Execute", "dmidecode", "-s", "system-version").Return(
mockDmidecodeNoCloud(),
)

mockCommand.On("Execute", "dmidecode", "-s", "bios-vendor").Return(
mockDmidecodeNoCloud(),
)

c, err := NewCloudInstance()

assert.NoError(t, err)
Expand Down