1
0
Fork 0

Adding upstream version 1.34.4.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-24 07:26:29 +02:00
parent e393c3af3f
commit 4978089aab
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
4963 changed files with 677545 additions and 0 deletions

View file

@ -0,0 +1,128 @@
# XtremIO Input Plugin
The `xtremio` plugin gathers metrics from a Dell EMC XtremIO Storage Array's V3
Rest API. Documentation can be found [here][1].
[1]: https://dl.dell.com/content/docu96624_xtremio-storage-array-x1-and-x2-cluster-types-with-xms-6-3-0-to-6-3-3-and-xios-4-0-15-to-4-0-31-and-6-0-0-to-6-3-3-restful-api-3-x-guide.pdf?language=en_us
## Global configuration options <!-- @/docs/includes/plugin_config.md -->
In addition to the plugin-specific configuration settings, plugins support
additional global and plugin configuration settings. These settings are used to
modify metrics, tags, and field or create aliases and configure ordering, etc.
See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
## Configuration
```toml @sample.conf
# Gathers Metrics From a Dell EMC XtremIO Storage Array's V3 API
[[inputs.xtremio]]
## XtremIO User Interface Endpoint
url = "https://xtremio.example.com/" # required
## Credentials
username = "user1"
password = "pass123"
## Metrics to collect from the XtremIO
# collectors = ["bbus","clusters","ssds","volumes","xms"]
## Optional TLS Config
# tls_ca = "/etc/telegraf/ca.pem"
# tls_cert = "/etc/telegraf/cert.pem"
# tls_key = "/etc/telegraf/key.pem"
## Use SSL but skip chain & host verification
# insecure_skip_verify = false
```
## Metrics
- bbus
- tags:
- serial_number
- guid
- power_feed
- name
- model_name
- fields:
- bbus_power
- bbus_average_daily_temp
- bbus_enabled
- bbus_ups_need_battery_replacement
- bbus_ups_low_battery_no_input
- clusters
- tags:
- hardware_platform
- license_id
- guid
- name
- sys_psnt_serial_number
- fields:
- clusters_compression_factor
- clusters_percent_memory_in_use
- clusters_read_iops
- clusters_write_iops
- clusters_number_of_volumes
- clusters_free_ssd_space_in_percent
- clusters_ssd_num
- clusters_data_reduction_ratio
- ssds
- tags:
- model_name
- firmware_version
- ssd_uid
- guid
- sys_name
- serial_number
- fields:
- ssds_ssd_size
- ssds_ssd_space_in_use
- ssds_write_iops
- ssds_read_iops
- ssds_write_bandwidth
- ssds_read_bandwidth
- ssds_num_bad_sectors
- volumes
- tags:
- guid
- sys_name
- name
- fields:
- volumes_read_iops
- volumes_write_iops
- volumes_read_latency
- volumes_write_latency
- volumes_data_reduction_ratio
- volumes_provisioned_space
- volumes_used_space
- xms
- tags:
- guid
- name
- version
- xms_ip
- fields:
- xms_write_iops
- xms_read_iops
- xms_overall_efficiency_ratio
- xms_ssd_space_in_use
- xms_ram_in_use
- xms_ram_total
- xms_cpu_usage_total
- xms_write_latency
- xms_read_latency
- xms_user_accounts_count
## Example Output
```text
xio,guid=abcdefghifklmnopqrstuvwxyz111111,host=HOSTNAME,model_name=Eaton\ 5P\ 1550,name=X2-BBU,power_feed=PWR-B,serial_number=SER1234567890 bbus_average_daily_temp=22i,bbus_enabled=1i,bbus_power=286i,bbus_ups_low_battery_no_input=0i,bbus_ups_need_battery_replacement=0i 1638295340000000000
xio,guid=abcdefghifklmnopqrstuvwxyz222222,host=HOSTNAME,model_name=Eaton\ 5P\ 1550,name=X1-BBU,power_feed=PWR-A,serial_number=SER1234567891 bbus_average_daily_temp=22i,bbus_enabled=1i,bbus_power=246i,bbus_ups_low_battery_no_input=0i,bbus_ups_need_battery_replacement=0i 1638295340000000000
xio,guid=abcdefghifklmnopqrstuvwxyz333333,hardware_platform=X1,host=HOSTNAME,license_id=LIC123456789,name=SERVER01,sys_psnt_serial_number=FNM01234567890 clusters_compression_factor=1.5160012465000001,clusters_data_reduction_ratio=2.1613617899,clusters_free_ssd_space_in_percent=34i,clusters_number_of_volumes=36i,clusters_percent_memory_in_use=29i,clusters_read_iops=331i,clusters_ssd_num=50i,clusters_write_iops=4649i 1638295341000000000
```

