cinder/cinder/volume/drivers/veritas_access/veritas_iscsi.py

901 lines
33 KiB
Python

# Copyright 2017 Veritas Technologies LLC.
#
# 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.
"""
Veritas Access Driver for ISCSI.
"""
import ast
import json
from random import randint
from xml.dom import minidom
from oslo_config import cfg
from oslo_log import log as logging
from oslo_service import loopingcall
from oslo_utils import netutils
from oslo_utils.secretutils import md5
from oslo_utils import strutils
from oslo_utils import units
import requests
import requests.auth
from six.moves import http_client
from cinder import exception
from cinder.i18n import _
from cinder import interface
from cinder.volume import driver
from cinder.volume.drivers.san import san
LOG = logging.getLogger(__name__)
VA_VOL_OPTS = [
cfg.BoolOpt('vrts_lun_sparse',
default=True,
help='Create sparse Lun.'),
cfg.StrOpt('vrts_target_config',
default='/etc/cinder/vrts_target.xml',
help='VA config file.')
]
CONF = cfg.CONF
CONF.register_opts(VA_VOL_OPTS)
class NoAuth(requests.auth.AuthBase):
"""This is a 'authentication' handler.
It exists for use with custom authentication systems, such as the
one for the Access API, it simply passes the Authorization header as-is.
The default authentication handler for requests will clobber the
Authorization header.
"""
def __call__(self, r):
return r
@interface.volumedriver
class ACCESSIscsiDriver(driver.ISCSIDriver):
"""ACCESS Share Driver.
Executes commands relating to ACCESS ISCSI.
Supports creation of volumes on ACCESS.
.. code-block:: none
API version history:
1.0 - Initial version.
"""
VERSION = "1.0"
# ThirdPartySytems wiki page
CI_WIKI_NAME = "Veritas_Access_CI"
DRIVER_VOLUME_TYPE = 'iSCSI'
LUN_FOUND_INTERVAL = 30 # seconds
# TODO(jsbryant) Remove driver in the 'U' release if CI is not fixed.
SUPPORTED = False
def __init__(self, *args, **kwargs):
# Parent sets db, host, _execute and base config
super(ACCESSIscsiDriver, self).__init__(*args, **kwargs)
self._va_ip = None
self._port = None
self._user = None
self._pwd = None
self.iscsi_port = None
self._fs_list_str = '/fs'
self._target_list_str = '/iscsi/target/list'
self._target_status = '/iscsi/target/status'
self._lun_create_str = '/iscsi/lun/create'
self._lun_destroy_str = '/iscsi/lun/destroy'
self._lun_list_str = '/iscsi/lun/list'
self._lun_create_from_snap_str = '/iscsi/lun_from_snap/create'
self._snapshot_create_str = '/iscsi/lun/snapshot/create'
self._snapshot_destroy_str = '/iscsi/lun/snapshot/destroy'
self._snapshot_list_str = '/iscsi/lun/snapshot/list'
self._lun_clone_create_str = '/iscsi/lun/clone/create'
self._lun_extend_str = '/iscsi/lun/growto'
self._lun_shrink_str = '/iscsi/lun/shrinkto'
self._lun_getid_str = '/iscsi/lun/getlunid'
self._target_map_str = '/iscsi/target/map/add'
self._target_list_status = '/iscsi/target/full_list'
self.configuration.append_config_values(VA_VOL_OPTS)
self.configuration.append_config_values(san.san_opts)
self.backend_name = (self.configuration.safe_get('volume_'
'backend_name') or
'ACCESS_ISCSI')
self.verify = (self.configuration.
safe_get('driver_ssl_cert_verify') or False)
if self.verify:
verify_path = (self.configuration.
safe_get('driver_ssl_cert_path') or None)
if verify_path:
self.verify = verify_path
@staticmethod
def get_driver_options():
return VA_VOL_OPTS
def do_setup(self, context):
"""Any initialization the volume driver does while starting."""
super(ACCESSIscsiDriver, self).do_setup(context)
required_config = ['san_ip',
'san_login',
'san_password',
'san_api_port']
for attr in required_config:
if not getattr(self.configuration, attr, None):
message = (_('config option %s is not set.') % attr)
raise exception.InvalidInput(message=message)
self._va_ip = self.configuration.san_ip
self._user = self.configuration.san_login
self._pwd = self.configuration.san_password
self._port = self.configuration.san_api_port
self._sparse_lun_support = self.configuration.vrts_lun_sparse
self.target_info_file = self.configuration.vrts_target_config
self.iscsi_port = self.configuration.target_port
self.session = self._authenticate_access(self._va_ip, self._user,
self._pwd)
def _get_va_lun_name(self, name):
length = len(name)
index = int(length / 2)
name1 = name[:index]
name2 = name[index:]
crc1 = md5(name1.encode('utf-8'),
usedforsecurity=False).hexdigest()[:5]
crc2 = md5(name2.encode('utf-8'),
usedforsecurity=False).hexdigest()[:5]
return 'cinder' + '-' + crc1 + '-' + crc2
def check_for_setup_error(self):
"""Check if veritas access target is online."""
target_list = self._vrts_parse_xml_file(self.target_info_file)
if not self._vrts_get_online_targets(target_list):
message = ('ACCESSIscsiDriver setup error as '
'no target is online')
raise exception.VolumeBackendAPIException(message=message)
def create_export(self, context, volume, connector):
"""Driver entry point to get the export info for a new volume."""
pass
def remove_export(self, context, volume):
"""Driver entry point to remove an export for a volume."""
pass
def ensure_export(self, context, volume):
"""Driver entry point to get the export info for an existing volume."""
pass
def _vrts_get_iscsi_properties(self, volume, target_name):
"""Get target and LUN details."""
lun_name = self._get_va_lun_name(volume.id)
data = {}
path = self._lun_getid_str
provider = '%s:%s' % (self._va_ip, self._port)
lun_id_list = self._access_api(self.session, provider, path,
json.dumps(data), 'GET')
if not lun_id_list:
message = _('ACCESSIscsiDriver get LUN ID list '
'operation failed')
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
for lun in ast.literal_eval(lun_id_list['output']):
vrts_lun_name = lun['storage_object'].split('/')[3]
if vrts_lun_name == lun_name:
lun_id = int(lun['index'])
target_list = self._vrts_parse_xml_file(self.target_info_file)
authentication = False
portal_ip = ""
for target in target_list:
if target_name == target['name']:
portal_ip = target['portal_ip']
if target['auth'] == '1':
auth_user = target['auth_user']
auth_password = target['auth_password']
authentication = True
break
if portal_ip == "":
message = (_('ACCESSIscsiDriver initialize_connection '
'failed for %s as no portal ip was found')
% volume.id)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
portal_list = portal_ip.split(',')
target_portal_list = []
for ip in portal_list:
if netutils.is_valid_ipv6(ip):
target_portal_list.append('[%s]:%s' % (ip,
str(self.iscsi_port)))
else:
target_portal_list.append('%s:%s' % (ip, str(self.iscsi_port)))
iscsi_properties = {}
iscsi_properties['target_discovered'] = True
iscsi_properties['target_iqn'] = target_name
iscsi_properties['target_portal'] = target_portal_list[0]
if len(target_portal_list) > 1:
iscsi_properties['target_portals'] = target_portal_list
iscsi_properties['target_lun'] = lun_id
iscsi_properties['volume_id'] = volume.id
if authentication:
iscsi_properties['auth_username'] = auth_user
iscsi_properties['auth_password'] = auth_password
iscsi_properties['auth_method'] = 'CHAP'
return iscsi_properties
def _get_vrts_lun_list(self):
"""Get Lun list."""
data = {}
path = self._lun_list_str
provider = '%s:%s' % (self._va_ip, self._port)
lun_list = self._access_api(self.session, provider, path,
json.dumps(data), 'GET')
if not lun_list:
message = _('ACCESSIscsiDriver get LUN list '
'operation failed')
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
return lun_list
def _vrts_target_initiator_mapping(self, target_name, initiator_name):
"""Map target to initiator."""
path = self._target_map_str
provider = '%s:%s' % (self._va_ip, self._port)
data = {}
data["target_name"] = target_name
data["initiator_name"] = initiator_name
result = self._access_api(self.session, provider, path,
json.dumps(data), 'POST')
if not result:
message = (_('ACCESSIscsiDriver target-initiator mapping '
'failed for target %s')
% target_name)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
def initialize_connection(self, volume, connector, initiator_data=None):
"""Initializes the connection and returns connection info.
The iscsi driver returns a driver_volume_type of 'iscsi'.
the format of the driver data is defined in _vrts_get_iscsi_properties.
Example return value::
{
'driver_volume_type': 'iscsi'
'data': {
'target_discovered': True,
'target_iqn': 'iqn.2010-10.org.openstack:volume-00000001',
'target_portal': '127.0.0.0.1:3260',
'target_lun': 1,
'volume_id': '12345678-1234-4321-1234-123456789012',
}
}
"""
lun_name = self._get_va_lun_name(volume.id)
target = {'target_name': ''}
def _inner():
lun_list = self._get_vrts_lun_list()
for lun in lun_list['output']['output']['luns']:
if lun['lun_name'] == lun_name:
target['target_name'] = lun['target_name']
raise loopingcall.LoopingCallDone()
timer = loopingcall.FixedIntervalWithTimeoutLoopingCall(_inner)
try:
timer.start(interval=5, timeout=self.LUN_FOUND_INTERVAL).wait()
except loopingcall.LoopingCallTimeOut:
message = (_('ACCESSIscsiDriver initialize_connection '
'failed for %s as no target was found')
% volume.id)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
self._vrts_target_initiator_mapping(target['target_name'],
connector['initiator'])
iscsi_properties = self._vrts_get_iscsi_properties(
volume, target['target_name'])
return {
'driver_volume_type': 'iscsi',
'data': iscsi_properties
}
def terminate_connection(self, volume, connector, **kwargs):
"""Disallow connection from connector."""
pass
def _vrts_parse_xml_file(self, filename):
"""VRTS target info.
<VRTS>
<VrtsTargets>
<Target>
<Name>iqn.2017-02.com.veritas:target03</Name>
<PortalIP>10.182.174.188</PortalIP>
</Target>
<Target>
<Name>iqn.2017-02.com.veritas:target04</Name>
<PortalIP>10.182.174.189</PortalIP>
</Target>
</VrtsTargets>
</VRST>
:param filename: the configuration file
:returns: list
"""
myfile = open(filename, 'r')
data = myfile.read()
myfile.close()
dom = minidom.parseString(data)
mylist = []
target = {}
try:
for trg in dom.getElementsByTagName('Target'):
target['name'] = (trg.getElementsByTagName('Name')[0]
.childNodes[0].nodeValue)
target['portal_ip'] = (trg.getElementsByTagName('PortalIP')[0]
.childNodes[0].nodeValue)
target['auth'] = (trg.getElementsByTagName('Authentication')[0]
.childNodes[0].nodeValue)
if target['auth'] == '1':
target['auth_user'] = (trg.getElementsByTagName
('Auth_username')[0]
.childNodes[0].nodeValue)
target['auth_password'] = (trg.getElementsByTagName
('Auth_password')[0]
.childNodes[0].nodeValue)
mylist.append(target)
target = {}
except IndexError:
pass
return mylist
def _vrts_get_fs_list(self):
"""Get FS list."""
path = self._fs_list_str
provider = '%s:%s' % (self._va_ip, self._port)
data = {}
fs_list = self._access_api(self.session, provider, path,
json.dumps(data), 'GET')
if not fs_list:
message = _('ACCESSIscsiDriver get FS list '
'operation failed')
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
return fs_list
def _vrts_get_online_targets(self, available_targets):
"""Out of available targets get list of targets which are online."""
online_targets = []
path = self._target_list_status
provider = '%s:%s' % (self._va_ip, self._port)
data = {}
target_status_list = self._access_api(self.session, provider, path,
json.dumps(data), 'GET')
try:
target_status_output = (ast.
literal_eval(target_status_list['output']))
except KeyError:
message = _('ACCESSIscsiDriver get online target list '
'operation failed')
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
for target in available_targets:
if target['name'] in target_status_output.keys():
if target_status_output[target['name']] == 'ONLINE':
online_targets.append(target)
return online_targets
def _vrts_get_targets_store(self):
"""Get target and its store list."""
path = self._target_list_str
provider = '%s:%s' % (self._va_ip, self._port)
data = {}
target_list = self._access_api(self.session, provider, path,
json.dumps(data), 'GET')
if not target_list:
message = _('ACCESSIscsiDriver get target list '
'operation failed')
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
return target_list['output']['output']['targets']
def _vrts_get_assigned_store(self, target, vrts_target_list):
"""Get the store mapped to given target."""
for vrts_target in vrts_target_list:
if vrts_target['wwn'] == target:
return vrts_target['fs_list'][0]
def _vrts_is_space_available_in_store(self, vol_size, store_name, fs_list):
"""Check whether space is available on store."""
if self._sparse_lun_support:
return True
for fs in fs_list:
if fs['name'] == store_name:
fs_avilable_space = (int(fs['file_storage_capacity']) -
int(fs['file_storage_used']))
free_space = fs_avilable_space / units.Gi
if free_space > vol_size:
return True
break
return False
def _vrts_get_suitable_target(self, target_list, vol_size):
"""Get a suitable target for lun creation.
Picking random target at first, if space is not available
in first selected target then check each target one by one
for suitable one.
"""
target_count = len(target_list)
incrmnt_pointer = 0
target_index = randint(0, (target_count - 1))
fs_list = self._vrts_get_fs_list()
vrts_target_list = self._vrts_get_targets_store()
store_name = self._vrts_get_assigned_store(
target_list[target_index]['name'],
vrts_target_list
)
if not self._vrts_is_space_available_in_store(
vol_size, store_name, fs_list):
while (incrmnt_pointer != target_count - 1):
target_index = (target_index + 1) % target_count
store_name = self._vrts_get_assigned_store(
target_list[target_index]['name'],
vrts_target_list
)
if self._vrts_is_space_available_in_store(
vol_size, store_name, fs_list):
return target_list[target_index]['name']
incrmnt_pointer = incrmnt_pointer + 1
else:
return target_list[target_index]['name']
return False
def create_volume(self, volume):
"""Creates a Veritas Access Iscsi LUN."""
create_dense = False
if 'dense' in volume.metadata.keys():
create_dense = strutils.bool_from_string(
volume.metadata['dense'])
lun_name = self._get_va_lun_name(volume.id)
lun_size = '%sg' % volume.size
path = self._lun_create_str
provider = '%s:%s' % (self._va_ip, self._port)
target_list = self._vrts_parse_xml_file(self.target_info_file)
target_name = self._vrts_get_suitable_target(target_list, volume.size)
if not target_name:
message = (_('ACCESSIscsiDriver create volume failed %s '
'as no space is available') % volume.id)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
data = {}
data["lun_name"] = lun_name
data["target_name"] = target_name
data["size"] = lun_size
if not self._sparse_lun_support or create_dense:
data["option"] = "option=dense"
result = self._access_api(self.session, provider, path,
json.dumps(data), 'POST')
if not result:
message = (_('ACCESSIscsiDriver create volume failed %s')
% volume.id)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
def delete_volume(self, volume):
"""Deletes a Veritas Access Iscsi LUN."""
lun_name = self._get_va_lun_name(volume.id)
lun_list = self._get_vrts_lun_list()
target_name = ""
for lun in lun_list['output']['output']['luns']:
if lun['lun_name'] == lun_name:
target_name = lun['target_name']
path = self._lun_destroy_str
provider = '%s:%s' % (self._va_ip, self._port)
data = {}
data["lun_name"] = lun_name
data["target_name"] = target_name
result = self._access_api(self.session, provider, path,
json.dumps(data), 'POST')
if not result:
message = (_('ACCESSIscsiDriver delete volume failed %s')
% volume.id)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
def create_snapshot(self, snapshot):
"""Creates a snapshot of LUN."""
lun_name = self._get_va_lun_name(snapshot.volume_id)
snap_name = self._get_va_lun_name(snapshot.id)
path = self._snapshot_create_str
provider = '%s:%s' % (self._va_ip, self._port)
data = {}
data["lun_name"] = lun_name
data["snap_name"] = snap_name
result = self._access_api(self.session, provider, path,
json.dumps(data), 'POST')
if not result:
message = (_('ACCESSIscsiDriver create snapshot failed for %s')
% snapshot.volume_id)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
def delete_snapshot(self, snapshot):
"""Deletes a snapshot of LUN."""
lun_name = self._get_va_lun_name(snapshot.volume_id)
snap_name = self._get_va_lun_name(snapshot.id)
path = self._snapshot_destroy_str
provider = '%s:%s' % (self._va_ip, self._port)
data = {}
data["lun_name"] = lun_name
data["snap_name"] = snap_name
result = self._access_api(self.session, provider, path,
json.dumps(data), 'POST')
if not result:
message = (_('ACCESSIscsiDriver delete snapshot failed for %s')
% snapshot.id)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
def create_cloned_volume(self, volume, src_vref):
"""Create a clone of the volume."""
lun_name = self._get_va_lun_name(src_vref.id)
cloned_lun_name = self._get_va_lun_name(volume.id)
lun_found = False
lun_list = self._get_vrts_lun_list()
for lun in lun_list['output']['output']['luns']:
if lun['lun_name'] == lun_name:
store_name = lun['fs_name']
lun_found = True
break
if not lun_found:
message = (_('ACCESSIscsiDriver create cloned volume '
'failed %s as no source volume found') % volume.id)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
fs_list = self._vrts_get_fs_list()
if not self._vrts_is_space_available_in_store(volume.size, store_name,
fs_list):
message = (_('ACCESSIscsiDriver create cloned volume '
'failed %s as no space is available') % volume.id)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
path = self._lun_clone_create_str
provider = '%s:%s' % (self._va_ip, self._port)
data = {}
data["lun_name"] = lun_name
data["clone_name"] = cloned_lun_name
result = self._access_api(self.session, provider, path,
json.dumps(data), 'POST')
if not result:
message = (_('ACCESSIscsiDriver create cloned '
'volume failed for %s')
% src_vref.id)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
if volume.size > src_vref.size:
self._vrts_extend_lun(volume, volume.size)
def create_volume_from_snapshot(self, volume, snapshot):
"""Creates a volume from snapshot."""
LOG.debug('ACCESSIscsiDriver create_volume_from_snapshot called')
lun_name = self._get_va_lun_name(volume.id)
snap_name = self._get_va_lun_name(snapshot.id)
path = self._snapshot_list_str
provider = '%s:%s' % (self._va_ip, self._port)
data = {}
data["snap_name"] = snap_name
snap_info = self._access_api(self.session, provider, path,
json.dumps(data), 'GET')
target_name = ""
if snap_info:
for snap in snap_info['output']['output']['snapshots']:
if snap['snapshot_name'] == snap_name:
target_name = snap['target_name']
break
if target_name == "":
message = (_('ACCESSIscsiDriver create volume from snapshot '
'failed for volume %s as failed to gather '
'snapshot details')
% volume.id)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
vrts_target_list = self._vrts_get_targets_store()
store_name = self._vrts_get_assigned_store(
target_name, vrts_target_list)
fs_list = self._vrts_get_fs_list()
if not self._vrts_is_space_available_in_store(volume.size, store_name,
fs_list):
message = (_('ACCESSIscsiDriver create volume from snapshot '
'failed %s as no space is available') % volume.id)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
path = self._lun_create_from_snap_str
provider = '%s:%s' % (self._va_ip, self._port)
data = {}
data["lun_name"] = lun_name
data["snap_name"] = snap_name
result = self._access_api(self.session, provider, path,
json.dumps(data), 'POST')
if not result:
message = (_('ACCESSIscsiDriver create volume from snapshot '
'failed for volume %s')
% volume.id)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
if volume.size > snapshot.volume_size:
self._vrts_extend_lun(volume, volume.size)
def _vrts_extend_lun(self, volume, size):
"""Extend vrts LUN to given size."""
lun_name = self._get_va_lun_name(volume.id)
target = {'target_name': ''}
def _inner():
lun_list = self._get_vrts_lun_list()
for lun in lun_list['output']['output']['luns']:
if lun['lun_name'] == lun_name:
target['target_name'] = lun['target_name']
raise loopingcall.LoopingCallDone()
timer = loopingcall.FixedIntervalWithTimeoutLoopingCall(_inner)
try:
timer.start(interval=5, timeout=self.LUN_FOUND_INTERVAL).wait()
except loopingcall.LoopingCallTimeOut:
return False
lun_size = '%sg' % size
path = self._lun_extend_str
provider = '%s:%s' % (self._va_ip, self._port)
data = {}
data["lun_name"] = lun_name
data["target_name"] = target['target_name']
data["size"] = lun_size
result = self._access_api(self.session, provider, path,
json.dumps(data), 'POST')
return result
def extend_volume(self, volume, size):
"""Extend the volume to new size"""
lun_name = self._get_va_lun_name(volume.id)
lun_found = False
lun_list = self._get_vrts_lun_list()
for lun in lun_list['output']['output']['luns']:
if lun['lun_name'] == lun_name:
store_name = lun['fs_name']
lun_found = True
break
if not lun_found:
message = (_('ACCESSIscsiDriver extend volume '
'failed %s as no volume found at backend')
% volume.id)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
fs_list = self._vrts_get_fs_list()
if not self._vrts_is_space_available_in_store(size, store_name,
fs_list):
message = (_('ACCESSIscsiDriver extend volume '
'failed %s as no space is available') % volume.id)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
result = self._vrts_extend_lun(volume, size)
if not result:
message = (_('ACCESSIscsiDriver extend '
'volume failed for %s')
% volume.id)
LOG.error(message)
raise exception.VolumeBackendAPIException(message=message)
def _get_api(self, provider, tail):
api_root = 'https://%s/api/access' % (provider)
if tail == self._fs_list_str:
api_root = 'https://%s/api' % (provider)
return api_root + tail
def _access_api(self, session, provider, path, input_data, method):
"""Returns False if failure occurs."""
kwargs = {'data': input_data}
if not isinstance(input_data, dict):
kwargs['headers'] = {'Content-Type': 'application/json'}
full_url = self._get_api(provider, path)
response = session.request(method, full_url, **kwargs)
if response.status_code == 401:
LOG.debug('Generating new session.')
self.session = self._authenticate_access(self._va_ip,
self._user, self._pwd)
response = self.session.request(method, full_url, **kwargs)
if response.status_code != http_client.OK:
LOG.error('Access API operation failed with HTTP error code %s.',
str(response.status_code))
return False
result = response.json()
return result
def _authenticate_access(self, address, username, password):
session = requests.session()
session.verify = self.verify
session.auth = NoAuth()
# Here 'address' will be only IPv4.
response = session.post('https://%s:%s/api/rest/authenticate'
% (address, self._port),
data={'username': username,
'password': password})
if response.status_code != http_client.OK:
LOG.error('Failed to authenticate to remote cluster at %s as %s.',
address, username)
raise exception.NotAuthorized(_('Authentication failure.'))
result = response.json()
session.headers.update({'Authorization': 'Bearer {}'
.format(result['token'])})
session.headers.update({'Content-Type': 'application/json'})
return session
def _get_va_backend_capacity(self):
"""Get VA backend total and free capacity."""
target_list = self._vrts_parse_xml_file(self.target_info_file)
fs_list = self._vrts_get_fs_list()
vrts_target_list = self._vrts_get_targets_store()
total_space = 0
free_space = 0
target_name = []
target_store = []
for target in target_list:
target_name.append(target['name'])
for target in vrts_target_list:
if target['wwn'] in target_name:
target_store.append(target['fs_list'][0])
for store in target_store:
for fs in fs_list:
if fs['name'] == store:
total_space = total_space + fs['file_storage_capacity']
fs_free_space = (fs['file_storage_capacity'] -
fs['file_storage_used'])
if fs_free_space > free_space:
free_space = fs_free_space
total_capacity = int(total_space) / units.Gi
free_capacity = int(free_space) / units.Gi
return (total_capacity, free_capacity)
def get_volume_stats(self, refresh=False):
"""Retrieve status info from share volume group."""
total_capacity, free_capacity = self._get_va_backend_capacity()
backend_name = self.configuration.safe_get('volume_backend_name')
res_percentage = self.configuration.safe_get('reserved_percentage')
self._stats["volume_backend_name"] = backend_name or 'VeritasISCSI'
self._stats["vendor_name"] = 'Veritas'
self._stats["reserved_percentage"] = res_percentage or 0
self._stats["driver_version"] = self.VERSION
self._stats["storage_protocol"] = self.DRIVER_VOLUME_TYPE
self._stats['total_capacity_gb'] = total_capacity
self._stats['free_capacity_gb'] = free_capacity
self._stats['thin_provisioning_support'] = True
return self._stats