| [1027] | 1 | #!/usr/bin/env python
 | 
|---|
 | 2 | 
 | 
|---|
| [1055] | 3 | """ospi-client: performs operation for opsi clients on opsi server via JSON-RPC."""
 | 
|---|
 | 4 | 
 | 
|---|
 | 5 | __author__ = "Jörg Steffens"
 | 
|---|
 | 6 | __copyright__ = "Copyright 2012, dass IT GmbH"
 | 
|---|
 | 7 | __license__ = "GPL"
 | 
|---|
 | 8 | __version__ = "1.0"
 | 
|---|
 | 9 | __email__ = "joerg.steffens@dass-it.de"
 | 
|---|
 | 10 | 
 | 
|---|
 | 11 | # 
 | 
|---|
| [1051] | 12 | # Skript, dass ein OPSI-Rechner-Eintrag kopiert.
 | 
|---|
| [1046] | 13 | # D.h. die Produkte, Anforderung.
 | 
|---|
 | 14 | # Ggf. optional Stand und ggf. Versionsnummer
 | 
|---|
 | 15 | # Ggf. optional ProductProperties
 | 
|---|
| [1055] | 16 | #
 | 
|---|
| [1027] | 17 | 
 | 
|---|
| [1051] | 18 | #self.command("opsi-admin -d method host_createOpsiClient "+ \
 | 
|---|
 | 19 |         #computername + " null " + "\\'"+description+"\\'" + \
 | 
|---|
 | 20 |         #" \\'created by dassadmin\\' " + mac_address + " " + \
 | 
|---|
 | 21 |         #ip_address)
 | 
|---|
 | 22 | #self.command("opsi-admin -d method configState_create clientconfig.depot.id " + \
 | 
|---|
 | 23 |         #computername + " " + depotName)                        
 | 
|---|
| [1047] | 24 |                         
 | 
|---|
 | 25 | import argparse
 | 
|---|
| [1046] | 26 | import jsonrpc
 | 
|---|
| [1027] | 27 | from pprint import pprint
 | 
|---|
 | 28 | 
 | 
|---|
| [1053] | 29 | UrlJsonRpc="https://<USERNAME>:<PASSWORD>@opsi:4447/rpc"
 | 
|---|
| [1027] | 30 | 
 | 
|---|
| [1046] | 31 | class OpsiRpc:
 | 
|---|
| [1047] | 32 |     
 | 
|---|
 | 33 |     ProductAttributesCopy = ['actionRequest','actionResult','installationStatus','packageVersion','productVersion']
 | 
|---|
 | 34 |     
 | 
|---|
 | 35 |     def __init__(self, urlJsonRpc, debug=False ):
 | 
|---|
 | 36 |         self.debug=debug
 | 
|---|
| [1046] | 37 |         self.urlJsonRpc=urlJsonRpc
 | 
|---|
| [1047] | 38 |         self.rpc=jsonrpc.ServiceProxy(self.urlJsonRpc)
 | 
|---|
| [1046] | 39 |         
 | 
|---|
 | 40 |     def dump(self):
 | 
|---|
 | 41 |         print self.urlJsonRpc
 | 
|---|
| [1047] | 42 |         print self.rpc.getClientIds_list()
 | 
|---|
| [1051] | 43 | 
 | 
|---|
 | 44 |     def list(self):
 | 
|---|
 | 45 |         return self.rpc.getClientIds_list()
 | 
|---|
| [1046] | 46 |         
 | 
|---|
| [1051] | 47 |     def exists(self, src):
 | 
|---|
 | 48 |         return len( self.rpc.host_getObjects( [], {"id":src} ) ) == 1
 | 
|---|
 | 49 |         
 | 
|---|
 | 50 |     def info(self, src):
 | 
|---|
 | 51 |         if not self.exists( src ):
 | 
|---|
 | 52 |             print "failed: opsi client", src, "does not exist"
 | 
|---|
 | 53 |             return False
 | 
|---|
 | 54 |         print src + ":"
 | 
|---|
| [1052] | 55 |         host = self.rpc.host_getHashes( [], {"id":src} )[0]
 | 
|---|
 | 56 |         print "  IP:", host["ipAddress"]
 | 
|---|
 | 57 |         print "  MAC:", host["hardwareAddress"]
 | 
|---|
 | 58 |         print "  inventory:", host["inventoryNumber"]
 | 
|---|
 | 59 |         print "  last seen:", host["lastSeen"]
 | 
|---|
 | 60 |         print "  notes:", host["notes"]
 | 
|---|
 | 61 |         
 | 
|---|
 | 62 |         print "  products:"
 | 
|---|
| [1051] | 63 |         products = self.getProductOnClient( src, [] )
 | 
