Skip to content

code proposition : RESTClient refactoring #5

Description

@frague59

Hi,

From your code, I've created a new way to access to the GLPI service. I've refactored the connexion / aithentification process and have curryed all glpi methods.

#!/usr/bin/env python# -*- coding:utf-8 -*-importurllib, urllib2importjsonimportsys, os, warnings# import getpassimportloggingDEBUG=Truelogging.basicConfig(level=logging.DEBUG)
defcurry(_curried_func, *args, **kwargs):
def_curried(*moreargs, **morekwargs):
return_curried_func(*(args+moreargs), **dict(kwargs, **morekwargs))
return_curriedclassRESTClient(object):
""" .. note:: If any boolean arguments are defined, they're automatically added to the GET request, which means the webservices API will treat them as being true. You've been warned. """# List all methods defined in the REST APIMETHODS=dict(test='glpi.test',
status='glpi.status',
listAllMethods='glpi.listAllMethods',
listEntities='glpi.listEntities',
doLogin='glpi.doLogin',
listKnowBaseItems='glpi.listKnowBaseItems',
getKnowBaseItem='glpi.getKnowBaseItem',
getDocument='glpi.getDocument',
doLogout='glpi.doLogout',
getMyInfo='glpi.getMyInfo',
listMyProfiles='glpi.listMyProfiles',
setMyProfile='glpi.setMyProfile',
listMyEntities='glpi.listMyEntities',
setMyEntity='glpi.setMyEntity',
listDropdownValues='glpi.listDropdownValues',
listGroups='glpi.listGroups',
listHelpdeskTypes='glpi.listHelpdeskTypes',
listHelpdeskItems='glpi.listHelpdeskItems',
listTickets='glpi.listTickets',
listUsers='glpi.listUsers',
listInventoryObjects='glpi.listInventoryObjects',
listObjects='glpi.listObjects',
getObject='glpi.getObject',
createObjects='glpi.createObjects',
deleteObjects='glpi.deleteObjects',
updateObjects='glpi.updateObjects',
linkObjects='glpi.linkObjects',
getInfocoms='glpi.getInfocoms',
getContracts='glpi.getContracts',
getComputer='glpi.getComputer',
getComputerInfoComs='glpi.getComputerInfoComs',
getComputerContracts='glpi.getComputerContracts',
getNetworkports='glpi.getNetworkports',
listComputers='glpi.listComputers',
getPhones='glpi.getPhones',
getNetworkEquipment='glpi.getNetworkEquipment',
getTicket='glpi.getTicket',
createTicket='glpi.createTicket',
addTicketFollowup='glpi.addTicketFollowup',
addTicketDocument='glpi.addTicketDocument',
addTicketObserver='glpi.addTicketObserver',
setTicketSatisfaction='glpi.setTicketSatisfaction',
setTicketValidation='glpi.setTicketValidation',)
def__init__(self, host='glpi', baseurl='/glpi',):
''' Initialize the RESTClient instance, adding supported glpi-methods by currying self._get_METHOD '''self.BASEURL=baseurlself._url='http://'+host+'/'+self.BASEURL+'/plugins/webservices/rest.php?'formethodinself.METHODS.keys():
setattr(self, 'get_%s'% (method),
curry(self._get_METHOD, self.METHODS.get(method)))
def_get_METHOD(self, method, **kwargs):
''' Private method that perform the call to glpi server with the glpi method and providing parameters as kwargs @param method: GLPI method to call @param kwargs: parameters to send to glpi test '''ifnotself.connected:
self.connect(login_name='webservices', login_password='webservices')
response=self.send_request(method, **kwargs)
DEBUGandlogging.debug(u'RESTClient::get_%s() 'u'response = %s'% (method, response,))
returnresponse# Attributes_session=None_url=None@propertydefsession(self):
''' The session string '''returnself._session@propertydefconnected(self):
''' tests in client is connected to the server '''returnself.sessionisnotNone@propertydefurl(self):
''' The complete url '''returnself._url@staticmethoddef_is_fault(response):
''' tests if a fault has been raised by the server @param response: the decoded respose object @return: False if there is no error @raise Exception: if a server side error has been raised '''DEBUGandlogging.debug(u'RESTClient::_is_fault() 'u'response = %s'% (response,))
if (isinstance(response, (dict))):
faultCode=response.get('faultCode')
faultString=response.get('faultString')
if (faultCodeisnotNone):
raiseException('Fault returned by GLPI service : %s : %s'% (faultCode, faultString,))
# There is no server-side fault.returnFalsedef_build_url(self, method, params=None):
''' private method to build the final url sent to the server @param method: the glpi method @param params: params to join to the request @return: the final url that will be sent '''_params= {"method": method, }
ifparams:
_params.update(params)
_url=self.url+urllib.urlencode(_params)
logging.debug(u'RESTClient::_build_url(%s, %s) 'u'_url = %s '% (method, params, _url,))
return_urldefsend_request(self, method, **kwargs):
''' send a request to GLPI server and returns the json-decoded response @param method: glpi-method @param kwargs: extra-parameters to pass to the method @return: response object json-decoded @raise Exception: if the server raises {'faultCode', 'faultString'} or if something has failed. '''self.connectedandlogging.debug(u'RESTClient::get(%s, %s) 'u'CONNECTED !'% (method, kwargs,))
# Prepares parameters_params= {'method': method, }
ifkwargs:
_params.update(kwargs)
# Append session to parametersifself.session:
_params['session'] =self.sessionurl=self._build_url(method, _params)
request=urllib2.Request(url)
# Sends the requesttry:
response=urllib2.urlopen(request)
headers=response.headersread=response.read()
logging.debug(u'RESTClient::send_request(%s, %s) 'u'response: %s /'% (method, kwargs, read,))
json_decoded=json.loads(read)
ifnotRESTClient._is_fault(json_decoded): # An exception is raised on protocol or glpi method errorreturnjson_decodedexceptExceptionase:
# Exception is re-raisedraiseedefconnect(self, login_name=None, login_password=None):
""" Connect to a running GLPI instance that has the webservices plugin enabled. Returns True if connection was successful. :type login_name: string :type login_password: string :param host: hostname of the GLPI server, has not been tested with HTTPS :param login_name: your GLPI username :param login_password: pretty obvious """self.login_name=login_nameself.login_password=login_passwordifself.login_name!=Noneandself.login_password!=None:
params= {'login_name':login_name,
'login_password': (login_password), }
response=self.send_request("glpi.doLogin", **params)
session_id=response.get('session')
ifsession_idisnotNone:
self._session=session_idreturnTrueelse:
raiseException("Login incorrect or server down")
else:
logging.warning("Connected anonymously, will only be able to use non-authenticated methods")
returnself

The curry function is copied from the django project.

To access to th glpi.method, you just have to call the get_method which has been dynalicaly created on RESTClient init.

By exemple:

$ python>>>fromGLPI.GLPIClientimportRESTClient>>>rc=RESTClient(host='glpi', baseurl='/glpi_tests')
>>>rc<GLPI.GLPIClient.RESTClientobjectat0x7fa6d7aec4d0>>>>rc.connect(login_name='<LOGIN>', login_password='<PWD>')
True>>>rc.sessionu'44h8sloakn4macki3kr0kmms42'>>rc.connectedTrue>>>rc.get_getComputer(id=100)
# Your computer !>>>rc.listObjects(itemtype='computer', rc.get_listObjects(itemtype='computer', start=10, limit=20,)
# Your computers list !

I let you read the code and tell me what you think about it.

cordially,
frague

PS : english is not my first language, so excuse for english faults...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions