Coverage for manila/share/drivers/infortrend/infortrend_nas.py: 60%

423 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2026-02-18 22:19 +0000

1# Copyright (c) 2019 Infortrend Technology, Inc. 

2# All Rights Reserved. 

3# 

4# Licensed under the Apache License, Version 2.0 (the "License"); you may 

5# not use this file except in compliance with the License. You may obtain 

6# a copy of the License at 

7# 

8# http://www.apache.org/licenses/LICENSE-2.0 

9# 

10# Unless required by applicable law or agreed to in writing, software 

11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 

12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 

13# License for the specific language governing permissions and limitations 

14# under the License. 

15 

16import json 

17import re 

18 

19from oslo_concurrency import processutils 

20from oslo_log import log 

21from oslo_utils import units 

22 

23from manila.common import constants 

24from manila import exception 

25from manila.i18n import _ 

26from manila.share import utils as share_utils 

27from manila import ssh_utils 

28from manila import utils as manila_utils 

29 

30 

31LOG = log.getLogger(__name__) 

32 

33 

34def _bi_to_gi(bi_size): 

35 return bi_size / units.Gi 

36 

37 

38class InfortrendNAS(object): 

39 

40 _SSH_PORT = 22 

41 

42 def __init__(self, nas_ip, username, password, ssh_key, 

43 timeout, pool_dict, channel_dict): 

44 self.nas_ip = nas_ip 

45 self.port = self._SSH_PORT 

46 self.username = username 

47 self.password = password 

48 self.ssh_key = ssh_key 

49 self.ssh_timeout = timeout 

50 self.pool_dict = pool_dict 

51 self.channel_dict = channel_dict 

52 self.command = "" 

53 self.ssh = None 

54 self.sshpool = None 

55 self.location = 'a@0' 

56 

57 def _execute(self, command_line): 

58 command_line.extend(['-z', self.location]) 

59 commands = ' '.join(command_line) 

60 manila_utils.check_ssh_injection(commands) 

61 LOG.debug('Executing: %(command)s', {'command': commands}) 

62 

63 cli_out = self._ssh_execute(commands) 

64 

65 return self._parser(cli_out) 

66 

67 def _ssh_execute(self, commands): 

68 try: 

69 out, err = processutils.ssh_execute( 

70 self.ssh, commands, 

71 timeout=self.ssh_timeout, check_exit_code=True) 

72 except processutils.ProcessExecutionError as pe: 

73 rc = pe.exit_code 

74 out = pe.stdout 

75 out = out.replace('\n', '\\n') 

76 msg = _('Error on execute ssh command. ' 

77 'Exit code: %(rc)d, msg: %(out)s') % { 

78 'rc': rc, 'out': out} 

79 raise exception.InfortrendNASException(err=msg) 

80 

81 return out 

82 

83 def _parser(self, content=None): 

84 LOG.debug('parsing data:\n%s', content) 

85 content = content.replace("\r", "") 

86 content = content.strip() 

87 json_string = content.replace("'", "\"") 

88 cli_data = json_string.splitlines()[2] 

89 if cli_data: 89 ↛ 105line 89 didn't jump to line 105 because the condition on line 89 was always true

90 try: 

91 data_dict = json.loads(cli_data) 

92 except Exception: 

93 msg = _('Failed to parse data: ' 

94 '%(cli_data)s to dictionary.') % { 

95 'cli_data': cli_data} 

96 LOG.error(msg) 

97 raise exception.InfortrendNASException(err=msg) 

98 

99 rc = int(data_dict['cliCode'][0]['Return'], 16) 

100 if rc == 0: 100 ↛ 103line 100 didn't jump to line 103 because the condition on line 100 was always true

101 result = data_dict['data'] 

102 else: 

103 result = data_dict['cliCode'][0]['CLI'] 

104 else: 

105 msg = _('No data is returned from NAS.') 

106 LOG.error(msg) 