View file

@ -0,0 +1,18 @@
# Gathers Metrics From a Dell EMC XtremIO Storage Array's V3 API
[[inputs.xtremio]]
## XtremIO User Interface Endpoint
url = "https://xtremio.example.com/" # required
## Credentials
username = "user1"
password = "pass123"
## Metrics to collect from the XtremIO
# collectors = ["bbus","clusters","ssds","volumes","xms"]
## Optional TLS Config
# tls_ca = "/etc/telegraf/ca.pem"
# tls_cert = "/etc/telegraf/cert.pem"
# tls_key = "/etc/telegraf/key.pem"
## Use SSL but skip chain & host verification
# insecure_skip_verify = false

View file

@ -0,0 +1,20 @@
{
"content": {
"is-low-battery-has-input": "false",
"serial-number": "A123B45678",
"guid": "987654321abcdef",
"brick-name": "X1",
"ups-battery-charge-in-percent": 100,
"power": 244,
"avg-daily-temp": 23,
"fw-version": "01.02.0034",
"sys-name": "ABCXIO001",
"power-feed": "PWR-A",
"ups-load-in-percent": 21,
"name": "X1-BBU",
"enabled-state": "enabled",
"is-low-battery-no-input": "false",
"ups-need-battery-replacement": "false",
"model-name": "Eaton Model Name"
}
}

View file

@ -0,0 +1,15 @@
{
"bbus": [
{
"href": "https://127.0.0.1/api/json/v3/types/bbus/987654321abcdef",
"name": "X1-BBU",
"sys-name": "ABCXIO001"
}
],
"links": [
{
"href": "https://127.0.0.1/api/json/v3/types/bbus/",
"rel": "self"
}
]
}

View file

@ -0,0 +1,382 @@
//go:generate ../../../tools/readme_config_includer/generator
package xtremio
import (
_ "embed"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strings"
"sync"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal/choice"
"github.com/influxdata/telegraf/plugins/common/tls"
"github.com/influxdata/telegraf/plugins/inputs"
)
//go:embed sample.conf
var sampleConfig string
type XtremIO struct {
Username string `toml:"username"`
Password string `toml:"password"`
URL string `toml:"url"`
Collectors []string `toml:"collectors"`
Log telegraf.Logger `toml:"-"`
tls.ClientConfig
cookie *http.Cookie
client *http.Client
}
func (*XtremIO) SampleConfig() string {
return sampleConfig
}
func (xio *XtremIO) Init() error {
if xio.Username == "" {
return errors.New("username cannot be empty")
}
if xio.Password == "" {
return errors.New("password cannot be empty")
}
if xio.URL == "" {
return errors.New("url cannot be empty")
}
availableCollectors := []string{"bbus", "clusters", "ssds", "volumes", "xms"}
if len(xio.Collectors) == 0 {
xio.Collectors = availableCollectors
}
for _, collector := range xio.Collectors {
if !choice.Contains(collector, availableCollectors) {
return fmt.Errorf("specified collector %q isn't supported", collector)
}
}
tlsCfg, err := xio.ClientConfig.TLSConfig()
if err != nil {
return err
}
xio.client = &http.Client{
Transport: &http.Transport{
TLSClientConfig: tlsCfg,
},
}
return nil
}
func (xio *XtremIO) Gather(acc telegraf.Accumulator) error {
if err := xio.authenticate(); err != nil {
return err
}
if xio.cookie == nil {
return errors.New("no authentication cookie set")
}
var wg sync.WaitGroup
for _, collector := range xio.Collectors {
wg.Add(1)
go func(collector string) {
defer wg.Done()
resp, err := xio.call(collector)
if err != nil {
acc.AddError(err)
return
}
data := collectorResponse{}
err = json.Unmarshal([]byte(resp), &data)
if err != nil {
acc.AddError(err)
}
var arr []href
switch collector {
case "bbus":
arr = data.BBUs
case "clusters":
arr = data.Clusters
case "ssds":
arr = data.SSDs
case "volumes":
arr = data.Volumes
case "xms":
arr = data.XMS
}
for _, item := range arr {
itemSplit := strings.Split(item.Href, "/")
if len(itemSplit) < 1 {
continue
}
url := collector + "/" + itemSplit[len(itemSplit)-1]
// Each collector is ran in a goroutine so they can be run in parallel.
// Each collector does an initial query to build out the subqueries it
// needs to run, which are started here in nested goroutines. A future
// refactor opportunity would be for the initial collector goroutines to
// return the results while exiting the goroutine, and then a series of
// goroutines can be kicked off for the subqueries. That way there is no
// nesting of goroutines.
switch collector {
case "bbus":
wg.Add(1)
go xio.gatherBBUs(acc, url, &wg)
case "clusters":
wg.Add(1)
go xio.gatherClusters(acc, url, &wg)
case "ssds":
wg.Add(1)
go xio.gatherSSDs(acc, url, &wg)
case "volumes":
wg.Add(1)
go xio.gatherVolumes(acc, url, &wg)
case "xms":
wg.Add(1)
go xio.gatherXMS(acc, url, &wg)
default:
acc.AddError(fmt.Errorf("specified collector %q isn't supported", collector))
}
}
}(collector)
}
wg.Wait()
// At the beginning of every collection, we re-authenticate.
// We reset this cookie so we don't accidentally use an
// expired cookie, we can just check if it's nil and know
// that we either need to re-authenticate or that the
// authentication failed to set the cookie.
xio.cookie = nil
return nil
}
func (xio *XtremIO) gatherBBUs(acc telegraf.Accumulator, url string, wg *sync.WaitGroup) {
defer wg.Done()
resp, err := xio.call(url)
if err != nil {
acc.AddError(err)
return
}
data := bbu{}
err = json.Unmarshal([]byte(resp), &data)
if err != nil {
acc.AddError(err)
return
}
tags := map[string]string{
"serial_number": data.Content.Serial,
"guid": data.Content.GUID,
"power_feed": data.Content.PowerFeed,
"name": data.Content.Name,
"model_name": data.Content.ModelName,
}
fields := map[string]interface{}{
"bbus_power": data.Content.BBUPower,
"bbus_average_daily_temp": data.Content.BBUDailyTemp,
"bbus_enabled": (data.Content.BBUEnabled == "enabled"),
"bbus_ups_need_battery_replacement": data.Content.BBUNeedBat,
"bbus_ups_low_battery_no_input": data.Content.BBULowBat,
}
acc.AddFields("xio", fields, tags)
}
func (xio *XtremIO) gatherClusters(acc telegraf.Accumulator, url string, wg *sync.WaitGroup) {
defer wg.Done()
resp, err := xio.call(url)
if err != nil {
acc.AddError(err)
return
}
data := clusters{}
err = json.Unmarshal([]byte(resp), &data)
if err != nil {
acc.AddError(err)
return
}
tags := map[string]string{
"hardware_platform": data.Content.HardwarePlatform,
"license_id": data.Content.LicenseID,
"guid": data.Content.GUID,
"name": data.Content.Name,
"sys_psnt_serial_number": data.Content.SerialNumber,
}
fields := map[string]interface{}{
"clusters_compression_factor": data.Content.CompressionFactor,
"clusters_percent_memory_in_use": data.Content.MemoryUsed,
"clusters_read_iops": data.Content.ReadIops,
"clusters_write_iops": data.Content.WriteIops,
"clusters_number_of_volumes": data.Content.NumVolumes,
"clusters_free_ssd_space_in_percent": data.Content.FreeSSDSpace,
"clusters_ssd_num": data.Content.NumSSDs,
"clusters_data_reduction_ratio": data.Content.DataReductionRatio,
}
acc.AddFields("xio", fields, tags)
}
func (xio *XtremIO) gatherSSDs(acc telegraf.Accumulator, url string, wg *sync.WaitGroup) {
defer wg.Done()
resp, err := xio.call(url)
if err != nil {
acc.AddError(err)
return
}
data := ssd{}
err = json.Unmarshal([]byte(resp), &data)
if err != nil {
acc.AddError(err)
return
}
tags := map[string]string{
"model_name": data.Content.ModelName,
"firmware_version": data.Content.FirmwareVersion,
"ssd_uid": data.Content.SSDuid,
"guid": data.Content.GUID,
"sys_name": data.Content.SysName,
"serial_number": data.Content.SerialNumber,
}
fields := map[string]interface{}{
"ssds_ssd_size": data.Content.Size,
"ssds_ssd_space_in_use": data.Content.SpaceUsed,
"ssds_write_iops": data.Content.WriteIops,
"ssds_read_iops": data.Content.ReadIops,
"ssds_write_bandwidth": data.Content.WriteBandwidth,
"ssds_read_bandwidth": data.Content.ReadBandwidth,
"ssds_num_bad_sectors": data.Content.NumBadSectors,
}
acc.AddFields("xio", fields, tags)
}
func (xio *XtremIO) gatherVolumes(acc telegraf.Accumulator, url string, wg *sync.WaitGroup) {
defer wg.Done()
resp, err := xio.call(url)
if err != nil {
acc.AddError(err)
return
}
data := volumes{}
err = json.Unmarshal([]byte(resp), &data)
if err != nil {
acc.AddError(err)
return
}
tags := map[string]string{
"guid": data.Content.GUID,
"sys_name": data.Content.SysName,
"name": data.Content.Name,
}
fields := map[string]interface{}{
"volumes_read_iops": data.Content.ReadIops,
"volumes_write_iops": data.Content.WriteIops,
"volumes_read_latency": data.Content.ReadLatency,
"volumes_write_latency": data.Content.WriteLatency,
"volumes_data_reduction_ratio": data.Content.DataReductionRatio,
"volumes_provisioned_space": data.Content.ProvisionedSpace,
"volumes_used_space": data.Content.UsedSpace,
}
acc.AddFields("xio", fields, tags)
}
func (xio *XtremIO) gatherXMS(acc telegraf.Accumulator, url string, wg *sync.WaitGroup) {
defer wg.Done()
resp, err := xio.call(url)
if err != nil {
acc.AddError(err)
return
}
data := xms{}
err = json.Unmarshal([]byte(resp), &data)
if err != nil {
acc.AddError(err)
return
}
tags := map[string]string{
"guid": data.Content.GUID,
"name": data.Content.Name,
"version": data.Content.Version,
"xms_ip": data.Content.IP,
}
fields := map[string]interface{}{
"xms_write_iops": data.Content.WriteIops,
"xms_read_iops": data.Content.ReadIops,
"xms_overall_efficiency_ratio": data.Content.EfficiencyRatio,
"xms_ssd_space_in_use": data.Content.SpaceUsed,
"xms_ram_in_use": data.Content.RAMUsage,
"xms_ram_total": data.Content.RAMTotal,
"xms_cpu_usage_total": data.Content.CPUUsage,
"xms_write_latency": data.Content.WriteLatency,
"xms_read_latency": data.Content.ReadLatency,
"xms_user_accounts_count": data.Content.NumAccounts,
}
acc.AddFields("xio", fields, tags)
}
func (xio *XtremIO) call(endpoint string) (string, error) {
req, err := http.NewRequest("GET", xio.URL+"/api/json/v3/types/"+endpoint, nil)
if err != nil {
return "", err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
req.AddCookie(xio.cookie)
resp, err := xio.client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(data), nil
}
func (xio *XtremIO) authenticate() error {
req, err := http.NewRequest("GET", xio.URL+"/api/json/v3/commands/login", nil)
if err != nil {
return err
}
req.SetBasicAuth(xio.Username, xio.Password)
resp, err := xio.client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
for _, cookie := range resp.Cookies() {
if cookie.Name == "sessid" {
xio.cookie = cookie
break
}
}
return nil
}
func init() {
inputs.Add("xtremio", func() telegraf.Input {
return &XtremIO{}
})
}

View file

@ -0,0 +1,225 @@
package xtremio
import (
"fmt"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/testutil"
)
var testdataDir = getTestdataDir()
func TestInitDefault(t *testing.T) {
// This test should succeed with the default initialization.
plugin := &XtremIO{
Username: "testuser",
Password: "testpass",
URL: "http://example.com",
Log: testutil.Logger{},
}
// Test the initialization succeeds
require.NoError(t, plugin.Init())
// Also test that default values are set correctly
require.Equal(t, "testuser", plugin.Username)
require.Equal(t, "testpass", plugin.Password)
require.Equal(t, "http://example.com", plugin.URL)
}
func TestInitFail(t *testing.T) {
tests := []struct {
name string
plugin *XtremIO
expected string
}{
{
name: "all empty",
plugin: &XtremIO{},
expected: "username cannot be empty",
},
{
name: "no username",
plugin: &XtremIO{Password: "testpass", URL: "http://example.com"},
expected: "username cannot be empty",
},
{
name: "no password",
plugin: &XtremIO{Username: "testuser", URL: "http://example.com"},
expected: "password cannot be empty",
},
{
name: "no url",
plugin: &XtremIO{Username: "testuser", Password: "testpass"},
expected: "url cannot be empty",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.plugin.Log = testutil.Logger{}
err := tt.plugin.Init()
require.Error(t, err)
require.EqualError(t, err, tt.expected)
})
}
}
func TestFixedValue(t *testing.T) {
ts := httptest.NewServer(
http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/api/json/v3/commands/login" {
cookie := &http.Cookie{Name: "sessid", Value: "cookie:123456789"}
http.SetCookie(w, cookie)
if _, err := fmt.Fprintln(w, "authentication succeeded"); err != nil {
w.WriteHeader(http.StatusInternalServerError)
t.Error(err)
return
}
w.WriteHeader(http.StatusOK)
} else if r.URL.Path == "/api/json/v3/types/bbus" {
sampleGetBBUsResponse, err := os.ReadFile(filepath.Join(testdataDir, "sample_get_bbu_response.json"))
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
t.Error(err)
return
}
if _, err = fmt.Fprintln(w, string(sampleGetBBUsResponse)); err != nil {
w.WriteHeader(http.StatusInternalServerError)
t.Error(err)
return
}
w.WriteHeader(http.StatusOK)
} else if r.URL.Path == "/api/json/v3/types/bbus/987654321abcdef" {
sampleBBUResponseOne, err := os.ReadFile(filepath.Join(testdataDir, "sample_bbu_response.json"))
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
t.Error(err)
return
}
if _, err = fmt.Fprintln(w, string(sampleBBUResponseOne)); err != nil {
w.WriteHeader(http.StatusInternalServerError)
t.Error(err)
return
}
w.WriteHeader(http.StatusOK)
}
},
),
)
defer ts.Close()
tests := []struct {
name string
plugin *XtremIO
expected []telegraf.Metric
}{
{
name: "gather bbus only",
plugin: &XtremIO{
Username: "testuser",
Password: "testpass",
URL: ts.URL,
Collectors: []string{"bbus"},
},
expected: []telegraf.Metric{
testutil.MustMetric(
"xio",
map[string]string{
"serial_number": "A123B45678",
"guid": "987654321abcdef",
"power_feed": "PWR-A",
"name": "X1-BBU",
"model_name": "Eaton Model Name",
},
map[string]interface{}{
"bbus_power": 244,
"bbus_average_daily_temp": 23,
"bbus_enabled": true,
"bbus_ups_need_battery_replacement": false,
"bbus_ups_low_battery_no_input": false,
},
time.Unix(0, 0),
),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var acc testutil.Accumulator
tt.plugin.Log = testutil.Logger{}
require.NoError(t, tt.plugin.Init())
require.NoError(t, tt.plugin.Gather(&acc))
require.Empty(t, acc.Errors, "found errors accumulated by acc.AddError()")
acc.Wait(len(tt.expected))
testutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())
})
}
}
func TestAuthenticationFailed(t *testing.T) {
ts := httptest.NewServer(
http.HandlerFunc(
func(w http.ResponseWriter, _ *http.Request) {
if _, err := fmt.Fprintln(w, "bad request"); err != nil {
w.WriteHeader(http.StatusInternalServerError)
t.Error(err)
return
}
w.WriteHeader(http.StatusBadRequest)
},
),
)
defer ts.Close()
tests := []struct {
name string
plugin *XtremIO
expected string
}{
{
name: "authentication failed",
plugin: &XtremIO{
Username: "usertest",
Password: "userpass",
URL: ts.URL,
},
expected: "no authentication cookie set",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var acc testutil.Accumulator
tt.plugin.Log = testutil.Logger{}
require.NoError(t, tt.plugin.Init())
err := tt.plugin.Gather(&acc)
require.Error(t, err)
require.EqualError(t, err, tt.expected)
})
}
}
func getTestdataDir() string {
dir, err := os.Getwd()
if err != nil {
// if we cannot even establish the test directory, further progress is meaningless
panic(err)
}
return filepath.Join(dir, "testdata")
}