|---|
 | 64 |         for i in products:
 | 
|---|
| [1052] | 65 |             print "    " + i['productId'] + ":"
 | 
|---|
 | 66 |             print "      " + i['installationStatus'], "(",
 | 
|---|
 | 67 |             if i['actionRequest']:
 | 
|---|
 | 68 |                 print i['actionRequest'],
 | 
|---|
 | 69 |                 if i['actionProgress']:
 | 
|---|
 | 70 |                     print i['actionProgress'],
 | 
|---|
 | 71 |             print ")"
 | 
|---|
 | 72 |             print "      ",
 | 
|---|
 | 73 |             pprint( i, indent=8 )
 | 
|---|
| [1051] | 74 |         return True
 | 
|---|
 | 75 | 
 | 
|---|
 | 76 |     def clean(self, src):
 | 
|---|
 | 77 |         if not self.exists( src ):
 | 
|---|
 | 78 |             return False
 | 
|---|
 | 79 |         products = self.rpc.productOnClient_getObjects( [], { 'clientId': src } )
 | 
|---|
 | 80 |         self.rpc.productOnClient_deleteObjects( products )
 | 
|---|
 | 81 |         if self.debug:
 | 
|---|
 | 82 |             pprint( self.getProductOnClient( src ) )
 | 
|---|
 | 83 |         return True
 | 
|---|
 | 84 |         
 | 
|---|
| [1047] | 85 |     def copyClient( self, src, dst, ipAddress = None, hardwareAddress = None, depot = None ):
 | 
|---|
| [1028] | 86 |     
 | 
|---|
| [1047] | 87 |         print "create/update", dst, "from template", src + ":",
 | 
|---|
| [1046] | 88 |         #method host_createOpsiClient id *opsiHostKey *description *notes *hardwareAddress *ipAddress *inventoryNumber *oneTimePassword *created *lastSeen
 | 
|---|
| [1047] | 89 |         #id=dst
 | 
|---|
| [1046] | 90 |         opsiHostKey=None
 | 
|---|
 | 91 |         description=""
 | 
|---|
 | 92 |         notes="copy of " + src
 | 
|---|
| [1047] | 93 |         self.rpc.host_createOpsiClient( dst, opsiHostKey, description, notes, hardwareAddress, ipAddress )
 | 
|---|
 | 94 |         if depot:
 | 
|---|
 | 95 |             self.rpc.configState_create( "clientconfig.depot.id", dst, depot )        
 | 
|---|
 | 96 |         if self.debug:
 | 
|---|
| [1051] | 97 |             pprint( self.getProductOnClient( src ) )
 | 
|---|
| [1047] | 98 |         self.copyProductOnClient( src, dst )
 | 
|---|
 | 99 |         # TODO: 
 | 
|---|
 | 100 |         #  copy product properties:
 | 
|---|
 | 101 |         #  opsiCallClientBaculaProperties=[ "method", "getProductProperties_hash", "bacula" ]
 | 
|---|
 | 102 |         print "done"
 | 
|---|
| [1052] | 103 |         return True
 | 
|---|
| [1047] | 104 | 
 | 
|---|
| [1046] | 105 |         
 | 
|---|
| [1051] | 106 |     def getProductOnClient( self, client, attributes = ProductAttributesCopy ):
 | 
|---|
| [1047] | 107 |         #pprint( self.rpc.productOnClient_getObjects( [], { 'clientId': client } ) )
 | 
|---|
 | 108 |         #pprint( self.rpc.productOnClient_getHashes( attributes, { 'clientId': client } ) )
 | 
|---|
| [1051] | 109 |         return self.rpc.productOnClient_getHashes( [], { 'clientId': client } )
 | 
|---|
| [1047] | 110 |         
 | 
|---|
 | 111 |     def copyProductOnClient( self, src, dst, attributes = ProductAttributesCopy ):
 | 
|---|
 | 112 |         products = self.rpc.productOnClient_getHashes( attributes, { 'clientId': src } )
 | 
|---|
 | 113 |         for i in products:
 | 
|---|
 | 114 |             if self.debug: 
 | 
|---|
| [1051] | 115 |                 print i['productId']
 | 
|---|
| [1047] | 116 |                 pprint( i )
 | 
|---|
 | 117 |             i['clientId'] = dst
 | 
|---|
 | 118 |             self.rpc.productOnClient_createObjects( i )
 | 
|---|
| [1051] | 119 |         if self.debug:
 | 
|---|
 | 120 |             pprint( self.getProductOnClient( dst ) )
 | 
|---|
| [1047] | 121 |         
 | 
|---|
| [1028] | 122 | 
 | 
|---|
 | 123 | 
 | 