107 raise exception.InfortrendNASException(err=msg) 

108 

109 if rc != 0: 109 ↛ 110line 109 didn't jump to line 110 because the condition on line 109 was never true

110 msg = _('NASCLI error, returned: %(result)s.') % { 

111 'result': result} 

112 LOG.error(msg) 

113 raise exception.InfortrendCLIException( 

114 err=msg, rc=rc, out=result) 

115 

116 return rc, result 

117 

118 def do_setup(self): 

119 self._init_connect() 

120 self._ensure_service_on('nfs') 

121 self._ensure_service_on('cifs') 

122 

123 def _init_connect(self): 

124 if not (self.sshpool and self.ssh): 

125 self.sshpool = ssh_utils.SSHPool(ip=self.nas_ip, 

126 port=self.port, 

127 conn_timeout=None, 

128 login=self.username, 

129 password=self.password, 

130 privatekey=self.ssh_key) 

131 self.ssh = self.sshpool.create() 

132 

133 if not self.ssh.get_transport().is_active(): 

134 self.sshpool = ssh_utils.SSHPool(ip=self.nas_ip, 

135 port=self.port, 

136 conn_timeout=None, 

137 login=self.username, 

138 password=self.password, 

139 privatekey=self.ssh_key) 

140 self.ssh = self.sshpool.create() 

141 

142 LOG.debug('NAScmd [%s@%s] start!', self.username, self.nas_ip) 

143 

144 def check_for_setup_error(self): 

145 self._check_pools_setup() 

146 self._check_channels_status() 

147 

148 def _ensure_service_on(self, proto, slot='A'): 

149 command_line = ['service', 'status', proto] 

150 rc, service_status = self._execute(command_line) 

151 if not service_status[0][slot][proto.upper()]['enabled']: 151 ↛ exitline 151 didn't return from function '_ensure_service_on' because the condition on line 151 was always true

152 command_line = ['service', 'restart', proto] 

153 self._execute(command_line) 

154 

155 def _check_channels_status(self): 

156 channel_list = list(self.channel_dict.keys()) 

157 command_line = ['ifconfig', 'inet', 'show'] 

158 rc, channels_status = self._execute(command_line) 

159 for channel in channels_status: 

160 if 'CH' in channel['datalink']: 

161 ch = channel['datalink'].strip('CH') 

162 if ch in self.channel_dict.keys(): 

163 self.channel_dict[ch] = channel['IP'] 

164 channel_list.remove(ch) 

165 if channel['status'] == 'DOWN': 

166 LOG.warning('Channel [%(ch)s] status ' 

167 'is down, please check.', { 

168 'ch': ch}) 

169 if len(channel_list) != 0: 

170 msg = _('Channel setting %(channel_list)s is invalid!') % { 

171 'channel_list': channel_list} 

172 LOG.error(msg) 

173 raise exception.InfortrendNASException(message=msg) 

174 

175 def _check_pools_setup(self): 

176 pool_list = list(self.pool_dict.keys()) 

177 command_line = ['folder', 'status'] 

178 rc, pool_data = self._execute(command_line) 

179 for pool in pool_data: 

180 pool_name = self._extract_pool_name(pool) 

181 if pool_name in self.pool_dict.keys(): 

182 pool_list.remove(pool_name) 

183 self.pool_dict[pool_name]['id'] = pool['volumeId'] 

184 self.pool_dict[pool_name]['path'] = pool['directory'] + '/' 

185 if len(pool_list) == 0: 

186 break 

187 

188 if len(pool_list) != 0: 

189 msg = _('Please create %(pool_list)s pool/s in advance!') % { 

190 'pool_list': pool_list} 

191 LOG.error(msg) 

192 raise exception.InfortrendNASException(message=msg) 

193 

194 def _extract_pool_name(self, pool_info): 

195 return pool_info['directory'].split('/')[1] 

196 

