21.7 ファイルアップロードのサンプルコード(監査ログ転送先設定)
ストレージシステムの監査ログ転送先設定のサンプルコードの流れ
ステップ |
サンプルコードの流れ |
コードの構成要素 |
---|---|---|
1 |
必要なライブラリのインポートおよびパラメータの設定 |
― |
2 |
ヘッダの定義 |
リクエストヘッダの指定(既定のHTTPヘッダの場合) |
3 |
HTTPリクエストの発行と非同期処理の状態確認のための関数の定義 |
GET操作によるジョブの状態取得 JSON形式によるリクエストボディの生成 ユーザ認証情報の設定(セッションベースの認証の場合) ジョブの実行結果の取得 操作結果が反映されたリソースのURL取得 エラーコードの取得 |
4 |
REST APIのバージョンの確認 |
GET操作によるREST APIバージョン情報の取得 |
5 |
セッションの生成 |
リソースのURL取得(オブジェクトIDを指定しない場合) ユーザ認証情報の設定(ユーザIDとパスワードによる認証の場合) POST操作によるオブジェクトの新規作成 |
6 |
転送先syslogサーバのルート証明書のアップロード |
リソースのURL取得(オブジェクトIDを指定しない場合) フォームデータの作成 POST操作によるオブジェクトに対するアクションの実行 |
7 |
転送先syslogサーバのクライアント証明書のアップロード |
リソースのURL取得(オブジェクトIDを指定しない場合) フォームデータの作成 POST操作によるオブジェクトに対するアクションの実行 |
8 |
転送先syslogサーバの設定 |
リソースのURL取得(単一インスタンスなどの固定のオブジェクトIDを指定する場合) JSON形式によるリクエストボディの生成 PUT 操作によるオブジェクトの属性変更 |
9 |
転送先syslogサーバへのテストメッセージ送信 |
リソースのURL取得(単一インスタンスなどの固定のオブジェクトIDを指定する場合) PUT操作によるオブジェクトに対するアクションの実行 |
10 |
監査ログの転送先設定の取得 |
リソースのURL取得(単一インスタンスなどの固定のオブジェクトIDを指定する場合) GET操作によるオブジェクトの取得(特定のオブジェクトを取得する場合) 取得した情報の出力 |
11 |
エラーメッセージの出力 |
エラーメッセージの出力 |
12 |
セッションの破棄 |
リソースのURL取得(操作結果から取得したオブジェクトIDを指定する場合) DELETE操作によるオブジェクトの削除 |
想定するシステム構成
このサンプルコードでは、次の概念図のようなシステム構成を想定しています。転送先のsyslogサーバは1台で構成するものとします。
サンプルコードのパラメータに設定している値を次に示します。必要に応じて、システムの環境や要件に合わせた設定に変更してください。
パラメータ |
設定値 |
説明 |
---|---|---|
USER_CREDENTIAL |
("user1", "pass1") |
ストレージシステムでの認証に使用する認証情報です。サンプルコードの例は、ユーザIDがuser1、パスワードがpass1の場合の設定例です。ユーザには、監査ログ管理者(参照・編集)ロールが必要です。 |
ROOT_CERT_FILE_PATH |
"D:\\cert\\" |
ストレージシステムへアップロードするsyslogサーバのルート証明書ファイルの格納先のパスです。 サンプルコードでは、ストレージシステムとsyslogサーバ間の通信にSSL通信を使用するよう設定します。事前にsyslogサーバのルート証明書を用意してください。 |
ROOT_CERT_FILE_NAME |
"root.crt" |
ストレージシステムへアップロードするsyslogサーバのルート証明書ファイル名です。 |
CLIENT_CERT_FILE_PATH |
"D:\\cert\\" |
ストレージシステムへアップロードするsyslogサーバのクライアント証明書ファイルの格納先のパスです。 サンプルコードでは、ストレージシステムとsyslogサーバ間の通信にSSL通信を使用するよう設定します。事前にsyslogサーバのクライアント証明書を用意してください。 |
CLIENT_CERT_FILE_NAME |
"client.pfx" |
ストレージシステムへアップロードするsyslogサーバのクライアント証明書ファイル名です。 |
TRANSFER_PROTOCOL |
"TLS" |
監査ログをsyslogサーバに転送する際に使用するプロトコルです。 |
LOCATION_NAME |
"STORAGE_SYSTEM_1" |
監査ログの転送元のストレージシステムを識別するための名称です。 |
RETRY_INTERVAL |
5 |
syslogサーバとの通信に失敗した場合のリトライ間隔(秒)です。 |
PRIMARY_SYSLOG_SERVER_IP_ADDR |
"192.0.1.101" |
syslog サーバのIPアドレスです。 |
PRIMARY_SYSLOG_SERVER_PORT |
"12345" |
syslog サーバが使用するポート番号です。 |
CLIENT_CERT_FILE_PASSWORD |
"certFilePass" |
クライアント証明書ファイルのパスワードです。 |
FIRST_WAIT_TIME |
1 |
非同期処理の実行結果を取得する1回目の間隔(秒)です。通常は変更する必要はありません。 |
MAX_RETRY_COUNT |
6 |
非同期処理の実行結果を取得する最大リトライ回数です。通常は変更する必要はありません。 |
サンプルコードの内容
サンプルコードの内容について説明します。
-
必要なライブラリのインポートおよびパラメータの設定
監査ログの転送先設定の処理を開始する前に、必要なライブラリやクラスをインポートします。サンプルコードでは、共通ライブラリのほか、URLを生成する関数を定義したBlockStorageAPIクラスをインポートしています。# coding:utf-8 """ auditlog_syslog_server setting This program requires API version 1.4.x 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 # A path of root certificate ROOT_CERT_FILE_PATH = "D:\\cert\\" # A root certificate name ROOT_CERT_FILE_NAME = "root.crt" # A path of client certificate CLIENT_CERT_FILE_PATH = "D:\\cert\\" # A client certificate name CLIENT_CERT_FILE_NAME = "client.pfx" # A transfer protocol TRANSFER_PROTOCOL = "TLS" # A location name LOCATION_NAME = "STORAGE_SYSTEM_1" # A retry interval RETRY_INTERVAL = 5 # A primary syslog server IP address PRIMARY_SYSLOG_SERVER_IP_ADDR = "192.0.1.101" # A primary syslog server port number PRIMARY_SYSLOG_SERVER_PORT = "12345" # A password of the client certificate CLIENT_CERT_FILE_PASSWORD = "certFilePass" # 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") ###########################################################
-
ヘッダの定義
HTTPリクエストヘッダを定義します。REST APIの標準であるJSON形式のほかに、ファイルをアップロードするAPIで使用するフォームデータ形式も扱うようヘッダ情報を定義しておきます。# ###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"} file_upload_headers = {"accept": "application/json"} REQUIRED_MAJOR_VERSION = 1 REQUIRED_MINOR_VERSION = 4 session_id = 0 ###########################################################
-
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 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": 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) if r.status_code != http.client.ACCEPTED: raise requests.HTTPError(r) print("Request was accepted. JOB URL : " + r.json()["self"])
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
-
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"] headers["Authorization"] = auth file_upload_headers["Authorization"] = auth
セッションを生成すると、セッションIDとトークンが返却されます。トークンは、これ以降の操作で必要な認証情報として、API実行時にAuthenticationヘッダに指定します。セッションIDは、一連の操作が終了したあと、セッションを破棄するときに使用します。
-
転送先syslogサーバのルート証明書のアップロード
監査ログのsyslogサーバへの転送をSSL通信で行うための準備として、syslogサーバのルート証明書をストレージシステムにアップロードします。# step3 Upload a root certificate # print("Upload a root certificate") url = block_storage_api.file_upload() files = {"file": (ROOT_CERT_FILE_NAME, open(ROOT_CERT_FILE_PATH + ROOT_CERT_FILE_NAME, "rb"), "application/octet-stream")} r = requests.post(url, headers=file_upload_headers, data={"fileType": "AuditSyslogPrimaryRootCertFile"}, files=files, verify=False) if r.status_code != http.client.OK: raise requests.HTTPError(r)
-
転送先syslogサーバのクライアント証明書のアップロード
監査ログのsyslogサーバへの転送をSSL通信で行うための準備として、syslogサーバのクライアント証明書をストレージシステムにアップロードします。# step4 Upload a client certificate # print("Upload a client certificate") files = {"file": (CLIENT_CERT_FILE_NAME, open(CLIENT_CERT_FILE_PATH + CLIENT_CERT_FILE_NAME, "rb"), "application/octet-stream")} r = requests.post(url, headers=file_upload_headers, data={"fileType": "AuditSyslogPrimaryClientCertFile"}, files=files, verify=False) if r.status_code != http.client.OK: raise requests.HTTPError(r)
-
転送先syslogサーバの設定
監査ログをsyslogサーバへ転送するための設定を行います。サンプルコードでは、syslogサーバとの通信にSSL通信を使用するよう設定するため、転送先のsyslogサーバの情報のほかにSSL通信用の証明書の情報も指定します。# step5 Modify the syslog server # print("Modify the syslog server") url = block_storage_api.auditlog_syslog() body = { "transferProtocol": TRANSFER_PROTOCOL, "locationName": LOCATION_NAME, "retries": True, "retryInterval": RETRY_INTERVAL, "primarySyslogServer": { "isEnabled": True, "ipAddress": PRIMARY_SYSLOG_SERVER_IP_ADDR, "port": PRIMARY_SYSLOG_SERVER_PORT, "clientCertFileName": CLIENT_CERT_FILE_NAME, "clientCertFilePassword": CLIENT_CERT_FILE_PASSWORD, "rootCertFileName": ROOT_CERT_FILE_NAME }, "secondarySyslogServer": { "isEnabled": False } } invoke_async_command("put", url, body)
invoke_async_command 関数は、監査ログの転送先を設定するリクエストを発行し、非同期に実行されるジョブの実行状態を確認して、ストレージシステムに設定した監査ログの転送先情報のURLを実行結果として返します。
-
転送先syslogサーバへのテストメッセージ送信
監査ログの転送先として設定したsyslogサーバが、監査ログのデータを正しく受信できるかどうかを確認するために、テストメッセージを送信します。# step6 Send a test message to the syslog server # print("Send a test message to the syslog server") url = block_storage_api.auditlog_syslog_send_test() invoke_async_command("put", url, None)
-
監査ログの転送先設定の情報取得
ここまでの操作が正しくストレージシステムに設定されていることを確認するため、監査ログの転送先設定の情報を取得して出力します。サンプルコードでは、取得した情報から、使用するプロトコル、転送元のストレージシステムの識別名、通信失敗時のリトライ設定およびリトライ間隔、syslog サーバIPアドレスおよびポート番号を取得し、出力しています。# step7 Get the syslog server # print("get the syslog server") url = block_storage_api.auditlog_syslog() r = requests.get(url, headers=headers, verify=False) if r.status_code != http.client.OK: raise requests.HTTPError(r) print("TRANSFER PROTOCOL : " + str(r.json()["transferProtocol"])) print("LOCATION NAME : " + str(r.json()["locationName"])) print("RETRIES : " + str(r.json()["retries"])) print("RETRY INTERVAL : " + str(r.json()["retryInterval"])) print("PRIMARY SYSLOG SERVER") print("IP ADDRESS : " + str(r.json()["primarySyslogServer"]["ipAddress"])) print("PORT : " + str(r.json()["primarySyslogServer"]["port"]))
-
エラーメッセージの出力
サンプルコードでは、通信エラー、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: # 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()