|---|
| [1047] | 124 | if __name__ == '__main__':
 | 
|---|
 | 125 |     parser = argparse.ArgumentParser(description='Command line tool for OPSI configuration.')
 | 
|---|
 | 126 |     parser.add_argument( '--debug', action='store_true', help="enable debugging output" )
 | 
|---|
 | 127 |     #parser.add_argument( '--verbose', type=bool, help="add debugging output" )
 | 
|---|
 | 128 |     parser.add_argument( '--url', help="OPSI Server JSON-RPC url, normally https://<username>:<password>@<OPSI-SERVER>:4447/rpc" )
 | 
|---|
| [1028] | 129 | 
 | 
|---|
| [1050] | 130 |     subparsers = parser.add_subparsers(title='subcommands',
 | 
|---|
 | 131 |         description='valid subcommands',
 | 
|---|
 | 132 |         help='additional help',
 | 
|---|
 | 133 |         dest='subcommand' )
 | 
|---|
| [1047] | 134 | 
 | 
|---|
| [1050] | 135 |     parser_list = subparsers.add_parser('list', help='list all opsi clients' )
 | 
|---|
 | 136 | 
 | 
|---|
 | 137 |     parser_exists = subparsers.add_parser('exists', help='check, if a opsi clients exists' )
 | 
|---|
 | 138 |     parser_exists.add_argument( 'src', help="source opsi client" )
 | 
|---|
| [1051] | 139 | 
 | 
|---|
 | 140 |     parser_info = subparsers.add_parser('info', help='print information about a opsi client' )
 | 
|---|
 | 141 |     parser_info.add_argument( 'src', help="opsi client" )
 | 
|---|
 | 142 |         
 | 
|---|
| [1050] | 143 |     parser_clean = subparsers.add_parser('clean', help='remove all product states from a opsi client' )
 | 
|---|
 | 144 |     parser_clean.add_argument( 'src', help="source opsi client to clean" )
 | 
|---|
 | 145 |                 
 | 
|---|
 | 146 |     parser_copy = subparsers.add_parser('copy', help='copy/create a opsi client from a template opsi client')    
 | 
|---|
 | 147 |     parser_copy.add_argument( 'src', help="source/template opsi client" )
 | 
|---|
 | 148 |     parser_copy.add_argument( 'dst', help="opsi client to be created" )
 | 
|---|
 | 149 |     parser_copy.add_argument( '--ip', help="IP address of the new opsi client" )
 | 
|---|
 | 150 |     parser_copy.add_argument( '--mac', help="MAC address of the new opsi client" )
 | 
|---|
 | 151 |     parser_copy.add_argument( '--depot', help="depot server the new opsi client should be located" )
 | 
|---|
 | 152 |     
 | 
|---|
| [1047] | 153 |     args = parser.parse_args()
 | 
|---|
 | 154 |     
 | 
|---|
| [1050] | 155 |     
 | 
|---|
| [1047] | 156 |     urlJsonRpc = UrlJsonRpc
 | 
|---|
 | 157 |     if args.url:
 | 
|---|
 | 158 |         urlJsonRpc = args.url
 | 
|---|
 | 159 |     
 | 
|---|
 | 160 |     opsi=OpsiRpc( urlJsonRpc, args.debug )
 | 
|---|
| [1050] | 161 |     
 | 
|---|
| [1051] | 162 |     result = True
 | 
|---|
 | 163 | 
 | 
|---|
 | 164 |     if args.subcommand == "list":
 | 
|---|
 | 165 |         print( "\n".join( opsi.list() ) )
 | 
|---|
 | 166 |     elif args.subcommand == "exists":
 | 
|---|
 | 167 |         result = opsi.exists( args.src )
 | 
|---|
 | 168 |     elif args.subcommand == "info":
 | 
|---|
 | 169 |         result = opsi.info( args.src )        
 | 
|---|
 | 170 |     elif args.subcommand == "clean":
 | 
|---|
 | 171 |         result = opsi.clean( args.src )
 | 
|---|
 | 172 |     elif args.subcommand == "copy": 
 | 
|---|
| [1052] | 173 |         result = opsi.copyClient( args.src, args.dst, args.ip, args.mac, args.depot )
 | 
|---|
| [1050] | 174 |     else:
 | 
|---|
 | 175 |         print "not yet implemented"
 | 
|---|
 | 176 | 
 | 
|---|
| [1051] | 177 |     if args.debug: print result    
 | 
|---|
 | 178 |         
 | 
|---|
 | 179 |     if result:
 | 
|---|
 | 180 |         exit(0)
 | 
|---|
 | 181 |     else:
 | 
|---|
 | 182 |         exit(1)
 | 
|---|