Coverage for src/zenossapi/routers/device.py: 79%

519 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-25 05:47 +0000

1# -*- coding: utf-8 -*- 

2 

3""" 

4Zenoss device_router 

5""" 

6 

7import re 

8import warnings 

9from zenossapi.apiclient import ZenossAPIClientError 

10from zenossapi.routers import ZenossRouter 

11from zenossapi.routers.properties import PropertiesRouter 

12from zenossapi.routers.template import TemplateRouter 

13 

14 

15class DeviceRouter(ZenossRouter): 

16 """ 

17 Class for interacting with the Zenoss device router 

18 """ 

19 

20 def __init__(self, url, headers, ssl_verify): 

21 super(DeviceRouter, self).__init__(url, headers, ssl_verify, 

22 'device_router', 'DeviceRouter') 

23 self.uid = None 

24 self.properties = None 

25 self.prod_states_by_value = {} 

26 self.prod_states_by_name = {} 

27 self.priorities_by_value = {} 

28 self.priorities_by_name = {} 

29 

30 prod_states_data = self._router_request( 

31 self._make_request_data( 

32 'getProductionStates', 

33 dict(), 

34 ) 

35 ) 

36 for state in prod_states_data['data']: 

37 self.prod_states_by_name[state['name']] = state['value'] 

38 self.prod_states_by_value[state['value']] = state['name'] 

39 

40 priority_data = self._router_request( 

41 self._make_request_data( 

42 'getPriorities', 

43 dict(), 

44 ) 

45 ) 

46 for p in priority_data['data']: 

47 self.priorities_by_name[p['name']] = p['value'] 

48 self.priorities_by_value[p['value']] = p['name'] 

49 

50 def __repr__(self): 

51 if self.uid: 

52 identifier = self.uid 

53 else: 

54 identifier = hex(id(self)) 

55 

56 return '<{0} object at {1}>'.format( 

57 type(self).__name__, identifier 

58 ) 

59 

60 def object_exists(self, uid): 

61 

62 object_data = self._router_request( 

63 self._make_request_data( 

64 'objectExists', 

65 dict(uid=uid) 

66 ) 

67 ) 

68 

69 return object_data['exists'] 

70 

71 def add_node(self, type, contextUid, id, description=""): 

72 """ 

73 Adds a node to the node tree 

74 Args: 

75 type: Class, Group or System 

76 contextUid: The existing node to add the new node to 

77 id: name of the node 

78 description: optional description 

79 

80 Returns: (bool) success 

81 

82 """ 

83 group_data = self._router_request( 

84 self._make_request_data( 

85 'addNode', 

86 dict(type=type, 

87 contextUid=contextUid, 

88 id=id, 

89 description=description) 

90 ) 

91 ) 

92 

93 return group_data['success'] 

94 

95 def add_location(self, id, contextUid='zport/dmd/Locations', address="", description=""): 

96 """ 

97 Adds a node to the location tree 

98 Args: 

99 contextUid: The existing node to add the new node to, defaults to root  

100 id: name of the node 

101 address: optional physical address 

102 description: optional description 

103 

104 Returns: (bool) success 

105 

106 """ 

107 group_data = self._router_request( 

108 self._make_request_data( 

109 'addLocationNode', 

110 dict(type='Location', 

111 contextUid=contextUid, 

112 id=id, 

113 address=address, 

114 description=description) 

115 ) 

116 ) 

117 

118 return group_data['success'] 

119 

120 def delete_node(self, uid): 

121 """ 

122 Removes a node from the node tree 

123 Args: 

124 uid: (str) UID of node to delte from tree 

125 

126 Returns: (bool) success 

127 

128 """ 

129 group_data = self._router_request( 

130 self._make_request_data( 

131 'deleteNode', 

132 dict(uid=uid) 

133 ) 

134 ) 

135 

136 return group_data['success'] 

137 

138 def get_device_uids(self, uid): 

139 

140 uid_data = self._router_request( 

141 self._make_request_data( 

142 'getDeviceUids', 

143 dict(uid=uid) 

144 ) 

145 ) 

146 

147 uid_list = dict( 

148 total=len(uid_data['devices']), 

149 uids=uid_data['devices'] 

150 ) 

151 

152 return uid_list 

153 

154 def list_devices(self, uid=None, params=None, start=0, limit=50, sort='name', 

155 dir='ASC'): 

156 """ 

157 Get the devices contained in a device class. Supports pagination. 

158 

159 Arguments: 

160 uid (str): The uid of the organizer to get devices from 

161 params (dict): Key/value filters for the search, options are 

162 name, ipAddress, deviceClass, or productionState 

163 start (int): Offset to start device list from, default 0 

164 limit (int): The number of results to return, default 50 

165 sort (str): Sort key for the list, default is 'name' 

166 dir (str): Sort order, either 'ASC' or 'DESC', default is 'ASC' 

167 

168 Returns: 

169 dict(int, str, list(ZenossDevice)): :: 

170 

171 { 

172 'total': Total number of devices found 

173 'hash': Hashcheck to determine if any devices have changed, 

174 'devices': ZenossDevice objects, 

175 } 

176 

177 """ 

178 device_data = self._router_request( 

179 self._make_request_data( 

180 'getDevices', 

181 dict( 

182 uid=uid, 

183 params=params, 

184 start=start, 

185 limit=limit, 

186 sort=sort, 

187 dir=dir, 

188 ) 

189 ) 

190 ) 

191 

192 device_list = dict( 

193 total=device_data['totalCount'], 

194 hash=device_data['hash'], 

195 devices=[] 

196 ) 

197 for device in device_data['devices']: 

198 device_list['devices'].append(self.get_device_by_uid( 

199 device['uid'].replace('/zport/dmd/', '', 1))) 

200 

201 return device_list 

202 

203 def _find_nodes_in_tree(self, tree_data): 

204 """ 

205 Works through the dict structure returned by the Zenoss API for 

206 a device class tree and returns the nodes. 

207 

208 Laving private along with _climb_tree as tree traversal can be hazardous. 

209 

210 Arguments: 

211 tree_data (dict): Templates data returned by the API 

212 

213 Returns: 

214 list: 

215 """ 

216 tree = [] 

217 for node in tree_data['children']: 

218 node_children = self._find_nodes_in_tree(node) 

219 tree.append( 

220 dict( 

221 uid=node['path'], 

222 children=node_children 

223 ) 

224 ) 

225 

226 return tree 

227 

228 def _climb_tree(self, tree_data, include_details, _root_path=True): 

229 """ 

230 A more advanced version of _find_nodes_in_tree that will return 

231 a dictionary-only structure instead of the mixed dict/list structure 

232 of the original. Also includes the otion to include details about each branch. 

233 

234 Args: 

235 tree_data (dict): The tree returned by the API call 

236 include_details (bool): If True returns all details from the getTree API call 

237 If false only includes the structure of dictionaries 

238 _root_path (bool): Used as a control within the function to avoid writing 

239 duplicate data. Probably a more elegant way to do this. 

240 

241 Returns: 

242 dict: Dict of the tree structure 

243 

244 """ 

245 if include_details is True: 

246 tree = dict(count=tree_data['text']['count'], 

247 uid=tree_data['uid'], 

248 id=tree_data['id'], 

249 path=tree_data['path'], 

250 uuid=tree_data['uuid'] 

251 ) 

252 else: 

253 tree = {} 

254 for node in tree_data['children']: 

255 node_children = self._climb_tree(node, include_details, _root_path=False) 

256 if include_details is False: 

257 tree[node['path']] = node_children 

258 else: 

259 tree[node['path']] = dict(node_children, 

260 count=node['text']['count'], 

261 uid=node['uid'], 

262 id=node['id'], 

263 path=node['path'], 

264 uuid=node['uuid'] 

265 ) 

266 if _root_path is True: 

267 tree = {tree_data['path']: tree} 

268 return tree 

269 

270 def get_info_by_uid(self, uid): 

271 """ 

272 Get object properties by the full UID 

273 

274 Arguments: 

275 uid (str): UID for the object 

276 

277 Returns: 

278 dict: 

279 """ 

280 return self._router_request( 

281 self._make_request_data( 

282 'getInfo', 

283 dict(uid=uid), 

284 ) 

285 ) 

286 

287 def get_device_by_uid(self, device_uid): 

288 """ 

289 Get a device by its full UID 

290 

291 Arguments: 

292 device_uid (str): The uid of the device to get 

293 

294 Returns: 

295 ZenossDevice: 

296 """ 

297 device_data = self.get_info_by_uid(device_uid) 

298 

299 return ZenossDevice( 

300 self.api_url, 

301 self.api_headers, 

302 self.ssl_verify, 

303 device_data['data'] 

304 ) 

