Hitachi

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


21.9 パリティグループ再作成(データの暗号化)のサンプルコード

パリティグループ再作成(データの暗号化)のサンプルコードについて説明します。
メモ

このサンプルコードで行う操作は、ドライブの構成を変更しないで既存のデータを暗号化する場合に行う操作の流れの一部の手順です。この操作の全体の手順については、データ暗号化の操作の流れの説明を参照してください。

削除するパリティグループ上のボリュームのデータは、あらかじめ別のパリティグループ上のボリュームに退避しておいてください。

パリティグループ再作成のサンプルコードの流れ

パリティグループ再作成のサンプルコードの流れと、対応するコードの構成要素を次に示します。
ステップ

サンプルコードの流れ

コードの構成要素

1

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

2

ヘッダの定義

リクエストヘッダの指定(既定のHTTPヘッダの場合)

3

HTTP リクエストの発行と非同期処理の状態確認のための関数の定義

GET操作によるジョブの状態取得

ユーザ認証情報の設定(セッションベースの認証の場合)

JSON形式によるリクエストボディの生成

ジョブの実行結果の取得

捜査結果が反映されたリソースのURL取得

エラーコードの取得

4

REST APIのバージョンの確認

GET操作によるREST APIバージョン情報の取得

5

セッションの生成

リソースのURL取得(オブジェクトIDを指定しない場合)

ユーザ認証情報の設定(ユーザIDとパスワードによる認証の場合)

POST操作によるオブジェクトの新規作成

6

パリティグループの情報取得

GET操作によるオブジェクトの取得

ユーザ認証情報の設定(セッションベースの認証の場合)

取得した情報の出力

7

ドライブの情報取得

GET操作によるオブジェクトの取得

ユーザ認証情報の設定(セッションベースの認証の場合)

取得した情報の出力

8

パリティグループの削除

リソースのURL取得(オブジェクトIDを指定しない場合)

ユーザ認証情報の設定(セッションベースの認証の場合)

JSON 形式によるリクエストボディの生成

DELETE 操作によるオブジェクトの削除

9

パリティグループの作成

リソースのURL取得(オブジェクトIDを指定しない場合)

ユーザ認証情報の設定(セッションベースの認証の場合)

JSON形式によるリクエストボディの生成

POST操作によるオブジェクトの新規作成

10

パリティグループの情報取得

GET操作によるオブジェクトの取得

ユーザ認証情報の設定(セッションベースの認証の場合)

取得した情報の出力

11

エラーメッセージの出力

エラーメッセージの出力

12

セッションの破棄

リソースのURL取得(操作結果から取得したオブジェクトIDを指定する場合)

DELETE操作によるオブジェクトの削除

想定するシステム構成

このサンプルコードでは、次の概念図のようなシステム構成を想定しています。

[図データ]

サンプルコードのパラメータに設定している値を次に示します。必要に応じて、システムの環境や要件に合わせた設定に変更してください。

パラメータ

設定値

説明

USER_CREDENTIAL

("user1", "pass1")

ストレージシステムでの認証に使用する認証情報です。サンプルコードの例は、ユーザIDがuser1、パスワードがpass1の場合の設定例です。このユーザにはストレージ管理者(プロビジョニング)ロールが必要です。

PARITY_GROUP_ID

1-1

再作成するパリティグループのIDです。

FIRST_WAIT_TIME

1

非同期処理の実行結果を取得する1回目の間隔(秒)です。通常は変更する必要はありません。

MAX_RETRY_COUNT

6

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

