Sample coding operation flow for registering remote storage system information
Step |
Sample coding operation flow |
Code constructs |
---|---|---|
1 |
Import necessary libraries and set parameters. |
- |
2 |
Define headers. |
Specifying request headers (for the default HTTP headers) |
3 |
Define functions for issuing an HTTP request and for verifying the status of asynchronous processing. |
Getting information about the job status by performing a GET operation Setting user authentication information (for authentication by using session-based authentication) Generating a request body in JSON format Getting the job execution results Getting the URLs of the resources to which the operation results have been applied Getting error codes |
4 |
Check the version of the REST API. |
Getting information about the version of the REST API by performing a GET operation |
5 |
Generate a session. |
Getting the URLs of the resources (when object IDs are not specified) Setting user authentication information (for authentication by using a user ID and a password) Creating objects by performing a POST operation |
6 |
Register information about storage systems. |
Getting the URLs of the resources (when object IDs are not specified) Generating a request body in JSON format Operations that require sessions to be generated on multiple devices (remote copy operation) Creating objects by performing a POST operation |
7 |
Get information about storage systems. |
Getting the URLs of the resources (when object IDs that are obtained from the operation results are specified) Setting user authentication information (for authentication by using session-based authentication) Getting an object by performing a GET operation Outputting the obtained information |
8 |
Output error messages. |
Outputting error messages |
9 |
Discard the session. |
Getting the URLs of the resources (when object IDs that are obtained from the operation results are specified) Deleting objects by performing a DELETE operation |
Expected system configuration
This sample coding assumes the system configuration is as shown in the following figure.
The following table shows the values specified for the parameters in the sample coding. If necessary, change the settings to match the system environment and requirements.
Parameter |
Value |
Description |
---|---|---|
LOCAL_USER _CREDENTIAL |
("local_user", "local_pass") |
This is the authentication information to be used for authentication in the local storage system. The coding sample shows a setting example when the user ID is local_user, and the password is local_pass. The user needs the Storage Administrator (Initial Configuration) role. |
REMOTE_USER _CREDENTIAL |
("remote_user", "remote_pass") |
This is the authentication information to be used for authentication in the remote storage system. The coding sample shows a setting example when the user ID is remote_user, and the password is remote_pass. The user needs the Storage Administrator (Initial Configuration) role. |
FIRST_WAIT_TIME |
1 |
The first interval for collecting the execution result of asynchronous processing. Normally, you do not need to change this value. |
MAX_RETRY_COUNT |
10 |
The maximum number of retries for collecting the execution result of asynchronous processing. Normally, you do not need to change this value. |
The following table shows the parameters and values defined in the remote_copy_param.py file, which can be used in coding samples as common variables for the information about the local and the remote storage systems. If necessary, change the settings to match the system environment and requirements.
Parameter |
Value |
Description |
---|---|---|
LOCAL_REST_SERVER_IP_ADDR |
192.0.2.100 |
The IP address of the REST API server of the local storage system |
LOCAL_PORT |
443 |
The SSL communication port for the REST API server of the local storage system |
LOCAL_STORAGE_MODEL |
VSP G900 |
The model name of the local storage system |
LOCAL_SERIAL_NUMBER |
410000 |
The serial number of the local storage system |
REMOTE_REST_SERVER_IP_ADDR |
192.0.2.200 |
The IP address of the REST API server of the remote storage system |
REMOTE_PORT |
443 |
The SSL communication port for the REST API server of the remote storage system |
REMOTE_STORAGE_MODEL |
VSP G900 |
The model name of the remote storage system |
REMOTE_SERIAL_NUMBER |
420000 |
The serial number of the remote storage system |
Contents of the sample coding
This subsection explains the sample coding.
-
Import necessary libraries and set parameters.
Before starting the registration processing of remote storage system information, the sample coding imports the required libraries or classes. In addition to the common libraries, the sample coding also imports the BlockStorageAPI class that defines the function that generates URLs.
# coding:utf-8 """ register_remote_storage This program requires API version 1.9.0 or newer. """ import traceback import requests import json import sys import http.client import time import remote_copy_param from block_storage_api import BlockStorageAPI
Set parameters to be used in the sample coding.
# #################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 = 10 # An user id and password of the local storage LOCAL_USER_CREDENTIAL = ("local_user", "local_pass") # An user id and password of the remote storage REMOTE_USER_CREDENTIAL = ("remote_user", "remote_pass") ###########################################################
-
Define headers.
Define the HTTP request header. Because the REST API only supports JSON format data, the sample coding defines header information so that data is handled in JSON format.
# ###You don't have to change the following parameters### # local_storage_api = BlockStorageAPI( remote_copy_param.LOCAL_REST_SERVER_IP_ADDR, remote_copy_param.LOCAL_PORT, remote_copy_param.LOCAL_STORAGE_MODEL, remote_copy_param.LOCAL_SERIAL_NUMBER) remote_storage_api = BlockStorageAPI( remote_copy_param.REMOTE_REST_SERVER_IP_ADDR, remote_copy_param.REMOTE_PORT, remote_copy_param.REMOTE_STORAGE_MODEL, remote_copy_param.REMOTE_SERIAL_NUMBER) local_headers = {"content-type": "application/json", "accept": "application/json", "Response-Job-Status": "Completed"} remote_headers = {"content-type": "application/json", "accept": "application/json", "Response-Job-Status": "Completed"} REQUIRED_MAJOR_VERSION = 1 REQUIRED_MINOR_VERSION = 9 local_session_id = 0 remote_session_id = 0 ###########################################################
-
Define the function for issuing an HTTP request and for verifying the status of asynchronous processing (the invoke_async_command function).
Define the function that issues an HTTP request and verifies the status of asynchronous processing. Call and use this function from the main registration operation of the remote storage system information. For details on this function, see the section explaining the functions used in the sample coding.
Tip: To prevent errors that occur when the server certificate used for SSL communication between the REST API client and the storage system is a self-signed certificate, the sample coding specifies verify=False in the request message to skip verification of the server certificate.""" Check whether the asynchronous command was finished. @param storage_api storage_api @param job_id the job ID to identify the asynchronous command @param headers the array of the http headers @return r the response data """ def check_update(storage_api, job_id, headers): url = storage_api.job(str(job_id)) r = requests.get(url, headers=headers, verify=False) return r """ Execute the HTTP request (POST or PATCH) @param storage_api storage_api @param method_type HTTP request method (POST or PATCH) @param headers the array of the http headers @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(storage_api, method_type, headers, url, body): if method_type == "patch": r = requests.patch(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(storage_api, r.json()["jobId"], headers) 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]
-
Check the version of the REST API.
Get information about the version of the REST API for both the local and the remote storage systems by using the REST API server of each system to make sure that the version is supported.
""" 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 of the local REST API # print("Check the API version of the local REST API") url = local_storage_api.api_version() r = requests.get(url, headers=local_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) # step1 Check the API version of the remote REST API # print("Check the API version of the remote REST API") url = remote_storage_api.api_version() r = requests.get(url, headers=remote_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)
-
Generate a session.
Generate a session in both the local and the remote storage systems by using the REST API server of each system.
# step2 Generate a local session # print("Generate a local session") url = local_storage_api.generate_session() r = requests.post( url, headers=local_headers, auth=LOCAL_USER_CREDENTIAL, verify=False) if r.status_code != http.client.OK: raise requests.HTTPError(r) local_token = r.json()["token"] local_auth = "Session " + local_token local_session_id = r.json()["sessionId"] # step2 Generate a remote session # print("Generate a remote session") url = remote_storage_api.generate_session() r = requests.post(url, headers=remote_headers, auth=REMOTE_USER_CREDENTIAL, verify=False) if r.status_code != http.client.OK: raise requests.HTTPError(r) remote_token = r.json()["token"] remote_auth = "Session " + remote_token remote_session_id = r.json()["sessionId"] remote_headers["Authorization"] = remote_auth
When a session is generated, a session ID and a token are returned. When running the API, specify the token for the Authentication header as the required authentication information for the subsequent operations. Use the session ID to discard the session after a set of operations is completed.
-
Register information about the remote storage system
Register information about the remote storage system on the REST API server of the local storage system. For the request body, specify information about the remote storage system.
# step3 Register a remote storage device # print("Register a remote storage device") url = local_storage_api.remote_storage() body = { "storageDeviceId": remote_storage_api. get_storage_id(), "restServerIp": remote_copy_param.REMOTE_REST_SERVER_IP_ADDR, "restServerPort": remote_copy_param.REMOTE_PORT } local_headers["Authorization"] = local_auth local_headers["Remote-Authorization"] = remote_auth affected_resource_path = invoke_async_command( local_storage_api, "post", local_headers, url, body)
The invoke_async_command function issues a request for registering information about the remote storage system, verifies the execution status of the jobs that were run asynchronously, and then returns the URL of the registered storage system as the execution result.
-
Get information about the registered remote storage system.
To confirm that information about the remote storage system is correctly registered, get the registered storage information by using the REST API server of the local storage system.
# step4 Print the remote storage device # print("Print the remote storage device") url = local_storage_api.affected_resource( affected_resource_path) r = requests.get(url, headers=local_headers, verify=False) if r.status_code != http.client.OK: raise requests.HTTPError(r) print("STORAGE DEVICE ID : " + str(r.json()["storageDeviceId"])) print("DKC TYPE : " + str(r.json()["dkcType"])) print("REST SERVER IP : " + str(r.json()["restServerIp"])) print("REST SERVER PORT : " + str(r.json()["restServerPort"])) print("MODEL : " + str(r.json()["model"])) print("SERIAL NUMBER : " + str(r.json()["serialNumber"]))
In the sample coding, the following items are obtained and output: storage device ID, storage system type, IP address of the REST API server for the remote storage system, port number of the REST API server for the remote storage system, model name, and serial number.
-
Output error messages.
In the sample coding, processing for communication errors, HTTP request errors, and job execution errors is described. If a communication error occurs, an error message is output. If an HTTP request error occurs, the error code, the error message, and the response body are output. If a job execution error occurs, all of the contents included in the job execution result are output.
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")
-
Discard the session.
After a set of operations is completed, discard the session by using the REST API server of both the local and the remote storage systems. Specify the session ID that was obtained when the session was created. The "finally" statement in the sample coding makes sure that the session will be discarded even if an error occurs while the API is running. After the session is discarded, the processing ends.
finally: # step5 Discard the local session # print("Discard the local session") url = local_storage_api.discard_session( local_session_id) r = requests.delete(url, headers=local_headers, verify=False) if r.status_code != http.client.OK: raise requests.HTTPError(r) # step5 Discard the remote session # print("Discard the remote session") url = remote_storage_api.discard_session( remote_session_id) r = requests.delete(url, headers=remote_headers, verify=False) if r.status_code != http.client.OK: raise requests.HTTPError(r) print("Operation was completed.") sys.exit()