197 def _extract_lv_name(self, pool_info): 

198 return pool_info['path'].split('/')[2] 

199 

200 def update_pools_stats(self): 

201 pools = [] 

202 command_line = ['folder', 'status'] 

203 rc, pools_data = self._execute(command_line) 

204 

205 for pool_info in pools_data: 

206 pool_name = self._extract_pool_name(pool_info) 

207 

208 if pool_name in self.pool_dict.keys(): 

209 total_space = float(pool_info['size']) 

210 pool_quota_used = self._get_pool_quota_used(pool_name) 

211 available_space = total_space - pool_quota_used 

212 

213 total_capacity_gb = round(_bi_to_gi(total_space), 2) 

214 free_capacity_gb = round(_bi_to_gi(available_space), 2) 

215 

216 pool = { 

217 'pool_name': pool_name, 

218 'total_capacity_gb': total_capacity_gb, 

219 'free_capacity_gb': free_capacity_gb, 

220 'reserved_percentage': 0, 

221 'qos': False, 

222 'dedupe': False, 

223 'compression': False, 

224 'snapshot_support': False, 

225 'thin_provisioning': False, 

226 'thick_provisioning': True, 

227 'replication_type': None, 

228 } 

229 pools.append(pool) 

230 

231 return pools 

232 

233 def _get_pool_quota_used(self, pool_name): 

234 pool_quota_used = 0.0 

235 pool_data = self._get_share_pool_data(pool_name) 

236 folder_name = self._extract_lv_name(pool_data) 

237 

238 command_line = ['fquota', 'status', pool_data['id'], 

239 folder_name, '-t', 'folder'] 

240 rc, quota_status = self._execute(command_line) 

241 

242 for share_quota in quota_status: 

243 pool_quota_used += int(share_quota['quota']) 

244 

245 return pool_quota_used 

246 

247 def _get_share_pool_data(self, pool_name): 

248 if not pool_name: 248 ↛ 249line 248 didn't jump to line 249 because the condition on line 248 was never true

249 msg = _("Pool is not available in the share host.") 

250 raise exception.InvalidHost(reason=msg) 

251 

252 if pool_name in self.pool_dict.keys(): 252 ↛ 255line 252 didn't jump to line 255 because the condition on line 252 was always true

253 return self.pool_dict[pool_name] 

254 else: 

255 msg = _('Pool [%(pool_name)s] not set in conf.') % { 

256 'pool_name': pool_name} 

257 LOG.error(msg) 

258 raise exception.InfortrendNASException(err=msg) 

259 

260 def create_share(self, share, share_server=None): 

261 pool_name = share_utils.extract_host(share['host'], level='pool') 

262 pool_data = self._get_share_pool_data(pool_name) 

263 folder_name = self._extract_lv_name(pool_data) 

264 share_proto = share['share_proto'].lower() 

265 share_name = share['id'].replace('-', '') 

266 share_path = pool_data['path'] + share_name 

267 

268 command_line = ['folder', 'options', pool_data['id'], 

269 folder_name, '-c', share_name] 

270 self._execute(command_line) 

271 

272 self._set_share_size( 

273 pool_data['id'], pool_name, share_name, share['size']) 

274 self._ensure_protocol_on(share_path, share_proto, share_name) 

275 

276 LOG.info('Create Share [%(share)s] completed.', { 

277 'share': share['id']}) 

278 

279 return self._export_location( 

280 share_name, share_proto, pool_data['path']) 

281 

282 def _export_location(self, share_name, share_proto, pool_path=None): 

283 location = [] 

284 location_data = { 

285 'pool_path': pool_path, 

286 'share_name': share_name, 

287 } 

288 self._check_channels_status() 

289 for ch in sorted(self.channel_dict.keys()): 

290 ip = self.channel_dict[ch] 

291 if share_proto == 'nfs': 

292 location.append( 

293 ip + ':%(pool_path)s%(share_name)s' % location_data) 

