components/openstack/cinder/files/zfssa/zfssarest.py
changeset 3998 5bd484384122
parent 3997 0ca3f3d6c919
child 4002 95b8f35fcdd5
equal deleted inserted replaced
3997:0ca3f3d6c919 3998:5bd484384122
     1 # Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
       
     2 #
       
     3 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
       
     4 #    not use this file except in compliance with the License. You may obtain
       
     5 #    a copy of the License at
       
     6 #
       
     7 #         http://www.apache.org/licenses/LICENSE-2.0
       
     8 #
       
     9 #    Unless required by applicable law or agreed to in writing, software
       
    10 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
       
    11 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
       
    12 #    License for the specific language governing permissions and limitations
       
    13 #    under the License.
       
    14 """
       
    15 ZFS Storage Appliance Proxy
       
    16 """
       
    17 import json
       
    18 import socket
       
    19 
       
    20 from cinder import exception
       
    21 from cinder.openstack.common import log
       
    22 
       
    23 from cinder.volume.drivers.zfssa import restclient
       
    24 
       
    25 LOG = log.getLogger(__name__)
       
    26 
       
    27 
       
    28 #pylint: disable=R0913
       
    29 #pylint: disable=R0904
       
    30 class ZFSSAApi(object):
       
    31     """ZFSSA API proxy class"""
       
    32     def __init__(self, host):
       
    33         self.host = host
       
    34         self.url = "https://" + self.host + ":215"
       
    35         self.rclient = restclient.RestClientURL(self.url)
       
    36 
       
    37     def __del__(self):
       
    38         if self.rclient and self.rclient.islogin():
       
    39             self.rclient.logout()
       
    40 
       
    41     def _is_pool_owned(self, pdata):
       
    42         """returns True if the pool's owner is the
       
    43            same as the host.
       
    44         """
       
    45         svc = '/api/system/v1/version'
       
    46         ret = self.rclient.get(svc)
       
    47         if ret.status != restclient.Status.OK:
       
    48             exception_msg = (_('Error getting version: '
       
    49                                'svc: %(svc)s.'
       
    50                                'Return code: %(ret.status)d '
       
    51                                'Message: %(ret.data)s.')
       
    52                              % {'svc': svc,
       
    53                                 'ret.status': ret.status,
       
    54                                 'ret.data': ret.data})
       
    55             LOG.error(exception_msg)
       
    56             raise exception.VolumeBackendAPIException(data=exception_msg)
       
    57 
       
    58         vdata = json.loads(ret.data)
       
    59         return vdata['version']['asn'] == pdata['pool']['asn'] and \
       
    60             vdata['version']['nodename'] == pdata['pool']['owner']
       
    61 
       
    62     def login(self, auth_str):
       
    63         """Login to the appliance"""
       
    64         if self.rclient:
       
    65             self.rclient.login(auth_str)
       
    66 
       
    67     def get_pool_stats(self, pool):
       
    68         """Get space_available and used properties of a pool
       
    69            returns (avail, used)
       
    70         """
       
    71         svc = '/api/storage/v1/pools/' + pool
       
    72         ret = self.rclient.get(svc)
       
    73         if ret.status != restclient.Status.OK:
       
    74             exception_msg = (_('Error Getting Pool Stats: '
       
    75                                'Pool: %(pool)s '
       
    76                                'Return code: %(ret.status)d '
       
    77                                'Message: %(ret.data)s.')
       
    78                              % {'pool': pool,
       
    79                                 'ret.status': ret.status,
       
    80                                 'ret.data': ret.data})
       
    81             LOG.error(exception_msg)
       
    82             raise exception.InvalidVolume(reason=exception_msg)
       
    83 
       
    84         val = json.loads(ret.data)
       
    85 
       
    86         if not self._is_pool_owned(val):
       
    87             exception_msg = (_('Error Pool ownership: '
       
    88                                'Pool %(pool)s is not owned '
       
    89                                'by %(host)s.')
       
    90                              % {'pool': pool,
       
    91                                 'host': self.host})
       
    92             LOG.error(exception_msg)
       
    93             raise exception.InstanceNotFound(instance_id=pool)
       
    94 
       
    95         avail = val['pool']['usage']['available']
       
    96         used = val['pool']['usage']['used']
       
    97 
       
    98         return (avail, used)
       
    99 
       
   100     def create_project(self, pool, project, compression=None, logbias=None):
       
   101         """Create a project on a pool
       
   102            Check first whether the pool exists.
       
   103         """
       
   104         self.verify_pool(pool)
       
   105         svc = '/api/storage/v1/pools/' + pool + '/projects/' + project
       
   106         ret = self.rclient.get(svc)
       
   107         if ret.status != restclient.Status.OK:
       
   108             svc = '/api/storage/v1/pools/' + pool + '/projects'
       
   109             arg = {
       
   110                 'name': project
       
   111             }
       
   112             if compression and compression != '':
       
   113                 arg.update({'compression': compression})
       
   114             if logbias and logbias != '':
       
   115                 arg.update({'logbias': logbias})
       
   116 
       
   117             ret = self.rclient.post(svc, arg)
       
   118             if ret.status != restclient.Status.CREATED:
       
   119                 exception_msg = (_('Error Creating Project: '
       
   120                                    '%(project)s on '
       
   121                                    'Pool: %(pool)s '
       
   122                                    'Return code: %(ret.status)d '
       
   123                                    'Message: %(ret.data)s .')
       
   124                                  % {'project': project,
       
   125                                     'pool': pool,
       
   126                                     'ret.status': ret.status,
       
   127                                     'ret.data': ret.data})
       
   128                 LOG.error(exception_msg)
       
   129                 raise exception.VolumeBackendAPIException(data=exception_msg)
       
   130 
       
   131     def create_initiator(self, initiator, alias, chapuser=None,
       
   132                          chapsecret=None):
       
   133         """Create an iSCSI initiator"""
       
   134 
       
   135         svc = '/api/san/v1/iscsi/initiators/alias=' + alias
       
   136         ret = self.rclient.get(svc)
       
   137         if ret.status != restclient.Status.OK:
       
   138             svc = '/api/san/v1/iscsi/initiators'
       
   139             arg = {
       
   140                 'initiator': initiator,
       
   141                 'alias': alias
       
   142             }
       
   143             if chapuser and chapuser != '' and chapsecret and chapsecret != '':
       
   144                 arg.update({'chapuser': chapuser,
       
   145                             'chapsecret': chapsecret})
       
   146 
       
   147             ret = self.rclient.post(svc, arg)
       
   148             if ret.status != restclient.Status.CREATED:
       
   149                 exception_msg = (_('Error Creating Initator: '
       
   150                                    '%(initiator)s on '
       
   151                                    'Alias: %(alias)s '
       
   152                                    'Return code: %(ret.status)d '
       
   153                                    'Message: %(ret.data)s .')
       
   154                                  % {'initiator': initiator,
       
   155                                     'alias': alias,
       
   156                                     'ret.status': ret.status,
       
   157                                     'ret.data': ret.data})
       
   158                 LOG.error(exception_msg)
       
   159                 raise exception.VolumeBackendAPIException(data=exception_msg)
       
   160 
       
   161     def add_to_initiatorgroup(self, initiator, initiatorgroup):
       
   162         """Add an iSCSI initiator to initiatorgroup"""
       
   163         svc = '/api/san/v1/iscsi/initiator-groups/' + initiatorgroup
       
   164         ret = self.rclient.get(svc)
       
   165         if ret.status != restclient.Status.OK:
       
   166             svc = '/api/san/v1/iscsi/initiator-groups'
       
   167             arg = {
       
   168                 'name': initiatorgroup,
       
   169                 'initiators': [initiator]
       
   170             }
       
   171             ret = self.rclient.post(svc, arg)
       
   172             if ret.status != restclient.Status.CREATED:
       
   173                 exception_msg = (_('Error Adding Initator: '
       
   174                                    '%(initiator)s on group'
       
   175                                    'InitiatorGroup: %(initiatorgroup)s '
       
   176                                    'Return code: %(ret.status)d '
       
   177                                    'Message: %(ret.data)s .')
       
   178                                  % {'initiator': initiator,
       
   179                                     'initiatorgroup': initiatorgroup,
       
   180                                     'ret.status': ret.status,
       
   181                                     'ret.data': ret.data})
       
   182                 LOG.error(exception_msg)
       
   183                 raise exception.VolumeBackendAPIException(data=exception_msg)
       
   184         else:
       
   185             svc = '/api/san/v1/iscsi/initiator-groups/' + initiatorgroup
       
   186             arg = {
       
   187                 'initiators': [initiator]
       
   188             }
       
   189             ret = self.rclient.put(svc, arg)
       
   190             if ret.status != restclient.Status.ACCEPTED:
       
   191                 exception_msg = (_('Error Adding Initator: '
       
   192                                    '%(initiator)s on group'
       
   193                                    'InitiatorGroup: %(initiatorgroup)s '
       
   194                                    'Return code: %(ret.status)d '
       
   195                                    'Message: %(ret.data)s .')
       
   196                                  % {'initiator': initiator,
       
   197                                     'initiatorgroup': initiatorgroup,
       
   198                                     'ret.status': ret.status,
       
   199                                     'ret.data': ret.data})
       
   200                 LOG.error(exception_msg)
       
   201                 raise exception.VolumeBackendAPIException(data=exception_msg)
       
   202 
       
   203     def create_target(self, alias, interfaces=None, tchapuser=None,
       
   204                       tchapsecret=None):
       
   205         """Create an iSCSI target
       
   206            interfaces: an array with network interfaces
       
   207            tchapuser, tchapsecret: target's chapuser and chapsecret
       
   208            returns target iqn
       
   209         """
       
   210         svc = '/api/san/v1/iscsi/targets/alias=' + alias
       
   211         ret = self.rclient.get(svc)
       
   212         if ret.status != restclient.Status.OK:
       
   213             svc = '/api/san/v1/iscsi/targets'
       
   214             arg = {
       
   215                 'alias': alias
       
   216             }
       
   217 
       
   218             if tchapuser and tchapuser != '' and tchapsecret and \
       
   219                tchapsecret != '':
       
   220                 arg.update({'targetchapuser': tchapuser,
       
   221                             'targetchapsecret': tchapsecret,
       
   222                             'auth': 'chap'})
       
   223 
       
   224             if interfaces is not None and len(interfaces) > 0:
       
   225                 arg.update({'interfaces': interfaces})
       
   226 
       
   227             ret = self.rclient.post(svc, arg)
       
   228             if ret.status != restclient.Status.CREATED:
       
   229                 exception_msg = (_('Error Creating Target: '
       
   230                                    '%(alias)s'
       
   231                                    'Return code: %(ret.status)d '
       
   232                                    'Message: %(ret.data)s .')
       
   233                                  % {'alias': alias,
       
   234                                     'ret.status': ret.status,
       
   235                                     'ret.data': ret.data})
       
   236                 LOG.error(exception_msg)
       
   237                 raise exception.VolumeBackendAPIException(data=exception_msg)
       
   238 
       
   239         val = json.loads(ret.data)
       
   240         return val['target']['iqn']
       
   241 
       
   242     def get_target(self, alias):
       
   243         """Get an iSCSI target iqn"""
       
   244         svc = '/api/san/v1/iscsi/targets/alias=' + alias
       
   245         ret = self.rclient.get(svc)
       
   246         if ret.status != restclient.Status.OK:
       
   247             exception_msg = (_('Error Getting Target: '
       
   248                                '%(alias)s'
       
   249                                'Return code: %(ret.status)d '
       
   250                                'Message: %(ret.data)s .')
       
   251                              % {'alias': alias,
       
   252                                 'ret.status': ret.status,
       
   253                                 'ret.data': ret.data})
       
   254             LOG.error(exception_msg)
       
   255             raise exception.VolumeBackendAPIException(data=exception_msg)
       
   256 
       
   257         val = json.loads(ret.data)
       
   258         return val['target']['iqn']
       
   259 
       
   260     def add_to_targetgroup(self, iqn, targetgroup):
       
   261         """Add an iSCSI target to targetgroup"""
       
   262         svc = '/api/san/v1/iscsi/target-groups/' + targetgroup
       
   263         ret = self.rclient.get(svc)
       
   264         if ret.status != restclient.Status.OK:
       
   265             svccrt = '/api/san/v1/iscsi/target-groups'
       
   266             arg = {
       
   267                 'name': targetgroup,
       
   268                 'targets': [iqn]
       
   269             }
       
   270 
       
   271             ret = self.rclient.post(svccrt, arg)
       
   272             if ret.status != restclient.Status.CREATED:
       
   273                 exception_msg = (_('Error Creating TargetGroup: '
       
   274                                    '%(targetgroup)s with'
       
   275                                    'IQN: %(iqn)s'
       
   276                                    'Return code: %(ret.status)d '
       
   277                                    'Message: %(ret.data)s .')
       
   278                                  % {'targetgroup': targetgroup,
       
   279                                     'iqn': iqn,
       
   280                                     'ret.status': ret.status,
       
   281                                     'ret.data': ret.data})
       
   282                 LOG.error(exception_msg)
       
   283                 raise exception.VolumeBackendAPIException(data=exception_msg)
       
   284 
       
   285             return
       
   286 
       
   287         arg = {
       
   288             'targets': [iqn]
       
   289         }
       
   290 
       
   291         ret = self.rclient.put(svc, arg)
       
   292         if ret.status != restclient.Status.ACCEPTED:
       
   293             exception_msg = (_('Error Adding to TargetGroup: '
       
   294                                '%(targetgroup)s with'
       
   295                                'IQN: %(iqn)s'
       
   296                                'Return code: %(ret.status)d '
       
   297                                'Message: %(ret.data)s.')
       
   298                              % {'targetgroup': targetgroup,
       
   299                                 'iqn': iqn,
       
   300                                 'ret.status': ret.status,
       
   301                                 'ret.data': ret.data})
       
   302             LOG.error(exception_msg)
       
   303             raise exception.VolumeBackendAPIException(data=exception_msg)
       
   304 
       
   305     def verify_pool(self, pool):
       
   306         """Checks whether pool exists"""
       
   307         svc = '/api/storage/v1/pools/' + pool
       
   308         ret = self.rclient.get(svc)
       
   309         if ret.status != restclient.Status.OK:
       
   310             exception_msg = (_('Error Verifying Pool: '
       
   311                                '%(pool)s '
       
   312                                'Return code: %(ret.status)d '
       
   313                                'Message: %(ret.data)s.')
       
   314                              % {'pool': pool,
       
   315                                 'ret.status': ret.status,
       
   316                                 'ret.data': ret.data})
       
   317             LOG.error(exception_msg)
       
   318             raise exception.VolumeBackendAPIException(data=exception_msg)
       
   319 
       
   320     def verify_project(self, pool, project):
       
   321         """Checks whether project exists"""
       
   322         svc = '/api/storage/v1/pools/' + pool + '/projects/' + project
       
   323         ret = self.rclient.get(svc)
       
   324         if ret.status != restclient.Status.OK:
       
   325             exception_msg = (_('Error Verifying '
       
   326                                'Project: %(project)s on '
       
   327                                'Pool: %(pool)s '
       
   328                                'Return code: %(ret.status)d '
       
   329                                'Message: %(ret.data)s.')
       
   330                              % {'project': project,
       
   331                                 'pool': pool,
       
   332                                 'ret.status': ret.status,
       
   333                                 'ret.data': ret.data})
       
   334             LOG.error(exception_msg)
       
   335             raise exception.VolumeBackendAPIException(data=exception_msg)
       
   336 
       
   337     def verify_initiator(self, iqn):
       
   338         """Check whether initiator iqn exists"""
       
   339         svc = '/api/san/v1/iscsi/initiators/' + iqn
       
   340         ret = self.rclient.get(svc)
       
   341         if ret.status != restclient.Status.OK:
       
   342             exception_msg = (_('Error Verifying '
       
   343                                'Initiator: %(iqn)s '
       
   344                                'Return code: %(ret.status)d '
       
   345                                'Message: %(ret.data)s.')
       
   346                              % {'initiator': iqn,
       
   347                                 'ret.status': ret.status,
       
   348                                 'ret.data': ret.data})
       
   349             LOG.error(exception_msg)
       
   350             raise exception.VolumeBackendAPIException(data=exception_msg)
       
   351 
       
   352     def verify_target(self, alias):
       
   353         """Check whether target alias exists."""
       
   354         svc = '/api/san/v1/iscsi/targets/alias=' + alias
       
   355         ret = self.rclient.get(svc)
       
   356         if ret.status != restclient.Status.OK:
       
   357             exception_msg = (_('Error Verifying '
       
   358                                'Target: %(alias)s '
       
   359                                'Return code: %(ret.status)d '
       
   360                                'Message: %(ret.data)s.')
       
   361                              % {'alias': alias,
       
   362                                 'ret.status': ret.status,
       
   363                                 'ret.data': ret.data})
       
   364             LOG.error(exception_msg)
       
   365             raise exception.VolumeBackendAPIException(data=exception_msg)
       
   366 
       
   367     def create_lun(self, pool, project, lun, volsize, targetgroup,
       
   368                    volblocksize='8k', sparse=False, compression=None,
       
   369                    logbias=None):
       
   370         """Create a LUN
       
   371            required - pool, project, lun, volsize, targetgroup.
       
   372            optional - volblocksize, sparse, compression, logbias
       
   373         """
       
   374 
       
   375         svc = '/api/storage/v1/pools/' + pool + '/projects/' + project + \
       
   376               '/luns/' + lun
       
   377         ret = self.rclient.get(svc)
       
   378         if ret.status != restclient.Status.OK:
       
   379             svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
       
   380                   project + '/luns'
       
   381             arg = {
       
   382                 'name': lun,
       
   383                 'volsize': volsize,
       
   384                 'targetgroup':  targetgroup,
       
   385                 'initiatorgroup': 'com.sun.ms.vss.hg.maskAll',
       
   386                 'volblocksize': volblocksize,
       
   387                 'sparse': sparse
       
   388             }
       
   389             if compression and compression != '':
       
   390                 arg.update({'compression': compression})
       
   391             if logbias and logbias != '':
       
   392                 arg.update({'logbias': logbias})
       
   393 
       
   394             ret = self.rclient.post(svc, arg)
       
   395             if ret.status != restclient.Status.CREATED:
       
   396                 exception_msg = (_('Error Creating '
       
   397                                    'Volume: %(lun)s '
       
   398                                    'Size: %(size)s '
       
   399                                    'Return code: %(ret.status)d '
       
   400                                    'Message: %(ret.data)s.')
       
   401                                  % {'lun': lun,
       
   402                                     'size': volsize,
       
   403                                     'ret.status': ret.status,
       
   404                                     'ret.data': ret.data})
       
   405                 LOG.error(exception_msg)
       
   406                 raise exception.VolumeBackendAPIException(data=exception_msg)
       
   407 
       
   408     def get_lun(self, pool, project, lun):
       
   409         """return iscsi lun properties"""
       
   410         svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
       
   411             project + "/luns/" + lun
       
   412         ret = self.rclient.get(svc)
       
   413         if ret.status != restclient.Status.OK:
       
   414             exception_msg = (_('Error Getting '
       
   415                                'Volume: %(lun)s on '
       
   416                                'Pool: %(pool)s '
       
   417                                'Project: %(project)s '
       
   418                                'Return code: %(ret.status)d '
       
   419                                'Message: %(ret.data)s.')
       
   420                              % {'lun': lun,
       
   421                                 'pool': pool,
       
   422                                 'project': project,
       
   423                                 'ret.status': ret.status,
       
   424                                 'ret.data': ret.data})
       
   425             LOG.error(exception_msg)
       
   426             raise exception.VolumeBackendAPIException(data=exception_msg)
       
   427 
       
   428         val = json.loads(ret.data)
       
   429         ret = {
       
   430             'guid': val['lun']['lunguid'],
       
   431             'number': val['lun']['assignednumber'],
       
   432             'initiatorgroup': val['lun']['initiatorgroup'],
       
   433             'size': val['lun']['volsize']
       
   434         }
       
   435         if 'origin' in val['lun']:
       
   436             ret.update({'origin': val['lun']['origin']})
       
   437 
       
   438         return ret
       
   439 
       
   440     def set_lun_initiatorgroup(self, pool, project, lun, initiatorgroup):
       
   441         """Set the initiatorgroup property of a LUN"""
       
   442         if initiatorgroup == '':
       
   443             initiatorgroup = 'com.sun.ms.vss.hg.maskAll'
       
   444 
       
   445         svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
       
   446             project + '/luns/' + lun
       
   447         arg = {
       
   448             'initiatorgroup': initiatorgroup
       
   449         }
       
   450 
       
   451         ret = self.rclient.put(svc, arg)
       
   452         if ret.status != restclient.Status.ACCEPTED:
       
   453             exception_msg = (_('Error Setting '
       
   454                                'Volume: %(lun)s to '
       
   455                                'InitiatorGroup: %(initiatorgroup)s '
       
   456                                'Pool: %(pool)s '
       
   457                                'Project: %(project)s  '
       
   458                                'Return code: %(ret.status)d '
       
   459                                'Message: %(ret.data)s.')
       
   460                              % {'lun': lun,
       
   461                                 'initiatorgroup': initiatorgroup,
       
   462                                 'pool': pool,
       
   463                                 'project': project,
       
   464                                 'ret.status': ret.status,
       
   465                                 'ret.data': ret.data})
       
   466             LOG.error(exception_msg)
       
   467 
       
   468     def delete_lun(self, pool, project, lun):
       
   469         """delete iscsi lun"""
       
   470         svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
       
   471             project + '/luns/' + lun
       
   472 
       
   473         ret = self.rclient.delete(svc)
       
   474         if ret.status != restclient.Status.NO_CONTENT:
       
   475             exception_msg = (_('Error Deleting '
       
   476                                'Volume: %(lun)s to '
       
   477                                'Pool: %(pool)s '
       
   478                                'Project: %(project)s  '
       
   479                                'Return code: %(ret.status)d '
       
   480                                'Message: %(ret.data)s.')
       
   481                              % {'lun': lun,
       
   482                                 'pool': pool,
       
   483                                 'project': project,
       
   484                                 'ret.status': ret.status,
       
   485                                 'ret.data': ret.data})
       
   486             LOG.error(exception_msg)
       
   487 
       
   488     def create_snapshot(self, pool, project, lun, snapshot):
       
   489         """create snapshot"""
       
   490         svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
       
   491             project + '/luns/' + lun + '/snapshots'
       
   492         arg = {
       
   493             'name': snapshot
       
   494         }
       
   495 
       
   496         ret = self.rclient.post(svc, arg)
       
   497         if ret.status != restclient.Status.CREATED:
       
   498             exception_msg = (_('Error Creating '
       
   499                                'Snapshot: %(snapshot)s on'
       
   500                                'Volume: %(lun)s to '
       
   501                                'Pool: %(pool)s '
       
   502                                'Project: %(project)s  '
       
   503                                'Return code: %(ret.status)d '
       
   504                                'Message: %(ret.data)s.')
       
   505                              % {'snapshot': snapshot,
       
   506                                 'lun': lun,
       
   507                                 'pool': pool,
       
   508                                 'project': project,
       
   509                                 'ret.status': ret.status,
       
   510                                 'ret.data': ret.data})
       
   511             LOG.error(exception_msg)
       
   512             raise exception.VolumeBackendAPIException(data=exception_msg)
       
   513 
       
   514     def delete_snapshot(self, pool, project, lun, snapshot):
       
   515         """delete snapshot"""
       
   516         svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
       
   517               project + '/luns/' + lun + '/snapshots/' + snapshot
       
   518 
       
   519         ret = self.rclient.delete(svc)
       
   520         if ret.status != restclient.Status.NO_CONTENT:
       
   521             exception_msg = (_('Error Deleting '
       
   522                                'Snapshot: %(snapshot)s on '
       
   523                                'Volume: %(lun)s to '
       
   524                                'Pool: %(pool)s '
       
   525                                'Project: %(project)s  '
       
   526                                'Return code: %(ret.status)d '
       
   527                                'Message: %(ret.data)s.')
       
   528                              % {'snapshot': snapshot,
       
   529                                 'lun': lun,
       
   530                                 'pool': pool,
       
   531                                 'project': project,
       
   532                                 'ret.status': ret.status,
       
   533                                 'ret.data': ret.data})
       
   534             LOG.error(exception_msg)
       
   535             raise exception.VolumeBackendAPIException(data=exception_msg)
       
   536 
       
   537     def clone_snapshot(self, pool, project, lun, snapshot, clone):
       
   538         """clone snapshot"""
       
   539         svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
       
   540             project + '/luns/' + lun + '/snapshots/' + snapshot + '/clone'
       
   541         arg = {
       
   542             'project': project,
       
   543             'share': clone
       
   544         }
       
   545 
       
   546         ret = self.rclient.put(svc, arg)
       
   547         if ret.status != restclient.Status.CREATED:
       
   548             exception_msg = (_('Error Cloning '
       
   549                                'Snapshot: %(snapshot)s on '
       
   550                                'Volume: %(lun)s of '
       
   551                                'Pool: %(pool)s '
       
   552                                'Project: %(project)s  '
       
   553                                'Return code: %(ret.status)d '
       
   554                                'Message: %(ret.data)s.')
       
   555                              % {'snapshot': snapshot,
       
   556                                 'lun': lun,
       
   557                                 'pool': pool,
       
   558                                 'project': project,
       
   559                                 'ret.status': ret.status,
       
   560                                 'ret.data': ret.data})
       
   561             LOG.error(exception_msg)
       
   562             raise exception.VolumeBackendAPIException(data=exception_msg)
       
   563 
       
   564     def set_lun_size(self, pool, project, lun, size):
       
   565         """increase lun size capacity"""
       
   566         svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
       
   567             project + '/luns/' + lun
       
   568         arg = {
       
   569             'volsize': size
       
   570         }
       
   571 
       
   572         ret = self.rclient.put(svc, arg)
       
   573         if ret.status != restclient.Status.ACCEPTED:
       
   574             exception_msg = (_('Error Setting size on '
       
   575                                'Size: %(size)s on '
       
   576                                'Volume: %(lun)s of '
       
   577                                'Pool: %(pool)s '
       
   578                                'Project: %(project)s  '
       
   579                                'Return code: %(ret.status)d '
       
   580                                'Message: %(ret.data)s.')
       
   581                              % {'size': size,
       
   582                                 'lun': lun,
       
   583                                 'pool': pool,
       
   584                                 'project': project,
       
   585                                 'ret.status': ret.status,
       
   586                                 'ret.data': ret.data})
       
   587             LOG.error(exception_msg)
       
   588             raise exception.VolumeBackendAPIException(data=exception_msg)
       
   589 
       
   590     def has_clones(self, pool, project, lun, snapshot):
       
   591         """Checks whether snapshot has clones or not."""
       
   592         svc = '/api/storage/v1/pools/' + pool + '/projects/' + \
       
   593             project + '/luns/' + lun + '/snapshots/' + snapshot
       
   594 
       
   595         ret = self.rclient.get(svc)
       
   596         if ret.status != restclient.Status.OK:
       
   597             exception_msg = (_('Error Getting '
       
   598                                'Snapshot: %(snapshot)s on '
       
   599                                'Volume: %(lun)s to '
       
   600                                'Pool: %(pool)s '
       
   601                                'Project: %(project)s  '
       
   602                                'Return code: %(ret.status)d '
       
   603                                'Message: %(ret.data)s.')
       
   604                              % {'snapshot': snapshot,
       
   605                                 'lun': lun,
       
   606                                 'pool': pool,
       
   607                                 'project': project,
       
   608                                 'ret.status': ret.status,
       
   609                                 'ret.data': ret.data})
       
   610             LOG.error(exception_msg)
       
   611             raise exception.VolumeBackendAPIException(data=exception_msg)
       
   612 
       
   613         val = json.loads(ret.data)
       
   614         return (val['snapshot']['numclones'] != 0)