Skip to content

Commit

Permalink
Feature 441 terraform snappolicy (dell#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
shenda1 authored Oct 28, 2022
1 parent f4fdf66 commit 88b4707
Show file tree
Hide file tree
Showing 11 changed files with 575 additions and 211 deletions.
20 changes: 10 additions & 10 deletions VolumeSnapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,10 @@ func (c *Client) GetSnapshotInfo(ctx context.Context, symID, volumeID, snapID st
}

// CreateSnapshot creates a snapVx snapshot of a volume or on the list of volumes passed as sourceVolumeList
// BothSides flag is used in SRDF usecases to create snapshots on both R1 and R2 side
// Star flag is used if the source device is participating in SRDF star mode
// Use the Force flag to automate some scenarios to succeed
// TimeToLive value ins hour is set on the snapshot to automatically delete the snapshot after target is unlinked
//  BothSides flag is used in SRDF usecases to create snapshots on both R1 and R2 side
//  Star flag is used if the source device is participating in SRDF star mode
//  Use the Force flag to automate some scenarios to succeed
//  TimeToLive value ins hour is set on the snapshot to automatically delete the snapshot after target is unlinked
func (c *Client) CreateSnapshot(ctx context.Context, symID string, snapID string, sourceVolumeList []types.VolumeList, ttl int64) error {
defer c.TimeSpent("CreateSnapshot", time.Now())
if _, err := c.IsAllowedArray(symID); err != nil {
Expand Down Expand Up @@ -166,10 +166,10 @@ func (c *Client) CreateSnapshot(ctx context.Context, symID string, snapID string
// DeleteSnapshot deletes a snapshot from a volume
// DeviceNameListSource is a list which contains the names of source volumes
// Symforce flag is used to automate some internal establish scenarios
// Star mode is used for devices in SRDF relations
// Use the Force flag in acceptable error conditions
//  Star mode is used for devices in SRDF relations
//  Use the Force flag in acceptable error conditions
// Restore, when set to true will terminate the Restore and the Snapshot as well
// Generation is used to tell which generation of snapshot needs to be deleted and is passed as int64
//  Generation is used to tell which generation of snapshot needs to be deleted and is passed as int64
// ExecutionOption tells the Unisphere to perform the operation either in Synchronous mode or Asynchronous mode
func (c *Client) DeleteSnapshot(ctx context.Context, symID, snapID string, sourceVolumes []types.VolumeList, generation int64) error {
defer c.TimeSpent("DeleteSnapshot", time.Now())
Expand Down Expand Up @@ -242,13 +242,13 @@ func (c *Client) DeleteSnapshotS(ctx context.Context, symID, snapID string, sour
// VolumeNameListSource is a list which contains the names of source volumes
// VolumeNameListTarget is a list which contains the names of target volumes to which the snapshot is linked or going to be linked
// Symforce flag is used to automate some internal establish scenarios
// Star mode is used for devices in SRDF relations
// Use the Force flag in acceptable error conditions
//  Star mode is used for devices in SRDF relations
//  Use the Force flag in acceptable error conditions
// Restore, when set to true will terminate the Restore and the Snapshot as well
// Exact when specified, pairs source and link devices in their ordinal positions within the selection. When not set uses the source and link device selections as a pool that pairs by best match
// Copy when specified creates an exact copy of the source device, otherwise copies the references
// Remote when specified propagates the data to the remote mirror of the RDF device
// Generation is used to tell which generation of snapshot needs to be updated, it is passed as int64
//  Generation is used to tell which generation of snapshot needs to be updated, it is passed as int64
// NewSnapshotName specifies the new snapshot name to which the old snapshot will be renamed
// ExecutionOption tells the Unisphere to perform the operation either in Synchronous mode or Asynchronous mode
// Action defined the operation which will be performed on the given snapshot
Expand Down
11 changes: 6 additions & 5 deletions authenticate.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,12 @@ func doLog(
// NewClient returns a new Client, which is of interface type Pmax.
// The Client holds state for the connection.
// Thhe following environment variables define the connection:
// CSI_POWERMAX_ENDPOINT - A URL of the form https://1.2.3.4:8443
// CSI_POWERMAX_VERSION - should not be used. Defines a particular form of versioning.
// CSI_APPLICATION_NAME - Application name which will be used for registering the application with Unisphere REST APIs
// CSI_POWERMAX_INSECURE - A boolean indicating whether unvalidated certificates can be accepted. Defaults to true.
// CSI_POWERMAX_USECERTS - Indicates whether to use certificates at all. Defaults to true.
//
// CSI_POWERMAX_ENDPOINT - A URL of the form https://1.2.3.4:8443
// CSI_POWERMAX_VERSION - should not be used. Defines a particular form of versioning.
// CSI_APPLICATION_NAME - Application name which will be used for registering the application with Unisphere REST APIs
// CSI_POWERMAX_INSECURE - A boolean indicating whether unvalidated certificates can be accepted. Defaults to true.
// CSI_POWERMAX_USECERTS - Indicates whether to use certificates at all. Defaults to true.
func NewClient() (client Pmax, err error) {
return NewClientWithArgs(
os.Getenv("CSI_POWERMAX_ENDPOINT"),
Expand Down
15 changes: 10 additions & 5 deletions interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ type Pmax interface {
// GetStorageGroup returns a storage group given the StorageGroup id.
GetStorageGroup(ctx context.Context, symID string, storageGroupID string) (*types.StorageGroup, error)

// GetStorageGroupSnapshotPolicy returns a storage group snapshot policy details.
GetStorageGroupSnapshotPolicy(ctx context.Context, symID, snapshotPolicyID, storageGroupID string) (*types.StorageGroupSnapshotPolicy, error)

// GetStoragePool returns a storage pool given the GetStoragePoolID and SymID.
GetStoragePool(ctx context.Context, symID string, storagePoolID string) (*types.StoragePool, error)

Expand All @@ -113,16 +116,16 @@ type Pmax interface {

// CreateVolumeInStorageGroup takes simplified input arguments to create a volume of a give name and size in a particular storage group.
// This method creates a job and waits on the job to complete.
CreateVolumeInStorageGroup(ctx context.Context, symID string, storageGroupID string, volumeName string, sizeInCylinders int, capUnits ...string) (*types.Volume, error)
CreateVolumeInStorageGroup(ctx context.Context, symID string, storageGroupID string, volumeName string, volumeSize interface{}, volOpts map[string]interface{}) (*types.Volume, error)

// CreateVolumeInStorageGroup takes simplified input arguments to create a volume of a give name and size in a particular storage group.
// This is done synchronously and no jobs are created. HTTP header argument is optional
CreateVolumeInStorageGroupS(ctx context.Context, symID, storageGroupID string, volumeName string, sizeInCylinders int, opts ...interface{}) (*types.Volume, error)
CreateVolumeInStorageGroupS(ctx context.Context, symID, storageGroupID string, volumeName string, volumeSize interface{}, volOpts map[string]interface{}, opts ...http.Header) (*types.Volume, error)

// CreateVolumeInProtectedStorageGroup takes simplified input arguments to create a volume of a give name and size in a protected storage group.
// This will add volume in both Local and Remote Storage group
// This is done synchronously and no jobs are created. HTTP header argument is optional
CreateVolumeInProtectedStorageGroupS(ctx context.Context, symID, remoteSymID, storageGroupID string, remoteStorageGroupID string, volumeName string, sizeInCylinders int, opts ...interface{}) (*types.Volume, error)
CreateVolumeInProtectedStorageGroupS(ctx context.Context, symID, remoteSymID, storageGroupID string, remoteStorageGroupID string, volumeName string, volumeSize interface{}, volOpts map[string]interface{}, opts ...http.Header) (*types.Volume, error)

// DeleteStorageGroup deletes a storage group given a storage group id
DeleteStorageGroup(ctx context.Context, symID string, storageGroupID string) error
Expand Down Expand Up @@ -275,9 +278,11 @@ type Pmax interface {
// UpdatePortGroup updates a port group
UpdatePortGroup(ctx context.Context, symID string, portGroupID string, ports []types.PortKey) (*types.PortGroup, error)

// ModifyMobilityForVolume allows enabling/disabling mobility id for the volume
ModifyMobilityForVolume(ctx context.Context, symID string, volumeID string, mobility bool) (*types.Volume, error)
// ExpandVolume expands the size of an existing volume
ExpandVolume(ctx context.Context, symID string, volumeID string, rdfGNo int, newSizeCYL int, capUnits ...string) (*types.Volume, error)
GetCreateVolInSGPayload(sizeInCylinders int, capUnit string, volumeName string, isSync bool, remoteSymID, storageGroupID string, opts ...http.Header) (payload interface{})
ExpandVolume(ctx context.Context, symID string, volumeID string, rdfGNo int, volumeSize interface{}, capUnits ...string) (*types.Volume, error)
GetCreateVolInSGPayload(volumeSize interface{}, capUnit string, volumeName string, isSync, enableMobility bool, remoteSymID, storageGroupID string, opts ...http.Header) (payload interface{})
//GetCreateVolInSGPayloadWithMetaDataHeaders(sizeInCylinders int, volumeName string, isSync bool, remoteSymID, remoteStorageGroupID string, metadata http.Header) (payload interface{})

// GetRDFGroupList GetRDFGroupList fetches all RDF group
Expand Down
110 changes: 98 additions & 12 deletions inttest/pmax_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ var (
defaultStorageGroup = "csi-Integration-Test"
defaultProtectedStorageGroup = "csi-Integration-Test-Protected-SG"
nonFASTManagedSG = "csi-Integration-No-FAST"
defaultSGWithSnapshotPolicy = "csi-Integration-Test-With-Snapshot-Policy"
defaultSnapshotPolicy = "DailyDefault"
defaultFCHost = "IntegrationFCHost"
defaultiSCSIHost = "IntegrationiSCSIHost"
localVol, remoteVol *types.Volume
Expand Down Expand Up @@ -165,6 +167,14 @@ func createDefaultSGAndHost() error {
return fmt.Errorf("failed to create non fast SG: (%s)", err.Error())
}

// Create default SG with snapshot policy
optionalPayload := make(map[string]interface{})
optionalPayload["snapshotPolicies"] = []string{defaultSnapshotPolicy}
_, err = client.CreateStorageGroup(context.TODO(), symmetrixID, defaultSGWithSnapshotPolicy, defaultSRP, defaultServiceLevel, false, optionalPayload)
if err != nil {
return fmt.Errorf("failed to create SG with snapshot policy: (%s)", err.Error())
}

// Create default FC Host
initiators := []string{defaultFCInitiatorID}
_, err = createHost(symmetrixID, defaultFCHost, initiators, nil)
Expand Down Expand Up @@ -195,8 +205,8 @@ func createRDFSetup() error {
volumeName := fmt.Sprintf("csi%s-Int%d", volumePrefix, now.Nanosecond())

//Creating source volume

localVol, err = client.CreateVolumeInStorageGroup(context.TODO(), symmetrixID, defaultProtectedStorageGroup, volumeName, 50)
volOpts := make(map[string]interface{})
localVol, err = client.CreateVolumeInStorageGroup(context.TODO(), symmetrixID, defaultProtectedStorageGroup, volumeName, 50, volOpts)
if err != nil {
return fmt.Errorf("failed to create volume : (%s)", err.Error())
}
Expand Down Expand Up @@ -236,6 +246,7 @@ func cleanupDefaultSGAndHOST(t *testing.T) {
if err != nil {
t.Errorf("failed to delete default non fast SG (%s) : (%s)", nonFASTManagedSG, err.Error())
}

// delete default FC host
err = deleteHost(symmetrixID, defaultFCHost)
if err != nil {
Expand Down Expand Up @@ -478,6 +489,42 @@ func TestGetStorageGroup(t *testing.T) {
fmt.Printf("%#v\n", storageGroup)
}

func TestGetStorageGroupSnapshotPolicy(t *testing.T) {
if client == nil {
err := getClient()
if err != nil {
t.Errorf("Unable to get/create pmax client: (%s)", err.Error())
return
}
}
storageGroupSnapshotPolicy, err := client.GetStorageGroupSnapshotPolicy(context.TODO(), symmetrixID, defaultSnapshotPolicy, defaultSGWithSnapshotPolicy)
if err != nil || storageGroupSnapshotPolicy == nil {
t.Error("Expected to find " + defaultSGWithSnapshotPolicy + " but didn't")
return
}
fmt.Printf("%#v\n", storageGroupSnapshotPolicy)

// Cleanup - remove snapshot policy from SG
optionalPayload := make(map[string]interface{})
optionalPayload["editStorageGroupActionParam"] = types.EditStorageGroupActionParam{
EditSnapshotPoliciesParam: &types.EditSnapshotPoliciesParam{
DisassociateSnapshotPolicyParam: &types.SnapshotPolicies{
SnapshotPolicies: []string{defaultSnapshotPolicy},
},
},
}
_, err = client.UpdateStorageGroup(context.TODO(), symmetrixID, defaultSGWithSnapshotPolicy, optionalPayload)
if err != nil {
t.Errorf("failed to remove snapshot policy from SG (%s) : (%s)", defaultSGWithSnapshotPolicy, err.Error())
} else {
// Cleanup - delete SG after snapshot policy is removed
err = deleteStorageGroup(symmetrixID, defaultSGWithSnapshotPolicy)
if err != nil {
t.Errorf("failed to delete default SG with snapshot policy (%s) : (%s)", defaultSGWithSnapshotPolicy, err.Error())
}
}
}

func TestGetStoragePool(t *testing.T) {
if client == nil {
err := getClient()
Expand Down Expand Up @@ -744,7 +791,7 @@ func TestCreateVolumeInStorageGroup1(t *testing.T) {
now := time.Now()
volumeName := fmt.Sprintf("csi%s-Int%d", volumePrefix, now.Nanosecond())
fmt.Printf("volumeName: %s\n", volumeName)
payload := client.GetCreateVolInSGPayload(1, "CYL", volumeName, false, "", "", nil)
payload := client.GetCreateVolInSGPayload(1, "CYL", volumeName, false, false, "", "", nil)

payloadBytes, err := json.Marshal(&payload)
if err != nil {
Expand Down Expand Up @@ -781,12 +828,42 @@ func TestCreateVolumeInStorageGroup2(t *testing.T) {
now := time.Now()
volumeName := fmt.Sprintf("csi%s-Int%d", volumePrefix, now.Nanosecond())
fmt.Printf("volumeName: %s\n", volumeName)
vol, err := client.CreateVolumeInStorageGroupS(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, 1)
volOpts := make(map[string]interface{})
vol, err := client.CreateVolumeInStorageGroupS(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, 1, volOpts)
if err != nil {
t.Error(err)
return
}
fmt.Printf("volume:\n%#v\n", vol)
cleanupVolume(vol.VolumeID, volumeName, defaultStorageGroup, t)
}

func TestModifyMobilityForVolume(t *testing.T) {
if client == nil {
err := getClient()
if err != nil {
t.Errorf("Unable to get/create pmax client: (%s)", err.Error())
return
}
}
now := time.Now()
volumeName := fmt.Sprintf("csi%s-Int%d", volumePrefix, now.Nanosecond())
fmt.Printf("volumeName: %s\n", volumeName)
volOpts := make(map[string]interface{})
vol, err := client.CreateVolumeInStorageGroupS(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, 1, volOpts)
if err != nil {
t.Error(err)
return
}
fmt.Printf("volume:\n%#v\n", vol)
vol, err = client.ModifyMobilityForVolume(context.TODO(), symmetrixID, vol.VolumeID, true)
if err != nil {
t.Error(err)
return
}
if !vol.MobilityIDEnabled {
t.Errorf("Failed to modify mobilityID")
}
cleanupVolume(vol.VolumeID, volumeName, defaultStorageGroup, t)
}

Expand All @@ -802,7 +879,9 @@ func TestCreateVolumeInStorageGroup2withUnit(t *testing.T) {
volumeName := fmt.Sprintf("csi%s-Int%d", volumePrefix, now.Nanosecond())
capUnit := "TB"
fmt.Printf("volumeName: %s\n", volumeName)
vol, err := client.CreateVolumeInStorageGroupS(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, 1, capUnit)
volopts := make(map[string]interface{})
volopts["capacityUnit"] = capUnit
vol, err := client.CreateVolumeInStorageGroupS(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, "1", volopts)
if err != nil {
t.Error(err)
return
Expand All @@ -822,7 +901,8 @@ func TestAddVolumesInStorageGroup(t *testing.T) {
now := time.Now()
volumeName := fmt.Sprintf("csi%s-Int%d", volumePrefix, now.Nanosecond())
fmt.Printf("volumeName: %s\n", volumeName)
vol, err := client.CreateVolumeInStorageGroup(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, 1)
volOpts := make(map[string]interface{})
vol, err := client.CreateVolumeInStorageGroup(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, 1, volOpts)
if err != nil {
t.Error(err)
return
Expand Down Expand Up @@ -889,6 +969,7 @@ func TestCreateVolumeInStorageGroupInParallel(t *testing.T) {
func CreateVolumesInParallel(nVols int, t *testing.T) {
fmt.Printf("testing CreateVolumeInStorageGroup with %d parallel requests\n", nVols)
volIDList := make([]string, nVols)
volOpts := make(map[string]interface{})
// make channels for communication
idchan := make(chan string, nVols)
errchan := make(chan error, nVols)
Expand All @@ -907,7 +988,7 @@ func CreateVolumesInParallel(nVols int, t *testing.T) {
name := fmt.Sprintf("pmax-Int%d-Scale%d", now.Nanosecond(), i)
go func(volumeName string, idchan chan string, errchan chan error) {
var err error
resp, err := client.CreateVolumeInStorageGroup(context.TODO(), symmetrixID, storageGroupName, volumeName, 1)
resp, err := client.CreateVolumeInStorageGroup(context.TODO(), symmetrixID, storageGroupName, volumeName, 1, volOpts)
if resp != nil {
fmt.Printf("ID %s Name %s\n%#v\n", resp.VolumeID, volumeName, resp)
idchan <- resp.VolumeID
Expand Down Expand Up @@ -1367,7 +1448,8 @@ func TestCreateFCMaskingView(t *testing.T) {
// add a volume in defaultStorageGroup
volumeName := fmt.Sprintf("csi%s-Int%d", volumePrefix, time.Now().Nanosecond())
fmt.Printf("volumeName: %s\n", volumeName)
vol, err := client.CreateVolumeInStorageGroup(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, 1)
volOpts := make(map[string]interface{})
vol, err := client.CreateVolumeInStorageGroup(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, 1, volOpts)
if err != nil {
t.Error("Expected to create a volume but didn't" + err.Error())
return
Expand Down Expand Up @@ -1438,7 +1520,8 @@ func TestRenameMaskingView(t *testing.T) {
// add a volume in defaultStorageGroup
volumeName := fmt.Sprintf("csi%s-Int%d", volumePrefix, time.Now().Nanosecond())
fmt.Printf("volumeName: %s\n", volumeName)
vol, err := client.CreateVolumeInStorageGroup(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, 1)
volOpts := make(map[string]interface{})
vol, err := client.CreateVolumeInStorageGroup(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, 1, volOpts)
if err != nil {
t.Error("Expected to create a volume but didn't" + err.Error())
return
Expand Down Expand Up @@ -1596,7 +1679,8 @@ func TestCreateiSCSIMaskingView(t *testing.T) {
// add a volume in defaultStorageGroup
volumeName := fmt.Sprintf("csi%s-Int%d", volumePrefix, time.Now().Nanosecond())
fmt.Printf("volumeName: %s\n", volumeName)
vol, err := client.CreateVolumeInStorageGroup(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, 1)
volOpts := make(map[string]interface{})
vol, err := client.CreateVolumeInStorageGroup(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, 1, volOpts)
if err != nil {
t.Error("Expected to create a volume but didn't" + err.Error())
return
Expand Down Expand Up @@ -1739,7 +1823,8 @@ func TestExpandVolume(t *testing.T) {
now := time.Now()
volumeName := fmt.Sprintf("csi%s-Int%d", volumePrefix, now.Nanosecond())
fmt.Printf("volumeName: %s\n", volumeName)
vol, err := client.CreateVolumeInStorageGroup(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, 26)
volOpts := make(map[string]interface{})
vol, err := client.CreateVolumeInStorageGroup(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, 26, volOpts)
if err != nil {
t.Error(err)
return
Expand Down Expand Up @@ -1776,7 +1861,8 @@ func TestExpandVolumeWithUnit(t *testing.T) {
now := time.Now()
volumeName := fmt.Sprintf("csi%s-Int%d", volumePrefix, now.Nanosecond())
fmt.Printf("volumeName: %s\n", volumeName)
vol, err := client.CreateVolumeInStorageGroup(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, 26)
volOpts := make(map[string]interface{})
vol, err := client.CreateVolumeInStorageGroup(context.TODO(), symmetrixID, defaultStorageGroup, volumeName, 26, volOpts)
if err != nil {
t.Error(err)
return
Expand Down
Loading

0 comments on commit 88b4707

Please sign in to comment.