305 

306 def get_device_by_name(self, device_name): 

307 """ 

308 Get a device by its name 

309 

310 Arguments: 

311 device_name (str): Name of the device to get 

312 

313 Returns: 

314 ZenossDevice: 

315 """ 

316 device_uid = self.get_device_uid_by_name(device_name) 

317 if device_uid is None: 

318 return None 

319 return self.get_device_by_uid(device_uid) 

320 

321 def list_devices_by_uid(self, uid, keys=None, **kwargs): 

322 """ 

323 Returns a list of all devices under a specified UID. 

324 UID could be a device class, group, system, location, etc. 

325 Args: 

326 uid: (str) Device organizer to list devices under 

327 keys: (list) List of keys to return in results, otherwise returns all 

328 **kwargs: Additional optional arguments (sort, start, limit, params, page, dir) 

329 

330 Returns: (list) List of all devices in the group organizer and its properties 

331 

332 """ 

333 if not keys: 

334 keys = [ 

335 'name', 

336 'uid', 

337 'ipAddressString', 

338 'collector', 

339 'productionState', 

340 'priority', 

341 'location', 

342 'groups', 

343 'events' 

344 ] 

345 

346 device_data = self._router_request( 

347 self._make_request_data( 

348 'getDevices', 

349 dict( 

350 uid=uid, 

351 **kwargs 

352 ) 

353 ) 

354 ) 

355 

356 device_list = dict( 

357 total=device_data['totalCount'], 

358 hash=device_data['hash'], 

359 devices=[], 

360 ) 

361 for device in device_data['devices']: 

362 devinfo = dict() 

363 for key in keys: 

364 if key == "uid": 

365 devinfo['uid'] = device['uid'].replace('/zport/dmd/', '', 1) 

366 elif key == "location": 

367 if device['location']: 

368 devinfo['location'] = device['location']['name'] 

369 else: 

370 devinfo['location'] = None 

371 else: 

372 devinfo[key] = device[key] 

373 device_list['devices'].append(devinfo) 

374 

375 return device_list 

376 

377 def get_device_uid_by_name(self, device_name): 

378 """ 

379 Get the UID for a device by its name 

380 

381 Arguments: 

382 device_name (str): Name of the device to get the UID for 

383 

384 Returns: 

385 str: UID for the device 

386 """ 

387 device_data = self._router_request( 

388 self._make_request_data( 

389 'getDevices', 

390 dict( 

391 params={'name': device_name}, 

392 keys=['uid'] 

393 ) 

394 ) 

395 ) 

396 

397 if len(device_data['devices']) == 0: 

398 return None 

399 return device_data['devices'][0]['uid'] 

400 

401 def move_devices_by_uid(self, devices, device_class): 

402 """ 

403 Move the devices in the list to a new device class. 

404 

405 Arguments: 

406 devices (list): List of device uids to move 

407 device_class (str): Target device class for the move 

408 

409 Returns: 

410 list(dict(str, str)): List of Job manager info for each device move :: 

411 

412 [{ 

413 'uuid': Job manager uuid for the device move, 

414 'description': Description of the move job, 

415 }] 

416 

417 """ 

418 if not isinstance(devices, list): 

419 raise ZenossAPIClientError( 

420 'Type error: devices to move must be a list') 

421 

422 move_job_data = self._router_request( 

423 self._make_request_data( 

424 'moveDevices', 

425 dict( 

426 uids=devices, 

427 target=device_class, 

428 ), 

429 ) 

430 ) 

431 move_jobs = [] 

432 for mj in move_job_data['new_jobs']: 

433 move_jobs.append(dict( 

434 uuid=mj['uuid'], 

435 description=mj['description'] 

436 )) 

437 

438 return move_jobs 

439 

440 def add_device_class(self, new_class, parent, 

441 description='', connection_info=None): 

442 """ 

443 Add a new device class under a parent path 

444 

445 Arguments: 

446 new_class (str): Name of the device class to add 

447 parent (str): Device class to place the new class under 

448 description (str): Description for the new class 

449 connection_info (list): zProperties that are the credentials for 

450 accessing this device class, e.g. zCommandUsername, 

451 zCommandPassword 

452 

453 Returns: 

454 ZenossDeviceClass: 

455 """ 

456 response_data = self._router_request( 

457 self._make_request_data( 

458 'addDeviceClassNode', 

459 dict( 

460 type='organizer', 

461 contextUid=parent, 

462 id=new_class, 

463 description=description, 

464 connectionInfo=connection_info, 

465 ) 

466 ) 

467 ) 

468 

469 dc_data = self.get_info_by_uid(response_data['nodeConfig']['path']) 

470 return ZenossDeviceClass( 

471 self.api_url, 

472 self.api_headers, 

473 self.ssl_verify, 

474 dc_data['data'] 

475 ) 

476 

477 def lock_devices_by_uid(self, devices, updates=False, deletion=False, 

478 send_event=False): 

479 """ 

480 Lock devices from changes. 

481 

482 Arguments: 

483 devices (list): Uids of the devices to lock 

484 updates (bool): Lock devices from updates 

485 deletion (bool): Lock devices from deletion 

486 send_event (bool): Send an event when an action is blocked by locking 

487 

488 Returns: 

489 str: Response message 

490 """ 

491 response_data = self._router_request( 

492 self._make_request_data( 

493 'lockDevices', 

494 dict( 

495 uids=devices, 

496 hashcheck='', 

497 updates=updates, 

498 deletion=deletion, 

499 sendEvent=send_event, 

500 ) 

501 ) 

502 ) 

503 

504 return response_data['msg'] 

505 

506 def reset_device_ip_addresses_by_uid(self, devices, ip_address=''): 

507 """ 

508 Reset IP addresses of devices, either by DNS lookup or manually 

509 specified address 

510 

511 Arguments: 

512 devices (list): Uids of devices to reset IP address for 

513 ip_address (str): IP address to set device to 

514 """ 

515 response_data = self._router_request( 

516 self._make_request_data( 

517 'resetIp', 

518 dict( 

519 uids=devices, 

520 hashcheck='', 

521 ip=ip_address, 

522 ) 

523 ) 

524 ) 

525 

526 return response_data['msg'] 

527 

528 def set_production_state_by_uids(self, devices, production_state): 

529 """ 

530 Sets the production state of a list of devices. 

531 

532 Arguments: 

533 devices (list): Uids of devices to set production state for 

534 production_state (int): Numeric value of production state to set 

535 

536 Returns: 

537 str: Response message 

538 """ 

539 if production_state not in self.prod_states_by_value: 

540 raise ZenossAPIClientError( 

541 'Production state {0} is not a valid option'.format( 

542 production_state)) 

543 

544 response_data = self._router_request( 

545 self._make_request_data( 

546 'setProductionState', 

547 dict( 

548 uids=devices, 

549 hashcheck='', 

550 prodState=production_state, 

551 ) 

552 ) 

553 ) 

554 

555 return response_data['msg'] 

556 

557 def set_priority_by_uids(self, devices, priority): 

558 """ 

559 Sets the priority of a list of devices 

560 

561 Arguments: 

562 devices (list): Uids of devices to set priority for 

563 priority (int): Numeric value of priority to set 

564 

565 Returns: 

566 str: Response message 

567 """ 

568 if priority not in self.priorities_by_value: 

569 raise ZenossAPIClientError( 

570 "Priority {0} is not a valid option".format( 

571 priority 

572 ) 

573 ) 

574 

575 response_data = self._router_request( 

576 self._make_request_data( 

577 'setPriority', 

578 dict( 

579 uids=devices, 

580 hashcheck='', 

581 priority=priority, 

582 ) 

583 ) 

584 ) 

585 

586 return response_data['msg'] 

587 

588 def set_collector_by_uids(self, devices, collector): 

589 """ 

590 Sets the collector for a list of devices. 

591 

592 Arguments: 

593 devices (list): Uids of the devices to set collector for 

594 collector (str): The collector to set devices to use 

595 

596 Returns: 

597 list(dict(str, str)): List of Job manager info for each device move :: 

598 

599 [{ 

600 'uuid': Job manager uuid for the device move 

601 'description': Description of the move job 

602 }] 

603 

604 """ 

605 collector_job_data = self._router_request( 

606 self._make_request_data( 

607 'setCollector', 

608 dict( 

609 uids=devices, 

610 hashcheck='', 

611 collector=collector, 

612 ) 

613 ) 

614 ) 

615 

616 return dict( 

617 uuid=collector_job_data['new_jobs']['uuid'], 

618 description=collector_job_data['new_jobs']['description'] 

619 ) 

620 

621 def delete_devices_by_uid(self, devices, action, del_events=False, 

622 del_perf=False, **kwargs): 

