Hitachi

Hitachi Command Suite Configuration Manager REST API リファレンスガイド


21.4 ShadowImageペア操作のサンプルコード

ShadowImageペア操作のサンプルコードについて説明します。

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

非同期処理の実行結果を取得する最大リトライ回数です。通常は変更する必要はありません。

サンプルコードの内容

サンプルコードの内容について説明します。

  1. 必要なライブラリのインポートおよびパラメータの設定

    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")
    
    ###########################################################
    
  2. ヘッダの定義

    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
    
    ###########################################################
    
  3. 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]
    
  4. REST APIのバージョンの確認

    REST APIのバージョン情報を取得し、サポートしているバージョンであることを確認します。
    ヒント

    次の場合は、ストレージシステムのマイクロコードのバージョンが適切であるかどうかも確認してください。

    • REST APIサーバとストレージシステム間でSSL通信を利用する場合
    • ストレージシステムがVSP 5000 シリーズVSP E シリーズVSP G150、G350、G370、G700、G900VSP 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)
    
  5. セッションの生成

    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は、一連の操作が終了したあと、セッションを破棄するときに使用します。

  6. 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を実行結果として返します。

  7. 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)
    
  8. 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()
    
  9. エラーメッセージの出力

    サンプルコードでは、通信エラー、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")
    
  10. セッションの破棄

    一連の操作が完了したら、セッションを破棄します。セッションの作成時に取得したセッション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()