21.4 ShadowImageペア操作のサンプルコード
ShadowImageペア操作のサンプルコードの流れ
ステップ |
サンプルコードの流れ |
コードの構成要素 |
---|---|---|
1 |
必要なライブラリのインポートおよびパラメータの設定 |
― |
2 |
ヘッダの定義 |
リクエストヘッダの指定(既定のHTTPヘッダの場合) リクエストヘッダの指定(カスタムHTTPヘッダの場合) |
3 |
HTTPリクエストの発行と非同期処理の状態確認のための関数の定義 |
GET操作によるジョブの状態取得 ユーザ認証情報の設定(セッションベースの認証の場合) JSON形式によるリクエストボディの生成 ジョブの実行結果の取得 操作結果が反映されたリソースのURL取得 エラーコードの取得 |
4 |
REST APIのバージョンの確認 |
GET操作によるREST APIバージョン情報の取得 |
5 |
セッションの生成 |
リソースのURL取得(オブジェクトIDを指定しない場合) ユーザ認証情報の設定(ユーザIDとパスワードによる認証の場合) POST操作によるオブジェクトの新規作成 |
6 |
ShadowImageペアの作成 |
リソースのURL取得(オブジェクトIDを指定しない場合) リソースのURL取得(操作結果から取得したオブジェクトIDを指定する場合) JSON形式によるリクエストボディの生成 POST操作によるオブジェクトの新規作成 |
7 |
ShadowImageペアの分割 |
GET操作による Action テンプレートの取得 ユーザ認証情報の設定(セッションベースの認証の場合) JSON形式によるリクエストボディの生成 PUT操作によるAction テンプレートを使用したアクションの実行 |
8 |
ShadowImageペアの情報取得 |
GET操作によるオブジェクトの取得(特定のオブジェクトを取得する場合) ユーザ認証情報の設定(セッションベースの認証の場合) 取得した情報の出力 |
9 |
エラーメッセージの出力 |
エラーメッセージの出力 |
10 |
セッションの破棄 |
リソースのURL取得(操作結果から取得したオブジェクトIDを指定する場合) DELETE操作によるオブジェクトの削除 |
想定するシステム構成
このサンプルコードでは、次の概念図のようなシステム構成を想定しています。
サンプルコードのパラメータに設定している値を次に示します。必要に応じて、システムの環境や要件に合わせた設定に変更してください。
パラメータ |
設定値 |
説明 |
---|---|---|
USER_CREDENTIAL |
("user1", "pass1") |
ストレージシステムでの認証に使用する認証情報です。サンプルコードの例は、ユーザIDがuser1、パスワードがpass1の場合の設定例です。このユーザには、ストレージ管理者(プロビジョニング)およびストレージ管理者(ローカルバックアップ管理)のロールが必要です。 |
COPY_GROUP_NAME |
"SI_347" |
ShadowImageペアの作成に使用するコピーグループ名です。サンプルコードでは、ペア作成時にコピーグループを新規に作成します。 |
COPY_PAIR_NAME |
"p_347-348" |
作成するShadowImageペアのコピーペア名です。 |
PVOL_LDEV_ID |
347 |
プライマリボリュームに使用する、作成済みボリュームのLDEV番号です。 |
SVOL_LDEV_ID |
348 |
セカンダリボリュームに使用する、作成済みボリュームのLDEV番号です。 |
FIRST_WAIT_TIME |
1 |
非同期処理の実行結果を取得する1回目の間隔(秒)です。通常は変更する必要はありません。 |
MAX_RETRY_COUNT |
10 |
非同期処理の実行結果を取得する最大リトライ回数です。通常は変更する必要はありません。 |
サンプルコードの内容
サンプルコードの内容について説明します。
-
必要なライブラリのインポートおよびパラメータの設定
ShadowImageペアの操作を開始する前に、必要なライブラリやクラスをインポートします。サンプルコードでは、共通ライブラリのほか、URLを生成する関数を定義したBlockStorageAPIクラスをインポートしています。# coding:utf-8 """ local_copy This program requires API version 1.2.x or newer. """ import traceback import requests import json import sys import http.client import time import rest_server_param import storage_param from block_storage_api import BlockStorageAPI
サンプルコード内で使用するパラメータを設定します。# #################Initialize parameters################# # # Change the following parameters to fit your environment # A copy group name COPY_GROUP_NAME = "SI_347" # A copy pair name COPY_PAIR_NAME = "p_347-348" # A primary volume ID # Specify already created and allocated volume ID by decimal PVOL_LDEV_ID = 347 # A secondary volume ID which has the exactly same size # as the primary volume # Specify already created and allocated volume ID by decimal SVOL_LDEV_ID = 348 # This parameter defines the first interval to access # an asynchronous job. (Unit: Second) FIRST_WAIT_TIME = 1 # This parameter defines the maximum retry time # to confirm job status. MAX_RETRY_COUNT = 10 # An user id and password of the target storage USER_CREDENTIAL = ("user1", "pass1") ###########################################################
-
ヘッダの定義
HTTPリクエストヘッダを定義します。REST APIはJSON形式のデータだけをサポートしているため、データをJSON形式で扱うようヘッダ情報を定義しておきます。また、非同期処理の場合に、ジョブが完了するのを待ってレスポンスを返すようResponse-Job-Statusヘッダで指定します。# ###You don't have to change the following parameters### # block_storage_api = BlockStorageAPI( rest_server_param.REST_SERVER_IP_ADDR, rest_server_param.REST_SERVER_PORT, storage_param.STORAGE_MODEL, storage_param.SERIAL_NUMBER) headers = {"content-type": "application/json", "accept": "application/json", "Response-Job-Status": "Completed"} REQUIRED_MAJOR_VERSION = 1 REQUIRED_MINOR_VERSION = 2 session_id = 0 ###########################################################
-
HTTPリクエストの発行と非同期処理の状態確認のための関数の定義(invoke_async_command関数)
HTTPリクエストの発行と非同期処理の状態を確認する関数を定義します。この関数は、メインのShadowImageペアの操作から呼び出して使用します。この関数の詳細については、サンプルコードで使用している関数の説明を参照してください。- ヒント
-
サンプルコードでは、REST APIクライアントとストレージシステム間のSSL通信で使用するサーバ証明書が自己署名証明書の場合に発生するエラーを回避するため、リクエスト発行時にverify=Falseを指定することでサーバ証明書の検証処理をスキップしています。
""" Check whether the asynchronous command was finished. @param job_id The job ID to identify the asynchronous command @return r.json() The JSON data that contains response data """ def check_update(job_id): url = block_storage_api.job(str(job_id)) r = requests.get(url, headers=headers, verify=False) return r """ Execute the HTTP request (POST or PUT) @param method_type HTTP request method (POST or PUT) @param url URL to execute HTTP method @param body The information of a resource @return job_result.json()["affectedResources"][0] URL of an affected resource """ def invoke_async_command(method_type, url, body): if method_type == "put": r = requests.put(url, headers=headers, data=json.dumps(body), verify=False) elif method_type == "post": r = requests.post( url, headers=headers, data=json.dumps(body), verify=False) if r.status_code != http.client.ACCEPTED: raise requests.HTTPError(r) print("Request was accepted. JOB URL : " + r.json()["self"]) status = "Initializing" job_result = None retry_count = 1 wait_time = FIRST_WAIT_TIME while status != "Completed": if retry_count > MAX_RETRY_COUNT: raise Exception("Timeout Error! " "Operation was not completed.") time.sleep(wait_time) job_result = check_update(r.json()["jobId"]) status = job_result.json()["status"] double_time = wait_time * 2 if double_time < 120: wait_time = double_time else: wait_time = 120 retry_count += 1 if job_result.json()["state"] == "Failed": error_obj = job_result.json()["error"] if "errorCode" in error_obj: if "SSB1" in error_obj["errorCode"]: print("Error! SSB code : ", error_obj["errorCode"]["SSB1"], ", ", error_obj["errorCode"]["SSB2"]) elif "errorCode" in error_obj["errorCode"]: print("Error! error code : ", error_obj["errorCode"]["errorCode"]) raise Exception("Job Error!", job_result.text) print("Async job was succeeded. affected resource : " + job_result.json()["affectedResources"][0]) return job_result.json()["affectedResources"][0]
-
REST APIのバージョンの確認
REST APIのバージョン情報を取得し、サポートしているバージョンであることを確認します。- ヒント
-
次の場合は、ストレージシステムのマイクロコードのバージョンが適切であるかどうかも確認してください。
- REST APIサーバとストレージシステム間でSSL通信を利用する場合
- ストレージシステムがVSP 5000 シリーズ、VSP E シリーズ、VSP G150、G350、G370、G700、G900、VSP F350、F370、F700、F900の場合
REST APIのバージョンとストレージシステムのマイクロコードのバージョンの対応については、Configuration Managerバージョン対応表を参照してください。
""" Check whether this API version allows the REST Server to execute this program @param api_version api version of this REST Server @param required_major_version the lowest number of the major version that this program requires @param required_minor_version the lowest number of the minor version that this program requires """ def check_api_version(api_version, required_major_version, required_minor_version): version = api_version.split(".") major_version = int(version[0]) minor_version = int(version[1]) if not ((major_version == required_major_version and minor_version >= required_minor_version) or major_version >= required_major_version + 1): sys.exit( "This program requires API Version " + str(required_major_version) + "." + str(required_minor_version) + "." + "x or newer.\n") try: # step1 Check the API version # print("Check the API version") url = block_storage_api.api_version() r = requests.get(url, headers=headers, verify=False) if r.status_code != http.client.OK: raise requests.HTTPError(r) check_api_version( r.json()["apiVersion"], REQUIRED_MAJOR_VERSION, REQUIRED_MINOR_VERSION)
-
セッションの生成
REST APIサーバで、セッションを生成します。# step2 Generate a session # print("Generate a session") url = block_storage_api.generate_session() r = requests.post(url, headers=headers, auth=USER_CREDENTIAL, verify=False) if r.status_code != http.client.OK: raise requests.HTTPError(r) token = r.json()["token"] auth = "Session " + token session_id = r.json()["sessionId"]
セッションを生成すると、セッションIDとトークンが返却されます。トークンは、これ以降の操作で必要な認証情報として、API実行時にAuthenticationヘッダに指定します。セッションIDは、一連の操作が終了したあと、セッションを破棄するときに使用します。
-
ShadowImageペアの作成
作成済みのボリュームを使用して、ShadowImageペアを作成します。コピーグループも新規に作成します。コピーグループ名やコピーペア名、使用するボリュームのLDEV番号は、あらかじめパラメータで定義したものを指定します。そのほか、コピーペア種別、MU番号、コピーグループの作成の有無などを指定して、ShadowImageペアを作成するリクエストを発行します。URLの生成にはblock_storage_api関数を使用しています。# step3 Create a local copy pair # print("Create a local copy pair") url = block_storage_api.local_copy_pairs() body = { "copyGroupName": COPY_GROUP_NAME, "copyPairName": COPY_PAIR_NAME, "replicationType": "SI", "pvolLdevId": PVOL_LDEV_ID, "pvolMuNumber": 0, "svolLdevId": SVOL_LDEV_ID, "isNewGroupCreation": True, } headers["Authorization"] = auth affected_resource = invoke_async_command("post", url, body) pair_url = block_storage_api.affected_resource( affected_resource)
invoke_async_command関数は、指定した条件でShadowImageペアを作成するリクエストを発行し、非同期に実行されるジョブの実行状態を確認して、作成したペアのURLを実行結果として返します。
-
ShadowImageペアの分割
サンプルコードでは、Actionテンプレートを使用してShadowImageペア分割の操作を行います。まず、ShadowImageペア作成ステップで取得したペアのURLを使用して、ペア分割用のActionテンプレートを取得します。# step4 Split the local copy pair # print("Split the local copy pair") url = block_storage_api.split_local_copy_pair_template( pair_url) r = requests.get(url, headers=headers, verify=False) if r.status_code != http.client.OK: raise requests.HTTPError(r) print("Action template(split):") print(r.text)
取得したテンプレートに値を設定して、作成したShadowImageペアを分割するためのリクエストを発行します。body = r.json() body["parameters"]["copyPace"] = 3 split_url = block_storage_api.split_local_copy_pair( pair_url) invoke_async_command("put", split_url, body)
-
ShadowImageペアの情報取得
ShadowImageペア作成ステップで取得したペアのURLを使用して、ペアの情報を取得します。サンプルコードでは、コピーグループ名、コピーペア名、P-VOLのLDEV番号とペアボリューム状態、S-VOLのLDEV番号とペアボリューム状態を出力しています。# step5 Print the pair status # print("Print the pair status") r = requests.get(pair_url, headers=headers, verify=False) if r.status_code != http.client.OK: raise requests.HTTPError(r) print("COPY GROUP NAME : " + r.json()["copyGroupName"]) print("COPY PAIR NAME : " + r.json()["copyPairName"]) print("P-VOL LDEV ID : " + str(r.json()["pvolLdevId"])) print("S-VOL LDEV ID : " + str(r.json()["svolLdevId"])) print("P-VOL STATUS : " + r.json()["pvolStatus"]) print("S-VOL STATUS : " + r.json()["svolStatus"]) print("LOCAL CLONE COPY PAIR ID : " + r.json()["localCloneCopypairId"]) print()
-
エラーメッセージの出力
サンプルコードでは、通信エラー、HTTPリクエストエラー、ジョブ実行時エラーの処理を記載しています。通信エラーの場合は、エラーメッセージを出力します。HTTPリクエストエラーの場合は、エラーコードとメッセージ、レスポンスボディを出力します。ジョブ実行時エラーの場合は、ジョブの実行結果に含まれる内容をすべて出力します。 必要な情報を出力したあと、処理を終了します。except requests.ConnectionError: sys.stderr.write("Connection Error!\n") sys.stderr.write(traceback.format_exc()) except requests.HTTPError as he: sys.stderr.write("HTTP Error! status code : ") sys.stderr.write(str(he.args[0].status_code) + "\n") sys.stderr.write(he.args[0].text + "\n") except Exception as e: sys.stderr.write(traceback.format_exc()) for msg in e.args: sys.stderr.write(str(msg) + "\n")
-
セッションの破棄
一連の操作が完了したら、セッションを破棄します。セッションの作成時に取得したセッションIDを指定します。サンプルコードでは、APIの実行中にエラーが発生した場合にも必ずセッションが破棄されるよう、finally句で記述しています。セッションを破棄したら、処理を終了します。finally: # step6 Discard the session # print("Discard the session") url = block_storage_api.discard_session(session_id) r = requests.delete(url, headers=headers, verify=False) try: if r.status_code != http.client.OK: raise requests.HTTPError(r) except requests.HTTPError as he: sys.stderr.write("HTTP Error! status code : ") sys.stderr.write(str(he.args[0].status_code) + "\n") sys.stderr.write(he.args[0].text + "\n") print("Operation was completed.") sys.exit()