Skip to content

Commit

Permalink
Adds File System metrics and its test scenarios (#60)
Browse files Browse the repository at this point in the history
  • Loading branch information
delldubey authored May 14, 2024
1 parent 4e2941d commit 0b464a1
Show file tree
Hide file tree
Showing 15 changed files with 343 additions and 109 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/linters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ jobs:
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.53
version: v1.56
skip-cache: true
4 changes: 2 additions & 2 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,10 @@ func New(
c.http.Timeout = opts.Timeout
}

if opts.Insecure { // #nosec G402
if opts.Insecure {
c.http.Transport = &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
InsecureSkipVerify: true, // #nosec G402
},
}
} else {
Expand Down
19 changes: 10 additions & 9 deletions interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ type Pmax interface {
// GetVolumeIDsIteratorWithParams returns an iterator of a list of volumes with query parameters
GetVolumeIDsIteratorWithParams(ctx context.Context, symID string, queryParams map[string]string) (*types.VolumeIterator, error)

// GetVolumeIDsIteraotrPage gets a page of volume ids from a Volume iterator.
// GetVolumeIDsIteratorPage gets a page of volume ids from a Volume iterator.
GetVolumeIDsIteratorPage(ctx context.Context, iter *types.VolumeIterator, from, to int) ([]string, error)

// DeleteVolumeIDsIterator deletes a Volume iterator.
Expand Down Expand Up @@ -134,10 +134,10 @@ type Pmax interface {
CreateVolumeInProtectedStorageGroupS(ctx context.Context, symID, remoteSymID, storageGroupID string, remoteStorageGroupID string, volumeName string, volumeSize interface{}, volOpts map[string]interface{}, opts ...http.Header) (*types.Volume, error)

// GetStorageGroupSnapshots Gets All Storage Group Snapshots
GetStorageGroupSnapshots(ctx context.Context, symID string, storageGroupID string, exludeManualSnaps bool, exludeSlSnaps bool) (*types.StorageGroupSnapshot, error)
GetStorageGroupSnapshots(ctx context.Context, symID string, storageGroupID string, excludeManualSnaps bool, excludeSlSnaps bool) (*types.StorageGroupSnapshot, error)

// GetStorageGroupSnapshotSnapIds Gets a list of SnapIDs for a particular snapshot
GetStorageGroupSnapshotSnapIds(ctx context.Context, symID string, storageGroupID string, snapshotID string) (*types.SnapID, error)
// GetStorageGroupSnapshotSnapIDs Gets a list of SnapIDs for a particular snapshot
GetStorageGroupSnapshotSnapIDs(ctx context.Context, symID string, storageGroupID string, snapshotID string) (*types.SnapID, error)

// GetStorageGroupSnapshotSnap Gets the details of a storage group snapshot snap
GetStorageGroupSnapshotSnap(ctx context.Context, symID string, storageGroupID string, snapshotID, snapID string) (*types.StorageGroupSnap, error)
Expand All @@ -157,7 +157,7 @@ type Pmax interface {
// DeleteMaskingView deletes a masking view given a masking view id
DeleteMaskingView(ctx context.Context, symID string, maskingViewID string) error

// RenameMaskingView renames masking view given it's identifier (which is the name)
// RenameMaskingView renames masking view given its identifier (which is the name)
RenameMaskingView(ctx context.Context, symID string, maskingViewID string, newName string) (*types.MaskingView, error)

// GetStoragePoolList Gets the list of Storage Pools
Expand Down Expand Up @@ -189,7 +189,7 @@ type Pmax interface {
// GetMaskingViewList returns a list of the MaskingView names.
GetMaskingViewList(ctx context.Context, symID string) (*types.MaskingViewList, error)

// GetMaskingViewByID returns a masking view given it's identifier (which is the name)
// GetMaskingViewByID returns a masking view given its identifier (which is the name)
GetMaskingViewByID(ctx context.Context, symID string, maskingViewID string) (*types.MaskingView, error)

// GetMaskingViewConnections returns the connections of a masking view (optionally for a specific volume id.)
Expand Down 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)
}
12 changes: 6 additions & 6 deletions inttest/pmax_replication_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,18 +141,18 @@ func TestCrudStorageGroupSnapshot(t *testing.T) {
}
fmt.Printf("Successfully created snapshot (%v)\n", sgSnap)

// Get the list of SnapIds
sgSnapIds, err := client.GetStorageGroupSnapshotSnapIds(context.TODO(), symmetrixID, snapshotSgName, defaultSnapshotName)
// Get the list of SnapIDs
sgSnapIDs, err := client.GetStorageGroupSnapshotSnapIDs(context.TODO(), symmetrixID, snapshotSgName, defaultSnapshotName)
if err != nil {
t.Error("Error getting the snapshot snapid details on storage group: " + err.Error())
// Cleanup temp sg
cleanupVolume(vol.VolumeID, volumeName, snapshotSgName, t)
deleteStorageGroup(symmetrixID, snapshotSgName)
return
}
fmt.Printf("Successfully fetched snapshot ids (%v) \n\n", sgSnapIds)
fmt.Printf("Successfully fetched snapshot ids (%v) \n\n", sgSnapIDs)

snapid := strconv.FormatInt(sgSnapIds.SnapIds[0], 10)
snapid := strconv.FormatInt(sgSnapIDs.SnapIDs[0], 10)

// Link snap
modifyPayloadLink := &types.ModifyStorageGroupSnapshot{
Expand Down Expand Up @@ -843,7 +843,7 @@ func afterRun(tests []testing.InternalTest) {
})
}
cleanup = append(cleanup, tests...)
testing.Main(func(pat, str string) (bool, error) {
testing.Main(func(_, _ string) (bool, error) {
return true, nil
}, cleanup, nil, nil)
}
Expand Down Expand Up @@ -1096,7 +1096,7 @@ func TestGetSnapshotPolicyList(t *testing.T) {
t.Error("Error calling GetSnapshotPolicyList " + err.Error())
return
}
fmt.Printf("Snapshot Policy names: %v\n", targets.SnapshotPolicyIds)
fmt.Printf("Snapshot Policy names: %v\n", targets.SnapshotPolicyIDs)
}

func TestDeleteSnapshotPolicy(t *testing.T) {
Expand Down
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
}
62 changes: 54 additions & 8 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 @@ -597,7 +599,7 @@ func getRouter() http.Handler {

// StorageGroup Snapshots
router.HandleFunc(PREFIX+"/replication/symmetrix/{symid}/storagegroup/{StorageGroupId}/snapshot", handleGetStorageGroupSnapshots)
router.HandleFunc(PREFIX+"/replication/symmetrix/{symid}/storagegroup/{StorageGroupId}/snapshot/{snapshotId}/snapid", handleGetStorageGroupSnapshotsSnapsIds)
router.HandleFunc(PREFIX+"/replication/symmetrix/{symid}/storagegroup/{StorageGroupId}/snapshot/{snapshotId}/snapid", handleGetStorageGroupSnapshotsSnapsIDs)
router.HandleFunc(PREFIX+"/replication/symmetrix/{symid}/storagegroup/{StorageGroupId}/snapshot/{snapshotId}/snapid/{snapID}", handleGetStorageGroupSnapshotsSnapsDetails)

// Snapshot
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 @@ -692,7 +695,7 @@ func handleGetStorageGroupSnapshotsSnapsDetails(w http.ResponseWriter, r *http.R
}

// GET /replication/symmetrix/{symid}/storagegroup/{StorageGroupId}/snapshot/{snapshotId}/snapid
func handleGetStorageGroupSnapshotsSnapsIds(w http.ResponseWriter, r *http.Request) {
func handleGetStorageGroupSnapshotsSnapsIDs(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
writeError(w, "Method not allowed", http.StatusMethodNotAllowed)
return
Expand All @@ -704,7 +707,7 @@ func handleGetStorageGroupSnapshotsSnapsIds(w http.ResponseWriter, r *http.Reque
snaps := make([]int64, 1)
snaps = append(snaps, 1234)
snapIDs := &types.SnapID{
SnapIds: snaps,
SnapIDs: snaps,
}
writeJSON(w, snapIDs)
}
Expand Down Expand Up @@ -820,7 +823,7 @@ func handleCreateSnapshotPolicy(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
ids := []string{"Test123", "Test345"}
snapPolicyList := &types.SnapshotPolicyList{
SnapshotPolicyIds: ids,
SnapshotPolicyIDs: ids,
}
writeJSON(w, snapPolicyList)
}
Expand Down Expand Up @@ -1459,7 +1462,11 @@ func handleVolume(w http.ResponseWriter, r *http.Request) {
writeError(w, "Error deleting Volume: induced error - device is a member of a storage group", http.StatusForbidden)
return
}
DeleteVolume(volID) // #nosec G20
err := DeleteVolume(volID)
if err != nil {
writeError(w, "error deleteVolume: "+err.Error(), http.StatusBadRequest)
return
}
}
}

Expand Down Expand Up @@ -2966,7 +2973,11 @@ func handlePortGroup(w http.ResponseWriter, r *http.Request) {
writeError(w, "Error deleting Port Group: induced error", http.StatusRequestTimeout)
return
}
DeletePortGroup(pgID) // #nosec G20
_, err := DeletePortGroup(pgID)
if err != nil {
writeError(w, "Error deletePortGroup", http.StatusRequestTimeout)
return
}
default:
writeError(w, "Invalid Method", http.StatusBadRequest)
}
Expand Down Expand Up @@ -3184,7 +3195,11 @@ func handleHost(w http.ResponseWriter, r *http.Request) {
writeError(w, "Error deleting Host: induced error", http.StatusRequestTimeout)
return
}
RemoveHost(hostID) // #nosec G20
err := RemoveHost(hostID)
if err != nil {
writeError(w, "error removeHost", http.StatusBadRequest)
return
}
default:
writeError(w, "Invalid Method", http.StatusBadRequest)
}
Expand Down Expand Up @@ -3314,6 +3329,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 Expand Up @@ -4194,7 +4236,11 @@ func handleHostGroup(w http.ResponseWriter, r *http.Request) {
writeError(w, "Error deleting HostGroup: induced error", http.StatusRequestTimeout)
return
}
RemoveHostGroup(hostGroupID) // #nosec G20
err := RemoveHostGroup(hostGroupID)
if err != nil {
writeError(w, "error removeHostGroup", http.StatusBadRequest)
return
}
default:
writeError(w, "Invalid Method", http.StatusBadRequest)
}
Expand Down
Loading

0 comments on commit 0b464a1

Please sign in to comment.