212 lines
7.4 KiB
Python
212 lines
7.4 KiB
Python
# Copyright (c) 2016 Hitachi Data Systems, Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import json
|
|
import requests
|
|
|
|
from manila import exception
|
|
from manila.i18n import _
|
|
from manila import utils
|
|
|
|
|
|
# Suppress the Insecure request warnings
|
|
requests.packages.urllib3.disable_warnings() # pylint: disable=no-member
|
|
|
|
|
|
class HSPRestBackend(object):
|
|
def __init__(self, hsp_host, hsp_username, hsp_password):
|
|
self.host = hsp_host
|
|
self.username = hsp_username
|
|
self.password = hsp_password
|
|
|
|
def _send_post(self, url, payload=None):
|
|
resp = requests.post(url, auth=(self.username, self.password),
|
|
data=payload, verify=False)
|
|
|
|
if resp.status_code == 202:
|
|
self._wait_job_status(resp.headers['location'], 'COMPLETE')
|
|
else:
|
|
msg = (_("HSP API post failed: %s.") %
|
|
resp.json()['messages'][0]['message'])
|
|
raise exception.HSPBackendException(msg=msg)
|
|
|
|
def _send_get(self, url, payload=None):
|
|
resp = requests.get(url, auth=(self.username, self.password),
|
|
data=payload, verify=False)
|
|
|
|
if resp.status_code == 200:
|
|
if resp.content == 'null':
|
|
return None
|
|
else:
|
|
return resp.json()
|
|
else:
|
|
msg = (_("HSP API get failed: %s.") %
|
|
resp.json()['messages'][0]['message'])
|
|
raise exception.HSPBackendException(msg=msg)
|
|
|
|
def _send_delete(self, url, payload=None):
|
|
resp = requests.delete(url, auth=(self.username, self.password),
|
|
data=payload, verify=False)
|
|
|
|
if resp.status_code == 202:
|
|
self._wait_job_status(resp.headers['location'], 'COMPLETE')
|
|
else:
|
|
msg = (_("HSP API delete failed: %s.") %
|
|
resp.json()['messages'][0]['message'])
|
|
raise exception.HSPBackendException(msg=msg)
|
|
|
|
def add_file_system(self, name, quota):
|
|
url = "https://%s/hspapi/file-systems/" % self.host
|
|
payload = {
|
|
'quota': quota,
|
|
'auto-access': False,
|
|
'enabled': True,
|
|
'description': '',
|
|
'record-access-time': True,
|
|
'tags': '',
|
|
# Usage percentage in which a warning will be shown
|
|
'space-hwm': 90,
|
|
# Usage percentage in which the warning will be cleared
|
|
'space-lwm': 70,
|
|
'name': name,
|
|
}
|
|
self._send_post(url, payload=json.dumps(payload))
|
|
|
|
def get_file_system(self, name):
|
|
url = ("https://%s/hspapi/file-systems/list?name=%s" %
|
|
(self.host, name))
|
|
|
|
filesystems = self._send_get(url)
|
|
|
|
try:
|
|
return filesystems['list'][0]
|
|
except (TypeError, KeyError, IndexError):
|
|
msg = _("Filesystem does not exist or is not available.")
|
|
raise exception.HSPItemNotFoundException(msg=msg)
|
|
|
|
def delete_file_system(self, filesystem_id):
|
|
url = "https://%s/hspapi/file-systems/%s" % (self.host, filesystem_id)
|
|
self._send_delete(url)
|
|
|
|
def resize_file_system(self, filesystem_id, new_size):
|
|
url = "https://%s/hspapi/file-systems/%s" % (self.host, filesystem_id)
|
|
payload = {'quota': new_size}
|
|
|
|
self._send_post(url, payload=json.dumps(payload))
|
|
|
|
def rename_file_system(self, filesystem_id, new_name):
|
|
url = "https://%s/hspapi/file-systems/%s" % (self.host, filesystem_id)
|
|
payload = {'name': new_name}
|
|
|
|
self._send_post(url, payload=json.dumps(payload))
|
|
|
|
def add_share(self, name, filesystem_id):
|
|
url = "https://%s/hspapi/shares/" % self.host
|
|
payload = {
|
|
'description': '',
|
|
'type': 'NFS',
|
|
'enabled': True,
|
|
'tags': '',
|
|
'name': name,
|
|
'file-system-id': filesystem_id,
|
|
}
|
|
|
|
self._send_post(url, payload=json.dumps(payload))
|
|
|
|
def get_share(self, fs_id=None, name=None):
|
|
if fs_id is not None:
|
|
url = ('https://%s/hspapi/shares/list?file-system-id=%s' %
|
|
(self.host, fs_id))
|
|
elif name is not None:
|
|
url = ('https://%s/hspapi/shares/list?name=%s' %
|
|
(self.host, name))
|
|
share = self._send_get(url)
|
|
|
|
try:
|
|
return share['list'][0]
|
|
except (TypeError, KeyError, IndexError):
|
|
msg = _("Share %s does not exist or is not available.")
|
|
|
|
if fs_id is not None:
|
|
args = "for filesystem %s" % fs_id
|
|
else:
|
|
args = name
|
|
|
|
raise exception.HSPItemNotFoundException(msg=msg % args)
|
|
|
|
def delete_share(self, share_id):
|
|
url = "https://%s/hspapi/shares/%s" % (self.host, share_id)
|
|
self._send_delete(url)
|
|
|
|
def add_access_rule(self, share_id, host_to, read_write):
|
|
url = "https://%s/hspapi/shares/%s/" % (self.host, share_id)
|
|
payload = {
|
|
"action": "add-access-rule",
|
|
"name": share_id + host_to,
|
|
"host-specification": host_to,
|
|
"read-write": read_write,
|
|
}
|
|
|
|
self._send_post(url, payload=json.dumps(payload))
|
|
|
|
def delete_access_rule(self, share_id, rule_name):
|
|
url = "https://%s/hspapi/shares/%s/" % (self.host, share_id)
|
|
payload = {
|
|
"action": "delete-access-rule",
|
|
"name": rule_name,
|
|
}
|
|
|
|
self._send_post(url, payload=json.dumps(payload))
|
|
|
|
def get_access_rules(self, share_id):
|
|
url = ("https://%s/hspapi/shares/%s/access-rules" %
|
|
(self.host, share_id))
|
|
rules = self._send_get(url)
|
|
|
|
try:
|
|
rules = rules['list']
|
|
except (TypeError, KeyError, IndexError):
|
|
rules = []
|
|
return rules
|
|
|
|
def get_cluster(self):
|
|
url = "https://%s/hspapi/clusters/list" % self.host
|
|
clusters = self._send_get(url)
|
|
|
|
try:
|
|
return clusters['list'][0]
|
|
except (TypeError, KeyError, IndexError):
|
|
msg = _("No cluster was found on HSP.")
|
|
raise exception.HSPBackendException(msg=msg)
|
|
|
|
@utils.retry(retry_param=exception.HSPTimeoutException,
|
|
retries=10,
|
|
wait_random=True)
|
|
def _wait_job_status(self, job_url, target_status):
|
|
resp_json = self._send_get(job_url)
|
|
|
|
status = resp_json['properties']['completion-status']
|
|
|
|
if status == 'ERROR':
|
|
msg = _("HSP job %(id)s failed. %(reason)s")
|
|
job_id = resp_json['id']
|
|
reason = resp_json['properties']['completion-details']
|
|
raise exception.HSPBackendException(msg=msg % {'id': job_id,
|
|
'reason': reason})
|
|
elif status != target_status:
|
|
msg = _("Timeout while waiting for job %s to complete.")
|
|
args = resp_json['id']
|
|
raise exception.HSPTimeoutException(msg=msg % args)
|