Changeset 1234
- Timestamp:
- Apr 3, 2017, 3:54:11 PM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
opsi/server/dass-opsi-tools/usr/bin/opsiclient
r1177 r1234 5 5 """ospi-client: performs operation for opsi clients on opsi server via JSON-RPC.""" 6 6 7 from __future__ import print_function 8 7 9 __author__ = "Joerg Steffens" 8 __copyright__ = "Copyright 2012-201 5, dass IT GmbH"10 __copyright__ = "Copyright 2012-2017, dass IT GmbH" 9 11 __license__ = "GPL" 10 __version__ = "1. 1"12 __version__ = "1.2" 11 13 __email__ = "joerg.steffens@dass-it.de" 12 14 … … 19 21 20 22 import argparse 23 from datetime import datetime, timedelta 24 from dateutil import parser as dateparser 21 25 import jsonrpc 22 26 import logging 23 27 import os 24 28 from pprint import pprint, pformat 29 import sys 25 30 import time 26 31 … … 29 34 HelpEpilog="WARNING: python-json-rpc is known to have problems with HTTP proxies. In case of problems, make sure, the environment variables http_proxy and/or https_proxy are *not* set." 30 35 36 class Nrpe: 37 OK = 0 38 WARNING = 1 39 CRITICAL = 2 40 UNKNOWN = 3 41 42 def toString(self, status): 43 if status == self.OK: 44 return 'OK' 45 elif status == self.WARNING: 46 return 'WARNING' 47 elif status == self.CRITICAL: 48 return 'CRITICAL' 49 else: 50 return 'UNKNOWN' 51 52 class Output(Nrpe): 53 def __init__(self, nagios=False): 54 self.nagios = nagios 55 self.result = Nrpe.UNKNOWN 56 self.message = '' 57 58 def setStatus(self, status, message = None): 59 self.result = status 60 if message is not None: 61 self.setMessage(message) 62 63 def setMessage(self, string): 64 self.message = string 65 66 def finalize(self): 67 if self.nagios: 68 print('{0} - {1}'.format(self.toString(self.result), self.message)) 69 sys.exit(self.result) 70 else: 71 print('{0} - {1}'.format(self.toString(self.result), self.message)) 72 return (self.result == Nrpe.OK) 73 31 74 class OpsiRpc: 32 75 … … 35 78 ProductAttributesCopy = ['actionRequest','actionResult','installationStatus','packageVersion','productVersion'] 36 79 37 def __init__(self, urlJsonRpc = UrlJsonRpcDefault, debug=False 80 def __init__(self, urlJsonRpc = UrlJsonRpcDefault, debug=False, nagios=False): 38 81 self.logger=logging.getLogger(__name__) 39 82 self.debug=debug 83 self.nagios=nagios 40 84 self.urlJsonRpc=urlJsonRpc 41 85 self.rpc=jsonrpc.ServiceProxy(self.urlJsonRpc) … … 44 88 45 89 def list(self): 46 print( "\n".join( self.rpc.getClientIds_list() ) ) 47 return True 90 try: 91 print( "\n".join( self.rpc.getClientIds_list() ) ) 92 except jsonrpc.json.JSONDecodeException as e: 93 self.logger.debug( pformat(self.rpc.getClientIds_list()) ) 94 self.logger.exception( "failed" ) 95 return True 48 96 49 97 … … 51 99 return self.rpc.productOnClient_getObjects( [], { "productId": product, "installationStatus": "installed" } ) 52 100 101 def getHardwareSerialNumber(self, src): 102 serialNumbers = self.rpc.auditHardwareOnHost_getHashes( [], {"hostId":src, "hardwareClass":"BIOS", "serialNumber":"*"} ) 103 serialNumbers += self.rpc.auditHardwareOnHost_getHashes( [], {"hostId":src, "hardwareClass":"CHASSIS", "serialNumber":"*"} ) 104 result = set() 105 for i in serialNumbers: 106 if i['serialNumber']: 107 result.add(i['serialNumber']) 108 if len(result) == 1: 109 return result.pop() 110 elif len(result) > 1: 111 self.logger.warning("found more then one serial number") 112 return list(result) 53 113 54 114 def listClients( self, product ): 55 115 if product: 56 116 for client in self.getClientsWithProduct( product ): 57 print client['clientId']117 print(client['clientId']) 58 118 else: 59 119 return self.list() … … 65 125 def info(self, src): 66 126 if not self.exists( src ): 67 print "failed: opsi client", src, "does not exist"127 print("failed: opsi client", src, "does not exist") 68 128 return False 69 print src + ":"129 print(src + ":") 70 130 host = self.rpc.host_getHashes( [], {"id":src} )[0] 71 print " IP:", host["ipAddress"] 72 print " MAC:", host["hardwareAddress"] 73 print " inventory:", host["inventoryNumber"] 74 print " last seen:", host["lastSeen"] 75 print " notes:", host["notes"] 76 print " depot:", self.clientGetDepot( src ) 77 78 print " products:" 131 print(" IP:", host["ipAddress"]) 132 print(" MAC:", host["hardwareAddress"]) 133 print(" inventory:", host["inventoryNumber"]) 134 print(" serial number:", self.getHardwareSerialNumber(src)) 135 print(" last seen:", host["lastSeen"]) 136 print(" notes:", host["notes"]) 137 print(" depot:", self.clientGetDepot(src)) 138 139 print(" products:") 79 140 products = self.getProductOnClient( src, [] ) 80 141 for i in products: 81 print " " + i['productId'] + ":"82 print " " + i['installationStatus'], "(",142 print(" " + i['productId'] + ":") 143 print(" " + i['installationStatus'], "(", end='') 83 144 if i['actionRequest']: 84 print i['actionRequest'],145 print(i['actionRequest'], end='') 85 146 if i['actionProgress']: 86 print i['actionProgress'],87 print ")"88 print " ",147 print(i['actionProgress'], end='') 148 print(")") 149 print(" ", end='') 89 150 pprint( i, indent=8 ) 90 151 return True … … 159 220 def copyClient( self, src, dst, ipAddress = None, hardwareAddress = None, depot = None, description = "", copyProperties = True ): 160 221 161 print "create/update", dst, "from template", src + ":",222 print("create/update", dst, "from template", src + ":", end='') 162 223 obj = { 163 224 "id" : dst, … … 185 246 if copyProperties: 186 247 if self.debug: 187 print "copy product properties"248 print("copy product properties") 188 249 if not depot: 189 250 # get default Properties from Master Depot Server (OpsiConfigserver) 190 251 depot = self.getOpsiConfigserverId() 191 252 self.copyProductPropertyState( src, dst, depot ) 192 print "done"253 print("done") 193 254 return True 194 255 … … 201 262 for i in products_src: 202 263 if self.debug: 203 print i['productId']264 print(i['productId']) 204 265 pprint( i ) 205 266 i['clientId'] = dst … … 230 291 use_default=True 231 292 if self.debug: 232 print i['productId'], "-", i["propertyId"] + ": ", pformat(i["values"]),293 print(i['productId'], "-", i["propertyId"] + ": ", pformat(i["values"]), end='') 233 294 if use_default: 234 print "(use default)"295 print("(use default)") 235 296 else: 236 print "(set, default:", default_value, ")"297 print("(set, default:", default_value, ")") 237 298 if not use_default: 238 299 i['objectId'] = dst … … 269 330 fd.write( ' Address = "' + client['clientId'] + '"' + "\n" ) 270 331 # ipAddress: method host_getObjects [] '{"id":client['clientId']}' 271 #print " # Address =", ipAddress332 #print(" # Address =", ipAddress) 272 333 fd.write( ' Password = "' + properties['filedaemon_full_password'] + '"' + "\n" ) 273 334 try: … … 348 409 return True 349 410 411 def __getVersionString(self, product): 412 return '{productVersion}-{packageVersion}'.format(**product) 413 414 def getProductCurrentVersion(self, productId): 415 products = self.rpc.product_getHashes( [], { 'id': productId } ) 416 if products: 417 return self.__getVersionString(products[0]) 418 else: 419 return None 420 421 def __getClientId(self, d): 422 return d.get("clientId") 423 424 def listInstalled(self, productId): 425 productVersion = self.getProductCurrentVersion(productId) 426 self.logger.debug('version: {0}'.format(productVersion)) 427 products = self.rpc.productOnClient_getHashes( [], { 'productId': productId } ) 428 for i in sorted(products, key=self.__getClientId): 429 i['version'] = self.__getVersionString(i) 430 if i.get('installationStatus') == 'installed': 431 if productVersion != i['version']: 432 i['proposedAction'] = 'update' 433 else: 434 i['proposedAction'] = 'None' 435 print('{clientId}: {version} (proposed action={proposedAction})'.format(**i)) 436 else: 437 i['proposedAction'] = 'install' 438 print('{clientId}: (proposed action={proposedAction})'.format(**i)) 439 self.logger.debug('{clientId}: {actionRequest} {installationStatus} {version}'.format(**i)) 440 #pprint( i, indent=8 ) 441 return True 442 443 def isInstalled(self, clientId, productId): 444 """ 445 CRITICAL: not installed 446 WARNING: installed, but not current version 447 OK: current version is installed 448 UNKNOWN: otherwise 449 """ 450 output = Output(self.nagios) 451 if not self.exists(clientId): 452 output.setMessage("failed: opsi client {0} does not exist".format(clientId)) 453 return output.finalize() 454 productVersion = self.getProductCurrentVersion(productId) 455 if not productVersion: 456 output.setMessage("failed: product {0} does not exist".format(productId)) 457 return output.finalize() 458 self.logger.debug('version: {0}'.format(productVersion)) 459 products = self.rpc.productOnClient_getHashes( [], { "clientId": clientId,'productId': productId } ) 460 if len(products) != 1: 461 print("failed: opsi client ({0}) product ({1}) combination does not exist".format(clientId, productId)) 462 return False 463 for i in sorted(products, key=self.__getClientId): 464 i['version'] = self.__getVersionString(i) 465 if i.get('installationStatus') == 'installed': 466 if productVersion != i['version']: 467 i['proposedAction'] = 'update' 468 output.setStatus(Nrpe.WARNING) 469 else: 470 i['proposedAction'] = 'None' 471 output.setStatus(Nrpe.OK) 472 output.setMessage('{version} (proposed action={proposedAction})'.format(**i)) 473 else: 474 i['proposedAction'] = 'install' 475 output.setStatus(Nrpe.CRITICAL, 'not installed (proposed action={proposedAction})'.format(**i)) 476 self.logger.debug('{clientId}: {actionRequest} {installationStatus} {version}'.format(**i)) 477 return output.finalize() 478 479 480 def clientLastSeen(self, clientId): 481 """ 482 < 1 day: OK 483 < 2 days: WARNING 484 otherwise: CRITICAL 485 """ 486 output = Output(self.nagios) 487 if not self.exists(clientId): 488 output.setMessage("failed: opsi client {0} does not exist".format(clientId)) 489 return output.finalize() 490 host = self.rpc.host_getHashes( [], {"id":clientId} )[0] 491 lastSeen = dateparser.parse(host["lastSeen"]) 492 output.setMessage(str(lastSeen)) 493 diff = datetime.now() - lastSeen 494 output.setMessage('{0} ({1} ago)'.format(str(lastSeen), diff)) 495 if diff < timedelta(1): 496 output.setStatus(Nrpe.OK) 497 elif diff < timedelta(2): 498 output.setStatus(Nrpe.WARNING) 499 else: 500 output.setStatus(Nrpe.CRITICAL) 501 return output.finalize() 502 350 503 351 504 … … 358 511 359 512 parser.add_argument( '--debug', action='store_true', help="enable debugging output" ) 513 parser.add_argument('--nagios', action='store_true', help='output in Nagios NRPE format') 360 514 361 515 parser_url = parser.add_mutually_exclusive_group(required=True) … … 395 549 parser_info = subparsers.add_parser('info', help='print information about a opsi client' ) 396 550 parser_info.add_argument( 'src', help="opsi client" ) 551 552 parser_clientLastSeen = subparsers.add_parser('clientLastSeen', help='print information about a opsi client' ) 553 parser_clientLastSeen.add_argument( 'client', help="opsi client" ) 554 555 parser_listInstalled = subparsers.add_parser('listInstalled', help='check if product is installed on client') 556 parser_listInstalled.add_argument('product', help='opsi product') 557 558 parser_isInstalled = subparsers.add_parser('isInstalled', help='check if product is installed on client') 559 parser_isInstalled.add_argument('client', help='opsi client') 560 parser_isInstalled.add_argument('product', help='opsi product') 397 561 398 562 parser_update = subparsers.add_parser('update', help='update/create a opsi client') … … 422 586 parser.error( "argument --url is required" ) 423 587 424 opsi=OpsiRpc( url, args.debug)588 opsi=OpsiRpc(url, args.debug, args.nagios) 425 589 426 590 result = True … … 443 607 elif args.subcommand == "update": 444 608 result = opsi.updateClient( args.src, None, args.description, args.notes, args.inventory, args.mac, args.ip, args.depot ) 445 else: 446 print "not yet implemented" 609 elif args.subcommand == 'listInstalled': 610 result = opsi.listInstalled(args.product) 611 elif args.subcommand == 'isInstalled': 612 result = opsi.isInstalled(args.client, args.product) 613 elif args.subcommand == 'clientLastSeen': 614 result = opsi.clientLastSeen(args.client) 615 else: 616 print("not yet implemented") 447 617 except IOError as e: 448 618 result = False 449 619 # connection refused 450 print "failed:", e451 452 if args.debug: print result620 print("failed:", e) 621 622 if args.debug: print(result) 453 623 454 624 if result:
Note:
See TracChangeset
for help on using the changeset viewer.