Skip to content

Commit b0019b9

Browse files
✨ Read tags from vsphere (#5857)
* Add tags field and also add tags to labels * A bit of small clean up * Update to grab all tags * Extract GetVmTags and GetHostTags into a single GetTags function
1 parent 6ab853e commit b0019b9

File tree

7 files changed

+176
-10
lines changed

7 files changed

+176
-10
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright (c) Mondoo, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
4+
package resources
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"net/url"
10+
11+
"github.com/vmware/govmomi/vapi/rest"
12+
"github.com/vmware/govmomi/vapi/tags"
13+
"github.com/vmware/govmomi/vim25"
14+
"github.com/vmware/govmomi/vim25/types"
15+
vmwaretypes "github.com/vmware/govmomi/vim25/types"
16+
"go.mondoo.com/cnquery/v11/providers-sdk/v1/inventory"
17+
"go.mondoo.com/cnquery/v11/providers-sdk/v1/vault"
18+
)
19+
20+
// extractTagKeys extracts tag keys from vmware Tag slice
21+
func extractTagKeys(tags []vmwaretypes.Tag) []string {
22+
tagKeys := make([]string, len(tags))
23+
for i, tag := range tags {
24+
tagKeys[i] = tag.Key
25+
}
26+
return tagKeys
27+
}
28+
29+
// GetTags retrieves tags for a host system using the vSphere vAPI
30+
// If the vAPI is not available, it will return an empty array instead of an error.
31+
// This maintains backward compatibility with vSphere environments that don't use tags.
32+
func GetTags(ctx context.Context, ref types.ManagedObjectReference, client *vim25.Client, conf *inventory.Config) []string {
33+
// Create vAPI REST client
34+
restClient := rest.NewClient(client)
35+
36+
// Get credentials from connection config
37+
creds, err := vault.GetPassword(conf.Credentials)
38+
if err != nil {
39+
return []string{}
40+
}
41+
42+
userInfo := url.UserPassword(creds.User, string(creds.Secret))
43+
err = restClient.Login(ctx, userInfo)
44+
if err != nil {
45+
return []string{}
46+
}
47+
48+
tagManager := tags.NewManager(restClient)
49+
50+
// Get attached tags for the host
51+
attachedTags, err := tagManager.GetAttachedTags(ctx, ref)
52+
if err != nil {
53+
return []string{}
54+
}
55+
56+
// Convert tags to string format: "category:tag"
57+
tagStrings := make([]string, len(attachedTags))
58+
for i, tag := range attachedTags {
59+
// Get category information
60+
category, err := tagManager.GetCategory(ctx, tag.CategoryID)
61+
if err != nil {
62+
// If we can't get category, just use tag name
63+
tagStrings[i] = tag.Name
64+
continue
65+
}
66+
tagStrings[i] = fmt.Sprintf("%s:%s", category.Name, tag.Name)
67+
}
68+
69+
return tagStrings
70+
}

providers/vsphere/resources/datacenter.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import (
1010
"github.com/vmware/govmomi/object"
1111
"go.mondoo.com/cnquery/v11/llx"
1212
"go.mondoo.com/cnquery/v11/providers-sdk/v1/plugin"
13+
"go.mondoo.com/cnquery/v11/providers-sdk/v1/util/convert"
1314
"go.mondoo.com/cnquery/v11/providers/vsphere/connection"
1415
"go.mondoo.com/cnquery/v11/providers/vsphere/resources/resourceclient"
16+
"go.mondoo.com/cnquery/v11/types"
1517
)
1618