294 elif share_proto == 'cifs': 294 ↛ 298line 294 didn't jump to line 298 because the condition on line 294 was always true

295 location.append( 

296 '\\\\' + ip + '\\%(share_name)s' % location_data) 

297 else: 

298 msg = _('Unsupported protocol: [%s].') % share_proto 

299 raise exception.InvalidInput(msg) 

300 

301 return location 

302 

303 def _set_share_size(self, pool_id, pool_name, share_name, share_size): 

304 pool_data = self._get_share_pool_data(pool_name) 

305 folder_name = self._extract_lv_name(pool_data) 

306 command_line = ['fquota', 'create', pool_id, folder_name, 

307 share_name, str(share_size) + 'G', '-t', 'folder'] 

308 self._execute(command_line) 

309 

310 LOG.debug('Set Share [%(share_name)s] ' 

311 'Size [%(share_size)s G] completed.', { 

312 'share_name': share_name, 

313 'share_size': share_size}) 

314 return 

315 

316 def _get_share_size(self, pool_id, pool_name, share_name): 

317 share_size = None 

318 command_line = ['fquota', 'status', pool_id, 

319 share_name, '-t', 'folder'] 

320 rc, quota_status = self._execute(command_line) 

321 

322 for share_quota in quota_status: 

323 if share_quota['name'] == share_name: 

324 share_size = round(_bi_to_gi(float(share_quota['quota'])), 2) 

325 break 

326 

327 return share_size 

328 

329 def delete_share(self, share, share_server=None): 

330 pool_name = share_utils.extract_host(share['host'], level='pool') 

331 pool_data = self._get_share_pool_data(pool_name) 

332 folder_name = self._extract_lv_name(pool_data) 

333 share_name = share['id'].replace('-', '') 

334 

335 if self._check_share_exist(pool_name, share_name): 

336 command_line = ['folder', 'options', pool_data['id'], 

337 folder_name, '-d', share_name] 

338 self._execute(command_line) 

339 else: 

340 LOG.warning('Share [%(share_name)s] is already deleted.', { 

341 'share_name': share_name}) 

342 

343 LOG.info('Delete Share [%(share)s] completed.', { 

344 'share': share['id']}) 

345 

346 def _check_share_exist(self, pool_name, share_name): 

347 path = self.pool_dict[pool_name]['path'] 

348 command_line = ['pagelist', 'folder', path] 

349 rc, subfolders = self._execute(command_line) 

350 return any(subfolder['name'] == share_name for subfolder in subfolders) 

351 

352 def update_access(self, share, access_rules, add_rules, 

353 delete_rules, share_server=None): 

354 self._evict_unauthorized_clients(share, access_rules, share_server) 

355 access_dict = {} 

356 for access in access_rules: 

357 try: 

358 self._allow_access(share, access, share_server) 

359 except (exception.InfortrendNASException) as e: 

360 msg = _('Failed to allow access to client %(access)s, ' 

361 'reason %(e)s.') % { 

362 'access': access['access_to'], 'e': e} 

363 LOG.error(msg) 

364 access_dict[access['id']] = 'error' 

365 

366 return access_dict 

367 

368 def _evict_unauthorized_clients(self, share, access_rules, 

369 share_server=None): 

370 pool_name = share_utils.extract_host(share['host'], level='pool') 

371 pool_data = self._get_share_pool_data(pool_name) 

372 share_proto = share['share_proto'].lower() 

373 share_name = share['id'].replace('-', '') 

374 share_path = pool_data['path'] + share_name 

375 

376 access_list = [] 

377 for access in access_rules: 

378 access_list.append(access['access_to']) 

379 

380 if share_proto == 'nfs': 

381 host_ip_list = [] 

382 command_line = ['share', 'status', '-f', share_path] 

383 rc, nfs_status = self._execute(command_line) 

384 host_list = nfs_status[0]['nfs_detail']['hostList'] 

