REC Sessionの反転
同期モードおよび非同期ConsistencyモードのREC Sessionを反転させ、ミラーVolumeのデータを業務Volumeにコピーしたあとに、REC Sessionを再度反転させて元の状態に戻すスクリプトを記載します。このスクリプトは、同期モードまたは非同期ConsistencyモードのRECを使用し、リモート筐体にミラーVolumeを作成する運用で使用します。詳細は、REC(同期モード)を使用したリモート筐体へのミラーVolumeの作成、またはREC(非同期Consistencyモード)を使用したリモート筐体へのミラーVolumeの作成を参照してください。
Copy Sessionの反転についての留意事項は、REC Sessionの反転を参照してください。
スクリプトの処理の流れは以下です。
GET /copysession/{copysession_id} APIを使用して、反転対象のCopy Session情報を取得する。
Copy Sessionが反転可能なStatusかどうかを判定する。
Copy SessionのStatusがSuspendedではない場合、POST /copysession/{copysession_id}/suspend APIを使用してCopy SessionをSuspendする。
POST /copysession/{copysession_id}/reverse APIを使用して、Copy Sessionを反転する。
POST /copysession/{copysession_id}/resume APIを使用してCopy SessionをResumeし、ミラーVolumeから業務Volumeへのデータ転送を開始する。
GET /copysession/{copysession_id} APIを使用してCopy Session情報を定期的に取得し、PhaseがEquivalentになるまで待機する。
POST /copysession/{copysession_id}/suspend APIを使用して、Copy SessionをSuspendする。
POST /copysession/{copysession_id}/reverse APIを使用して、Copy Sessionを反転する(元の方向に戻す)。
3でCopy SessionをSuspendしていた場合は、POST /copysession/{copysession_id}/resume APIを使用して、Copy SessionのStatusをスクリプト実行前の状態(Active)に戻す。
rec_sync_consis_recover.py
import sys
import time
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"
# Copy session ID to recover the source volume data.
storage1_copysession_id = 1
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_can_recover(self, copysession_id):
"""Check if the REC session can start the recovery.
Args:
copysession_id (int): Copy Session ID to check.
Returns:
bool: True if the specified REC session can start the recovery.
False otherwise. Returns false if retrieving copy session
information failed.
"""
r = super().get("/api/v1/copysession/{0!s}?fields=status,"
"is_local_source_volume".format(copysession_id))
data = r.json()
if r.status_code != 200:
print("Failed to get information about the copy session.")
print(r)
print(data)
return False
if data["status"] not in ["Active", "Suspended"]:
print("The REC session is not in normal status.")
print(data)
return False
if not data["is_local_source_volume"]:
print("The REC session might be in recovering.")
print(data)
return False
return True
def rec_wait_for_equivalent(self, copysession_id):
"""Wait for the REC session phase to be equivalent.
Args:
copysession_id (int): Copy session ID to wait.
Returns:
bool: True if the copy session phase is equivalent.
False if error occurs.
"""
while True:
r = super().get("/api/v1/copysession/{0!s}".format(copysession_id))
data = r.json()
if r.status_code != 200 or data["status"] == "Error":
print("Failed to get information of the copy session or"
" some error occurred on the copy session.")
print(r)
print(data)
return False
if data["phase"] == "Equivalent":
break
print("The REC session is not yet equivalent. Check again in"
" 60 seconds.")
print("Total Data Size: ", data["total_data_size"])
print("Copied Data Size:", data["copied_data_size"])
print("Progress: ", data["progress"])
print("Elapsed Time: ", data["elapsed_time"])
time.sleep(60)
return True
def rec_suspend(self, copysession_id, force=False):
"""Suspend the REC session.
Args:
copysession_id (int): Copy session ID to suspend.
force (bool, optional): True to force suspend. Defaults to False.
Returns:
bool: True if successful, False otherwise.
"""
if force:
r = super().post("/api/v1/copysession/{0!s}/suspend?force=true"
.format(copysession_id))
else:
r = super().post("/api/v1/copysession/{0!s}/suspend"
.format(copysession_id))
if r.status_code != 202:
print("Failed to request the REC session suspend.")
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 suspend the REC session.")
print(job_r)
print(job_r.json())
return False
return True
def rec_resume(self, copysession_id):
"""Resume the REC session
Args:
copysession_id (int): Copy session ID to resume.
Returns:
bool: True if successful, False otherwise.
"""
r = super().post("/api/v1/copysession/{0!s}/resume"
.format(copysession_id))
if r.status_code != 202:
print("Failed to request the REC session resume.")
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 resume the REC session.")
print(job_r)
print(job_r.json())
return False
return True
def rec_consistency_wait_for_suspend(self, copysession_id):
"""Wait for the REC concurrent copy session to suspend.
Args:
copysession_id (int): Copy session ID to suspend.
Returns:
bool: True if suspend the copy session is completed.
False if error occurs.
"""
while True:
r = super().get("/api/v1/copysession/{0!s}".format(copysession_id))
data = r.json()
if r.status_code != 200:
print("Failed to get information of the copy session.")
print(r)
print(data)
return False
if data["status"] == "Error":
print("The copy session is in error status.")
print(data)
return False
if data["status"] != "Suspended":
print("Failed to suspend the copy session. Stop access to the"
" source volume of the copy session and try again.")
print(data)
return False
if data["concurrent_suspend_result"] == "Error":
print("Failed to suspend the copy session.")
print(data)
return False
if (data["concurrent_suspend_result"] == "Success"
and data["status"] == "Suspended"):
break
# Get it again after remain_time_to_finish_suspend.
if data["remain_time_to_finish_suspend"] > 10:
time.sleep(data["remain_time_to_finish_suspend"])
else:
time.sleep(10)
return True
def rec_reverse(self, copysession_id):
"""Reverse the REC session
Args:
copysession_id (int): Copy session ID to reverse.
Returns:
bool: True if successful, False otherwise.
"""
r = super().post("/api/v1/copysession/{0!s}/reverse"
.format(copysession_id))
if r.status_code != 202:
print("Failed to request the REC session reverse.")
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 reverse the REC session.")
print(job_r)
print(job_r.json())
return False
return True
def rec_recover(self, copysession_id):
"""Restore the source volume data from the REC destination volume.
Args:
copysession_id (int): Copy session ID of the REC.
Returns:
bool: True if successful, False otherwise.
"""
is_suspended = False
is_consistency = False
# Get the information of the copy session.
r = super().get("/api/v1/copysession/{0!s}".format(copysession_id))
data = r.json()
if r.status_code != 200:
print("Failed to get information of the copy session.")
print(r)
print(data)
return False
if data["status"] == "Suspended":
is_suspended = True
if data["transfer_mode"] == "Consistency":
is_consistency = True
# Execute suspend if the REC session is not suspended.
if not is_suspended:
print("Suspending the REC session.")
if not self.rec_suspend(copysession_id):
return False
# Need to wait for the completion of suspend if the REC is consistency.
if is_consistency:
print("Waiting for the REC session to complete suspend.")
if not self.rec_consistency_wait_for_suspend(copysession_id):
print("Some error occurred before suspend completion of"
" the REC session.")
return False
# Reverse the REC session
print("Reversing the REC session.")
if not self.rec_reverse(copysession_id):
return False
# Restore the data from the destination volume to the source
# volume of the REC.
print("Resuming the REC session.")
if not self.rec_resume(copysession_id):
return False
print("Waiting for the REC session to be equivalent.")
if not self.rec_wait_for_equivalent(copysession_id):
return False
print("The data restore Completed.")
# Restore the REC session to its former state.
print("Suspending the REC session.")
if not self.rec_suspend(copysession_id):
return False
# Need to wait for the completion of suspend if the REC is consistency.
if is_consistency:
print("Waiting for the REC session to complete suspend.")
if not self.rec_consistency_wait_for_suspend(copysession_id):
print("Some error occurred before suspend completion of"
" the REC session.")
return False
print("Reversing the REC session.")
if not self.rec_reverse(copysession_id):
return False
# Execute resume if needed.
if not is_suspended:
print("Resuming the REC session.")
if not self.rec_resume(copysession_id):
return False
return True
def main():
storage1 = EtdxApi(storage1_url)
# Login
if not storage1.login(storage1_user_name, storage1_password):
return False
print("Start recovery of the source volume data about the REC session"
" (ID: {0!s}).".format(storage1_copysession_id))
# Change recovery process according to the operation condition.
try:
if not storage1.rec_can_recover(storage1_copysession_id):
print("Could not start recovery.")
return False
if not storage1.rec_recover(storage1_copysession_id):
print("Failed to recover.")
return False
except Exception as e:
print(e)
return False
print("Recovery completed.")
# Logout
storage1.logout()
return True
if __name__ == '__main__':
if not main():
sys.exit(1)