623 """ 

624 Remove a list of devices from their organizer UID, or delete them 

625 from Zenoss altogether. 

626 

627 Arguments: 

628 devices (list): Uids of devices to remove/delete 

629 action (str): 'remove' to remove the devices from their organizer(see 'uid' below), 

630 'delete' to delete them from Zenoss 

631 del_events (bool): Remove all events for the devices 

632 del_perf (bool): Remove all perf data for the devices 

633 

634 Optional Arguments: 

635 uid (str): If using the 'remove' action this option must be included and should be the uid of the organizer you wish to remove the device from. ie "/zport/dmd/Groups/SOMEGROUP" 

636 

637 Returns: 

638 dict: 

639 """ 

640 if action not in ['remove', 'delete']: 

641 raise ZenossAPIClientError( 

642 "Delete action must be either 'remove' or 'delete'" 

643 ) 

644 

645 response_data = self._router_request( 

646 self._make_request_data( 

647 'removeDevices', 

648 dict( 

649 uids=devices, 

650 hashcheck='', 

651 action=action, 

652 deleteEvents=del_events, 

653 deletePerf=del_perf, 

654 **kwargs 

655 ) 

656 ), 

657 response_timeout=30 

658 ) 

659 

660 return response_data 

661 

662 def _set_components_monitored_by_uids(self, components, monitor=True): 

663 """ 

664 Sets the monitored state for a list of components. 

665 

666 Leaving component methods private for now as manipulating components by uid directly is 

667 cumbersome and likely better achieved using the object methods that reference them. 

668 

669 Arguments: 

670 components (list): Uids of the components to update 

671 monitor (bool): True to monitor, False to stop monitoring 

672 

673 Returns: 

674 str: Response message 

675 """ 

676 response_data = self._router_request( 

677 self._make_request_data( 

678 'setComponentsMonitored', 

679 dict( 

680 uids=components, 

681 hashcheck='', 

682 monitor=monitor, 

683 ) 

684 ) 

685 ) 

686 

687 return response_data['msg'] 

688 

689 def _lock_components_by_uid(self, components, updates=False, deletion=False, 

690 send_event=False): 

691 """ 

692 Lock devices from changes. 

693 

694 Arguments: 

695 components (list): Uids of the components to lock 

696 updates (bool): Lock components from updates 

697 deletion (bool): Lock components from deletion 

698 send_event (bool): Send an event when an action is blocked by locking 

699 

700 Returns: 

701 str: Response message 

702 """ 

703 response_data = self._router_request( 

704 self._make_request_data( 

705 'lockComponents', 

706 dict( 

707 uids=components, 

708 hashcheck='', 

709 updates=updates, 

710 deletion=deletion, 

711 sendEvent=send_event, 

712 ) 

713 ) 

714 ) 

715 

716 return response_data['msg'] 

717 

718 def _delete_components_by_uid(self, components): 

719 """ 

720 Deletes a list of components from a device. 

721 

722 Arguments: 

723 components (list): Uids of the components to delete 

724 

725 Returns: 

726 str: Response message 

727 """ 

728 response_data = self._router_request( 

729 self._make_request_data( 

730 'deleteComponents', 

731 dict( 

732 uids=components, 

733 hashcheck='' 

734 ) 

735 ) 

736 ) 

737 

738 return response_data['msg'] 

739 

740 def get_tree(self, device_class, climb_tree=False, include_details=False): 

741 """ 

742 Get the tree structure of a device class. 

743 

744 Arguments: 

745 device_class (str): Device class to use as the top of the tree 

746 climb_tree (bool): If true will return a different dictionary structure 

747 where each branch is a dictionary and contains helpful metadata as 

748 well as dictionaries for any branches of the tree. This version 

749 ONLY uses dicts. Leaving this to 'False' will return a dictionary 

750 with a structure similar to that found in the standard getTree API call. 

751 include_details (bool): If the climb_tree option is used then the 

752 include_details option may also be specified. If True, the function 

753 returns all data provided by the getTree API method. If False, the 

754 function returns only the tree structure as a dict of dicts. 

755 

756 Returns: 

757 dict: 

758 """ 

759 tree_data = self._router_request( 

760 self._make_request_data( 

761 'getTree', 

762 dict(id=device_class) 

763 ) 

764 ) 

765 

766 if climb_tree is True: 

767 return self._climb_tree(tree_data[0], include_details) 

768 else: 

769 return self._find_nodes_in_tree(tree_data[0]) 

770 

771 def list_collectors(self): 

772 """ 

773 Get the list of collectors. 

774 

775 Returns: 

776 list: 

777 """ 

778 return self._router_request( 

779 self._make_request_data( 

780 'getCollectors', 

781 dict(), 

782 ) 

783 ) 

784 

785 def list_device_classes(self): 

786 """ 

787 Get the list of all device classes. 

788 

789 Returns: 

790 list: 

791 """ 

792 device_classes_data = self._router_request( 

793 self._make_request_data( 

794 'getDeviceClasses', 

795 dict(), 

796 ) 

797 ) 

798 

799 dc_list = [] 

800 for dc in device_classes_data['deviceClasses']: 

801 if len(dc['name']) == 0 or dc['name'] == '/': 

802 continue 

803 dc_list.append('Devices{0}'.format(dc['name'])) 

804 

805 return dc_list 

806 

807 def list_systems(self): 

808 """ 

809 Get the list of all systems. 

810 

811 Returns: 

812 list: 

813 """ 

814 systems_data = self._router_request( 

815 self._make_request_data( 

816 'getSystems', 

817 dict(), 

818 ) 

819 ) 

820 

821 systems = [] 

822 for s in systems_data['systems']: 

823 systems.append(s['name']) 

824 

825 return systems 

826 

827 def list_groups(self): 

828 """ 

829 Get the list of all groups. 

830 

831 Returns: 

832 list: 

833 """ 

834 groups_data = self._router_request( 

835 self._make_request_data( 

836 'getGroups', 

837 dict(), 

838 ) 

839 ) 

840 

841 groups = [] 

842 for g in groups_data['groups']: 

843 groups.append(g['name']) 

844 

845 return groups 

846 

847 def list_locations(self): 

848 """ 

849 Get the list of all locations. 

850 

851 Returns: 

852 list: 

853 """ 

854 location_data = self._router_request( 

855 self._make_request_data( 

856 'getLocations', 

857 dict(), 

858 ) 

859 ) 

860 

861 loci = [] 

862 for l in location_data['locations']: 

863 loci.append(l['name']) 

864 

865 return loci 

866 

867 def get_device_class(self, device_class): 

868 """ 

869 Get a device class 

870 

871 Arguments: 

872 device_class (str): The name of the device class 

873 

874 Returns: 

875 ZenossDeviceClass: 

876 """ 

877 if not device_class.startswith('Devices'): 

878 if device_class.startswith('/'): 

879 device_class = 'Devices{0}'.format(device_class) 

880 else: 

881 device_class = 'Devices/{0}'.format(device_class) 

882 

883 dc_data = self.get_info_by_uid(device_class) 

884 

885 return ZenossDeviceClass( 

886 self.api_url, 

887 self.api_headers, 

888 self.ssl_verify, 

889 dc_data['data'] 

890 ) 

891 

892 def add_comment_by_uid(self, device_uid, comment): 

893 """ 

894 Append a new comment to a device  

895 

896 Arguments: 

897 device_uid (str): The uid of the device to comment on  

898 comment (str): Text of the desired comment 

899 

900 Returns: 

901 str: Response message 

902 """ 

903 

904 # Get existing comments  

905 device = self.get_device_by_uid(device_uid) 

906 if len(device.comments) > 0: 

907 comment = f'{device.comments}\n{comment}' 

908 

909 response_data = self._router_request( 

910 self._make_request_data( 

911 'setInfo', 

912 dict( 

913 uid=device_uid, 

914 comments=comment, 

915 ) 

916 ) 

917 ) 

918 

919 return response_data['success'] 

920 

921 def set_info_by_uid(self, device_uid, property, value): 

922 """ 

923 Set Attributes on a device or device organizer 

924 

925 Arguments: 

926 device_uid (str): The uid of the device to comment on 

927 property (str): Name of the attribute to set 

928 value (str): Value of the attribute to set 

929 

930 Returns: 

931 str: Response message 

932 """ 

933 

934 response_data = self._router_request( 

935 self._make_request_data( 

936 'setInfo', 

937 {'uid': device_uid, property: value} 

938 ) 

939 ) 

940 

941 return response_data['success'] 

942 

943 

944class ZenossDeviceClass(DeviceRouter): 

945 """ 

946 Class for Zenoss device class objects 

947 """ 

948 

949 def __init__(self, url, headers, ssl_verify, device_class_data): 

