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

✨ Set asset.kind to virtualmachine when in cloud #5267

Merged
merged 9 commits into from
Mar 5, 2025
11 changes: 11 additions & 0 deletions providers-sdk/v1/inventory/asset_kinds.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package inventory

// Use this file to define kinds of assets that are used widely.

const (
AssetKindCloudVM = "virtualmachine"
AssetKindBaremetal = "baremetal"
)
4 changes: 2 additions & 2 deletions providers-sdk/v1/inventory/inventory.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,13 +361,13 @@ func (p *Platform) PrettyTitle() string {
} else {
runtimeKind := p.Kind
switch runtimeKind {
case "baremetal":
case AssetKindBaremetal:
runtimeNiceName = "bare metal"
case "container":
runtimeNiceName = "Container"
case "container-image":
runtimeNiceName = "Container Image"
case "virtualmachine":
case AssetKindCloudVM:
runtimeNiceName = "Virtual Machine"
case "virtualmachine-image":
runtimeNiceName = "Virtual Machine Image"
Expand Down
4 changes: 2 additions & 2 deletions providers/aws/resources/discovery_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ func addConnectionInfoToEc2Asset(instance *mqlAwsEc2Instance, accountId string,
asset.PlatformIds = []string{awsec2.MondooInstanceID(accountId, instance.Region.Data, instance.InstanceId.Data)}
asset.IdDetector = []string{ids.IdDetector_Hostname, ids.IdDetector_CloudDetect, ids.IdDetector_SshHostkey}
asset.Platform = &inventory.Platform{
Kind: "virtual_machine",
Kind: inventory.AssetKindCloudVM,
Runtime: "aws-ec2-instance",
Family: getPlatformFamily(instance.PlatformDetails.Data),
}
Expand Down Expand Up @@ -432,7 +432,7 @@ func addConnectionInfoToSSMAsset(instance *mqlAwsSsmInstance, accountId string,
asset.Options = conn.ConnectionOptions()
asset.PlatformIds = []string{awsec2.MondooInstanceID(accountId, instance.Region.Data, instance.InstanceId.Data)}
asset.Platform = &inventory.Platform{
Kind: "virtual_machine",
Kind: inventory.AssetKindCloudVM,
Runtime: "aws-ssm-instance",
Family: getPlatformFamily(instance.PlatformName.Data),
}
Expand Down
2 changes: 1 addition & 1 deletion providers/azure/resources/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ func discoverInstances(runtime *plugin.Runtime, subsWithConfigs []subWithConfig)
enrichWithLabels(asset, labels)
asset.PlatformIds = []string{MondooAzureInstanceID(vm.Id.Data)}
asset.Platform.Runtime = "azure"
asset.Platform.Kind = "virtualmachine"
asset.Platform.Kind = inventory.AssetKindCloudVM
assets = append(assets, asset)
}
}
Expand Down
2 changes: 1 addition & 1 deletion providers/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func assetinfo2providerName(asset *inventory.Asset) (string, error) {
}

switch asset.Platform.Kind {
case "container-image", "baremetal":
case "container-image", inventory.AssetKindBaremetal:
return "os", nil
}

Expand Down
7 changes: 3 additions & 4 deletions providers/os/id/aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,10 @@ func Detect(conn shared.Connection, p *inventory.Platform, smbiosMgr smbios.SmBi
idEcs, err := mdsvcEcs.Identify()
if err == nil {
return idEcs.PlatformIds[0], idEcs.Name, []string{idEcs.AccountPlatformID}
} else {
log.Debug().Err(err).
Strs("platform", p.GetFamily()).
Msg("failed to get AWS platform id")
}
log.Debug().Err(err).
Strs("platform", p.GetFamily()).
Msg("failed to get AWS platform id")
}

return "", "", nil
Expand Down
11 changes: 5 additions & 6 deletions providers/os/id/azure/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,12 @@ func Detect(conn shared.Connection, pf *inventory.Platform, smbiosMgr smbios.SmB
return "", "", nil
}
id, err := mdsvc.Identify()
if err != nil {
log.Debug().Err(err).
Strs("platform", pf.GetFamily()).
Msg("failed to get Azure platform id")
return "", "", nil
if err == nil {
return id.InstanceID, "", []string{id.AccountID}
}
return id.InstanceID, "", []string{id.AccountID}
log.Debug().Err(err).
Strs("platform", pf.GetFamily()).
Msg("failed to get Azure platform id")
}

return "", "", nil
Expand Down
20 changes: 15 additions & 5 deletions providers/os/id/clouddetect/clouddetect.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,20 @@ type detectResult struct {
relatedPlatformIds []string
}

func Detect(conn shared.Connection, p *inventory.Platform) (PlatformID, PlatformName, []RelatedPlatformID) {
// PlatformInfo contains platform information gathered from one of our cloud detectors.
type PlatformInfo struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add comments

ID string
Name string
Kind string
RelatedPlatformIDs []string
}

// Detect tried to detect if we are running on a cloud asset, and if so, it returns
// the platform information, otherwise it returns a `nil` pointer.
func Detect(conn shared.Connection, p *inventory.Platform) *PlatformInfo {
mgr, err := smbios.ResolveManager(conn, p)
if err != nil {
return "", "", nil
return nil
}

wg := sync.WaitGroup{}
Expand Down Expand Up @@ -73,11 +83,11 @@ func Detect(conn shared.Connection, p *inventory.Platform) (PlatformID, Platform
}

if len(platformIds) == 0 {
return "", "", nil
return nil
} else if len(platformIds) > 1 {
log.Error().Strs("detected", platformIds).Msg("multiple cloud platform ids detected")
return "", "", nil
return nil
}

return platformIds[0], name, relatedPlatformIds
return &PlatformInfo{platformIds[0], name, inventory.AssetKindCloudVM, relatedPlatformIds}
}
55 changes: 33 additions & 22 deletions providers/os/id/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ type PlatformFingerprint struct {
ActiveIdDetectors []string
}

type PlatformInfo struct {
type platformInfo struct {
IDs []string
Name string
Kind string
RelatedPlatformIDs []string
}

Expand All @@ -53,14 +54,18 @@ func IdentifyPlatform(conn shared.Connection, req *plugin.ConnectReq, p *invento

if len(idDetectors) == 0 {
// fallback to default id detectors
//
// we want to make sure that we mark assets running in the cloud to `virtualmachine`,
// therefore we use the cloud detect detector as our first option.

switch conn.Type() {
case shared.Type_Local:
idDetectors = []string{ids.IdDetector_Hostname, ids.IdDetector_CloudDetect}
idDetectors = []string{ids.IdDetector_CloudDetect, ids.IdDetector_Hostname}
if cnquery.Features(req.Features).IsActive(cnquery.SerialNumberAsID) {
idDetectors = append(idDetectors, ids.IdDetector_SerialNumber)
}
case shared.Type_SSH:
idDetectors = []string{ids.IdDetector_Hostname, ids.IdDetector_CloudDetect, ids.IdDetector_SshHostkey}
idDetectors = []string{ids.IdDetector_CloudDetect, ids.IdDetector_Hostname, ids.IdDetector_SshHostkey}
case shared.Type_Tar, shared.Type_FileSystem, shared.Type_DockerSnapshot:
idDetectors = []string{ids.IdDetector_Hostname}
}
Expand All @@ -69,7 +74,7 @@ func IdentifyPlatform(conn shared.Connection, req *plugin.ConnectReq, p *invento

for i := range idDetectors {
idDetector := idDetectors[i]
platformInfo, err := GatherPlatformInfo(conn, p, idDetector)
platformInfo, err := gatherPlatformInfo(conn, p, idDetector)
if err != nil {
// we only err if we found zero platform ids, if we try multiple, a fail of an individual one is okay
log.Debug().Err(err).Str("detector", string(idDetector)).Msg("could not determine platform info")
Expand All @@ -93,6 +98,11 @@ func IdentifyPlatform(conn shared.Connection, req *plugin.ConnectReq, p *invento
}
}
}

if len(platformInfo.Kind) > 0 {
p.Kind = platformInfo.Kind
}

// check whether we can extract runtime and kind information
for _, id := range platformInfo.IDs {
runtime, kind := ExtractPlatformAndKindFromPlatformId(id)
Expand Down Expand Up @@ -132,7 +142,7 @@ func GatherNameForPlatformId(id string) string {

func ExtractPlatformAndKindFromPlatformId(id string) (string, string) {
if awsec2.ParseEc2PlatformID(id) != nil {
return "aws-ec2", "virtual-machine"
return "aws-ec2", inventory.AssetKindCloudVM
} else if awsec2.IsValidMondooAccountId(id) {
return "aws", "api"
} else if awsecs.IsValidMondooECSContainerId(id) {
Expand All @@ -141,43 +151,43 @@ func ExtractPlatformAndKindFromPlatformId(id string) (string, string) {
return "", ""
}

func GatherPlatformInfo(conn shared.Connection, pf *inventory.Platform, idDetector string) (*PlatformInfo, error) {
func gatherPlatformInfo(conn shared.Connection, pf *inventory.Platform, idDetector string) (*platformInfo, error) {
var identifier string
switch {
case idDetector == ids.IdDetector_Hostname:
// NOTE: we need to be careful with hostname's since they are not required to be unique
hostname, ok := hostname.Hostname(conn, pf)
if ok && len(hostname) > 0 {
identifier = "//platformid.api.mondoo.app/hostname/" + hostname
return &PlatformInfo{
return &platformInfo{
IDs: []string{identifier},
Name: hostname,
RelatedPlatformIDs: []string{},
}, nil
}
return &PlatformInfo{}, nil
return &platformInfo{}, nil
case idDetector == ids.IdDetector_MachineID:
guid, hostErr := machineid.MachineId(conn, pf)
if hostErr == nil && len(guid) > 0 {
identifier = "//platformid.api.mondoo.app/machineid/" + guid
return &PlatformInfo{
return &platformInfo{
IDs: []string{identifier},
Name: "",
RelatedPlatformIDs: []string{},
}, hostErr
}
return &PlatformInfo{}, nil
return &platformInfo{}, nil
case idDetector == ids.IdDetector_SerialNumber:
serial, err := serialnumber.SerialNumber(conn, pf)
if err == nil && len(serial) > 0 {
identifier = "//platformid.api.mondoo.app/serialnumber/" + serial
return &PlatformInfo{
return &platformInfo{
IDs: []string{identifier},
Name: "",
RelatedPlatformIDs: []string{},
}, nil
}
return &PlatformInfo{}, nil
return &platformInfo{}, nil
case idDetector == ids.IdDetector_AwsEcs:
metadata, err := awsecs.Resolve(conn, pf)
if err != nil {
Expand All @@ -188,29 +198,30 @@ func GatherPlatformInfo(conn shared.Connection, pf *inventory.Platform, idDetect
return nil, err
}
if len(ident.PlatformIds) != 0 {
return &PlatformInfo{
return &platformInfo{
IDs: ident.PlatformIds,
Name: ident.Name,
RelatedPlatformIDs: []string{ident.AccountPlatformID},
}, nil
}
return &PlatformInfo{}, nil
return &platformInfo{}, nil
case idDetector == ids.IdDetector_CloudDetect:
identifier, name, relatedIdentifiers := clouddetect.Detect(conn, pf)
if identifier != "" {
return &PlatformInfo{
IDs: []string{identifier},
Name: name,
RelatedPlatformIDs: relatedIdentifiers,
cloudPlatformInfo := clouddetect.Detect(conn, pf)
if cloudPlatformInfo != nil {
return &platformInfo{
IDs: []string{cloudPlatformInfo.ID},
Name: cloudPlatformInfo.Name,
RelatedPlatformIDs: cloudPlatformInfo.RelatedPlatformIDs,
Kind: cloudPlatformInfo.Kind,
}, nil
}
return &PlatformInfo{}, nil
return &platformInfo{}, nil
case idDetector == ids.IdDetector_SshHostkey:
identifier, err := sshhostkey.Detect(conn, pf)
if err != nil {
return nil, err
}
return &PlatformInfo{
return &platformInfo{
IDs: identifier,
Name: "",
RelatedPlatformIDs: []string{},
Expand Down
37 changes: 11 additions & 26 deletions providers/os/provider/detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,11 @@ import (
"go.mondoo.com/cnquery/v11/providers/os/connection/shared"
"go.mondoo.com/cnquery/v11/providers/os/detector"
"go.mondoo.com/cnquery/v11/providers/os/id"
"go.mondoo.com/cnquery/v11/providers/os/id/aws"
"go.mondoo.com/cnquery/v11/providers/os/id/azure"
"go.mondoo.com/cnquery/v11/providers/os/id/gcp"
"go.mondoo.com/cnquery/v11/providers/os/id/clouddetect"
"go.mondoo.com/cnquery/v11/providers/os/id/hostname"
"go.mondoo.com/cnquery/v11/providers/os/id/ids"
"go.mondoo.com/cnquery/v11/providers/os/id/machineid"
"go.mondoo.com/cnquery/v11/providers/os/id/sshhostkey"
"go.mondoo.com/cnquery/v11/providers/os/resources/smbios"
)

// default id detectors
Expand Down Expand Up @@ -56,11 +53,11 @@ func (s *Service) detect(asset *inventory.Asset, conn shared.Connection) error {
return errors.New("failed to detect OS")
}
if asset.Platform.Kind == "" {
asset.Platform.Kind = "baremetal"
asset.Platform.Kind = inventory.AssetKindBaremetal
}
if asset.Connections[0].Runtime == "vagrant" {
// detect overrides this
asset.Platform.Kind = "virtualmachine"
asset.Platform.Kind = inventory.AssetKindCloudVM
}

var detectors map[string]struct{}
Expand All @@ -76,29 +73,17 @@ func (s *Service) detect(asset *inventory.Asset, conn shared.Connection) error {
}

if hasDetector(detectors, ids.IdDetector_CloudDetect) {
mgr, err := smbios.ResolveManager(conn, asset.Platform)
if err != nil {
return err
}

log.Debug().Msg("run cloud platform detector")
if id, name, related := aws.Detect(conn, asset.Platform, mgr); id != "" {
asset.PlatformIds = append(asset.PlatformIds, id)
if name != "" {
cloudPlatformInfo := clouddetect.Detect(conn, asset.Platform)
if cloudPlatformInfo != nil {
log.Debug().Interface("info", cloudPlatformInfo).Msg("cloud platform detected")
asset.PlatformIds = append(asset.PlatformIds, cloudPlatformInfo.ID)
if cloudPlatformInfo.Name != "" {
// if we weren't able to detect a name for this asset, don't update to an empty value
asset.Name = name
asset.Name = cloudPlatformInfo.Name
}
asset.RelatedAssets = append(asset.RelatedAssets, relatedIds2assets(related)...)
}

if id, _, related := azure.Detect(conn, asset.Platform, mgr); id != "" {
asset.PlatformIds = append(asset.PlatformIds, id)
asset.RelatedAssets = append(asset.RelatedAssets, relatedIds2assets(related)...)
}

if id, _, related := gcp.Detect(conn, asset.Platform, mgr); id != "" {
asset.PlatformIds = append(asset.PlatformIds, id)
asset.RelatedAssets = append(asset.RelatedAssets, relatedIds2assets(related)...)
asset.Platform.Kind = cloudPlatformInfo.Kind
asset.RelatedAssets = append(asset.RelatedAssets, relatedIds2assets(cloudPlatformInfo.RelatedPlatformIDs)...)
}
}

Expand Down
2 changes: 1 addition & 1 deletion providers/os/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ func (s *Service) connect(req *plugin.ConnectReq, callback plugin.ProviderCallba
}

if asset.Platform != nil && asset.Platform.Kind == "" {
asset.Platform.Kind = "baremetal"
asset.Platform.Kind = inventory.AssetKindBaremetal
}

return runtime.Connection.(shared.Connection), nil
Expand Down
2 changes: 1 addition & 1 deletion providers/vsphere/resources/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func discoverDatacenter(conn *connection.VsphereConnection, datacenterResource *
Name: connection.EsxiPlatform,
Version: esxiVersion.Version,
Build: esxiVersion.Build,
Kind: "baremetal",
Kind: inventory.AssetKindBaremetal,
Runtime: "vsphere-host",
Family: []string{connection.Family},
TechnologyUrlSegments: []string{"vmware", "esxi", esxiVersion.Version + "-" + esxiVersion.Build},
Expand Down
Loading