diff --git a/client.go b/client.go index 30a8eff..66253f4 100644 --- a/client.go +++ b/client.go @@ -142,6 +142,7 @@ type Client interface { PerformanceMetricsByAppliance(ctx context.Context, entityID string, interval MetricsIntervalEnum) ([]PerformanceMetricsByApplianceResponse, error) PerformanceMetricsByNode(ctx context.Context, entityID string, interval MetricsIntervalEnum) ([]PerformanceMetricsByNodeResponse, error) PerformanceMetricsByVolume(ctx context.Context, entityID string, interval MetricsIntervalEnum) ([]PerformanceMetricsByVolumeResponse, error) + VolumeMirrorTransferRate(ctx context.Context, entityID string) ([]VolumeMirrorTransferRateResponse, error) PerformanceMetricsByCluster(ctx context.Context, entityID string, interval MetricsIntervalEnum) ([]PerformanceMetricsByClusterResponse, error) PerformanceMetricsByVM(ctx context.Context, entityID string, interval MetricsIntervalEnum) ([]PerformanceMetricsByVMResponse, error) PerformanceMetricsByVg(ctx context.Context, entityID string, interval MetricsIntervalEnum) ([]PerformanceMetricsByVgResponse, error) diff --git a/go.mod b/go.mod index 39c5d56..f0a3f92 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ module github.com/dell/gopowerstore go 1.23 - +toolchain go1.23.1 require ( github.com/go-openapi/strfmt v0.23.0 github.com/jarcoal/httpmock v1.2.0 diff --git a/inttests/metrics_test.go b/inttests/metrics_test.go index 437f6ce..dfb2d80 100644 --- a/inttests/metrics_test.go +++ b/inttests/metrics_test.go @@ -60,6 +60,19 @@ func Test_PerformanceMetricsByVolume(t *testing.T) { assert.Equal(t, "performance_metrics_by_volume", resp[0].Entity) } +func Test_VolumeMirrorTransferRate(t *testing.T) { + volumesResp, err := C.GetVolumes(context.Background()) + checkAPIErr(t, err) + if len(volumesResp) == 0 { + t.Skip("no volumes are available to check for metrics") + return + } + resp, err := C.VolumeMirrorTransferRate(context.Background(), volumesResp[0].ID) + checkAPIErr(t, err) + assert.NotEmpty(t, resp) + assert.Equal(t, "volume_mirror_transfer_rate", resp[0].ID) +} + func Test_PerformanceMetricsByCluster(t *testing.T) { resp, err := C.PerformanceMetricsByCluster(context.Background(), "0", gopowerstore.FiveMins) checkAPIErr(t, err) diff --git a/metrics.go b/metrics.go index 1acd664..e580477 100644 --- a/metrics.go +++ b/metrics.go @@ -1,6 +1,6 @@ /* * - * Copyright © 2020-2022 Dell Inc. or its subsidiaries. All Rights Reserved. + * Copyright © 2020-2024 Dell Inc. or its subsidiaries. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,9 +21,15 @@ package gopowerstore import ( "context" "errors" + "fmt" + "net/http" ) -const metricsURL = "metrics" +const ( + metricsURL = "metrics" + mirrorURL = "volume_mirror_transfer_rate_cma_view" + limit = 2000 +) func (c *ClientIMPL) metricsRequest(ctx context.Context, response interface{}, entity string, entityID string, interval MetricsIntervalEnum) error { _, err := c.APIClient().Query( @@ -45,6 +51,35 @@ func (c *ClientIMPL) metricsRequest(ctx context.Context, response interface{}, e return err } +// mirrorTransferRate - Volume Mirror Transfer Rate +func (c *ClientIMPL) mirrorTransferRate(ctx context.Context, response interface{}, entityID string, limit int) error { + qp := getFSDefaultQueryParams(c) + qp.RawArg("id", fmt.Sprintf("eq.%s", entityID)) + qp.Limit(limit) + qp.RawArg("select", "id,timestamp,synchronization_bandwidth,mirror_bandwidth,data_remaining") + + customHeader := http.Header{} + customHeader.Add("DELL-VISIBILITY", "Internal") + apiClient := c.APIClient() + apiClient.SetCustomHTTPHeaders(customHeader) + + _, err := c.APIClient().Query( + ctx, + RequestConfig{ + Method: "GET", + Endpoint: mirrorURL, + QueryParams: qp, + }, + response) + if err != nil { + err = WrapErr(err) + } + customHeader.Del("DELL-VISIBILITY") + apiClient.SetCustomHTTPHeaders(customHeader) + + return err +} + // PerformanceMetricsByAppliance - Appliance performance metrics func (c *ClientIMPL) PerformanceMetricsByAppliance(ctx context.Context, entityID string, interval MetricsIntervalEnum) ([]PerformanceMetricsByApplianceResponse, error) { var resp []PerformanceMetricsByApplianceResponse @@ -66,6 +101,13 @@ func (c *ClientIMPL) PerformanceMetricsByVolume(ctx context.Context, entityID st return resp, err } +// VolumeMirrorTransferRate - Volume Mirror Transfer Rate +func (c *ClientIMPL) VolumeMirrorTransferRate(ctx context.Context, entityID string) ([]VolumeMirrorTransferRateResponse, error) { + var resp []VolumeMirrorTransferRateResponse + err := c.mirrorTransferRate(ctx, &resp, entityID, limit) + return resp, err +} + // PerformanceMetricsByCluster - Cluster performance metrics func (c *ClientIMPL) PerformanceMetricsByCluster(ctx context.Context, entityID string, interval MetricsIntervalEnum) ([]PerformanceMetricsByClusterResponse, error) { var resp []PerformanceMetricsByClusterResponse diff --git a/metrics_test.go b/metrics_test.go index 3b4a0f0..4df05de 100644 --- a/metrics_test.go +++ b/metrics_test.go @@ -1,6 +1,6 @@ /* * - * Copyright © 2020-2022 Dell Inc. or its subsidiaries. All Rights Reserved. + * Copyright © 2020-2024 Dell Inc. or its subsidiaries. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,11 @@ import ( "github.com/stretchr/testify/assert" ) -const metricsMockURL = APIMockURL + metricsURL +const ( + metricsMockURL = APIMockURL + metricsURL + metricsMockVolMirrURL = APIMockURL + mirrorURL + volumeID = "4ffcd8e8-2a93-49ed-b9b3-2e68c8ddc5e4" +) func TestClientIMPL_GetCapacity(t *testing.T) { totalSpace0 := 12077448036352 @@ -136,6 +140,20 @@ func TestClientIMPL_PerformanceMetricsByVolume(t *testing.T) { assert.Equal(t, float64(1000), resp[0].TotalIops) } +func TestClientIMPL_VolumeMirrorTransferRate(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + setResponder := func(respData string) { + httpmock.RegisterResponder("GET", metricsMockVolMirrURL, + httpmock.NewStringResponder(200, respData)) + } + respData := fmt.Sprintf(`[{"id": "%s"}]`, volumeID) + setResponder(respData) + volMirr, err := C.VolumeMirrorTransferRate(context.Background(), volumeID) + assert.Nil(t, err) + assert.Equal(t, volumeID, volMirr[0].ID) +} + func TestClientIMPL_PerformanceMetricsByCluster(t *testing.T) { httpmock.Activate() defer httpmock.DeactivateAndReset() diff --git a/metrics_types.go b/metrics_types.go index 5d3cb26..cb29b63 100644 --- a/metrics_types.go +++ b/metrics_types.go @@ -1,6 +1,6 @@ /* * - * Copyright © 2020-2022 Dell Inc. or its subsidiaries. All Rights Reserved. + * Copyright © 2020-2024 Dell Inc. or its subsidiaries. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1194,6 +1194,24 @@ type PerformanceMetricsByVolumeResponse struct { CommonMaxAvgIopsBandwidthFields } +// VolumeMirrorTransferRateResponse is returned by volume_mirror_transfer_rate +type VolumeMirrorTransferRateResponse struct { + // Unique identifier representing a specific volume. + ID string `json:"id,omitempty"` + + // The timestamp of the last read or write operation. + Timestamp strfmt.DateTime `json:"timestamp,omitempty"` + + // The read or write bandwidth in bytes per second. + SynchronizationBandwidth float32 `json:"synchronization_bandwidth,omitempty"` + + // The read or write bandwidth in bytes per second. + MirrorBandwidth float32 `json:"mirror_bandwidth,omitempty"` + + // The amount of data remaining in the bandwidth + DataRemaining float32 `json:"data_remaining,omitempty"` +} + type CommonAvgFields struct { // Average size of read and write operations in bytes. AvgIoSize float32 `json:"avg_io_size,omitempty"` diff --git a/mocks/Client.go b/mocks/Client.go index 29f745c..d138f0d 100644 --- a/mocks/Client.go +++ b/mocks/Client.go @@ -3711,6 +3711,33 @@ func (_m *Client) PerformanceMetricsByVolume(ctx context.Context, entityID strin return r0, r1 } +func (_m *Client) VolumeMirrorTransferRate(ctx context.Context, entityID string) ([]gopowerstore.VolumeMirrorTransferRateResponse, error) { + ret := _m.Called(ctx, entityID) + + if len(ret) == 0 { + panic("no return value specified for VolumeMirrorTransferRate") + } + + var r0 []gopowerstore.VolumeMirrorTransferRateResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) ([]gopowerstore.VolumeMirrorTransferRateResponse, error)); ok { + return rf(ctx, entityID) + } + if rf, ok := ret.Get(0).(func(context.Context, string) []gopowerstore.VolumeMirrorTransferRateResponse); ok { + r0 = rf(ctx, entityID) + } else { + r0 = ret.Get(0).([]gopowerstore.VolumeMirrorTransferRateResponse) + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, entityID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // PerformanceMetricsNfsByNode provides a mock function with given fields: ctx, entityID, interval func (_m *Client) PerformanceMetricsNfsByNode(ctx context.Context, entityID string, interval gopowerstore.MetricsIntervalEnum) ([]gopowerstore.PerformanceMetricsByNfsResponse, error) { ret := _m.Called(ctx, entityID, interval) @@ -4342,7 +4369,8 @@ func (_m *Client) WearMetricsByDrive(ctx context.Context, entityID string, inter func NewClient(t interface { mock.TestingT Cleanup(func()) -}) *Client { +}, +) *Client { mock := &Client{} mock.Mock.Test(t)