950 super(ZenossDeviceClass, self).__init__(url, headers, ssl_verify) 

951 

952 self.uid = device_class_data['uid'].replace('/zport/dmd/', '', 1) 

953 self.name = device_class_data['name'] 

954 self.severity = device_class_data['severity'] 

955 self.id = device_class_data['id'] 

956 self.description = device_class_data['description'] 

957 self.connectionInfo = device_class_data['connectionInfo'] 

958 self.events = device_class_data['events'] 

959 

960 def list_devices(self, params=None, keys=None, start=0, limit=50, 

961 sort='name', dir='ASC'): 

962 """ 

963 List the devices contained in a device class. Supports pagination. 

964 

965 Arguments: 

966 params (dict): Key/value filters for the search, options are 

967 name, ipAddress, deviceClass, or productionState 

968 keys (list): List of keys to return for the devices found 

969 start (int): Offset to start device list from, default 0 

970 limit (int): The number of results to return, default 50 

971 sort (str): Sort key for the list, default is 'name' 

972 dir (str): Sort order, either 'ASC' or 'DESC', default is 'ASC' 

973 

974 Returns: 

975 dict: 

976 """ 

977 if not keys: 

978 keys = [ 

979 'name', 

980 'uid', 

981 'ipAddressString', 

982 'collector', 

983 'productionState', 

984 'priority', 

985 'location', 

986 'groups', 

987 'events' 

988 ] 

989 

990 device_data = self._router_request( 

991 self._make_request_data( 

992 'getDevices', 

993 dict( 

994 uid=self.uid, 

995 params=params, 

996 keys=keys, 

997 start=start, 

998 limit=limit, 

999 sort=sort, 

1000 dir=dir, 

1001 ) 

1002 ) 

1003 ) 

1004 

1005 device_list = dict( 

1006 total=device_data['totalCount'], 

1007 hash=device_data['hash'], 

1008 devices=[], 

1009 ) 

1010 for device in device_data['devices']: 

1011 devinfo = dict() 

1012 for key in keys: 

1013 if key == "uid": 

1014 devinfo['uid'] = device['uid'].replace('/zport/dmd/', '', 1) 

1015 elif key == "location": 

1016 if device['location']: 

1017 devinfo['location'] = device['location']['name'] 

1018 else: 

1019 devinfo['location'] = None 

1020 else: 

1021 devinfo[key] = device[key] 

1022 device_list['devices'].append(devinfo) 

1023 

1024 return device_list 

1025 

1026 def get_devices(self, params=None, start=0, limit=50, sort='name', 

1027 dir='ASC'): 

1028 """ 

1029 Get the devices contained in a device class. Supports pagination. 

1030 

1031 Arguments: 

1032 params (dict): Key/value filters for the search, options are 

1033 name, ipAddress, deviceClass, or productionState 

1034 start (int): Offset to start device list from, default 0 

1035 limit (int): The number of results to return, default 50 

1036 sort (str): Sort key for the list, default is 'name' 

1037 dir (str): Sort order, either 'ASC' or 'DESC', default is 'ASC' 

1038 

1039 Returns: 

1040 dict(int, str, list(ZenossDevice)): :: 

1041 

1042 { 

1043 'total': Total number of devices found 

1044 'hash': Hashcheck to determine if any devices have changed, 

1045 'devices': ZenossDevice objects, 

1046 } 

1047 

1048 """ 

1049 device_data = self._router_request( 

1050 self._make_request_data( 

1051 'getDevices', 

1052 dict( 

1053 uid=self.uid, 

1054 params=params, 

1055 start=start, 

1056 limit=limit, 

1057 sort=sort, 

1058 dir=dir, 

1059 ) 

1060 ) 

1061 ) 

1062 

1063 device_list = dict( 

1064 total=device_data['totalCount'], 

1065 hash=device_data['hash'], 

1066 devices=[] 

1067 ) 

1068 for device in device_data['devices']: 

1069 device_list['devices'].append(self.get_device_by_uid( 

1070 device['uid'].replace('/zport/dmd/', '', 1))) 

1071 

1072 return device_list 

1073 

1074 def get_device(self, device_name): 

1075 """ 

1076 Get a device from the device class 

1077 

1078 Arguments: 

1079 device_name (str): The name of the device to get 

1080 

1081 Returns: 

1082 ZenossDevice: 

1083 """ 

1084 device_uid = '{0}/devices/{1}'.format(self.uid, device_name) 

1085 return self.get_device_by_uid(device_uid) 

1086 

1087 def add_subclass(self, name, description='', connection_info=None): 

1088 """ 

1089 Add a new subclass to the device class. 

1090 

1091 Arguments: 

1092 name (str): Name of the new subclass 

1093 description (str): Description for the new subclass 

1094 connection_info (list): zProperties that represent the credentials 

1095 for access in the subclass 

1096 """ 

1097 return self.add_device_class(name, self.uid, description, 

1098 connection_info) 

1099 

1100 def add_device(self, device_name, title='', ip_address='', location=None, 

1101 systems=None, groups=None, model=False, 

1102 collector='localhost', production_state=500, comments='', 

1103 priority=3, snmp_community='', snmp_port=161, rack_slot='', 

1104 hw_manufacturer='', hw_product_name='', os_manufacturer='', 

1105 os_product_name='', asset_tag='', serial_number='', 

1106 windows_user='', windows_password='', zcommand_user='', 

1107 zcommand_password='', configuration_properties=None, 

1108 custom_properties=None): 

1109 """ 

1110 Add a new device to the device class. 

1111 

1112 Arguments: 

1113 device_name (str): Name of the new device, will be the device id 

1114 title (str): Optional title for the device, default is to match 

1115 the device_name 

1116 ip_address (str): Ip address for the device, default is to derive 

1117 this from DNS based on device_name 

1118 location (str): Location for the device 

1119 systems (list[(str)]: List of systems for the device 

1120 groups (list[(str)]: List of groups for the device 

1121 model (bool): Set to True to model the device automatically after 

1122 creation 

1123 collector (str): Collector to use for the device 

1124 production_state (int): Numerical production state for the device, 

1125 default is 500 (Pre-Production) 

1126 comments (str): Comments for the device 

1127 priority (int): Numerical priority for the device, default 

1128 is 3 (Normal) 

1129 snmp_community (str): SNMP community string for the device 

1130 snmp_port (int): SNMP port for the device 

1131 rack_slot (str): Rack slot description 

1132 hw_manufacturer (str): Hardware manufacturer name, default is to 

1133 derive by modeling 

1134 hw_product_name (str): Hardware product name, default is to 

1135 derive by modeling 

1136 os_manufacturer (str): Operating system developer, default is to 

1137 derive by modeling 

1138 os_product_name (str): Operating system name, default is to 

1139 derive by modeling 

1140 asset_tag (str): Device's inventory asset tag 

1141 serial_number (str): Device's serial number 

1142 windows_user (str): Username for Windows device monitoring 

1143 windows_password (str): Password for the windows_user 

1144 zcommand_user (str): Username for SSH-based monitoring user 

1145 zcommand_password (str): Password for the zcommand_user 

1146 configuration_properties (dict): Key/value pairs for setting 

1147 Configuration Properties for the device 

1148 custom_properties (dict): Key/value pairs for setting Custom 

1149 Properties for the device 

1150 

1151 Returns: 

1152 str: ID of the add device job 

1153 """ 

1154 if not configuration_properties: 

1155 configuration_properties = dict() 

1156 if not custom_properties: 

1157 custom_properties = dict() 

1158 if not systems: 

1159 systems = [] 

1160 if not groups: 

1161 groups = [] 

1162 

1163 job_data = self._router_request( 

1164 self._make_request_data( 

1165 'addDevice', 

1166 dict( 

1167 deviceName=device_name, 

1168 deviceClass=self.uid.replace('Devices', ''), 

1169 title=title, 

1170 snmpCommunity=snmp_community, 

1171 snmpPort=snmp_port, 

1172 manageIp=ip_address, 

1173 locationPath='Locations/{0}'.format(location), 

1174 systemPaths=systems, 

1175 groupPaths=groups, 

1176 model=model, 

1177 collector=collector, 

1178 rackSlot=rack_slot, 

1179 productionState=production_state, 

1180 comments=comments, 

1181 hwManufacturer=hw_manufacturer, 

1182 hwProductName=hw_product_name, 

1183 osManufacturer=os_manufacturer, 

1184 osProductName=os_product_name, 

1185 priority=priority, 

1186 tag=asset_tag, 

1187 serialNumber=serial_number, 

1188 zWinUser=windows_user, 

1189 zWinPassword=windows_password, 

1190 zCommandPassword=zcommand_password, 

1191 zCommandUsername=zcommand_user, 

1192 zProperties=configuration_properties, 

1193 cProperties=custom_properties, 

1194 ) 

1195 ) 

1196 ) 