View file

@ -0,0 +1,98 @@
package xtremio
type bbu struct {
Content struct {
Serial string `json:"serial-number"`
GUID string `json:"guid"`
PowerFeed string `json:"power-feed"`
Name string `json:"Name"`
ModelName string `json:"model-name"`
BBUPower int `json:"power"`
BBUDailyTemp int `json:"avg-daily-temp"`
BBUEnabled string `json:"enabled-state"`
BBUNeedBat bool `json:"ups-need-battery-replacement,string"`
BBULowBat bool `json:"is-low-battery-no-input,string"`
}
}
type clusters struct {
Content struct {
HardwarePlatform string `json:"hardware-platform"`
LicenseID string `json:"license-id"`
GUID string `json:"guid"`
Name string `json:"name"`
SerialNumber string `json:"sys-psnt-serial-number"`
CompressionFactor float64 `json:"compression-factor"`
MemoryUsed int `json:"total-memory-in-use-in-percent"`
ReadIops int `json:"rd-iops,string"`
WriteIops int `json:"wr-iops,string"`
NumVolumes int `json:"num-of-vols"`
FreeSSDSpace int `json:"free-ud-ssd-space-in-percent"`
NumSSDs int `json:"num-of-ssds"`
DataReductionRatio float64 `json:"data-reduction-ratio"`
}
}
type ssd struct {
Content struct {
ModelName string `json:"model-name"`
FirmwareVersion string `json:"fw-version"`
SSDuid string `json:"ssd-uid"`
GUID string `json:"guid"`
SysName string `json:"sys-name"`
SerialNumber string `json:"serial-number"`
Size int `json:"ssd-size,string"`
SpaceUsed int `json:"ssd-space-in-use,string"`
WriteIops int `json:"wr-iops,string"`
ReadIops int `json:"rd-iops,string"`
WriteBandwidth int `json:"wr-bw,string"`
ReadBandwidth int `json:"rd-bw,string"`
NumBadSectors int `json:"num-bad-sectors"`
}
}
type volumes struct {
Content struct {
GUID string `json:"guid"`
SysName string `json:"sys-name"`
Name string `json:"name"`
ReadIops int `json:"rd-iops,string"`
WriteIops int `json:"wr-iops,string"`
ReadLatency int `json:"rd-latency,string"`
WriteLatency int `json:"wr-latency,string"`
DataReductionRatio float64 `json:"data-reduction-ratio,string"`
ProvisionedSpace int `json:"vol-size,string"`
UsedSpace int `json:"logical-space-in-use,string"`
}
}
type xms struct {
Content struct {
GUID string `json:"guid"`
Name string `json:"name"`
Version string `json:"version"`
IP string `json:"xms-ip"`
WriteIops int `json:"wr-iops,string"`
ReadIops int `json:"rd-iops,string"`
EfficiencyRatio float64 `json:"overall-efficiency-ratio,string"`
SpaceUsed int `json:"ssd-space-in-use,string"`
RAMUsage int `json:"ram-usage,string"`
RAMTotal int `json:"ram-total,string"`
CPUUsage float64 `json:"cpu"`
WriteLatency int `json:"wr-latency,string"`
ReadLatency int `json:"rd-latency,string"`
NumAccounts int `json:"num-of-user-accounts"`
}
}
type href struct {
Href string `json:"href"`
}
type collectorResponse struct {
BBUs []href `json:"bbus"`
Clusters []href `json:"clusters"`
SSDs []href `json:"ssds"`
Volumes []href `json:"volumes"`
XMS []href `json:"xmss"`
}