Skip to content

Commit

Permalink
Adds file System metrics
Browse files Browse the repository at this point in the history
Adds unit/int test for added metric API

Signed-off-by: Utkarsh Dubey <[email protected]>
  • Loading branch information
delldubey committed May 9, 2024
1 parent 4e2941d commit fe94e7a
Show file tree
Hide file tree
Showing 8 changed files with 267 additions and 58 deletions.
7 changes: 4 additions & 3 deletions interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,15 +358,16 @@ type Pmax interface {

// GetStorageGroupMetrics returns the list of required metrics
GetStorageGroupMetrics(ctx context.Context, symID string, storageGroupID string, metricsQuery []string, firstAvailableDate int64, lastAvailableTime int64) (*types.StorageGroupMetricsIterator, error)

// GetVolumesMetrics returns the list of volume metrics for specific storage groups
GetVolumesMetrics(ctx context.Context, symID string, storageGroups string, metricsQuery []string, firstAvailableDate int64, lastAvailableTime int64) (*types.VolumeMetricsIterator, error)

// GetStorageGroupPerfKeys returns the performance keys of storage group
GetStorageGroupPerfKeys(ctx context.Context, symID string) (*types.StorageGroupKeysResult, error)

// GetArrayPerfKeys returns the performance keys of array
GetArrayPerfKeys(ctx context.Context) (*types.ArrayKeysResult, error)
// GetVolumesMetricsByID returns a given Volume performance metrics
GetVolumesMetricsByID(ctx context.Context, symID string, volID string, metricsQuery []string, firstAvailableTime, lastAvailableTime int64) (*types.VolumeMetricsIterator, error)
// GetFileSystemMetricsByID returns a given FileSystem performance metrics
GetFileSystemMetricsByID(ctx context.Context, symID string, fsID string, metricsQuery []string, firstAvailableTime, lastAvailableTime int64) (*types.FileSystemMetricsIterator, error)

// CreateMigrationEnvironment creates a migration environment
CreateMigrationEnvironment(ctx context.Context, sourceSymID, remoteSymID string) (*types.MigrationEnv, error)
Expand Down
10 changes: 10 additions & 0 deletions inttest/pmax_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2219,10 +2219,20 @@ func TestGetVolumesMetrics(t *testing.T) {
t.Errorf("Failed to get array %s perf keys", symmetrixID)
return
}
fmt.Println("... getting VolumeMetrics ...")
metrics, err := client.GetVolumesMetrics(context.TODO(), symmetrixID, defaultStorageGroup, queryParams, firstTime, lastTime)
if err != nil {
t.Errorf("Failed to get volume in storage group %s Metrics", defaultStorageGroup)
return
}
fmt.Printf("MBRead of volume %s: %f \n", metrics.ResultList.Result[0].VolumeID, metrics.ResultList.Result[0].VolumeResult[0].MBRead)

fmt.Println("... getting VolumeMetricsByID ...")

metrics, err = client.GetVolumesMetricsByID(context.TODO(), symmetrixID, vol.VolumeID, queryParams, firstTime, lastTime)
if err != nil {
t.Errorf("Failed to get volume in storage group %s Metrics", defaultStorageGroup)
return
}
fmt.Printf("MBRead of volume %s: %f \n", metrics.ResultList.Result[0].VolumeID, metrics.ResultList.Result[0].VolumeResult[0].MBRead)
}
68 changes: 68 additions & 0 deletions metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const (
Performance = "performance"
StorageGroup = "/StorageGroup"
Volume = "/Volume"
FileSystem = "/file/filesystem"
Metrics = "/metrics"
Keys = "/keys"
Array = "/Array"
Expand Down Expand Up @@ -149,3 +150,70 @@ func (c *Client) GetVolumesMetrics(ctx context.Context, symID string, storageGro
}
return metricsList, nil
}

// GetVolumesMetricsByID returns a given Volume performance metrics
func (c *Client) GetVolumesMetricsByID(ctx context.Context, symID string, volID string, metricsQuery []string, firstAvailableTime, lastAvailableTime int64) (*types.VolumeMetricsIterator, error) {
defer c.TimeSpent("GetVolumesMetricsByID", time.Now())
if _, err := c.IsAllowedArray(symID); err != nil {
return nil, err
}
URL := RESTPrefix + Performance + Volume + Metrics
ctx, cancel := c.GetTimeoutContext(ctx)
defer cancel()
params := types.VolumeMetricsParam{
SystemID: symID,
StartDate: firstAvailableTime,
EndDate: lastAvailableTime,
VolumeStartRange: volID,
VolumeEndRange: volID,
DataFormat: Average,
Metrics: metricsQuery,
}
resp, err := c.api.DoAndGetResponseBody(ctx, http.MethodPost, URL, c.getDefaultHeaders(), params)
if err = c.checkResponse(resp); err != nil {
return nil, err
}
metricsList := &types.VolumeMetricsIterator{}
decoder := json.NewDecoder(resp.Body)
if err = decoder.Decode(metricsList); err != nil {
return nil, err
}
err = resp.Body.Close()
if err != nil {
return nil, err
}
return metricsList, nil
}

