--- a/components/openstack/cinder/files/zfssa/zfssarest.py Thu Apr 16 01:36:32 2015 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,614 +0,0 @@
-# Copyright (c) 2014, Oracle and/or its affiliates. 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.
-"""
-ZFS Storage Appliance Proxy
-"""
-import json
-import socket
-
-from cinder import exception
-from cinder.openstack.common import log
-
-from cinder.volume.drivers.zfssa import restclient
-
-LOG = log.getLogger(__name__)
-
-
-#pylint: disable=R0913
-#pylint: disable=R0904
-class ZFSSAApi(object):
- """ZFSSA API proxy class"""
- def __init__(self, host):
- self.host = host
- self.url = "https://" + self.host + ":215"
- self.rclient = restclient.RestClientURL(self.url)
-
- def __del__(self):
- if self.rclient and self.rclient.islogin():
- self.rclient.logout()
-
- def _is_pool_owned(self, pdata):
- """returns True if the pool's owner is the
- same as the host.
- """
- svc = '/api/system/v1/version'
- ret = self.rclient.get(svc)
- if ret.status != restclient.Status.OK:
- exception_msg = (_('Error getting version: '
- 'svc: %(svc)s.'
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s.')
- % {'svc': svc,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- vdata = json.loads(ret.data)
- return vdata['version']['asn'] == pdata['pool']['asn'] and \
- vdata['version']['nodename'] == pdata['pool']['owner']
-
- def login(self, auth_str):
- """Login to the appliance"""
- if self.rclient:
- self.rclient.login(auth_str)
-
- def get_pool_stats(self, pool):
- """Get space_available and used properties of a pool
- returns (avail, used)
- """
- svc = '/api/storage/v1/pools/' + pool
- ret = self.rclient.get(svc)
- if ret.status != restclient.Status.OK:
- exception_msg = (_('Error Getting Pool Stats: '
- 'Pool: %(pool)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s.')
- % {'pool': pool,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.InvalidVolume(reason=exception_msg)
-
- val = json.loads(ret.data)
-
- if not self._is_pool_owned(val):
- exception_msg = (_('Error Pool ownership: '
- 'Pool %(pool)s is not owned '
- 'by %(host)s.')
- % {'pool': pool,
- 'host': self.host})
- LOG.error(exception_msg)
- raise exception.InstanceNotFound(instance_id=pool)
-
- avail = val['pool']['usage']['available']
- used = val['pool']['usage']['used']
-
- return (avail, used)
-
- def create_project(self, pool, project, compression=None, logbias=None):
- """Create a project on a pool
- Check first whether the pool exists.
- """
- self.verify_pool(pool)
- svc = '/api/storage/v1/pools/' + pool + '/projects/' + project
- ret = self.rclient.get(svc)
- if ret.status != restclient.Status.OK:
- svc = '/api/storage/v1/pools/' + pool + '/projects'
- arg = {
- 'name': project
- }
- if compression and compression != '':
- arg.update({'compression': compression})
- if logbias and logbias != '':
- arg.update({'logbias': logbias})
-
- ret = self.rclient.post(svc, arg)
- if ret.status != restclient.Status.CREATED:
- exception_msg = (_('Error Creating Project: '
- '%(project)s on '
- 'Pool: %(pool)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s .')
- % {'project': project,
- 'pool': pool,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- def create_initiator(self, initiator, alias, chapuser=None,
- chapsecret=None):
- """Create an iSCSI initiator"""
-
- svc = '/api/san/v1/iscsi/initiators/alias=' + alias
- ret = self.rclient.get(svc)
- if ret.status != restclient.Status.OK:
- svc = '/api/san/v1/iscsi/initiators'
- arg = {
- 'initiator': initiator,
- 'alias': alias
- }
- if chapuser and chapuser != '' and chapsecret and chapsecret != '':
- arg.update({'chapuser': chapuser,
- 'chapsecret': chapsecret})
-
- ret = self.rclient.post(svc, arg)
- if ret.status != restclient.Status.CREATED:
- exception_msg = (_('Error Creating Initator: '
- '%(initiator)s on '
- 'Alias: %(alias)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s .')
- % {'initiator': initiator,
- 'alias': alias,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- def add_to_initiatorgroup(self, initiator, initiatorgroup):
- """Add an iSCSI initiator to initiatorgroup"""
- svc = '/api/san/v1/iscsi/initiator-groups/' + initiatorgroup
- ret = self.rclient.get(svc)
- if ret.status != restclient.Status.OK:
- svc = '/api/san/v1/iscsi/initiator-groups'
- arg = {
- 'name': initiatorgroup,
- 'initiators': [initiator]
- }
- ret = self.rclient.post(svc, arg)
- if ret.status != restclient.Status.CREATED:
- exception_msg = (_('Error Adding Initator: '
- '%(initiator)s on group'
- 'InitiatorGroup: %(initiatorgroup)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s .')
- % {'initiator': initiator,
- 'initiatorgroup': initiatorgroup,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
- else:
- svc = '/api/san/v1/iscsi/initiator-groups/' + initiatorgroup
- arg = {
- 'initiators': [initiator]
- }
- ret = self.rclient.put(svc, arg)
- if ret.status != restclient.Status.ACCEPTED:
- exception_msg = (_('Error Adding Initator: '
- '%(initiator)s on group'
- 'InitiatorGroup: %(initiatorgroup)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s .')
- % {'initiator': initiator,
- 'initiatorgroup': initiatorgroup,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- def create_target(self, alias, interfaces=None, tchapuser=None,
- tchapsecret=None):
- """Create an iSCSI target
- interfaces: an array with network interfaces
- tchapuser, tchapsecret: target's chapuser and chapsecret
- returns target iqn
- """
- svc = '/api/san/v1/iscsi/targets/alias=' + alias
- ret = self.rclient.get(svc)
- if ret.status != restclient.Status.OK:
- svc = '/api/san/v1/iscsi/targets'
- arg = {
- 'alias': alias
- }
-
- if tchapuser and tchapuser != '' and tchapsecret and \
- tchapsecret != '':
- arg.update({'targetchapuser': tchapuser,
- 'targetchapsecret': tchapsecret,
- 'auth': 'chap'})
-
- if interfaces is not None and len(interfaces) > 0:
- arg.update({'interfaces': interfaces})
-
- ret = self.rclient.post(svc, arg)
- if ret.status != restclient.Status.CREATED:
- exception_msg = (_('Error Creating Target: '
- '%(alias)s'
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s .')
- % {'alias': alias,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- val = json.loads(ret.data)
- return val['target']['iqn']
-
- def get_target(self, alias):
- """Get an iSCSI target iqn"""
- svc = '/api/san/v1/iscsi/targets/alias=' + alias
- ret = self.rclient.get(svc)
- if ret.status != restclient.Status.OK:
- exception_msg = (_('Error Getting Target: '
- '%(alias)s'
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s .')
- % {'alias': alias,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- val = json.loads(ret.data)
- return val['target']['iqn']
-
- def add_to_targetgroup(self, iqn, targetgroup):
- """Add an iSCSI target to targetgroup"""
- svc = '/api/san/v1/iscsi/target-groups/' + targetgroup
- ret = self.rclient.get(svc)
- if ret.status != restclient.Status.OK:
- svccrt = '/api/san/v1/iscsi/target-groups'
- arg = {
- 'name': targetgroup,
- 'targets': [iqn]
- }
-
- ret = self.rclient.post(svccrt, arg)
- if ret.status != restclient.Status.CREATED:
- exception_msg = (_('Error Creating TargetGroup: '
- '%(targetgroup)s with'
- 'IQN: %(iqn)s'
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s .')
- % {'targetgroup': targetgroup,
- 'iqn': iqn,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- return
-
- arg = {
- 'targets': [iqn]
- }
-
- ret = self.rclient.put(svc, arg)
- if ret.status != restclient.Status.ACCEPTED:
- exception_msg = (_('Error Adding to TargetGroup: '
- '%(targetgroup)s with'
- 'IQN: %(iqn)s'
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s.')
- % {'targetgroup': targetgroup,
- 'iqn': iqn,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- def verify_pool(self, pool):
- """Checks whether pool exists"""
- svc = '/api/storage/v1/pools/' + pool
- ret = self.rclient.get(svc)
- if ret.status != restclient.Status.OK:
- exception_msg = (_('Error Verifying Pool: '
- '%(pool)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s.')
- % {'pool': pool,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- def verify_project(self, pool, project):
- """Checks whether project exists"""
- svc = '/api/storage/v1/pools/' + pool + '/projects/' + project
- ret = self.rclient.get(svc)
- if ret.status != restclient.Status.OK:
- exception_msg = (_('Error Verifying '
- 'Project: %(project)s on '
- 'Pool: %(pool)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s.')
- % {'project': project,
- 'pool': pool,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- def verify_initiator(self, iqn):
- """Check whether initiator iqn exists"""
- svc = '/api/san/v1/iscsi/initiators/' + iqn
- ret = self.rclient.get(svc)
- if ret.status != restclient.Status.OK:
- exception_msg = (_('Error Verifying '
- 'Initiator: %(iqn)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s.')
- % {'initiator': iqn,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- def verify_target(self, alias):
- """Check whether target alias exists."""
- svc = '/api/san/v1/iscsi/targets/alias=' + alias
- ret = self.rclient.get(svc)
- if ret.status != restclient.Status.OK:
- exception_msg = (_('Error Verifying '
- 'Target: %(alias)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s.')
- % {'alias': alias,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- def create_lun(self, pool, project, lun, volsize, targetgroup,
- volblocksize='8k', sparse=False, compression=None,
- logbias=None):
- """Create a LUN
- required - pool, project, lun, volsize, targetgroup.
- optional - volblocksize, sparse, compression, logbias
- """
-
- svc = '/api/storage/v1/pools/' + pool + '/projects/' + project + \
- '/luns/' + lun
- ret = self.rclient.get(svc)
- if ret.status != restclient.Status.OK:
- svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
- project + '/luns'
- arg = {
- 'name': lun,
- 'volsize': volsize,
- 'targetgroup': targetgroup,
- 'initiatorgroup': 'com.sun.ms.vss.hg.maskAll',
- 'volblocksize': volblocksize,
- 'sparse': sparse
- }
- if compression and compression != '':
- arg.update({'compression': compression})
- if logbias and logbias != '':
- arg.update({'logbias': logbias})
-
- ret = self.rclient.post(svc, arg)
- if ret.status != restclient.Status.CREATED:
- exception_msg = (_('Error Creating '
- 'Volume: %(lun)s '
- 'Size: %(size)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s.')
- % {'lun': lun,
- 'size': volsize,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- def get_lun(self, pool, project, lun):
- """return iscsi lun properties"""
- svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
- project + "/luns/" + lun
- ret = self.rclient.get(svc)
- if ret.status != restclient.Status.OK:
- exception_msg = (_('Error Getting '
- 'Volume: %(lun)s on '
- 'Pool: %(pool)s '
- 'Project: %(project)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s.')
- % {'lun': lun,
- 'pool': pool,
- 'project': project,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- val = json.loads(ret.data)
- ret = {
- 'guid': val['lun']['lunguid'],
- 'number': val['lun']['assignednumber'],
- 'initiatorgroup': val['lun']['initiatorgroup'],
- 'size': val['lun']['volsize']
- }
- if 'origin' in val['lun']:
- ret.update({'origin': val['lun']['origin']})
-
- return ret
-
- def set_lun_initiatorgroup(self, pool, project, lun, initiatorgroup):
- """Set the initiatorgroup property of a LUN"""
- if initiatorgroup == '':
- initiatorgroup = 'com.sun.ms.vss.hg.maskAll'
-
- svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
- project + '/luns/' + lun
- arg = {
- 'initiatorgroup': initiatorgroup
- }
-
- ret = self.rclient.put(svc, arg)
- if ret.status != restclient.Status.ACCEPTED:
- exception_msg = (_('Error Setting '
- 'Volume: %(lun)s to '
- 'InitiatorGroup: %(initiatorgroup)s '
- 'Pool: %(pool)s '
- 'Project: %(project)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s.')
- % {'lun': lun,
- 'initiatorgroup': initiatorgroup,
- 'pool': pool,
- 'project': project,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
-
- def delete_lun(self, pool, project, lun):
- """delete iscsi lun"""
- svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
- project + '/luns/' + lun
-
- ret = self.rclient.delete(svc)
- if ret.status != restclient.Status.NO_CONTENT:
- exception_msg = (_('Error Deleting '
- 'Volume: %(lun)s to '
- 'Pool: %(pool)s '
- 'Project: %(project)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s.')
- % {'lun': lun,
- 'pool': pool,
- 'project': project,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
-
- def create_snapshot(self, pool, project, lun, snapshot):
- """create snapshot"""
- svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
- project + '/luns/' + lun + '/snapshots'
- arg = {
- 'name': snapshot
- }
-
- ret = self.rclient.post(svc, arg)
- if ret.status != restclient.Status.CREATED:
- exception_msg = (_('Error Creating '
- 'Snapshot: %(snapshot)s on'
- 'Volume: %(lun)s to '
- 'Pool: %(pool)s '
- 'Project: %(project)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s.')
- % {'snapshot': snapshot,
- 'lun': lun,
- 'pool': pool,
- 'project': project,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- def delete_snapshot(self, pool, project, lun, snapshot):
- """delete snapshot"""
- svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
- project + '/luns/' + lun + '/snapshots/' + snapshot
-
- ret = self.rclient.delete(svc)
- if ret.status != restclient.Status.NO_CONTENT:
- exception_msg = (_('Error Deleting '
- 'Snapshot: %(snapshot)s on '
- 'Volume: %(lun)s to '
- 'Pool: %(pool)s '
- 'Project: %(project)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s.')
- % {'snapshot': snapshot,
- 'lun': lun,
- 'pool': pool,
- 'project': project,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- def clone_snapshot(self, pool, project, lun, snapshot, clone):
- """clone snapshot"""
- svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
- project + '/luns/' + lun + '/snapshots/' + snapshot + '/clone'
- arg = {
- 'project': project,
- 'share': clone
- }
-
- ret = self.rclient.put(svc, arg)
- if ret.status != restclient.Status.CREATED:
- exception_msg = (_('Error Cloning '
- 'Snapshot: %(snapshot)s on '
- 'Volume: %(lun)s of '
- 'Pool: %(pool)s '
- 'Project: %(project)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s.')
- % {'snapshot': snapshot,
- 'lun': lun,
- 'pool': pool,
- 'project': project,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- def set_lun_size(self, pool, project, lun, size):
- """increase lun size capacity"""
- svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
- project + '/luns/' + lun
- arg = {
- 'volsize': size
- }
-
- ret = self.rclient.put(svc, arg)
- if ret.status != restclient.Status.ACCEPTED:
- exception_msg = (_('Error Setting size on '
- 'Size: %(size)s on '
- 'Volume: %(lun)s of '
- 'Pool: %(pool)s '
- 'Project: %(project)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s.')
- % {'size': size,
- 'lun': lun,
- 'pool': pool,
- 'project': project,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- def has_clones(self, pool, project, lun, snapshot):
- """Checks whether snapshot has clones or not."""
- svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
- project + '/luns/' + lun + '/snapshots/' + snapshot
-
- ret = self.rclient.get(svc)
- if ret.status != restclient.Status.OK:
- exception_msg = (_('Error Getting '
- 'Snapshot: %(snapshot)s on '
- 'Volume: %(lun)s to '
- 'Pool: %(pool)s '
- 'Project: %(project)s '
- 'Return code: %(ret.status)d '
- 'Message: %(ret.data)s.')
- % {'snapshot': snapshot,
- 'lun': lun,
- 'pool': pool,
- 'project': project,
- 'ret.status': ret.status,
- 'ret.data': ret.data})
- LOG.error(exception_msg)
- raise exception.VolumeBackendAPIException(data=exception_msg)
-
- val = json.loads(ret.data)
- return (val['snapshot']['numclones'] != 0)