This is an old revision of the document!
Yet another method of reading the JSON-RPC interface.
The example below reads the result of the latest softwareAudit and displays it as a table. Information about installed sw products are merged in.
All needed files (.html, .js, .css) should be hosted below /usr/share/opsiconfd/static/AngularExample folder thus avoiding cross scripting complaints of modern browsers.
The location would then read https://opsi:4447/AngularExample.
configed will currently answer /rpc? requests with Encoding “deflate”, but will anounce it as “gzip”. This issue is known and a patch is mentioned in the forums.
Most requests require a logon, some even special rights. The script user should be member of a new group opsireader and the acl.conf file should be prepended with appropriate lines:
getProducts_.* : sys_group(opsireader); sys_group(opsiadmin); opsi_depotserver; self; opsi_client productOnClient_get.* : sys_group(opsireader); sys_group(opsiadmin); opsi_depotserver;self; opsi_client auditSoftwareOnClient_get.* : sys_group(opsireader); sys_group(opsiadmin); opsi_depotserver; self; opsi_client product_get.* : sys_group(opsireader); sys_group(opsiadmin); opsi_depotserver; self; opsi_client
/usr/share/opsiconfd/static/AngularExample ├ index.html ├ swinv.js └ swinv.css
Where all other is loaded from..
<!DOCTYPE html> <html ng-app="opsi-swinv"> <head> <link rel="stylesheet" type="text/css" href="swinv.css" > <script type="text/javascript" src="angular.js"></script> <!-- chenge to angular-min for production --> <!-- script type="text/javascript" src="angular-resource.js"></script --> <script type="text/javascript" src="swinv.js"></script> <script type="text/javascript" src="swpattern.js"></script> </head> <body ng-controller="swinvController as sw"> <div class="swlist"> <input id="inputId" ng-model="sw.clientId"></input> <button ng-click="sw.refresh(sw.clientId)">refresh list</button> <table border > <tr><th>Name</th><th>Version</th><th>Lizenz</th><th>Installationsgrund</th></tr> <tr ng-repeat="swp in sw.products" ng-show="sw.nonMS(swp.name)"> <td>{{swp.name}} </td> <td> {{swp.version}}</td> <td>{{sw.reason(swp.name)}}</td> <td class={{sw.csswarn(swp.name)}}><span ng-show="!sw.isOpsi(swp.name)">{{sw.reason(swp.name)}} </span>{{sw.opsiProdId(swp.name)}}</td> </tr> </table> <br/><label><input type="checkbox" ng-model="sw.showopsiinstalled" />installed OPSI products on this client <span>({{sw.clientId}})</span></label> <div ng-show="sw.showopsiinstalled"> <table border> <tr><th>OpsiProduct</th></tr> <tr ng-repeat="inst in sw.installed"> <td>{{inst}}</td> </tr> </table> </div> <br/><label><input type="checkbox" ng-model="sw.showallprods" />available products</label> <table ng-show="sw.showallprods" border width="100%"> <tr><th>productInfo</th><th>productId</th><th>...............................................</th></tr> <tr ng-repeat="prod in sw.productinfos"> <td>{{prod.productId}}</td> <td>{{prod.name}}</td> <td></td> </tr> </table> </div> </body> </html>
swinv.js The AngularJS mimic..
(function(){ var app = angular.module('opsi-swinv', []); app.controller('swinvController',function($http,$filter){ this.showallprods=0; this.showopsiinstalled=0; baseurl='/rpc'; logonurl='https://testerMemberOfGroupopsireader:unGuessablePassword@'+window.location.host+'/rpc'; this.clientId="defaultclient.domain.local"; this.auditParams={'id':'jsonrpc','method':'auditSoftwareOnClient_getObjects','params':[]}; this.auditParams.params.push([]); this.auditParams.params.push({"clientId":"defaultclient.domain.local"}); opsiURL=baseurl+"?"+$filter('json')(this.auditParams); me=this; me['installed']=[]; me['productinfos']=[]; this.jsonParmDns=function(){ this.search=window.location.search; if (this.search.match(/dns/)){ // we believe in barcode like {"dns":"<clientId>"} var qsearch=decodeURIComponent(this.search).match(/{.+dns.+:.+}/); var jsonsearch=decodeURIComponent(qsearch); // get the json return angular.fromJson(jsonsearch).dns; // return JSON.parse(jsonsearch).dns; } return null; }; this.opsicall=function(field,method,arg){ Params={'id':'1','method':method,'params':[]}; if(arg)Params.params[0]=arg; $http.post(baseurl,Params) .success(function(response,stat,head,conf){ // alert("success: "+$filter('json')(response)); me.opsires="success: "+method; me.opsiconf=conf; if(response.error) alert(response.error.message); else me[field]=response.result; }) .error(function(err,stat,head,conf){ me.opsires="error"; alert("err: "+(err)+stat+head+$filter('json')(conf)); me.opsistat=stat; me.opsihead=head; me.opsiconf=conf; }); }; this.logon=function(){ $http.post(logonurl,this.logonParams) .success(function(response){ // alert("success: "+$filter('json')(response)); // call after logon success me.getproductinfos(); me.refresh(me.clientId); }) .error(function(response){ alert("err: "+(response)); }); }; this.getprods=function(id){ this.opsires="calling.. "+id; if(id)this.auditParams.params[1].clientId=id; $http.post(baseurl,this.auditParams) .success(function(response,stat,head,conf){ // alert("success: "+response); if(response.error)alert(response.error.message); me.products=response.result; me.opsistat=stat; me.opsihead=head; me.opsiconf=conf; }) .error(function(err,stat,head,conf){ me.opsires="error"; alert("err: "+(err)+stat+head+$filter('json')(conf)); me.opsistat=stat; me.opsihead=head; me.opsiconf=conf; }); }; // get products on Client with id this.getinstalled=function(id){ this.opsicall('installed','getInstalledLocalBootProductIds_list',id); }; // get all available OPSi products this.getproductinfos=function(){ this.opsicall('productinfos','getProducts_listOfHashes'); }; this.logon(); this.clientId=this.jsonParmDns(); // this.getproductinfos(); this.refresh=function(id){ if(null != id){ this.getprods(id); this.getinstalled(id); } }; this.nonMS=function(name){ // return true; if(name.match(/AddressBook/)) return false; if(name.match(/^Connection Manager/)) return false; if(name.match(/^DirectDrawEx/)) return false; if(name.match(/^DXM_Runtime/)) return false; if(name.match(/^Fontcore/)) return false; if(name.match(/KB[0-9]+/)) return false; if(name.match(/Microsoft/)) return false; if(name.match(/^MPlayer2/)) return false; if(name.match(/^Outlook/)) return false; if(name.match(/^[iI][Ee]/)) return false; if(name.match(/^Windows/)) return false; if(name.match(/^MobileOptionPack/)) return false; if(name.match(/^SchedulingAgent/)) return false; if(name.match(/^WIC/)) return false; return true; } this.pattern=swpattern; this.reason=function(name){ for(p in this.pattern){ if(name.match(p)) return this.pattern[p]; } }; // guess the corresponding OPSI productId from the Windows Product name this.opsiProdId=function(name){ for(i=0; i<this.productinfos.length;i++){ p=this.productinfos[i]; if(p.name && name.match(p.name)||name.match(p.productId)) return p.productId; } return null; }; // convenience: is this an OPSI product? this.isOpsi=function(name){ return (null != this.opsiProdId(name)); }; // mark rows w/o reason/license this.csswarn=function(name){ if(this.isOpsi(name) || this.reason(name)) return "ng-binding"; else return "warn"; }; }); var swpattern={'^Audacity':'OpenSource', '^Java':'Oracle', '^Mozilla ':'Mozilla Public', '^OpenOff':'OpenSource', '^Google':'Google Public', '^Adobe Flash':'Adobe Public', '^OpenSSL':'OpenSource', '^Python':'OpenSource' }; })();