385 for host in host_list: 

386 if host['host'] != '*': 

387 host_ip_list.append(host['host']) 

388 for ip in host_ip_list: 

389 if ip not in access_list: 

390 command_line = ['share', 'options', share_path, 

391 'nfs', '-c', ip] 

392 try: 

393 self._execute(command_line) 

394 except exception.InfortrendNASException: 

395 msg = _("Failed to remove share access rule %s") % (ip) 

396 LOG.exception(msg) 

397 pass 

398 

399 elif share_proto == 'cifs': 

400 host_user_list = [] 

401 command_line = ['acl', 'get', share_path] 

402 rc, cifs_status = self._execute(command_line) 

403 for cifs_rule in cifs_status: 

404 if cifs_rule['name']: 

405 host_user_list.append(cifs_rule['name']) 

406 for user in host_user_list: 

407 if user not in access_list: 

408 command_line = ['acl', 'delete', share_path, '-u', user] 

409 try: 

410 self._execute(command_line) 

411 except exception.InfortrendNASException: 

412 msg = _("Failed to remove share access rule %s") % ( 

413 user) 

414 LOG.exception(msg) 

415 pass 

416 

417 def _allow_access(self, share, access, share_server=None): 

418 pool_name = share_utils.extract_host(share['host'], level='pool') 

419 pool_data = self._get_share_pool_data(pool_name) 

420 share_name = share['id'].replace('-', '') 

421 share_path = pool_data['path'] + share_name 

422 share_proto = share['share_proto'].lower() 

423 access_type = access['access_type'] 

424 access_level = access['access_level'] or constants.ACCESS_LEVEL_RW 

425 access_to = access['access_to'] 

426 ACCESS_LEVEL_MAP = {access_level: access_level} 

427 msg = self._check_access_legal(share_proto, access_type) 

428 if msg: 

429 raise exception.InvalidShareAccess(reason=msg) 

430 

431 if share_proto == 'nfs': 

432 command_line = ['share', 'options', share_path, 'nfs', 

433 '-h', access_to, '-p', access_level] 

434 self._execute(command_line) 

435 

436 elif share_proto == 'cifs': 

437 if not self._check_user_exist(access_to): 

438 msg = _('Please create user [%(user)s] in advance.') % { 

439 'user': access_to} 

440 LOG.error(msg) 

441 raise exception.InfortrendNASException(err=msg) 

442 

443 if access_level == constants.ACCESS_LEVEL_RW: 

444 cifs_access = 'f' 

445 elif access_level == constants.ACCESS_LEVEL_RO: 

446 cifs_access = 'r' 

447 try: 

448 access_level = ACCESS_LEVEL_MAP[access_level] 

449 except KeyError: 

450 msg = _('Unsupported access_level: [%s].') % access_level 

451 raise exception.InvalidInput(msg) 

452 

453 command_line = ['acl', 'set', share_path, 

454 '-u', access_to, '-a', cifs_access] 

455 self._execute(command_line) 

456 

457 LOG.info('Share [%(share)s] access to [%(access_to)s] ' 

458 'level [%(level)s] protocol [%(share_proto)s] completed.', { 

459 'share': share['id'], 

460 'access_to': access_to, 

461 'level': access_level, 

462 'share_proto': share_proto}) 

463 

464 def _ensure_protocol_on(self, share_path, share_proto, cifs_name): 

465 if not self._check_proto_enabled(share_path, share_proto): 465 ↛ exitline 465 didn't return from function '_ensure_protocol_on' because the condition on line 465 was always true

466 command_line = ['share', share_path, share_proto, 'on'] 

467 if share_proto == 'cifs': 

468 command_line.extend(['-n', cifs_name]) 

469 self._execute(command_line) 

470 

471 def _check_proto_enabled(self, share_path, share_proto): 

472 command_line = ['share', 'status', '-f', share_path] 