1719
func newVsphereHostResources(vClient *resourceclient.Client, runtime *plugin.Runtime, vhosts []*object.HostSystem) ([]interface{}, error) {
@@ -29,15 +31,31 @@ func newVsphereHostResources(vClient *resourceclient.Client, runtime *plugin.Run
2931
}
3032

3133
var name string
34+
var tags []string
3235
if hostInfo != nil {
3336
name = hostInfo.Name
37+
simpleTags := extractTagKeys(hostInfo.Tag)
38+
39+
// Get vAPI tags using the connection
40+
conn := runtime.Connection.(*connection.VsphereConnection)
41+
ctx := context.Background()
42+
43+
// Get vAPI tags using the connection config
44+
vapiTags := GetTags(ctx, h.Reference(), vClient.Client.Client, conn.Conf)
45+
// Use vAPI tags if available, otherwise use simple tags
46+
if len(vapiTags) > 0 {
47+
tags = vapiTags
48+
} else {
49+
tags = simpleTags
50+
}
3451
}
3552

3653
mqlHost, err := CreateResource(runtime, "vsphere.host", map[string]*llx.RawData{
3754
"moid": llx.StringData(h.Reference().Encode()),
3855
"name": llx.StringData(name),
3956
"properties": llx.DictData(props),
4057
"inventoryPath": llx.StringData(h.InventoryPath),
58+
"tags": llx.ArrayData(convert.SliceAnyToInterface(tags), types.String),
4159
})
4260
if err != nil {
4361
return nil, err

providers/vsphere/resources/discovery.go

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,22 @@ func discoverDatacenter(conn *connection.VsphereConnection, datacenterResource *
124124
platformID := connection.VsphereResourceID(instanceUuid, mqlHost.Moid.Data)
125125
clonedConfig := conn.Conf.Clone(inventory.WithoutDiscovery())
126126
clonedConfig.PlatformId = platformID
127+
128+
labels := map[string]string{
129+
"vsphere.vmware.com/name": mqlHost.Name.Data,
130+
"vsphere.vmware.com/moid": mqlHost.Moid.Data,
131+
"vsphere.vmware.com/inventorypath": mqlHost.InventoryPath.Data,
132+
}
133+
134+
// Add tags as labels with vsphere.vmware.com/tag/ prefix
135+
if mqlHost.Tags.Error == nil {
136+
for _, tag := range mqlHost.Tags.Data {
137+
if tagStr, ok := tag.(string); ok {
138+
labels["vsphere.vmware.com/tag/"+tagStr] = "true"
139+
}
140+
}
141+
}
142+
127143
assetList = append(assetList, &inventory.Asset{
128144
Name: mqlHost.Name.Data,
129145
Platform: &inventory.Platform{
@@ -137,11 +153,7 @@ func discoverDatacenter(conn *connection.VsphereConnection, datacenterResource *
137153
TechnologyUrlSegments: []string{"vmware", "esxi", esxiVersion.Version + "-" + esxiVersion.Build},
138154
},
139155
Connections: []*inventory.Config{clonedConfig}, // pass-in the parent connection config
140-
Labels: map[string]string{
141-
"vsphere.vmware.com/name": mqlHost.Name.Data,
142-
"vsphere.vmware.com/moid": mqlHost.Moid.Data,
143-
"vsphere.vmware.com/inventorypath": mqlHost.InventoryPath.Data,
144-
},
156+
Labels: labels,
145157
State: mapHostPowerstateToState(mqlHost.host.Runtime.PowerState),
146158
PlatformIds: []string{platformID},
147159
})
@@ -157,15 +169,27 @@ func discoverDatacenter(conn *connection.VsphereConnection, datacenterResource *
157169
platformID := connection.VsphereResourceID(instanceUuid, vm.Moid.Data)
158170
clonedConfig := conn.Conf.Clone(inventory.WithoutDiscovery())
159171
clonedConfig.PlatformId = platformID
172+
173+
labels := map[string]string{
174+
"vsphere.vmware.com/name": vm.Name.Data,
175+
"vsphere.vmware.com/moid": vm.Moid.Data,
176+
"vsphere.vmware.com/inventory-path": vm.InventoryPath.Data,
177+
}
178+
179+
// Add tags as labels with vsphere.vmware.com/tag/ prefix
180+
if vm.Tags.Error == nil {
181+
for _, tag := range vm.Tags.Data {
182+
if tagStr, ok := tag.(string); ok {
183+
labels["vsphere.vmware.com/tag/"+tagStr] = "true"
184+
}
185+
}
186+
}
187+
160188
assetList = append(assetList, &inventory.Asset{
161189
Name: vm.Name.Data,
162190
Platform: &inventory.Platform{},
163191
Connections: []*inventory.Config{clonedConfig},
164-
Labels: map[string]string{
165-
"vsphere.vmware.com/name": vm.Name.Data,
166-
"vsphere.vmware.com/moid": vm.Moid.Data,
167-
"vsphere.vmware.com/inventory-path": vm.InventoryPath.Data,
168-
},
192+
Labels: labels,
169193
State: mapVmGuestState(vm.vm.Guest.GuestState),
170194
PlatformIds: []string{platformID},
171195
})

providers/vsphere/resources/vm.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@
44
package resources
55

66
import (
7+
"context"
8+
79
"github.com/vmware/govmomi/object"
810
"github.com/vmware/govmomi/vim25/mo"
911
"go.mondoo.com/cnquery/v11/llx"
1012
"go.mondoo.com/cnquery/v11/providers-sdk/v1/plugin"
13+
"go.mondoo.com/cnquery/v11/providers-sdk/v1/util/convert"
1114
"go.mondoo.com/cnquery/v11/providers/vsphere/connection"
1215
"go.mondoo.com/cnquery/v11/providers/vsphere/resources/resourceclient"
16+
"go.mondoo.com/cnquery/v11/types"
1317
)
1418

1519
func newMqlVm(runtime *plugin.Runtime, vm *object.VirtualMachine, vmInfo *mo.VirtualMachine) (*mqlVsphereVm, error) {
@@ -19,15 +23,33 @@ func newMqlVm(runtime *plugin.Runtime, vm *object.VirtualMachine, vmInfo *mo.Vir
1923
}
2024

2125
var name string
26+
var tags []string
2227
if vmInfo != nil && vmInfo.Config != nil {
2328
name = vmInfo.Config.Name
29+
// Try both approaches for testing
30+
simpleTags := extractTagKeys(vmInfo.Tag)
31+
32+
// Get vAPI tags using the connection
33+
conn := runtime.Connection.(*connection.VsphereConnection)
34+
vClient := resourceclient.New(conn.Client())
35+
ctx := context.Background()
36+
37+
// Get vAPI tags using the connection config
38+
vapiTags := GetTags(ctx, vm.Reference(), vClient.Client.Client, conn.Conf)
39+
// Use vAPI tags if available, fallback to simple tags
40+
if len(vapiTags) > 0 {
41+
tags = vapiTags
42+
} else {
43+
tags = simpleTags
44+
}
2445
}
2546

2647
mqlVm, err := CreateResource(runtime, "vsphere.vm", map[string]*llx.RawData{
2748
"moid": llx.StringData(vm.Reference().Encode()),
2849
"name": llx.StringData(name),
2950
"properties": llx.DictData(props),
3051
"inventoryPath": llx.StringData(vm.InventoryPath),
52+
"tags": llx.ArrayData(convert.SliceAnyToInterface(tags), types.String),
3153
})
3254
if err != nil {
3355
return nil, err

providers/vsphere/resources/vsphere.lr

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ private vsphere.host @defaults("moid name") {
186186
ntp() esxi.ntpconfig
187187
// Host SNMP configuration
188188
snmp() map[string]string
189+
//Host tags
190+
tags []string
189191
}
190192

191193
// vSphere VM resource
@@ -200,6 +202,8 @@ private vsphere.vm @defaults("moid name") {
200202
properties dict
201203
// Virtual machine advanced properties
202204
advancedSettings() map[string]string
205+
// VM tags
206+
tags []string
203207
}
204208

205209
// vSphere standard virtual switch

providers/vsphere/resources/vsphere.lr.go

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

providers/vsphere/resources/vsphere.lr.manifest.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ resources:
197197
services: {}
198198
snmp: {}
199199
standardSwitch: {}
200+
tags:
201+
min_mondoo_version: 9.0.0
200202
timezone: {}
201203
vmknics: {}
202204
is_private: true
@@ -244,6 +246,8 @@ resources:
244246
moid: {}
245247
name: {}
246248
properties: {}
249+
tags:
250+
min_mondoo_version: 9.0.0
247251
is_private: true
248252
min_mondoo_version: 5.15.0
249253
platform:

0 commit comments

Comments
 (0)