Creating a Mirrored Volume (Asynchronous Consistency Mode) in a Remote Storage System
The following script creates a Volume on the remote storage system and creates a REC Session in asynchronous consistency mode. This script is used in production to create a mirrored volume in a remote storage system using REC (Asynchronous Consistency Mode). For more information, see the description of Creating a Mirrored Volume in a Remote Storage with REC (Asynchronous Consistency Mode).
The sequence of script processing is as follows.
Use POST /volume API to create a Volume in the remote storage system to use as a Copy destination for REC Sessions.
Using POST /copysession/rec API, create a REC Session (Asynchronous Consistency Mode) between the business volume and the volume you created in 1.
rec_consistency_create.py
import sys
from eternus_rest import EtdxBaseApi
# Change the following values for your environment.
# Source storage (storage that has the source volume)
storage1_url = "https://192.168.0.1:5665"
storage1_user_name = "username"
storage1_password = "password"
# Target storage (storage that has the destination volume)
storage2_url = "https://192.168.0.2:5665"
storage2_user_name = "username"
storage2_password = "password"
# Change the following values as required.
# Create a REC(consistency) session from the volume on storage1 to storage2.
# Volume ID on storage1 to backup.
storage1_volume_id = 100001
# TPP ID to create a backup volume on storage2.
storage2_backup_tpp_id = 1
# Name of the backup volume.
storage2_backup_name = "backup_vol"
class EtdxApi(EtdxBaseApi):
def __init__(self, base_url, boxid=None, proxies=None):
"""Constructor of EtdxApi
If storage is used as target storage of REC without calling login
method in this script, need to specify the boxid of this storage
as follows.
storage2 = EtdxApi(storage2_url,
boxid="00ETERNUSDXHS3ET00000A####EI000001######")
Args:
base_url ([type]): [description]
boxid ([type], optional): [description]. Defaults to None.
proxies ([type], optional): [description]. Defaults to None.
"""
super().__init__(base_url, boxid=boxid, proxies=proxies)
def login(self, user_name="", password=""):
"""Create a session of RESTful API and get boxid.
Args:
user_name (str, optional): User name to login. Defaults to "".
password (str, optional): Password for the user. Defaults to "".
Returns:
bool: True if successful, False otherwise.
"""
rtn = super().login(user_name, password)
if rtn and self.boxid is None:
r = super().get("/api/v1/storagesystem")
if r.status_code != 200:
print(r)
print(r.json())
print("Failed to get boxid.")
return False
self.boxid = r.json()["boxid"]
return rtn
def rec_create_backup_volume(self, destination_tpp_id,
destination_volume_name,
source_storage,
source_volume_id):
"""Create a backup volume for REC destination volume.
Create a volume on the target storage with the same capacity as
the source volume.
Args:
destination_tpp_id (int): TPP ID to create a backup volume.
destination_volume_name (str): Name of the backup volume.
source_storage (obj): Instance of EtdxApi class of the backup
source storage.
source_volume_id (int): Volume ID of the backup source volume.
Returns:
int: Volume ID of the destination volume that was created.
If volume creation fails, returns a value of -1.
This value cannot be used as a volume ID.
"""
# Get the capacity of source volume.
r = source_storage.get("/api/v1/volume/{0!s}?fields=capacity"
.format(source_volume_id))
if r.status_code != 200:
print("Failed to get information of the source volume (ID: {0!s})."
.format(source_volume_id))
print(r)
print(r.json())
return -1
capacity = r.json()["capacity"]
# Create backup volume
body = {
"name": destination_volume_name,
"capacity": capacity,
"tpp_id": destination_tpp_id
}
r = super().post("/api/v1/volume", body)
if r.status_code != 202:
print("Failed to request a volume creation.")
print(r)
print(r.json())
return -1
# Wait for the job completion
job_r = super().wait_job(r.json()["job_id"])
if job_r.json()["status"] != "Success":
print("Failed to create a volume.")
print(job_r)
print(job_r.json())
return -1
backup_volume_href = job_r.json()["resource_href_list"][0]
backup_volume_id = int(backup_volume_href.split("/")[4])
return backup_volume_id
def rec_delete_volume(self, volume_id):
"""Delete the volume.
Args:
volume_id (int): Volume ID to delete.
Returns:
bool: True if successful, False otherwise.
"""
r = super().delete("/api/v1/volume/{0!s}".format(volume_id))
if r.status_code != 202:
print("Failed to request the volume deletion.")
print(r)
print(r.json())
return False
# Wait for the job completion
job_r = super().wait_job(r.json()["job_id"])
if job_r.json()["status"] != "Success":
print("Failed to delete the volume.")
print(job_r)
print(job_r.json())
return False
return True
def rec_consistency_create(self, source_volume_id, destination_storage,
destination_volume_id):
"""Create REC(Consistency) session.
Args:
source_volume_id (int): Volume ID of the backup source volume.
destination_storage (obj): Instance of EtdxApi class of the backup
destination storage.
destination_volume_id (int): Volume ID of the backup destination
volume.
Returns:
int: Copy session ID that is created. If REC creation fails,
returns a value of -1. This value cannot be used as copy
session ID.
"""
body = {
"source_volume_id": source_volume_id,
"destination_volume_id": destination_volume_id,
"source_boxid": self.boxid,
"destination_boxid": destination_storage.boxid,
"transfer_mode": "Consistency",
"recovery_mode": "automatic"
}
r = super().post("/api/v1/copysession/rec", body)
if r.status_code != 202:
print("Failed to request a REC session creation.")
print(r)
print(r.json())
return -1
# Wait for the job completion
job_r = super().wait_job(r.json()["job_id"])
if job_r.json()["status"] != "Success":
print("Failed to creation a REC session.")
print(job_r)
print(job_r.json())
return -1
copysession_href = job_r.json()["resource_href_list"][0]
copysession_id = int(copysession_href.split("/")[4])
return copysession_id
def main():
storage1 = EtdxApi(storage1_url)
storage2 = EtdxApi(storage2_url)
# Login
if not storage1.login(storage1_user_name, storage1_password):
return False
if not storage2.login(storage2_user_name, storage2_password):
return False
print("Create a REC(Consistency) of the volume (ID: {0!s})."
.format(storage1_volume_id))
# Create a backup volume on storage2.
print("Creating backup volume on the destination storage.")
storage2_volume_id = storage2.rec_create_backup_volume(
storage2_backup_tpp_id, storage2_backup_name, storage1,
storage1_volume_id)
if storage2_volume_id == -1:
print("Failed to create a backup volume.")
return False
print("Backup volume ID created on storage2:", storage2_volume_id)
# Create REC(Consistency) session.
print("Creating REC(Consistency) session (from {0!s} to {1!s})."
.format(storage1_volume_id, storage2_volume_id))
copysession_id = storage1.rec_consistency_create(storage1_volume_id,
storage2,
storage2_volume_id)
if copysession_id == -1:
print("Failed to create a REC session.")
print("Deleting the created backup volume (ID: {0!s})."
.format(storage2_volume_id))
storage2.rec_delete_volume(storage2_volume_id)
return False
print("Created REC(Consistency) session ID:", copysession_id)
# Get information of the copy session.
r = storage1.get("/api/v1/copysession/{0!s}".format(copysession_id))
print(r)
print(r.json())
# Variables declaration for other REC stack scripts
print()
print("--- Variables declaration for other REC scripts ---")
print("storage1_copysession_id = {0!s}".format(copysession_id))
# Logout
storage1.logout()
storage2.logout()
return True
if __name__ == '__main__':
if not main():
sys.exit(1)