// GetFileSystemMetricsByID returns a given FileSystem performance metrics
func (c *Client) GetFileSystemMetricsByID(ctx context.Context, symID string, fsID string, metricsQuery []string, firstAvailableTime, lastAvailableTime int64) (*types.FileSystemMetricsIterator, error) {
defer c.TimeSpent("GetFileSystemMetricsByID", time.Now())
if _, err := c.IsAllowedArray(symID); err != nil {
return nil, err
}
URL := RESTPrefix + Performance + FileSystem + Metrics
ctx, cancel := c.GetTimeoutContext(ctx)
defer cancel()
params := types.FileSystemMetricsParam{
SystemID: symID,
StartDate: firstAvailableTime,
EndDate: lastAvailableTime,
DataFormat: Average,
FileSystemID: fsID,
Metrics: metricsQuery,
}
resp, err := c.api.DoAndGetResponseBody(ctx, http.MethodPost, URL, c.getDefaultHeaders(), params)
if err = c.checkResponse(resp); err != nil {
return nil, err
}
metricsList := &types.FileSystemMetricsIterator{}
decoder := json.NewDecoder(resp.Body)
if err = decoder.Decode(metricsList); err != nil {
return nil, err
}
err = resp.Body.Close()
if err != nil {
return nil, err
}
return metricsList, nil
}
30 changes: 30 additions & 0 deletions mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ var InducedErrors struct {
GetHostGroupListError bool
GetStorageGroupMetricsError bool
GetVolumesMetricsError bool
GetFileSysMetricsError bool
GetStorageGroupPerfKeyError bool
GetArrayPerfKeyError bool
GetFreeRDFGError bool
Expand Down Expand Up @@ -355,6 +356,7 @@ func Reset() {
InducedErrors.GetHostGroupListError = false
InducedErrors.GetStorageGroupMetricsError = false
InducedErrors.GetVolumesMetricsError = false
InducedErrors.GetFileSysMetricsError = false
InducedErrors.GetStorageGroupPerfKeyError = false
InducedErrors.GetArrayPerfKeyError = false
InducedErrors.GetFreeRDFGError = false
Expand Down Expand Up @@ -626,6 +628,7 @@ func getRouter() http.Handler {
// Performance Metrics
router.HandleFunc(PREFIXNOVERSION+"/performance/StorageGroup/metrics", handleStorageGroupMetrics)
router.HandleFunc(PREFIXNOVERSION+"/performance/Volume/metrics", handleVolumeMetrics)
router.HandleFunc(PREFIXNOVERSION+"/performance/file/filesystem/metrics", handleFileSysMetrics)

// Performance Keys
router.HandleFunc(PREFIXNOVERSION+"/performance/StorageGroup/keys", handleStorageGroupPerfKeys)
Expand Down Expand Up @@ -3314,6 +3317,33 @@ func handleVolumeMetrics(w http.ResponseWriter, r *http.Request) {
writeJSON(w, metricsIterator)
}

// /univmax/restapi/performance/file/filesystem/metrics
func handleFileSysMetrics(w http.ResponseWriter, _ *http.Request) {
mockCacheMutex.Lock()
defer mockCacheMutex.Unlock()
if InducedErrors.GetFileSysMetricsError {
writeError(w, "Error getting volume metrics: induced error", http.StatusRequestTimeout)
return
}
fileMetric := types.FileSystemResult{
PercentBusy: 1,
Timestamp: 1671091500000,
}

metricsIterator := &types.FileSystemMetricsIterator{
ResultList: types.FileSystemMetricsResultList{
Result: []types.FileSystemResult{fileMetric},
From: 1,
To: 1,
},
ID: "query_id",
Count: 1,
ExpirationTime: 1671091597409,
MaxPageSize: 1000,
}
writeJSON(w, metricsIterator)
}

// /univmax/restapi/performance/StorageGroup/keys
func handleStorageGroupPerfKeys(w http.ResponseWriter, r *http.Request) {
mockCacheMutex.Lock()
Expand Down
35 changes: 35 additions & 0 deletions types/v100/performanceMetrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ type VolumeMetricsParam struct {
SystemID string `json:"systemId"`
StartDate int64 `json:"startDate"`
EndDate int64 `json:"endDate"`
VolumeStartRange string `json:"volumeStartRange"`
VolumeEndRange string `json:"volumeEndRange"`
DataFormat string `json:"dataFormat"`
CommaSeparatedStorageGroupList string `json:"commaSeparatedStorageGroupList"`
Metrics []string `json:"metrics"`
Expand Down Expand Up @@ -94,6 +96,7 @@ type VolumeMetric struct {
Writes float64 `json:"Writes"`
ReadResponseTime float64 `json:"ReadResponseTime"`
WriteResponseTime float64 `json:"WriteResponseTime"`
IoRate float64 `json:"IoRate"`
Timestamp int64 `json:"timestamp"`
}

Expand Down Expand Up @@ -125,3 +128,35 @@ type ArrayInfo struct {
FirstAvailableDate int64 `json:"firstAvailableDate"`
LastAvailableDate int64 `json:"lastAvailableDate"`
}

// FileSystemMetricsParam contains req param for filesystem metric
type FileSystemMetricsParam struct {
SystemID string `json:"systemId"`
EndDate int64 `json:"endDate"`
FileSystemID string `json:"fileSystemID"`
DataFormat string `json:"dataFormat"`
Metrics []string `json:"metrics"`
StartDate int64 `json:"startDate"`
}

// FileSystemMetricsIterator contains the result of query
type FileSystemMetricsIterator struct {
ResultList FileSystemMetricsResultList `json:"resultList"`
ID string `json:"id"`
Count int `json:"count"`
ExpirationTime int64 `json:"expirationTime"`
MaxPageSize int `json:"maxPageSize"`
}

// FileSystemMetricsResultList contains the list of volume result
type FileSystemMetricsResultList struct {
Result []FileSystemResult `json:"result"`
From int `json:"from"`
To int `json:"to"`
}

// FileSystemResult contains the list of volume metrics and ID of volume
type FileSystemResult struct {
PercentBusy float64 `json:"PercentBusy"`
Timestamp int64 `json:"timestamp"`
}
34 changes: 34 additions & 0 deletions unit_steps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ type unitContext struct {
volResultPrivate *types.VolumeResultPrivate
storageGroupMetrics *types.StorageGroupMetricsIterator
volumesMetrics *types.VolumeMetricsIterator
fileSystemMetrics *types.FileSystemMetricsIterator

sgSnapshot *types.StorageGroupSnapshot
storageGroupSnapSetting *types.CreateStorageGroupSnapshot
Expand Down Expand Up @@ -179,6 +180,8 @@ func (c *unitContext) reset() {
c.nfsExport = nil
c.nasServer = nil
c.fileInterface = nil
c.volumesMetrics = nil
c.fileSystemMetrics = nil
}

func (c *unitContext) iInduceError(errorType string) error {
Expand Down Expand Up @@ -393,6 +396,8 @@ func (c *unitContext) iInduceError(errorType string) error {
mock.InducedErrors.GetStorageGroupMetricsError = true
case "GetVolumesMetricsError":
mock.InducedErrors.GetVolumesMetricsError = true
case "GetFileSysMetricsError":
mock.InducedErrors.GetFileSysMetricsError = true
case "GetStorageGroupPerfKeyError":
mock.InducedErrors.GetStorageGroupPerfKeyError = true
case "GetArrayPerfKeyError":
Expand Down Expand Up @@ -2234,6 +2239,13 @@ func (c *unitContext) iCallGetVolumesMetrics() error {
return nil
}

func (c *unitContext) iCallGetVolumesMetricsByIDFor(volID string) error {
var metrics *types.VolumeMetricsIterator
metrics, c.err = c.client.GetVolumesMetricsByID(context.TODO(), symID, volID, []string{"MBReads"}, 0, 0)
c.volumesMetrics = metrics
return nil
}

func (c *unitContext) iGetVolumesMetrics() error {
if c.err == nil {
if c.volumesMetrics == nil {
Expand All @@ -2246,6 +2258,25 @@ func (c *unitContext) iGetVolumesMetrics() error {
return nil
}

func (c *unitContext) iCallGetFileSystemMetricsByIDFor(fileSystemID string) error {
var metrics *types.FileSystemMetricsIterator
metrics, c.err = c.client.GetFileSystemMetricsByID(context.TODO(), symID, fileSystemID, []string{"MBReads"}, 0, 0)
c.fileSystemMetrics = metrics
return nil
}

func (c *unitContext) iGetFileMetrics() error {
if c.err == nil {
if c.fileSystemMetrics == nil {
return fmt.Errorf("fileMetrics nil")
}
if len(c.fileSystemMetrics.ResultList.Result) == 0 {
return fmt.Errorf("no metric in filemetrics")
}
}
return nil
}

func (c *unitContext) iCallGetStorageGroupPerfKeys() error {
var perfKeys *types.StorageGroupKeysResult
perfKeys, c.err = c.client.GetStorageGroupPerfKeys(context.TODO(), symID)
Expand Down Expand Up @@ -2751,6 +2782,9 @@ func UnitTestContext(s *godog.ScenarioContext) {
s.Step(`^I get StorageGroupMetrics$`, c.iGetStorageGroupMetrics)
s.Step(`^I call GetVolumesMetrics$`, c.iCallGetVolumesMetrics)
s.Step(`^I get VolumesMetrics$`, c.iGetVolumesMetrics)
s.Step(`^I call GetFileSystemMetricsByID for "([^"]*)"$`, c.iCallGetFileSystemMetricsByIDFor)
s.Step(`^I call GetVolumesMetricsByID for "([^"]*)"$`, c.iCallGetVolumesMetricsByIDFor)
s.Step(`^I get FileMetrics$`, c.iGetFileMetrics)

// Performance keys
s.Step(`^I call GetStorageGroupPerfKeys$`, c.iCallGetStorageGroupPerfKeys)
Expand Down
86 changes: 86 additions & 0 deletions unittest/metric.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
Feature: PMAX metrics test

Scenario Outline: Test GetStorageGroupMetrics
Given a valid connection
And I have an allowed list of <arrays>
And I induce error <induced>
When I call GetStorageGroupMetrics
Then the error message contains <errormsg>
And I get StorageGroupMetrics

Examples:
| arrays | induced | errormsg |
| "000000000000" | "none" | "ignored as it is not managed" |
| "000197900046" | "GetStorageGroupMetricsError" | "induced error" |
| "000197900046" | "none" | "none" |

Scenario Outline: Test GetVolumesMetrics
Given a valid connection
And I have an allowed list of <arrays>
And I induce error <induced>
When I call GetVolumesMetrics
Then the error message contains <errormsg>
And I get VolumesMetrics

Examples:
| arrays | induced | errormsg |
| "000000000000" | "none" | "ignored as it is not managed" |
| "000197900046" | "GetVolumesMetricsError" | "induced error" |
| "000197900046" | "none" | "none" |

Scenario Outline: Test GetStorageGroupPerfKeys
Given a valid connection
And I have an allowed list of <arrays>
And I induce error <induced>
When I call GetStorageGroupPerfKeys
Then the error message contains <errormsg>
And I get StorageGroupPerfKeys

Examples:
| arrays | induced | errormsg |
| "000000000000" | "none" | "ignored as it is not managed" |
| "000197900046" | "GetStorageGroupPerfKeyError" | "induced error" |
| "000197900046" | "none" | "none" |


Scenario Outline: Test GetArrayPerfKeys
Given a valid connection
And I induce error <induced>
When I call GetArrayPerfKeys
Then the error message contains <errormsg>
And I get ArrayPerfKeys

Examples:
| arrays | induced | errormsg |
| "000197900046" | "GetArrayPerfKeyError" | "induced error" |
| "000197900046" | "none" | "none" |

@this
Scenario Outline: Test GetVolumesMetricsByID
Given a valid connection
And I have an allowed list of <arrays>
And I induce error <induced>
When I call GetVolumesMetricsByID for "vol1"
Then the error message contains <errormsg>
And I get VolumesMetrics

Examples:
| arrays | induced | errormsg |
| "000000000000" | "none" | "ignored as it is not managed" |
| "000197900046" | "GetVolumesMetricsError" | "induced error" |
| "000197900046" | "none" | "none" |

@this
Scenario Outline: Test GetFileSystemMetricsByID
Given a valid connection
And I have an allowed list of <arrays>
And I induce error <induced>
When I call GetFileSystemMetricsByID for "file1"
Then the error message contains <errormsg>
And I get FileMetrics

Examples:
| arrays | induced | errormsg |
| "000000000000" | "none" | "ignored as it is not managed" |
| "000197900046" | "GetFileSysMetricsError" | "induced error" |
| "000197900046" | "none" | "none" |
Loading

0 comments on commit fe94e7a

Please sign in to comment.