1 from httplib import HTTPConnection, HTTPException, NotConnected
3 from sfa.util.config import Config
4 from sfa.util.sfalogging import logger
11 """Class used to manipulate json pages given by OAR.
13 In case the json answer from a GET request is too big to fit in one json
14 page, this class provides helper methods to retrieve all the pages and
15 store them in a list before putting them into one single json dictionary,
16 facilitating the parsing.
21 """Defines attributes to manipulate and parse the json pages.
24 #All are boolean variables
25 self.concatenate = False
26 #Indicates end of data, no more pages to be loaded.
28 self.next_page = False
30 self.next_offset = None
34 def FindNextPage(self):
36 Gets next data page from OAR when the query's results are too big to
37 be transmitted in a single page. Uses the "links' item in the json
38 returned to check if an additionnal page has to be loaded. Updates
39 object attributes next_page, next_offset, and end.
42 if "links" in self.raw_json:
43 for page in self.raw_json['links']:
44 if page['rel'] == 'next':
45 self.concatenate = True
47 self.next_offset = "?" + page['href'].split("?")[1]
52 self.next_page = False
53 self.next_offset = None
57 #Otherwise, no next page and no concatenate, must be a single page
58 #Concatenate the single page and get out of here.
60 self.next_page = False
61 self.concatenate = True
62 self.next_offset = None
66 def ConcatenateJsonPages(saved_json_list):
68 If the json answer is too big to be contained in a single page,
69 all the pages have to be loaded and saved before being appended to the
72 :param saved_json_list: list of all the stored pages, including the
74 :type saved_json_list: list
75 :returns: Returns a dictionary with all the pages saved in the
76 saved_json_list. The key of the dictionary is 'items'.
80 .. seealso:: SendRequest
81 .. warning:: Assumes the apilib is 0.2.10 (with the 'items' key in the
90 for page in saved_json_list:
91 tmp['items'].extend(page['items'])
94 def ResetNextPage(self):
96 Resets all the Json page attributes (next_page, next_offset,
97 concatenate, end). Has to be done before getting another json answer
98 so that the previous page status does not affect the new json load.
101 self.next_page = True
102 self.next_offset = None
103 self.concatenate = False
108 """Class used to connect to the OAR server and to send GET and POST
115 OAR_REQUEST_POST_URI_DICT = {'POST_job': {'uri': '/oarapi/jobs.json'},
117 {'uri': '/oarapi/jobs/id.json'},
120 POST_FORMAT = {'json': {'content': "application/json", 'object': json}}
122 #OARpostdatareqfields = {'resource' :"/nodes=", 'command':"sleep", \
123 #'workdir':"/home/", 'walltime':""}
125 def __init__(self, config_file='/etc/sfa/oar_config.py'):
127 self.oarserver['uri'] = None
128 self.oarserver['postformat'] = 'json'
131 execfile(config_file, self.__dict__)
133 self.config_file = config_file
134 # path to configuration data
135 self.config_path = os.path.dirname(config_file)
138 raise IOError, "Could not find or load the configuration file: %s" \
140 #logger.setLevelDebug()
141 self.oarserver['ip'] = self.OAR_IP
142 self.oarserver['port'] = self.OAR_PORT
143 self.jobstates = ['Terminated', 'Hold', 'Waiting', 'toLaunch',
144 'toError', 'toAckReservation', 'Launching',
145 'Finishing', 'Running', 'Suspended', 'Resuming',
148 self.parser = OARGETParser(self)
151 def GETRequestToOARRestAPI(self, request, strval=None,
152 next_page=None, username=None):
154 """Makes a GET request to OAR.
156 Fetch the uri associated with the resquest stored in
157 OARrequests_uri_dict, adds the username if needed and if available, adds
158 strval to the request uri if needed, connects to OAR and issues the GET
159 request. Gets the json reply.
161 :param request: One of the known get requests that are keys in the
162 OARrequests_uri_dict.
163 :param strval: used when a job id has to be specified.
164 :param next_page: used to tell OAR to send the next page for this
165 Get request. Is appended to the GET uri.
166 :param username: used when a username has to be specified, when looking
167 for jobs scheduled by a particular user for instance.
169 :type request: string
170 :type strval: integer
171 :type next_page: boolean
172 :type username: string
175 :returns: a json dictionary if OAR successfully processed the GET
178 .. seealso:: OARrequests_uri_dict
180 self.oarserver['uri'] = \
181 OARGETParser.OARrequests_uri_dict[request]['uri']
182 #Get job details with username
183 if 'owner' in OARGETParser.OARrequests_uri_dict[request] and username:
184 self.oarserver['uri'] += \
185 OARGETParser.OARrequests_uri_dict[request]['owner'] + username
187 data = json.dumps({})
188 logger.debug("OARrestapi \tGETRequestToOARRestAPI %s" % (request))
190 self.oarserver['uri'] = self.oarserver['uri'].\
191 replace("id",str(strval))
194 self.oarserver['uri'] += next_page
197 headers['X-REMOTE_IDENT'] = username
199 logger.debug("OARrestapi: \t GETRequestToOARRestAPI \
200 self.oarserver['uri'] %s strval %s" \
201 %(self.oarserver['uri'], strval))
203 #seems that it does not work if we don't add this
204 headers['content-length'] = '0'
206 conn = HTTPConnection(self.oarserver['ip'], \
207 self.oarserver['port'])
208 conn.request("GET", self.oarserver['uri'], data, headers)
209 resp = ( conn.getresponse()).read()
212 except HTTPException, error :
213 logger.log_exc("GET_OAR_SRVR : Problem with OAR server : %s " \
215 #raise ServerError("GET_OAR_SRVR : Could not reach OARserver")
217 js_dict = json.loads(resp)
218 #print "\r\n \t\t\t js_dict keys" , js_dict.keys(), " \r\n", js_dict
221 except ValueError, error:
222 logger.log_exc("Failed to parse Server Response: %s ERROR %s"\
224 #raise ServerError("Failed to parse Server Response:" + js)
227 def POSTRequestToOARRestAPI(self, request, datadict, username=None):
228 """ Used to post a job on OAR , along with data associated
233 #first check that all params for are OK
235 self.oarserver['uri'] = self.OAR_REQUEST_POST_URI_DICT[request]['uri']
238 logger.log_exc("OARrestapi \tPOSTRequestToOARRestAPI request not \
241 if datadict and 'strval' in datadict:
242 self.oarserver['uri'] = self.oarserver['uri'].replace("id", \
243 str(datadict['strval']))
244 del datadict['strval']
246 data = json.dumps(datadict)
247 headers = {'X-REMOTE_IDENT':username, \
248 'content-type': self.POST_FORMAT['json']['content'], \
249 'content-length':str(len(data))}
252 conn = HTTPConnection(self.oarserver['ip'], \
253 self.oarserver['port'])
254 conn.request("POST", self.oarserver['uri'], data, headers)
255 resp = (conn.getresponse()).read()
258 logger.log_exc("POSTRequestToOARRestAPI NotConnected ERROR: \
259 data %s \r\n \t\n \t\t headers %s uri %s" \
260 %(data,headers,self.oarserver['uri']))
262 #raise ServerError("POST_OAR_SRVR : error")
265 answer = json.loads(resp)
266 logger.debug("POSTRequestToOARRestAPI : answer %s" % (answer))
269 except ValueError, error:
270 logger.log_exc("Failed to parse Server Response: error %s \
272 #raise ServerError("Failed to parse Server Response:" + answer)
275 class ParsingResourcesFull():
277 Class dedicated to parse the json response from a GET_resources_full from
282 self.resources_fulljson_dict = {
283 'network_address': self.AddNodeNetworkAddr,
284 'site': self.AddNodeSite,
285 # 'radio': self.AddNodeRadio,
286 'mobile': self.AddMobility,
290 'archi': self.AddHardwareType,
291 'state': self.AddBootState,
292 'id': self.AddOarNodeId,
297 def AddOarNodeId(self, tuplelist, value):
298 """Adds Oar internal node id to the nodes' attributes.
300 Appends tuple ('oar_id', node_id) to the tuplelist. Used by ParseNodes.
302 .. seealso:: ParseNodes
306 tuplelist.append(('oar_id', int(value)))
309 def AddNodeNetworkAddr(self, dictnode, value):
310 """First parsing function to be called to parse the json returned by OAR
311 answering a GET_resources (/oarapi/resources.json) request.
313 When a new node is found in the json, this function is responsible for
314 creating a new entry in the dictionary for storing information on this
315 specific node. The key is the node network address, which is also the
317 The value associated with the key is a tuple list.It contains all
318 the nodes attributes. The tuplelist will later be turned into a dict.
320 :param dictnode: should be set to the OARGETParser atribute node_dictlist.
321 It will store the information on the nodes.
322 :param value: the node_id is the network_address in the raw json.
324 :type dictnode: dictionary
326 .. seealso: ParseResources, ParseNodes
330 dictnode[node_id] = [('node_id', node_id),('hostname', node_id) ]
334 def AddNodeSite(self, tuplelist, value):
335 """Add the site's node to the dictionary.
338 :param tuplelist: tuple list on which to add the node's site. Contains the
339 other node attributes as well.
340 :param value: value to add to the tuple list, in this case the node's site.
341 :type tuplelist: list
344 .. seealso:: AddNodeNetworkAddr
347 tuplelist.append(('site', str(value)))
349 # def AddNodeRadio(tuplelist, value):
350 # """Add thenode's radio chipset type to the tuple list.
352 # :param tuplelist: tuple list on which to add the node's mobility status. The
353 # tuplelist is the value associated with the node's id in the OARGETParser
354 # 's dictionary node_dictlist.
355 # :param value: name of the radio chipset on the node.
356 # :type tuplelist: list
357 # :type value: string
359 # .. seealso:: AddNodeNetworkAddr
362 # tuplelist.append(('radio', str(value)))
365 def AddMobility(self, tuplelist, value):
366 """Add if the node is a mobile node or not to the tuple list.
368 :param tuplelist: tuple list on which to add the node's mobility status. The
369 tuplelist is the value associated with the node's id in the OARGETParser
370 's dictionary node_dictlist.
371 :param value: tells if a node is a mobile node or not. The value is found
374 :type tuplelist: list
377 .. seealso:: AddNodeNetworkAddr
381 tuplelist.append(('mobile', 'False'))
383 tuplelist.append(('mobile', 'True'))
386 def AddPosX(self, tuplelist, value):
387 """Add the node's position on the x axis.
389 :param tuplelist: tuple list on which to add the node's position . The
390 tuplelist is the value associated with the node's id in the OARGETParser
391 's dictionary node_dictlist.
392 :param value: the position x.
394 :type tuplelist: list
397 .. seealso:: AddNodeNetworkAddr
400 tuplelist.append(('posx', value ))
404 def AddPosY(self, tuplelist, value):
405 """Add the node's position on the y axis.
407 :param tuplelist: tuple list on which to add the node's position . The
408 tuplelist is the value associated with the node's id in the OARGETParser
409 's dictionary node_dictlist.
410 :param value: the position y.
412 :type tuplelist: list
415 .. seealso:: AddNodeNetworkAddr
418 tuplelist.append(('posy', value))
422 def AddPosZ(self, tuplelist, value):
423 """Add the node's position on the z axis.
425 :param tuplelist: tuple list on which to add the node's position . The
426 tuplelist is the value associated with the node's id in the OARGETParser
427 's dictionary node_dictlist.
428 :param value: the position z.
430 :type tuplelist: list
433 .. seealso:: AddNodeNetworkAddr
437 tuplelist.append(('posz', value))
441 def AddBootState(tself, tuplelist, value):
442 """Add the node's state, Alive or Suspected.
444 :param tuplelist: tuple list on which to add the node's state . The
445 tuplelist is the value associated with the node's id in the OARGETParser
446 's dictionary node_dictlist.
447 :param value: node's state.
449 :type tuplelist: list
452 .. seealso:: AddNodeNetworkAddr
455 tuplelist.append(('boot_state', str(value)))
458 def AddHardwareType(self, tuplelist, value):
459 """Add the node's hardware model and radio chipset type to the tuple
462 :param tuplelist: tuple list on which to add the node's architecture
463 and radio chipset type.
464 :param value: hardware type: radio chipset. The value contains both the
465 architecture and the radio chipset, separated by a colon.
466 :type tuplelist: list
469 .. seealso:: AddNodeNetworkAddr
473 value_list = value.split(':')
474 tuplelist.append(('archi', value_list[0]))
475 tuplelist.append(('radio', value_list[1]))
479 # resources_fulljson_dict = {
480 # 'network_address': AddNodeNetworkAddr,
481 # 'site': AddNodeSite,
482 # # 'radio': AddNodeRadio,
483 # 'mobile': AddMobility,
487 # 'archi':AddHardwareType,
488 # 'state':AddBootState,
489 # 'id' : AddOarNodeId,
493 def __init__(self, srv) :
494 self.version_json_dict = {
495 'api_version' : None , 'apilib_version' :None,\
496 'api_timezone': None, 'api_timestamp': None, 'oar_version': None ,}
497 self.config = Config()
498 self.interface_hrn = self.config.SFA_INTERFACE_HRN
499 self.timezone_json_dict = {
500 'timezone': None, 'api_timestamp': None, }
501 #self.jobs_json_dict = {
502 #'total' : None, 'links' : [],\
503 #'offset':None , 'items' : [], }
504 #self.jobs_table_json_dict = self.jobs_json_dict
505 #self.jobs_details_json_dict = self.jobs_json_dict
507 self.node_dictlist = {}
509 self.json_page = JsonPage()
510 self.parsing_resourcesfull = ParsingResourcesFull()
512 self.SendRequest("GET_version")
518 def ParseVersion(self) :
519 """Parses the OAR answer to the GET_version ( /oarapi/version.json.)
521 Finds the OAR apilib version currently used. Has an impact on the json
522 structure returned by OAR, so the version has to be known before trying
523 to parse the jsons returned after a get request has been issued.
524 Updates the attribute version_json_dict.
529 if 'oar_version' in self.json_page.raw_json :
530 self.version_json_dict.update(api_version =
531 self.json_page.raw_json['api_version'],
532 apilib_version=self.json_page.raw_json['apilib_version'],
533 api_timezone=self.json_page.raw_json['api_timezone'],
534 api_timestamp=self.json_page.raw_json['api_timestamp'],
535 oar_version=self.json_page.raw_json['oar_version'])
537 self.version_json_dict.update(api_version =
538 self.json_page.raw_json['api'],
539 apilib_version=self.json_page.raw_json['apilib'],
540 api_timezone=self.json_page.raw_json['api_timezone'],
541 api_timestamp=self.json_page.raw_json['api_timestamp'],
542 oar_version=self.json_page.raw_json['oar'])
544 print self.version_json_dict['apilib_version']
547 def ParseTimezone(self):
548 """Get the timezone used by OAR.
550 Get the timezone from the answer to the GET_timezone request.
551 :return: api_timestamp and api timezone.
552 :rype: integer, integer
556 api_timestamp = self.json_page.raw_json['api_timestamp']
557 api_tz = self.json_page.raw_json['timezone']
558 return api_timestamp, api_tz
561 """Called when a GET_jobs request has been issued to OAR.
563 Corresponds to /oarapi/jobs.json uri. Currently returns the raw json
565 :returns: json_page.raw_json
568 .. warning:: Does not actually parse the information in the json. SA
574 return self.json_page.raw_json
576 def ParseJobsTable(self):
577 """In case we need to use the job table in the future.
579 Associated with the GET_jobs_table : '/oarapi/jobs/table.json uri.
580 .. warning:: NOT USED. DOES NOTHING.
582 print "ParseJobsTable"
584 def ParseJobsDetails(self):
585 """Currently only returns the same json in self.json_page.raw_json.
587 .. todo:: actually parse the json
588 .. warning:: currently, this function is not used a lot, so I have no
589 idea what could be useful to parse, returning the full json. NT
592 #logger.debug("ParseJobsDetails %s " %(self.json_page.raw_json))
593 return self.json_page.raw_json
596 def ParseJobsIds(self):
597 """Associated with the GET_jobs_id OAR request.
599 Parses the json dict (OAR answer) to the GET_jobs_id request
600 /oarapi/jobs/id.json.
603 :returns: dictionary whose keys are listed in the local variable
604 job_resources and values that are in the json dictionary returned
605 by OAR with the job information.
609 job_resources = ['wanted_resources', 'name', 'id', 'start_time',
610 'state', 'owner', 'walltime', 'message']
613 job_resources_full = ['launching_directory', 'links',
614 'resubmit_job_id', 'owner', 'events', 'message',
615 'scheduled_start', 'id', 'array_id', 'exit_code',
616 'properties', 'state','array_index', 'walltime',
617 'type', 'initial_request', 'stop_time', 'project',
618 'start_time', 'dependencies','api_timestamp','submission_time',
619 'reservation', 'stdout_file', 'types', 'cpuset_name',
620 'name', 'wanted_resources','queue','stderr_file','command']
623 job_info = self.json_page.raw_json
624 #logger.debug("OARESTAPI ParseJobsIds %s" %(self.json_page.raw_json))
627 for k in job_resources:
628 values.append(job_info[k])
629 return dict(zip(job_resources, values))
632 logger.log_exc("ParseJobsIds KeyError ")
635 def ParseJobsIdResources(self):
636 """ Parses the json produced by the request
637 /oarapi/jobs/id/resources.json.
638 Returns a list of oar node ids that are scheduled for the
643 for resource in self.json_page.raw_json['items']:
644 job_resources.append(resource['id'])
646 #logger.debug("OARESTAPI \tParseJobsIdResources %s" %(self.json_page.raw_json))
649 def ParseResources(self) :
650 """ Parses the json produced by a get_resources request on oar."""
652 #logger.debug("OARESTAPI \tParseResources " )
653 #resources are listed inside the 'items' list from the json
654 self.json_page.raw_json = self.json_page.raw_json['items']
657 def ParseReservedNodes(self):
658 """ Returns an array containing the list of the reserved nodes """
660 #resources are listed inside the 'items' list from the json
661 reservation_list = []
663 #Parse resources info
664 for json_element in self.json_page.raw_json['items']:
665 #In case it is a real reservation (not asap case)
666 if json_element['scheduled_start']:
667 job['t_from'] = json_element['scheduled_start']
668 job['t_until'] = int(json_element['scheduled_start']) + \
669 int(json_element['walltime'])
670 #Get resources id list for the job
671 job['resource_ids'] = \
672 [ node_dict['id'] for node_dict in json_element['resources']]
674 job['t_from'] = "As soon as possible"
675 job['t_until'] = "As soon as possible"
676 job['resource_ids'] = ["Undefined"]
679 job['state'] = json_element['state']
680 job['lease_id'] = json_element['id']
683 job['user'] = json_element['owner']
684 #logger.debug("OARRestapi \tParseReservedNodes job %s" %(job))
685 reservation_list.append(job)
688 return reservation_list
690 def ParseRunningJobs(self):
691 """ Gets the list of nodes currently in use from the attributes of the
695 logger.debug("OARESTAPI \tParseRunningJobs__________________________ ")
696 #resources are listed inside the 'items' list from the json
698 for job in self.json_page.raw_json['items']:
699 for node in job['nodes']:
700 nodes.append(node['network_address'])
703 def ChangeRawJsonDependingOnApilibVersion(self):
705 if self.version_json_dict['apilib_version'] != "0.2.10" :
706 self.json_page.raw_json = self.json_page.raw_json['items']
708 def ParseDeleteJobs(self):
709 """ No need to parse anything in this function.A POST
710 is done to delete the job.
715 def ParseResourcesFull(self) :
716 """ This method is responsible for parsing all the attributes
717 of all the nodes returned by OAR when issuing a get resources full.
718 The information from the nodes and the sites are separated.
719 Updates the node_dictlist so that the dictionnary of the platform's
720 nodes is available afterwards.
723 logger.debug("OARRESTAPI ParseResourcesFull________________________ ")
724 #print self.json_page.raw_json[1]
725 #resources are listed inside the 'items' list from the json
726 self.ChangeRawJsonDependingOnApilibVersion()
729 return self.node_dictlist
731 def ParseResourcesFullSites(self) :
732 """ UNUSED. Originally used to get information from the sites.
733 ParseResourcesFull is used instead.
736 self.ChangeRawJsonDependingOnApilibVersion()
739 return self.site_dict
742 def ParseNodes(self):
743 """ Parse nodes properties from OAR
744 Put them into a dictionary with key = node id and value is a dictionary
745 of the node properties and properties'values.
749 _resources_fulljson_dict = \
750 self.parsing_resourcesfull.resources_fulljson_dict
751 keys = _resources_fulljson_dict.keys()
754 for dictline in self.json_page.raw_json:
756 # dictionary is empty and/or a new node has to be inserted
757 node_id = _resources_fulljson_dict['network_address'](\
758 self.node_dictlist, dictline['network_address'])
761 if k == 'network_address':
764 _resources_fulljson_dict[k](\
765 self.node_dictlist[node_id], dictline[k])
767 #The last property has been inserted in the property tuple list,
769 #Turn the property tuple list (=dict value) into a dictionary
770 self.node_dictlist[node_id] = dict(self.node_dictlist[node_id])
774 def iotlab_hostname_to_hrn(root_auth, hostname):
776 Transforms a node hostname into a SFA hrn.
778 :param root_auth: Name of the root authority of the SFA server. In
779 our case, it is set to iotlab.
780 :param hostname: node's hotname, given by OAR.
781 :type root_auth: string
782 :type hostname: string
783 :returns: inserts the root_auth and '.' before the hostname.
787 return root_auth + '.' + hostname
791 def ParseSites(self):
792 """ Returns a list of dictionnaries containing the sites' attributes."""
796 #logger.debug(" OARrestapi.py \tParseSites self.node_dictlist %s"\
797 #%(self.node_dictlist))
798 # Create a list of nodes per site_id
799 for node_id in self.node_dictlist:
800 node = self.node_dictlist[node_id]
802 if node['site'] not in nodes_per_site:
803 nodes_per_site[node['site']] = []
804 nodes_per_site[node['site']].append(node['node_id'])
806 if node['node_id'] not in nodes_per_site[node['site']]:
807 nodes_per_site[node['site']].append(node['node_id'])
809 #Create a site dictionary whose key is site_login_base (name of the site)
810 # and value is a dictionary of properties, including the list
812 for node_id in self.node_dictlist:
813 node = self.node_dictlist[node_id]
814 #node.update({'hrn':self.iotlab_hostname_to_hrn(self.interface_hrn, \
815 #node['site'],node['hostname'])})
816 node.update({'hrn':self.iotlab_hostname_to_hrn(self.interface_hrn, node['hostname'])})
817 self.node_dictlist.update({node_id:node})
819 if node['site'] not in self.site_dict:
820 self.site_dict[node['site']] = {
822 'node_ids':nodes_per_site[node['site']],
823 'latitude':"48.83726",
824 'longitude':"- 2.10336",'name':config.SFA_REGISTRY_ROOT_AUTH,
825 'pcu_ids':[], 'max_slices':None, 'ext_consortium_id':None,
826 'max_slivers':None, 'is_public':True, 'peer_site_id': None,
827 'abbreviated_name':"iotlab", 'address_ids': [],
828 'url':"http,//www.senslab.info", 'person_ids':[],
829 'site_tag_ids':[], 'enabled': True, 'slice_ids':[],
830 'date_created': None, 'peer_id': None }
831 #if node['site_login_base'] not in self.site_dict.keys():
832 #self.site_dict[node['site_login_base']] = {'login_base':node['site_login_base'],
833 #'node_ids':nodes_per_site[node['site_login_base']],
834 #'latitude':"48.83726",
835 #'longitude':"- 2.10336",'name':"senslab",
836 #'pcu_ids':[], 'max_slices':None, 'ext_consortium_id':None,
837 #'max_slivers':None, 'is_public':True, 'peer_site_id': None,
838 #'abbreviated_name':"senslab", 'address_ids': [],
839 #'url':"http,//www.senslab.info", 'person_ids':[],
840 #'site_tag_ids':[], 'enabled': True, 'slice_ids':[],
841 #'date_created': None, 'peer_id': None }
846 OARrequests_uri_dict = {
848 {'uri':'/oarapi/version.json', 'parse_func': ParseVersion},
850 {'uri':'/oarapi/timezone.json' ,'parse_func': ParseTimezone },
852 {'uri':'/oarapi/jobs.json','parse_func': ParseJobs},
854 {'uri':'/oarapi/jobs/id.json','parse_func': ParseJobsIds},
855 'GET_jobs_id_resources':
856 {'uri':'/oarapi/jobs/id/resources.json',\
857 'parse_func': ParseJobsIdResources},
859 {'uri':'/oarapi/jobs/table.json','parse_func': ParseJobsTable},
861 {'uri':'/oarapi/jobs/details.json',\
862 'parse_func': ParseJobsDetails},
863 'GET_reserved_nodes':
865 '/oarapi/jobs/details.json?state=Running,Waiting,Launching',\
867 'parse_func':ParseReservedNodes},
871 {'uri':'/oarapi/jobs/details.json?state=Running',\
872 'parse_func':ParseRunningJobs},
873 'GET_resources_full':
874 {'uri':'/oarapi/resources/full.json',\
875 'parse_func': ParseResourcesFull},
877 {'uri':'/oarapi/resources/full.json',\
878 'parse_func': ParseResourcesFullSites},
880 {'uri':'/oarapi/resources.json' ,'parse_func': ParseResources},
882 {'uri':'/oarapi/jobs/id.json' ,'parse_func': ParseDeleteJobs}
888 def SendRequest(self, request, strval = None , username = None):
889 """ Connects to OAR , sends the valid GET requests and uses
890 the appropriate json parsing functions.
895 self.json_page.ResetNextPage()
898 if request in self.OARrequests_uri_dict :
899 while self.json_page.next_page:
900 self.json_page.raw_json = self.server.GETRequestToOARRestAPI(\
903 self.json_page.next_offset, \
905 self.json_page.FindNextPage()
906 if self.json_page.concatenate:
907 save_json.append(self.json_page.raw_json)
909 if self.json_page.concatenate and self.json_page.end :
910 self.json_page.raw_json = \
911 self.json_page.ConcatenateJsonPages(save_json)
913 return self.OARrequests_uri_dict[request]['parse_func'](self)
915 logger.error("OARRESTAPI OARGetParse __init__ : ERROR_REQUEST " \