サンプルコードの内容

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

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

    ボリューム割り当ての処理を開始する前に、必要なライブラリやクラスをインポートします。サンプルコードでは、共通ライブラリのほか、URLを生成する関数を定義したBlockStorageAPIクラスをインポートしています。

    # coding:utf-8
    
    """
    recreate_parity_group
    
    This program requires API version 1.12.0 or newer.
    """
    
    import requests
    import json
    import sys
    import http.client
    import time
    import traceback
    import rest_server_param
    import storage_param
    
    from block_storage_api import BlockStorageAPI
    

    サンプルコード内で使用するパラメータを設定します。

    # #################Initialize parameters################# #
    # Change the following parameters to fit your environment
    
    # 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 = 6
    
    # An user id and password of the target storage
    USER_CREDENTIAL = ("user1", "pass1")
    
    # A parity group id
    PARITY_GROUP_ID = "1-1"
    
    ###########################################################
    
  2. ヘッダの定義

    HTTPリクエストヘッダを定義します。REST APIはJSON形式のデータだけをサポートしているため、データをJSON形式で扱うようヘッダ情報を定義しておきます。

    # ###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 = 12
    
    ###########################################################
    
  3. HTTP リクエストの発行と非同期処理の状態確認のための関数の定義(invoke_async_command関数)

    HTTPリクエストの発行と非同期処理の状態を確認する関数を定義します。この関数は、メインのボリューム割り当て操作から呼び出して使用します。この関数の詳細については、サンプルコードで使用している関数の説明を参照してください。

    ヒント

    サンプルコードでは、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 the 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, PUT or DELETE)
    @param method_type HTTP request method (POST, PUT or DELETE)
    @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":
            if body is None:
                r = requests.put(url, headers=headers, verify=False)
            else:
                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)
        elif method_type == "delete":
            r = requests.delete(
                url,
                headers=headers,
                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)
        if "affectedResources" in job_result.json():
            print("Async job was succeeded. affected resource : " +
                  job_result.json()["affectedResources"][0])
            return job_result.json()["affectedResources"][0]
        else:
            print("Async job was succeeded.")
            return None
    
  4. REST APIのバージョンの確認

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

    ヒント

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

    • REST APIサーバとストレージシステム間でSSL通信を利用する場合
    • ストレージシステムが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"]
        headers["Authorization"] = auth
    

    セッションを生成すると、セッションIDとトークンが返却されます。トークンは、これ以降の操作で必要な認証情報として、API実行時にAuthenticationヘッダに指定します。セッションIDは、一連の操作が終了したあと、セッションを破棄するときに使用します。

  6. パリティグループの情報取得

    パリティグループ番号を指定して、パリティグループの情報を取得します。サンプルコードでは、取得した情報から、パリティグループ内のLDEV数、パリティグループの使用率、使用できる容量、RAIDレベル、RAID種別、CLPR番号、パリティグループを構成するドライブのドライブタイプコード、パリティグループを構成するドライブのドライブタイプ、パリティグループを構成するドライブの回転数、パリティグループの暗号化の設定、パリティグループの論理容量の合計、パリティグループの物理容量の合計、パリティグループの容量拡張の設定を出力しています。

        # step3 Get the parity group #
        print("Get the parity group")
        url = block_storage_api.parity_group(PARITY_GROUP_ID)
        r = requests.get(url, headers=headers,
                         auth=USER_CREDENTIAL, verify=False)
        if r.status_code != http.client.OK:
            raise requests.HTTPError(r)
        
        raidType = r.json()["raidType"]
        isCopyBackModeEnabled = r.json()["isEncryptionEnabled"]
        isAcceleratedCompressionEnabled = r.json()["isAcceleratedCompressionEnabled"]
        clprId = r.json()["clprId"]
        print("NUM OF LDEVS : " + str(r.json()["numOfLdevs"]))
        print("USED CAPACITY RATE : " + str(r.json()["usedCapacityRate"]))
        print("AVAILABLE VOLUME CAPACITY : " + str(r.json()["availableVolumeCapacity"]))
        print("RAID LEVEL : " + str(r.json()["raidLevel"]))
        print("RAID TYPE : " + str(r.json()["raidType"]))
        print("CLPR ID : " + str(r.json()["clprId"]))
        print("DRIVE TYPE : " + r.json()["driveType"])
        print("DRIVE TYPE NAME : " + str(r.json()["driveTypeName"]))
        print("DRIVE SPEED : " + str(r.json()["driveSpeed"]))
        print("IS ENCRYPTION ENABLED : " + str(r.json()["isEncryptionEnabled"]))
        print("TOTAL CAPACITY : " + str(r.json()["totalCapacity"]))
        print("PHYSICAL TOTAL CAPACITY : " + str(r.json()["physicalCapacity"]))
        print("IS ACCELERATED COMPRESSION ENABLED : " + str(r.json()["isAcceleratedCompressionEnabled"]))
        print()
    
  7. ドライブの情報取得

    パリティグループ番号を指定して、パリティグループに属するドライブの情報を取得します。

        # step4 Get drives #
        print("Get drives")
        url = block_storage_api.drives_parity_group(PARITY_GROUP_ID)
        r = requests.get(url, headers=headers,
                         auth=USER_CREDENTIAL, verify=False)
        if r.status_code != http.client.OK:
            raise requests.HTTPError(r)
        
        drive_ids = []
        for d in r.json()["data"]:
            drive_ids.append(d["driveLocationId"])
            print("DRIVE LOCATION ID : " + str(d["driveLocationId"]))
        print()
    
  8. パリティグループの削除

    パリティグループ番号を指定して、パリティグループを削除します。

        # step5 Delete the parity group #
        print("Delete the parity group")
        url = block_storage_api.parity_group(PARITY_GROUP_ID)
        invoke_async_command("delete", url, None)
    

    invoke_async_command関数は、パリティグループを削除するリクエストを発行し、非同期に実行されるジョブの実行状態を確認して、削除したパリティグループのURLを実行結果として返します。

  9. パリティグループの作成

    パリティグループ番号、ドライブIDを指定して、パリティグループを作成します。

        # step6 Create the parity group #
        print("Create the parity group")
        url = block_storage_api.parity_groups()
        body = {
            "parityGroupId": PARITY_GROUP_ID,
            "driveLocationIds": drive_ids,
            "raidType": raidType,
            "isEncryptionEnabled": True,
            "isCopyBackModeEnabled": isCopyBackModeEnabled,
            "isAcceleratedCompressionEnabled": isAcceleratedCompressionEnabled,
            "clprId": clprId
        }
        invoke_async_command("post", url, body)
    

    invoke_async_command関数は、パリティグループを作成するリクエストを発行し、非同期に実行されるジョブの実行状態を確認して、作成したパリティグループのURLを実行結果として返します。

  10. パリティグループの情報取得

    ここまでの操作が正しくリソースに反映されていることを確認するため、パリティグループの作成時に取得したパリティグループ番号を指定して、パリティグループの情報を取得します。サンプルコードでは、取得した情報から、パリティグループ内のLDEV数、パリティグループの使用率、使用できる容量、RAIDレベル、RAID種別、CLPR番号、パリティグループを構成するドライブのドライブタイプコード、パリティグループを構成するドライブのドライブタイプ、パリティグループを構成するドライブの回転数、パリティグループの暗号化の設定、パリティグループの論理容量の合計、パリティグループの物理容量の合計、パリティグループの容量拡張の設定を出力しています。

        # step7 Get the parity group #
        print("Get the parity group")
        url = block_storage_api.parity_group(PARITY_GROUP_ID)
        r = requests.get(url, headers=headers,
                         auth=USER_CREDENTIAL, verify=False)
        if r.status_code != http.client.OK:
            raise requests.HTTPError(r)
        
        print("NUM OF LDEVS : " + str(r.json()["numOfLdevs"]))
        print("USED CAPACITY RATE : " + str(r.json()["usedCapacityRate"]))
        print("AVAILABLE VOLUME CAPACITY : " + str(r.json()["availableVolumeCapacity"]))
        print("RAID LEVEL : " + str(r.json()["raidLevel"]))
        print("RAID TYPE : " + str(r.json()["raidType"]))
        print("CLPR ID : " + str(r.json()["clprId"]))
        print("DRIVE TYPE : " + r.json()["driveType"])
        print("DRIVE TYPE NAME : " + str(r.json()["driveTypeName"]))
        print("DRIVE SPEED : " + str(r.json()["driveSpeed"]))
        print("IS ENCRYPTION ENABLED : " + str(r.json()["isEncryptionEnabled"]))
        print("TOTAL CAPACITY : " + str(r.json()["totalCapacity"]))
        print("PHYSICAL TOTAL CAPACITY : " + str(r.json()["physicalCapacity"]))
        print("IS ACCELERATED COMPRESSION ENABLED : " + str(r.json()["isAcceleratedCompressionEnabled"]))
        print()
    
  11. エラーメッセージの出力

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

    一連の操作が完了したら、セッションを破棄します。セッションの作成時に取得したセッションIDを指定します。サンプルコードでは、APIの実行中にエラーが発生した場合にも必ずセッションが破棄されるよう、finally句で記述しています。セッションを破棄したら、処理を終了します。

    finally:
        # step8 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()