473 rc, share_status = self._execute(command_line) 

474 if share_status: 474 ↛ 478line 474 didn't jump to line 478 because the condition on line 474 was always true

475 check_enabled = share_status[0][share_proto] 

476 if check_enabled: 476 ↛ 477line 476 didn't jump to line 477 because the condition on line 476 was never true

477 return True 

478 return False 

479 

480 def _check_user_exist(self, user_name): 

481 command_line = ['useradmin', 'user', 'list'] 

482 rc, user_list = self._execute(command_line) 

483 for user in user_list: 

484 if user['Name'] == user_name: 

485 return True 

486 return False 

487 

488 def _check_access_legal(self, share_proto, access_type): 

489 msg = None 

490 if share_proto == 'cifs' and access_type != 'user': 

491 msg = _('Infortrend CIFS share only supports USER access type.') 

492 elif share_proto == 'nfs' and access_type != 'ip': 

493 msg = _('Infortrend NFS share only supports IP access type.') 

494 elif share_proto not in ('nfs', 'cifs'): 

495 msg = _('Unsupported share protocol [%s].') % share_proto 

496 return msg 

497 

498 def get_pool(self, share): 

499 pool_name = share_utils.extract_host(share['host'], level='pool') 

500 if not pool_name: 

501 share_name = share['id'].replace('-', '') 

502 for pool in self.pool_dict.keys(): 502 ↛ 506line 502 didn't jump to line 506 because the loop on line 502 didn't complete

503 if self._check_share_exist(pool, share_name): 503 ↛ 502line 503 didn't jump to line 502 because the condition on line 503 was always true

504 pool_name = pool 

505 break 

506 return pool_name 

507 

508 def ensure_share(self, share, share_server=None): 

509 share_proto = share['share_proto'].lower() 

510 pool_name = share_utils.extract_host(share['host'], level='pool') 

511 pool_data = self._get_share_pool_data(pool_name) 

512 share_name = share['id'].replace('-', '') 

513 return self._export_location( 

514 share_name, share_proto, pool_data['path']) 

515 

516 def extend_share(self, share, new_size, share_server=None): 

517 pool_name = share_utils.extract_host(share['host'], level='pool') 

518 pool_data = self._get_share_pool_data(pool_name) 

519 share_name = share['id'].replace('-', '') 

520 self._set_share_size(pool_data['id'], pool_name, share_name, new_size) 

521 

522 LOG.info('Successfully Extend Share [%(share)s] ' 

523 'to size [%(new_size)s G].', { 

524 'share': share['id'], 

525 'new_size': new_size}) 

526 

527 def shrink_share(self, share, new_size, share_server=None): 

528 pool_name = share_utils.extract_host(share['host'], level='pool') 

529 pool_data = self._get_share_pool_data(pool_name) 

530 share_name = share['id'].replace('-', '') 

531 folder_name = self._extract_lv_name(pool_data) 

532 

533 command_line = ['fquota', 'status', pool_data['id'], 

534 folder_name, '-t', 'folder'] 

535 rc, quota_status = self._execute(command_line) 

536 

537 for share_quota in quota_status: 

538 if share_quota['name'] == share_name: 

539 used_space = round(_bi_to_gi(float(share_quota['used'])), 2) 

540 

541 if new_size < used_space: 

542 raise exception.ShareShrinkingPossibleDataLoss( 

543 share_id=share['id']) 

544 

545 self._set_share_size(pool_data['id'], pool_name, share_name, new_size) 

546 

547 LOG.info('Successfully Shrink Share [%(share)s] ' 

548 'to size [%(new_size)s G].', { 

549 'share': share['id'], 

550 'new_size': new_size}) 

551 

552 def manage_existing(self, share, driver_options): 

553 share_proto = share['share_proto'].lower() 

554 pool_name = share_utils.extract_host(share['host'], level='pool') 

555 pool_data = self._get_share_pool_data(pool_name) 

