diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..668621b --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +c.out + +# editor and IDE paraphernalia +.idea +*.swp +*.swo +*~ + diff --git a/VolumeReplication.go b/VolumeReplication.go index 1090526..163a004 100644 --- a/VolumeReplication.go +++ b/VolumeReplication.go @@ -30,6 +30,7 @@ import ( const ( XRDFGroup = "/rdf_group" ASYNC = "ASYNC" + METRO = "METRO" ) // GetRDFGroup returns RDF group information given the RDF group number @@ -119,6 +120,40 @@ func (c *Client) ExecuteReplicationActionOnSG(symID, action, storageGroup, rdfGr Action: action, ExecutionOption: types.ExecutionOptionSynchronous, } + case "Failback": + actionParam := &types.Failback{ + Force: force, + SymForce: false, + Star: false, + Hop2: false, + Bypass: false, + Remote: false, + RecoverPoint: false, + } + modifyParam = &types.ModifySGRDFGroup{ + Failback: actionParam, + Action: action, + ExecutionOption: types.ExecutionOptionSynchronous, + } + case "Failover": + actionParam := &types.Failover{ + Force: force, + SymForce: false, + Star: false, + Hop2: false, + Bypass: false, + Remote: false, + Immediate: false, + ConsExempt: exemptConsistency, + MetroBias: false, + Establish: false, + Restore: false, + } + modifyParam = &types.ModifySGRDFGroup{ + Failover: actionParam, + Action: action, + ExecutionOption: types.ExecutionOptionSynchronous, + } default: return fmt.Errorf("not a supported action on a protected storage group") } @@ -142,7 +177,8 @@ func (c *Client) ExecuteReplicationActionOnSG(symID, action, storageGroup, rdfGr func (c *Client) GetCreateSGReplicaPayload(remoteSymID string, rdfMode string, rdfgNo int, remoteSGName string, remoteServiceLevel string, establish bool) *types.CreateSGSRDF { var payload *types.CreateSGSRDF - if rdfMode == ASYNC { + switch rdfMode { + case ASYNC: payload = &types.CreateSGSRDF{ ReplicationMode: "Asynchronous", RemoteSLO: remoteServiceLevel, @@ -152,6 +188,17 @@ func (c *Client) GetCreateSGReplicaPayload(remoteSymID string, rdfMode string, r Establish: establish, ExecutionOption: types.ExecutionOptionSynchronous, } + case METRO: + payload = &types.CreateSGSRDF{ + ReplicationMode: "Active", + RemoteSLO: remoteServiceLevel, + RemoteSymmID: remoteSymID, + RdfgNumber: rdfgNo, + RemoteStorageGroupName: remoteSGName, + Establish: establish, + MetroBias: true, + ExecutionOption: types.ExecutionOptionSynchronous, + } } return payload } @@ -189,7 +236,8 @@ func (c *Client) CreateSGReplica(symID, remoteSymID, rdfMode, rdfGroupNo, source func (c *Client) GetCreateRDFPairPayload(devList types.LocalDeviceListCriteria, rdfMode, rdfType string, establish, exemptConsistency bool) *types.CreateRDFPair { var payload *types.CreateRDFPair - if rdfMode == ASYNC { + switch rdfMode { + case ASYNC: payload = &types.CreateRDFPair{ RdfMode: "Asynchronous", RdfType: rdfType, @@ -198,6 +246,16 @@ func (c *Client) GetCreateRDFPairPayload(devList types.LocalDeviceListCriteria, LocalDeviceListCriteria: &devList, ExecutionOption: types.ExecutionOptionSynchronous, } + case METRO: + payload = &types.CreateRDFPair{ + RdfMode: "Active", + RdfType: "RDF1", + Bias: true, + Establish: establish, + Exempt: exemptConsistency, + LocalDeviceListCriteria: &devList, + ExecutionOption: types.ExecutionOptionSynchronous, + } } return payload } diff --git a/authenticate.go b/authenticate.go index ce16164..45654f1 100644 --- a/authenticate.go +++ b/authenticate.go @@ -34,6 +34,7 @@ type Client struct { api api.Client allowedArrays []string version string + symmetrixID string } var ( @@ -185,6 +186,13 @@ func NewClientWithArgs( return client, nil } +// WithSymmetrixID sets the default array for the client +func (c *Client) WithSymmetrixID(symmetrixID string) Pmax { + client := *c + client.symmetrixID = symmetrixID + return &client +} + func (c *Client) getDefaultHeaders() map[string]string { headers := make(map[string]string) headers["Accept"] = accHeader @@ -194,5 +202,8 @@ func (c *Client) getDefaultHeaders() map[string]string { headers["Content-Type"] = conHeader basicAuthString := basicAuth(c.configConnect.Username, c.configConnect.Password) headers["Authorization"] = "Basic " + basicAuthString + if c.symmetrixID != "" { + headers["symid"] = c.symmetrixID + } return headers } diff --git a/go.mod b/go.mod index 60a7418..217ee12 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/dell/gopowermax -go 1.12 +go 1.16 require ( github.com/cucumber/godog v0.10.0 diff --git a/interface.go b/interface.go index 918b5b2..9718d7d 100644 --- a/interface.go +++ b/interface.go @@ -54,6 +54,10 @@ type Pmax interface { // Authenticate causes authentication and tests the connection Authenticate(configConnect *ConfigConnect) error + // WithSymmetrixID set a default symmetrix ID for the admin client, + // for it to be added to the request header. + WithSymmetrixID(symmetrixID string) Pmax + // SLO provisioning are the methods for SLO provisioning. All the methods requre a // symID to identify the Symmetrix. diff --git a/types/v90/Replication.go b/types/v90/Replication.go index 7990f39..6018764 100644 --- a/types/v90/Replication.go +++ b/types/v90/Replication.go @@ -67,10 +67,12 @@ type Resume struct { // ModifySGRDFGroup holds parameters for rdf storage group updates type ModifySGRDFGroup struct { - Action string `json:"action"` - Suspend *Suspend `json:"suspend,omitempty"` - Resume *Resume `json:"resume,omitempty"` - ExecutionOption string `json:"executionOption"` + Action string `json:"action"` + Suspend *Suspend `json:"suspend,omitempty"` + Resume *Resume `json:"resume,omitempty"` + Failback *Failback `json:"failback,omitempty"` + Failover *Failover `json:"failover,omitempty"` + ExecutionOption string `json:"executionOption"` } // CreateSGSRDF contains parameters to create storage group replication {in u4p a.k.a "storageGroupSrdfCreate"} @@ -196,3 +198,29 @@ type StorageGroupRDFG struct { States []string `json:"states"` Modes []string `json:"modes"` } + +// Failover action +type Failover struct { + Force bool `json:"force"` + SymForce bool `json:"symForce"` + Star bool `json:"star"` + Hop2 bool `json:"hop2"` + Bypass bool `json:"bypass"` + Immediate bool `json:"immediate"` + ConsExempt bool `json:"consExempt"` + MetroBias bool `json:"metroBias"` + Establish bool `json:"establish"` + Restore bool `json:"restore"` + Remote bool `json:"remote"` +} + +// Failback action +type Failback struct { + Force bool `json:"force"` + SymForce bool `json:"symForce"` + Star bool `json:"star"` + Hop2 bool `json:"hop2"` + Bypass bool `json:"bypass"` + Remote bool `json:"remote"` + RecoverPoint bool `json:"recoverPoint"` +}