1197 

1198 return job_data['new_jobs'][0]['uuid'] 

1199 

1200 def list_properties(self, params=None, sort=None, sort_dir='ASC'): 

1201 """ 

1202 List the configuration properties for the device class 

1203 

1204 Arguments: 

1205 params (dict): Search parameters to filter the properties list on. 

1206 sort (str): Sort key for the properties list. 

1207 sort_dir (str): Sort direction, either ASC or DESC 

1208 

1209 Returns: 

1210 dict(int, list(dict)): :: 

1211 

1212 { 

1213 'total': Total count of properties returned. 

1214 'properties': List of properties found. 

1215 } 

1216 

1217 """ 

1218 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

1219 return pr.list_properties(self.uid, params=params, sort=sort, 

1220 sort_dir=sort_dir) 

1221 

1222 def list_local_properties(self): 

1223 """ 

1224 List the locally defined configuration properties for the device class 

1225 

1226 Returns: 

1227 dict(int, list(dict)): :: 

1228 

1229 { 

1230 'total': Total count of properties returned. 

1231 'properties': List of properties found. 

1232 } 

1233 

1234 """ 

1235 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

1236 return pr.list_local_properties(self.uid) 

1237 

1238 def list_custom_properties(self): 

1239 """ 

1240 List the custom properties for the device class 

1241 

1242 Returns: 

1243 dict(int, list(dict)): :: 

1244 

1245 { 

1246 'total': Total count of properties returned. 

1247 'properties': List of properties found. 

1248 } 

1249 

1250 """ 

1251 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

1252 return pr.list_custom_properties(self.uid) 

1253 

1254 def get_properties(self, params=None): 

1255 """ 

1256 Get the configuration properties for the device class 

1257 

1258 Arguments: 

1259 params (dict): Search parameters for filter the properties on. 

1260 

1261 Returns: 

1262 dict(int, list(ZenossProperty)): :: 

1263 

1264 { 

1265 'total': Total count of properties returned. 

1266 'properties': List of ZenossProperty objects. 

1267 } 

1268 

1269 """ 

1270 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

1271 return pr.get_properties(self.uid, params=params) 

1272 

1273 def get_property(self, zproperty): 

1274 """ 

1275 Get a configuration property 

1276 

1277 Arguments: 

1278 zproperty (str): The id of the property to get 

1279 

1280 Returns: 

1281 ZenossProperty: 

1282 """ 

1283 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

1284 return pr.get_property(self.uid, zproperty) 

1285 

1286 def get_custom_properties(self, params=None): 

1287 """ 

1288 Get the cProperties for the device class 

1289 

1290 Arguments: 

1291 params (dict): Search parameters for filter the properties on. 

1292 

1293 Returns: 

1294 dict(int, list(ZenossCustomProperty)): :: 

1295 

1296 { 

1297 'total': Total count of properties returned. 

1298 'properties': List of ZenossCustomProperty objects. 

1299 } 

1300 

1301 """ 

1302 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

1303 return pr.get_custom_properties(self.uid, params=params) 

1304 

1305 def get_custom_property(self, cproperty): 

1306 """ 

1307 Get a custom property for the device class 

1308 

1309 Arguments: 

1310 cproperty (str): ID of the property to get. 

1311 

1312 Returns: 

1313 ZenossCustomProperty: 

1314 """ 

1315 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

1316 return pr.get_custom_property(self.uid, cproperty) 

1317 

1318 def set_property(self, zproperty, value=None): 

1319 """ 

1320 Set the value of a configuration property 

1321 

1322 Arguments: 

1323 zproperty (str): The id of the property to set a value for 

1324 value (str): The value to set for the property 

1325 

1326 Returns: 

1327 bool: 

1328 """ 

1329 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

1330 return pr.set_property_value(self.uid, id=zproperty, value=value) 

1331 

1332 def delete_property(self, zproperty): 

1333 """ 

1334 Delete the locally set value of a property for a device class 

1335 

1336 Arguments: 

1337 zproperty (str): ID of the property to delete. 

1338 

1339 Returns: 

1340 bool: 

1341 """ 

1342 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

1343 return pr.delete_property(self.uid, zproperty) 

1344 

1345 

1346class ZenossDevice(DeviceRouter): 

1347 """ 

1348 Class for Zenoss device objects 

1349 """ 

1350 

1351 def __init__(self, url, headers, ssl_verify, device_data): 

1352 super(ZenossDevice, self).__init__(url, headers, ssl_verify) 

1353 

1354 unneeded_props = ['class_label', 'class_plural_label', 

1355 'class_plural_short_label', 'class_short_label', 

1356 'deviceClass', 'inspector_type', 

1357 'ipAddress', 'meta_type', 'priorityLabel', 

1358 'productionStateLabel', 'pythonClass', 'uuid', ] 

1359 

1360 default_props = ['collector', 'comments', 'description', 'device', 

1361 'deviceConnectionInfo', 'events', 'firstSeen', 

1362 'groups', 'icon', 'id', 'hwManufacturer', 'hwModel', 

1363 'lastChanged', 'lastCollected', 'links', 'locking', 

1364 'memory', 'name', 'osManufacturer', 'osModel', 

1365 'priority', 'productionState', 'rackSlot', 

1366 'serialNumber', 'severity', 'snmpAgent', 

1367 'snmpCommunity', 'snmpContact', 'snmpDescr', 

1368 'snmpLocation', 'snmpSysName', 'snmpVersion', 

1369 'sshLink', 'status', 'systems', 

1370 'tagNumber', 'uptime', ] 

1371 

1372 for i in unneeded_props: 

1373 if i in device_data: 

1374 device_data.pop(i) 

1375 

1376 uid = device_data.pop('uid') 

1377 self.uid = uid.replace('/zport/dmd/', '', 1) 

1378 

1379 location = device_data.pop('location') 

1380 if location: 

1381 self.location = location['name'] 

1382 else: 

1383 self.location = None 

1384 

1385 self.ip_address = device_data.pop('ipAddressString') 

1386 

1387 for prop in default_props: 

1388 setattr(self, prop, device_data.pop(prop)) 

1389 

1390 self.properties = device_data 

1391 self.parent = self.uid.split('/devices/')[0] 

1392 

1393 def list_components(self, meta_type=None, start=0, limit=50, sort='name', 

1394 dir='ASC', keys=None, name=None): 

1395 """ 

1396 Get a list of all the components on a device. Supports pagination. 

1397 

1398 Arguments: 

1399 meta_type (str): Meta type of components to list 

1400 start (int): Offset to start device list from, default 0 

1401 limit (int): The number of results to return, default 50 

1402 sort (str): Sort key for the list, default is 'name' 

1403 dir (str): Sort order, either 'ASC' or 'DESC', default is 'ASC' 

1404 keys (list): Keys to include in the returned data 

1405 name (str): Regular expression pattern to filter on, requries 

1406 the keys parameter 

1407 

1408 Returns: 

1409 dict(int, str, list): :: 

1410 

1411 { 

1412 'total': Total number of components found. 

1413 'hash': Hash check to determine if components have changed 

1414 'components': List of components found 

1415 } 

1416 

1417 """ 

1418 if name and not keys: 

1419 warnings.warn("Filtering by name also requires a list of keys", UserWarning) 

1420 name = None 

1421 

1422 components_data = self._router_request( 

1423 self._make_request_data( 

1424 'getComponents', 

1425 dict( 

1426 uid='/zport/dmd/{0}'.format(self.uid), 

1427 meta_type=meta_type, 

1428 start=start, 

1429 limit=limit, 

1430 sort=sort, 

1431 dir=dir, 

1432 keys=keys, 

1433 name=name, 

1434 ) 

1435 ) 

1436 ) 

1437 

1438 components_list = dict( 

1439 total=components_data['totalCount'], 

1440 hash=components_data['hash'], 

1441 components=[], 

1442 ) 

1443 

1444 for c in components_data['data']: 

1445 components_list['components'].append( 

1446 c['uid'].split('/{0}/'.format(self.id))[-1]) 

1447 

1448 return components_list 

1449 

1450 def get_components(self, meta_type=None, start=0, limit=50, sort='name', 

1451 dir='ASC'): 

1452 """ 

1453 Get component objects for all components on the device. 

1454 Supports Pagination. 

1455 

1456 Arguments: 

1457 meta_type (str): Meta type of components to list 

1458 start (int): Offset to start device list from, default 0 

1459 limit (int): The number of results to return, default 50 

1460 sort (str): Sort key for the list, default is 'name' 

1461 dir (str): Sort order, either 'ASC' or 'DESC', default is 'ASC' 

1462 

1463 Returns: 

1464 list(ZenossComponent): 

1465 """ 