556 volume_name = self._extract_lv_name(pool_data) 

557 input_location = share['export_locations'][0]['path'] 

558 share_name = share['id'].replace('-', '') 

559 

560 ch_ip, folder_name = self._parse_location(input_location, share_proto) 

561 

562 if not self._check_channel_ip(ch_ip): 

563 msg = _('Export location ip: [%(ch_ip)s] ' 

564 'is incorrect, please use data port ip.') % { 

565 'ch_ip': ch_ip} 

566 LOG.error(msg) 

567 raise exception.InfortrendNASException(err=msg) 

568 

569 if not self._check_share_exist(pool_name, folder_name): 

570 msg = _('Can not find folder [%(folder_name)s] ' 

571 'in pool [%(pool_name)s].') % { 

572 'folder_name': folder_name, 

573 'pool_name': pool_name} 

574 LOG.error(msg) 

575 raise exception.InfortrendNASException(err=msg) 

576 

577 share_path = pool_data['path'] + folder_name 

578 self._ensure_protocol_on(share_path, share_proto, share_name) 

579 share_size = self._get_share_size( 

580 pool_data['id'], pool_name, folder_name) 

581 

582 if not share_size: 

583 msg = _('Folder [%(folder_name)s] has no size limitation, ' 

584 'please set it first for Openstack management.') % { 

585 'folder_name': folder_name} 

586 LOG.error(msg) 

587 raise exception.InfortrendNASException(err=msg) 

588 

589 # rename folder name 

590 command_line = ['folder', 'options', pool_data['id'], volume_name, 

591 '-k', folder_name, share_name] 

592 self._execute(command_line) 

593 

594 location = self._export_location( 

595 share_name, share_proto, pool_data['path']) 

596 

597 LOG.info('Successfully Manage Infortrend Share [%(folder_name)s], ' 

598 'Size: [%(size)s G], Protocol: [%(share_proto)s], ' 

599 'new name: [%(share_name)s].', { 

600 'folder_name': folder_name, 

601 'size': share_size, 

602 'share_proto': share_proto, 

603 'share_name': share_name}) 

604 

605 return {'size': share_size, 'export_locations': location} 

606 

607 def _parse_location(self, input_location, share_proto): 

608 ip = None 

609 folder_name = None 

610 pattern_ip = r'[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' 

611 if share_proto == 'nfs': 

612 pattern_folder = r'[^\/]+$' 

613 ip = "".join(re.findall(pattern_ip, input_location)) 

614 folder_name = "".join(re.findall(pattern_folder, input_location)) 

615 

616 elif share_proto == 'cifs': 616 ↛ 621line 616 didn't jump to line 621 because the condition on line 616 was always true

617 pattern_folder = r'[^\\]+$' 

618 ip = "".join(re.findall(pattern_ip, input_location)) 

619 folder_name = "".join(re.findall(pattern_folder, input_location)) 

620 

621 if not (ip and folder_name): 

622 msg = _('Export location error, please check ' 

623 'ip: [%(ip)s], folder_name: [%(folder_name)s].') % { 

624 'ip': ip, 

625 'folder_name': folder_name} 

626 LOG.error(msg) 

627 raise exception.InfortrendNASException(err=msg) 

628 

629 return ip, folder_name 

630 

631 def _check_channel_ip(self, channel_ip): 

632 return any(ip == channel_ip for ip in self.channel_dict.values()) 

633 

634 def unmanage(self, share): 

635 pool_name = share_utils.extract_host(share['host'], level='pool') 

636 share_name = share['id'].replace('-', '') 

637 

638 if not self._check_share_exist(pool_name, share_name): 

639 LOG.warning('Share [%(share_name)s] does not exist.', { 

640 'share_name': share_name}) 

641 return 

642 

643 LOG.info('Successfully Unmanaged Share [%(share)s].', { 

644 'share': share['id']})