source: opsi/server/dass-opsi-tools/usr/bin/opsiclient@ 1254

Last change on this file since 1254 was 1254, checked in by joergs, on Feb 15, 2021 at 6:34:36 PM

Use tinyrpc instead of jsonrpc.

  • Property svn:executable set to *
File size: 26.4 KB
RevLine 
[1027]1#!/usr/bin/env python
2
[1061]3# -*- coding: utf-8 -*-
4
[1055]5"""ospi-client: performs operation for opsi clients on opsi server via JSON-RPC."""
6
[1234]7from __future__ import print_function
8
[1061]9__author__ = "Joerg Steffens"
[1254]10__copyright__ = "Copyright 2012-2021, dass IT GmbH"
[1055]11__license__ = "GPL"
[1254]12__version__ = "1.3"
[1055]13__email__ = "joerg.steffens@dass-it.de"
14
[1051]15#self.command("opsi-admin -d method host_createOpsiClient "+ \
16 #computername + " null " + "\\'"+description+"\\'" + \
17 #" \\'created by dassadmin\\' " + mac_address + " " + \
18 #ip_address)
19#self.command("opsi-admin -d method configState_create clientconfig.depot.id " + \
[1174]20 #computername + " " + depotName)
21
[1047]22import argparse
[1239]23from datetime import datetime, timedelta
24from dateutil import parser as dateparser
[1110]25import logging
26import os
[1239]27from pprint import pprint, pformat
[1234]28import sys
[1239]29import ssl
[1110]30import time
[1027]31
[1254]32from tinyrpc.protocols.jsonrpc import JSONRPCProtocol
33from tinyrpc.transports.http import HttpPostClientTransport
34from tinyrpc import RPCClient
[1239]35
[1063]36UrlJsonRpc="https://<username>:<password>@opsi:4447/rpc"
[1027]37
[1239]38HelpEpilog="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. It might also be neccesary to set variable PYTHONHTTPSVERIFY=0"
[1063]39
[1234]40class Nrpe:
41 OK = 0
42 WARNING = 1
43 CRITICAL = 2
44 UNKNOWN = 3
45
46 def toString(self, status):
47 if status == self.OK:
48 return 'OK'
49 elif status == self.WARNING:
50 return 'WARNING'
51 elif status == self.CRITICAL:
52 return 'CRITICAL'
53 else:
54 return 'UNKNOWN'
55
56class Output(Nrpe):
57 def __init__(self, nagios=False):
58 self.nagios = nagios
59 self.result = Nrpe.UNKNOWN
60 self.message = ''
61
62 def setStatus(self, status, message = None):
63 self.result = status
64 if message is not None:
65 self.setMessage(message)
66
67 def setMessage(self, string):
68 self.message = string
69
70 def finalize(self):
71 if self.nagios:
72 print('{0} - {1}'.format(self.toString(self.result), self.message))
73 sys.exit(self.result)
74 else:
75 print('{0} - {1}'.format(self.toString(self.result), self.message))
76 return (self.result == Nrpe.OK)
77
[1087]78class OpsiRpc:
79
80 UrlJsonRpcDefault="https://opsi:4447/rpc"
[1174]81
[1087]82 ProductAttributesCopy = ['actionRequest','actionResult','installationStatus','packageVersion','productVersion']
[1174]83
[1234]84 def __init__(self, urlJsonRpc = UrlJsonRpcDefault, debug=False, nagios=False):
[1174]85 self.logger=logging.getLogger(__name__)
[1087]86 self.debug=debug
[1234]87 self.nagios=nagios
[1087]88 self.urlJsonRpc=urlJsonRpc
[1254]89 self.rpc = RPCClient(JSONRPCProtocol(), HttpPostClientTransport(self.urlJsonRpc, verify=False)).get_proxy()
90
[1110]91 self.logger.debug( "initialized: " + self.urlJsonRpc )
[1239]92 self.logger.debug(dir(self.rpc))
[1110]93
[1174]94
[1110]95 def list(self):
[1239]96 exceptions = []
97 if 'jsonrpc' in sys.modules:
98 exceptions = [ jsonrpc.json.JSONDecodeException ]
[1234]99 try:
100 print( "\n".join( self.rpc.getClientIds_list() ) )
[1239]101 except exceptions as e:
[1234]102 self.logger.debug( pformat(self.rpc.getClientIds_list()) )
103 self.logger.exception( "failed" )
104 return True
[1087]105
[1174]106
[1110]107 def getClientsWithProduct( self, product ):
108 return self.rpc.productOnClient_getObjects( [], { "productId": product, "installationStatus": "installed" } )
109
[1234]110 def getHardwareSerialNumber(self, src):
111 serialNumbers = self.rpc.auditHardwareOnHost_getHashes( [], {"hostId":src, "hardwareClass":"BIOS", "serialNumber":"*"} )
112 serialNumbers += self.rpc.auditHardwareOnHost_getHashes( [], {"hostId":src, "hardwareClass":"CHASSIS", "serialNumber":"*"} )
113 result = set()
114 for i in serialNumbers:
115 if i['serialNumber']:
116 result.add(i['serialNumber'])
117 if len(result) == 1:
118 return result.pop()
119 elif len(result) > 1:
120 self.logger.warning("found more then one serial number")
121 return list(result)
[1110]122
123 def listClients( self, product ):
124 if product:
125 for client in self.getClientsWithProduct( product ):
[1234]126 print(client['clientId'])
[1110]127 else:
128 return self.list()
129 return True
[1174]130
[1087]131 def exists(self, src):
132 return len( self.rpc.host_getObjects( [], {"id":src} ) ) == 1
[1174]133
[1087]134 def info(self, src):
135 if not self.exists( src ):
[1234]136 print("failed: opsi client", src, "does not exist")
[1087]137 return False
[1234]138 print(src + ":")
[1087]139 host = self.rpc.host_getHashes( [], {"id":src} )[0]
[1234]140 print(" IP:", host["ipAddress"])
141 print(" MAC:", host["hardwareAddress"])
142 print(" inventory:", host["inventoryNumber"])
143 print(" serial number:", self.getHardwareSerialNumber(src))
144 print(" last seen:", host["lastSeen"])
145 print(" notes:", host["notes"])
146 print(" depot:", self.clientGetDepot(src))
[1174]147
[1234]148 print(" products:")
[1087]149 products = self.getProductOnClient( src, [] )
150 for i in products:
[1234]151 print(" " + i['productId'] + ":")
152 print(" " + i['installationStatus'], "(", end='')
[1087]153 if i['actionRequest']:
[1234]154 print(i['actionRequest'], end='')
[1087]155 if i['actionProgress']:
[1234]156 print(i['actionProgress'], end='')
157 print(")")
158 print(" ", end='')
[1087]159 pprint( i, indent=8 )
160 return True
161
162 def clean(self, src):
163 if not self.exists( src ):
164 return False
165 products = self.rpc.productOnClient_getObjects( [], { 'clientId': src } )
166 self.rpc.productOnClient_deleteObjects( products )
[1088]167
[1109]168 products = self.rpc.productPropertyState_getObjects( [], { 'objectId': src } )
[1088]169 self.rpc.productPropertyState_deleteObjects( products )
[1174]170
[1087]171 if self.debug:
172 pprint( self.getProductOnClient( src ) )
173 return True
[1174]174
175 def getOpsiConfigserverId(self):
176 # there should always be only one OpsiConfigserver
177 opsiConfigservers=self.rpc.host_getHashes( [], { "type": "OpsiConfigserver" } )
178 try:
179 return opsiConfigservers[0]['id']
180 except (KeyError,IndexError) as e:
181 self.logger.error( "failed to retreive OpsiConfigserver" )
182
[1087]183 def createClient(self, name, opsiHostKey, description, notes, hardwareAddress, ipAddress):
[1117]184 # self.rpc.host_createOpsiClient( name, opsiHostKey, description, notes, hardwareAddress, ipAddress )
[1177]185 self.updateClient( name, opsiHostKey, description, notes, None, hardwareAddress, ipAddress )
[1087]186
[1175]187 def deleteClient(self, name):
188 self.rpc.host_delete( name )
189
[1177]190 def updateClient(self, src, opsiHostKey = None, description = None, notes = None, inventoryNumber = None, hardwareAddress = None, ipAddress = None, depot = None ):
[1117]191 obj = {
192 "id" : src,
193 "type" : "OpsiClient",
194 }
195 if opsiHostKey:
196 obj['opsiHostKey'] = opsiHostKey
197 if description:
198 obj['description'] = description
199 if notes:
[1174]200 obj['notes'] = notes
[1177]201 if inventoryNumber:
202 obj['inventoryNumber'] = inventoryNumber
[1117]203 if hardwareAddress:
204 obj['hardwareAddress'] = hardwareAddress
205 if ipAddress:
206 obj['ipAddress'] = ipAddress
207
208 if self.exists( src ):
209 self.rpc.host_updateObject(obj)
210 else:
211 self.rpc.host_insertObject(obj)
[1174]212
[1117]213 if depot:
214 self.clientSetDepot(src,depot)
215 return True
216
[1176]217 def clientGetDepot(self, name):
218 depot = self.rpc.configState_getHashes( [], {
219 "configId": "clientconfig.depot.id",
220 "objectId": name } )
221 try:
222 return depot[0]["values"][0]
223 except (IndexError,KeyError):
224 return self.getOpsiConfigserverId()
[1117]225
[1087]226 def clientSetDepot(self, name, depot):
[1174]227 self.rpc.configState_create( "clientconfig.depot.id", name, depot )
[1087]228
[1088]229 def copyClient( self, src, dst, ipAddress = None, hardwareAddress = None, depot = None, description = "", copyProperties = True ):
[1174]230
[1234]231 print("create/update", dst, "from template", src + ":", end='')
[1087]232 obj = {
233 "id" : dst,
234 "type" : "OpsiClient",
235 "notes" : "copy of " + src,
236 "description" : description,
237 #"inventoryNumber" : "",
238 }
239 if hardwareAddress:
240 obj['hardwareAddress'] = hardwareAddress
241 if ipAddress:
242 obj['ipAddress'] = ipAddress
243
244 if self.exists( dst ):
245 self.rpc.host_updateObject(obj)
246 else:
247 self.rpc.host_insertObject(obj)
[1174]248
[1087]249 if depot:
250 self.clientSetDepot(dst,depot)
[1174]251
[1087]252 if self.debug:
253 pprint( self.getProductOnClient( src ) )
254 self.copyProductOnClient( src, dst )
[1088]255 if copyProperties:
256 if self.debug:
[1234]257 print("copy product properties")
[1174]258 if not depot:
259 # get default Properties from Master Depot Server (OpsiConfigserver)
260 depot = self.getOpsiConfigserverId()
261 self.copyProductPropertyState( src, dst, depot )
[1234]262 print("done")
[1087]263 return True
264
265 def getProductOnClient( self, client, attributes = ProductAttributesCopy ):
266 return self.rpc.productOnClient_getHashes( [], { 'clientId': client } )
[1110]267
[1087]268 def copyProductOnClient( self, src, dst, attributes = ProductAttributesCopy ):
[1088]269 products_src = self.rpc.productOnClient_getHashes( attributes, { 'clientId': src } )
270 products_dst = []
271 for i in products_src:
[1087]272 if self.debug:
[1234]273 print(i['productId'])
[1087]274 pprint( i )
275 i['clientId'] = dst
[1088]276 products_dst.append(i)
277 self.rpc.productOnClient_createObjects( products_dst )
[1087]278 if self.debug:
279 pprint( self.getProductOnClient( dst ) )
[1088]280
[1174]281
[1088]282 def getProductPropertyState( self, client, attributes = [] ):
283 return self.rpc.productPropertyState_getHashes( [], { 'objectId': client } )
[1174]284
285
286 def copyProductPropertyState( self, src, dst, default = None, attributes = [] ):
287 if default:
288 productProperties_default = self.getProductPropertyState( default, attributes )
289 else:
290 productProperties_default = []
[1088]291 productProperties_src = self.getProductPropertyState( src, attributes )
292 productProperties_dst = []
293 for i in productProperties_src:
[1174]294 use_default=False
[1176]295 default_value=None
[1174]296 for j in productProperties_default:
297 if i['productId'] == j['productId'] and i["propertyId"] == j["propertyId"]:
[1176]298 default_value = j['values']
[1174]299 if i['values'] == j['values']:
300 use_default=True
301 if self.debug:
[1234]302 print(i['productId'], "-", i["propertyId"] + ": ", pformat(i["values"]), end='')
[1174]303 if use_default:
[1234]304 print("(use default)")
[1174]305 else:
[1234]306 print("(set, default:", default_value, ")")
[1174]307 if not use_default:
308 i['objectId'] = dst
309 productProperties_dst.append(i)
[1088]310 self.rpc.productPropertyState_createObjects( productProperties_dst )
311 if self.debug:
312 pprint( self.getProductPropertyState( dst ) )
[1110]313
314
315 def getClientProductProperty( self, client, product ):
316 return self.rpc.getProductProperties_hash( product, [ client ] )
317
[1118]318 def setProductPropertiesOnClient( self, dst, product, properties ):
319 self.rpc.setProductProperties(product,properties,dst)
320
321 def setProductPropertyOnClient( self, dst, product, prop, value):
322 self.rpc.setProductProperty(product,prop,value,dst)
323
324
[1239]325
326 def write_value_conf(self, fd, key, properties, default=None):
327 value = None
328 comment = ''
329 try:
330 value = properties[key.lower()]
331 except KeyError:
332 pass
333 if not value and default:
334 value = default
335 if not value:
336 # prevent a None to be written
337 value = ''
338 comment = '# '
339 fd.write(' {}{} = "{}"\n'.format(comment, key, value))
340
341
342
[1110]343 def write_client_conf( self, fd, client, properties ):
344 #Client {
345 #Name = ting-fd
346 #Address = ting.dass-it
347 #FDPort = 9102
[1239]348 #Password = "D5w2V5w6B8a9H5Z"
[1110]349 #Catalog = MyCatalog
350 #File Retention = 6 months
351 #Job Retention = 6 months
352 #AutoPrune = yes
353 #}
[1239]354 params = [ 'catalog', "FDPort", "FileRetention", "JobRetention", "AutoPrune" ]
[1110]355 fd.write( "Client {\n" )
356 fd.write( ' Name = "' + properties['filedaemon_full_name'] + '"' + "\n" )
[1239]357 fd.write( ' Address = "' + properties['filedaemon_client_address'] + '"' + "\n" )
[1110]358 # ipAddress: method host_getObjects [] '{"id":client['clientId']}'
[1234]359 #print(" # Address =", ipAddress)
[1110]360 fd.write( ' Password = "' + properties['filedaemon_full_password'] + '"' + "\n" )
361 for i in params:
[1239]362 self.write_value_conf(fd, i, properties)
[1110]363 fd.write( "}\n")
364 fd.write( "\n" )
[1087]365
366
[1239]367 def write_job_conf(self, fd, client, properties, defaultjobdefs, defaultfileset):
[1110]368 #Job {
369 #FileSet = "tingfileset"
370 #Name = "ting"
371 #Client = ting-fd
372 #JobDefs = "LaptopJob"
373 ## Write Bootstrap = "/var/lib/bacula/ting.bsr"
374 #}
[1239]375 params = [ "JobDefs", "FileSet" ]
[1110]376 fd.write( "Job {" + "\n" )
377 fd.write( ' Name = "' + client['clientId'] + '-job"' + "\n" )
378 fd.write( ' Client = "' + properties['filedaemon_full_name'] + '"' + "\n" )
[1239]379 self.write_value_conf(fd, 'JobDefs', properties, defaultjobdefs)
380 self.write_value_conf(fd, 'FileSet', properties, defaultfileset)
[1110]381 fd.write( "}" + "\n" )
382 fd.write( "\n" )
383
384
385 def write_config_file_header( self, fd ):
[1174]386 try:
[1110]387 fd.write( "#\n" )
[1114]388 fd.write( "# automatically generated at {0}\n".format( time.asctime() ) )
[1110]389 fd.write( "#\n\n" )
[1177]390 except BaseException as e:
[1110]391 self.logger.exception( "failed to create files" )
392 return False
393 return True
394
[1174]395
[1239]396
397 def createBareosConfigFiles(self, defaultjobdefs, defaultfileset):
398 bareosDirConfigPath = '/etc/bareos/bareos-dir.d/'
399 clientsWithBacula=self.getClientsWithProduct('winbareos')
[1110]400 if clientsWithBacula:
401 try:
[1239]402 configfile = bareosDirConfigPath + 'client/opsi-clients-generated.conf'
403 file_opsi_clients = open(configfile, 'w')
[1110]404 self.write_config_file_header( file_opsi_clients )
[1239]405 except (BaseException, IOError) as e:
406 self.logger.exception( "failed to create configuration file {}".format(configfile) )
407 return False
[1174]408
[1239]409 try:
410 configfile = bareosDirConfigPath + 'job/opsi-jobs-generated.conf'
411 file_opsi_jobs = open(configfile, 'w')
[1110]412 self.write_config_file_header( file_opsi_jobs )
[1239]413 except (BaseException, IOError) as e:
414 self.logger.exception( "failed to create configuration file {}".format(configfile) )
[1110]415 return False
[1239]416
[1110]417 for client in clientsWithBacula:
[1174]418 clientId = client['clientId']
[1110]419 try:
[1239]420 clientBaculaProperties=self.getClientProductProperty( clientId, 'winbareos' )
[1110]421 except ValueError as e:
422 self.logger.warn( "%s: no valid information found: %s" %(clientId, e) )
423 else:
424 if clientBaculaProperties:
425 #pprint( clientBaculaProperties )
[1239]426 self.write_client_conf(file_opsi_clients, client, clientBaculaProperties)
427 self.write_job_conf(file_opsi_jobs, client, clientBaculaProperties, defaultjobdefs, defaultfileset)
[1110]428 self.logger.info( "%s: OK" % clientId )
429 else:
430 self.logger.warn( "%s: failed: no product properties defined" %(clientId) )
431 return True
432
[1234]433 def __getVersionString(self, product):
434 return '{productVersion}-{packageVersion}'.format(**product)
[1110]435
[1234]436 def getProductCurrentVersion(self, productId):
437 products = self.rpc.product_getHashes( [], { 'id': productId } )
438 if products:
439 return self.__getVersionString(products[0])
440 else:
441 return None
[1110]442
[1234]443 def __getClientId(self, d):
444 return d.get("clientId")
445
446 def listInstalled(self, productId):
447 productVersion = self.getProductCurrentVersion(productId)
448 self.logger.debug('version: {0}'.format(productVersion))
449 products = self.rpc.productOnClient_getHashes( [], { 'productId': productId } )
450 for i in sorted(products, key=self.__getClientId):
451 i['version'] = self.__getVersionString(i)
452 if i.get('installationStatus') == 'installed':
453 if productVersion != i['version']:
454 i['proposedAction'] = 'update'
455 else:
456 i['proposedAction'] = 'None'
457 print('{clientId}: {version} (proposed action={proposedAction})'.format(**i))
458 else:
459 i['proposedAction'] = 'install'
460 print('{clientId}: (proposed action={proposedAction})'.format(**i))
461 self.logger.debug('{clientId}: {actionRequest} {installationStatus} {version}'.format(**i))
462 #pprint( i, indent=8 )
463 return True
464
465 def isInstalled(self, clientId, productId):
466 """
467 CRITICAL: not installed
468 WARNING: installed, but not current version
469 OK: current version is installed
470 UNKNOWN: otherwise
471 """
472 output = Output(self.nagios)
473 if not self.exists(clientId):
474 output.setMessage("failed: opsi client {0} does not exist".format(clientId))
475 return output.finalize()
476 productVersion = self.getProductCurrentVersion(productId)
477 if not productVersion:
478 output.setMessage("failed: product {0} does not exist".format(productId))
479 return output.finalize()
480 self.logger.debug('version: {0}'.format(productVersion))
481 products = self.rpc.productOnClient_getHashes( [], { "clientId": clientId,'productId': productId } )
482 if len(products) != 1:
483 print("failed: opsi client ({0}) product ({1}) combination does not exist".format(clientId, productId))
484 return False
485 for i in sorted(products, key=self.__getClientId):
486 i['version'] = self.__getVersionString(i)
487 if i.get('installationStatus') == 'installed':
488 if productVersion != i['version']:
489 i['proposedAction'] = 'update'
490 output.setStatus(Nrpe.WARNING)
491 else:
492 i['proposedAction'] = 'None'
493 output.setStatus(Nrpe.OK)
494 output.setMessage('{version} (proposed action={proposedAction})'.format(**i))
495 else:
496 i['proposedAction'] = 'install'
497 output.setStatus(Nrpe.CRITICAL, 'not installed (proposed action={proposedAction})'.format(**i))
498 self.logger.debug('{clientId}: {actionRequest} {installationStatus} {version}'.format(**i))
499 return output.finalize()
500
501
502 def clientLastSeen(self, clientId):
503 """
504 < 1 day: OK
505 < 2 days: WARNING
506 otherwise: CRITICAL
507 """
508 output = Output(self.nagios)
509 if not self.exists(clientId):
510 output.setMessage("failed: opsi client {0} does not exist".format(clientId))
511 return output.finalize()
512 host = self.rpc.host_getHashes( [], {"id":clientId} )[0]
513 lastSeen = dateparser.parse(host["lastSeen"])
514 output.setMessage(str(lastSeen))
515 diff = datetime.now() - lastSeen
516 output.setMessage('{0} ({1} ago)'.format(str(lastSeen), diff))
517 if diff < timedelta(1):
518 output.setStatus(Nrpe.OK)
519 elif diff < timedelta(2):
520 output.setStatus(Nrpe.WARNING)
521 else:
522 output.setStatus(Nrpe.CRITICAL)
523 return output.finalize()
524
525
526
[1047]527if __name__ == '__main__':
[1110]528 logging.basicConfig(format='%(message)s')
529 logger = logging.getLogger(__name__)
530 logger.setLevel(logging.INFO)
531
[1239]532 parser = argparse.ArgumentParser(
533 description='Command line tool for OPSI configuration.',
534 epilog=HelpEpilog
535 )
[1063]536
[1047]537 parser.add_argument( '--debug', action='store_true', help="enable debugging output" )
[1234]538 parser.add_argument('--nagios', action='store_true', help='output in Nagios NRPE format')
[1028]539
[1110]540 parser_url = parser.add_mutually_exclusive_group(required=True)
541 parser_url.add_argument( '--url', help="OPSI Server JSON-RPC url, in following format: " + UrlJsonRpc )
542
543 parser_url.add_argument( '--server', help="OPSI Server (instead of URL)" )
544 username_default=os.getlogin()
545
546 parser.add_argument( '--username', help="username (instead of URL), default: " + username_default, default=username_default )
547 parser.add_argument( '--password', help="password (instead of URL)" )
548
[1050]549 subparsers = parser.add_subparsers(title='subcommands',
550 description='valid subcommands',
551 help='additional help',
552 dest='subcommand' )
[1047]553
[1050]554 parser_clean = subparsers.add_parser('clean', help='remove all product states from a opsi client' )
555 parser_clean.add_argument( 'src', help="source opsi client to clean" )
[1174]556
557 parser_copy = subparsers.add_parser('copy', help='copy/create a opsi client from a template opsi client')
[1050]558 parser_copy.add_argument( 'src', help="source/template opsi client" )
559 parser_copy.add_argument( 'dst', help="opsi client to be created" )
560 parser_copy.add_argument( '--ip', help="IP address of the new opsi client" )
561 parser_copy.add_argument( '--mac', help="MAC address of the new opsi client" )
562 parser_copy.add_argument( '--depot', help="depot server the new opsi client should be located" )
[1088]563 #parser_copy.add_argument( '--no-properties', action='store_false', help="don't copy product properties" )
[1174]564
[1239]565 parser_createBareosConfigFiles = subparsers.add_parser(
566 'createBareosConfigFiles',
567 help='create Bareos config files for all clients that have winbareos installed',
568 formatter_class=argparse.ArgumentDefaultsHelpFormatter
569 )
570 parser_createBareosConfigFiles.add_argument(
571 '--defaultjobdefs',
572 metavar='JobDefs',
573 default='DefaultJob',
574 help="use this JobDefs if no other is defined for a client"
575 )
576 parser_createBareosConfigFiles.add_argument(
577 '--defaultfileset',
578 metavar='FileSet',
579 help="use this FileSet if no other is defined for a client"
580 )
[1110]581
582 parser_exists = subparsers.add_parser('exists', help='check, if a opsi clients exists' )
583 parser_exists.add_argument( 'src', help="source opsi client" )
584 #parser_list = subparsers.add_parser('list', help='list all opsi clients' )
[1174]585
[1110]586 parser_listClients = subparsers.add_parser('listClients', help='list opsi clients')
587 parser_listClients.add_argument( '--product', help="only list clients, that have product installed" )
[1174]588
[1110]589 parser_info = subparsers.add_parser('info', help='print information about a opsi client' )
590 parser_info.add_argument( 'src', help="opsi client" )
[1234]591
592 parser_clientLastSeen = subparsers.add_parser('clientLastSeen', help='print information about a opsi client' )
593 parser_clientLastSeen.add_argument( 'client', help="opsi client" )
[1174]594
[1234]595 parser_listInstalled = subparsers.add_parser('listInstalled', help='check if product is installed on client')
596 parser_listInstalled.add_argument('product', help='opsi product')
597
598 parser_isInstalled = subparsers.add_parser('isInstalled', help='check if product is installed on client')
599 parser_isInstalled.add_argument('client', help='opsi client')
600 parser_isInstalled.add_argument('product', help='opsi product')
601
[1117]602 parser_update = subparsers.add_parser('update', help='update/create a opsi client')
[1177]603 parser_update.add_argument( 'src', help="opsi client to be created/updated" )
604 parser_update.add_argument( '--ip', help="IP address of the opsi client" )
605 parser_update.add_argument( '--mac', help="MAC address of the opsi client" )
606 parser_update.add_argument( '--description', help="a description of the client" )
607 parser_update.add_argument( '--notes', help="notes about the client" )
608 parser_update.add_argument( '--inventory', help="inventory number" )
609 parser_update.add_argument( '--depot', help="depot server the opsi client should be located" )
610
[1047]611 args = parser.parse_args()
[1177]612
[1110]613 if args.debug:
614 logger.setLevel(logging.DEBUG)
615
616 url=args.url
617 if (not url):
618 if args.server:
619 account=""
620 if args.username and args.password:
621 account=args.username + ":" + args.password + "@"
622 elif args.username:
623 account=args.username + "@"
624 url="https://" + account + args.server + ":4447/rpc"
625 else:
626 parser.error( "argument --url is required" )
[1174]627
[1234]628 opsi=OpsiRpc(url, args.debug, args.nagios)
[1174]629
[1051]630 result = True
631
[1174]632 try:
633 if args.subcommand == "clean":
634 result = opsi.clean( args.src )
635 elif args.subcommand == "copy":
636 result = opsi.copyClient( args.src, args.dst, args.ip, args.mac, args.depot )
[1239]637 elif args.subcommand == "createBareosConfigFiles":
638 result = opsi.createBareosConfigFiles(args.defaultjobdefs, args.defaultfileset)
[1174]639 elif args.subcommand == "exists":
640 result = opsi.exists( args.src )
641 elif args.subcommand == "list":
642 result = opsi.list()
643 elif args.subcommand == "listClients":
644 result = opsi.listClients( args.product )
645 elif args.subcommand == "info":
646 result = opsi.info( args.src )
647 elif args.subcommand == "update":
[1177]648 result = opsi.updateClient( args.src, None, args.description, args.notes, args.inventory, args.mac, args.ip, args.depot )
[1234]649 elif args.subcommand == 'listInstalled':
650 result = opsi.listInstalled(args.product)
651 elif args.subcommand == 'isInstalled':
652 result = opsi.isInstalled(args.client, args.product)
653 elif args.subcommand == 'clientLastSeen':
654 result = opsi.clientLastSeen(args.client)
[1174]655 else:
[1234]656 print("not yet implemented")
[1174]657 except IOError as e:
658 result = False
659 # connection refused
[1234]660 print("failed:", e)
[1050]661
[1234]662 if args.debug: print(result)
[1174]663
[1051]664 if result:
665 exit(0)
666 else:
667 exit(1)
Note: See TracBrowser for help on using the repository browser.