diff options
Diffstat (limited to '')
21 files changed, 6111 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/README.md b/src/go/collectors/go.d.plugin/modules/scaleio/README.md new file mode 120000 index 000000000..1836d2805 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/README.md @@ -0,0 +1 @@ +integrations/dell_emc_scaleio.md
\ No newline at end of file diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/charts.go b/src/go/collectors/go.d.plugin/modules/scaleio/charts.go new file mode 100644 index 000000000..a6ac24bd9 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/charts.go @@ -0,0 +1,465 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package scaleio + +import ( + "fmt" + + "github.com/netdata/netdata/go/go.d.plugin/modules/scaleio/client" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" +) + +type ( + // Charts is an alias for module.Charts. + Charts = module.Charts + // Dims is an alias for module.Dims. + Dims = module.Dims + // Vars is an alias for module.Vars. + Vars = module.Vars +) + +var ( + prioStoragePool = module.Priority + len(systemCharts) + 10 + prioSdc = prioStoragePool + len(storagePoolCharts) + 10 +) + +var systemCharts = Charts{ + // Capacity + { + ID: "system_capacity_total", + Title: "Total Capacity", + Units: "KiB", + Fam: "capacity", + Ctx: "scaleio.system_capacity_total", + Dims: Dims{ + {ID: "system_capacity_max_capacity", Name: "total"}, + }, + }, + { + ID: "system_capacity_in_use", + Title: "Capacity In Use", + Units: "KiB", + Fam: "capacity", + Ctx: "scaleio.system_capacity_in_use", + Dims: Dims{ + {ID: "system_capacity_in_use", Name: "in_use"}, + }, + }, + { + ID: "system_capacity_usage", + Title: "Capacity Usage", + Units: "KiB", + Fam: "capacity", + Type: module.Stacked, + Ctx: "scaleio.system_capacity_usage", + Dims: Dims{ + {ID: "system_capacity_thick_in_use", Name: "thick"}, + {ID: "system_capacity_decreased", Name: "decreased"}, + {ID: "system_capacity_thin_in_use", Name: "thin"}, + {ID: "system_capacity_snapshot", Name: "snapshot"}, + {ID: "system_capacity_spare", Name: "spare"}, + {ID: "system_capacity_unused", Name: "unused"}, + }, + }, + { + ID: "system_capacity_available_volume_allocation", + Title: "Available For Volume Allocation", + Units: "KiB", + Fam: "capacity", + Ctx: "scaleio.system_capacity_available_volume_allocation", + Dims: Dims{ + {ID: "system_capacity_available_for_volume_allocation", Name: "available"}, + }, + }, + { + ID: "system_capacity_health_state", + Title: "Capacity Health State", + Units: "KiB", + Fam: "health", + Type: module.Stacked, + Ctx: "scaleio.system_capacity_health_state", + Dims: Dims{ + {ID: "system_capacity_protected", Name: "protected"}, + {ID: "system_capacity_degraded", Name: "degraded"}, + {ID: "system_capacity_in_maintenance", Name: "in_maintenance"}, + {ID: "system_capacity_failed", Name: "failed"}, + {ID: "system_capacity_unreachable_unused", Name: "unavailable"}, + }, + }, + // I/O Workload BW + { + ID: "system_workload_primary_bandwidth_total", + Title: "Primary Backend Bandwidth Total (Read and Write)", + Units: "KiB/s", + Fam: "workload", + Ctx: "scaleio.system_workload_primary_bandwidth_total", + Dims: Dims{ + {ID: "system_backend_primary_bandwidth_read_write", Name: "total", Div: 1000}, + }, + }, + { + ID: "system_workload_primary_bandwidth", + Title: "Primary Backend Bandwidth", + Units: "KiB/s", + Fam: "workload", + Ctx: "scaleio.system_workload_primary_bandwidth", + Type: module.Area, + Dims: Dims{ + {ID: "system_backend_primary_bandwidth_read", Name: "read", Div: 1000}, + {ID: "system_backend_primary_bandwidth_write", Name: "write", Mul: -1, Div: 1000}, + }, + }, + // I/O Workload IOPS + { + ID: "system_workload_primary_iops_total", + Title: "Primary Backend IOPS Total (Read and Write)", + Units: "iops/s", + Fam: "workload", + Ctx: "scaleio.system_workload_primary_iops_total", + Dims: Dims{ + {ID: "system_backend_primary_iops_read_write", Name: "total", Div: 1000}, + }, + }, + { + ID: "system_workload_primary_iops", + Title: "Primary Backend IOPS", + Units: "iops/s", + Fam: "workload", + Ctx: "scaleio.system_workload_primary_iops", + Type: module.Area, + Dims: Dims{ + {ID: "system_backend_primary_iops_read", Name: "read", Div: 1000}, + {ID: "system_backend_primary_iops_write", Name: "write", Mul: -1, Div: 1000}, + }, + }, + { + ID: "system_workload_primary_io_size_total", + Title: "Primary Backend I/O Size Total (Read and Write)", + Units: "KiB", + Fam: "workload", + Ctx: "scaleio.system_workload_primary_io_size_total", + Dims: Dims{ + {ID: "system_backend_primary_io_size_read_write", Name: "io_size", Div: 1000}, + }, + }, + // Rebalance + { + ID: "system_rebalance", + Title: "Rebalance", + Units: "KiB/s", + Fam: "rebalance", + Type: module.Area, + Ctx: "scaleio.system_rebalance", + Dims: Dims{ + {ID: "system_rebalance_bandwidth_read", Name: "read", Div: 1000}, + {ID: "system_rebalance_bandwidth_write", Name: "write", Mul: -1, Div: 1000}, + }, + }, + { + ID: "system_rebalance_left", + Title: "Rebalance Pending Capacity", + Units: "KiB", + Fam: "rebalance", + Ctx: "scaleio.system_rebalance_left", + Dims: Dims{ + {ID: "system_rebalance_pending_capacity_in_Kb", Name: "left"}, + }, + }, + { + ID: "system_rebalance_time_until_finish", + Title: "Rebalance Approximate Time Until Finish", + Units: "seconds", + Fam: "rebalance", + Ctx: "scaleio.system_rebalance_time_until_finish", + Dims: Dims{ + {ID: "system_rebalance_time_until_finish", Name: "time"}, + }, + }, + // Rebuild + { + ID: "system_rebuild", + Title: "Rebuild Bandwidth Total (Forward, Backward and Normal)", + Units: "KiB/s", + Fam: "rebuild", + Ctx: "scaleio.system_rebuild", + Type: module.Area, + Dims: Dims{ + {ID: "system_rebuild_total_bandwidth_read", Name: "read", Div: 1000}, + {ID: "system_rebuild_total_bandwidth_write", Name: "write", Mul: -1, Div: 1000}, + }, + }, + { + ID: "system_rebuild_left", + Title: "Rebuild Pending Capacity Total (Forward, Backward and Normal)", + Units: "KiB", + Fam: "rebuild", + Ctx: "scaleio.system_rebuild_left", + Dims: Dims{ + {ID: "system_rebuild_total_pending_capacity_in_Kb", Name: "left"}, + }, + }, + // Components + { + ID: "system_defined_components", + Title: "Components", + Units: "components", + Fam: "components", + Ctx: "scaleio.system_defined_components", + Dims: Dims{ + {ID: "system_num_of_devices", Name: "devices"}, + {ID: "system_num_of_fault_sets", Name: "fault_sets"}, + {ID: "system_num_of_protection_domains", Name: "protection_domains"}, + {ID: "system_num_of_rfcache_devices", Name: "rfcache_devices"}, + {ID: "system_num_of_sdc", Name: "sdc"}, + {ID: "system_num_of_sds", Name: "sds"}, + {ID: "system_num_of_snapshots", Name: "snapshots"}, + {ID: "system_num_of_storage_pools", Name: "storage_pools"}, + {ID: "system_num_of_volumes", Name: "volumes"}, + {ID: "system_num_of_vtrees", Name: "vtrees"}, + }, + }, + { + ID: "system_components_volumes_by_type", + Title: "Volumes By Type", + Units: "volumes", + Fam: "components", + Ctx: "scaleio.system_components_volumes_by_type", + Type: module.Stacked, + Dims: Dims{ + {ID: "system_num_of_thick_base_volumes", Name: "thick"}, + {ID: "system_num_of_thin_base_volumes", Name: "thin"}, + }, + }, + { + ID: "system_components_volumes_by_mapping", + Title: "Volumes By Mapping", + Units: "volumes", + Fam: "components", + Ctx: "scaleio.system_components_volumes_by_mapping", + Type: module.Stacked, + Dims: Dims{ + {ID: "system_num_of_mapped_volumes", Name: "mapped"}, + {ID: "system_num_of_unmapped_volumes", Name: "unmapped"}, + }, + }, +} + +var storagePoolCharts = Charts{ + { + ID: "storage_pool_%s_capacity_total", + Title: "Total Capacity", + Units: "KiB", + Fam: "pool %s", + Ctx: "scaleio.storage_pool_capacity_total", + Dims: Dims{ + {ID: "storage_pool_%s_capacity_max_capacity", Name: "total"}, + }, + }, + { + ID: "storage_pool_%s_capacity_in_use", + Title: "Capacity In Use", + Units: "KiB", + Fam: "pool %s", + Ctx: "scaleio.storage_pool_capacity_in_use", + Dims: Dims{ + {ID: "storage_pool_%s_capacity_in_use", Name: "in_use"}, + }, + }, + { + ID: "storage_pool_%s_capacity_usage", + Title: "Capacity Usage", + Units: "KiB", + Fam: "pool %s", + Type: module.Stacked, + Ctx: "scaleio.storage_pool_capacity_usage", + Dims: Dims{ + {ID: "storage_pool_%s_capacity_thick_in_use", Name: "thick"}, + {ID: "storage_pool_%s_capacity_decreased", Name: "decreased"}, + {ID: "storage_pool_%s_capacity_thin_in_use", Name: "thin"}, + {ID: "storage_pool_%s_capacity_snapshot", Name: "snapshot"}, + {ID: "storage_pool_%s_capacity_spare", Name: "spare"}, + {ID: "storage_pool_%s_capacity_unused", Name: "unused"}, + }, + }, + { + ID: "storage_pool_%s_capacity_utilization", + Title: "Capacity Utilization", + Units: "percentage", + Fam: "pool %s", + Ctx: "scaleio.storage_pool_capacity_utilization", + Dims: Dims{ + {ID: "storage_pool_%s_capacity_utilization", Name: "used", Div: 100}, + }, + Vars: Vars{ + {ID: "storage_pool_%s_capacity_alert_high_threshold"}, + {ID: "storage_pool_%s_capacity_alert_critical_threshold"}, + }, + }, + { + ID: "storage_pool_%s_capacity_available_volume_allocation", + Title: "Available For Volume Allocation", + Units: "KiB", + Fam: "pool %s", + Ctx: "scaleio.storage_pool_capacity_available_volume_allocation", + Dims: Dims{ + {ID: "storage_pool_%s_capacity_available_for_volume_allocation", Name: "available"}, + }, + }, + { + ID: "storage_pool_%s_capacity_health_state", + Title: "Capacity Health State", + Units: "KiB", + Fam: "pool %s", + Type: module.Stacked, + Ctx: "scaleio.storage_pool_capacity_health_state", + Dims: Dims{ + {ID: "storage_pool_%s_capacity_protected", Name: "protected"}, + {ID: "storage_pool_%s_capacity_degraded", Name: "degraded"}, + {ID: "storage_pool_%s_capacity_in_maintenance", Name: "in_maintenance"}, + {ID: "storage_pool_%s_capacity_failed", Name: "failed"}, + {ID: "storage_pool_%s_capacity_unreachable_unused", Name: "unavailable"}, + }, + }, + { + ID: "storage_pool_%s_components", + Title: "Components", + Units: "components", + Fam: "pool %s", + Ctx: "scaleio.storage_pool_components", + Dims: Dims{ + {ID: "storage_pool_%s_num_of_devices", Name: "devices"}, + {ID: "storage_pool_%s_num_of_snapshots", Name: "snapshots"}, + {ID: "storage_pool_%s_num_of_volumes", Name: "volumes"}, + {ID: "storage_pool_%s_num_of_vtrees", Name: "vtrees"}, + }, + }, +} + +func newStoragePoolCharts(pool client.StoragePool) *Charts { + charts := storagePoolCharts.Copy() + for i, chart := range *charts { + chart.ID = fmt.Sprintf(chart.ID, pool.ID) + chart.Fam = fmt.Sprintf(chart.Fam, pool.Name) + chart.Priority = prioStoragePool + i + for _, dim := range chart.Dims { + dim.ID = fmt.Sprintf(dim.ID, pool.ID) + } + for _, v := range chart.Vars { + v.ID = fmt.Sprintf(v.ID, pool.ID) + } + } + return charts +} + +var sdcCharts = Charts{ + { + ID: "sdc_%s_mdm_connection_state", + Title: "MDM Connection State", + Units: "boolean", + Fam: "sdc %s", + Ctx: "scaleio.sdc_mdm_connection_state", + Dims: Dims{ + {ID: "sdc_%s_mdm_connection_state", Name: "connected"}, + }, + }, + { + ID: "sdc_%s_bandwidth", + Title: "Bandwidth", + Units: "KiB/s", + Fam: "sdc %s", + Ctx: "scaleio.sdc_bandwidth", + Type: module.Area, + Dims: Dims{ + {ID: "sdc_%s_bandwidth_read", Name: "read", Div: 1000}, + {ID: "sdc_%s_bandwidth_write", Name: "write", Mul: -1, Div: 1000}, + }, + }, + { + ID: "sdc_%s_iops", + Title: "IOPS", + Units: "iops/s", + Fam: "sdc %s", + Ctx: "scaleio.sdc_iops", + Type: module.Area, + Dims: Dims{ + {ID: "sdc_%s_iops_read", Name: "read", Div: 1000}, + {ID: "sdc_%s_iops_write", Name: "write", Mul: -1, Div: 1000}, + }, + }, + { + ID: "sdc_%s_io_size", + Title: "I/O Size", + Units: "KiB", + Fam: "sdc %s", + Ctx: "scaleio.sdc_io_size", + Type: module.Area, + Dims: Dims{ + {ID: "sdc_%s_io_size_read", Name: "read", Div: 1000}, + {ID: "sdc_%s_io_size_write", Name: "write", Mul: -1, Div: 1000}, + }, + }, + { + ID: "sdc_%s_num_of_mapped_volumed", + Title: "Mapped Volumes", + Units: "volumes", + Fam: "sdc %s", + Ctx: "scaleio.sdc_num_of_mapped_volumed", + Dims: Dims{ + {ID: "sdc_%s_num_of_mapped_volumes", Name: "mapped"}, + }, + }, +} + +func newSdcCharts(sdc client.Sdc) *Charts { + charts := sdcCharts.Copy() + for i, chart := range *charts { + chart.ID = fmt.Sprintf(chart.ID, sdc.ID) + chart.Fam = fmt.Sprintf(chart.Fam, sdc.SdcIp) + chart.Priority = prioSdc + i + for _, dim := range chart.Dims { + dim.ID = fmt.Sprintf(dim.ID, sdc.ID) + } + } + return charts +} + +// TODO: remove stale charts? +func (s *ScaleIO) updateCharts() { + s.updateStoragePoolCharts() + s.updateSdcCharts() +} + +func (s *ScaleIO) updateStoragePoolCharts() { + for _, pool := range s.discovered.pool { + if s.charted[pool.ID] { + continue + } + s.charted[pool.ID] = true + s.addStoragePoolCharts(pool) + } +} + +func (s *ScaleIO) updateSdcCharts() { + for _, sdc := range s.discovered.sdc { + if s.charted[sdc.ID] { + continue + } + s.charted[sdc.ID] = true + s.addSdcCharts(sdc) + } +} + +func (s *ScaleIO) addStoragePoolCharts(pool client.StoragePool) { + charts := newStoragePoolCharts(pool) + if err := s.Charts().Add(*charts...); err != nil { + s.Warningf("couldn't add charts for storage pool '%s(%s)': %v", pool.ID, pool.Name, err) + } +} + +func (s *ScaleIO) addSdcCharts(sdc client.Sdc) { + charts := newSdcCharts(sdc) + if err := s.Charts().Add(*charts...); err != nil { + s.Warningf("couldn't add charts for sdc '%s(%s)': %v", sdc.ID, sdc.SdcIp, err) + } +} diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/client/client.go b/src/go/collectors/go.d.plugin/modules/scaleio/client/client.go new file mode 100644 index 000000000..e60dfbf68 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/client/client.go @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package client + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "path" + "strconv" + "strings" + "sync" + + "github.com/netdata/netdata/go/go.d.plugin/pkg/web" +) + +/* +The REST API is served from the VxFlex OS Gateway. +The FxFlex Gateway connects to a single MDM and serves requests by querying the MDM +and reformatting the answers it receives from the MDM in s RESTful manner, back to a REST API. +The Gateway is stateless. It requires the MDM username and password for the login requests. +The login returns a token in the response, that is used for later authentication for other requests. + +The token is valid for 8 hours from the time it was created, unless there has been no activity +for 10 minutes, of if the client has sent a logout request. + +General URI: +- /api/login +- /api/logout +- /api/version +- /api/instances/ // GET all instances +- /api/types/{type}/instances // POST (create) / GET all objects for a given type +- /api/instances/{type::id} // GET by ID +- /api/instances/{type::id}/relationships/{Relationship name} // GET +- /api/instances/querySelectedStatistics // POST Query selected statistics +- /api/instances/{type::id}/action/{actionName} // POST a special action on an object +- /api/types/{type}/instances/action/{actionName} // POST a special action on a given type + +Types: +- System +- Sds +- StoragePool +- ProtectionDomain +- Device +- Volume +- VTree +- Sdc +- User +- FaultSet +- RfcacheDevice +- Alerts + +Actions: +- querySelectedStatistics // All types except Alarm and User +- querySystemLimits // System +- queryDisconnectedSdss // Sds +- querySdsNetworkLatencyMeters // Sds +- queryFailedDevices" // Device. Note: works strange! + +Relationships: +- Statistics // All types except Alarm and User +- ProtectionDomain // System +- Sdc // System +- User // System +- StoragePool // ProtectionDomain +- FaultSet // ProtectionDomain +- Sds // ProtectionDomain +- RfcacheDevice // Sds +- Device // Sds, StoragePool +- Volume // Sdc, StoragePool +- VTree // StoragePool +*/ + +// New creates new ScaleIO client. +func New(client web.Client, request web.Request) (*Client, error) { + httpClient, err := web.NewHTTPClient(client) + if err != nil { + return nil, err + } + return &Client{ + Request: request, + httpClient: httpClient, + token: newToken(), + }, nil +} + +// Client represents ScaleIO client. +type Client struct { + Request web.Request + httpClient *http.Client + token *token +} + +// LoggedIn reports whether the client is logged in. +func (c *Client) LoggedIn() bool { + return c.token.isSet() +} + +// Login connects to FxFlex Gateway to get the token that is used for later authentication for other requests. +func (c *Client) Login() error { + if c.LoggedIn() { + _ = c.Logout() + } + req := c.createLoginRequest() + resp, err := c.doOK(req) + defer closeBody(resp) + if err != nil { + return err + } + + token, err := decodeToken(resp.Body) + if err != nil { + return err + } + + c.token.set(token) + return nil +} + +// Logout sends logout request and unsets token. +func (c *Client) Logout() error { + if !c.LoggedIn() { + return nil + } + req := c.createLogoutRequest() + c.token.unset() + + resp, err := c.do(req) + defer closeBody(resp) + return err +} + +// APIVersion returns FxFlex Gateway API version. +func (c *Client) APIVersion() (Version, error) { + req := c.createAPIVersionRequest() + resp, err := c.doOK(req) + defer closeBody(resp) + if err != nil { + return Version{}, err + } + return decodeVersion(resp.Body) +} + +// SelectedStatistics returns selected statistics. +func (c *Client) SelectedStatistics(query SelectedStatisticsQuery) (SelectedStatistics, error) { + b, _ := json.Marshal(query) + req := c.createSelectedStatisticsRequest(b) + var stats SelectedStatistics + err := c.doJSONWithRetry(&stats, req) + return stats, err +} + +// Instances returns all instances. +func (c *Client) Instances() (Instances, error) { + req := c.createInstancesRequest() + var instances Instances + err := c.doJSONWithRetry(&instances, req) + return instances, err +} + +func (c *Client) createLoginRequest() web.Request { + req := c.Request.Copy() + u, _ := url.Parse(req.URL) + u.Path = path.Join(u.Path, "/api/login") + req.URL = u.String() + return req +} + +func (c *Client) createLogoutRequest() web.Request { + req := c.Request.Copy() + u, _ := url.Parse(req.URL) + u.Path = path.Join(u.Path, "/api/logout") + req.URL = u.String() + req.Password = c.token.get() + return req +} + +func (c *Client) createAPIVersionRequest() web.Request { + req := c.Request.Copy() + u, _ := url.Parse(req.URL) + u.Path = path.Join(u.Path, "/api/version") + req.URL = u.String() + req.Password = c.token.get() + return req +} + +func (c *Client) createSelectedStatisticsRequest(query []byte) web.Request { + req := c.Request.Copy() + u, _ := url.Parse(req.URL) + u.Path = path.Join(u.Path, "/api/instances/querySelectedStatistics") + req.URL = u.String() + req.Password = c.token.get() + req.Method = http.MethodPost + req.Headers = map[string]string{ + "Content-Type": "application/json", + } + req.Body = string(query) + return req +} + +func (c *Client) createInstancesRequest() web.Request { + req := c.Request.Copy() + u, _ := url.Parse(req.URL) + u.Path = path.Join(u.Path, "/api/instances") + req.URL = u.String() + req.Password = c.token.get() + return req +} + +func (c *Client) do(req web.Request) (*http.Response, error) { + httpReq, err := web.NewHTTPRequest(req) + if err != nil { + return nil, fmt.Errorf("error on creating http request to %s: %v", req.URL, err) + } + return c.httpClient.Do(httpReq) +} + +func (c *Client) doOK(req web.Request) (*http.Response, error) { + resp, err := c.do(req) + if err != nil { + return nil, err + } + if err = checkStatusCode(resp); err != nil { + err = fmt.Errorf("%s returned %v", req.URL, err) + } + return resp, err +} + +func (c *Client) doOKWithRetry(req web.Request) (*http.Response, error) { + resp, err := c.do(req) + if err != nil { + return nil, err + } + if resp.StatusCode == http.StatusUnauthorized { + if err = c.Login(); err != nil { + return resp, err + } + req.Password = c.token.get() + return c.doOK(req) + } + if err = checkStatusCode(resp); err != nil { + err = fmt.Errorf("%s returned %v", req.URL, err) + } + return resp, err +} + +func (c *Client) doJSONWithRetry(dst interface{}, req web.Request) error { + resp, err := c.doOKWithRetry(req) + defer closeBody(resp) + if err != nil { + return err + } + return json.NewDecoder(resp.Body).Decode(dst) +} + +func closeBody(resp *http.Response) { + if resp != nil && resp.Body != nil { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + } +} + +func checkStatusCode(resp *http.Response) error { + // For all 4xx and 5xx return codes, the body may contain an apiError + // instance with more specifics about the failure. + if resp.StatusCode >= 400 { + e := error(&apiError{}) + if err := json.NewDecoder(resp.Body).Decode(e); err != nil { + e = err + } + return fmt.Errorf("HTTP status code %d : %v", resp.StatusCode, e) + } + + // 200(OK), 201(Created), 202(Accepted), 204 (No Content). + if resp.StatusCode < 200 || resp.StatusCode > 299 { + return fmt.Errorf("HTTP status code %d", resp.StatusCode) + } + return nil +} + +func decodeVersion(reader io.Reader) (ver Version, err error) { + bs, err := io.ReadAll(reader) + if err != nil { + return ver, err + } + parts := strings.Split(strings.Trim(string(bs), "\n "), ".") + if len(parts) != 2 { + return ver, fmt.Errorf("can't parse: %s", string(bs)) + } + if ver.Major, err = strconv.ParseInt(parts[0], 10, 64); err != nil { + return ver, err + } + ver.Minor, err = strconv.ParseInt(parts[1], 10, 64) + return ver, err +} + +func decodeToken(reader io.Reader) (string, error) { + bs, err := io.ReadAll(reader) + if err != nil { + return "", err + } + return strings.Trim(string(bs), `"`), nil +} + +type token struct { + mux *sync.RWMutex + value string +} + +func newToken() *token { return &token{mux: &sync.RWMutex{}} } +func (t *token) get() string { t.mux.RLock(); defer t.mux.RUnlock(); return t.value } +func (t *token) set(v string) { t.mux.Lock(); defer t.mux.Unlock(); t.value = v } +func (t *token) unset() { t.set("") } +func (t *token) isSet() bool { return t.get() != "" } diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/client/client_test.go b/src/go/collectors/go.d.plugin/modules/scaleio/client/client_test.go new file mode 100644 index 000000000..ea82814c2 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/client/client_test.go @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package client + +import ( + "net/http/httptest" + "testing" + + "github.com/netdata/netdata/go/go.d.plugin/pkg/web" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNew(t *testing.T) { + _, err := New(web.Client{}, web.Request{}) + assert.NoError(t, err) +} + +func TestClient_Login(t *testing.T) { + srv, client := prepareSrvClient(t) + defer srv.Close() + + assert.NoError(t, client.Login()) + assert.Equal(t, testToken, client.token.get()) +} + +func TestClient_Logout(t *testing.T) { + srv, client := prepareSrvClient(t) + defer srv.Close() + + require.NoError(t, client.Login()) + + assert.NoError(t, client.Logout()) + assert.False(t, client.token.isSet()) + +} + +func TestClient_LoggedIn(t *testing.T) { + srv, client := prepareSrvClient(t) + defer srv.Close() + + assert.False(t, client.LoggedIn()) + assert.NoError(t, client.Login()) + assert.True(t, client.LoggedIn()) +} + +func TestClient_APIVersion(t *testing.T) { + srv, client := prepareSrvClient(t) + defer srv.Close() + + err := client.Login() + require.NoError(t, err) + + version, err := client.APIVersion() + assert.NoError(t, err) + assert.Equal(t, Version{Major: 2, Minor: 5}, version) +} + +func TestClient_Instances(t *testing.T) { + srv, client := prepareSrvClient(t) + defer srv.Close() + + err := client.Login() + require.NoError(t, err) + + instances, err := client.Instances() + assert.NoError(t, err) + assert.Equal(t, testInstances, instances) +} + +func TestClient_Instances_RetryOnExpiredToken(t *testing.T) { + srv, client := prepareSrvClient(t) + defer srv.Close() + + instances, err := client.Instances() + assert.NoError(t, err) + assert.Equal(t, testInstances, instances) +} + +func TestClient_SelectedStatistics(t *testing.T) { + srv, client := prepareSrvClient(t) + defer srv.Close() + + err := client.Login() + require.NoError(t, err) + + stats, err := client.SelectedStatistics(SelectedStatisticsQuery{}) + assert.NoError(t, err) + assert.Equal(t, testStatistics, stats) +} + +func TestClient_SelectedStatistics_RetryOnExpiredToken(t *testing.T) { + srv, client := prepareSrvClient(t) + defer srv.Close() + + stats, err := client.SelectedStatistics(SelectedStatisticsQuery{}) + assert.Equal(t, testStatistics, stats) + assert.NoError(t, err) + assert.Equal(t, testStatistics, stats) +} + +func prepareSrvClient(t *testing.T) (*httptest.Server, *Client) { + t.Helper() + srv := httptest.NewServer(MockScaleIOAPIServer{ + User: testUser, + Password: testPassword, + Version: testVersion, + Token: testToken, + Instances: testInstances, + Statistics: testStatistics, + }) + client, err := New(web.Client{}, web.Request{ + URL: srv.URL, + Username: testUser, + Password: testPassword, + }) + assert.NoError(t, err) + return srv, client +} + +var ( + testUser = "user" + testPassword = "password" + testVersion = "2.5" + testToken = "token" + testInstances = Instances{ + StoragePoolList: []StoragePool{ + {ID: "id1", Name: "Marketing", SparePercentage: 10}, + {ID: "id2", Name: "Finance", SparePercentage: 10}, + }, + SdcList: []Sdc{ + {ID: "id1", SdcIp: "10.0.0.1", MdmConnectionState: "Connected"}, + {ID: "id2", SdcIp: "10.0.0.2", MdmConnectionState: "Connected"}, + }, + } + testStatistics = SelectedStatistics{ + System: SystemStatistics{NumOfDevices: 1}, + Sdc: map[string]SdcStatistics{"id1": {}, "id2": {}}, + StoragePool: map[string]StoragePoolStatistics{"id1": {}, "id2": {}}, + } +) diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/client/server.go b/src/go/collectors/go.d.plugin/modules/scaleio/client/server.go new file mode 100644 index 000000000..b7269d339 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/client/server.go @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package client + +import ( + "encoding/json" + "fmt" + "io" + "net/http" +) + +// MockScaleIOAPIServer represents VxFlex OS Gateway. +type MockScaleIOAPIServer struct { + User string + Password string + Token string + Version string + Instances Instances + Statistics SelectedStatistics +} + +func (s MockScaleIOAPIServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + default: + w.WriteHeader(http.StatusNotFound) + msg := fmt.Sprintf("unknown URL path: %s", r.URL.Path) + writeAPIError(w, msg) + case "/api/login": + s.handleLogin(w, r) + case "/api/logout": + s.handleLogout(w, r) + case "/api/version": + s.handleVersion(w, r) + case "/api/instances": + s.handleInstances(w, r) + case "/api/instances/querySelectedStatistics": + s.handleQuerySelectedStatistics(w, r) + } +} + +func (s MockScaleIOAPIServer) handleLogin(w http.ResponseWriter, r *http.Request) { + if user, pass, ok := r.BasicAuth(); !ok || user != s.User || pass != s.Password { + w.WriteHeader(http.StatusUnauthorized) + msg := fmt.Sprintf("user got/expected: %s/%s, pass got/expected: %s/%s", user, s.User, pass, s.Password) + writeAPIError(w, msg) + return + } + if r.Method != http.MethodGet { + w.WriteHeader(http.StatusBadRequest) + msg := fmt.Sprintf("wrong method: '%s', expected '%s'", r.Method, http.MethodGet) + writeAPIError(w, msg) + return + } + _, _ = w.Write([]byte(s.Token)) +} + +func (s MockScaleIOAPIServer) handleLogout(w http.ResponseWriter, r *http.Request) { + if _, pass, ok := r.BasicAuth(); !ok || pass != s.Token { + w.WriteHeader(http.StatusUnauthorized) + msg := fmt.Sprintf("token got/expected: %s/%s", pass, s.Token) + writeAPIError(w, msg) + return + } + if r.Method != http.MethodGet { + w.WriteHeader(http.StatusBadRequest) + msg := fmt.Sprintf("wrong method: '%s', expected '%s'", r.Method, http.MethodGet) + writeAPIError(w, msg) + return + } +} + +func (s MockScaleIOAPIServer) handleVersion(w http.ResponseWriter, r *http.Request) { + if _, pass, ok := r.BasicAuth(); !ok || pass != s.Token { + w.WriteHeader(http.StatusUnauthorized) + msg := fmt.Sprintf("token got/expected: %s/%s", pass, s.Token) + writeAPIError(w, msg) + return + } + if r.Method != http.MethodGet { + w.WriteHeader(http.StatusBadRequest) + msg := fmt.Sprintf("wrong method: '%s', expected '%s'", r.Method, http.MethodGet) + writeAPIError(w, msg) + return + } + _, _ = w.Write([]byte(s.Version)) +} + +func (s MockScaleIOAPIServer) handleInstances(w http.ResponseWriter, r *http.Request) { + if _, pass, ok := r.BasicAuth(); !ok || pass != s.Token { + w.WriteHeader(http.StatusUnauthorized) + msg := fmt.Sprintf("token got/expected: %s/%s", pass, s.Token) + writeAPIError(w, msg) + return + } + if r.Method != http.MethodGet { + w.WriteHeader(http.StatusBadRequest) + msg := fmt.Sprintf("wrong method: '%s', expected '%s'", r.Method, http.MethodGet) + writeAPIError(w, msg) + return + } + b, err := json.Marshal(s.Instances) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + msg := fmt.Sprintf("marshal Instances: %v", err) + writeAPIError(w, msg) + return + } + _, _ = w.Write(b) +} + +func (s MockScaleIOAPIServer) handleQuerySelectedStatistics(w http.ResponseWriter, r *http.Request) { + if _, pass, ok := r.BasicAuth(); !ok || pass != s.Token { + w.WriteHeader(http.StatusUnauthorized) + msg := fmt.Sprintf("token got/expected: %s/%s", pass, s.Token) + writeAPIError(w, msg) + return + } + if r.Method != http.MethodPost { + w.WriteHeader(http.StatusBadRequest) + msg := fmt.Sprintf("wrong method: '%s', expected '%s'", r.Method, http.MethodPost) + writeAPIError(w, msg) + return + } + if r.Header.Get("Content-Type") != "application/json" { + w.WriteHeader(http.StatusBadRequest) + writeAPIError(w, "no \"Content-Type: application/json\" in the header") + return + } + if err := json.NewDecoder(r.Body).Decode(&SelectedStatisticsQuery{}); err != nil { + w.WriteHeader(http.StatusBadRequest) + msg := fmt.Sprintf("body decode error: %v", err) + writeAPIError(w, msg) + return + } + b, err := json.Marshal(s.Statistics) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + msg := fmt.Sprintf("marshal SelectedStatistics: %v", err) + writeAPIError(w, msg) + return + } + _, _ = w.Write(b) +} + +func writeAPIError(w io.Writer, msg string) { + err := apiError{Message: msg} + b, _ := json.Marshal(err) + _, _ = w.Write(b) +} diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/client/types.go b/src/go/collectors/go.d.plugin/modules/scaleio/client/types.go new file mode 100644 index 000000000..c85bddf8d --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/client/types.go @@ -0,0 +1,1096 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package client + +// https://github.com/dell/goscaleio/blob/master/types/v1/types.go + +// For all 4xx and 5xx return codes, the body may contain an apiError instance +// with more specifics about the failure. +type apiError struct { + Message string + HTTPStatusCode int + ErrorCode int +} + +func (e apiError) Error() string { + return e.Message +} + +// Version represents API version. +type Version struct { + Major int64 + Minor int64 +} + +// Bwc Bwc. +type Bwc struct { + NumOccured int64 + NumSeconds int64 + TotalWeightInKb int64 +} + +// Sdc represents ScaleIO Data Client. +type Sdc struct { + ID string + SdcIp string + MdmConnectionState string +} + +// StoragePool represents ScaleIO Storage Pool. +type StoragePool struct { + ID string + Name string + SparePercentage int64 + CapacityAlertCriticalThreshold int64 + CapacityAlertHighThreshold int64 +} + +// Instances represents '/api/instances' response. +type Instances struct { + StoragePoolList []StoragePool + SdcList []Sdc +} + +type ( + // SelectedStatisticsQuery represents '/api/instances/querySelectedStatistics' query. + SelectedStatisticsQuery struct { + List []SelectedObject `json:"selectedStatisticsList"` + } + // SelectedObject represents '/api/instances/querySelectedStatistics' query object. + SelectedObject struct { + Type string `json:"type"` // object type (System, ProtectionDomain, Sds, StoragePool, Device, Volume, VTree, Sdc, FaultSet, RfcacheDevice). + + // the following parameters are not relevant to the System type and can be omitted: + IDs []string `json:"ids,omitempty"` // list of objects ids + AllIDs allIds `json:"allIds,omitempty"` // all available objects + + Properties []string `json:"properties"` // list of properties to fetch + } + allIds bool +) + +func (b allIds) MarshalJSON() ([]byte, error) { + // should be set to empty value if AllIDs is true. + if b { + return []byte("[]"), nil + } + return nil, nil +} +func (b *allIds) UnmarshalJSON([]byte) error { + *b = true + return nil +} + +// SelectedStatistics represents '/api/instances/querySelectedStatistics' response. +type SelectedStatistics struct { + System SystemStatistics + Sdc map[string]SdcStatistics + StoragePool map[string]StoragePoolStatistics +} + +// Those commented out structure fields are not deleted on purpose. We need them to see what other metrics can be collected. +type ( + // CapacityStatistics is System/StoragePool capacity statistics. + CapacityStatistics struct { + CapacityAvailableForVolumeAllocationInKb int64 + MaxCapacityInKb int64 + CapacityLimitInKb int64 + ProtectedCapacityInKb int64 + DegradedFailedCapacityInKb int64 + DegradedHealthyCapacityInKb int64 + SpareCapacityInKb int64 + FailedCapacityInKb int64 + UnreachableUnusedCapacityInKb int64 + InMaintenanceCapacityInKb int64 + ThinCapacityAllocatedInKb int64 + ThinCapacityInUseInKb int64 + ThickCapacityInUseInKb int64 + SnapCapacityInUseOccupiedInKb int64 + CapacityInUseInKb int64 + } + SystemStatistics struct { + CapacityStatistics + + NumOfDevices int64 + NumOfFaultSets int64 + NumOfProtectionDomains int64 + NumOfRfcacheDevices int64 + NumOfSdc int64 + NumOfSds int64 + NumOfSnapshots int64 + NumOfStoragePools int64 + NumOfVolumes int64 + NumOfVtrees int64 + NumOfThickBaseVolumes int64 + NumOfThinBaseVolumes int64 + NumOfMappedToAllVolumes int64 + NumOfUnmappedVolumes int64 + + RebalanceReadBwc Bwc + RebalanceWriteBwc Bwc + PendingRebalanceCapacityInKb int64 + + PendingNormRebuildCapacityInKb int64 + PendingBckRebuildCapacityInKb int64 + PendingFwdRebuildCapacityInKb int64 + NormRebuildReadBwc Bwc // TODO: ??? + NormRebuildWriteBwc Bwc // TODO: ??? + BckRebuildReadBwc Bwc // failed node/disk is back alive + BckRebuildWriteBwc Bwc // failed node/disk is back alive + FwdRebuildReadBwc Bwc // node/disk fails + FwdRebuildWriteBwc Bwc // node/disk fails + + PrimaryReadBwc Bwc // Backend (SDSs + Devices) Primary - Mater MDM + PrimaryWriteBwc Bwc // Backend (SDSs + Devices) Primary - Mater MDM + SecondaryReadBwc Bwc // Backend (SDSs + Devices, 2nd) Secondary - Slave MDM + SecondaryWriteBwc Bwc // Backend (SDSs + Devices, 2nd) Secondary - Slave MDM + UserDataReadBwc Bwc // Frontend (Volumes + SDCs) + UserDataWriteBwc Bwc // Frontend (Volumes + SDCs) + TotalReadBwc Bwc // *ReadBwc + TotalWriteBwc Bwc // *WriteBwc + + //SnapCapacityInUseInKb int64 + //BackgroundScanCompareCount int64 + //BackgroundScannedInMB int64 + //ActiveBckRebuildCapacityInKb int64 + //ActiveFwdRebuildCapacityInKb int64 + //ActiveMovingCapacityInKb int64 + //ActiveMovingInBckRebuildJobs int64 + //ActiveMovingInFwdRebuildJobs int64 + //ActiveMovingInNormRebuildJobs int64 + //ActiveMovingInRebalanceJobs int64 + //ActiveMovingOutBckRebuildJobs int64 + //ActiveMovingOutFwdRebuildJobs int64 + //ActiveMovingOutNormRebuildJobs int64 + //ActiveMovingRebalanceJobs int64 + //ActiveNormRebuildCapacityInKb int64 + //ActiveRebalanceCapacityInKb int64 + //AtRestCapacityInKb int64 + //BckRebuildCapacityInKb int64 + //DegradedFailedVacInKb int64 + //DegradedHealthyVacInKb int64 + //FailedVacInKb int64 + //FixedReadErrorCount int64 + //FwdRebuildCapacityInKb int64 + //InMaintenanceVacInKb int64 + //InUseVacInKb int64 + //MovingCapacityInKb int64 + //NormRebuildCapacityInKb int64 + //NumOfScsiInitiators int64 // removed from version 3 of ScaleIO/VxFlex API + //PendingMovingCapacityInKb int64 + //PendingMovingInBckRebuildJobs int64 + //PendingMovingInFwdRebuildJobs int64 + //PendingMovingInNormRebuildJobs int64 + //PendingMovingInRebalanceJobs int64 + //PendingMovingOutBckRebuildJobs int64 + //PendingMovingOutFwdRebuildJobs int64 + //PendingMovingOutNormrebuildJobs int64 + //PendingMovingRebalanceJobs int64 + //PrimaryReadFromDevBwc int64 + //PrimaryReadFromRmcacheBwc int64 + //PrimaryVacInKb int64 + //ProtectedVacInKb int64 + //ProtectionDomainIds int64 + //RebalanceCapacityInKb int64 + //RebalancePerReceiveJobNetThrottlingInKbps int64 + //RebalanceWaitSendQLength int64 + //RebuildPerReceiveJobNetThrottlingInKbps int64 + //RebuildWaitSendQLength int64 + //RfacheReadHit int64 + //RfacheWriteHit int64 + //RfcacheAvgReadTime int64 + //RfcacheAvgWriteTime int64 + //RfcacheFdAvgReadTime int64 + //RfcacheFdAvgWriteTime int64 + //RfcacheFdCacheOverloaded int64 + //RfcacheFdInlightReads int64 + //RfcacheFdInlightWrites int64 + //RfcacheFdIoErrors int64 + //RfcacheFdMonitorErrorStuckIo int64 + //RfcacheFdReadTimeGreater1Min int64 + //RfcacheFdReadTimeGreater1Sec int64 + //RfcacheFdReadTimeGreater500Millis int64 + //RfcacheFdReadTimeGreater5Sec int64 + //RfcacheFdReadsReceived int64 + //RfcacheFdWriteTimeGreater1Min int64 + //RfcacheFdWriteTimeGreater1Sec int64 + //RfcacheFdWriteTimeGreater500Millis int64 + //RfcacheFdWriteTimeGreater5Sec int64 + //RfcacheFdWritesReceived int64 + //RfcacheIoErrors int64 + //RfcacheIosOutstanding int64 + //RfcacheIosSkipped int64 + //RfcachePooIosOutstanding int64 + //RfcachePoolCachePages int64 + //RfcachePoolEvictions int64 + //RfcachePoolInLowMemoryCondition int64 + //RfcachePoolIoTimeGreater1Min int64 + //RfcachePoolLockTimeGreater1Sec int64 + //RfcachePoolLowResourcesInitiatedPassthroughMode int64 + //RfcachePoolNumCacheDevs int64 + //RfcachePoolNumSrcDevs int64 + //RfcachePoolPagesInuse int64 + //RfcachePoolReadHit int64 + //RfcachePoolReadMiss int64 + //RfcachePoolReadPendingG10Millis int64 + //RfcachePoolReadPendingG1Millis int64 + //RfcachePoolReadPendingG1Sec int64 + //RfcachePoolReadPendingG500Micro int64 + //RfcachePoolReadsPending int64 + //RfcachePoolSize int64 + //RfcachePoolSourceIdMismatch int64 + //RfcachePoolSuspendedIos int64 + //RfcachePoolSuspendedPequestsRedundantSearchs int64 + //RfcachePoolWriteHit int64 + //RfcachePoolWriteMiss int64 + //RfcachePoolWritePending int64 + //RfcachePoolWritePendingG10Millis int64 + //RfcachePoolWritePendingG1Millis int64 + //RfcachePoolWritePendingG1Sec int64 + //RfcachePoolWritePendingG500Micro int64 + //RfcacheReadMiss int64 + //RfcacheReadsFromCache int64 + //RfcacheReadsPending int64 + //RfcacheReadsReceived int64 + //RfcacheReadsSkipped int64 + //RfcacheReadsSkippedAlignedSizeTooLarge int64 + //RfcacheReadsSkippedHeavyLoad int64 + //RfcacheReadsSkippedInternalError int64 + //RfcacheReadsSkippedLockIos int64 + //RfcacheReadsSkippedLowResources int64 + //RfcacheReadsSkippedMaxIoSize int64 + //RfcacheReadsSkippedStuckIo int64 + //RfcacheSkippedUnlinedWrite int64 + //RfcacheSourceDeviceReads int64 + //RfcacheSourceDeviceWrites int64 + //RfcacheWriteMiss int64 + //RfcacheWritePending int64 + //RfcacheWritesReceived int64 + //RfcacheWritesSkippedCacheMiss int64 + //RfcacheWritesSkippedHeavyLoad int64 + //RfcacheWritesSkippedInternalError int64 + //RfcacheWritesSkippedLowResources int64 + //RfcacheWritesSkippedMaxIoSize int64 + //RfcacheWritesSkippedStuckIo int64 + //RmPendingAllocatedInKb int64 + //Rmcache128kbEntryCount int64 + //Rmcache16kbEntryCount int64 + //Rmcache32kbEntryCount int64 + //Rmcache4kbEntryCount int64 + //Rmcache64kbEntryCount int64 + //Rmcache8kbEntryCount int64 + //RmcacheBigBlockEvictionCount int64 + //RmcacheBigBlockEvictionSizeCountInKb int64 + //RmcacheCurrNumOf128kbEntries int64 + //RmcacheCurrNumOf16kbEntries int64 + //RmcacheCurrNumOf32kbEntries int64 + //RmcacheCurrNumOf4kbEntries int64 + //RmcacheCurrNumOf64kbEntries int64 + //RmcacheCurrNumOf8kbEntries int64 + //RmcacheEntryEvictionCount int64 + //RmcacheEntryEvictionSizeCountInKb int64 + //RmcacheNoEvictionCount int64 + //RmcacheSizeInKb int64 + //RmcacheSizeInUseInKb int64 + //RmcacheSkipCountCacheAllBusy int64 + //RmcacheSkipCountLargeIo int64 + //RmcacheSkipCountUnaligned4kbIo int64 + //ScsiInitiatorIds int64 + //SdcIds int64 + //SecondaryReadFromDevBwc int64 + //SecondaryReadFromRmcacheBwc int64 + //SecondaryVacInKb int64 + //SemiProtectedCapacityInKb int64 + //SemiProtectedVacInKb int64 + //SnapCapacityInUseOccupiedInKb int64 + //UnusedCapacityInKb int64 + } + SdcStatistics struct { + NumOfMappedVolumes int64 + UserDataReadBwc Bwc + UserDataWriteBwc Bwc + //VolumeIds int64 + } + StoragePoolStatistics struct { + CapacityStatistics + + NumOfDevices int64 + NumOfVolumes int64 + NumOfVtrees int64 + NumOfSnapshots int64 + + //SnapCapacityInUseInKb int64 + //BackgroundScanCompareCount int64 + //BackgroundScannedInMB int64 + //ActiveBckRebuildCapacityInKb int64 + //ActiveFwdRebuildCapacityInKb int64 + //ActiveMovingCapacityInKb int64 + //ActiveMovingInBckRebuildJobs int64 + //ActiveMovingInFwdRebuildJobs int64 + //ActiveMovingInNormRebuildJobs int64 + //ActiveMovingInRebalanceJobs int64 + //ActiveMovingOutBckRebuildJobs int64 + //ActiveMovingOutFwdRebuildJobs int64 + //ActiveMovingOutNormRebuildJobs int64 + //ActiveMovingRebalanceJobs int64 + //ActiveNormRebuildCapacityInKb int64 + //ActiveRebalanceCapacityInKb int64 + //AtRestCapacityInKb int64 + //BckRebuildCapacityInKb int64 + //BckRebuildReadBwc int64 + //BckRebuildWriteBwc int64 + //DegradedFailedVacInKb int64 + //DegradedHealthyVacInKb int64 + //DeviceIds int64 + //FailedVacInKb int64 + //FixedReadErrorCount int64 + //FwdRebuildCapacityInKb int64 + //FwdRebuildReadBwc int64 + //FwdRebuildWriteBwc int64 + //InMaintenanceVacInKb int64 + //InUseVacInKb int64 + //MovingCapacityInKb int64 + //NormRebuildCapacityInKb int64 + //NormRebuildReadBwc int64 + //NormRebuildWriteBwc int64 + //NumOfMappedToAllVolumes int64 + //NumOfThickBaseVolumes int64 + //NumOfThinBaseVolumes int64 + //NumOfUnmappedVolumes int64 + //NumOfVolumesInDeletion int64 + //PendingBckRebuildCapacityInKb int64 + //PendingFwdRebuildCapacityInKb int64 + //PendingMovingCapacityInKb int64 + //PendingMovingInBckRebuildJobs int64 + //PendingMovingInFwdRebuildJobs int64 + //PendingMovingInNormRebuildJobs int64 + //PendingMovingInRebalanceJobs int64 + //PendingMovingOutBckRebuildJobs int64 + //PendingMovingOutFwdRebuildJobs int64 + //PendingMovingOutNormrebuildJobs int64 + //PendingMovingRebalanceJobs int64 + //PendingNormRebuildCapacityInKb int64 + //PendingRebalanceCapacityInKb int64 + //PrimaryReadBwc int64 + //PrimaryReadFromDevBwc int64 + //PrimaryReadFromRmcacheBwc int64 + //PrimaryVacInKb int64 + //PrimaryWriteBwc int64 + //ProtectedVacInKb int64 + //RebalanceCapacityInKb int64 + //RebalanceReadBwc int64 + //RebalanceWriteBwc int64 + //RfacheReadHit int64 + //RfacheWriteHit int64 + //RfcacheAvgReadTime int64 + //RfcacheAvgWriteTime int64 + //RfcacheIoErrors int64 + //RfcacheIosOutstanding int64 + //RfcacheIosSkipped int64 + //RfcacheReadMiss int64 + //RfcacheReadsFromCache int64 + //RfcacheReadsPending int64 + //RfcacheReadsReceived int64 + //RfcacheReadsSkipped int64 + //RfcacheReadsSkippedAlignedSizeTooLarge int64 + //RfcacheReadsSkippedHeavyLoad int64 + //RfcacheReadsSkippedInternalError int64 + //RfcacheReadsSkippedLockIos int64 + //RfcacheReadsSkippedLowResources int64 + //RfcacheReadsSkippedMaxIoSize int64 + //RfcacheReadsSkippedStuckIo int64 + //RfcacheSkippedUnlinedWrite int64 + //RfcacheSourceDeviceReads int64 + //RfcacheSourceDeviceWrites int64 + //RfcacheWriteMiss int64 + //RfcacheWritePending int64 + //RfcacheWritesReceived int64 + //RfcacheWritesSkippedCacheMiss int64 + //RfcacheWritesSkippedHeavyLoad int64 + //RfcacheWritesSkippedInternalError int64 + //RfcacheWritesSkippedLowResources int64 + //RfcacheWritesSkippedMaxIoSize int64 + //RfcacheWritesSkippedStuckIo int64 + //RmPendingAllocatedInKb int64 + //SecondaryReadBwc int64 + //SecondaryReadFromDevBwc int64 + //SecondaryReadFromRmcacheBwc int64 + //SecondaryVacInKb int64 + //SecondaryWriteBwc int64 + //SemiProtectedCapacityInKb int64 + //SemiProtectedVacInKb int64 + //SnapCapacityInUseOccupiedInKb int64 + //TotalReadBwc int64 + //TotalWriteBwc int64 + //UnusedCapacityInKb int64 + //UserDataReadBwc int64 + //UserDataWriteBwc int64 + //VolumeIds int64 + //VtreeIds int64 + } + DeviceStatistic struct { + // BackgroundScanCompareCount int64 + // BackgroundScannedInMB int64 + // ActiveMovingInBckRebuildJobs int64 + // ActiveMovingInFwdRebuildJobs int64 + // ActiveMovingInNormRebuildJobs int64 + // ActiveMovingInRebalanceJobs int64 + // ActiveMovingOutBckRebuildJobs int64 + // ActiveMovingOutFwdRebuildJobs int64 + // ActiveMovingOutNormRebuildJobs int64 + // ActiveMovingRebalanceJobs int64 + // AvgReadLatencyInMicrosec int64 + // AvgReadSizeInBytes int64 + // AvgWriteLatencyInMicrosec int64 + // AvgWriteSizeInBytes int64 + // BckRebuildReadBwc int64 + // BckRebuildWriteBwc int64 + // CapacityInUseInKb int64 + // CapacityLimitInKb int64 + // DegradedFailedVacInKb int64 + // DegradedHealthyVacInKb int64 + // FailedVacInKb int64 + // FixedReadErrorCount int64 + // FwdRebuildReadBwc int64 + // FwdRebuildWriteBwc int64 + // InMaintenanceVacInKb int64 + // InUseVacInKb int64 + // MaxCapacityInKb int64 + // NormRebuildReadBwc int64 + // NormRebuildWriteBwc int64 + // PendingMovingInBckRebuildJobs int64 + // PendingMovingInFwdRebuildJobs int64 + // PendingMovingInNormRebuildJobs int64 + // PendingMovingInRebalanceJobs int64 + // PendingMovingOutBckRebuildJobs int64 + // PendingMovingOutFwdRebuildJobs int64 + // PendingMovingOutNormrebuildJobs int64 + // PendingMovingRebalanceJobs int64 + // PrimaryReadBwc int64 + // PrimaryReadFromDevBwc int64 + // PrimaryReadFromRmcacheBwc int64 + // PrimaryVacInKb int64 + // PrimaryWriteBwc int64 + // ProtectedVacInKb int64 + // RebalanceReadBwc int64 + // RebalanceWriteBwc int64 + // RfacheReadHit int64 + // RfacheWriteHit int64 + // RfcacheAvgReadTime int64 + // RfcacheAvgWriteTime int64 + // RfcacheIoErrors int64 + // RfcacheIosOutstanding int64 + // RfcacheIosSkipped int64 + // RfcacheReadMiss int64 + // RfcacheReadsFromCache int64 + // RfcacheReadsPending int64 + // RfcacheReadsReceived int64 + // RfcacheReadsSkipped int64 + // RfcacheReadsSkippedAlignedSizeTooLarge int64 + // RfcacheReadsSkippedHeavyLoad int64 + // RfcacheReadsSkippedInternalError int64 + // RfcacheReadsSkippedLockIos int64 + // RfcacheReadsSkippedLowResources int64 + // RfcacheReadsSkippedMaxIoSize int64 + // RfcacheReadsSkippedStuckIo int64 + // RfcacheSkippedUnlinedWrite int64 + // RfcacheSourceDeviceReads int64 + // RfcacheSourceDeviceWrites int64 + // RfcacheWriteMiss int64 + // RfcacheWritePending int64 + // RfcacheWritesReceived int64 + // RfcacheWritesSkippedCacheMiss int64 + // RfcacheWritesSkippedHeavyLoad int64 + // RfcacheWritesSkippedInternalError int64 + // RfcacheWritesSkippedLowResources int64 + // RfcacheWritesSkippedMaxIoSize int64 + // RfcacheWritesSkippedStuckIo int64 + // RmPendingAllocatedInKb int64 + // SecondaryReadBwc int64 + // SecondaryReadFromDevBwc int64 + // SecondaryReadFromRmcacheBwc int64 + // SecondaryVacInKb int64 + // SecondaryWriteBwc int64 + // SemiProtectedVacInKb int64 + // SnapCapacityInUseInKb int64 + // SnapCapacityInUseOccupiedInKb int64 + // ThickCapacityInUseInKb int64 + // ThinCapacityAllocatedInKb int64 + // ThinCapacityInUseInKb int64 + // TotalReadBwc int64 + // TotalWriteBwc int64 + // UnreachableUnusedCapacityInKb int64 + // UnusedCapacityInKb int64 + } + FaultSetStatistics struct { + // BackgroundScanCompareCount int64 + // BackgroundScannedInMB int64 + // ActiveMovingInBckRebuildJobs int64 + // ActiveMovingInFwdRebuildJobs int64 + // ActiveMovingInNormRebuildJobs int64 + // ActiveMovingInRebalanceJobs int64 + // ActiveMovingOutBckRebuildJobs int64 + // ActiveMovingOutFwdRebuildJobs int64 + // ActiveMovingOutNormRebuildJobs int64 + // ActiveMovingRebalanceJobs int64 + // BckRebuildReadBwc int64 + // BckRebuildWriteBwc int64 + // CapacityInUseInKb int64 + // CapacityLimitInKb int64 + // DegradedFailedVacInKb int64 + // DegradedHealthyVacInKb int64 + // FailedVacInKb int64 + // FixedReadErrorCount int64 + // FwdRebuildReadBwc int64 + // FwdRebuildWriteBwc int64 + // InMaintenanceVacInKb int64 + // InUseVacInKb int64 + // MaxCapacityInKb int64 + // NormRebuildReadBwc int64 + // NormRebuildWriteBwc int64 + // NumOfSds int64 + // PendingMovingInBckRebuildJobs int64 + // PendingMovingInFwdRebuildJobs int64 + // PendingMovingInNormRebuildJobs int64 + // PendingMovingInRebalanceJobs int64 + // PendingMovingOutBckRebuildJobs int64 + // PendingMovingOutFwdRebuildJobs int64 + // PendingMovingOutNormrebuildJobs int64 + // PendingMovingRebalanceJobs int64 + // PrimaryReadBwc int64 + // PrimaryReadFromDevBwc int64 + // PrimaryReadFromRmcacheBwc int64 + // PrimaryVacInKb int64 + // PrimaryWriteBwc int64 + // ProtectedVacInKb int64 + // RebalancePerReceiveJobNetThrottlingInKbps int64 + // RebalanceReadBwc int64 + // RebalanceWaitSendQLength int64 + // RebalanceWriteBwc int64 + // RebuildPerReceiveJobNetThrottlingInKbps int64 + // RebuildWaitSendQLength int64 + // RfacheReadHit int64 + // RfacheWriteHit int64 + // RfcacheAvgReadTime int64 + // RfcacheAvgWriteTime int64 + // RfcacheFdAvgReadTime int64 + // RfcacheFdAvgWriteTime int64 + // RfcacheFdCacheOverloaded int64 + // RfcacheFdInlightReads int64 + // RfcacheFdInlightWrites int64 + // RfcacheFdIoErrors int64 + // RfcacheFdMonitorErrorStuckIo int64 + // RfcacheFdReadTimeGreater1Min int64 + // RfcacheFdReadTimeGreater1Sec int64 + // RfcacheFdReadTimeGreater500Millis int64 + // RfcacheFdReadTimeGreater5Sec int64 + // RfcacheFdReadsReceived int64 + // RfcacheFdWriteTimeGreater1Min int64 + // RfcacheFdWriteTimeGreater1Sec int64 + // RfcacheFdWriteTimeGreater500Millis int64 + // RfcacheFdWriteTimeGreater5Sec int64 + // RfcacheFdWritesReceived int64 + // RfcacheIoErrors int64 + // RfcacheIosOutstanding int64 + // RfcacheIosSkipped int64 + // RfcachePooIosOutstanding int64 + // RfcachePoolCachePages int64 + // RfcachePoolEvictions int64 + // RfcachePoolInLowMemoryCondition int64 + // RfcachePoolIoTimeGreater1Min int64 + // RfcachePoolLockTimeGreater1Sec int64 + // RfcachePoolLowResourcesInitiatedPassthroughMode int64 + // RfcachePoolNumCacheDevs int64 + // RfcachePoolNumSrcDevs int64 + // RfcachePoolPagesInuse int64 + // RfcachePoolReadHit int64 + // RfcachePoolReadMiss int64 + // RfcachePoolReadPendingG10Millis int64 + // RfcachePoolReadPendingG1Millis int64 + // RfcachePoolReadPendingG1Sec int64 + // RfcachePoolReadPendingG500Micro int64 + // RfcachePoolReadsPending int64 + // RfcachePoolSize int64 + // RfcachePoolSourceIdMismatch int64 + // RfcachePoolSuspendedIos int64 + // RfcachePoolSuspendedPequestsRedundantSearchs int64 + // RfcachePoolWriteHit int64 + // RfcachePoolWriteMiss int64 + // RfcachePoolWritePending int64 + // RfcachePoolWritePendingG10Millis int64 + // RfcachePoolWritePendingG1Millis int64 + // RfcachePoolWritePendingG1Sec int64 + // RfcachePoolWritePendingG500Micro int64 + // RfcacheReadMiss int64 + // RfcacheReadsFromCache int64 + // RfcacheReadsPending int64 + // RfcacheReadsReceived int64 + // RfcacheReadsSkipped int64 + // RfcacheReadsSkippedAlignedSizeTooLarge int64 + // RfcacheReadsSkippedHeavyLoad int64 + // RfcacheReadsSkippedInternalError int64 + // RfcacheReadsSkippedLockIos int64 + // RfcacheReadsSkippedLowResources int64 + // RfcacheReadsSkippedMaxIoSize int64 + // RfcacheReadsSkippedStuckIo int64 + // RfcacheSkippedUnlinedWrite int64 + // RfcacheSourceDeviceReads int64 + // RfcacheSourceDeviceWrites int64 + // RfcacheWriteMiss int64 + // RfcacheWritePending int64 + // RfcacheWritesReceived int64 + // RfcacheWritesSkippedCacheMiss int64 + // RfcacheWritesSkippedHeavyLoad int64 + // RfcacheWritesSkippedInternalError int64 + // RfcacheWritesSkippedLowResources int64 + // RfcacheWritesSkippedMaxIoSize int64 + // RfcacheWritesSkippedStuckIo int64 + // RmPendingAllocatedInKb int64 + // Rmcache128kbEntryCount int64 + // Rmcache16kbEntryCount int64 + // Rmcache32kbEntryCount int64 + // Rmcache4kbEntryCount int64 + // Rmcache64kbEntryCount int64 + // Rmcache8kbEntryCount int64 + // RmcacheBigBlockEvictionCount int64 + // RmcacheBigBlockEvictionSizeCountInKb int64 + // RmcacheCurrNumOf128kbEntries int64 + // RmcacheCurrNumOf16kbEntries int64 + // RmcacheCurrNumOf32kbEntries int64 + // RmcacheCurrNumOf4kbEntries int64 + // RmcacheCurrNumOf64kbEntries int64 + // RmcacheCurrNumOf8kbEntries int64 + // RmcacheEntryEvictionCount int64 + // RmcacheEntryEvictionSizeCountInKb int64 + // RmcacheNoEvictionCount int64 + // RmcacheSizeInKb int64 + // RmcacheSizeInUseInKb int64 + // RmcacheSkipCountCacheAllBusy int64 + // RmcacheSkipCountLargeIo int64 + // RmcacheSkipCountUnaligned4kbIo int64 + // SdsIds int64 + // SecondaryReadBwc int64 + // SecondaryReadFromDevBwc int64 + // SecondaryReadFromRmcacheBwc int64 + // SecondaryVacInKb int64 + // SecondaryWriteBwc int64 + // SemiProtectedVacInKb int64 + // SnapCapacityInUseInKb int64 + // SnapCapacityInUseOccupiedInKb int64 + // ThickCapacityInUseInKb int64 + // ThinCapacityAllocatedInKb int64 + // ThinCapacityInUseInKb int64 + // TotalReadBwc int64 + // TotalWriteBwc int64 + // UnreachableUnusedCapacityInKb int64 + // UnusedCapacityInKb int64 + } + ProtectionDomainStatistics struct { + // BackgroundScanCompareCount int64 + // BackgroundScannedInMB int64 + // ActiveBckRebuildCapacityInKb int64 + // ActiveFwdRebuildCapacityInKb int64 + // ActiveMovingCapacityInKb int64 + // ActiveMovingInBckRebuildJobs int64 + // ActiveMovingInFwdRebuildJobs int64 + // ActiveMovingInNormRebuildJobs int64 + // ActiveMovingInRebalanceJobs int64 + // ActiveMovingOutBckRebuildJobs int64 + // ActiveMovingOutFwdRebuildJobs int64 + // ActiveMovingOutNormRebuildJobs int64 + // ActiveMovingRebalanceJobs int64 + // ActiveNormRebuildCapacityInKb int64 + // ActiveRebalanceCapacityInKb int64 + // AtRestCapacityInKb int64 + // BckRebuildCapacityInKb int64 + // BckRebuildReadBwc int64 + // BckRebuildWriteBwc int64 + // CapacityAvailableForVolumeAllocationInKb int64 + // CapacityInUseInKb int64 + // CapacityLimitInKb int64 + // DegradedFailedCapacityInKb int64 + // DegradedFailedVacInKb int64 + // DegradedHealthyCapacityInKb int64 + // DegradedHealthyVacInKb int64 + // FailedCapacityInKb int64 + // FailedVacInKb int64 + // FaultSetIds int64 + // FixedReadErrorCount int64 + // FwdRebuildCapacityInKb int64 + // FwdRebuildReadBwc int64 + // FwdRebuildWriteBwc int64 + // InMaintenanceCapacityInKb int64 + // InMaintenanceVacInKb int64 + // InUseVacInKb int64 + // MaxCapacityInKb int64 + // MovingCapacityInKb int64 + // NormRebuildCapacityInKb int64 + // NormRebuildReadBwc int64 + // NormRebuildWriteBwc int64 + // NumOfFaultSets int64 + // NumOfMappedToAllVolumes int64 + // NumOfSds int64 + // NumOfSnapshots int64 + // NumOfStoragePools int64 + // NumOfThickBaseVolumes int64 + // NumOfThinBaseVolumes int64 + // NumOfUnmappedVolumes int64 + // NumOfVolumesInDeletion int64 + // PendingBckRebuildCapacityInKb int64 + // PendingFwdRebuildCapacityInKb int64 + // PendingMovingCapacityInKb int64 + // PendingMovingInBckRebuildJobs int64 + // PendingMovingInFwdRebuildJobs int64 + // PendingMovingInNormRebuildJobs int64 + // PendingMovingInRebalanceJobs int64 + // PendingMovingOutBckRebuildJobs int64 + // PendingMovingOutFwdRebuildJobs int64 + // PendingMovingOutNormrebuildJobs int64 + // PendingMovingRebalanceJobs int64 + // PendingNormRebuildCapacityInKb int64 + // PendingRebalanceCapacityInKb int64 + // PrimaryReadBwc int64 + // PrimaryReadFromDevBwc int64 + // PrimaryReadFromRmcacheBwc int64 + // PrimaryVacInKb int64 + // PrimaryWriteBwc int64 + // ProtectedCapacityInKb int64 + // ProtectedVacInKb int64 + // RebalanceCapacityInKb int64 + // RebalancePerReceiveJobNetThrottlingInKbps int64 + // RebalanceReadBwc int64 + // RebalanceWaitSendQLength int64 + // RebalanceWriteBwc int64 + // RebuildPerReceiveJobNetThrottlingInKbps int64 + // RebuildWaitSendQLength int64 + // RfacheReadHit int64 + // RfacheWriteHit int64 + // RfcacheAvgReadTime int64 + // RfcacheAvgWriteTime int64 + // RfcacheFdAvgReadTime int64 + // RfcacheFdAvgWriteTime int64 + // RfcacheFdCacheOverloaded int64 + // RfcacheFdInlightReads int64 + // RfcacheFdInlightWrites int64 + // RfcacheFdIoErrors int64 + // RfcacheFdMonitorErrorStuckIo int64 + // RfcacheFdReadTimeGreater1Min int64 + // RfcacheFdReadTimeGreater1Sec int64 + // RfcacheFdReadTimeGreater500Millis int64 + // RfcacheFdReadTimeGreater5Sec int64 + // RfcacheFdReadsReceived int64 + // RfcacheFdWriteTimeGreater1Min int64 + // RfcacheFdWriteTimeGreater1Sec int64 + // RfcacheFdWriteTimeGreater500Millis int64 + // RfcacheFdWriteTimeGreater5Sec int64 + // RfcacheFdWritesReceived int64 + // RfcacheIoErrors int64 + // RfcacheIosOutstanding int64 + // RfcacheIosSkipped int64 + // RfcachePooIosOutstanding int64 + // RfcachePoolCachePages int64 + // RfcachePoolEvictions int64 + // RfcachePoolInLowMemoryCondition int64 + // RfcachePoolIoTimeGreater1Min int64 + // RfcachePoolLockTimeGreater1Sec int64 + // RfcachePoolLowResourcesInitiatedPassthroughMode int64 + // RfcachePoolNumCacheDevs int64 + // RfcachePoolNumSrcDevs int64 + // RfcachePoolPagesInuse int64 + // RfcachePoolReadHit int64 + // RfcachePoolReadMiss int64 + // RfcachePoolReadPendingG10Millis int64 + // RfcachePoolReadPendingG1Millis int64 + // RfcachePoolReadPendingG1Sec int64 + // RfcachePoolReadPendingG500Micro int64 + // RfcachePoolReadsPending int64 + // RfcachePoolSize int64 + // RfcachePoolSourceIdMismatch int64 + // RfcachePoolSuspendedIos int64 + // RfcachePoolSuspendedPequestsRedundantSearchs int64 + // RfcachePoolWriteHit int64 + // RfcachePoolWriteMiss int64 + // RfcachePoolWritePending int64 + // RfcachePoolWritePendingG10Millis int64 + // RfcachePoolWritePendingG1Millis int64 + // RfcachePoolWritePendingG1Sec int64 + // RfcachePoolWritePendingG500Micro int64 + // RfcacheReadMiss int64 + // RfcacheReadsFromCache int64 + // RfcacheReadsPending int64 + // RfcacheReadsReceived int64 + // RfcacheReadsSkipped int64 + // RfcacheReadsSkippedAlignedSizeTooLarge int64 + // RfcacheReadsSkippedHeavyLoad int64 + // RfcacheReadsSkippedInternalError int64 + // RfcacheReadsSkippedLockIos int64 + // RfcacheReadsSkippedLowResources int64 + // RfcacheReadsSkippedMaxIoSize int64 + // RfcacheReadsSkippedStuckIo int64 + // RfcacheSkippedUnlinedWrite int64 + // RfcacheSourceDeviceReads int64 + // RfcacheSourceDeviceWrites int64 + // RfcacheWriteMiss int64 + // RfcacheWritePending int64 + // RfcacheWritesReceived int64 + // RfcacheWritesSkippedCacheMiss int64 + // RfcacheWritesSkippedHeavyLoad int64 + // RfcacheWritesSkippedInternalError int64 + // RfcacheWritesSkippedLowResources int64 + // RfcacheWritesSkippedMaxIoSize int64 + // RfcacheWritesSkippedStuckIo int64 + // RmPendingAllocatedInKb int64 + // Rmcache128kbEntryCount int64 + // Rmcache16kbEntryCount int64 + // Rmcache32kbEntryCount int64 + // Rmcache4kbEntryCount int64 + // Rmcache64kbEntryCount int64 + // Rmcache8kbEntryCount int64 + // RmcacheBigBlockEvictionCount int64 + // RmcacheBigBlockEvictionSizeCountInKb int64 + // RmcacheCurrNumOf128kbEntries int64 + // RmcacheCurrNumOf16kbEntries int64 + // RmcacheCurrNumOf32kbEntries int64 + // RmcacheCurrNumOf4kbEntries int64 + // RmcacheCurrNumOf64kbEntries int64 + // RmcacheCurrNumOf8kbEntries int64 + // RmcacheEntryEvictionCount int64 + // RmcacheEntryEvictionSizeCountInKb int64 + // RmcacheNoEvictionCount int64 + // RmcacheSizeInKb int64 + // RmcacheSizeInUseInKb int64 + // RmcacheSkipCountCacheAllBusy int64 + // RmcacheSkipCountLargeIo int64 + // RmcacheSkipCountUnaligned4kbIo int64 + // SdsIds int64 + // SecondaryReadBwc int64 + // SecondaryReadFromDevBwc int64 + // SecondaryReadFromRmcacheBwc int64 + // SecondaryVacInKb int64 + // SecondaryWriteBwc int64 + // SemiProtectedCapacityInKb int64 + // SemiProtectedVacInKb int64 + // SnapCapacityInUseInKb int64 + // SnapCapacityInUseOccupiedInKb int64 + // SpareCapacityInKb int64 + // StoragePoolIds int64 + // ThickCapacityInUseInKb int64 + // ThinCapacityAllocatedInKb int64 + // ThinCapacityInUseInKb int64 + // TotalReadBwc int64 + // TotalWriteBwc int64 + // UnreachableUnusedCapacityInKb int64 + // UnusedCapacityInKb int64 + // UserDataReadBwc int64 + // UserDataWriteBwc int64 + } + RFCacheDeviceStatistics struct { + // RfcacheFdAvgReadTime int64 + // RfcacheFdAvgWriteTime int64 + // RfcacheFdCacheOverloaded int64 + // RfcacheFdInlightReads int64 + // RfcacheFdInlightWrites int64 + // RfcacheFdIoErrors int64 + // RfcacheFdMonitorErrorStuckIo int64 + // RfcacheFdReadTimeGreater1Min int64 + // RfcacheFdReadTimeGreater1Sec int64 + // RfcacheFdReadTimeGreater500Millis int64 + // RfcacheFdReadTimeGreater5Sec int64 + // RfcacheFdReadsReceived int64 + // RfcacheFdWriteTimeGreater1Min int64 + // RfcacheFdWriteTimeGreater1Sec int64 + // RfcacheFdWriteTimeGreater500Millis int64 + // RfcacheFdWriteTimeGreater5Sec int64 + // RfcacheFdWritesReceived int64 + } + SdsStatistics struct { + // BackgroundScanCompareCount int64 + // BackgroundScannedInMB int64 + // ActiveMovingInBckRebuildJobs int64 + // ActiveMovingInFwdRebuildJobs int64 + // ActiveMovingInNormRebuildJobs int64 + // ActiveMovingInRebalanceJobs int64 + // ActiveMovingOutBckRebuildJobs int64 + // ActiveMovingOutFwdRebuildJobs int64 + // ActiveMovingOutNormRebuildJobs int64 + // ActiveMovingRebalanceJobs int64 + // BckRebuildReadBwc int64 + // BckRebuildWriteBwc int64 + // CapacityInUseInKb int64 + // CapacityLimitInKb int64 + // DegradedFailedVacInKb int64 + // DegradedHealthyVacInKb int64 + // DeviceIds int64 + // FailedVacInKb int64 + // FixedReadErrorCount int64 + // FwdRebuildReadBwc int64 + // FwdRebuildWriteBwc int64 + // InMaintenanceVacInKb int64 + // InUseVacInKb int64 + // MaxCapacityInKb int64 + // NormRebuildReadBwc int64 + // NormRebuildWriteBwc int64 + // NumOfDevices int64 + // NumOfRfcacheDevices int64 + // PendingMovingInBckRebuildJobs int64 + // PendingMovingInFwdRebuildJobs int64 + // PendingMovingInNormRebuildJobs int64 + // PendingMovingInRebalanceJobs int64 + // PendingMovingOutBckRebuildJobs int64 + // PendingMovingOutFwdRebuildJobs int64 + // PendingMovingOutNormrebuildJobs int64 + // PendingMovingRebalanceJobs int64 + // PrimaryReadBwc int64 + // PrimaryReadFromDevBwc int64 + // PrimaryReadFromRmcacheBwc int64 + // PrimaryVacInKb int64 + // PrimaryWriteBwc int64 + // ProtectedVacInKb int64 + // RebalancePerReceiveJobNetThrottlingInKbps int64 + // RebalanceReadBwc int64 + // RebalanceWaitSendQLength int64 + // RebalanceWriteBwc int64 + // RebuildPerReceiveJobNetThrottlingInKbps int64 + // RebuildWaitSendQLength int64 + // RfacheReadHit int64 + // RfacheWriteHit int64 + // RfcacheAvgReadTime int64 + // RfcacheAvgWriteTime int64 + // RfcacheDeviceIds int64 + // RfcacheFdAvgReadTime int64 + // RfcacheFdAvgWriteTime int64 + // RfcacheFdCacheOverloaded int64 + // RfcacheFdInlightReads int64 + // RfcacheFdInlightWrites int64 + // RfcacheFdIoErrors int64 + // RfcacheFdMonitorErrorStuckIo int64 + // RfcacheFdReadTimeGreater1Min int64 + // RfcacheFdReadTimeGreater1Sec int64 + // RfcacheFdReadTimeGreater500Millis int64 + // RfcacheFdReadTimeGreater5Sec int64 + // RfcacheFdReadsReceived int64 + // RfcacheFdWriteTimeGreater1Min int64 + // RfcacheFdWriteTimeGreater1Sec int64 + // RfcacheFdWriteTimeGreater500Millis int64 + // RfcacheFdWriteTimeGreater5Sec int64 + // RfcacheFdWritesReceived int64 + // RfcacheIoErrors int64 + // RfcacheIosOutstanding int64 + // RfcacheIosSkipped int64 + // RfcachePooIosOutstanding int64 + // RfcachePoolCachePages int64 + // RfcachePoolContinuosMem int64 + // RfcachePoolEvictions int64 + // RfcachePoolInLowMemoryCondition int64 + // RfcachePoolIoTimeGreater1Min int64 + // RfcachePoolLockTimeGreater1Sec int64 + // RfcachePoolLowResourcesInitiatedPassthroughMode int64 + // RfcachePoolMaxIoSize int64 + // RfcachePoolNumCacheDevs int64 + // RfcachePoolNumOfDriverTheads int64 + // RfcachePoolNumSrcDevs int64 + // RfcachePoolOpmode int64 + // RfcachePoolPageSize int64 + // RfcachePoolPagesInuse int64 + // RfcachePoolReadHit int64 + // RfcachePoolReadMiss int64 + // RfcachePoolReadPendingG10Millis int64 + // RfcachePoolReadPendingG1Millis int64 + // RfcachePoolReadPendingG1Sec int64 + // RfcachePoolReadPendingG500Micro int64 + // RfcachePoolReadsPending int64 + // RfcachePoolSize int64 + // RfcachePoolSourceIdMismatch int64 + // RfcachePoolSuspendedIos int64 + // RfcachePoolSuspendedIosMax int64 + // RfcachePoolSuspendedPequestsRedundantSearchs int64 + // RfcachePoolWriteHit int64 + // RfcachePoolWriteMiss int64 + // RfcachePoolWritePending int64 + // RfcachePoolWritePendingG10Millis int64 + // RfcachePoolWritePendingG1Millis int64 + // RfcachePoolWritePendingG1Sec int64 + // RfcachePoolWritePendingG500Micro int64 + // RfcacheReadMiss int64 + // RfcacheReadsFromCache int64 + // RfcacheReadsPending int64 + // RfcacheReadsReceived int64 + // RfcacheReadsSkipped int64 + // RfcacheReadsSkippedAlignedSizeTooLarge int64 + // RfcacheReadsSkippedHeavyLoad int64 + // RfcacheReadsSkippedInternalError int64 + // RfcacheReadsSkippedLockIos int64 + // RfcacheReadsSkippedLowResources int64 + // RfcacheReadsSkippedMaxIoSize int64 + // RfcacheReadsSkippedStuckIo int64 + // RfcacheSkippedUnlinedWrite int64 + // RfcacheSourceDeviceReads int64 + // RfcacheSourceDeviceWrites int64 + // RfcacheWriteMiss int64 + // RfcacheWritePending int64 + // RfcacheWritesReceived int64 + // RfcacheWritesSkippedCacheMiss int64 + // RfcacheWritesSkippedHeavyLoad int64 + // RfcacheWritesSkippedInternalError int64 + // RfcacheWritesSkippedLowResources int64 + // RfcacheWritesSkippedMaxIoSize int64 + // RfcacheWritesSkippedStuckIo int64 + // RmPendingAllocatedInKb int64 + // Rmcache128kbEntryCount int64 + // Rmcache16kbEntryCount int64 + // Rmcache32kbEntryCount int64 + // Rmcache4kbEntryCount int64 + // Rmcache64kbEntryCount int64 + // Rmcache8kbEntryCount int64 + // RmcacheBigBlockEvictionCount int64 + // RmcacheBigBlockEvictionSizeCountInKb int64 + // RmcacheCurrNumOf128kbEntries int64 + // RmcacheCurrNumOf16kbEntries int64 + // RmcacheCurrNumOf32kbEntries int64 + // RmcacheCurrNumOf4kbEntries int64 + // RmcacheCurrNumOf64kbEntries int64 + // RmcacheCurrNumOf8kbEntries int64 + // RmcacheEntryEvictionCount int64 + // RmcacheEntryEvictionSizeCountInKb int64 + // RmcacheNoEvictionCount int64 + // RmcacheSizeInKb int64 + // RmcacheSizeInUseInKb int64 + // RmcacheSkipCountCacheAllBusy int64 + // RmcacheSkipCountLargeIo int64 + // RmcacheSkipCountUnaligned4kbIo int64 + // SecondaryReadBwc int64 + // SecondaryReadFromDevBwc int64 + // SecondaryReadFromRmcacheBwc int64 + // SecondaryVacInKb int64 + // SecondaryWriteBwc int64 + // SemiProtectedVacInKb int64 + // SnapCapacityInUseInKb int64 + // SnapCapacityInUseOccupiedInKb int64 + // ThickCapacityInUseInKb int64 + // ThinCapacityAllocatedInKb int64 + // ThinCapacityInUseInKb int64 + // TotalReadBwc int64 + // TotalWriteBwc int64 + // UnreachableUnusedCapacityInKb int64 + // UnusedCapacityInKb int64 + } + VolumeStatistics struct { + // ChildVolumeIds int64 + // DescendantVolumeIds int64 + // MappedSdcIds int64 + // NumOfChildVolumes int64 + // NumOfDescendantVolumes int64 + // NumOfMappedScsiInitiators int64 + // NumOfMappedSdcs int64 + // UserDataReadBwc int64 + // UserDataWriteBwc int64 + } + VTreeStatistics struct { + // BaseNetCapacityInUseInKb int64 + // NetCapacityInUseInKb int64 + // NumOfVolumes int64 + // SnapNetCapacityInUseInKb int64 + // TrimmedCapacityInKb int64 + // VolumeIds int64 + } +) diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/collect.go b/src/go/collectors/go.d.plugin/modules/scaleio/collect.go new file mode 100644 index 000000000..93a0a609d --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/collect.go @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package scaleio + +import ( + "time" + + "github.com/netdata/netdata/go/go.d.plugin/modules/scaleio/client" + "github.com/netdata/netdata/go/go.d.plugin/pkg/stm" +) + +const discoveryEvery = 5 + +func (s *ScaleIO) collect() (map[string]int64, error) { + s.runs += 1 + if !s.lastDiscoveryOK || s.runs%discoveryEvery == 0 { + if err := s.discovery(); err != nil { + return nil, err + } + } + + stats, err := s.client.SelectedStatistics(query) + if err != nil { + return nil, err + } + + mx := metrics{ + System: s.collectSystem(stats.System), + StoragePool: s.collectStoragePool(stats.StoragePool), + Sdc: s.collectSdc(stats.Sdc), + } + + s.updateCharts() + return stm.ToMap(mx), nil +} + +func (s *ScaleIO) discovery() error { + start := time.Now() + s.Debugf("starting discovery") + ins, err := s.client.Instances() + if err != nil { + s.lastDiscoveryOK = false + return err + } + s.Debugf("discovering: discovered %d storage pools, %d sdcs, it took %s", + len(ins.StoragePoolList), len(ins.SdcList), time.Since(start)) + + s.discovered.pool = make(map[string]client.StoragePool, len(ins.StoragePoolList)) + for _, pool := range ins.StoragePoolList { + s.discovered.pool[pool.ID] = pool + } + s.discovered.sdc = make(map[string]client.Sdc, len(ins.SdcList)) + for _, sdc := range ins.SdcList { + s.discovered.sdc[sdc.ID] = sdc + } + s.lastDiscoveryOK = true + return nil +} diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/collect_sdc.go b/src/go/collectors/go.d.plugin/modules/scaleio/collect_sdc.go new file mode 100644 index 000000000..e840b781d --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/collect_sdc.go @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package scaleio + +import "github.com/netdata/netdata/go/go.d.plugin/modules/scaleio/client" + +func (s *ScaleIO) collectSdc(ss map[string]client.SdcStatistics) map[string]sdcMetrics { + ms := make(map[string]sdcMetrics, len(ss)) + + for id, stats := range ss { + sdc, ok := s.discovered.sdc[id] + if !ok { + continue + } + var m sdcMetrics + m.BW.set( + calcBW(stats.UserDataReadBwc), + calcBW(stats.UserDataWriteBwc), + ) + m.IOPS.set( + calcIOPS(stats.UserDataReadBwc), + calcIOPS(stats.UserDataWriteBwc), + ) + m.IOSize.set( + calcIOSize(stats.UserDataReadBwc), + calcIOSize(stats.UserDataWriteBwc), + ) + m.MappedVolumes = stats.NumOfMappedVolumes + m.MDMConnectionState = isSdcConnected(sdc.MdmConnectionState) + + ms[id] = m + } + return ms +} + +func isSdcConnected(state string) bool { + return state == "Connected" +} diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/collect_storage_pool.go b/src/go/collectors/go.d.plugin/modules/scaleio/collect_storage_pool.go new file mode 100644 index 000000000..409be0bdb --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/collect_storage_pool.go @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package scaleio + +import "github.com/netdata/netdata/go/go.d.plugin/modules/scaleio/client" + +func (s *ScaleIO) collectStoragePool(ss map[string]client.StoragePoolStatistics) map[string]storagePoolMetrics { + ms := make(map[string]storagePoolMetrics, len(ss)) + + for id, stats := range ss { + pool, ok := s.discovered.pool[id] + if !ok { + continue + } + var pm storagePoolMetrics + collectStoragePoolCapacity(&pm, stats, pool) + collectStoragePoolComponents(&pm, stats) + + ms[id] = pm + } + return ms +} + +func collectStoragePoolCapacity(pm *storagePoolMetrics, ps client.StoragePoolStatistics, pool client.StoragePool) { + collectCapacity(&pm.Capacity.capacity, ps.CapacityStatistics) + pm.Capacity.Utilization = calcCapacityUtilization(ps.CapacityInUseInKb, ps.MaxCapacityInKb, pool.SparePercentage) + pm.Capacity.AlertThreshold.Critical = pool.CapacityAlertCriticalThreshold + pm.Capacity.AlertThreshold.High = pool.CapacityAlertHighThreshold +} + +func collectStoragePoolComponents(pm *storagePoolMetrics, ps client.StoragePoolStatistics) { + pm.Components.Devices = ps.NumOfDevices + pm.Components.Snapshots = ps.NumOfSnapshots + pm.Components.Volumes = ps.NumOfVolumes + pm.Components.Vtrees = ps.NumOfVtrees +} + +func calcCapacityUtilization(inUse int64, max int64, sparePercent int64) float64 { + spare := float64(max) / 100 * float64(sparePercent) + return divFloat(float64(100*inUse), float64(max)-spare) +} diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/collect_system.go b/src/go/collectors/go.d.plugin/modules/scaleio/collect_system.go new file mode 100644 index 000000000..b2c02db1b --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/collect_system.go @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package scaleio + +import "github.com/netdata/netdata/go/go.d.plugin/modules/scaleio/client" + +func (s *ScaleIO) collectSystem(ss client.SystemStatistics) systemMetrics { + var sm systemMetrics + collectSystemCapacity(&sm, ss) + collectSystemWorkload(&sm, ss) + collectSystemRebalance(&sm, ss) + collectSystemRebuild(&sm, ss) + collectSystemComponents(&sm, ss) + return sm +} + +func collectSystemCapacity(sm *systemMetrics, ss client.SystemStatistics) { + collectCapacity(&sm.Capacity, ss.CapacityStatistics) +} + +func collectCapacity(m *capacity, ss client.CapacityStatistics) { + // Health + m.Protected = ss.ProtectedCapacityInKb + m.InMaintenance = ss.InMaintenanceCapacityInKb + m.Degraded = sum(ss.DegradedFailedCapacityInKb, ss.DegradedHealthyCapacityInKb) + m.Failed = ss.FailedCapacityInKb + m.UnreachableUnused = ss.UnreachableUnusedCapacityInKb + + // Capacity + m.MaxCapacity = ss.MaxCapacityInKb + m.ThickInUse = ss.ThickCapacityInUseInKb + m.ThinInUse = ss.ThinCapacityInUseInKb + m.Snapshot = ss.SnapCapacityInUseOccupiedInKb + m.Spare = ss.SpareCapacityInKb + m.Decreased = sum(ss.MaxCapacityInKb, -ss.CapacityLimitInKb) // TODO: probably wrong + // Note: can't use 'UnusedCapacityInKb' directly, dashboard shows calculated value + used := sum( + ss.ProtectedCapacityInKb, + ss.InMaintenanceCapacityInKb, + m.Decreased, + m.Degraded, + ss.FailedCapacityInKb, + ss.SpareCapacityInKb, + ss.UnreachableUnusedCapacityInKb, + ss.SnapCapacityInUseOccupiedInKb, + ) + m.Unused = sum(ss.MaxCapacityInKb, -used) + + // Other + m.InUse = ss.CapacityInUseInKb + m.AvailableForVolumeAllocation = ss.CapacityAvailableForVolumeAllocationInKb +} + +func collectSystemComponents(sm *systemMetrics, ss client.SystemStatistics) { + m := &sm.Components + + m.Devices = ss.NumOfDevices + m.FaultSets = ss.NumOfFaultSets + m.MappedToAllVolumes = ss.NumOfMappedToAllVolumes + m.ProtectionDomains = ss.NumOfProtectionDomains + m.RfcacheDevices = ss.NumOfRfcacheDevices + m.Sdc = ss.NumOfSdc + m.Sds = ss.NumOfSds + m.Snapshots = ss.NumOfSnapshots + m.StoragePools = ss.NumOfStoragePools + m.VTrees = ss.NumOfVtrees + m.Volumes = ss.NumOfVolumes + m.ThickBaseVolumes = ss.NumOfThickBaseVolumes + m.ThinBaseVolumes = ss.NumOfThinBaseVolumes + m.UnmappedVolumes = ss.NumOfUnmappedVolumes + m.MappedVolumes = sum(ss.NumOfVolumes, -ss.NumOfUnmappedVolumes) +} + +func collectSystemWorkload(sm *systemMetrics, ss client.SystemStatistics) { + m := &sm.Workload + + m.Total.BW.set( + calcBW(ss.TotalReadBwc), + calcBW(ss.TotalWriteBwc), + ) + m.Frontend.BW.set( + calcBW(ss.UserDataReadBwc), + calcBW(ss.UserDataWriteBwc), + ) + m.Backend.Primary.BW.set( + calcBW(ss.PrimaryReadBwc), + calcBW(ss.PrimaryWriteBwc), + ) + m.Backend.Secondary.BW.set( + calcBW(ss.SecondaryReadBwc), + calcBW(ss.SecondaryWriteBwc), + ) + m.Backend.Total.BW.set( + sumFloat(m.Backend.Primary.BW.Read, m.Backend.Secondary.BW.Read), + sumFloat(m.Backend.Primary.BW.Write, m.Backend.Secondary.BW.Write), + ) + + m.Total.IOPS.set( + calcIOPS(ss.TotalReadBwc), + calcIOPS(ss.TotalWriteBwc), + ) + m.Frontend.IOPS.set( + calcIOPS(ss.UserDataReadBwc), + calcIOPS(ss.UserDataWriteBwc), + ) + m.Backend.Primary.IOPS.set( + calcIOPS(ss.PrimaryReadBwc), + calcIOPS(ss.PrimaryWriteBwc), + ) + m.Backend.Secondary.IOPS.set( + calcIOPS(ss.SecondaryReadBwc), + calcIOPS(ss.SecondaryWriteBwc), + ) + m.Backend.Total.IOPS.set( + sumFloat(m.Backend.Primary.IOPS.Read, m.Backend.Secondary.IOPS.Read), + sumFloat(m.Backend.Primary.IOPS.Write, m.Backend.Secondary.IOPS.Write), + ) + + m.Total.IOSize.set( + calcIOSize(ss.TotalReadBwc), + calcIOSize(ss.TotalWriteBwc), + ) + m.Frontend.IOSize.set( + calcIOSize(ss.UserDataReadBwc), + calcIOSize(ss.UserDataWriteBwc), + ) + m.Backend.Primary.IOSize.set( + calcIOSize(ss.PrimaryReadBwc), + calcIOSize(ss.PrimaryWriteBwc), + ) + m.Backend.Secondary.IOSize.set( + calcIOSize(ss.SecondaryReadBwc), + calcIOSize(ss.SecondaryWriteBwc), + ) + m.Backend.Total.IOSize.set( + sumFloat(m.Backend.Primary.IOSize.Read, m.Backend.Secondary.IOSize.Read), + sumFloat(m.Backend.Primary.IOSize.Write, m.Backend.Secondary.IOSize.Write), + ) +} + +func collectSystemRebuild(sm *systemMetrics, ss client.SystemStatistics) { + m := &sm.Rebuild + + m.Forward.BW.set( + calcBW(ss.FwdRebuildReadBwc), + calcBW(ss.FwdRebuildWriteBwc), + ) + m.Backward.BW.set( + calcBW(ss.BckRebuildReadBwc), + calcBW(ss.BckRebuildWriteBwc), + ) + m.Normal.BW.set( + calcBW(ss.NormRebuildReadBwc), + calcBW(ss.NormRebuildWriteBwc), + ) + m.Total.BW.set( + sumFloat(m.Forward.BW.Read, m.Backward.BW.Read, m.Normal.BW.Read), + sumFloat(m.Forward.BW.Write, m.Backward.BW.Write, m.Normal.BW.Write), + ) + + m.Forward.IOPS.set( + calcIOPS(ss.FwdRebuildReadBwc), + calcIOPS(ss.FwdRebuildWriteBwc), + ) + m.Backward.IOPS.set( + calcIOPS(ss.BckRebuildReadBwc), + calcIOPS(ss.BckRebuildWriteBwc), + ) + m.Normal.IOPS.set( + calcIOPS(ss.NormRebuildReadBwc), + calcIOPS(ss.NormRebuildWriteBwc), + ) + m.Total.IOPS.set( + sumFloat(m.Forward.IOPS.Read, m.Backward.IOPS.Read, m.Normal.IOPS.Read), + sumFloat(m.Forward.IOPS.Write, m.Backward.IOPS.Write, m.Normal.IOPS.Write), + ) + + m.Forward.IOSize.set( + calcIOSize(ss.FwdRebuildReadBwc), + calcIOSize(ss.FwdRebuildWriteBwc), + ) + m.Backward.IOSize.set( + calcIOSize(ss.BckRebuildReadBwc), + calcIOSize(ss.BckRebuildWriteBwc), + ) + m.Normal.IOSize.set( + calcIOSize(ss.NormRebuildReadBwc), + calcIOSize(ss.NormRebuildWriteBwc), + ) + m.Total.IOSize.set( + sumFloat(m.Forward.IOSize.Read, m.Backward.IOSize.Read, m.Normal.IOSize.Read), + sumFloat(m.Forward.IOSize.Write, m.Backward.IOSize.Write, m.Normal.IOSize.Write), + ) + + m.Forward.Pending = ss.PendingFwdRebuildCapacityInKb + m.Backward.Pending = ss.PendingBckRebuildCapacityInKb + m.Normal.Pending = ss.PendingNormRebuildCapacityInKb + m.Total.Pending = sum(m.Forward.Pending, m.Backward.Pending, m.Normal.Pending) +} + +func collectSystemRebalance(sm *systemMetrics, ss client.SystemStatistics) { + m := &sm.Rebalance + + m.BW.set( + calcBW(ss.RebalanceReadBwc), + calcBW(ss.RebalanceWriteBwc), + ) + + m.IOPS.set( + calcIOPS(ss.RebalanceReadBwc), + calcIOPS(ss.RebalanceWriteBwc), + ) + + m.IOSize.set( + calcIOSize(ss.RebalanceReadBwc), + calcIOSize(ss.RebalanceWriteBwc), + ) + + m.Pending = ss.PendingRebalanceCapacityInKb + m.TimeUntilFinish = divFloat(float64(m.Pending), m.BW.ReadWrite) +} + +func calcBW(bwc client.Bwc) float64 { return div(bwc.TotalWeightInKb, bwc.NumSeconds) } +func calcIOPS(bwc client.Bwc) float64 { return div(bwc.NumOccured, bwc.NumSeconds) } +func calcIOSize(bwc client.Bwc) float64 { return div(bwc.TotalWeightInKb, bwc.NumOccured) } + +func sum(a, b int64, others ...int64) (res int64) { + for _, v := range others { + res += v + } + return res + a + b +} + +func sumFloat(a, b float64, others ...float64) (res float64) { + for _, v := range others { + res += v + } + return res + a + b +} + +func div(a, b int64) float64 { + return divFloat(float64(a), float64(b)) +} + +func divFloat(a, b float64) float64 { + if b == 0 { + return 0 + } + return a / b +} diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/config_schema.json b/src/go/collectors/go.d.plugin/modules/scaleio/config_schema.json new file mode 100644 index 000000000..ba1067325 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/config_schema.json @@ -0,0 +1,177 @@ +{ + "jsonSchema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ScaleIO collector configuration.", + "type": "object", + "properties": { + "update_every": { + "title": "Update every", + "description": "Data collection interval, measured in seconds.", + "type": "integer", + "minimum": 1, + "default": 1 + }, + "url": { + "title": "URL", + "description": "The base URL of the VxFlex OS Gateway API.", + "type": "string", + "default": "http://127.0.0.1:80", + "format": "uri" + }, + "timeout": { + "title": "Timeout", + "description": "The timeout in seconds for the HTTP request.", + "type": "number", + "minimum": 0.5, + "default": 1 + }, + "not_follow_redirects": { + "title": "Not follow redirects", + "description": "If set, the client will not follow HTTP redirects automatically.", + "type": "boolean" + }, + "username": { + "title": "Username", + "description": "The username for basic authentication.", + "type": "string", + "sensitive": true + }, + "password": { + "title": "Password", + "description": "The password for basic authentication.", + "type": "string", + "sensitive": true + }, + "proxy_url": { + "title": "Proxy URL", + "description": "The URL of the proxy server.", + "type": "string" + }, + "proxy_username": { + "title": "Proxy username", + "description": "The username for proxy authentication.", + "type": "string", + "sensitive": true + }, + "proxy_password": { + "title": "Proxy password", + "description": "The password for proxy authentication.", + "type": "string", + "sensitive": true + }, + "headers": { + "title": "Headers", + "description": "Additional HTTP headers to include in the request.", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "string" + } + }, + "tls_skip_verify": { + "title": "Skip TLS verification", + "description": "If set, TLS certificate verification will be skipped.", + "type": "boolean" + }, + "tls_ca": { + "title": "TLS CA", + "description": "The path to the CA certificate file for TLS verification.", + "type": "string", + "pattern": "^$|^/" + }, + "tls_cert": { + "title": "TLS certificate", + "description": "The path to the client certificate file for TLS authentication.", + "type": "string", + "pattern": "^$|^/" + }, + "tls_key": { + "title": "TLS key", + "description": "The path to the client key file for TLS authentication.", + "type": "string", + "pattern": "^$|^/" + }, + "body": { + "title": "Body", + "type": "string" + }, + "method": { + "title": "Method", + "type": "string" + } + }, + "required": [ + "url" + ], + "additionalProperties": false, + "patternProperties": { + "^name$": {} + } + }, + "uiSchema": { + "ui:flavour": "tabs", + "ui:options": { + "tabs": [ + { + "title": "Base", + "fields": [ + "update_every", + "url", + "timeout", + "not_follow_redirects" + ] + }, + { + "title": "Auth", + "fields": [ + "username", + "password" + ] + }, + { + "title": "TLS", + "fields": [ + "tls_skip_verify", + "tls_ca", + "tls_cert", + "tls_key" + ] + }, + { + "title": "Proxy", + "fields": [ + "proxy_url", + "proxy_username", + "proxy_password" + ] + }, + { + "title": "Headers", + "fields": [ + "headers" + ] + } + ] + }, + "uiOptions": { + "fullPage": true + }, + "body": { + "ui:widget": "hidden" + }, + "method": { + "ui:widget": "hidden" + }, + "timeout": { + "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)." + }, + "password": { + "ui:widget": "password" + }, + "proxy_password": { + "ui:widget": "password" + } + } +} diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/integrations/dell_emc_scaleio.md b/src/go/collectors/go.d.plugin/modules/scaleio/integrations/dell_emc_scaleio.md new file mode 100644 index 000000000..c5a977600 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/integrations/dell_emc_scaleio.md @@ -0,0 +1,255 @@ +<!--startmeta +custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/go/collectors/go.d.plugin/modules/scaleio/README.md" +meta_yaml: "https://github.com/netdata/netdata/edit/master/src/go/collectors/go.d.plugin/modules/scaleio/metadata.yaml" +sidebar_label: "Dell EMC ScaleIO" +learn_status: "Published" +learn_rel_path: "Collecting Metrics/Storage, Mount Points and Filesystems" +most_popular: False +message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE" +endmeta--> + +# Dell EMC ScaleIO + + +<img src="https://netdata.cloud/img/dell.svg" width="150"/> + + +Plugin: go.d.plugin +Module: scaleio + +<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" /> + +## Overview + +This collector monitors ScaleIO (VxFlex OS) instances via VxFlex OS Gateway API. + +It collects metrics for the following ScaleIO components: + +- System +- Storage Pool +- Sdc + + + + +This collector is supported on all platforms. + +This collector supports collecting metrics from multiple instances of this integration, including remote instances. + + +### Default Behavior + +#### Auto-Detection + +This integration doesn't support auto-detection. + +#### Limits + +The default configuration for this integration does not impose any limits on data collection. + +#### Performance Impact + +The default configuration for this integration is not expected to impose a significant performance impact on the system. + + +## Metrics + +Metrics grouped by *scope*. + +The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels. + + + +### Per Dell EMC ScaleIO instance + +These metrics refer to the entire monitored application. + +This scope has no labels. + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| scaleio.system_capacity_total | total | KiB | +| scaleio.system_capacity_in_use | in_use | KiB | +| scaleio.system_capacity_usage | thick, decreased, thin, snapshot, spare, unused | KiB | +| scaleio.system_capacity_available_volume_allocation | available | KiB | +| scaleio.system_capacity_health_state | protected, degraded, in_maintenance, failed, unavailable | KiB | +| scaleio.system_workload_primary_bandwidth_total | total | KiB/s | +| scaleio.system_workload_primary_bandwidth | read, write | KiB/s | +| scaleio.system_workload_primary_iops_total | total | iops/s | +| scaleio.system_workload_primary_iops | read, write | iops/s | +| scaleio.system_workload_primary_io_size_total | io_size | KiB | +| scaleio.system_rebalance | read, write | KiB/s | +| scaleio.system_rebalance_left | left | KiB | +| scaleio.system_rebalance_time_until_finish | time | seconds | +| scaleio.system_rebuild | read, write | KiB/s | +| scaleio.system_rebuild_left | left | KiB | +| scaleio.system_defined_components | devices, fault_sets, protection_domains, rfcache_devices, sdc, sds, snapshots, storage_pools, volumes, vtrees | components | +| scaleio.system_components_volumes_by_type | thick, thin | volumes | +| scaleio.system_components_volumes_by_mapping | mapped, unmapped | volumes | + +### Per storage pool + +These metrics refer to the storage pool. + +This scope has no labels. + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| scaleio.storage_pool_capacity_total | total | KiB | +| scaleio.storage_pool_capacity_in_use | in_use | KiB | +| scaleio.storage_pool_capacity_usage | thick, decreased, thin, snapshot, spare, unused | KiB | +| scaleio.storage_pool_capacity_utilization | used | percentage | +| scaleio.storage_pool_capacity_available_volume_allocation | available | KiB | +| scaleio.storage_pool_capacity_health_state | protected, degraded, in_maintenance, failed, unavailable | KiB | +| scaleio.storage_pool_components | devices, snapshots, volumes, vtrees | components | + +### Per sdc + +These metrics refer to the SDC (ScaleIO Data Client). + +This scope has no labels. + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| scaleio.sdc_mdm_connection_state | connected | boolean | +| scaleio.sdc_bandwidth | read, write | KiB/s | +| scaleio.sdc_iops | read, write | iops/s | +| scaleio.sdc_io_size | read, write | KiB | +| scaleio.sdc_num_of_mapped_volumed | mapped | volumes | + + + +## Alerts + +There are no alerts configured by default for this integration. + + +## Setup + +### Prerequisites + +No action required. + +### Configuration + +#### File + +The configuration file name for this integration is `go.d/scaleio.conf`. + + +You can edit the configuration file using the `edit-config` script from the +Netdata [config directory](/docs/netdata-agent/configuration/README.md#the-netdata-config-directory). + +```bash +cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata +sudo ./edit-config go.d/scaleio.conf +``` +#### Options + +The following options can be defined globally: update_every, autodetection_retry. + + +<details open><summary>Config options</summary> + +| Name | Description | Default | Required | +|:----|:-----------|:-------|:--------:| +| update_every | Data collection frequency. | 5 | no | +| autodetection_retry | Recheck interval in seconds. Zero means no recheck will be scheduled. | 0 | no | +| url | Server URL. | https://127.0.0.1:80 | yes | +| timeout | HTTP request timeout. | 1 | no | +| username | Username for basic HTTP authentication. | | yes | +| password | Password for basic HTTP authentication. | | yes | +| proxy_url | Proxy URL. | | no | +| proxy_username | Username for proxy basic HTTP authentication. | | no | +| proxy_password | Password for proxy basic HTTP authentication. | | no | +| method | HTTP request method. | GET | no | +| body | HTTP request body. | | no | +| headers | HTTP request headers. | | no | +| not_follow_redirects | Redirect handling policy. Controls whether the client follows redirects. | no | no | +| tls_skip_verify | Server certificate chain and hostname validation policy. Controls whether the client performs this check. | no | no | +| tls_ca | Certification authority that the client uses when verifying the server's certificates. | | no | +| tls_cert | Client TLS certificate. | | no | +| tls_key | Client TLS key. | | no | + +</details> + +#### Examples + +##### Basic + +An example configuration. + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: local + url: https://127.0.0.1 + username: admin + password: password + tls_skip_verify: yes # self-signed certificate + +``` +</details> + +##### Multi-instance + +> **Note**: When you define multiple jobs, their names must be unique. + +Local and remote instance. + + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: local + url: https://127.0.0.1 + username: admin + password: password + tls_skip_verify: yes # self-signed certificate + + - name: remote + url: https://203.0.113.10 + username: admin + password: password + tls_skip_verify: yes + +``` +</details> + + + +## Troubleshooting + +### Debug Mode + +To troubleshoot issues with the `scaleio` collector, run the `go.d.plugin` with the debug option enabled. The output +should give you clues as to why the collector isn't working. + +- Navigate to the `plugins.d` directory, usually at `/usr/libexec/netdata/plugins.d/`. If that's not the case on + your system, open `netdata.conf` and look for the `plugins` setting under `[directories]`. + + ```bash + cd /usr/libexec/netdata/plugins.d/ + ``` + +- Switch to the `netdata` user. + + ```bash + sudo -u netdata -s + ``` + +- Run the `go.d.plugin` to debug the collector: + + ```bash + ./go.d.plugin -d -m scaleio + ``` + + diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/metadata.yaml b/src/go/collectors/go.d.plugin/modules/scaleio/metadata.yaml new file mode 100644 index 000000000..edee6fc8b --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/metadata.yaml @@ -0,0 +1,399 @@ +plugin_name: go.d.plugin +modules: + - meta: + id: collector-go.d.plugin-scaleio + plugin_name: go.d.plugin + module_name: scaleio + monitored_instance: + name: Dell EMC ScaleIO + link: https://www.dell.com/en-ca/dt/storage/scaleio/scaleioreadynode.htm + icon_filename: dell.svg + categories: + - data-collection.storage-mount-points-and-filesystems + keywords: + - scaleio + related_resources: + integrations: + list: [] + info_provided_to_referring_integrations: + description: "" + most_popular: false + overview: + data_collection: + metrics_description: | + This collector monitors ScaleIO (VxFlex OS) instances via VxFlex OS Gateway API. + + It collects metrics for the following ScaleIO components: + + - System + - Storage Pool + - Sdc + method_description: "" + supported_platforms: + include: [] + exclude: [] + multi_instance: true + additional_permissions: + description: "" + default_behavior: + auto_detection: + description: "" + limits: + description: "" + performance_impact: + description: "" + setup: + prerequisites: + list: [] + configuration: + file: + name: go.d/scaleio.conf + options: + description: | + The following options can be defined globally: update_every, autodetection_retry. + folding: + title: Config options + enabled: true + list: + - name: update_every + description: Data collection frequency. + default_value: 5 + required: false + - name: autodetection_retry + description: Recheck interval in seconds. Zero means no recheck will be scheduled. + default_value: 0 + required: false + - name: url + description: Server URL. + default_value: https://127.0.0.1:80 + required: true + - name: timeout + description: HTTP request timeout. + default_value: 1 + required: false + - name: username + description: Username for basic HTTP authentication. + default_value: "" + required: true + - name: password + description: Password for basic HTTP authentication. + default_value: "" + required: true + - name: proxy_url + description: Proxy URL. + default_value: "" + required: false + - name: proxy_username + description: Username for proxy basic HTTP authentication. + default_value: "" + required: false + - name: proxy_password + description: Password for proxy basic HTTP authentication. + default_value: "" + required: false + - name: method + description: HTTP request method. + default_value: GET + required: false + - name: body + description: HTTP request body. + default_value: "" + required: false + - name: headers + description: HTTP request headers. + default_value: "" + required: false + - name: not_follow_redirects + description: Redirect handling policy. Controls whether the client follows redirects. + default_value: false + required: false + - name: tls_skip_verify + description: Server certificate chain and hostname validation policy. Controls whether the client performs this check. + default_value: false + required: false + - name: tls_ca + description: Certification authority that the client uses when verifying the server's certificates. + default_value: "" + required: false + - name: tls_cert + description: Client TLS certificate. + default_value: "" + required: false + - name: tls_key + description: Client TLS key. + default_value: "" + required: false + examples: + folding: + title: Config + enabled: true + list: + - name: Basic + description: An example configuration. + config: | + jobs: + - name: local + url: https://127.0.0.1 + username: admin + password: password + tls_skip_verify: yes # self-signed certificate + - name: Multi-instance + description: | + > **Note**: When you define multiple jobs, their names must be unique. + + Local and remote instance. + config: | + jobs: + - name: local + url: https://127.0.0.1 + username: admin + password: password + tls_skip_verify: yes # self-signed certificate + + - name: remote + url: https://203.0.113.10 + username: admin + password: password + tls_skip_verify: yes + troubleshooting: + problems: + list: [] + alerts: [] + metrics: + folding: + title: Metrics + enabled: false + description: "" + availability: [] + scopes: + - name: global + description: These metrics refer to the entire monitored application. + labels: [] + metrics: + - name: scaleio.system_capacity_total + description: Total Capacity + unit: KiB + chart_type: line + dimensions: + - name: total + - name: scaleio.system_capacity_in_use + description: Capacity In Use + unit: KiB + chart_type: line + dimensions: + - name: in_use + - name: scaleio.system_capacity_usage + description: Capacity Usage + unit: KiB + chart_type: stacked + dimensions: + - name: thick + - name: decreased + - name: thin + - name: snapshot + - name: spare + - name: unused + - name: scaleio.system_capacity_available_volume_allocation + description: Available For Volume Allocation + unit: KiB + chart_type: line + dimensions: + - name: available + - name: scaleio.system_capacity_health_state + description: Capacity Health State + unit: KiB + chart_type: stacked + dimensions: + - name: protected + - name: degraded + - name: in_maintenance + - name: failed + - name: unavailable + - name: scaleio.system_workload_primary_bandwidth_total + description: Primary Backend Bandwidth Total (Read and Write) + unit: KiB/s + chart_type: line + dimensions: + - name: total + - name: scaleio.system_workload_primary_bandwidth + description: Primary Backend Bandwidth + unit: KiB/s + chart_type: area + dimensions: + - name: read + - name: write + - name: scaleio.system_workload_primary_iops_total + description: Primary Backend IOPS Total (Read and Write) + unit: iops/s + chart_type: line + dimensions: + - name: total + - name: scaleio.system_workload_primary_iops + description: Primary Backend IOPS + unit: iops/s + chart_type: area + dimensions: + - name: read + - name: write + - name: scaleio.system_workload_primary_io_size_total + description: Primary Backend I/O Size Total (Read and Write) + unit: KiB + chart_type: line + dimensions: + - name: io_size + - name: scaleio.system_rebalance + description: Rebalance + unit: KiB/s + chart_type: area + dimensions: + - name: read + - name: write + - name: scaleio.system_rebalance_left + description: Rebalance Pending Capacity + unit: KiB + chart_type: line + dimensions: + - name: left + - name: scaleio.system_rebalance_time_until_finish + description: Rebalance Approximate Time Until Finish + unit: seconds + chart_type: line + dimensions: + - name: time + - name: scaleio.system_rebuild + description: Rebuild Bandwidth Total (Forward, Backward and Normal) + unit: KiB/s + chart_type: area + dimensions: + - name: read + - name: write + - name: scaleio.system_rebuild_left + description: Rebuild Pending Capacity Total (Forward, Backward and Normal) + unit: KiB + chart_type: line + dimensions: + - name: left + - name: scaleio.system_defined_components + description: Components + unit: components + chart_type: line + dimensions: + - name: devices + - name: fault_sets + - name: protection_domains + - name: rfcache_devices + - name: sdc + - name: sds + - name: snapshots + - name: storage_pools + - name: volumes + - name: vtrees + - name: scaleio.system_components_volumes_by_type + description: Volumes By Type + unit: volumes + chart_type: stacked + dimensions: + - name: thick + - name: thin + - name: scaleio.system_components_volumes_by_mapping + description: Volumes By Mapping + unit: volumes + chart_type: stacked + dimensions: + - name: mapped + - name: unmapped + - name: storage pool + description: These metrics refer to the storage pool. + labels: [] + metrics: + - name: scaleio.storage_pool_capacity_total + description: Total Capacity + unit: KiB + chart_type: line + dimensions: + - name: total + - name: scaleio.storage_pool_capacity_in_use + description: Capacity In Use + unit: KiB + chart_type: line + dimensions: + - name: in_use + - name: scaleio.storage_pool_capacity_usage + description: Capacity Usage + unit: KiB + chart_type: stacked + dimensions: + - name: thick + - name: decreased + - name: thin + - name: snapshot + - name: spare + - name: unused + - name: scaleio.storage_pool_capacity_utilization + description: Capacity Utilization + unit: percentage + chart_type: line + dimensions: + - name: used + - name: scaleio.storage_pool_capacity_available_volume_allocation + description: Available For Volume Allocation + unit: KiB + chart_type: line + dimensions: + - name: available + - name: scaleio.storage_pool_capacity_health_state + description: Capacity Health State + unit: KiB + chart_type: stacked + dimensions: + - name: protected + - name: degraded + - name: in_maintenance + - name: failed + - name: unavailable + - name: scaleio.storage_pool_components + description: Components + unit: components + chart_type: line + dimensions: + - name: devices + - name: snapshots + - name: volumes + - name: vtrees + - name: sdc + description: These metrics refer to the SDC (ScaleIO Data Client). + labels: [] + metrics: + - name: scaleio.sdc_mdm_connection_state + description: MDM Connection State + unit: boolean + chart_type: line + dimensions: + - name: connected + - name: scaleio.sdc_bandwidth + description: Bandwidth + unit: KiB/s + chart_type: area + dimensions: + - name: read + - name: write + - name: scaleio.sdc_iops + description: IOPS + unit: iops/s + chart_type: area + dimensions: + - name: read + - name: write + - name: scaleio.sdc_io_size + description: IOPS Size + unit: KiB + chart_type: area + dimensions: + - name: read + - name: write + - name: scaleio.sdc_num_of_mapped_volumed + description: Mapped Volumes + unit: volumes + chart_type: line + dimensions: + - name: mapped diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/metrics.go b/src/go/collectors/go.d.plugin/modules/scaleio/metrics.go new file mode 100644 index 000000000..a5a9b9810 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/metrics.go @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package scaleio + +type metrics struct { + System systemMetrics `stm:"system"` + Sdc map[string]sdcMetrics `stm:"sdc"` + StoragePool map[string]storagePoolMetrics `stm:"storage_pool"` +} + +type capacity struct { + MaxCapacity int64 `stm:"max_capacity"` + ThickInUse int64 `stm:"thick_in_use"` + ThinInUse int64 `stm:"thin_in_use"` + Snapshot int64 `stm:"snapshot"` + Spare int64 `stm:"spare"` + Decreased int64 `stm:"decreased"` // not in statistics, should be calculated + Unused int64 `stm:"unused"` + + InUse int64 `stm:"in_use"` + AvailableForVolumeAllocation int64 `stm:"available_for_volume_allocation"` + + Protected int64 `stm:"protected"` + InMaintenance int64 `stm:"in_maintenance"` + Degraded int64 `stm:"degraded"` + Failed int64 `stm:"failed"` + UnreachableUnused int64 `stm:"unreachable_unused"` +} + +type ( + systemMetrics struct { + Capacity systemCapacity `stm:"capacity"` + Workload systemWorkload `stm:""` + Rebalance systemRebalance `stm:"rebalance"` + Rebuild systemRebuild `stm:"rebuild"` + Components systemComponents `stm:"num_of"` + } + systemCapacity = capacity + systemComponents struct { + Devices int64 `stm:"devices"` + FaultSets int64 `stm:"fault_sets"` + ProtectionDomains int64 `stm:"protection_domains"` + RfcacheDevices int64 `stm:"rfcache_devices"` + Sdc int64 `stm:"sdc"` + Sds int64 `stm:"sds"` + Snapshots int64 `stm:"snapshots"` + StoragePools int64 `stm:"storage_pools"` + MappedToAllVolumes int64 `stm:"mapped_to_all_volumes"` + ThickBaseVolumes int64 `stm:"thick_base_volumes"` + ThinBaseVolumes int64 `stm:"thin_base_volumes"` + UnmappedVolumes int64 `stm:"unmapped_volumes"` + MappedVolumes int64 `stm:"mapped_volumes"` + Volumes int64 `stm:"volumes"` + VTrees int64 `stm:"vtrees"` + } + systemWorkload struct { + Total bwIOPS `stm:"total"` + Backend struct { + Total bwIOPS `stm:"total"` + Primary bwIOPS `stm:"primary"` + Secondary bwIOPS `stm:"secondary"` + } `stm:"backend"` + Frontend bwIOPS `stm:"frontend_user_data"` + } + systemRebalance struct { + TimeUntilFinish float64 `stm:"time_until_finish"` + bwIOPSPending `stm:""` + } + systemRebuild struct { + Total bwIOPSPending `stm:"total"` + Forward bwIOPSPending `stm:"forward"` + Backward bwIOPSPending `stm:"backward"` + Normal bwIOPSPending `stm:"normal"` + } +) + +type ( + sdcMetrics struct { + bwIOPS `stm:""` + MappedVolumes int64 `stm:"num_of_mapped_volumes"` + MDMConnectionState bool `stm:"mdm_connection_state"` + } +) + +type ( + storagePoolMetrics struct { + Capacity storagePoolCapacity `stm:"capacity"` + Components struct { + Devices int64 `stm:"devices"` + Volumes int64 `stm:"volumes"` + Vtrees int64 `stm:"vtrees"` + Snapshots int64 `stm:"snapshots"` + } `stm:"num_of"` + } + storagePoolCapacity struct { + capacity `stm:""` + Utilization float64 `stm:"utilization,100,1"` // TODO: only StoragePool (sparePercentage) + AlertThreshold struct { + Critical int64 `stm:"critical_threshold"` + High int64 `stm:"high_threshold"` + } `stm:"alert"` + } +) + +type ( + readWrite struct { + Read float64 `stm:"read,1000,1"` + Write float64 `stm:"write,1000,1"` + ReadWrite float64 `stm:"read_write,1000,1"` + } + bwIOPS struct { + BW readWrite `stm:"bandwidth"` + IOPS readWrite `stm:"iops"` + IOSize readWrite `stm:"io_size"` + } + bwIOPSPending struct { + bwIOPS `stm:""` + Pending int64 `stm:"pending_capacity_in_Kb"` + } +) + +func (rw *readWrite) set(r, w float64) { + rw.Read = r + rw.Write = w + rw.ReadWrite = r + w +} diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/queries.go b/src/go/collectors/go.d.plugin/modules/scaleio/queries.go new file mode 100644 index 000000000..265c3b874 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/queries.go @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package scaleio + +import "github.com/netdata/netdata/go/go.d.plugin/modules/scaleio/client" + +/* +Starting from version 3 of ScaleIO/VxFlex API numOfScsiInitiators property is removed from the system selectedStatisticsQuery. +Reference: VxFlex OS v3.x REST API Reference Guide.pdf +*/ + +var query = client.SelectedStatisticsQuery{ + List: []client.SelectedObject{ + { + Type: "System", + Properties: []string{ + "maxCapacityInKb", + "thickCapacityInUseInKb", + "thinCapacityInUseInKb", + "snapCapacityInUseOccupiedInKb", + "spareCapacityInKb", + "capacityLimitInKb", + + "protectedCapacityInKb", + "degradedHealthyCapacityInKb", + "degradedFailedCapacityInKb", + "failedCapacityInKb", + "unreachableUnusedCapacityInKb", + "inMaintenanceCapacityInKb", + + "capacityInUseInKb", + "capacityAvailableForVolumeAllocationInKb", + + "numOfDevices", + "numOfFaultSets", + "numOfProtectionDomains", + "numOfRfcacheDevices", + "numOfSdc", + "numOfSds", + "numOfSnapshots", + "numOfStoragePools", + "numOfVolumes", + "numOfVtrees", + "numOfThickBaseVolumes", + "numOfThinBaseVolumes", + "numOfMappedToAllVolumes", + "numOfUnmappedVolumes", + + "rebalanceReadBwc", + "rebalanceWriteBwc", + "pendingRebalanceCapacityInKb", + + "pendingNormRebuildCapacityInKb", + "pendingBckRebuildCapacityInKb", + "pendingFwdRebuildCapacityInKb", + "normRebuildReadBwc", + "normRebuildWriteBwc", + "bckRebuildReadBwc", + "bckRebuildWriteBwc", + "fwdRebuildReadBwc", + "fwdRebuildWriteBwc", + + "primaryReadBwc", + "primaryWriteBwc", + "secondaryReadBwc", + "secondaryWriteBwc", + "userDataReadBwc", + "userDataWriteBwc", + "totalReadBwc", + "totalWriteBwc", + }, + }, + { + Type: "StoragePool", + AllIDs: true, + Properties: []string{ + "maxCapacityInKb", + "thickCapacityInUseInKb", + "thinCapacityInUseInKb", + "snapCapacityInUseOccupiedInKb", + "spareCapacityInKb", + "capacityLimitInKb", + + "protectedCapacityInKb", + "degradedHealthyCapacityInKb", + "degradedFailedCapacityInKb", + "failedCapacityInKb", + "unreachableUnusedCapacityInKb", + "inMaintenanceCapacityInKb", + + "capacityInUseInKb", + "capacityAvailableForVolumeAllocationInKb", + + "numOfDevices", + "numOfVolumes", + "numOfVtrees", + "numOfSnapshots", + }, + }, + { + Type: "Sdc", + AllIDs: true, + Properties: []string{ + "userDataReadBwc", + "userDataWriteBwc", + + "numOfMappedVolumes", + }, + }, + }, +} diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/scaleio.go b/src/go/collectors/go.d.plugin/modules/scaleio/scaleio.go new file mode 100644 index 000000000..4cc8e69a9 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/scaleio.go @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package scaleio + +import ( + _ "embed" + "errors" + "time" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + "github.com/netdata/netdata/go/go.d.plugin/modules/scaleio/client" + "github.com/netdata/netdata/go/go.d.plugin/pkg/web" +) + +//go:embed "config_schema.json" +var configSchema string + +func init() { + module.Register("scaleio", module.Creator{ + JobConfigSchema: configSchema, + Create: func() module.Module { return New() }, + Config: func() any { return &Config{} }, + }) +} + +func New() *ScaleIO { + return &ScaleIO{ + Config: Config{ + HTTP: web.HTTP{ + Request: web.Request{ + URL: "https://127.0.0.1", + }, + Client: web.Client{ + Timeout: web.Duration(time.Second), + }, + }, + }, + charts: systemCharts.Copy(), + charted: make(map[string]bool), + } +} + +type Config struct { + UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"` + web.HTTP `yaml:",inline" json:""` +} + +type ( + ScaleIO struct { + module.Base + Config `yaml:",inline" json:""` + + charts *module.Charts + + client *client.Client + + discovered instances + charted map[string]bool + lastDiscoveryOK bool + runs int + } + instances struct { + sdc map[string]client.Sdc + pool map[string]client.StoragePool + } +) + +func (s *ScaleIO) Configuration() any { + return s.Config +} + +func (s *ScaleIO) Init() error { + if s.Username == "" || s.Password == "" { + s.Error("username and password aren't set") + return errors.New("username and password aren't set") + } + + c, err := client.New(s.Client, s.Request) + if err != nil { + s.Errorf("error on creating ScaleIO client: %v", err) + return err + } + s.client = c + + s.Debugf("using URL %s", s.URL) + s.Debugf("using timeout: %s", s.Timeout) + + return nil +} + +func (s *ScaleIO) Check() error { + if err := s.client.Login(); err != nil { + s.Error(err) + return err + } + mx, err := s.collect() + if err != nil { + s.Error(err) + return err + } + if len(mx) == 0 { + return errors.New("no metrics collected") + } + return nil +} + +func (s *ScaleIO) Charts() *module.Charts { + return s.charts +} + +func (s *ScaleIO) Collect() map[string]int64 { + mx, err := s.collect() + if err != nil { + s.Error(err) + return nil + } + + if len(mx) == 0 { + return nil + } + return mx +} + +func (s *ScaleIO) Cleanup() { + if s.client == nil { + return + } + _ = s.client.Logout() +} diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/scaleio_test.go b/src/go/collectors/go.d.plugin/modules/scaleio/scaleio_test.go new file mode 100644 index 000000000..970ee263d --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/scaleio_test.go @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package scaleio + +import ( + "encoding/json" + "net/http/httptest" + "os" + "testing" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + "github.com/netdata/netdata/go/go.d.plugin/modules/scaleio/client" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + dataConfigJSON, _ = os.ReadFile("testdata/config.json") + dataConfigYAML, _ = os.ReadFile("testdata/config.yaml") + + dataSelectedStatistics, _ = os.ReadFile("testdata/selected_statistics.json") + dataInstances, _ = os.ReadFile("testdata/instances.json") +) + +func Test_testDataIsValid(t *testing.T) { + for name, data := range map[string][]byte{ + "dataConfigJSON": dataConfigJSON, + "dataConfigYAML": dataConfigYAML, + "dataSelectedStatistics": dataSelectedStatistics, + "dataInstances": dataInstances, + } { + require.NotNil(t, data, name) + } +} + +func TestScaleIO_ConfigurationSerialize(t *testing.T) { + module.TestConfigurationSerialize(t, &ScaleIO{}, dataConfigJSON, dataConfigYAML) +} + +func TestScaleIO_Init(t *testing.T) { + scaleIO := New() + scaleIO.Username = "username" + scaleIO.Password = "password" + + assert.NoError(t, scaleIO.Init()) +} +func TestScaleIO_Init_UsernameAndPasswordNotSet(t *testing.T) { + assert.Error(t, New().Init()) +} + +func TestScaleIO_Init_ErrorOnCreatingClientWrongTLSCA(t *testing.T) { + job := New() + job.Username = "username" + job.Password = "password" + job.Client.TLSConfig.TLSCA = "testdata/tls" + + assert.Error(t, job.Init()) +} + +func TestScaleIO_Check(t *testing.T) { + srv, _, scaleIO := prepareSrvMockScaleIO(t) + defer srv.Close() + require.NoError(t, scaleIO.Init()) + + assert.NoError(t, scaleIO.Check()) +} + +func TestScaleIO_Check_ErrorOnLogin(t *testing.T) { + srv, mock, scaleIO := prepareSrvMockScaleIO(t) + defer srv.Close() + require.NoError(t, scaleIO.Init()) + mock.Password = "new password" + + assert.Error(t, scaleIO.Check()) +} + +func TestScaleIO_Charts(t *testing.T) { + assert.NotNil(t, New().Charts()) +} + +func TestScaleIO_Cleanup(t *testing.T) { + srv, _, scaleIO := prepareSrvMockScaleIO(t) + defer srv.Close() + require.NoError(t, scaleIO.Init()) + require.NoError(t, scaleIO.Check()) + + scaleIO.Cleanup() + assert.False(t, scaleIO.client.LoggedIn()) +} + +func TestScaleIO_Collect(t *testing.T) { + srv, _, scaleIO := prepareSrvMockScaleIO(t) + defer srv.Close() + require.NoError(t, scaleIO.Init()) + require.NoError(t, scaleIO.Check()) + + expected := map[string]int64{ + "sdc_6076fd0f00000000_bandwidth_read": 0, + "sdc_6076fd0f00000000_bandwidth_read_write": 0, + "sdc_6076fd0f00000000_bandwidth_write": 0, + "sdc_6076fd0f00000000_io_size_read": 0, + "sdc_6076fd0f00000000_io_size_read_write": 0, + "sdc_6076fd0f00000000_io_size_write": 0, + "sdc_6076fd0f00000000_iops_read": 0, + "sdc_6076fd0f00000000_iops_read_write": 0, + "sdc_6076fd0f00000000_iops_write": 0, + "sdc_6076fd0f00000000_mdm_connection_state": 1, + "sdc_6076fd0f00000000_num_of_mapped_volumes": 1, + "sdc_6076fd1000000001_bandwidth_read": 1000, + "sdc_6076fd1000000001_bandwidth_read_write": 117400000, + "sdc_6076fd1000000001_bandwidth_write": 117399000, + "sdc_6076fd1000000001_io_size_read": 1000, + "sdc_6076fd1000000001_io_size_read_write": 695668, + "sdc_6076fd1000000001_io_size_write": 694668, + "sdc_6076fd1000000001_iops_read": 1000, + "sdc_6076fd1000000001_iops_read_write": 170000, + "sdc_6076fd1000000001_iops_write": 169000, + "sdc_6076fd1000000001_mdm_connection_state": 0, + "sdc_6076fd1000000001_num_of_mapped_volumes": 1, + "sdc_6076fd1100000002_bandwidth_read": 0, + "sdc_6076fd1100000002_bandwidth_read_write": 118972000, + "sdc_6076fd1100000002_bandwidth_write": 118972000, + "sdc_6076fd1100000002_io_size_read": 0, + "sdc_6076fd1100000002_io_size_read_write": 820496, + "sdc_6076fd1100000002_io_size_write": 820496, + "sdc_6076fd1100000002_iops_read": 0, + "sdc_6076fd1100000002_iops_read_write": 145000, + "sdc_6076fd1100000002_iops_write": 145000, + "sdc_6076fd1100000002_mdm_connection_state": 0, + "sdc_6076fd1100000002_num_of_mapped_volumes": 1, + "storage_pool_40395b7b00000000_capacity_alert_critical_threshold": 90, + "storage_pool_40395b7b00000000_capacity_alert_high_threshold": 80, + "storage_pool_40395b7b00000000_capacity_available_for_volume_allocation": 100663296, + "storage_pool_40395b7b00000000_capacity_decreased": 0, + "storage_pool_40395b7b00000000_capacity_degraded": 0, + "storage_pool_40395b7b00000000_capacity_failed": 0, + "storage_pool_40395b7b00000000_capacity_in_maintenance": 0, + "storage_pool_40395b7b00000000_capacity_in_use": 50110464, + "storage_pool_40395b7b00000000_capacity_max_capacity": 311424000, + "storage_pool_40395b7b00000000_capacity_protected": 50110464, + "storage_pool_40395b7b00000000_capacity_snapshot": 749568, + "storage_pool_40395b7b00000000_capacity_spare": 31141888, + "storage_pool_40395b7b00000000_capacity_thick_in_use": 0, + "storage_pool_40395b7b00000000_capacity_thin_in_use": 49360896, + "storage_pool_40395b7b00000000_capacity_unreachable_unused": 0, + "storage_pool_40395b7b00000000_capacity_unused": 229422080, + "storage_pool_40395b7b00000000_capacity_utilization": 1787, + "storage_pool_40395b7b00000000_num_of_devices": 3, + "storage_pool_40395b7b00000000_num_of_snapshots": 1, + "storage_pool_40395b7b00000000_num_of_volumes": 3, + "storage_pool_40395b7b00000000_num_of_vtrees": 2, + "storage_pool_4039828b00000001_capacity_alert_critical_threshold": 90, + "storage_pool_4039828b00000001_capacity_alert_high_threshold": 80, + "storage_pool_4039828b00000001_capacity_available_for_volume_allocation": 142606336, + "storage_pool_4039828b00000001_capacity_decreased": 0, + "storage_pool_4039828b00000001_capacity_degraded": 0, + "storage_pool_4039828b00000001_capacity_failed": 0, + "storage_pool_4039828b00000001_capacity_in_maintenance": 0, + "storage_pool_4039828b00000001_capacity_in_use": 0, + "storage_pool_4039828b00000001_capacity_max_capacity": 332395520, + "storage_pool_4039828b00000001_capacity_protected": 0, + "storage_pool_4039828b00000001_capacity_snapshot": 0, + "storage_pool_4039828b00000001_capacity_spare": 33239040, + "storage_pool_4039828b00000001_capacity_thick_in_use": 0, + "storage_pool_4039828b00000001_capacity_thin_in_use": 0, + "storage_pool_4039828b00000001_capacity_unreachable_unused": 0, + "storage_pool_4039828b00000001_capacity_unused": 299156480, + "storage_pool_4039828b00000001_capacity_utilization": 0, + "storage_pool_4039828b00000001_num_of_devices": 3, + "storage_pool_4039828b00000001_num_of_snapshots": 0, + "storage_pool_4039828b00000001_num_of_volumes": 0, + "storage_pool_4039828b00000001_num_of_vtrees": 0, + "system_backend_primary_bandwidth_read": 800, + "system_backend_primary_bandwidth_read_write": 238682400, + "system_backend_primary_bandwidth_write": 238681600, + "system_backend_primary_io_size_read": 4000, + "system_backend_primary_io_size_read_write": 770971, + "system_backend_primary_io_size_write": 766971, + "system_backend_primary_iops_read": 200, + "system_backend_primary_iops_read_write": 311400, + "system_backend_primary_iops_write": 311200, + "system_backend_secondary_bandwidth_read": 0, + "system_backend_secondary_bandwidth_read_write": 233926400, + "system_backend_secondary_bandwidth_write": 233926400, + "system_backend_secondary_io_size_read": 0, + "system_backend_secondary_io_size_read_write": 764465, + "system_backend_secondary_io_size_write": 764465, + "system_backend_secondary_iops_read": 0, + "system_backend_secondary_iops_read_write": 306000, + "system_backend_secondary_iops_write": 306000, + "system_backend_total_bandwidth_read": 800, + "system_backend_total_bandwidth_read_write": 472608800, + "system_backend_total_bandwidth_write": 472608000, + "system_backend_total_io_size_read": 4000, + "system_backend_total_io_size_read_write": 1535437, + "system_backend_total_io_size_write": 1531437, + "system_backend_total_iops_read": 200, + "system_backend_total_iops_read_write": 617400, + "system_backend_total_iops_write": 617200, + "system_capacity_available_for_volume_allocation": 243269632, + "system_capacity_decreased": 0, + "system_capacity_degraded": 0, + "system_capacity_failed": 0, + "system_capacity_in_maintenance": 0, + "system_capacity_in_use": 50110464, + "system_capacity_max_capacity": 643819520, + "system_capacity_protected": 50110464, + "system_capacity_snapshot": 749568, + "system_capacity_spare": 64380928, + "system_capacity_thick_in_use": 0, + "system_capacity_thin_in_use": 49360896, + "system_capacity_unreachable_unused": 0, + "system_capacity_unused": 528578560, + "system_frontend_user_data_bandwidth_read": 0, + "system_frontend_user_data_bandwidth_read_write": 227170000, + "system_frontend_user_data_bandwidth_write": 227170000, + "system_frontend_user_data_io_size_read": 0, + "system_frontend_user_data_io_size_read_write": 797087, + "system_frontend_user_data_io_size_write": 797087, + "system_frontend_user_data_iops_read": 0, + "system_frontend_user_data_iops_read_write": 285000, + "system_frontend_user_data_iops_write": 285000, + "system_num_of_devices": 6, + "system_num_of_fault_sets": 0, + "system_num_of_mapped_to_all_volumes": 0, + "system_num_of_mapped_volumes": 3, + "system_num_of_protection_domains": 1, + "system_num_of_rfcache_devices": 0, + "system_num_of_sdc": 3, + "system_num_of_sds": 3, + "system_num_of_snapshots": 1, + "system_num_of_storage_pools": 2, + "system_num_of_thick_base_volumes": 0, + "system_num_of_thin_base_volumes": 2, + "system_num_of_unmapped_volumes": 0, + "system_num_of_volumes": 3, + "system_num_of_vtrees": 2, + "system_rebalance_bandwidth_read": 0, + "system_rebalance_bandwidth_read_write": 0, + "system_rebalance_bandwidth_write": 0, + "system_rebalance_io_size_read": 0, + "system_rebalance_io_size_read_write": 0, + "system_rebalance_io_size_write": 0, + "system_rebalance_iops_read": 0, + "system_rebalance_iops_read_write": 0, + "system_rebalance_iops_write": 0, + "system_rebalance_pending_capacity_in_Kb": 0, + "system_rebalance_time_until_finish": 0, + "system_rebuild_backward_bandwidth_read": 0, + "system_rebuild_backward_bandwidth_read_write": 0, + "system_rebuild_backward_bandwidth_write": 0, + "system_rebuild_backward_io_size_read": 0, + "system_rebuild_backward_io_size_read_write": 0, + "system_rebuild_backward_io_size_write": 0, + "system_rebuild_backward_iops_read": 0, + "system_rebuild_backward_iops_read_write": 0, + "system_rebuild_backward_iops_write": 0, + "system_rebuild_backward_pending_capacity_in_Kb": 0, + "system_rebuild_forward_bandwidth_read": 0, + "system_rebuild_forward_bandwidth_read_write": 0, + "system_rebuild_forward_bandwidth_write": 0, + "system_rebuild_forward_io_size_read": 0, + "system_rebuild_forward_io_size_read_write": 0, + "system_rebuild_forward_io_size_write": 0, + "system_rebuild_forward_iops_read": 0, + "system_rebuild_forward_iops_read_write": 0, + "system_rebuild_forward_iops_write": 0, + "system_rebuild_forward_pending_capacity_in_Kb": 0, + "system_rebuild_normal_bandwidth_read": 0, + "system_rebuild_normal_bandwidth_read_write": 0, + "system_rebuild_normal_bandwidth_write": 0, + "system_rebuild_normal_io_size_read": 0, + "system_rebuild_normal_io_size_read_write": 0, + "system_rebuild_normal_io_size_write": 0, + "system_rebuild_normal_iops_read": 0, + "system_rebuild_normal_iops_read_write": 0, + "system_rebuild_normal_iops_write": 0, + "system_rebuild_normal_pending_capacity_in_Kb": 0, + "system_rebuild_total_bandwidth_read": 0, + "system_rebuild_total_bandwidth_read_write": 0, + "system_rebuild_total_bandwidth_write": 0, + "system_rebuild_total_io_size_read": 0, + "system_rebuild_total_io_size_read_write": 0, + "system_rebuild_total_io_size_write": 0, + "system_rebuild_total_iops_read": 0, + "system_rebuild_total_iops_read_write": 0, + "system_rebuild_total_iops_write": 0, + "system_rebuild_total_pending_capacity_in_Kb": 0, + "system_total_bandwidth_read": 800, + "system_total_bandwidth_read_write": 472608800, + "system_total_bandwidth_write": 472608000, + "system_total_io_size_read": 4000, + "system_total_io_size_read_write": 769729, + "system_total_io_size_write": 765729, + "system_total_iops_read": 200, + "system_total_iops_read_write": 617400, + "system_total_iops_write": 617200, + } + + collected := scaleIO.Collect() + assert.Equal(t, expected, collected) + testCharts(t, scaleIO, collected) +} + +func TestScaleIO_Collect_ConnectionRefused(t *testing.T) { + srv, _, scaleIO := prepareSrvMockScaleIO(t) + defer srv.Close() + require.NoError(t, scaleIO.Init()) + require.NoError(t, scaleIO.Check()) + scaleIO.client.Request.URL = "http://127.0.0.1:38001" + + assert.Nil(t, scaleIO.Collect()) +} + +func testCharts(t *testing.T, scaleIO *ScaleIO, collected map[string]int64) { + t.Helper() + ensureStoragePoolChartsAreCreated(t, scaleIO) + ensureSdcChartsAreCreated(t, scaleIO) + ensureCollectedHasAllChartsDimsVarsIDs(t, scaleIO, collected) +} + +func ensureStoragePoolChartsAreCreated(t *testing.T, scaleIO *ScaleIO) { + for _, pool := range scaleIO.discovered.pool { + for _, chart := range *newStoragePoolCharts(pool) { + assert.Truef(t, scaleIO.Charts().Has(chart.ID), "chart '%s' is not created", chart.ID) + } + } +} + +func ensureSdcChartsAreCreated(t *testing.T, scaleIO *ScaleIO) { + for _, sdc := range scaleIO.discovered.sdc { + for _, chart := range *newSdcCharts(sdc) { + assert.Truef(t, scaleIO.Charts().Has(chart.ID), "chart '%s' is not created", chart.ID) + } + } +} + +func ensureCollectedHasAllChartsDimsVarsIDs(t *testing.T, scaleIO *ScaleIO, collected map[string]int64) { + for _, chart := range *scaleIO.Charts() { + for _, dim := range chart.Dims { + _, ok := collected[dim.ID] + assert.Truef(t, ok, "collected metrics has no data for dim '%s' chart '%s'", dim.ID, chart.ID) + } + for _, v := range chart.Vars { + _, ok := collected[v.ID] + assert.Truef(t, ok, "collected metrics has no data for var '%s' chart '%s'", v.ID, chart.ID) + } + } +} + +func prepareSrvMockScaleIO(t *testing.T) (*httptest.Server, *client.MockScaleIOAPIServer, *ScaleIO) { + t.Helper() + const ( + user = "user" + password = "password" + version = "2.5" + token = "token" + ) + var stats client.SelectedStatistics + err := json.Unmarshal(dataSelectedStatistics, &stats) + require.NoError(t, err) + + var ins client.Instances + err = json.Unmarshal(dataInstances, &ins) + require.NoError(t, err) + + mock := client.MockScaleIOAPIServer{ + User: user, + Password: password, + Version: version, + Token: token, + Instances: ins, + Statistics: stats, + } + srv := httptest.NewServer(&mock) + require.NoError(t, err) + + scaleIO := New() + scaleIO.URL = srv.URL + scaleIO.Username = user + scaleIO.Password = password + return srv, &mock, scaleIO +} diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/testdata/config.json b/src/go/collectors/go.d.plugin/modules/scaleio/testdata/config.json new file mode 100644 index 000000000..984c3ed6e --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/testdata/config.json @@ -0,0 +1,20 @@ +{ + "update_every": 123, + "url": "ok", + "body": "ok", + "method": "ok", + "headers": { + "ok": "ok" + }, + "username": "ok", + "password": "ok", + "proxy_url": "ok", + "proxy_username": "ok", + "proxy_password": "ok", + "timeout": 123.123, + "not_follow_redirects": true, + "tls_ca": "ok", + "tls_cert": "ok", + "tls_key": "ok", + "tls_skip_verify": true +} diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/testdata/config.yaml b/src/go/collectors/go.d.plugin/modules/scaleio/testdata/config.yaml new file mode 100644 index 000000000..8558b61cc --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/testdata/config.yaml @@ -0,0 +1,17 @@ +update_every: 123 +url: "ok" +body: "ok" +method: "ok" +headers: + ok: "ok" +username: "ok" +password: "ok" +proxy_url: "ok" +proxy_username: "ok" +proxy_password: "ok" +timeout: 123.123 +not_follow_redirects: yes +tls_ca: "ok" +tls_cert: "ok" +tls_key: "ok" +tls_skip_verify: yes diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/testdata/instances.json b/src/go/collectors/go.d.plugin/modules/scaleio/testdata/instances.json new file mode 100644 index 000000000..bc8c6e8ac --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/testdata/instances.json @@ -0,0 +1,1160 @@ +{ + "System": { + "authenticationMethod": "Native", + "capacityAlertCriticalThresholdPercent": 90, + "capacityAlertHighThresholdPercent": 80, + "capacityTimeLeftInDays": "Unlimited", + "cliPasswordAllowed": true, + "daysInstalled": 17, + "defaultIsVolumeObfuscated": false, + "enterpriseFeaturesEnabled": true, + "id": "499634a44778afc0", + "installId": "3e9fc5811a7efb00", + "isInitialLicense": true, + "links": [ + { + "href": "/api/instances/System::499634a44778afc0", + "rel": "self" + }, + { + "href": "/api/instances/System::499634a44778afc0/relationships/Statistics", + "rel": "/api/System/relationship/Statistics" + }, + { + "href": "/api/instances/System::499634a44778afc0/relationships/ProtectionDomain", + "rel": "/api/System/relationship/ProtectionDomain" + }, + { + "href": "/api/instances/System::499634a44778afc0/relationships/Sdc", + "rel": "/api/System/relationship/Sdc" + }, + { + "href": "/api/instances/System::499634a44778afc0/relationships/User", + "rel": "/api/System/relationship/User" + } + ], + "managementClientSecureCommunicationEnabled": true, + "maxCapacityInGb": "Unlimited", + "mdmCluster": { + "clusterMode": "ThreeNodes", + "clusterState": "ClusteredNormal", + "goodNodesNum": 3, + "goodReplicasNum": 2, + "id": "5302483491453710272", + "master": { + "id": "65ed0ee3247d0a00", + "ips": [ + "100.127.0.10" + ], + "managementIPs": [ + "100.127.0.10" + ], + "name": "Manager1", + "opensslVersion": "OpenSSL 1.0.2g 1 Mar 2016", + "port": 9011, + "role": "Manager", + "versionInfo": "R2_6.11000.0", + "virtualInterfaces": [] + }, + "slaves": [ + { + "id": "4cc44104130ce7b1", + "ips": [ + "100.127.0.11" + ], + "managementIPs": [ + "100.127.0.11" + ], + "name": "Manager2", + "opensslVersion": "OpenSSL 1.0.2g 1 Mar 2016", + "port": 9011, + "role": "Manager", + "status": "Normal", + "versionInfo": "R2_6.11000.0", + "virtualInterfaces": [] + } + ], + "tieBreakers": [ + { + "id": "35bf9d62661a6db2", + "ips": [ + "100.127.0.12" + ], + "managementIPs": [ + "100.127.0.12" + ], + "name": "Tie-Breaker1", + "opensslVersion": "N/A", + "port": 9011, + "role": "TieBreaker", + "status": "Normal", + "versionInfo": "R2_6.11000.0" + } + ] + }, + "mdmManagementPort": 6611, + "mdmToSdsPolicy": "Authentication", + "perfProfile": "Default", + "remoteReadOnlyLimitState": false, + "restrictedSdcMode": "None", + "restrictedSdcModeEnabled": false, + "sdcLongOperationsCounterParameters": { + "longWindow": { + "threshold": 1000000, + "windowSizeInSec": 86400 + }, + "mediumWindow": { + "threshold": 100000, + "windowSizeInSec": 3600 + }, + "shortWindow": { + "threshold": 10000, + "windowSizeInSec": 60 + } + }, + "sdcMdmNetworkDisconnectionsCounterParameters": { + "longWindow": { + "threshold": 700, + "windowSizeInSec": 86400 + }, + "mediumWindow": { + "threshold": 500, + "windowSizeInSec": 3600 + }, + "shortWindow": { + "threshold": 300, + "windowSizeInSec": 60 + } + }, + "sdcMemoryAllocationFailuresCounterParameters": { + "longWindow": { + "threshold": 700, + "windowSizeInSec": 86400 + }, + "mediumWindow": { + "threshold": 500, + "windowSizeInSec": 3600 + }, + "shortWindow": { + "threshold": 300, + "windowSizeInSec": 60 + } + }, + "sdcSdsConnectivityInfo": { + "disconnectedSdcId": null, + "disconnectedSdcName": null, + "disconnectedSdsId": null, + "disconnectedSdsIp": null, + "disconnectedSdsName": null, + "sdcSdsConnectivityStatus": "AllConnected" + }, + "sdcSdsNetworkDisconnectionsCounterParameters": { + "longWindow": { + "threshold": 20000, + "windowSizeInSec": 86400 + }, + "mediumWindow": { + "threshold": 4000, + "windowSizeInSec": 3600 + }, + "shortWindow": { + "threshold": 800, + "windowSizeInSec": 60 + } + }, + "sdcSocketAllocationFailuresCounterParameters": { + "longWindow": { + "threshold": 700, + "windowSizeInSec": 86400 + }, + "mediumWindow": { + "threshold": 500, + "windowSizeInSec": 3600 + }, + "shortWindow": { + "threshold": 300, + "windowSizeInSec": 60 + } + }, + "showGuid": true, + "swid": "", + "systemVersionName": "DellEMC ScaleIO Version: R2_6.11000.113", + "tlsVersion": "TLSv1.2", + "upgradeState": "NoUpgrade" + }, + "deviceList": [ + { + "aggregatedState": "NeverFailed", + "capacityLimitInKb": 103808000, + "deviceCurrentPathName": "/dev/sdb", + "deviceOriginalPathName": "/dev/sdb", + "deviceState": "Normal", + "errorState": "None", + "id": "ebbf9d6500010000", + "ledSetting": "Off", + "links": [ + { + "href": "/api/instances/Device::ebbf9d6500010000", + "rel": "self" + }, + { + "href": "/api/instances/Device::ebbf9d6500010000/relationships/Statistics", + "rel": "/api/Device/relationship/Statistics" + }, + { + "href": "/api/instances/Sds::130dcabe00000001", + "rel": "/api/parent/relationship/sdsId" + }, + { + "href": "/api/instances/StoragePool::40395b7b00000000", + "rel": "/api/parent/relationship/storagePoolId" + } + ], + "longSuccessfulIos": { + "longWindow": null, + "mediumWindow": null, + "shortWindow": null + }, + "maxCapacityInKb": 103808000, + "name": "sdb", + "rfcacheErrorDeviceDoesNotExist": false, + "sdsId": "130dcabe00000001", + "ssdEndOfLifeState": "NeverFailed", + "storagePoolId": "40395b7b00000000", + "temperatureState": "NeverFailed" + }, + { + "aggregatedState": "NeverFailed", + "capacityLimitInKb": 114293760, + "deviceCurrentPathName": "/dev/sdc", + "deviceOriginalPathName": "/dev/sdc", + "deviceState": "Normal", + "errorState": "None", + "id": "ebbfc47300010001", + "ledSetting": "Off", + "links": [ + { + "href": "/api/instances/Device::ebbfc47300010001", + "rel": "self" + }, + { + "href": "/api/instances/Device::ebbfc47300010001/relationships/Statistics", + "rel": "/api/Device/relationship/Statistics" + }, + { + "href": "/api/instances/Sds::130dcabe00000001", + "rel": "/api/parent/relationship/sdsId" + }, + { + "href": "/api/instances/StoragePool::4039828b00000001", + "rel": "/api/parent/relationship/storagePoolId" + } + ], + "longSuccessfulIos": { + "longWindow": null, + "mediumWindow": null, + "shortWindow": null + }, + "maxCapacityInKb": 114293760, + "name": "sdc", + "rfcacheErrorDeviceDoesNotExist": false, + "sdsId": "130dcabe00000001", + "ssdEndOfLifeState": "NeverFailed", + "storagePoolId": "4039828b00000001", + "temperatureState": "NeverFailed" + }, + { + "aggregatedState": "NeverFailed", + "capacityLimitInKb": 103808000, + "deviceCurrentPathName": "/dev/sdb", + "deviceOriginalPathName": "/dev/sdb", + "deviceState": "Normal", + "errorState": "None", + "id": "ebbd9d6400000000", + "ledSetting": "Off", + "links": [ + { + "href": "/api/instances/Device::ebbd9d6400000000", + "rel": "self" + }, + { + "href": "/api/instances/Device::ebbd9d6400000000/relationships/Statistics", + "rel": "/api/Device/relationship/Statistics" + }, + { + "href": "/api/instances/Sds::130dcabd00000000", + "rel": "/api/parent/relationship/sdsId" + }, + { + "href": "/api/instances/StoragePool::40395b7b00000000", + "rel": "/api/parent/relationship/storagePoolId" + } + ], + "longSuccessfulIos": { + "longWindow": null, + "mediumWindow": null, + "shortWindow": null + }, + "maxCapacityInKb": 103808000, + "name": "sdb", + "rfcacheErrorDeviceDoesNotExist": false, + "sdsId": "130dcabd00000000", + "ssdEndOfLifeState": "NeverFailed", + "storagePoolId": "40395b7b00000000", + "temperatureState": "NeverFailed" + }, + { + "aggregatedState": "NeverFailed", + "capacityLimitInKb": 114293760, + "deviceCurrentPathName": "/dev/sdc", + "deviceOriginalPathName": "/dev/sdc", + "deviceState": "Normal", + "errorState": "None", + "id": "ebbfc47700020001", + "ledSetting": "Off", + "links": [ + { + "href": "/api/instances/Device::ebbfc47700020001", + "rel": "self" + }, + { + "href": "/api/instances/Device::ebbfc47700020001/relationships/Statistics", + "rel": "/api/Device/relationship/Statistics" + }, + { + "href": "/api/instances/Sds::130dcabf00000002", + "rel": "/api/parent/relationship/sdsId" + }, + { + "href": "/api/instances/StoragePool::4039828b00000001", + "rel": "/api/parent/relationship/storagePoolId" + } + ], + "longSuccessfulIos": { + "longWindow": null, + "mediumWindow": null, + "shortWindow": null + }, + "maxCapacityInKb": 114293760, + "name": "sdc", + "rfcacheErrorDeviceDoesNotExist": false, + "sdsId": "130dcabf00000002", + "ssdEndOfLifeState": "NeverFailed", + "storagePoolId": "4039828b00000001", + "temperatureState": "NeverFailed" + }, + { + "aggregatedState": "NeverFailed", + "capacityLimitInKb": 103808000, + "deviceCurrentPathName": "/dev/sdc", + "deviceOriginalPathName": "/dev/sdc", + "deviceState": "Normal", + "errorState": "None", + "id": "ebbdc47600000001", + "ledSetting": "Off", + "links": [ + { + "href": "/api/instances/Device::ebbdc47600000001", + "rel": "self" + }, + { + "href": "/api/instances/Device::ebbdc47600000001/relationships/Statistics", + "rel": "/api/Device/relationship/Statistics" + }, + { + "href": "/api/instances/Sds::130dcabd00000000", + "rel": "/api/parent/relationship/sdsId" + }, + { + "href": "/api/instances/StoragePool::40395b7b00000000", + "rel": "/api/parent/relationship/storagePoolId" + } + ], + "longSuccessfulIos": { + "longWindow": null, + "mediumWindow": null, + "shortWindow": null + }, + "maxCapacityInKb": 103808000, + "name": "sdc", + "rfcacheErrorDeviceDoesNotExist": false, + "sdsId": "130dcabd00000000", + "ssdEndOfLifeState": "NeverFailed", + "storagePoolId": "40395b7b00000000", + "temperatureState": "NeverFailed" + }, + { + "aggregatedState": "NeverFailed", + "capacityLimitInKb": 103808000, + "deviceCurrentPathName": "/dev/sdb", + "deviceOriginalPathName": "/dev/sdb", + "deviceState": "Normal", + "errorState": "None", + "id": "ebbfc47800020000", + "ledSetting": "Off", + "links": [ + { + "href": "/api/instances/Device::ebbfc47800020000", + "rel": "self" + }, + { + "href": "/api/instances/Device::ebbfc47800020000/relationships/Statistics", + "rel": "/api/Device/relationship/Statistics" + }, + { + "href": "/api/instances/Sds::130dcabf00000002", + "rel": "/api/parent/relationship/sdsId" + }, + { + "href": "/api/instances/StoragePool::4039828b00000001", + "rel": "/api/parent/relationship/storagePoolId" + } + ], + "longSuccessfulIos": { + "longWindow": null, + "mediumWindow": null, + "shortWindow": null + }, + "maxCapacityInKb": 103808000, + "name": "sdb", + "rfcacheErrorDeviceDoesNotExist": false, + "sdsId": "130dcabf00000002", + "ssdEndOfLifeState": "NeverFailed", + "storagePoolId": "4039828b00000001", + "temperatureState": "NeverFailed" + } + ], + "faultSetList": [ + { + "id": "a6a7b4cf00000000", + "links": [ + { + "href": "/api/instances/FaultSet::a6a7b4cf00000000", + "rel": "self" + }, + { + "href": "/api/instances/FaultSet::a6a7b4cf00000000/relationships/Statistics", + "rel": "/api/FaultSet/relationship/Statistics" + }, + { + "href": "/api/instances/FaultSet::a6a7b4cf00000000/relationships/Sds", + "rel": "/api/FaultSet/relationship/Sds" + }, + { + "href": "/api/instances/ProtectionDomain::74d855a900000000", + "rel": "/api/parent/relationship/protectionDomainId" + } + ], + "name": "MyFaultSet", + "protectionDomainId": "74d855a900000000" + } + ], + "isDirty": false, + "lastDeviceVersion": 47, + "lastFaultSetVersion": 2, + "lastProtectionDomainVersion": 2, + "lastRfcacheDeviceVersion": 1, + "lastSdcVersion": 7, + "lastSdsVersion": 19, + "lastStoragePoolVersion": 4, + "lastSystemVersion": 2, + "lastVTreeVersion": 3, + "lastVolumeVersion": 3, + "protectionDomainList": [ + { + "id": "74d855a900000000", + "links": [ + { + "href": "/api/instances/ProtectionDomain::74d855a900000000", + "rel": "self" + }, + { + "href": "/api/instances/ProtectionDomain::74d855a900000000/relationships/Statistics", + "rel": "/api/ProtectionDomain/relationship/Statistics" + }, + { + "href": "/api/instances/ProtectionDomain::74d855a900000000/relationships/StoragePool", + "rel": "/api/ProtectionDomain/relationship/StoragePool" + }, + { + "href": "/api/instances/ProtectionDomain::74d855a900000000/relationships/Sds", + "rel": "/api/ProtectionDomain/relationship/Sds" + }, + { + "href": "/api/instances/ProtectionDomain::74d855a900000000/relationships/FaultSet", + "rel": "/api/ProtectionDomain/relationship/FaultSet" + }, + { + "href": "/api/instances/System::499634a44778afc0", + "rel": "/api/parent/relationship/systemId" + } + ], + "mdmSdsNetworkDisconnectionsCounterParameters": { + "longWindow": { + "threshold": 700, + "windowSizeInSec": 86400 + }, + "mediumWindow": { + "threshold": 500, + "windowSizeInSec": 3600 + }, + "shortWindow": { + "threshold": 300, + "windowSizeInSec": 60 + } + }, + "name": "default", + "overallIoNetworkThrottlingEnabled": false, + "overallIoNetworkThrottlingInKbps": null, + "protectionDomainState": "Active", + "rebalanceNetworkThrottlingEnabled": false, + "rebalanceNetworkThrottlingInKbps": null, + "rebuildNetworkThrottlingEnabled": false, + "rebuildNetworkThrottlingInKbps": null, + "rfcacheEnabled": true, + "rfcacheMaxIoSizeKb": 128, + "rfcacheOpertionalMode": "WriteMiss", + "rfcachePageSizeKb": 64, + "sdsConfigurationFailureCounterParameters": { + "longWindow": { + "threshold": 700, + "windowSizeInSec": 86400 + }, + "mediumWindow": { + "threshold": 500, + "windowSizeInSec": 3600 + }, + "shortWindow": { + "threshold": 300, + "windowSizeInSec": 60 + } + }, + "sdsDecoupledCounterParameters": { + "longWindow": { + "threshold": 700, + "windowSizeInSec": 86400 + }, + "mediumWindow": { + "threshold": 500, + "windowSizeInSec": 3600 + }, + "shortWindow": { + "threshold": 300, + "windowSizeInSec": 60 + } + }, + "sdsReceiveBufferAllocationFailuresCounterParameters": { + "longWindow": { + "threshold": 2000000, + "windowSizeInSec": 86400 + }, + "mediumWindow": { + "threshold": 200000, + "windowSizeInSec": 3600 + }, + "shortWindow": { + "threshold": 20000, + "windowSizeInSec": 60 + } + }, + "sdsSdsNetworkDisconnectionsCounterParameters": { + "longWindow": { + "threshold": 700, + "windowSizeInSec": 86400 + }, + "mediumWindow": { + "threshold": 500, + "windowSizeInSec": 3600 + }, + "shortWindow": { + "threshold": 300, + "windowSizeInSec": 60 + } + }, + "systemId": "499634a44778afc0" + } + ], + "rfcacheDeviceList": null, + "sdcList": [ + { + "id": "6076fd1100000002", + "installedSoftwareVersionInfo": "R2_6.11000.0", + "kernelBuildNumber": null, + "kernelVersion": "4.15.18", + "links": [ + { + "href": "/api/instances/Sdc::6076fd1100000002", + "rel": "self" + }, + { + "href": "/api/instances/Sdc::6076fd1100000002/relationships/Statistics", + "rel": "/api/Sdc/relationship/Statistics" + }, + { + "href": "/api/instances/Sdc::6076fd1100000002/relationships/Volume", + "rel": "/api/Sdc/relationship/Volume" + }, + { + "href": "/api/instances/System::499634a44778afc0", + "rel": "/api/parent/relationship/systemId" + } + ], + "mdmConnectionState": "Disconnected", + "memoryAllocationFailure": null, + "name": null, + "osType": "Linux", + "perfProfile": "Default", + "sdcApproved": true, + "sdcApprovedIps": [ + "100.127.0.12" + ], + "sdcGuid": "B71F01AE-FF7A-47C5-A303-583FFD416818", + "sdcIp": "100.127.0.12", + "socketAllocationFailure": null, + "softwareVersionInfo": null, + "systemId": "499634a44778afc0", + "versionInfo": null + }, + { + "id": "6076fd1000000001", + "installedSoftwareVersionInfo": "R2_6.11000.0", + "kernelBuildNumber": null, + "kernelVersion": "4.15.18", + "links": [ + { + "href": "/api/instances/Sdc::6076fd1000000001", + "rel": "self" + }, + { + "href": "/api/instances/Sdc::6076fd1000000001/relationships/Statistics", + "rel": "/api/Sdc/relationship/Statistics" + }, + { + "href": "/api/instances/Sdc::6076fd1000000001/relationships/Volume", + "rel": "/api/Sdc/relationship/Volume" + }, + { + "href": "/api/instances/System::499634a44778afc0", + "rel": "/api/parent/relationship/systemId" + } + ], + "mdmConnectionState": "Disconnected", + "memoryAllocationFailure": null, + "name": null, + "osType": "Linux", + "perfProfile": "Default", + "sdcApproved": true, + "sdcApprovedIps": [ + "100.127.0.11" + ], + "sdcGuid": "5D2B24F9-5D49-4688-A67D-88AF8790BC05", + "sdcIp": "100.127.0.11", + "socketAllocationFailure": null, + "softwareVersionInfo": null, + "systemId": "499634a44778afc0", + "versionInfo": null + }, + { + "id": "6076fd0f00000000", + "installedSoftwareVersionInfo": "R2_6.11000.0", + "kernelBuildNumber": null, + "kernelVersion": "4.15.18", + "links": [ + { + "href": "/api/instances/Sdc::6076fd0f00000000", + "rel": "self" + }, + { + "href": "/api/instances/Sdc::6076fd0f00000000/relationships/Statistics", + "rel": "/api/Sdc/relationship/Statistics" + }, + { + "href": "/api/instances/Sdc::6076fd0f00000000/relationships/Volume", + "rel": "/api/Sdc/relationship/Volume" + }, + { + "href": "/api/instances/System::499634a44778afc0", + "rel": "/api/parent/relationship/systemId" + } + ], + "mdmConnectionState": "Connected", + "memoryAllocationFailure": null, + "name": null, + "osType": "Linux", + "perfProfile": "Default", + "sdcApproved": true, + "sdcApprovedIps": [ + "100.127.0.10" + ], + "sdcGuid": "974F4AC7-FF37-4909-8713-D1BD3F002843", + "sdcIp": "100.127.0.10", + "socketAllocationFailure": null, + "softwareVersionInfo": "R2_6.11000.0", + "systemId": "499634a44778afc0", + "versionInfo": "R2_6.11000.0" + } + ], + "sdsList": [ + { + "authenticationError": "None", + "certificateInfo": { + "issuer": "/GN=MDM/CN=test-VirtualBox/L=Hopkinton/ST=Massachusetts/C=US/O=EMC/OU=ASD", + "subject": "/GN=SDS-000/CN=scaleIOslave1/L=Hopkinton/ST=Massachusetts/C=US/O=EMC/OU=ASD", + "thumbprint": "FD:00:99:E9:40:90:A5:CE:85:B8:A9:07:86:BB:7E:F0:E0:DE:F9:75", + "validFrom": "Nov 12 19:17:22 2019 GMT", + "validFromAsn1Format": "191112191722Z", + "validTo": "Nov 10 20:17:22 2029 GMT", + "validToAsn1Format": "291110201722Z" + }, + "drlMode": "Volatile", + "faultSetId": null, + "id": "130dcabd00000000", + "ipList": [ + { + "ip": "100.127.0.11", + "role": "all" + } + ], + "links": [ + { + "href": "/api/instances/Sds::130dcabd00000000", + "rel": "self" + }, + { + "href": "/api/instances/Sds::130dcabd00000000/relationships/Statistics", + "rel": "/api/Sds/relationship/Statistics" + }, + { + "href": "/api/instances/Sds::130dcabd00000000/relationships/Device", + "rel": "/api/Sds/relationship/Device" + }, + { + "href": "/api/instances/Sds::130dcabd00000000/relationships/RfcacheDevice", + "rel": "/api/Sds/relationship/RfcacheDevice" + }, + { + "href": "/api/instances/ProtectionDomain::74d855a900000000", + "rel": "/api/parent/relationship/protectionDomainId" + } + ], + "maintenanceState": "NoMaintenance", + "mdmConnectionState": "Connected", + "membershipState": "Joined", + "name": "SDS_[100.127.0.11]", + "numOfIoBuffers": null, + "onVmWare": false, + "perfProfile": "Default", + "port": 7072, + "protectionDomainId": "74d855a900000000", + "rfcacheEnabled": true, + "rfcacheErrorApiVersionMismatch": false, + "rfcacheErrorDeviceDoesNotExist": false, + "rfcacheErrorInconsistentCacheConfiguration": false, + "rfcacheErrorInconsistentSourceConfiguration": false, + "rfcacheErrorInvalidDriverPath": false, + "rfcacheErrorLowResources": false, + "rmcacheEnabled": true, + "rmcacheFrozen": false, + "rmcacheMemoryAllocationState": "AllocationPending", + "rmcacheSizeInKb": 131072, + "sdsConfigurationFailure": null, + "sdsDecoupled": null, + "sdsReceiveBufferAllocationFailures": null, + "sdsState": "Normal", + "softwareVersionInfo": "R2_6.11000.0" + }, + { + "authenticationError": "None", + "certificateInfo": { + "issuer": "/GN=MDM/CN=test-VirtualBox/L=Hopkinton/ST=Massachusetts/C=US/O=EMC/OU=ASD", + "subject": "/GN=SDS-001/CN=test-VirtualBox/L=Hopkinton/ST=Massachusetts/C=US/O=EMC/OU=ASD", + "thumbprint": "B2:F9:88:84:55:94:A1:D8:7F:C1:4F:50:81:17:56:AC:72:B7:A2:AD", + "validFrom": "Nov 12 19:17:22 2019 GMT", + "validFromAsn1Format": "191112191722Z", + "validTo": "Nov 10 20:17:22 2029 GMT", + "validToAsn1Format": "291110201722Z" + }, + "drlMode": "Volatile", + "faultSetId": null, + "id": "130dcabe00000001", + "ipList": [ + { + "ip": "100.127.0.10", + "role": "all" + } + ], + "links": [ + { + "href": "/api/instances/Sds::130dcabe00000001", + "rel": "self" + }, + { + "href": "/api/instances/Sds::130dcabe00000001/relationships/Statistics", + "rel": "/api/Sds/relationship/Statistics" + }, + { + "href": "/api/instances/Sds::130dcabe00000001/relationships/Device", + "rel": "/api/Sds/relationship/Device" + }, + { + "href": "/api/instances/Sds::130dcabe00000001/relationships/RfcacheDevice", + "rel": "/api/Sds/relationship/RfcacheDevice" + }, + { + "href": "/api/instances/ProtectionDomain::74d855a900000000", + "rel": "/api/parent/relationship/protectionDomainId" + } + ], + "maintenanceState": "NoMaintenance", + "mdmConnectionState": "Connected", + "membershipState": "Joined", + "name": "SDS_[100.127.0.10]", + "numOfIoBuffers": null, + "onVmWare": false, + "perfProfile": "Default", + "port": 7072, + "protectionDomainId": "74d855a900000000", + "rfcacheEnabled": true, + "rfcacheErrorApiVersionMismatch": false, + "rfcacheErrorDeviceDoesNotExist": false, + "rfcacheErrorInconsistentCacheConfiguration": false, + "rfcacheErrorInconsistentSourceConfiguration": false, + "rfcacheErrorInvalidDriverPath": false, + "rfcacheErrorLowResources": false, + "rmcacheEnabled": true, + "rmcacheFrozen": false, + "rmcacheMemoryAllocationState": "AllocationPending", + "rmcacheSizeInKb": 131072, + "sdsConfigurationFailure": null, + "sdsDecoupled": null, + "sdsReceiveBufferAllocationFailures": null, + "sdsState": "Normal", + "softwareVersionInfo": "R2_6.11000.0" + }, + { + "authenticationError": "None", + "certificateInfo": { + "issuer": "/GN=MDM/CN=test-VirtualBox/L=Hopkinton/ST=Massachusetts/C=US/O=EMC/OU=ASD", + "subject": "/GN=SDS-002/CN=scaleIOSlave2/L=Hopkinton/ST=Massachusetts/C=US/O=EMC/OU=ASD", + "thumbprint": "CC:A0:E8:B7:84:9B:E5:D1:2E:F6:7C:3A:AC:21:D6:5C:5F:D1:47:D1", + "validFrom": "Nov 12 19:17:21 2019 GMT", + "validFromAsn1Format": "191112191721Z", + "validTo": "Nov 10 20:17:21 2029 GMT", + "validToAsn1Format": "291110201721Z" + }, + "drlMode": "Volatile", + "faultSetId": null, + "id": "130dcabf00000002", + "ipList": [ + { + "ip": "100.127.0.12", + "role": "all" + } + ], + "links": [ + { + "href": "/api/instances/Sds::130dcabf00000002", + "rel": "self" + }, + { + "href": "/api/instances/Sds::130dcabf00000002/relationships/Statistics", + "rel": "/api/Sds/relationship/Statistics" + }, + { + "href": "/api/instances/Sds::130dcabf00000002/relationships/Device", + "rel": "/api/Sds/relationship/Device" + }, + { + "href": "/api/instances/Sds::130dcabf00000002/relationships/RfcacheDevice", + "rel": "/api/Sds/relationship/RfcacheDevice" + }, + { + "href": "/api/instances/ProtectionDomain::74d855a900000000", + "rel": "/api/parent/relationship/protectionDomainId" + } + ], + "maintenanceState": "NoMaintenance", + "mdmConnectionState": "Connected", + "membershipState": "Joined", + "name": "SDS_[100.127.0.12]", + "numOfIoBuffers": null, + "onVmWare": false, + "perfProfile": "Default", + "port": 7072, + "protectionDomainId": "74d855a900000000", + "rfcacheEnabled": true, + "rfcacheErrorApiVersionMismatch": false, + "rfcacheErrorDeviceDoesNotExist": false, + "rfcacheErrorInconsistentCacheConfiguration": false, + "rfcacheErrorInconsistentSourceConfiguration": false, + "rfcacheErrorInvalidDriverPath": false, + "rfcacheErrorLowResources": false, + "rmcacheEnabled": true, + "rmcacheFrozen": false, + "rmcacheMemoryAllocationState": "AllocationPending", + "rmcacheSizeInKb": 131072, + "sdsConfigurationFailure": null, + "sdsDecoupled": null, + "sdsReceiveBufferAllocationFailures": null, + "sdsState": "Normal", + "softwareVersionInfo": "R2_6.11000.0" + } + ], + "sessionTag": 19, + "storagePoolList": [ + { + "backgroundScannerBWLimitKBps": 0, + "backgroundScannerMode": "Disabled", + "capacityAlertCriticalThreshold": 90, + "capacityAlertHighThreshold": 80, + "checksumEnabled": false, + "id": "4039828b00000001", + "links": [ + { + "href": "/api/instances/StoragePool::4039828b00000001", + "rel": "self" + }, + { + "href": "/api/instances/StoragePool::4039828b00000001/relationships/Statistics", + "rel": "/api/StoragePool/relationship/Statistics" + }, + { + "href": "/api/instances/StoragePool::4039828b00000001/relationships/Volume", + "rel": "/api/StoragePool/relationship/Volume" + }, + { + "href": "/api/instances/StoragePool::4039828b00000001/relationships/Device", + "rel": "/api/StoragePool/relationship/Device" + }, + { + "href": "/api/instances/StoragePool::4039828b00000001/relationships/VTree", + "rel": "/api/StoragePool/relationship/VTree" + }, + { + "href": "/api/instances/ProtectionDomain::74d855a900000000", + "rel": "/api/parent/relationship/protectionDomainId" + } + ], + "name": "StoragePool2", + "numOfParallelRebuildRebalanceJobsPerDevice": 2, + "protectionDomainId": "74d855a900000000", + "rebalanceEnabled": true, + "rebalanceIoPriorityAppBwPerDeviceThresholdInKbps": null, + "rebalanceIoPriorityAppIopsPerDeviceThreshold": null, + "rebalanceIoPriorityBwLimitPerDeviceInKbps": 10240, + "rebalanceIoPriorityNumOfConcurrentIosPerDevice": 1, + "rebalanceIoPriorityPolicy": "favorAppIos", + "rebalanceIoPriorityQuietPeriodInMsec": null, + "rebuildEnabled": true, + "rebuildIoPriorityAppBwPerDeviceThresholdInKbps": null, + "rebuildIoPriorityAppIopsPerDeviceThreshold": null, + "rebuildIoPriorityBwLimitPerDeviceInKbps": 10240, + "rebuildIoPriorityNumOfConcurrentIosPerDevice": 1, + "rebuildIoPriorityPolicy": "limitNumOfConcurrentIos", + "rebuildIoPriorityQuietPeriodInMsec": null, + "rmcacheWriteHandlingMode": "Cached", + "sparePercentage": 10, + "useRfcache": false, + "useRmcache": false, + "zeroPaddingEnabled": false + }, + { + "backgroundScannerBWLimitKBps": 0, + "backgroundScannerMode": "Disabled", + "capacityAlertCriticalThreshold": 90, + "capacityAlertHighThreshold": 80, + "checksumEnabled": false, + "id": "40395b7b00000000", + "links": [ + { + "href": "/api/instances/StoragePool::40395b7b00000000", + "rel": "self" + }, + { + "href": "/api/instances/StoragePool::40395b7b00000000/relationships/Statistics", + "rel": "/api/StoragePool/relationship/Statistics" + }, + { + "href": "/api/instances/StoragePool::40395b7b00000000/relationships/Volume", + "rel": "/api/StoragePool/relationship/Volume" + }, + { + "href": "/api/instances/StoragePool::40395b7b00000000/relationships/Device", + "rel": "/api/StoragePool/relationship/Device" + }, + { + "href": "/api/instances/StoragePool::40395b7b00000000/relationships/VTree", + "rel": "/api/StoragePool/relationship/VTree" + }, + { + "href": "/api/instances/ProtectionDomain::74d855a900000000", + "rel": "/api/parent/relationship/protectionDomainId" + } + ], + "name": "StoragePool1", + "numOfParallelRebuildRebalanceJobsPerDevice": 2, + "protectionDomainId": "74d855a900000000", + "rebalanceEnabled": true, + "rebalanceIoPriorityAppBwPerDeviceThresholdInKbps": null, + "rebalanceIoPriorityAppIopsPerDeviceThreshold": null, + "rebalanceIoPriorityBwLimitPerDeviceInKbps": 10240, + "rebalanceIoPriorityNumOfConcurrentIosPerDevice": 1, + "rebalanceIoPriorityPolicy": "favorAppIos", + "rebalanceIoPriorityQuietPeriodInMsec": null, + "rebuildEnabled": true, + "rebuildIoPriorityAppBwPerDeviceThresholdInKbps": null, + "rebuildIoPriorityAppIopsPerDeviceThreshold": null, + "rebuildIoPriorityBwLimitPerDeviceInKbps": 10240, + "rebuildIoPriorityNumOfConcurrentIosPerDevice": 1, + "rebuildIoPriorityPolicy": "limitNumOfConcurrentIos", + "rebuildIoPriorityQuietPeriodInMsec": null, + "rmcacheWriteHandlingMode": "Cached", + "sparePercentage": 10, + "useRfcache": false, + "useRmcache": false, + "zeroPaddingEnabled": false + } + ], + "vTreeList": [ + { + "baseVolumeId": "993a355e00000001", + "id": "252fd6e400000001", + "links": [ + { + "href": "/api/instances/VTree::252fd6e400000001", + "rel": "self" + }, + { + "href": "/api/instances/VTree::252fd6e400000001/relationships/Statistics", + "rel": "/api/VTree/relationship/Statistics" + }, + { + "href": "/api/instances/VTree::252fd6e400000001/relationships/Volume", + "rel": "/api/VTree/relationship/Volume" + }, + { + "href": "/api/instances/Volume::993a355e00000001", + "rel": "/api/parent/relationship/baseVolumeId" + }, + { + "href": "/api/instances/StoragePool::40395b7b00000000", + "rel": "/api/parent/relationship/storagePoolId" + } + ], + "name": null, + "storagePoolId": "40395b7b00000000" + }, + { + "baseVolumeId": "993a355d00000000", + "id": "252fd6e300000000", + "links": [ + { + "href": "/api/instances/VTree::252fd6e300000000", + "rel": "self" + }, + { + "href": "/api/instances/VTree::252fd6e300000000/relationships/Statistics", + "rel": "/api/VTree/relationship/Statistics" + }, + { + "href": "/api/instances/VTree::252fd6e300000000/relationships/Volume", + "rel": "/api/VTree/relationship/Volume" + }, + { + "href": "/api/instances/Volume::993a355d00000000", + "rel": "/api/parent/relationship/baseVolumeId" + }, + { + "href": "/api/instances/StoragePool::40395b7b00000000", + "rel": "/api/parent/relationship/storagePoolId" + } + ], + "name": null, + "storagePoolId": "40395b7b00000000" + } + ], + "volumeList": [ + { + "ancestorVolumeId": null, + "consistencyGroupId": null, + "creationTime": 1574882772, + "id": "993a355e00000001", + "isObfuscated": false, + "isVvol": false, + "links": [ + { + "href": "/api/instances/Volume::993a355e00000001", + "rel": "self" + }, + { + "href": "/api/instances/Volume::993a355e00000001/relationships/Statistics", + "rel": "/api/Volume/relationship/Statistics" + }, + { + "href": "/api/instances/VTree::252fd6e400000001", + "rel": "/api/parent/relationship/vtreeId" + }, + { + "href": "/api/instances/StoragePool::40395b7b00000000", + "rel": "/api/parent/relationship/storagePoolId" + } + ], + "mappedSdcInfo": [ + { + "limitBwInMbps": 0, + "limitIops": 0, + "sdcId": "6076fd1100000002", + "sdcIp": "100.127.0.12" + } + ], + "mappingToAllSdcsEnabled": false, + "name": "volume2-16", + "sizeInKb": 16777216, + "storagePoolId": "40395b7b00000000", + "useRmcache": false, + "volumeType": "ThinProvisioned", + "vtreeId": "252fd6e400000001" + }, + { + "ancestorVolumeId": null, + "consistencyGroupId": null, + "creationTime": 1574882580, + "id": "993a355d00000000", + "isObfuscated": false, + "isVvol": false, + "links": [ + { + "href": "/api/instances/Volume::993a355d00000000", + "rel": "self" + }, + { + "href": "/api/instances/Volume::993a355d00000000/relationships/Statistics", + "rel": "/api/Volume/relationship/Statistics" + }, + { + "href": "/api/instances/VTree::252fd6e300000000", + "rel": "/api/parent/relationship/vtreeId" + }, + { + "href": "/api/instances/StoragePool::40395b7b00000000", + "rel": "/api/parent/relationship/storagePoolId" + } + ], + "mappedSdcInfo": [ + { + "limitBwInMbps": 0, + "limitIops": 0, + "sdcId": "6076fd1000000001", + "sdcIp": "100.127.0.11" + } + ], + "mappingToAllSdcsEnabled": false, + "name": "volume1-16", + "sizeInKb": 16777216, + "storagePoolId": "40395b7b00000000", + "useRmcache": false, + "volumeType": "ThinProvisioned", + "vtreeId": "252fd6e300000000" + } + ] +}
\ No newline at end of file diff --git a/src/go/collectors/go.d.plugin/modules/scaleio/testdata/selected_statistics.json b/src/go/collectors/go.d.plugin/modules/scaleio/testdata/selected_statistics.json new file mode 100644 index 000000000..0b141bbe6 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/scaleio/testdata/selected_statistics.json @@ -0,0 +1,777 @@ +{ + "Sdc": { + "6076fd0f00000000": { + "numOfMappedVolumes": 1, + "userDataReadBwc": { + "numOccured": 0, + "numSeconds": 1, + "totalWeightInKb": 0 + }, + "userDataWriteBwc": { + "numOccured": 0, + "numSeconds": 1, + "totalWeightInKb": 0 + }, + "volumeIds": [ + "993a5c6d00000002" + ] + }, + "6076fd1000000001": { + "numOfMappedVolumes": 1, + "userDataReadBwc": { + "numOccured": 1, + "numSeconds": 1, + "totalWeightInKb": 1 + }, + "userDataWriteBwc": { + "numOccured": 169, + "numSeconds": 1, + "totalWeightInKb": 117399 + }, + "volumeIds": [ + "993a355d00000000" + ] + }, + "6076fd1100000002": { + "numOfMappedVolumes": 1, + "userDataReadBwc": { + "numOccured": 0, + "numSeconds": 1, + "totalWeightInKb": 0 + }, + "userDataWriteBwc": { + "numOccured": 145, + "numSeconds": 1, + "totalWeightInKb": 118972 + }, + "volumeIds": [ + "993a355e00000001" + ] + } + }, + "StoragePool": { + "40395b7b00000000": { + "BackgroundScanCompareCount": 0, + "BackgroundScannedInMB": 0, + "activeBckRebuildCapacityInKb": 0, + "activeFwdRebuildCapacityInKb": 0, + "activeMovingCapacityInKb": 0, + "activeMovingInBckRebuildJobs": 0, + "activeMovingInFwdRebuildJobs": 0, + "activeMovingInNormRebuildJobs": 0, + "activeMovingInRebalanceJobs": 0, + "activeMovingOutBckRebuildJobs": 0, + "activeMovingOutFwdRebuildJobs": 0, + "activeMovingOutNormRebuildJobs": 0, + "activeMovingRebalanceJobs": 0, + "activeNormRebuildCapacityInKb": 0, + "activeRebalanceCapacityInKb": 0, + "atRestCapacityInKb": 50110464, + "bckRebuildCapacityInKb": 0, + "bckRebuildReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "bckRebuildWriteBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "capacityAvailableForVolumeAllocationInKb": 100663296, + "capacityInUseInKb": 50110464, + "capacityLimitInKb": 311424000, + "degradedFailedCapacityInKb": 0, + "degradedFailedVacInKb": 0, + "degradedHealthyCapacityInKb": 0, + "degradedHealthyVacInKb": 0, + "deviceIds": [ + "ebbdc47a00000000", + "ebbf9d6500010000", + "ebbfc47900020000" + ], + "failedCapacityInKb": 0, + "failedVacInKb": 0, + "fixedReadErrorCount": 0, + "fwdRebuildCapacityInKb": 0, + "fwdRebuildReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "fwdRebuildWriteBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "inMaintenanceCapacityInKb": 0, + "inMaintenanceVacInKb": 0, + "inUseVacInKb": 67108864, + "maxCapacityInKb": 311424000, + "movingCapacityInKb": 0, + "normRebuildCapacityInKb": 0, + "normRebuildReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "normRebuildWriteBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "numOfDevices": 3, + "numOfMappedToAllVolumes": 0, + "numOfSnapshots": 1, + "numOfThickBaseVolumes": 0, + "numOfThinBaseVolumes": 2, + "numOfUnmappedVolumes": 0, + "numOfVolumes": 3, + "numOfVolumesInDeletion": 0, + "numOfVtrees": 2, + "pendingBckRebuildCapacityInKb": 0, + "pendingFwdRebuildCapacityInKb": 0, + "pendingMovingCapacityInKb": 0, + "pendingMovingInBckRebuildJobs": 0, + "pendingMovingInFwdRebuildJobs": 0, + "pendingMovingInNormRebuildJobs": 0, + "pendingMovingInRebalanceJobs": 0, + "pendingMovingOutBckRebuildJobs": 0, + "pendingMovingOutFwdRebuildJobs": 0, + "pendingMovingOutNormrebuildJobs": 0, + "pendingMovingRebalanceJobs": 0, + "pendingNormRebuildCapacityInKb": 0, + "pendingRebalanceCapacityInKb": 0, + "primaryReadBwc": { + "numOccured": 1, + "numSeconds": 5, + "totalWeightInKb": 4 + }, + "primaryReadFromDevBwc": { + "numOccured": 1, + "numSeconds": 5, + "totalWeightInKb": 4 + }, + "primaryReadFromRmcacheBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "primaryVacInKb": 33554432, + "primaryWriteBwc": { + "numOccured": 1556, + "numSeconds": 5, + "totalWeightInKb": 1193408 + }, + "protectedCapacityInKb": 50110464, + "protectedVacInKb": 67108864, + "rebalanceCapacityInKb": 0, + "rebalanceReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "rebalanceWriteBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "rfacheReadHit": 0, + "rfacheWriteHit": 0, + "rfcacheAvgReadTime": 0, + "rfcacheAvgWriteTime": 0, + "rfcacheIoErrors": 0, + "rfcacheIosOutstanding": 0, + "rfcacheIosSkipped": 0, + "rfcacheReadMiss": 0, + "rfcacheReadsFromCache": 0, + "rfcacheReadsPending": 0, + "rfcacheReadsReceived": 0, + "rfcacheReadsSkipped": 0, + "rfcacheReadsSkippedAlignedSizeTooLarge": 0, + "rfcacheReadsSkippedHeavyLoad": 0, + "rfcacheReadsSkippedInternalError": 0, + "rfcacheReadsSkippedLockIos": 0, + "rfcacheReadsSkippedLowResources": 0, + "rfcacheReadsSkippedMaxIoSize": 0, + "rfcacheReadsSkippedStuckIo": 0, + "rfcacheSkippedUnlinedWrite": 0, + "rfcacheSourceDeviceReads": 0, + "rfcacheSourceDeviceWrites": 0, + "rfcacheWriteMiss": 0, + "rfcacheWritePending": 0, + "rfcacheWritesReceived": 0, + "rfcacheWritesSkippedCacheMiss": 0, + "rfcacheWritesSkippedHeavyLoad": 0, + "rfcacheWritesSkippedInternalError": 0, + "rfcacheWritesSkippedLowResources": 0, + "rfcacheWritesSkippedMaxIoSize": 0, + "rfcacheWritesSkippedStuckIo": 0, + "rmPendingAllocatedInKb": 0, + "secondaryReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "secondaryReadFromDevBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "secondaryReadFromRmcacheBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "secondaryVacInKb": 33554432, + "secondaryWriteBwc": { + "numOccured": 1530, + "numSeconds": 5, + "totalWeightInKb": 1169632 + }, + "semiProtectedCapacityInKb": 0, + "semiProtectedVacInKb": 0, + "snapCapacityInUseInKb": 16699392, + "snapCapacityInUseOccupiedInKb": 749568, + "spareCapacityInKb": 31141888, + "thickCapacityInUseInKb": 0, + "thinCapacityAllocatedInKb": 67108864, + "thinCapacityInUseInKb": 49360896, + "totalReadBwc": { + "numOccured": 1, + "numSeconds": 5, + "totalWeightInKb": 4 + }, + "totalWriteBwc": { + "numOccured": 3086, + "numSeconds": 5, + "totalWeightInKb": 2363040 + }, + "unreachableUnusedCapacityInKb": 0, + "unusedCapacityInKb": 230171648, + "userDataReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "userDataWriteBwc": { + "numOccured": 285, + "numSeconds": 1, + "totalWeightInKb": 227170 + }, + "volumeIds": [ + "993a355d00000000", + "993a5c6d00000002", + "993a355e00000001" + ], + "vtreeIds": [ + "252fd6e300000000", + "252fd6e400000001" + ] + }, + "4039828b00000001": { + "BackgroundScanCompareCount": 0, + "BackgroundScannedInMB": 0, + "activeBckRebuildCapacityInKb": 0, + "activeFwdRebuildCapacityInKb": 0, + "activeMovingCapacityInKb": 0, + "activeMovingInBckRebuildJobs": 0, + "activeMovingInFwdRebuildJobs": 0, + "activeMovingInNormRebuildJobs": 0, + "activeMovingInRebalanceJobs": 0, + "activeMovingOutBckRebuildJobs": 0, + "activeMovingOutFwdRebuildJobs": 0, + "activeMovingOutNormRebuildJobs": 0, + "activeMovingRebalanceJobs": 0, + "activeNormRebuildCapacityInKb": 0, + "activeRebalanceCapacityInKb": 0, + "atRestCapacityInKb": 0, + "bckRebuildCapacityInKb": 0, + "bckRebuildReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "bckRebuildWriteBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "capacityAvailableForVolumeAllocationInKb": 142606336, + "capacityInUseInKb": 0, + "capacityLimitInKb": 332395520, + "degradedFailedCapacityInKb": 0, + "degradedFailedVacInKb": 0, + "degradedHealthyCapacityInKb": 0, + "degradedHealthyVacInKb": 0, + "deviceIds": [ + "ebbdc47b00000001", + "ebbfc47300010001", + "ebbfc47700020001" + ], + "failedCapacityInKb": 0, + "failedVacInKb": 0, + "fixedReadErrorCount": 0, + "fwdRebuildCapacityInKb": 0, + "fwdRebuildReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "fwdRebuildWriteBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "inMaintenanceCapacityInKb": 0, + "inMaintenanceVacInKb": 0, + "inUseVacInKb": 0, + "maxCapacityInKb": 332395520, + "movingCapacityInKb": 0, + "normRebuildCapacityInKb": 0, + "normRebuildReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "normRebuildWriteBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "numOfDevices": 3, + "numOfMappedToAllVolumes": 0, + "numOfSnapshots": 0, + "numOfThickBaseVolumes": 0, + "numOfThinBaseVolumes": 0, + "numOfUnmappedVolumes": 0, + "numOfVolumes": 0, + "numOfVolumesInDeletion": 0, + "numOfVtrees": 0, + "pendingBckRebuildCapacityInKb": 0, + "pendingFwdRebuildCapacityInKb": 0, + "pendingMovingCapacityInKb": 0, + "pendingMovingInBckRebuildJobs": 0, + "pendingMovingInFwdRebuildJobs": 0, + "pendingMovingInNormRebuildJobs": 0, + "pendingMovingInRebalanceJobs": 0, + "pendingMovingOutBckRebuildJobs": 0, + "pendingMovingOutFwdRebuildJobs": 0, + "pendingMovingOutNormrebuildJobs": 0, + "pendingMovingRebalanceJobs": 0, + "pendingNormRebuildCapacityInKb": 0, + "pendingRebalanceCapacityInKb": 0, + "primaryReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "primaryReadFromDevBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "primaryReadFromRmcacheBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "primaryVacInKb": 0, + "primaryWriteBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "protectedCapacityInKb": 0, + "protectedVacInKb": 0, + "rebalanceCapacityInKb": 0, + "rebalanceReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "rebalanceWriteBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "rfacheReadHit": 0, + "rfacheWriteHit": 0, + "rfcacheAvgReadTime": 0, + "rfcacheAvgWriteTime": 0, + "rfcacheIoErrors": 0, + "rfcacheIosOutstanding": 0, + "rfcacheIosSkipped": 0, + "rfcacheReadMiss": 0, + "rfcacheReadsFromCache": 0, + "rfcacheReadsPending": 0, + "rfcacheReadsReceived": 0, + "rfcacheReadsSkipped": 0, + "rfcacheReadsSkippedAlignedSizeTooLarge": 0, + "rfcacheReadsSkippedHeavyLoad": 0, + "rfcacheReadsSkippedInternalError": 0, + "rfcacheReadsSkippedLockIos": 0, + "rfcacheReadsSkippedLowResources": 0, + "rfcacheReadsSkippedMaxIoSize": 0, + "rfcacheReadsSkippedStuckIo": 0, + "rfcacheSkippedUnlinedWrite": 0, + "rfcacheSourceDeviceReads": 0, + "rfcacheSourceDeviceWrites": 0, + "rfcacheWriteMiss": 0, + "rfcacheWritePending": 0, + "rfcacheWritesReceived": 0, + "rfcacheWritesSkippedCacheMiss": 0, + "rfcacheWritesSkippedHeavyLoad": 0, + "rfcacheWritesSkippedInternalError": 0, + "rfcacheWritesSkippedLowResources": 0, + "rfcacheWritesSkippedMaxIoSize": 0, + "rfcacheWritesSkippedStuckIo": 0, + "rmPendingAllocatedInKb": 0, + "secondaryReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "secondaryReadFromDevBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "secondaryReadFromRmcacheBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "secondaryVacInKb": 0, + "secondaryWriteBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "semiProtectedCapacityInKb": 0, + "semiProtectedVacInKb": 0, + "snapCapacityInUseInKb": 3145728, + "snapCapacityInUseOccupiedInKb": 0, + "spareCapacityInKb": 33239040, + "thickCapacityInUseInKb": 0, + "thinCapacityAllocatedInKb": 0, + "thinCapacityInUseInKb": 0, + "totalReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "totalWriteBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "unreachableUnusedCapacityInKb": 0, + "unusedCapacityInKb": 299156480, + "userDataReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "userDataWriteBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "volumeIds": [], + "vtreeIds": [] + } + }, + "System": { + "BackgroundScanCompareCount": 0, + "BackgroundScannedInMB": 0, + "activeBckRebuildCapacityInKb": 0, + "activeFwdRebuildCapacityInKb": 0, + "activeMovingCapacityInKb": 0, + "activeMovingInBckRebuildJobs": 0, + "activeMovingInFwdRebuildJobs": 0, + "activeMovingInNormRebuildJobs": 0, + "activeMovingInRebalanceJobs": 0, + "activeMovingOutBckRebuildJobs": 0, + "activeMovingOutFwdRebuildJobs": 0, + "activeMovingOutNormRebuildJobs": 0, + "activeMovingRebalanceJobs": 0, + "activeNormRebuildCapacityInKb": 0, + "activeRebalanceCapacityInKb": 0, + "atRestCapacityInKb": 50110464, + "bckRebuildCapacityInKb": 0, + "bckRebuildReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "bckRebuildWriteBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "capacityAvailableForVolumeAllocationInKb": 243269632, + "capacityInUseInKb": 50110464, + "capacityLimitInKb": 643819520, + "degradedFailedCapacityInKb": 0, + "degradedFailedVacInKb": 0, + "degradedHealthyCapacityInKb": 0, + "degradedHealthyVacInKb": 0, + "failedCapacityInKb": 0, + "failedVacInKb": 0, + "fixedReadErrorCount": 0, + "fwdRebuildCapacityInKb": 0, + "fwdRebuildReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "fwdRebuildWriteBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "inMaintenanceCapacityInKb": 0, + "inMaintenanceVacInKb": 0, + "inUseVacInKb": 67108864, + "maxCapacityInKb": 643819520, + "movingCapacityInKb": 0, + "normRebuildCapacityInKb": 0, + "normRebuildReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "normRebuildWriteBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "numOfDevices": 6, + "numOfFaultSets": 0, + "numOfMappedToAllVolumes": 0, + "numOfProtectionDomains": 1, + "numOfRfcacheDevices": 0, + "numOfScsiInitiators": 0, + "numOfSdc": 3, + "numOfSds": 3, + "numOfSnapshots": 1, + "numOfStoragePools": 2, + "numOfThickBaseVolumes": 0, + "numOfThinBaseVolumes": 2, + "numOfUnmappedVolumes": 0, + "numOfVolumes": 3, + "numOfVolumesInDeletion": 0, + "numOfVtrees": 2, + "pendingBckRebuildCapacityInKb": 0, + "pendingFwdRebuildCapacityInKb": 0, + "pendingMovingCapacityInKb": 0, + "pendingMovingInBckRebuildJobs": 0, + "pendingMovingInFwdRebuildJobs": 0, + "pendingMovingInNormRebuildJobs": 0, + "pendingMovingInRebalanceJobs": 0, + "pendingMovingOutBckRebuildJobs": 0, + "pendingMovingOutFwdRebuildJobs": 0, + "pendingMovingOutNormrebuildJobs": 0, + "pendingMovingRebalanceJobs": 0, + "pendingNormRebuildCapacityInKb": 0, + "pendingRebalanceCapacityInKb": 0, + "primaryReadBwc": { + "numOccured": 1, + "numSeconds": 5, + "totalWeightInKb": 4 + }, + "primaryReadFromDevBwc": { + "numOccured": 1, + "numSeconds": 5, + "totalWeightInKb": 4 + }, + "primaryReadFromRmcacheBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "primaryVacInKb": 33554432, + "primaryWriteBwc": { + "numOccured": 1556, + "numSeconds": 5, + "totalWeightInKb": 1193408 + }, + "protectedCapacityInKb": 50110464, + "protectedVacInKb": 67108864, + "protectionDomainIds": [ + "74d855a900000000" + ], + "rebalanceCapacityInKb": 0, + "rebalancePerReceiveJobNetThrottlingInKbps": 0, + "rebalanceReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "rebalanceWaitSendQLength": 0, + "rebalanceWriteBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "rebuildPerReceiveJobNetThrottlingInKbps": 0, + "rebuildWaitSendQLength": 0, + "rfacheReadHit": 0, + "rfacheWriteHit": 0, + "rfcacheAvgReadTime": 0, + "rfcacheAvgWriteTime": 0, + "rfcacheFdAvgReadTime": 0, + "rfcacheFdAvgWriteTime": 0, + "rfcacheFdCacheOverloaded": 0, + "rfcacheFdInlightReads": 0, + "rfcacheFdInlightWrites": 0, + "rfcacheFdIoErrors": 0, + "rfcacheFdMonitorErrorStuckIo": 0, + "rfcacheFdReadTimeGreater1Min": 0, + "rfcacheFdReadTimeGreater1Sec": 0, + "rfcacheFdReadTimeGreater500Millis": 0, + "rfcacheFdReadTimeGreater5Sec": 0, + "rfcacheFdReadsReceived": 0, + "rfcacheFdWriteTimeGreater1Min": 0, + "rfcacheFdWriteTimeGreater1Sec": 0, + "rfcacheFdWriteTimeGreater500Millis": 0, + "rfcacheFdWriteTimeGreater5Sec": 0, + "rfcacheFdWritesReceived": 0, + "rfcacheIoErrors": 0, + "rfcacheIosOutstanding": 0, + "rfcacheIosSkipped": 0, + "rfcachePooIosOutstanding": 0, + "rfcachePoolCachePages": 0, + "rfcachePoolEvictions": 0, + "rfcachePoolInLowMemoryCondition": 0, + "rfcachePoolIoTimeGreater1Min": 0, + "rfcachePoolLockTimeGreater1Sec": 0, + "rfcachePoolLowResourcesInitiatedPassthroughMode": 0, + "rfcachePoolNumCacheDevs": 0, + "rfcachePoolNumSrcDevs": 0, + "rfcachePoolPagesInuse": 0, + "rfcachePoolReadHit": 0, + "rfcachePoolReadMiss": 0, + "rfcachePoolReadPendingG10Millis": 0, + "rfcachePoolReadPendingG1Millis": 0, + "rfcachePoolReadPendingG1Sec": 0, + "rfcachePoolReadPendingG500Micro": 0, + "rfcachePoolReadsPending": 0, + "rfcachePoolSize": 0, + "rfcachePoolSourceIdMismatch": 0, + "rfcachePoolSuspendedIos": 0, + "rfcachePoolSuspendedPequestsRedundantSearchs": 0, + "rfcachePoolWriteHit": 0, + "rfcachePoolWriteMiss": 0, + "rfcachePoolWritePending": 0, + "rfcachePoolWritePendingG10Millis": 0, + "rfcachePoolWritePendingG1Millis": 0, + "rfcachePoolWritePendingG1Sec": 0, + "rfcachePoolWritePendingG500Micro": 0, + "rfcacheReadMiss": 0, + "rfcacheReadsFromCache": 0, + "rfcacheReadsPending": 0, + "rfcacheReadsReceived": 0, + "rfcacheReadsSkipped": 0, + "rfcacheReadsSkippedAlignedSizeTooLarge": 0, + "rfcacheReadsSkippedHeavyLoad": 0, + "rfcacheReadsSkippedInternalError": 0, + "rfcacheReadsSkippedLockIos": 0, + "rfcacheReadsSkippedLowResources": 0, + "rfcacheReadsSkippedMaxIoSize": 0, + "rfcacheReadsSkippedStuckIo": 0, + "rfcacheSkippedUnlinedWrite": 0, + "rfcacheSourceDeviceReads": 0, + "rfcacheSourceDeviceWrites": 0, + "rfcacheWriteMiss": 0, + "rfcacheWritePending": 0, + "rfcacheWritesReceived": 0, + "rfcacheWritesSkippedCacheMiss": 0, + "rfcacheWritesSkippedHeavyLoad": 0, + "rfcacheWritesSkippedInternalError": 0, + "rfcacheWritesSkippedLowResources": 0, + "rfcacheWritesSkippedMaxIoSize": 0, + "rfcacheWritesSkippedStuckIo": 0, + "rmPendingAllocatedInKb": 0, + "rmcache128kbEntryCount": 0, + "rmcache16kbEntryCount": 0, + "rmcache32kbEntryCount": 0, + "rmcache4kbEntryCount": 0, + "rmcache64kbEntryCount": 0, + "rmcache8kbEntryCount": 0, + "rmcacheBigBlockEvictionCount": 0, + "rmcacheBigBlockEvictionSizeCountInKb": 0, + "rmcacheCurrNumOf128kbEntries": 0, + "rmcacheCurrNumOf16kbEntries": 0, + "rmcacheCurrNumOf32kbEntries": 0, + "rmcacheCurrNumOf4kbEntries": 0, + "rmcacheCurrNumOf64kbEntries": 0, + "rmcacheCurrNumOf8kbEntries": 0, + "rmcacheEntryEvictionCount": 0, + "rmcacheEntryEvictionSizeCountInKb": 0, + "rmcacheNoEvictionCount": 0, + "rmcacheSizeInKb": 393216, + "rmcacheSizeInUseInKb": 0, + "rmcacheSkipCountCacheAllBusy": 0, + "rmcacheSkipCountLargeIo": 0, + "rmcacheSkipCountUnaligned4kbIo": 0, + "scsiInitiatorIds": [], + "sdcIds": [ + "6076fd0f00000000", + "6076fd1000000001", + "6076fd1100000002" + ], + "secondaryReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "secondaryReadFromDevBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "secondaryReadFromRmcacheBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "secondaryVacInKb": 33554432, + "secondaryWriteBwc": { + "numOccured": 1530, + "numSeconds": 5, + "totalWeightInKb": 1169632 + }, + "semiProtectedCapacityInKb": 0, + "semiProtectedVacInKb": 0, + "snapCapacityInUseInKb": 19845120, + "snapCapacityInUseOccupiedInKb": 749568, + "spareCapacityInKb": 64380928, + "thickCapacityInUseInKb": 0, + "thinCapacityAllocatedInKb": 67108864, + "thinCapacityInUseInKb": 49360896, + "totalReadBwc": { + "numOccured": 1, + "numSeconds": 5, + "totalWeightInKb": 4 + }, + "totalWriteBwc": { + "numOccured": 3086, + "numSeconds": 5, + "totalWeightInKb": 2363040 + }, + "unreachableUnusedCapacityInKb": 0, + "unusedCapacityInKb": 529328128, + "userDataReadBwc": { + "numOccured": 0, + "numSeconds": 0, + "totalWeightInKb": 0 + }, + "userDataWriteBwc": { + "numOccured": 285, + "numSeconds": 1, + "totalWeightInKb": 227170 + } + } +}
\ No newline at end of file |