Skip to content
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
2 changes: 0 additions & 2 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ builds:
- arm64
goos:
- linux
- windows
- darwin
ldflags:
- >-
-s -w -X main.version={{.Version}}
Expand Down
62 changes: 42 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,61 @@
![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/NETWAYS/check_vspheredb_data)
![GitHub](https://img.shields.io/github/license/NETWAYS/check_vspheredb_data)
# check_vspheredb_data

# README
An Icinga check plugin to check the performance data gathered by the [Icingaweb2 vSphereDB module](https://github.com/icinga/icingaweb2-module-vspheredb).

`check_vspheredb_data` is a check plugin for checking performance data gathered by the [Icingaweb2 vSphereDB module](https://github.com/icinga/icingaweb2-module-vspheredb)
against given thresholds written in Go. It is a rewrite of [an older version](https://github.com/NETWAYS/vspheredb-data-check) written in Rust, utilizing the [go-check](https://github.com/NETWAYS/go-check) SDK for monitoring plugins for better maintainability.

It allows for finegrained monitoring of ESXI hosts on Icinga2's side without the need to configure alerting on
the vCenters' side as vSphereDB's inbuilt mechanisms do.

![screenshot of plugin output](docs/thumbnail.png)
It allows for monitoring of ESXI hosts on Icinga2's side without the need to configure alerting on the vCenters' side as vSphereDB's inbuilt mechanisms do.

## Installation

Download a Release binary for your system's architecture from the [Releases](https://github.com/NETWAYS/check_vspheredb_data/releases) page.

## Building the project
## Usage

```
Available Commands:
completion Generate the autocompletion script for the specified shell
cpu Checks the current CPU usage
datastore Checks all datastores or a single specified datastore
hba Checks attached HBAs. Uses negative thresholds as parameters, e.g. 10:
help Help about any command
memory Checks the current memory usage
nic Checks the number of attached NICs. Uses negative thresholds as parameters, e.g. 10:
temperature Checks the temperature of sensors

Flags:
-f, --credentials-file string Path to the credentials file
-d, --database string Database name (default "vspheredb")
-h, --help help for check_vspheredb_data
-H, --host string Database host to connect to
-m, --machine string Machine to be queried for
-P, --password string Database password (default "vspheredb")
-p, --port int16 Database port to connect to (default 3306)
-u, --username string Database username (default "vspheredb")

datastore:
-s, --datastore string Name of the datastore to check
temperature:
-s, --sensor string Sensor name filter (supports SQL LIKE pattern)
```

## Development

Alternatively, you can build the binary yourself using the Golang toolchain.
To build the tool yourself using the Golang toolchain:

```shell
git clone https://github.com/NETWAYS/check_vspheredb_data --branch=v1.0.0
git clone https://github.com/NETWAYS/check_vspheredb_data
cd check_vspheredb_data
go build
```

The resulting binary `check_vspheredb_data` can be found in the root directory of the repository.

## Usage

The check plugin provides detailed information about available check modes (see thumbnail above). More information can be accessed by
entering `check_vspheredb_data <mode> --help`.
The repository contains example SQL data to test the plugin against:

```
podman run -ti --rm -p 3306:3306 \
-e MYSQL_DATABASE=example -e MYSQL_USER=example -e MYSQL_PASSWORD=example -e MYSQL_ROOT_PASSWORD=example \
-v $(pwd)/testdata/:/docker-entrypoint-initdb.d docker.io/mariadb:latest
```
## License

Copyright© 2024 [NETWAYS GmbH](mailto:info@netways.de)

This check plugin is distributed under the GPL-2.0 or newer license shipped with this repository in the [LICENSE](LICENSE) file.
This check plugin is distributed under the GPL-3.0 license shipped with this repository in the [LICENSE](LICENSE) file.
27 changes: 11 additions & 16 deletions cmd/cpu.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,18 @@ var cpuCritical string
var cpuWarnThreshold *check.Threshold
var cpuCritThreshold *check.Threshold

// cpuCmd represents the cpu command.
var cpuCmd = &cobra.Command{
Use: "cpu",
Short: "Checks CPU usage",
Short: "Checks the current CPU usage",
Run: func(_ *cobra.Command, _ []string) {
queryCPU()
},
}

func init() {
rootCmd.AddCommand(cpuCmd)
cpuCmd.Flags().StringVarP(&cpuWarning, "warning", "w", "80", "Warning threshold in percent as Integer")
cpuCmd.Flags().StringVarP(&cpuCritical, "critical", "c", "90", "Critical threshold in percent as Integer")
cpuCmd.Flags().StringVarP(&cpuWarning, "warning", "w", "80", "Warning threshold in percent")
cpuCmd.Flags().StringVarP(&cpuCritical, "critical", "c", "90", "Critical threshold in percent")
}

// Query for CPU usage of the given machine, exit with UNKNOWN on query errors.
Expand All @@ -52,40 +51,36 @@ func queryCPU() {
dbConnection := internal.DBConnection(host, port, username, password, database)

err = dbConnection.QueryRow(
`SELECT hqs.overall_cpu_usage,
hs.hardware_cpu_mhz,
hs.hardware_cpu_cores
FROM host_quick_stats hqs
INNER JOIN host_system hs
ON hqs.uuid = hs.uuid
`SELECT hqs.overall_cpu_usage,
hs.hardware_cpu_mhz,
hs.hardware_cpu_cores
FROM host_quick_stats hqs
INNER JOIN host_system hs
ON hqs.uuid = hs.uuid
WHERE hs.host_name LIKE ?`, machine).Scan(&overallCPUUsage, &hardwareCPUMHz, &hardwareCPUCores)
if err != nil {
check.ExitError(err)
}

// calculate percentage usage for check result decision.
// Calculate percentage usage for check result decision.
cpuUsagePercent := overallCPUUsage * 100 / (hardwareCPUCores * hardwareCPUMHz)

// Add Perfdata.
// total usage.
// Add performance data
pl.Add(&check.Perfdata{
Label: "usage",
Value: overallCPUUsage,
})
// usage in percent, including thresholds.
pl.Add(&check.Perfdata{
Label: "usage_percent",
Value: cpuUsagePercent,
Uom: "%",
Warn: cpuWarnThreshold,
Crit: cpuCritThreshold,
})
// mhz.
pl.Add(&check.Perfdata{
Label: "mhz",
Value: hardwareCPUMHz,
})
// cores.
pl.Add(&check.Perfdata{
Label: "cores",
Value: hardwareCPUCores,
Expand Down
35 changes: 17 additions & 18 deletions cmd/datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ var datastoreWarnThreshold *check.Threshold
var datastoreCritThreshold *check.Threshold
var datastore string

// datastoreCmd represents the datastore command.
var datastoreCmd = &cobra.Command{
Use: "datastore",
Short: "Checks all datastores or a singular, specified datastore",
Short: "Checks all datastores or a single specified datastore",
Run: func(_ *cobra.Command, _ []string) {
queryDatastore()
},
Expand All @@ -35,9 +34,9 @@ var datastoreCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(datastoreCmd)

datastoreCmd.Flags().StringVarP(&datastoreWarning, "warning", "w", "80", "Warning threshold in percent as Integer")
datastoreCmd.Flags().StringVarP(&datastoreCritical, "critical", "c", "90", "Critical threshold in percent as Integer")
datastoreCmd.Flags().StringVarP(&datastore, "datastore", "s", "", "Datastore to check")
datastoreCmd.Flags().StringVarP(&datastoreWarning, "warning", "w", "80", "Warning threshold in percent")
datastoreCmd.Flags().StringVarP(&datastoreCritical, "critical", "c", "90", "Critical threshold in percent")
datastoreCmd.Flags().StringVarP(&datastore, "datastore", "s", "", "Name of the datastore to check")
}

func queryDatastore() {
Expand All @@ -60,11 +59,11 @@ func queryDatastore() {

dbConnection := internal.DBConnection(host, port, username, password, database)

err = dbConnection.QueryRow(`SELECT ds.capacity, ds.free_space
FROM datastore ds
INNER JOIN vcenter vc
ON ds.vcenter_uuid = vc.instance_uuid
INNER JOIN object o
err = dbConnection.QueryRow(`SELECT ds.capacity, ds.free_space
FROM datastore ds
INNER JOIN vcenter vc
ON ds.vcenter_uuid = vc.instance_uuid
INNER JOIN object o
ON ds.uuid = o.uuid
WHERE o.object_name LIKE ?
AND vc.name LIKE ?`,
Expand Down Expand Up @@ -105,11 +104,11 @@ func queryDatastores() {
// Collect query results.
dbConnection := internal.DBConnection(host, port, username, password, database)

rows, err := dbConnection.Query(`SELECT o.object_name, ds.capacity, ds.free_space
FROM datastore ds
INNER JOIN vcenter vc
ON ds.vcenter_uuid = vc.instance_uuid
INNER JOIN object o
rows, err := dbConnection.Query(`SELECT o.object_name, ds.capacity, ds.free_space
FROM datastore ds
INNER JOIN vcenter vc
ON ds.vcenter_uuid = vc.instance_uuid
INNER JOIN object o
ON ds.uuid = o.uuid
WHERE vc.name LIKE ?`,
machine)
Expand Down Expand Up @@ -147,13 +146,13 @@ func queryDatastores() {
// Computes Perfdata, check result based on the queried data.
func processQueryResults(datastore string, capacity, freeSpace int64) (check.Perfdata, check.Status) {
// calculate percentage usage for check result decision.
datastoreUsagePercent := int64(0)
var datastoreUsagePercent int64

if capacity != 0 {
datastoreUsagePercent = (capacity - freeSpace) * 100 / capacity
}

// Add Perfdata.
// percentage usage.
// Add performance data
perfData := check.Perfdata{
Label: datastore + "_used",
Value: datastoreUsagePercent,
Expand Down
15 changes: 7 additions & 8 deletions cmd/hba.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ var hbaCritical string
var hbaWarnThreshold *check.Threshold
var hbaCritThreshold *check.Threshold

// hbaCmd represents the hba command.
var hbaCmd = &cobra.Command{
Use: "hba",
Short: "Checks attached HBAs",
Short: "Checks attached HBAs. Uses negative thresholds as parameters, e.g. 10:",
Run: func(_ *cobra.Command, _ []string) {
queryHba()
},
Expand All @@ -26,8 +25,8 @@ var hbaCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(hbaCmd)

hbaCmd.Flags().StringVarP(&hbaWarning, "warning", "w", "2", "Warning threshold as Integer (\"less than X available\")")
hbaCmd.Flags().StringVarP(&hbaCritical, "critical", "c", "1", "Critical threshold as Integer (\"less than X available\")")
hbaCmd.Flags().StringVarP(&hbaWarning, "warning", "w", "2:", "Warning threshold (\"less than X available\")")
hbaCmd.Flags().StringVarP(&hbaCritical, "critical", "c", "1:", "Critical threshold (\"less than X available\")")
}

func queryHba() {
Expand All @@ -37,20 +36,20 @@ func queryHba() {
)

// Parse thresholds from given flags.
hbaWarnThreshold, err = check.ParseThreshold(hbaWarning + ":") // `:` is needed because warning/critical are reversed.
hbaWarnThreshold, err = check.ParseThreshold(hbaWarning)
if err != nil {
check.ExitError(err)
}

hbaCritThreshold, err = check.ParseThreshold(hbaCritical + ":") // `:` is needed because warning/critical are reversed.
hbaCritThreshold, err = check.ParseThreshold(hbaCritical)
if err != nil {
check.ExitError(err)
}

dbConnection := internal.DBConnection(host, port, username, password, database)

err = dbConnection.QueryRow(`SELECT hardware_num_hba
FROM host_system
err = dbConnection.QueryRow(`SELECT hardware_num_hba
FROM host_system
WHERE host_system.host_name LIKE ?`,
machine).Scan(&hardwareNumHBAs)
if err != nil {
Expand Down
20 changes: 8 additions & 12 deletions cmd/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ var memoryCritical string
var memoryWarnThreshold *check.Threshold
var memoryCritThreshold *check.Threshold

// memoryCmd represents the memory command.
var memoryCmd = &cobra.Command{
Use: "memory",
Short: "Checks memory usage",
Short: "Checks the current memory usage",
Run: func(_ *cobra.Command, _ []string) {
queryMemory()
},
Expand All @@ -26,8 +25,8 @@ var memoryCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(memoryCmd)

memoryCmd.Flags().StringVarP(&memoryWarning, "warning", "w", "80", "Warning threshold in percent as Integer")
memoryCmd.Flags().StringVarP(&memoryCritical, "critical", "c", "90", "Critical threshold in percent as Integer")
memoryCmd.Flags().StringVarP(&memoryWarning, "warning", "w", "80", "Warning threshold in percent")
memoryCmd.Flags().StringVarP(&memoryCritical, "critical", "c", "90", "Critical threshold in percent")
}

// Query for memory usage of the given machine, exit with UNKNOWN on query errors.
Expand All @@ -52,11 +51,11 @@ func queryMemory() {
dbConnection := internal.DBConnection(host, port, username, password, database)

err = dbConnection.QueryRow(
`SELECT hqs.overall_memory_usage_mb,
hs.hardware_memory_size_mb
FROM host_quick_stats hqs
INNER JOIN host_system hs
ON hqs.uuid = hs.uuid
`SELECT hqs.overall_memory_usage_mb,
hs.hardware_memory_size_mb
FROM host_quick_stats hqs
INNER JOIN host_system hs
ON hqs.uuid = hs.uuid
WHERE hs.host_name LIKE ?`, machine).Scan(&overallMemoryUsageMB, &hardwareMemorySizeMB)
if err != nil {
check.ExitError(err)
Expand All @@ -65,14 +64,11 @@ func queryMemory() {
// calculate percentage usage for check result decision.
memoryUsagePercent := overallMemoryUsageMB * 100 / hardwareMemorySizeMB

// Add Perfdata.
// total usage.
pl.Add(&check.Perfdata{
Label: "usage",
Value: overallMemoryUsageMB * 1024 * 1024, // Report in Bytes.
Uom: "B",
})
// percentage usage.
pl.Add(&check.Perfdata{
Label: "usage_percent",
Value: memoryUsagePercent,
Expand Down
15 changes: 7 additions & 8 deletions cmd/nic.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ var nicCritical string
var nicWarnThreshold *check.Threshold
var nicCritThreshold *check.Threshold

// nicCmd represents the nic command.
var nicCmd = &cobra.Command{
Use: "nic",
Short: "Checks attached NICs",
Short: "Checks the number of attached NICs. Uses negative thresholds as parameters, e.g. 10:",
Run: func(_ *cobra.Command, _ []string) {
queryNic()
},
Expand All @@ -26,8 +25,8 @@ var nicCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(nicCmd)

nicCmd.Flags().StringVarP(&nicWarning, "warning", "w", "2", "Warning threshold as Integer (\"less than X available\")")
nicCmd.Flags().StringVarP(&nicCritical, "critical", "c", "1", "Critical threshold as Integer (\"less than X available\")")
nicCmd.Flags().StringVarP(&nicWarning, "warning", "w", "2:", "Warning threshold (\"less than X available\")")
nicCmd.Flags().StringVarP(&nicCritical, "critical", "c", "1:", "Critical threshold (\"less than X available\")")
}

func queryNic() {
Expand All @@ -37,20 +36,20 @@ func queryNic() {
)

// Parse thresholds from given flags.
nicWarnThreshold, err = check.ParseThreshold(nicWarning + ":") // `:` is needed because warning/critical are reversed.
nicWarnThreshold, err = check.ParseThreshold(nicWarning)
if err != nil {
check.ExitError(err)
}

nicCritThreshold, err = check.ParseThreshold(nicCritical + ":") // `:` is needed because warning/critical are reversed.
nicCritThreshold, err = check.ParseThreshold(nicCritical)
if err != nil {
check.ExitError(err)
}

dbConnection := internal.DBConnection(host, port, username, password, database)

err = dbConnection.QueryRow(`SELECT hardware_num_nic
FROM host_system
err = dbConnection.QueryRow(`SELECT hardware_num_nic
FROM host_system
WHERE host_system.host_name LIKE ?`,
machine).Scan(&hardwareNumNICs)
if err != nil {
Expand Down
Loading