1466 components_list = self.list_components(meta_type=meta_type, start=start, 

1467 limit=limit, sort=sort, dir=dir) 

1468 

1469 components = [] 

1470 for component in components_list['components']: 

1471 c_info = self.get_info_by_uid( 

1472 '{0}/{1}'.format(self.uid, component)) 

1473 components.append( 

1474 ZenossComponent( 

1475 self.api_url, 

1476 self.api_headers, 

1477 self.ssl_verify, 

1478 c_info['data'] 

1479 ) 

1480 ) 

1481 

1482 return components 

1483 

1484 def get_component(self, component): 

1485 """ 

1486 Get a component object. 

1487 

1488 Arguments: 

1489 component (str): Name of the component, e.g. 'hw/cpus/0' 

1490 

1491 Returns: 

1492 ZenossComponent: 

1493 """ 

1494 c_info = self.get_info_by_uid('{0}/{1}'.format(self.uid, component)) 

1495 

1496 return ZenossComponent( 

1497 self.api_url, 

1498 self.api_headers, 

1499 self.ssl_verify, 

1500 c_info['data'] 

1501 ) 

1502 

1503 def list_user_commands(self): 

1504 """ 

1505 Get the list of user commands for a device. 

1506 

1507 Returns: 

1508 dict(str, str): :: 

1509 

1510 { 

1511 name: Name of the user command 

1512 description: Command description 

1513 } 

1514 

1515 """ 

1516 uc_data = self._router_request( 

1517 self._make_request_data( 

1518 'getUserCommands', 

1519 dict(uid=self.uid), 

1520 ) 

1521 ) 

1522 

1523 user_commands = [] 

1524 for uc in uc_data: 

1525 user_commands.append( 

1526 dict( 

1527 name=uc['id'], 

1528 description=uc['description'] 

1529 )) 

1530 

1531 return user_commands 

1532 

1533 def list_local_templates(self): 

1534 """ 

1535 Get the list of monitoring templates defined locally on a device. 

1536 

1537 Returns: 

1538 list: 

1539 """ 

1540 lt_data = self._router_request( 

1541 self._make_request_data( 

1542 'getLocalTemplates', 

1543 dict( 

1544 uid=self.uid, 

1545 query='', 

1546 ), 

1547 ) 

1548 ) 

1549 

1550 local_templates = [] 

1551 for lt in lt_data['data']: 

1552 local_templates.append(lt['uid'].split('/')[-1]) 

1553 

1554 return local_templates 

1555 

1556 def get_local_templates(self): 

1557 """ 

1558 Get ZenossTemplate objects for all locally defined templates. 

1559 

1560 Returns: 

1561 list(ZenossTemplate): 

1562 """ 

1563 lt_list = self.list_local_templates() 

1564 

1565 local_templates = [] 

1566 tr = TemplateRouter(self.api_url, self.api_headers, self.ssl_verify) 

1567 for lt in lt_list: 

1568 local_templates.append( 

1569 tr._get_template_by_uid('{0}/{1}'.format(self.uid, lt)) 

1570 ) 

1571 

1572 return local_templates 

1573 

1574 def add_local_template(self, template): 

1575 """ 

1576 Add a local template to the device. 

1577 

1578 Arguments: 

1579 template (str): Name of the new local template 

1580 """ 

1581 self._router_request( 

1582 self._make_request_data( 

1583 'addLocalTemplate', 

1584 dict( 

1585 deviceUid=self.uid, 

1586 templateId=template, 

1587 ) 

1588 ) 

1589 ) 

1590 

1591 return True 

1592 

1593 def delete_local_template(self, template): 

1594 """ 

1595 Remove a local template from the device. 

1596 

1597 Arguments: 

1598 template (str): Name of the template to remove 

1599 """ 

1600 self._router_request( 

1601 self._make_request_data( 

1602 'removeLocalTemplate', 

1603 dict( 

1604 deviceUid=self.uid, 

1605 templateId=template, 

1606 ) 

1607 ) 

1608 ) 

1609 

1610 return True 

1611 

1612 def list_active_templates(self): 

1613 """ 

1614 Get the list of templates active on a device, both bound and local. 

1615 

1616 Returns: 

1617 list(dict(str, str)): :: 

1618 

1619 { 

1620 'name': Template name, 

1621 'label': Display label for the template, 

1622 } 

1623 

1624 """ 

1625 templates_data = self._router_request( 

1626 self._make_request_data( 

1627 'getTemplates', 

1628 dict(id=self.uid), 

1629 ) 

1630 ) 

1631 

1632 templates = [] 

1633 for t in templates_data: 

1634 templates.append(dict( 

1635 name=t['uid'].split('/')[-1], 

1636 label=t['text']) 

1637 ) 

1638 

1639 return templates 

1640 

1641 def get_active_templates(self): 

1642 """ 

1643 Get ZenossTemplate objects for all active templates on a device. 

1644 

1645 Returns: 

1646 list(ZenossTemplate): 

1647 """ 

1648 templates_data = self._router_request( 

1649 self._make_request_data( 

1650 'getTemplates', 

1651 dict(id=self.uid), 

1652 ) 

1653 ) 

1654 

1655 templates = [] 

1656 tr = TemplateRouter(self.api_url, self.api_headers, self.ssl_verify) 

1657 for t in templates_data: 

1658 tuid = t['uid'].replace('/zport/dmd/', '', 1) 

1659 templates.append( 

1660 tr._get_template_by_uid(tuid) 

1661 ) 

1662 

1663 return templates 

1664 

1665 def list_unbound_templates(self): 

1666 """ 

1667 Get the list of available templates that are not bound to the device. 

1668 

1669 Returns: 

1670 list(dict(str, str)): :: 

1671 

1672 { 

1673 'name': Template name, 

1674 'label': Display label for the template, 

1675 } 

1676 

1677 """ 

1678 templates_data = self._router_request( 

1679 self._make_request_data( 

1680 'getUnboundTemplates', 

1681 dict(uid=self.uid), 

1682 ) 

1683 ) 

1684 

1685 templates = [] 

1686 for t in templates_data['data']: 

1687 templates.append(dict( 

1688 name=t[0], 

1689 label=t[1] 

1690 )) 

1691 

1692 return templates 

1693 

1694 def get_unbound_templates(self): 

1695 """ 

1696 Get ZenossTemplate objects for available templates that are not bound 

1697 to the device. 

1698 

1699 Returns: 

1700 list(ZenossTemplate): 

1701 """ 

1702 ut_list = self.list_unbound_templates() 

1703 find_path = re.compile('[(]([/].*)[)]') 

1704 templates = [] 

1705 tr = TemplateRouter(self.api_url, self.api_headers, self.ssl_verify) 

1706 for t in ut_list: 

1707 m = re.search(find_path, t['label']) 

1708 if m: 

1709 if m.groups()[0] == "/": 

1710 path = '' 

1711 else: 

1712 path = m.groups()[0] 

1713 uid = 'Devices{0}/rrdTemplates/{1}'.format(path, t['name']) 

1714 templates.append( 

1715 tr._get_template_by_uid(uid) 

1716 ) 

1717 

1718 return templates 

1719 

1720 def list_bound_templates(self): 

1721 """ 

1722 Get the list of templates bound to a device, does not include 

1723 local templates. 

1724 

1725 Returns: 

1726 list(dict(str, str)): :: 

1727 

1728 { 

1729 'name': Template name, 

1730 'label': Display label for the template, 

1731 } 

1732 

1733 """ 

1734 templates_data = self._router_request( 

1735 self._make_request_data( 

1736 'getBoundTemplates', 

1737 dict(uid=self.uid), 

1738 ) 

1739 ) 

1740 

1741 templates = [] 

1742 for t in templates_data['data']: 

1743 templates.append(dict( 

1744 name=t[0], 

1745 label=t[1] 

1746 )) 

1747 

1748 return templates 

1749 

1750 def get_bound_templates(self): 

1751 """ 

1752 Get ZenossTemplate objects templates that are bound to the device. 

1753 

1754 Returns: 

1755 list(ZenosTemplate): 

1756 """ 

1757 bt_list = self.list_bound_templates() 

1758 find_path = re.compile('[(]([/].*)[)]') 

1759 templates = [] 

1760 tr = TemplateRouter(self.api_url, self.api_headers, self.ssl_verify) 

1761 for t in bt_list: 

1762 m = re.search(find_path, t['label']) 

1763 if m: 

1764 if m.groups()[0] == "/": 

1765 path = '' 

1766 else: 

1767 path = m.groups()[0] 

