Sample Script Common Processing
This section describes common sample script processes, such as login/logout, RESTful API publishing, and getting job information. All of the sample scripts described below import the classes described here.
eternus_rest.py
import time
import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
class EtdxBaseApi(object):
"""Base class for implementations of RESTful API of ETERNUS DX.
To avoid errors when using a self-signed certificate for the server
certificate for SSL communication, the sample code skips the server
certificate verification process by specifying "verify = False"
when issuing the request.
"""
def __init__(self, base_url, boxid=None, proxies=None):
self.base_url = base_url
self.boxid = boxid
if proxies is None:
proxies = {
"http": None,
"https": None,
}
self.proxies = proxies
self.token = ""
def __del__(self):
if self.token != "":
self.logout()
def login(self, user_name="", password=""):
"""Create a session of RESTful API.
Args:
user_name (str, optional): User name to login. Defaults to "".
password (str, optional): Password for the user. Defaults to "".
Returns:
bool: True if successful, False otherwise.
"""
if user_name != "":
self.user_name = user_name
else:
if "user_name" not in dir(self):
print("Specify user name.")
return False
if password != "":
self.password = password
else:
if "password" not in dir(self):
print("Specify password.")
return False
body = {
"user_name": self.user_name,
"password": self.password
}
r = requests.post("{0!s}/api/v1/session".format(self.base_url),
json=body,
verify=False,
proxies=self.proxies)
if r.status_code != 200:
print("Login failed.")
return False
# Keep the session information
self.token = r.json()["token"]
self.session_id = r.json()["session_id"]
self.headers = {"Authorization": "Bearer {0!s}".format(self.token)}
return True
def logout(self):
"""Delete the session of RESTful API.
Delete the session and the information of the session in the class.
Returns:
bool: True if successful, False otherwise.
"""
r = self.delete("/api/v1/session/{0!s}".format(self.session_id))
if r.status_code != 200:
print("Logout failed.")
return False
# Clear the session information
self.token = ""
self.session_id = 0
self.headers = {}
return True
def get(self, resource):
"""Get data from a specified resource.
Log in to the storage automatically if the session expires.
Args:
resource (str): Resource url with query to get data.
Returns:
obj: The Response object, which contains a storage's response
to an HTTP request.
"""
for _ in range(2):
r = requests.get(self.base_url + resource,
headers=self.headers,
verify=False,
proxies=self.proxies)
if r.status_code != 401:
break
self.login()
return r
def post(self, resource, body={}, retry_interval=5, max_try=370):
"""Make a POST request to a specified resource.
Log in to the storage automatically if the session expires.
If the storage returns the http status as 503, send it again
until retry timeout.
Args:
resource (str): Resource url to make a POST request.
body (obj, optional): Body object if needed. Defaults to {}.
retry_interval (int, optional): Retry interval.
The unit is seconds. Defaults to 5.
max_try (int, optional): Number of retries.
Default retries for 30 minutes plus a little more,
since a job is stored in storage for 30 minutes.
Returns:
obj: The Response object, which contains a storage's response
to an HTTP request.
"""
for _ in range(max_try):
for _ in range(2):
if body != {}:
r = requests.post(self.base_url + resource,
headers=self.headers,
json=body, verify=False,
proxies=self.proxies)
else:
r = requests.post(self.base_url + resource,
headers=self.headers,
verify=False,
proxies=self.proxies)
if r.status_code != 401:
break
self.login()
if r.status_code != 503:
break
time.sleep(retry_interval)
else:
print("Running out of job entries. "
"Please try again later or check the storage condition.")
return r
def delete(self, resource, body={}, retry_interval=5, max_try=370):
"""Make a DELETE request to a specified resource.
Log in to the storage automatically if the session expires.
If the storage returns the http status as 503,
send it again until retry timeout.
Args:
resource (str): Resource url to make a DELETE request.
body (obj, optional): Body object if needed. Defaults to {}.
retry_interval (int, optional): Retry interval.
The unit is seconds. Defaults to 5.
max_try (int, optional): Number of retries.
Default retries for 30 minutes plus a little more,
since a job is stored in storage for 30 minutes.
Returns:
obj: The Response object, which contains a storage's response
to an HTTP request.
"""
for _ in range(max_try):
for _ in range(2):
if body != {}:
r = requests.delete(self.base_url + resource,
headers=self.headers,
json=body,
verify=False,
proxies=self.proxies)
else:
r = requests.delete(self.base_url + resource,
headers=self.headers,
verify=False,
proxies=self.proxies)
if r.status_code != 401:
break
self.login()
if r.status_code != 503:
break
time.sleep(retry_interval)
else:
print("Running out of job entries. "
"Please try again later or check the storage condition.")
return r
def patch(self, resource, body, retry_interval=5, max_try=370):
"""Make a PATCH request to a specified resource.
Log in to the storage automatically if the session expires.
If the storage returns the http status as 503,
send it again until retry timeout.
Args:
resource (str): Resource url to make a PATCH request.
body (obj): Body object of PATCH request.
retry_interval (int): Retry interval.
The unit is seconds. Defaults to 5.
max_try (int): Number of retries.
Default retries for 30 minutes plus a little more,
since a job is stored in storage for 30 minutes.
Returns:
obj: The Response object, which contains a storage's response
to an HTTP request.
"""
for _ in range(max_try):
for _ in range(2):
r = requests.patch(self.base_url + resource,
headers=self.headers,
json=body,
verify=False,
proxies=self.proxies)
if r.status_code != 401:
break
self.login()
if r.status_code != 503:
break
time.sleep(retry_interval)
else:
print("Running out of job entries. "
"Please try again later or check the storage condition.")
return r
def wait_job(self, job_id, retry_interval=5, max_try=360):
"""Wait for a completion of a specified job.
Get a job information every 5 seconds until the job status is
"Success" or "Error".
The last Response object of the job will be returned, if the job
status is not "Success" or "Error" when retry to get "max_try" times.
If the job status is "Success" or "Error", delete the job resource.
Log in to the storage automatically if the session expires.
Args:
job_id (int): Job_id to wait for a completion.
retry_interval (int, optional): Retry interval.
The unit is seconds. Defaults to 5.
max_try (int, optional): Number of retries.
Default retries for 30 minutes,
since a job is stored in storage for 30 minutes.
Returns:
obj: The Response object of the job, which contains a storage's
response to an HTTP request.
"""
for _ in range(max_try):
r = self.get("/api/v1/job/{0!s}".format(job_id))
if r.status_code != 200:
print(r.status_code)
print(r.json())
break
if (r.json()["status"] in
["Success", "Error", "Partial_Error", "Canceled"]):
break
time.sleep(retry_interval)
else:
print("The job timed out.")
return r
self.delete("/api/v1/job/{0!s}".format(job_id))
return r
def get_resource_id(self, resource, number=None, name=None,
host_type=None):
"""Get the resource ID from number or name.
It is possible to get resource ID about the following resources.
- volume, raidgroup, tpp, ftrp, host
Specify either number or name, but not both.
If "host" is specified for resource, host_type must be specified.
Args:
resource (str): Resource to get ID.
The followings can be specified.
- volume, raidgroup, tpp, ftrp, host
number (int, optional): Number of the resource to get ID.
Defaults to None.
name (str, optional): Name of the resource to get ID.
Defaults to None.
host_type (str, optional): If "host" is specified for resource,
host_type must be specified. For other resources, host_type is
ignored.
The followings can be specified.
- FC, iSCSI
Returns:
int: Resource ID. If failed or not found, returns a value of -1.
This value cannot be used as resource ID.
"""
if ((number is None and name is None)
or (number is not None and name is not None)):
print("Specify either number or name, but not both.")
return -1
# If "host" is specified for resource, host_type must be specified.
# For other resources, set host_type to None.
if resource == "host" and host_type is None:
print("host_type is required to get host id.")
return -1
elif resource != "host":
host_type = None
# Get the resource list to search for the specified resource.
if resource == "host":
r = self.get("/api/v1/{0!s}?fields=number,name,type"
.format(resource))
else:
r = self.get("/api/v1/{0!s}?fields=number,name".format(resource))
if r.status_code != 200:
print("Failed to get the resource information or "
"cannot get the resource ID ({0!s}) by this method."
.format(resource))
return -1
data = r.json()
# Resources are in {resource_name}_list.
if "{0!s}_list".format(resource) in data:
list = data["{0!s}_list".format(resource)]
else:
print("Cannot get this resource ID ({0!s}) by this method."
.format(resource))
return -1
# Search for a resource with the specified number or name.
for i in list:
# If the specified resource is host, check the type.
if host_type is not None and i["type"] != host_type:
continue
if number is not None and i["number"] == number:
return i["{0!s}_id".format(resource)]
if name is not None and i["name"] == name:
return i["{0!s}_id".format(resource)]
else:
print("Could not find the specified resource.")
return -1

