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
173 :returns: a json dictionary if OAR successfully processed the GET
176 .. seealso:: OARrequests_uri_dict
178 self.oarserver['uri'] = \
179 OARGETParser.OARrequests_uri_dict[request]['uri']
180 #Get job details with username
181 if 'owner' in OARGETParser.OARrequests_uri_dict[request] and username:
182 self.oarserver['uri'] += \
183 OARGETParser.OARrequests_uri_dict[request]['owner'] + username
185 data = json.dumps({})
186 logger.debug("OARrestapi \tGETRequestToOARRestAPI %s" % (request))
188 self.oarserver['uri'] = self.oarserver['uri'].\
189 replace("id",str(strval))
192 self.oarserver['uri'] += next_page
195 headers['X-REMOTE_IDENT'] = username
197 logger.debug("OARrestapi: \t GETRequestToOARRestAPI \
198 self.oarserver['uri'] %s strval %s" \
199 %(self.oarserver['uri'], strval))
201 #seems that it does not work if we don't add this
202 headers['content-length'] = '0'
204 conn = HTTPConnection(self.oarserver['ip'], \
205 self.oarserver['port'])
206 conn.request("GET", self.oarserver['uri'], data, headers)
207 resp = ( conn.getresponse()).read()
210 except HTTPException, error :
211 logger.log_exc("GET_OAR_SRVR : Problem with OAR server : %s " \
213 #raise ServerError("GET_OAR_SRVR : Could not reach OARserver")
215 js_dict = json.loads(resp)
216 #print "\r\n \t\t\t js_dict keys" , js_dict.keys(), " \r\n", js_dict
219 except ValueError, error:
220 logger.log_exc("Failed to parse Server Response: %s ERROR %s"\
222 #raise ServerError("Failed to parse Server Response:" + js)
225 def POSTRequestToOARRestAPI(self, request, datadict, username=None):
226 """ Used to post a job on OAR , along with data associated
231 #first check that all params for are OK
233 self.oarserver['uri'] = \
234 self.OAR_REQUEST_POST_URI_DICT[request]['uri']
237 logger.log_exc("OARrestapi \tPOSTRequestToOARRestAPI request not \
240 if datadict and 'strval' in datadict:
241 self.oarserver['uri'] = self.oarserver['uri'].replace("id", \
242 str(datadict['strval']))
243 del datadict['strval']
245 data = json.dumps(datadict)
246 headers = {'X-REMOTE_IDENT':username, \
247 'content-type': self.POST_FORMAT['json']['content'], \
248 'content-length':str(len(data))}
251 conn = HTTPConnection(self.oarserver['ip'], \
252 self.oarserver['port'])
253 conn.request("POST", self.oarserver['uri'], data, headers)
254 resp = (conn.getresponse()).read()
257 logger.log_exc("POSTRequestToOARRestAPI NotConnected ERROR: \
258 data %s \r\n \t\n \t\t headers %s uri %s" \
259 %(data,headers,self.oarserver['uri']))
261 #raise ServerError("POST_OAR_SRVR : error")
264 answer = json.loads(resp)
265 logger.debug("POSTRequestToOARRestAPI : answer %s" % (answer))
268 except ValueError, error:
269 logger.log_exc("Failed to parse Server Response: error %s \
271 #raise ServerError("Failed to parse Server Response:" + answer)
274 class ParsingResourcesFull():
276 Class dedicated to parse the json response from a GET_resources_full from
282 Set the parsing dictionary. Works like a switch case, if the key is
283 found in the dictionary, then the associated function is called.
284 This is used in ParseNodes to create an usable dictionary from
285 the Json returned by OAR when issuing a GET resources full request.
287 .. seealso:: ParseNodes
290 self.resources_fulljson_dict = {
291 'network_address': self.AddNodeNetworkAddr,
292 'site': self.AddNodeSite,
293 # 'radio': self.AddNodeRadio,
294 'mobile': self.AddMobility,
298 'archi': self.AddHardwareType,
299 'state': self.AddBootState,
300 'id': self.AddOarNodeId,
305 def AddOarNodeId(self, tuplelist, value):
306 """Adds Oar internal node id to the nodes' attributes.
308 Appends tuple ('oar_id', node_id) to the tuplelist. Used by ParseNodes.
310 .. seealso:: ParseNodes
314 tuplelist.append(('oar_id', int(value)))
317 def AddNodeNetworkAddr(self, dictnode, value):
318 """First parsing function to be called to parse the json returned by OAR
319 answering a GET_resources (/oarapi/resources.json) request.
321 When a new node is found in the json, this function is responsible for
322 creating a new entry in the dictionary for storing information on this
323 specific node. The key is the node network address, which is also the
325 The value associated with the key is a tuple list.It contains all
326 the nodes attributes. The tuplelist will later be turned into a dict.
328 :param dictnode: should be set to the OARGETParser atribute
329 node_dictlist. It will store the information on the nodes.
330 :param value: the node_id is the network_address in the raw json.
332 :type dictnode: dictionary
334 .. seealso: ParseResources, ParseNodes
338 dictnode[node_id] = [('node_id', node_id),('hostname', node_id) ]
342 def AddNodeSite(self, tuplelist, value):
343 """Add the site's node to the dictionary.
346 :param tuplelist: tuple list on which to add the node's site.
347 Contains the other node attributes as well.
348 :param value: value to add to the tuple list, in this case the node's
350 :type tuplelist: list
353 .. seealso:: AddNodeNetworkAddr
356 tuplelist.append(('site', str(value)))
358 # def AddNodeRadio(tuplelist, value):
359 # """Add thenode's radio chipset type to the tuple list.
361 # :param tuplelist: tuple list on which to add the node's mobility
362 # status. The tuplelist is the value associated with the node's
363 # id in the OARGETParser
364 # 's dictionary node_dictlist.
365 # :param value: name of the radio chipset on the node.
366 # :type tuplelist: list
367 # :type value: string
369 # .. seealso:: AddNodeNetworkAddr
372 # tuplelist.append(('radio', str(value)))
375 def AddMobility(self, tuplelist, value):
376 """Add if the node is a mobile node or not to the tuple list.
378 :param tuplelist: tuple list on which to add the node's mobility status.
379 The tuplelist is the value associated with the node's id in the
380 OARGETParser's dictionary node_dictlist.
381 :param value: tells if a node is a mobile node or not. The value is found
384 :type tuplelist: list
387 .. seealso:: AddNodeNetworkAddr
391 tuplelist.append(('mobile', 'False'))
393 tuplelist.append(('mobile', 'True'))
396 def AddPosX(self, tuplelist, value):
397 """Add the node's position on the x axis.
399 :param tuplelist: tuple list on which to add the node's position . The
400 tuplelist is the value associated with the node's id in the
401 OARGETParser's dictionary node_dictlist.
402 :param value: the position x.
404 :type tuplelist: list
407 .. seealso:: AddNodeNetworkAddr
410 tuplelist.append(('posx', value ))
414 def AddPosY(self, tuplelist, value):
415 """Add the node's position on the y axis.
417 :param tuplelist: tuple list on which to add the node's position . The
418 tuplelist is the value associated with the node's id in the
419 OARGETParser's dictionary node_dictlist.
420 :param value: the position y.
422 :type tuplelist: list
425 .. seealso:: AddNodeNetworkAddr
428 tuplelist.append(('posy', value))
432 def AddPosZ(self, tuplelist, value):
433 """Add the node's position on the z axis.
435 :param tuplelist: tuple list on which to add the node's position . The
436 tuplelist is the value associated with the node's id in the
437 OARGETParser's dictionary node_dictlist.
438 :param value: the position z.
440 :type tuplelist: list
443 .. seealso:: AddNodeNetworkAddr
447 tuplelist.append(('posz', value))
451 def AddBootState(tself, tuplelist, value):
452 """Add the node's state, Alive or Suspected.
454 :param tuplelist: tuple list on which to add the node's state . The
455 tuplelist is the value associated with the node's id in the
456 OARGETParser 's dictionary node_dictlist.
457 :param value: node's state.
459 :type tuplelist: list
462 .. seealso:: AddNodeNetworkAddr
465 tuplelist.append(('boot_state', str(value)))
468 def AddHardwareType(self, tuplelist, value):
469 """Add the node's hardware model and radio chipset type to the tuple
472 :param tuplelist: tuple list on which to add the node's architecture
473 and radio chipset type.
474 :param value: hardware type: radio chipset. The value contains both the
475 architecture and the radio chipset, separated by a colon.
476 :type tuplelist: list
479 .. seealso:: AddNodeNetworkAddr
483 value_list = value.split(':')
484 tuplelist.append(('archi', value_list[0]))
485 tuplelist.append(('radio', value_list[1]))
489 # resources_fulljson_dict = {
490 # 'network_address': AddNodeNetworkAddr,
491 # 'site': AddNodeSite,
492 # # 'radio': AddNodeRadio,
493 # 'mobile': AddMobility,
497 # 'archi':AddHardwareType,
498 # 'state':AddBootState,
499 # 'id' : AddOarNodeId,
503 def __init__(self, srv) :
504 self.version_json_dict = {
505 'api_version' : None , 'apilib_version' :None,\
506 'api_timezone': None, 'api_timestamp': None, 'oar_version': None ,}
507 self.config = Config()
508 self.interface_hrn = self.config.SFA_INTERFACE_HRN
509 self.timezone_json_dict = {
510 'timezone': None, 'api_timestamp': None, }
511 #self.jobs_json_dict = {
512 #'total' : None, 'links' : [],\
513 #'offset':None , 'items' : [], }
514 #self.jobs_table_json_dict = self.jobs_json_dict
515 #self.jobs_details_json_dict = self.jobs_json_dict
517 self.node_dictlist = {}
519 self.json_page = JsonPage()
520 self.parsing_resourcesfull = ParsingResourcesFull()
522 self.SendRequest("GET_version")
528 def ParseVersion(self) :
529 """Parses the OAR answer to the GET_version ( /oarapi/version.json.)
531 Finds the OAR apilib version currently used. Has an impact on the json
532 structure returned by OAR, so the version has to be known before trying
533 to parse the jsons returned after a get request has been issued.
534 Updates the attribute version_json_dict.
538 if 'oar_version' in self.json_page.raw_json :
539 self.version_json_dict.update(api_version =
540 self.json_page.raw_json['api_version'],
541 apilib_version=self.json_page.raw_json['apilib_version'],
542 api_timezone=self.json_page.raw_json['api_timezone'],
543 api_timestamp=self.json_page.raw_json['api_timestamp'],
544 oar_version=self.json_page.raw_json['oar_version'])
546 self.version_json_dict.update(api_version =
547 self.json_page.raw_json['api'],
548 apilib_version=self.json_page.raw_json['apilib'],
549 api_timezone=self.json_page.raw_json['api_timezone'],
550 api_timestamp=self.json_page.raw_json['api_timestamp'],
551 oar_version=self.json_page.raw_json['oar'])
553 print self.version_json_dict['apilib_version']
556 def ParseTimezone(self):
557 """Get the timezone used by OAR.
559 Get the timezone from the answer to the GET_timezone request.
560 :return: api_timestamp and api timezone.
561 :rype: integer, integer
565 api_timestamp = self.json_page.raw_json['api_timestamp']
566 api_tz = self.json_page.raw_json['timezone']
567 return api_timestamp, api_tz
570 """Called when a GET_jobs request has been issued to OAR.
572 Corresponds to /oarapi/jobs.json uri. Currently returns the raw json
574 :returns: json_page.raw_json
577 .. warning:: Does not actually parse the information in the json. SA
583 return self.json_page.raw_json
585 def ParseJobsTable(self):
586 """In case we need to use the job table in the future.
588 Associated with the GET_jobs_table : '/oarapi/jobs/table.json uri.
589 .. warning:: NOT USED. DOES NOTHING.
591 print "ParseJobsTable"
593 def ParseJobsDetails(self):
594 """Currently only returns the same json in self.json_page.raw_json.
596 .. todo:: actually parse the json
597 .. warning:: currently, this function is not used a lot, so I have no
598 idea what could be useful to parse, returning the full json. NT
601 #logger.debug("ParseJobsDetails %s " %(self.json_page.raw_json))
602 return self.json_page.raw_json
605 def ParseJobsIds(self):
606 """Associated with the GET_jobs_id OAR request.
608 Parses the json dict (OAR answer) to the GET_jobs_id request
609 /oarapi/jobs/id.json.
612 :returns: dictionary whose keys are listed in the local variable
613 job_resources and values that are in the json dictionary returned
614 by OAR with the job information.
618 job_resources = ['wanted_resources', 'name', 'id', 'start_time',
619 'state', 'owner', 'walltime', 'message']
622 job_resources_full = ['launching_directory', 'links',
623 'resubmit_job_id', 'owner', 'events', 'message',
624 'scheduled_start', 'id', 'array_id', 'exit_code',
625 'properties', 'state','array_index', 'walltime',
626 'type', 'initial_request', 'stop_time', 'project',
627 'start_time', 'dependencies','api_timestamp','submission_time',
628 'reservation', 'stdout_file', 'types', 'cpuset_name',
629 'name', 'wanted_resources','queue','stderr_file','command']
632 job_info = self.json_page.raw_json
633 #logger.debug("OARESTAPI ParseJobsIds %s" %(self.json_page.raw_json))
636 for k in job_resources:
637 values.append(job_info[k])
638 return dict(zip(job_resources, values))
641 logger.log_exc("ParseJobsIds KeyError ")
644 def ParseJobsIdResources(self):
645 """ Parses the json produced by the request
646 /oarapi/jobs/id/resources.json.
647 Returns a list of oar node ids that are scheduled for the
652 for resource in self.json_page.raw_json['items']:
653 job_resources.append(resource['id'])
657 def ParseResources(self) :
658 """ Parses the json produced by a get_resources request on oar."""
660 #logger.debug("OARESTAPI \tParseResources " )
661 #resources are listed inside the 'items' list from the json
662 self.json_page.raw_json = self.json_page.raw_json['items']
665 def ParseReservedNodes(self):
666 """ Returns an array containing the list of the reserved nodes """
668 #resources are listed inside the 'items' list from the json
669 reservation_list = []
671 #Parse resources info
672 for json_element in self.json_page.raw_json['items']:
673 #In case it is a real reservation (not asap case)
674 if json_element['scheduled_start']:
675 job['t_from'] = json_element['scheduled_start']
676 job['t_until'] = int(json_element['scheduled_start']) + \
677 int(json_element['walltime'])
678 #Get resources id list for the job
679 job['resource_ids'] = [ node_dict['id'] for node_dict
680 in json_element['resources']]
682 job['t_from'] = "As soon as possible"
683 job['t_until'] = "As soon as possible"
684 job['resource_ids'] = ["Undefined"]
687 job['state'] = json_element['state']
688 job['lease_id'] = json_element['id']
691 job['user'] = json_element['owner']
692 #logger.debug("OARRestapi \tParseReservedNodes job %s" %(job))
693 reservation_list.append(job)
696 return reservation_list
698 def ParseRunningJobs(self):
699 """ Gets the list of nodes currently in use from the attributes of the
703 logger.debug("OARESTAPI \tParseRunningJobs__________________________ ")
704 #resources are listed inside the 'items' list from the json
706 for job in self.json_page.raw_json['items']:
707 for node in job['nodes']:
708 nodes.append(node['network_address'])
711 def ChangeRawJsonDependingOnApilibVersion(self):
713 if self.version_json_dict['apilib_version'] != "0.2.10":
714 self.json_page.raw_json = self.json_page.raw_json['items']
716 def ParseDeleteJobs(self):
717 """ No need to parse anything in this function.A POST
718 is done to delete the job.
723 def ParseResourcesFull(self) :
724 """ This method is responsible for parsing all the attributes
725 of all the nodes returned by OAR when issuing a get resources full.
726 The information from the nodes and the sites are separated.
727 Updates the node_dictlist so that the dictionnary of the platform's
728 nodes is available afterwards.
731 logger.debug("OARRESTAPI ParseResourcesFull________________________ ")
732 #print self.json_page.raw_json[1]
733 #resources are listed inside the 'items' list from the json
734 self.ChangeRawJsonDependingOnApilibVersion()
737 return self.node_dictlist
739 def ParseResourcesFullSites(self) :
740 """ UNUSED. Originally used to get information from the sites.
741 ParseResourcesFull is used instead.
744 self.ChangeRawJsonDependingOnApilibVersion()
747 return self.site_dict
750 def ParseNodes(self):
751 """ Parse nodes properties from OAR
752 Put them into a dictionary with key = node id and value is a dictionary
753 of the node properties and properties'values.
757 _resources_fulljson_dict = \
758 self.parsing_resourcesfull.resources_fulljson_dict
759 keys = _resources_fulljson_dict.keys()
762 for dictline in self.json_page.raw_json:
764 # dictionary is empty and/or a new node has to be inserted
765 node_id = _resources_fulljson_dict['network_address'](\
766 self.node_dictlist, dictline['network_address'])
769 if k == 'network_address':
772 _resources_fulljson_dict[k](\
773 self.node_dictlist[node_id], dictline[k])
775 #The last property has been inserted in the property tuple list,
777 #Turn the property tuple list (=dict value) into a dictionary
778 self.node_dictlist[node_id] = dict(self.node_dictlist[node_id])
782 def iotlab_hostname_to_hrn(root_auth, hostname):
784 Transforms a node hostname into a SFA hrn.
786 :param root_auth: Name of the root authority of the SFA server. In
787 our case, it is set to iotlab.
788 :param hostname: node's hotname, given by OAR.
789 :type root_auth: string
790 :type hostname: string
791 :returns: inserts the root_auth and '.' before the hostname.
795 return root_auth + '.' + hostname
799 def ParseSites(self):
800 """ Returns a list of dictionnaries containing the sites' attributes."""
804 #logger.debug(" OARrestapi.py \tParseSites self.node_dictlist %s"\
805 #%(self.node_dictlist))
806 # Create a list of nodes per site_id
807 for node_id in self.node_dictlist:
808 node = self.node_dictlist[node_id]
810 if node['site'] not in nodes_per_site:
811 nodes_per_site[node['site']] = []
812 nodes_per_site[node['site']].append(node['node_id'])
814 if node['node_id'] not in nodes_per_site[node['site']]:
815 nodes_per_site[node['site']].append(node['node_id'])
817 #Create a site dictionary whose key is site_login_base
818 # (name of the site) and value is a dictionary of properties,
819 # including the list of the node_ids
820 for node_id in self.node_dictlist:
821 node = self.node_dictlist[node_id]
822 node.update({'hrn':self.iotlab_hostname_to_hrn(self.interface_hrn,
824 self.node_dictlist.update({node_id:node})
826 if node['site'] not in self.site_dict:
827 self.site_dict[node['site']] = {
829 'node_ids':nodes_per_site[node['site']],
830 'latitude':"48.83726",
831 'longitude':"- 2.10336",
832 'name': config.SFA_REGISTRY_ROOT_AUTH,
833 'pcu_ids':[], 'max_slices':None, 'ext_consortium_id':None,
834 'max_slivers':None, 'is_public':True, 'peer_site_id': None,
835 'abbreviated_name':"iotlab", 'address_ids': [],
836 'url':"http,//www.senslab.info", 'person_ids':[],
837 'site_tag_ids':[], 'enabled': True, 'slice_ids':[],
838 'date_created': None, 'peer_id': None }
841 OARrequests_uri_dict = {
843 {'uri':'/oarapi/version.json', 'parse_func': ParseVersion},
845 {'uri':'/oarapi/timezone.json' ,'parse_func': ParseTimezone },
847 {'uri':'/oarapi/jobs.json','parse_func': ParseJobs},
849 {'uri':'/oarapi/jobs/id.json','parse_func': ParseJobsIds},
850 'GET_jobs_id_resources':
851 {'uri':'/oarapi/jobs/id/resources.json',\
852 'parse_func': ParseJobsIdResources},
854 {'uri':'/oarapi/jobs/table.json','parse_func': ParseJobsTable},
856 {'uri':'/oarapi/jobs/details.json',\
857 'parse_func': ParseJobsDetails},
858 'GET_reserved_nodes':
860 '/oarapi/jobs/details.json?state=Running,Waiting,Launching',\
862 'parse_func':ParseReservedNodes},
866 {'uri':'/oarapi/jobs/details.json?state=Running',\
867 'parse_func':ParseRunningJobs},
868 'GET_resources_full':
869 {'uri':'/oarapi/resources/full.json',\
870 'parse_func': ParseResourcesFull},
872 {'uri':'/oarapi/resources/full.json',\
873 'parse_func': ParseResourcesFullSites},
875 {'uri':'/oarapi/resources.json' ,'parse_func': ParseResources},
877 {'uri':'/oarapi/jobs/id.json' ,'parse_func': ParseDeleteJobs}
883 def SendRequest(self, request, strval = None , username = None):
884 """ Connects to OAR , sends the valid GET requests and uses
885 the appropriate json parsing functions.
890 self.json_page.ResetNextPage()
893 if request in self.OARrequests_uri_dict :
894 while self.json_page.next_page:
895 self.json_page.raw_json = self.server.GETRequestToOARRestAPI(\
898 self.json_page.next_offset, \
900 self.json_page.FindNextPage()
901 if self.json_page.concatenate:
902 save_json.append(self.json_page.raw_json)
904 if self.json_page.concatenate and self.json_page.end :
905 self.json_page.raw_json = \
906 self.json_page.ConcatenateJsonPages(save_json)
908 return self.OARrequests_uri_dict[request]['parse_func'](self)
910 logger.error("OARRESTAPI OARGetParse __init__ : ERROR_REQUEST " \