1768 if path.endswith(self.name): 

1769 path = path.replace(self.name, 

1770 'devices/{0}'.format(self.name)) 

1771 uid = 'Devices{0}/{1}'.format(path, t['name']) 

1772 else: 

1773 uid = 'Devices{0}/rrdTemplates/{1}'.format(path, t['name']) 

1774 templates.append( 

1775 tr._get_template_by_uid(uid) 

1776 ) 

1777 

1778 return templates 

1779 

1780 def list_overridable_templates(self): 

1781 """ 

1782 Get the list of available templates on a device that can be overridden. 

1783 

1784 Returns: 

1785 list(dict(str, str)): :: 

1786 

1787 { 

1788 'name': Template name, 

1789 'label': Display label for the template, 

1790 } 

1791 

1792 """ 

1793 template_data = self._router_request( 

1794 self._make_request_data( 

1795 'getOverridableTemplates', 

1796 dict( 

1797 uid=self.uid, 

1798 query='', 

1799 ), 

1800 ) 

1801 ) 

1802 

1803 templates = [] 

1804 for t in template_data['data']: 

1805 templates.append(dict( 

1806 name=t['uid'].split('/')[-1], 

1807 label=t['label']) 

1808 ) 

1809 

1810 return templates 

1811 

1812 def get_overridable_templates(self): 

1813 """ 

1814 Get ZenossTemplate objects for templates that can be overridden. 

1815 

1816 Returns: 

1817 list(ZenossTemplate): 

1818 """ 

1819 template_data = self._router_request( 

1820 self._make_request_data( 

1821 'getOverridableTemplates', 

1822 dict( 

1823 uid=self.uid, 

1824 query='', 

1825 ) 

1826 ) 

1827 ) 

1828 

1829 templates = [] 

1830 tr = TemplateRouter(self.api_url, self.api_headers, self.ssl_verify) 

1831 for t in template_data['data']: 

1832 templates.append( 

1833 tr._get_template_by_uid(t['uid'].replace('/zport/dmd/', '', 1)) 

1834 ) 

1835 

1836 return templates 

1837 

1838 def set_bound_templates(self, templates): 

1839 """ 

1840 Set a list of templates as bound to a device. 

1841 

1842 Arguments: 

1843 templates (list): List of template names 

1844 """ 

1845 self._router_request( 

1846 self._make_request_data( 

1847 'setBoundTemplates', 

1848 dict( 

1849 uid=self.uid, 

1850 templateIds=templates, 

1851 ) 

1852 ) 

1853 ) 

1854 

1855 return True 

1856 

1857 def bind_or_unbind_template(self, path, template): 

1858 """ 

1859 Binds a template to the device if it's unbound, or unbinds it if 

1860 it's bound. 

1861 

1862 Arguments: 

1863 path (str): Template's path, as given in the display label 

1864 template (str): Name of the template to bind/unbind 

1865 """ 

1866 self._router_request( 

1867 self._make_request_data( 

1868 'bindOrUnbindTemplate', 

1869 dict( 

1870 uid=self.uid, 

1871 templateUid='Devices{0}/rrdtemplates/{1}'.format(path, 

1872 template) 

1873 ) 

1874 ) 

1875 ) 

1876 

1877 return True 

1878 

1879 def reset_bound_templates(self): 

1880 """ 

1881 Remove all bound templates from device. 

1882 """ 

1883 self._router_request( 

1884 self._make_request_data( 

1885 'resetBoundTemplates', 

1886 dict(uid=self.uid) 

1887 ) 

1888 ) 

1889 

1890 return True 

1891 

1892 def move(self, device_class): 

1893 """ 

1894 Move the device to a different device class 

1895 

1896 Arguments: 

1897 device_class (str): Name of the device class to move the device into 

1898 

1899 Returns: 

1900 str: uuid of the Job Manager job for the move 

1901 """ 

1902 job_data = self.move_devices_by_uid([self.uid], device_class) 

1903 return job_data[0]['uuid'] 

1904 

1905 def reidentify(self, new_id): 

1906 """ 

1907 Change the device's id in Zenoss. Note that changing the device id will 

1908 cause the loss of all graph data for the device. 

1909 

1910 Arguments: 

1911 new_id (str): New ID for the device 

1912 """ 

1913 return_data = self._router_request( 

1914 self._make_request_data( 

1915 'renameDevice', 

1916 dict( 

1917 uid=self.uid, 

1918 newId=new_id, 

1919 ), 

1920 ) 

1921 ) 

1922 

1923 self.id = new_id 

1924 self.name = new_id 

1925 self.uid = '{0}/devices/{1}'.format(self.parent, self.uid) 

1926 

1927 return True 

1928 

1929 def lock(self, updates=False, deletion=False, send_event=False): 

1930 """ 

1931 Lock the device for changes. 

1932 

1933 Arguments: 

1934 updates (bool): Lock for updates 

1935 deletion (bool): Lock for deletion 

1936 send_event (bool): Send an event when an action is blocked by locking 

1937 

1938 Returns: 

1939 str: Response message 

1940 """ 

1941 return self.lock_devices_by_uid([self.uid], updates=updates, 

1942 deletion=deletion, 

1943 send_event=send_event) 

1944 

1945 def lock_for_updates(self, send_event=False): 

1946 """ 

1947 Lock the device for updates. 

1948 

1949 Arguments: 

1950 send_event (bool): Send an event when updates are blocked by locking 

1951 

1952 Returns: 

1953 str: Response message 

1954 """ 

1955 return self.lock(updates=True, send_event=send_event) 

1956 

1957 def lock_for_deletion(self, send_event=False): 

1958 """ 

1959 Lock the device for updates. 

1960 

1961 Arguments: 

1962 send_event (bool): Send an event when deletion is blocked by locking 

1963 

1964 Returns: 

1965 str: Response message 

1966 """ 

1967 return self.lock(deletion=True, send_event=send_event) 

1968 

1969 def reset_ip_address(self, ip_address=''): 

1970 """ 

1971 Reset the IP address of the device to ip_address if specified or to the 

1972 result of a DNS lookup if not. 

1973 

1974 Arguments: 

1975 ip_address (str): IP address to set device to 

1976 

1977 Returns: 

1978 str: Response message 

1979 """ 

1980 return self.reset_device_ip_addresses_by_uid([self.uid], 

1981 ip_address=ip_address) 

1982 

1983 def set_production_state(self, production_state): 

1984 """ 

1985 Set the production state for the device. 

1986 

1987 Arguments: 

1988 production_state (int): Numeric value for the desired production 

1989 state. 

1990 

1991 Returns: 

1992 str: Response message 

1993 """ 

1994 message = self.set_production_state_by_uids([self.uid], 

1995 production_state) 

1996 self.productionState = production_state 

1997 return message 

1998 

1999 def set_priority(self, priority): 

2000 """ 

2001 Set the priority for the device. 

2002 

2003 Arguments: 

2004 priority (int): Numeric value for the desired priority 

2005 

2006 Returns: 

2007 str: Reponse message 

2008 """ 

2009 message = self.set_priority_by_uids([self.uid], priority) 

2010 self.priority = priority 

2011 return message 

2012 

2013 def add_comment(self, comment): 

2014 """ 

2015 Append a comment to a device. 

2016 

2017 Arguments: 

2018 comment (str): Desired comment text 

2019 

2020 Returns: 

2021 str: Reponse message 

2022 """ 

2023 

2024 message = self.add_comment_by_uid(self.uid, comment) 

2025 if len(self.comments) > 0: 

2026 self.comments = f'{self.comments}\n{comment}' 

2027 else: 

2028 self.comments = comment 

2029 return message 

2030 

2031 def set_info(self, property, value): 

2032 """ 

2033 Set attribute of a device. DOES NOT update zProps or cProps 

2034 

2035 Arguments: 

2036 property (str): Name of property to set 

2037 value (str): Value to set property to 

2038 

2039 Returns: 

2040 str: Reponse message 

2041 """ 

2042 

2043 message = self.set_info_by_uid(self.uid, property, value) 

2044 return message 

2045 

2046 

2047 def set_collector(self, collector): 

2048 """ 

2049 Set the collector for the device. 

2050 

2051 Arguments: 

2052 collector (str): The collector to use for the device 

2053 

2054 Returns: 

2055 str: uuid of the Job Manager job for the change 

2056 """ 

2057 job_data = self.set_collector_by_uids([self.uid], collector) 

2058 return job_data['uuid'] 

2059 

2060 def delete(self, action, del_events=False, del_perf=True, **kwargs): 

2061 """ 

2062 Remove a device from its organizer, or delete it from Zenoss altogether. 

2063 

2064 Arguments: 

2065 action (str): 'remove' to remove the devices from their organizer(see 'uid' below), 

2066 'delete' to delete them from Zenoss 

2067 del_events (bool): Remove all events for the devices 

2068 del_perf (bool): Remove all perf data for the devices 

2069 

2070 Optional Arguments: 

2071 uid (str): If using the 'remove' action this option must 

2072 be included and should be the uid of the organizer you 

2073 wish to remove the device from. ie "/zport/dmd/Groups/SOMEGROUP" 

2074 

2075 Returns: 

2076 bool: 

2077 """ 

2078 self.delete_devices_by_uid([self.uid], action, del_events, del_perf, **kwargs) 

2079 

2080 return True 

2081 

2082 def remodel(self): 

2083 """ 

2084 Remodel the device. 

2085 

2086 Returns: 

2087 str: uuid of the Job Manager job for the remodel 

2088 """ 

2089 response_data = self._router_request( 

2090 self._make_request_data( 

2091 'remodel', 

2092 dict(deviceUid=self.uid) 

2093 ) 

2094 ) 

2095 

2096 return response_data['jobId'] 

2097 

2098 def list_properties(self, params=None, sort=None, sort_dir='ASC'): 

2099 """ 

2100 List the configuration properties for the device 

2101 

2102 Arguments: 

2103 params (dict): Search parameters to filter the properties list on. 

2104 sort (str): Sort key for the properties list. 

2105 sort_dir (str): Sort direction, either ASC or DESC 

2106 

2107 Returns: 

2108 dict(int, list(dict)): :: 

2109 

2110 { 

2111 'total': Total count of properties returned. 

2112 'properties': List of properties found. 

2113 } 

2114 

2115 """ 

2116 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

2117 return pr.list_properties(self.uid, params=params, sort=sort, 

2118 sort_dir=sort_dir) 

2119 

2120 def list_local_properties(self): 

2121 """ 

2122 List the locally defined configuration properties for the device 

2123 

2124 Returns: 

2125 dict(int, list(dict)): :: 

2126 

2127 { 

2128 'total': Total count of properties returned. 

2129 'properties': List of properties found. 

2130 } 

2131 

2132 """ 

2133 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

2134 return pr.list_local_properties(self.uid) 

2135 

2136 def list_custom_properties(self): 

2137 """ 

2138 List the custom properties for the device 

2139 

2140 Returns: 

2141 dict(int, list(dict)): :: 

2142 

2143 { 

2144 'total': Total count of properties returned. 

2145 'properties': List of properties found. 

2146 } 

2147 

2148 """ 

2149 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

2150 return pr.list_custom_properties(self.uid) 

2151 

2152 def get_properties(self, params=None): 

2153 """ 

2154 Get the configuration properties for the device 

2155 

2156 Arguments: 

2157 params (dict): Search parameters for filter the properties on. 

2158 

2159 Returns: 

2160 dict(int, list(ZenossProperty)): :: 

2161 

2162 { 

2163 'total': Total count of properties returned. 

2164 'properties': List of ZenossProperty objects. 

2165 } 

2166 

2167 """ 

2168 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

2169 return pr.get_properties(self.uid, params=params) 

2170 

2171 def get_property(self, zproperty): 

2172 """ 

2173 Get a configuration property 

2174 

2175 Arguments: 

2176 zproperty (str): The id of the property to get 

2177 

2178 Returns: 

2179 ZenossProperty: 

2180 """ 

2181 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

2182 return pr.get_property(self.uid, zproperty) 

2183 

2184 def get_custom_properties(self, params=None): 

2185 """ 

2186 Get the cProperties for the device 

2187 

2188 Arguments: 

2189 params (dict): Search parameters for filter the properties on. 

2190 

2191 Returns: 

2192 dict(int, list(ZenossCustomProperty)): :: 

2193 

2194 { 

2195 'total': Total count of properties returned. 

2196 'properties': List of ZenossCustomProperty objects. 

2197 } 

2198 

2199 """ 

2200 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

2201 return pr.get_custom_properties(self.uid, params=params) 

2202 

2203 def get_custom_property(self, cproperty): 

2204 """ 

2205 Get a custom property for the device 

2206 

2207 Arguments: 

2208 cproperty (str): ID of the property to get. 

2209 

2210 Returns: 

2211 ZenossCustomProperty: 

2212 """ 

2213 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

2214 return pr.get_custom_property(self.uid, cproperty) 

2215 

2216 def set_property(self, zproperty, value=None): 

2217 """ 

2218 Set the value of a configuration property 

2219 

2220 Arguments: 

2221 zproperty (str): The id of the property to set a value for 

2222 value (str): The value to set for the property 

2223 

2224 Returns: 

2225 bool: 

2226 """ 

2227 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

2228 return pr.set_property_value(self.uid, zproperty, value=value) 

2229 

2230 def delete_property(self, zproperty): 

2231 """ 

2232 Delete the locally set value of a property for a device 

2233 

2234 Arguments: 

2235 zproperty (str): ID of the property to delete. 

2236 

2237 Returns: 

2238 bool: 

2239 """ 

2240 pr = PropertiesRouter(self.api_url, self.api_headers, self.ssl_verify) 

2241 return pr.delete_property(self.uid, zproperty) 

2242 

2243 

2244class ZenossComponent(DeviceRouter): 

2245 """ 

2246 Class for Zenoss component objects 

2247 """ 

2248 

2249 def __init__(self, url, headers, ssl_verify, device_data): 

2250 super(ZenossComponent, self).__init__(url, headers, ssl_verify) 

2251 

2252 unneeded_props = ['class_label', 'class_plural_label', 

2253 'class_plural_short_label', 'class_short_label', 

2254 'inspector_type', 'uuid'] 

2255 

2256 for i in unneeded_props: 

2257 if i in device_data: 

2258 device_data.pop(i) 

2259 

2260 uid = device_data.pop('uid') 

2261 self.uid = uid.replace('/zport/dmd/', '', 1) 

2262 self.description = device_data.pop('description') 

2263 self.device = device_data.pop('device') 

2264 self.deviceName = device_data.pop('deviceName') 

2265 self.events = device_data.pop('events') 

2266 self.icon = device_data.pop('icon') 

2267 self.id = device_data.pop('id') 

2268 self.locking = device_data.pop('locking') 

2269 self.meta_type = device_data.pop('meta_type') 

2270 self.monitor = device_data.pop('monitor') 

2271 self.monitored = device_data.pop('monitored') 

2272 self.name = device_data.pop('name') 

2273 self.pingStatus = device_data.pop('pingStatus') 

2274 self.severity = device_data.pop('severity') 

2275 self.status = device_data.pop('status') 

2276 self.usesMonitorAttribute = device_data.pop('usesMonitorAttribute') 

2277 

2278 self.properties = device_data 

2279 dev_path = self.uid.split('/{0}/'.format(self.device))[0] 

2280 self.parent = '{0}/{1}'.format(dev_path, self.device) 

2281 

2282 def set_monitored(self, monitor=True): 

2283 """ 

2284 Sets the monitored state for the component. 

2285 

2286 Arguments: 

2287 monitor (bool): True to monitor, False to stop monitoring 

2288 

2289 Returns: 

2290 str: Response message 

2291 """ 

2292 return self._set_components_monitored_by_uids([self.uid], monitor) 

2293 

2294 def lock(self, updates=False, deletion=False, send_event=False): 

2295 """ 

2296 Lock the component for changes. 

2297 

2298 Arguments: 

2299 updates (bool): Lock for updates 

2300 deletion (bool): Lock for deletion 

2301 send_event (bool): Send an event when an action is blocked by locking 

2302 

2303 Returns: 

2304 str: Response message 

2305 """ 

2306 return self._lock_components_by_uid([self.uid], updates=updates, 

2307 deletion=deletion, 

2308 send_event=send_event) 

2309 

2310 def lock_for_updates(self, send_event=False): 

2311 """ 

2312 Lock the component for updates. 

2313 

2314 Arguments: 

2315 send_event (bool): Send an event when updates are blocked by locking 

2316 

2317 Returns: 

2318 str: Response message 

2319 """ 

2320 return self.lock(updates=True, send_event=send_event) 

2321 

2322 def lock_for_deletion(self, send_event=False): 

2323 """ 

2324 Lock the component for updates. 

2325 

2326 Arguments: 

2327 send_event (bool): Send an event when deletion is blocked by locking 

2328 

2329 Returns: 

2330 str: Response message 

2331 """ 

2332 return self.lock(deletion=True, send_event=send_event) 

2333 

2334 def delete(self): 

2335 """ 

2336 Delete the component. 

2337 

2338 Returns: 

2339 str: Response message 

2340 """ 

2341 return self._delete_components_by_uid([self.uid])