Add TaskQueue sample.
Index: samples/gtaskqueue_sample/README =================================================================== new file mode 100755
This commit is contained in:
		
							
								
								
									
										46
									
								
								samples/gtaskqueue_sample/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								samples/gtaskqueue_sample/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| This acts as a sample as well as commandline tool for accessing Google TaskQueue | ||||
| APIs. | ||||
|  | ||||
| Installation | ||||
| ============ | ||||
|  | ||||
| To install, simply say | ||||
|  | ||||
|    $ python setup.py install --record=files.txt | ||||
|  | ||||
| to install the files and record what files are installed in files.txt. | ||||
| Make sure that you have already installed the google-python-client-libraries | ||||
| using the setup.py in the toplevel directory. | ||||
|  | ||||
| You may need root priveleges for install. | ||||
|  | ||||
| Running | ||||
| ======= | ||||
| This sample provides following: | ||||
| 1. gtaskqueue: This works as a command-line tool to access Google TaskQueue | ||||
| API. You can perform various operations on taskqueues such as leastask, | ||||
| getask, listtasks, deletetask, getqueue. | ||||
| Example usage: | ||||
|   i. To lease a task | ||||
|   gtaskqueue leasetask --taskqueue_name=<your queue_name> | ||||
|   -lease_secs=30  --project_name=<your appengine app_name> | ||||
|   ii. To get stats on a queue | ||||
|   gtaskqueue getqueue --taskqueue_name=<your queue_name> | ||||
|   --project_name=<your appengine app_name> --get_stats | ||||
|  | ||||
| 2. gtaskqueue_puller: This works as a worker to continuously pull tasks enqueued | ||||
| by your app,perform the task and the post the output back to your app. | ||||
| Example Usage: | ||||
|   gtaskqueue_puller --taskqueue_name=<your queue_name> | ||||
|   -lease_secs=30  --project_name=<your appengine app_name> | ||||
|   --executable_binary=”cat” --output_url=<url location if you want to pos the data | ||||
|   back(optional)> | ||||
|  | ||||
| Third Party Libraries | ||||
| ===================== | ||||
|  | ||||
| These libraries will be installed when you install the client library: | ||||
|  | ||||
| http://code.google.com/p/httplib2 | ||||
| http://code.google.com/p/uri-templates | ||||
| http://github.com/simplegeo/python-oauth2 | ||||
							
								
								
									
										334
									
								
								samples/gtaskqueue_sample/gtaskqueue/client_task.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										334
									
								
								samples/gtaskqueue_sample/gtaskqueue/client_task.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,334 @@ | ||||
| #!/usr/bin/env python | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #      http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| """Class to encapsulate task related information and methods on task_puller.""" | ||||
|  | ||||
|  | ||||
|  | ||||
| import base64 | ||||
| import oauth2 as oauth | ||||
| import os | ||||
| import subprocess | ||||
| import tempfile | ||||
| import time | ||||
| import urllib2 | ||||
| from apiclient.errors import HttpError | ||||
| from gtaskqueue.taskqueue_logger import logger | ||||
| import gflags as flags | ||||
|  | ||||
|  | ||||
| FLAGS = flags.FLAGS | ||||
| flags.DEFINE_string( | ||||
|         'executable_binary', | ||||
|         '/bin/cat', | ||||
|         'path of the binary to be executed') | ||||
| flags.DEFINE_string( | ||||
|         'output_url', | ||||
|         '', | ||||
|         'url to which output is posted. The url must include param name, ' | ||||
|         'value for which is populated with task_id from puller while posting ' | ||||
|         'the data. Format of output url is absolute url which handles the' | ||||
|         'post request from task queue puller.' | ||||
|         '(Eg: "http://taskpuller.appspot.com/taskdata?name=").' | ||||
|         'The Param value is always the task_id. The handler for this post' | ||||
|         'should be able to associate the task with its id and take' | ||||
|         'appropriate action. Use the appengine_access_token.py tool to' | ||||
|         'generate the token and store it in a file before you start.') | ||||
| flags.DEFINE_string( | ||||
|         'appengine_access_token_file', | ||||
|         None, | ||||
|         'File containing an Appengine Access token, if any. If present this' | ||||
|         'token is added to the output_url request, so that the output_url can' | ||||
|         'be an authenticated end-point. Use the appengine_access_token.py tool' | ||||
|         'to generate the token and store it in a file before you start.') | ||||
| flags.DEFINE_float( | ||||
|         'task_timeout_secs', | ||||
|         '3600', | ||||
|         'timeout to kill the task') | ||||
|  | ||||
|  | ||||
| class ClientTaskInitError(Exception): | ||||
|     """Raised when initialization of client task fails.""" | ||||
|  | ||||
|     def __init__(self, task_id, error_str): | ||||
|         Exception.__init__(self) | ||||
|         self.task_id = task_id | ||||
|         self.error_str = error_str | ||||
|  | ||||
|     def __str__(self): | ||||
|         return ('Error initializing task "%s". Error details "%s". ' | ||||
|                         % (self.task_id, self.error_str)) | ||||
|  | ||||
|  | ||||
| class ClientTask(object): | ||||
|     """Class to encapsulate task information pulled by taskqueue_puller module. | ||||
|  | ||||
|     This class is responsible for creating an independent client task object by | ||||
|     taking some information from lease response task object. It encapsulates | ||||
|     methods responsible for spawning an independent subprocess for executing | ||||
|     the task, tracking the status of the task and also deleting the task from | ||||
|     taskqeueue when completed. It also has the functionality to give the output | ||||
|     back to the application by posting to the specified url. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, task): | ||||
|         self._task = task | ||||
|         self._process = None | ||||
|         self._output_file = None | ||||
|  | ||||
|     # Class method that caches the Appengine Access Token if any | ||||
|     @classmethod | ||||
|     def get_access_token(cls): | ||||
|         if not FLAGS.appengine_access_token_file: | ||||
|             return None | ||||
|         if not _access_token: | ||||
|             fhandle = open(FLAGS.appengine_access_token_file, 'rb') | ||||
|             _access_token = oauth.Token.from_string(fhandle.read()) | ||||
|             fhandle.close() | ||||
|         return _access_token | ||||
|  | ||||
|     def init(self): | ||||
|         """Extracts information from task object and intializes processing. | ||||
|  | ||||
|         Extracts id and payload from task object, decodes the payload and puts | ||||
|         it in input file. After this, it spawns a subprocess to execute the | ||||
|         task. | ||||
|  | ||||
|         Returns: | ||||
|             True if everything till task execution starts fine. | ||||
|             False if anything goes wrong in initialization of task execution. | ||||
|         """ | ||||
|         try: | ||||
|             self.task_id = self._task.get('id') | ||||
|             self._payload = self._decode_base64_payload( | ||||
|                 self._task.get('payloadBase64')) | ||||
|             self._payload_file = self._dump_payload_to_file() | ||||
|             self._start_task_execution() | ||||
|             return True | ||||
|         except ClientTaskInitError, ctie: | ||||
|             logger.error(str(ctie)) | ||||
|             return False | ||||
|  | ||||
|     def _decode_base64_payload(self, encoded_str): | ||||
|         """Method to decode payload encoded in base64.""" | ||||
|         try: | ||||
|             # If the payload is empty, do not try to decode it. Payload usually | ||||
|             # not expected to be empty and hence log a warning and then | ||||
|             # continue. | ||||
|             if encoded_str: | ||||
|                 decoded_str = base64.urlsafe_b64decode( | ||||
|                     encoded_str.encode('utf-8')) | ||||
|                 return decoded_str | ||||
|             else: | ||||
|                 logger.warn('Empty paylaod for task %s' % self.task_id) | ||||
|                 return '' | ||||
|         except base64.binascii.Error, berror: | ||||
|             logger.error('Error decoding payload for task %s. Error details %s' | ||||
|                          % (self.task_id, str(berror))) | ||||
|             raise ClientTaskInitError(self.task_id, 'Error decoding payload') | ||||
|         # Generic catch block to avoid crashing of puller due to some bad | ||||
|         # encoding issue wih payload of any task. | ||||
|         except: | ||||
|             raise ClientTaskInitError(self.task_id, 'Error decoding payload') | ||||
|  | ||||
|     def _dump_payload_to_file(self): | ||||
|         """Method to write input extracted from payload to a temporary file.""" | ||||
|         try: | ||||
|             (fd, fname) = tempfile.mkstemp() | ||||
|             f = os.fdopen(fd, 'w') | ||||
|             f.write(self._payload) | ||||
|             f.close() | ||||
|             return fname | ||||
|         except OSError: | ||||
|             logger.error('Error dumping payload %s. Error details %s' % | ||||
|                                       (self.task_id, str(OSError))) | ||||
|             raise ClientTaskInitError(self.task_id, 'Error dumping payload') | ||||
|  | ||||
|     def _get_input_file(self): | ||||
|         return self._payload_file | ||||
|  | ||||
|     def _post_output(self): | ||||
|         """Posts the outback back to specified url in the form of a byte | ||||
|         array. | ||||
|  | ||||
|         It reads the output generated by the task as a byte-array. It posts the | ||||
|         response to specified url appended with the taskId. The  application | ||||
|         using the taskqueue must have a handler to handle the data being posted | ||||
|         from puller. Format of body of response object is byte-array to make | ||||
|         the it genric for any kind of output generated. | ||||
|  | ||||
|         Returns: | ||||
|             True/False based on post status. | ||||
|         """ | ||||
|         if FLAGS.output_url: | ||||
|             try: | ||||
|                 f = open(self._get_output_file(), 'rb') | ||||
|                 body = f.read() | ||||
|                 f.close() | ||||
|                 url = FLAGS.output_url + self.task_id | ||||
|                 logger.debug('Posting data to url %s' % url) | ||||
|                 headers = {'Content-Type': 'byte-array'} | ||||
|                 # Add an access token to the headers if specified. | ||||
|                 # This enables the output_url to be authenticated and not open. | ||||
|                 access_token = ClientTask.get_access_token() | ||||
|                 if access_token: | ||||
|                     consumer = oauth.Consumer('anonymous', 'anonymous') | ||||
|                     oauth_req = oauth.Request.from_consumer_and_token( | ||||
|                         consumer, | ||||
|                         token=access_token, | ||||
|                         http_url=url) | ||||
|                     headers.update(oauth_req.to_header()) | ||||
|                 # TODO: Use httplib instead of urllib for consistency. | ||||
|                 req = urllib2.Request(url, body, headers) | ||||
|                 urllib2.urlopen(req) | ||||
|             except ValueError: | ||||
|                 logger.error('Error posting data back %s. Error details %s' | ||||
|                              % (self.task_id, str(ValueError))) | ||||
|                 return False | ||||
|             except Exception: | ||||
|                 logger.error('Exception while posting data back %s. Error' | ||||
|                              'details %s' % (self.task_id, str(Exception))) | ||||
|                 return False | ||||
|         return True | ||||
|  | ||||
|     def _get_output_file(self): | ||||
|         """Returns the output file if it exists, else creates it and returns | ||||
|         it.""" | ||||
|         if not self._output_file: | ||||
|             (_, self._output_file) = tempfile.mkstemp() | ||||
|         return self._output_file | ||||
|  | ||||
|     def get_task_id(self): | ||||
|         return self.task_id | ||||
|  | ||||
|     def _start_task_execution(self): | ||||
|         """Method to spawn subprocess to execute the tasks. | ||||
|  | ||||
|         This method splits the commands/executable_binary to desired arguments | ||||
|         format for Popen API. It appends input and output files to the | ||||
|         arguments. It is assumed that commands/executable_binary expects input | ||||
|         and output files as first and second positional parameters | ||||
|         respectively. | ||||
|         """ | ||||
|         # TODO: Add code to handle the cleanly shutdown when a process is killed | ||||
|         # by Ctrl+C. | ||||
|         try: | ||||
|             cmdline = FLAGS.executable_binary.split(' ') | ||||
|             cmdline.append(self._get_input_file()) | ||||
|             cmdline.append(self._get_output_file()) | ||||
|             self._process = subprocess.Popen(cmdline) | ||||
|             self.task_start_time = time.time() | ||||
|         except OSError: | ||||
|             logger.error('Error creating subprocess %s. Error details %s' | ||||
|                         % (self.task_id, str(OSError))) | ||||
|             self._cleanup() | ||||
|             raise ClientTaskInitError(self.task_id, | ||||
|                                       'Error creating subprocess') | ||||
|         except ValueError: | ||||
|             logger.error('Invalid arguments while executing task ', | ||||
|                          self.task_id) | ||||
|             self._cleanup() | ||||
|             raise ClientTaskInitError(self.task_id, | ||||
|                                       'Invalid arguments while executing task') | ||||
|  | ||||
|     def is_completed(self, task_api): | ||||
|         """Method to check if task has finished executing. | ||||
|  | ||||
|         This is responsible for checking status of task execution. If the task | ||||
|         has already finished executing, it deletes the task from the task | ||||
|         queue. If the task has been running since long time then it assumes | ||||
|         that there is high proabbility that it is dfunct and hence kills the | ||||
|         corresponding subprocess. In this case, task had not completed | ||||
|         successfully and hence we do not delete it form the taskqueue. In above | ||||
|         two cases, task completion status is returned as true since there is | ||||
|         nothing more to run in the task. In all other cases, task is still | ||||
|         running and hence we return false as completion status. | ||||
|  | ||||
|         Args: | ||||
|             task_api: handle for taskqueue api collection. | ||||
|  | ||||
|         Returns: | ||||
|             Task completion status (True/False) | ||||
|         """ | ||||
|         status = False | ||||
|         try: | ||||
|             task_status = self._process.poll() | ||||
|             if task_status == 0: | ||||
|                 status = True | ||||
|                 if self._post_output(): | ||||
|                     self._delete_task_from_queue(task_api) | ||||
|                 self._cleanup() | ||||
|             elif self._has_timedout(): | ||||
|                 status = True | ||||
|                 self._kill_subprocess() | ||||
|         except OSError: | ||||
|             logger.error('Error during polling status of task %s, Error '  | ||||
|                          'details %s' % (self.task_id, str(OSError))) | ||||
|         return status | ||||
|  | ||||
|     def _cleanup(self): | ||||
|         """Cleans up temporary input/output files used in task execution.""" | ||||
|         try: | ||||
|             if os.path.exists(self._get_input_file()): | ||||
|                 os.remove(self._get_input_file()) | ||||
|             if os.path.exists(self._get_output_file()): | ||||
|                 os.remove(self._get_output_file()) | ||||
|         except OSError: | ||||
|             logger.error('Error during file cleanup for task %s. Error' | ||||
|                          'details %s' % (self.task_id, str(OSError))) | ||||
|  | ||||
|     def _delete_task_from_queue(self, task_api): | ||||
|         """Method to delete the task from the taskqueue. | ||||
|  | ||||
|         First, it tries to post the output back to speified url. On successful | ||||
|         post, the task is deleted from taskqueue since the task has produced | ||||
|         expected output. If the post was unsuccessful, the task is not deleted | ||||
|         form the tskqueue since the expected output has yet not reached the | ||||
|         application. In either case cleanup is performed on the task. | ||||
|  | ||||
|         Args: | ||||
|             task_api: handle for taskqueue api collection. | ||||
|  | ||||
|         Returns: | ||||
|             Delete status (True/False) | ||||
|         """ | ||||
|  | ||||
|         try: | ||||
|             delete_request = task_api.tasks().delete( | ||||
|                 project=FLAGS.project_name, | ||||
|                 taskqueue=FLAGS.taskqueue_name, | ||||
|                 task=self.task_id) | ||||
|             delete_request.execute() | ||||
|         except HttpError, http_error: | ||||
|             logger.error('Error deleting task %s from taskqueue.' | ||||
|                          'Error details %s' | ||||
|                          % (self.task_id, str(http_error))) | ||||
|  | ||||
|     def _has_timedout(self): | ||||
|         """Checks if task has been running since long and has timedout.""" | ||||
|         if (time.time() - self.task_start_time) > FLAGS.task_timeout_secs: | ||||
|             return True | ||||
|         else: | ||||
|             return False | ||||
|  | ||||
|     def _kill_subprocess(self): | ||||
|         """Kills the process after cleaning up the task.""" | ||||
|         self._cleanup() | ||||
|         try: | ||||
|             self._process.kill() | ||||
|             logger.info('Trying to kill task %s, since it has been running ' | ||||
|                         'for long' % self.task_id) | ||||
|         except OSError: | ||||
|             logger.error('Error killing task %s. Error details %s' | ||||
|                          % (self.task_id, str(OSError))) | ||||
							
								
								
									
										116
									
								
								samples/gtaskqueue_sample/gtaskqueue/gen_appengine_access_token
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								samples/gtaskqueue_sample/gtaskqueue/gen_appengine_access_token
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | ||||
| #!/usr/bin/env python | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #      http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| """Tool to get an Access Token to access an auth protected Appengine end point. | ||||
|  | ||||
| This tool talks to the appengine end point, and gets an Access Token that is | ||||
| stored in a file. This token can be used by a tool to do authorized access to | ||||
| an appengine end point. | ||||
| """ | ||||
|  | ||||
|  | ||||
|  | ||||
| from google.apputils import app | ||||
| import gflags as flags | ||||
| import httplib2 | ||||
| import oauth2 as oauth | ||||
| import time | ||||
|  | ||||
| FLAGS = flags.FLAGS | ||||
|  | ||||
| flags.DEFINE_string( | ||||
|         'appengine_host', | ||||
|         None, | ||||
|         'Appengine Host for whom we are trying to get an access token') | ||||
| flags.DEFINE_string( | ||||
|         'access_token_file', | ||||
|         None, | ||||
|         'The file where the access token is stored') | ||||
|  | ||||
|  | ||||
| def get_access_token(): | ||||
|     if not FLAGS.appengine_host: | ||||
|         print('must supply the appengine host') | ||||
|         exit(1) | ||||
|  | ||||
|     # setup | ||||
|     server = FLAGS.appengine_host | ||||
|     request_token_url = server + '/_ah/OAuthGetRequestToken' | ||||
|     authorization_url = server + '/_ah/OAuthAuthorizeToken' | ||||
|     access_token_url = server + '/_ah/OAuthGetAccessToken' | ||||
|     consumer = oauth.Consumer('anonymous', 'anonymous') | ||||
|     signature_method_hmac_sha1 = oauth.SignatureMethod_HMAC_SHA1() | ||||
|  | ||||
|     # The Http client that will be used to make the requests. | ||||
|     h = httplib2.Http() | ||||
|  | ||||
|     # get request token | ||||
|     print '* Obtain a request token ...' | ||||
|     parameters = {} | ||||
|     # We dont have a callback server, we're going to use the browser to | ||||
|     # authorize. | ||||
|  | ||||
|     #TODO: Add check for 401 etc | ||||
|     parameters['oauth_callback'] = 'oob' | ||||
|     oauth_req1 = oauth.Request.from_consumer_and_token( | ||||
|         consumer, http_url=request_token_url, parameters=parameters) | ||||
|     oauth_req1.sign_request(signature_method_hmac_sha1, consumer, None) | ||||
|     print 'Request headers: %s' % str(oauth_req1.to_header()) | ||||
|     response, content = h.request(oauth_req1.to_url(), 'GET') | ||||
|     token = oauth.Token.from_string(content) | ||||
|     print 'GOT key: %s  secret:%s' % (str(token.key), str(token.secret)) | ||||
|  | ||||
|     print '* Authorize the request token ...' | ||||
|     oauth_req2 = oauth.Request.from_token_and_callback( | ||||
|         token=token, callback='oob', http_url=authorization_url) | ||||
|     print 'Please run this URL in a browser and paste the token back here' | ||||
|     print oauth_req2.to_url() | ||||
|     verification_code = raw_input('Enter verification code: ').strip() | ||||
|     token.set_verifier(verification_code) | ||||
|  | ||||
|     # get access token | ||||
|     print '* Obtain an access token ...' | ||||
|     oauth_req3 = oauth.Request.from_consumer_and_token( | ||||
|         consumer, token=token, http_url=access_token_url) | ||||
|     oauth_req3.sign_request(signature_method_hmac_sha1, consumer, token) | ||||
|     print 'Request headers: %s' % str(oauth_req3.to_header()) | ||||
|     response, content = h.request(oauth_req3.to_url(), 'GET') | ||||
|     access_token = oauth.Token.from_string(content) | ||||
|     print 'Access Token key: %s  secret:%s' % (str(access_token.key), | ||||
|                                                str(access_token.secret)) | ||||
|  | ||||
|     # Save the token to a file if its specified. | ||||
|     if FLAGS.access_token_file: | ||||
|         fhandle = open(FLAGS.access_token_file, 'w') | ||||
|         fhandle.write(access_token.to_string()) | ||||
|         fhandle.close() | ||||
|  | ||||
|     # Example : access some protected resources | ||||
|     print '* Checking the access token against protected resources...' | ||||
|     # Assumes that the server + "/" is protected. | ||||
|     test_url = server + "/" | ||||
|     oauth_req4 = oauth.Request.from_consumer_and_token(consumer, | ||||
|                                                        token=token, | ||||
|                                                        http_url=test_url) | ||||
|     oauth_req4.sign_request(signature_method_hmac_sha1, consumer, token) | ||||
|     resp, content = h.request(test_url, "GET", headers=oauth_req4.to_header()) | ||||
|     print resp | ||||
|     print content | ||||
|  | ||||
|  | ||||
| def main(argv): | ||||
|     get_access_token() | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|         app.run() | ||||
							
								
								
									
										53
									
								
								samples/gtaskqueue_sample/gtaskqueue/gtaskqueue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								samples/gtaskqueue_sample/gtaskqueue/gtaskqueue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| #!/usr/bin/env python | ||||
| # | ||||
| # Copyright (C) 2010 Google Inc. | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #      http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| # | ||||
|  | ||||
| """Command line tool for interacting with Google TaskQueue API.""" | ||||
|  | ||||
| __version__ = '0.0.1' | ||||
|  | ||||
|  | ||||
| import logging | ||||
|  | ||||
| from gtaskqueue import task_cmds | ||||
| from gtaskqueue import taskqueue_cmds | ||||
|  | ||||
| from google.apputils import appcommands | ||||
| import gflags as flags | ||||
|  | ||||
| LOG_LEVELS = [logging.DEBUG, | ||||
|               logging.INFO, | ||||
|               logging.WARNING, | ||||
|               logging.CRITICAL] | ||||
| LOG_LEVEL_NAMES = map(logging.getLevelName, LOG_LEVELS) | ||||
| FLAGS = flags.FLAGS | ||||
|  | ||||
| flags.DEFINE_enum( | ||||
|         'log_level', | ||||
|         logging.getLevelName(logging.WARNING), | ||||
|         LOG_LEVEL_NAMES, | ||||
|         'Logging output level.') | ||||
|  | ||||
|  | ||||
| def main(unused_argv): | ||||
|     log_level_map = dict( | ||||
|         [(logging.getLevelName(level), level) for level in LOG_LEVELS]) | ||||
|     logging.getLogger().setLevel(log_level_map[FLAGS.log_level]) | ||||
|     taskqueue_cmds.add_commands() | ||||
|     task_cmds.add_commands() | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     appcommands.Run() | ||||
							
								
								
									
										348
									
								
								samples/gtaskqueue_sample/gtaskqueue/gtaskqueue_puller
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										348
									
								
								samples/gtaskqueue_sample/gtaskqueue/gtaskqueue_puller
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,348 @@ | ||||
| #!/usr/bin/env python | ||||
| # | ||||
| # Copyright (C) 2010 Google Inc. | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #      http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| """Module to pull tasks from TaskQueues and execute them. | ||||
|  | ||||
| This module does the following in an infinite loop. | ||||
| 1. Connects to Task API (of TaskQueues API collection) to request lease on | ||||
|    certain number of tasks (specified by user). | ||||
| 2. Spawns parallel processes to execute the leased tasks. | ||||
| 3. Polls all the tasks continously till they finish. | ||||
| 4. Deletes the tasks from taskqueue on their successful completion. | ||||
| 5. It lets the user specify when to invoke the lease request instead of polling | ||||
|    tasks status in a tight loop for better resource utilization: | ||||
|       a. Invoke the Lease request when runnning tasks go beyound certain | ||||
|          threshold (min_running_tasks) | ||||
|       b. Wait time becomes more than specified poll-time-out interval. | ||||
| 6. Repeat the steps from 1 to 5 when either all tasks have finished executing | ||||
|    or one of the conditions in 5) is met. """ | ||||
|  | ||||
|  | ||||
|  | ||||
| import sys | ||||
| import time | ||||
| from apiclient.errors import HttpError | ||||
| from gtaskqueue.client_task import ClientTask | ||||
| from gtaskqueue.taskqueue_client import TaskQueueClient | ||||
| from gtaskqueue.taskqueue_logger import logger | ||||
| from gtaskqueue.taskqueue_logger import set_logger | ||||
| from google.apputils import app | ||||
| import gflags as flags | ||||
|  | ||||
| FLAGS = flags.FLAGS | ||||
| flags.DEFINE_string( | ||||
|         'project_name', | ||||
|         'default', | ||||
|         'The name of the Taskqueue API project.') | ||||
| flags.DEFINE_string( | ||||
|         'taskqueue_name', | ||||
|         'testpuller', | ||||
|         'taskqueue to which client wants to connect to') | ||||
| flags.DEFINE_integer( | ||||
|         'lease_secs', | ||||
|         30, | ||||
|         'The lease for the task in seconds') | ||||
| flags.DEFINE_integer( | ||||
|         'num_tasks', | ||||
|         10, | ||||
|         'The number of tasks to lease') | ||||
| flags.DEFINE_integer( | ||||
|         'min_running_tasks', | ||||
|         0, | ||||
|         'minmum number of tasks below which lease can be invoked') | ||||
| flags.DEFINE_float( | ||||
|         'sleep_interval_secs', | ||||
|         2, | ||||
|         'sleep interval when no tasks are found in the taskqueue') | ||||
| flags.DEFINE_float( | ||||
|         'timeout_secs_for_next_lease_request', | ||||
|         600, | ||||
|         'Wait time before next poll when no tasks are found in the' | ||||
|         'queue (in seconds)') | ||||
| flags.DEFINE_integer( | ||||
|         'taskapi_requests_per_sec', | ||||
|         None, | ||||
|         'limit on task_api requests per second') | ||||
| flags.DEFINE_float( | ||||
|         'sleep_before_next_poll_secs', | ||||
|         2, | ||||
|         'sleep interval before next poll') | ||||
|  | ||||
|  | ||||
| class TaskQueuePuller(object): | ||||
|     """Maintains state information for TaskQueuePuller.""" | ||||
|  | ||||
|     def __init__(self): | ||||
|         self._last_lease_time = None | ||||
|         self._poll_timeout_start = None | ||||
|         self._num_last_leased_tasks = 0 | ||||
|         # Dictionary for running tasks's ids and their corresponding | ||||
|         # client_task object. | ||||
|         self._taskprocess_map = {} | ||||
|         try: | ||||
|             self.__tcq = TaskQueueClient() | ||||
|             self.task_api = self.__tcq.get_taskapi() | ||||
|         except HttpError, http_error: | ||||
|             logger.error('Could not get TaskQueue API handler and hence' \ | ||||
|                        'exiting: %s' % str(http_error)) | ||||
|             sys.exit() | ||||
|  | ||||
|     def _can_lease(self): | ||||
|         """Determines if new tasks can be leased. | ||||
|  | ||||
|         Determines if new taks can be leased based on | ||||
|             1. Number of tasks already running in the system. | ||||
|             2. Limit on accessing the taskqueue apirary. | ||||
|  | ||||
|         Returns: | ||||
|             True/False. | ||||
|         """ | ||||
|         if self._num_tasks_to_lease() > 0 and not self._is_rate_exceeded(): | ||||
|             return True | ||||
|         else: | ||||
|             return False | ||||
|  | ||||
|     def _is_rate_exceeded(self): | ||||
|  | ||||
|         """Determines if requests/second to TaskQueue API has exceeded limit. | ||||
|  | ||||
|         We do not access the APIs beyond the specified permissible limit. | ||||
|         If we have run N tasks in elapsed time since last lease, we have | ||||
|         already made N+1 requests to API (1 for collective lease and N for | ||||
|         their individual delete operations). If K reqs/sec is the limit on | ||||
|         accessing APIs, then we sould not invoke any request to API before | ||||
|         N+1/K sec approximately. The above condition is formulated in the | ||||
|         following method. | ||||
|         Returns: | ||||
|           True/False | ||||
|         """ | ||||
|         if not FLAGS.taskapi_requests_per_sec: | ||||
|             return False | ||||
|         if not self._last_lease_time: | ||||
|             return False | ||||
|         curr_time = time.time() | ||||
|         if ((curr_time - self._last_lease_time) < | ||||
|                 ((1.0 * (self._num_last_leased_tasks - | ||||
|                          len(self._taskprocess_map)) / | ||||
|                     FLAGS.taskapi_requests_per_sec))): | ||||
|             return True | ||||
|         else: | ||||
|             return False | ||||
|  | ||||
|     def _num_tasks_to_lease(self): | ||||
|  | ||||
|         """Determines how many tasks can be leased. | ||||
|  | ||||
|         num_tasks is upper limit to running tasks in the system and hence | ||||
|         number of tasks which could be leased is difference of numtasks and | ||||
|         currently running tasks. | ||||
|  | ||||
|         Returns: | ||||
|             Number of tasks to lease. | ||||
|         """ | ||||
|         return FLAGS.num_tasks - len(self._taskprocess_map) | ||||
|  | ||||
|     def _update_last_lease_info(self, result): | ||||
|  | ||||
|         """Updates the information regarding last lease. | ||||
|  | ||||
|         Args: | ||||
|             result: Response object from TaskQueue API, containing list of | ||||
|             tasks. | ||||
|         """ | ||||
|         self._last_lease_time = time.time() | ||||
|         if result: | ||||
|             if result.get('items'): | ||||
|                 self._num_last_leased_tasks = len(result.get('items')) | ||||
|             else: | ||||
|                 self._num_last_leased_tasks = 0 | ||||
|         else: | ||||
|             self._num_last_leased_tasks = 0 | ||||
|  | ||||
|     def _update_poll_timeout_start(self): | ||||
|  | ||||
|         """Updates the start time for poll-timeout.""" | ||||
|         if not self._poll_timeout_start: | ||||
|             self._poll_timeout_start = time.time() | ||||
|  | ||||
|     def _continue_polling(self): | ||||
|  | ||||
|         """Checks whether lease can be invoked based on running tasks and | ||||
|         timeout. | ||||
|  | ||||
|         Lease can be invoked if | ||||
|         1. Running tasks in the sytem has gone below the specified | ||||
|            threshold (min_running_tasks). | ||||
|         2. Wait time has exceeded beyond time-out specified and at least one | ||||
|            tas has finished since last lease invocation. | ||||
|  | ||||
|         By doing this, we are essentially trying to batch the lease requests. | ||||
|         If this is not done and we start off leasing N tasks, its likely tasks | ||||
|         may finish slightly one after another, and we make N lease requests for | ||||
|         each task for next N tasks and so on. This can result in unnecessary | ||||
|         lease API call and hence to avoid that, we try and batch the lease | ||||
|         requests. Also we put certain limit on wait time for batching the | ||||
|         requests by incororating the time-out. | ||||
|  | ||||
|         Returns: | ||||
|             True/False | ||||
|         """ | ||||
|         if len(self._taskprocess_map) <= FLAGS.min_running_tasks: | ||||
|             return False | ||||
|         if self._poll_timeout_start: | ||||
|             elapsed_time = time.time() - self._poll_timeout_start | ||||
|             if elapsed_time > FLAGS.timeout_secs_for_next_lease_request: | ||||
|                 self._poll_timeout_start = None | ||||
|                 return False | ||||
|         return True | ||||
|  | ||||
|     def _get_tasks_from_queue(self): | ||||
|  | ||||
|         """Gets the available tasks from the taskqueue. | ||||
|  | ||||
|         Returns: | ||||
|             Lease response object. | ||||
|         """ | ||||
|         try: | ||||
|             tasks_to_fetch = self._num_tasks_to_lease() | ||||
|             lease_req = self.task_api.tasks().lease( | ||||
|                 project=FLAGS.project_name, | ||||
|                 taskqueue=FLAGS.taskqueue_name, | ||||
|                 leaseSecs=FLAGS.lease_secs, | ||||
|                 numTasks=tasks_to_fetch, | ||||
|                 body={}) | ||||
|             result = lease_req.execute() | ||||
|             return result | ||||
|         except HttpError, http_error: | ||||
|             logger.error('Error during lease request: %s' % str(http_error)) | ||||
|             return None | ||||
|  | ||||
|     def _create_subprocesses_for_tasks(self, result): | ||||
|  | ||||
|         """Spawns parallel sub processes to execute tasks for better | ||||
|         throughput. | ||||
|  | ||||
|         Args: | ||||
|             result: lease resonse dictionary object. | ||||
|         """ | ||||
|         if not result: | ||||
|             logger.info('Error: result is not defined') | ||||
|             return None | ||||
|         if result.get('items'): | ||||
|             for task in result.get('items'): | ||||
|                 task_id = task.get('id') | ||||
|                 # Given that a task may be leased multiple times, we may get a | ||||
|                 # task which we are currently executing on, so make sure we | ||||
|                 # dont spaw another subprocess for it. | ||||
|                 if task_id not in self._taskprocess_map: | ||||
|                     ct = ClientTask(task) | ||||
|                     # Check if tasks got initialized properly and then pu them | ||||
|                     # in running tasks map. | ||||
|                     if ct.init(): | ||||
|                         # Put the clientTask objects in a dictionary to keep | ||||
|                         # track of stats and objects are used later to delete | ||||
|                         # the tasks from taskqueue | ||||
|                         self._taskprocess_map[ct.get_task_id()] = ct | ||||
|  | ||||
|     def _poll_running_tasks(self): | ||||
|  | ||||
|         """Polls all the running tasks and delete them from taskqueue if | ||||
|         completed.""" | ||||
|         if self._taskprocess_map: | ||||
|             for task in self._taskprocess_map.values(): | ||||
|                 if task.is_completed(self.task_api): | ||||
|                     del self._taskprocess_map[task.get_task_id()] | ||||
|                     # updates scheduling information for later use. | ||||
|                     self._update_poll_timeout_start() | ||||
|  | ||||
|     def _sleep_before_next_lease(self): | ||||
|  | ||||
|         """Sleeps before invoking lease if required based on last lease info. | ||||
|  | ||||
|         It sleeps when no tasks were found on the taskqueue during last lease | ||||
|         request. To note, it discount the time taken in polling the tasks and | ||||
|         sleeps for (sleep_interval - time taken in poll). This avoids the | ||||
|         unnecessary wait if tasks could be leased. If no time was taken in | ||||
|         poll since there were not tasks in the system, it waits for full sleep | ||||
|         interval and thus optimizes the CPU cycles. | ||||
|         It does not sleep if the method is called for the first time (when no | ||||
|         lease request has ever been made). | ||||
|         """ | ||||
|         if not self._last_lease_time: | ||||
|             sleep_secs = 0 | ||||
|         elif self._num_last_leased_tasks <= 0: | ||||
|             time_elpased_since_last_lease = time.time() - self._last_lease_time | ||||
|             sleep_secs = (FLAGS.sleep_interval_secs - | ||||
|                           time_elpased_since_last_lease) | ||||
|             if sleep_secs > 0: | ||||
|                 logger.info('No tasks found and hence sleeping for sometime') | ||||
|                 time.sleep(FLAGS.sleep_interval_secs) | ||||
|  | ||||
|     def lease_tasks(self): | ||||
|  | ||||
|         """Requests lease for specified number of tasks. | ||||
|  | ||||
|         It invokes lease request for appropriate number of tasks, spawns | ||||
|         parallel processes to execute them and also maintains scheduling | ||||
|         information. | ||||
|  | ||||
|         LeaseTask also takes care of waiting(sleeping) before invoking lease if | ||||
|         there are no tasks which can be leased in the taskqueue. This results | ||||
|         in better resource utilization. Apart from this, it also controls the | ||||
|         number of requests being sent to taskqueue APIs. | ||||
|  | ||||
|         Returns: | ||||
|         True/False based on if tasks could be leased or not. | ||||
|         """ | ||||
|         self._sleep_before_next_lease() | ||||
|         if self._can_lease(): | ||||
|             result = self._get_tasks_from_queue() | ||||
|             self._update_last_lease_info(result) | ||||
|             self._create_subprocesses_for_tasks(result) | ||||
|             return True | ||||
|         return False | ||||
|  | ||||
|     def poll_tasks(self): | ||||
|  | ||||
|         """Polls the status of running tasks of the system. | ||||
|  | ||||
|         Polls the status of tasks and then decides if it should continue to | ||||
|         poll depending on number of tasks running in the system and timeouts. | ||||
|         Instead of polling in a tight loop, it sleeps for sometime before the | ||||
|         next poll to avoid any unnecessary CPU cycles. poll_tasks returns | ||||
|         only when system has capability to accomodate at least one new task. | ||||
|         """ | ||||
|  | ||||
|         self._poll_running_tasks() | ||||
|         while self._continue_polling(): | ||||
|             logger.info('Sleeping before next poll') | ||||
|             time.sleep(FLAGS.sleep_before_next_poll_secs) | ||||
|             self._poll_running_tasks() | ||||
|  | ||||
|  | ||||
| def main(argv): | ||||
|  | ||||
|     """Infinite loop to lease new tasks and poll them for completion.""" | ||||
|     # Settings for logger | ||||
|     set_logger() | ||||
|     # Instantiate puller | ||||
|     puller = TaskQueuePuller() | ||||
|     while True: | ||||
|         puller.lease_tasks() | ||||
|         puller.poll_tasks() | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     app.run() | ||||
							
								
								
									
										150
									
								
								samples/gtaskqueue_sample/gtaskqueue/task_cmds.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								samples/gtaskqueue_sample/gtaskqueue/task_cmds.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,150 @@ | ||||
| #!/usr/bin/env python | ||||
| # | ||||
| # Copyright (C) 2010 Google Inc. | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #      http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
|  | ||||
| """Commands to interact with the Task object of the TaskQueue API.""" | ||||
|  | ||||
|  | ||||
| __version__ = '0.0.1' | ||||
|  | ||||
|  | ||||
|  | ||||
| from gtaskqueue.taskqueue_cmd_base import GoogleTaskCommand | ||||
|  | ||||
| from google.apputils import app | ||||
| from google.apputils import appcommands | ||||
| import gflags as flags | ||||
|  | ||||
| FLAGS = flags.FLAGS | ||||
|  | ||||
|  | ||||
| class GetTaskCommand(GoogleTaskCommand): | ||||
|     """Get properties of an existing task.""" | ||||
|  | ||||
|     def __init__(self, name, flag_values): | ||||
|         super(GetTaskCommand, self).__init__(name, flag_values) | ||||
|  | ||||
|     def build_request(self, task_api, flag_values): | ||||
|         """Build a request to get properties of a Task. | ||||
|  | ||||
|         Args: | ||||
|             task_api: The handle to the task collection API. | ||||
|             flag_values: The parsed command flags. | ||||
|         Returns: | ||||
|             The properties of the task. | ||||
|         """ | ||||
|         return task_api.get(project=flag_values.project_name, | ||||
|                             taskqueue=flag_values.taskqueue_name, | ||||
|                             task=flag_values.task_name) | ||||
|  | ||||
|  | ||||
| class LeaseTaskCommand(GoogleTaskCommand): | ||||
|     """Lease a new task from the queue.""" | ||||
|  | ||||
|     def __init__(self, name, flag_values): | ||||
|         super(LeaseTaskCommand, self).__init__(name, | ||||
|                                                flag_values, | ||||
|                                                need_task_flag=False) | ||||
|         flags.DEFINE_integer('lease_secs', | ||||
|                              None, | ||||
|                              'The lease for the task in seconds') | ||||
|         flags.DEFINE_integer('num_tasks', | ||||
|                              1, | ||||
|                              'The number of tasks to lease') | ||||
|         flags.DEFINE_integer('payload_size_to_display', | ||||
|                              2 * 1024 * 1024, | ||||
|                              'Size of the payload for leased tasks to show') | ||||
|  | ||||
|     def build_request(self, task_api, flag_values): | ||||
|         """Build a request to lease a pending task from the TaskQueue. | ||||
|  | ||||
|         Args: | ||||
|             task_api: The handle to the task collection API. | ||||
|             flag_values: The parsed command flags. | ||||
|         Returns: | ||||
|             A new leased task. | ||||
|         """ | ||||
|         if not flag_values.lease_secs: | ||||
|             raise app.UsageError('lease_secs must be specified') | ||||
|  | ||||
|         return task_api.lease(project=flag_values.project_name, | ||||
|                               taskqueue=flag_values.taskqueue_name, | ||||
|                               leaseSecs=flag_values.lease_secs, | ||||
|                               numTasks=flag_values.num_tasks, | ||||
|                               body={}) | ||||
|  | ||||
|     def print_result(self, result): | ||||
|         """Override to optionally strip the payload since it can be long.""" | ||||
|         if result.get('items'): | ||||
|             items = [] | ||||
|             for task in result.get('items'): | ||||
|                 payloadlen = len(task['payloadBase64']) | ||||
|                 if payloadlen > FLAGS.payload_size_to_display: | ||||
|                     extra = payloadlen - FLAGS.payload_size_to_display | ||||
|                     task['payloadBase64'] = ('%s(%d more bytes)' % | ||||
|                         (task['payloadBase64'][:FLAGS.payload_size_to_display], | ||||
|                          extra)) | ||||
|                 items.append(task) | ||||
|             result['items'] = items | ||||
|         GoogleTaskCommand.print_result(self, result) | ||||
|  | ||||
|  | ||||
| class DeleteTaskCommand(GoogleTaskCommand): | ||||
|     """Delete an existing task.""" | ||||
|  | ||||
|     def __init__(self, name, flag_values): | ||||
|         super(DeleteTaskCommand, self).__init__(name, flag_values) | ||||
|  | ||||
|     def build_request(self, task_api, flag_values): | ||||
|         """Build a request to delete a Task. | ||||
|  | ||||
|         Args: | ||||
|             task_api: The handle to the taskqueue collection API. | ||||
|             flag_values: The parsed command flags. | ||||
|         Returns: | ||||
|             Whether the delete was successful. | ||||
|         """ | ||||
|         return task_api.delete(project=flag_values.project_name, | ||||
|                                taskqueue=flag_values.taskqueue_name, | ||||
|                                task=flag_values.task_name) | ||||
|  | ||||
|  | ||||
| class ListTasksCommand(GoogleTaskCommand): | ||||
|     """Lists all tasks in a queue (currently upto a max of 100).""" | ||||
|  | ||||
|     def __init__(self, name, flag_values): | ||||
|         super(ListTasksCommand, self).__init__(name, | ||||
|                                                flag_values, | ||||
|                                                need_task_flag=False) | ||||
|  | ||||
|     def build_request(self, task_api, flag_values): | ||||
|         """Build a request to lists tasks in a queue. | ||||
|  | ||||
|         Args: | ||||
|             task_api: The handle to the taskqueue collection API. | ||||
|             flag_values: The parsed command flags. | ||||
|         Returns: | ||||
|           A list of pending tasks in the queue. | ||||
|         """ | ||||
|         return task_api.list(project=flag_values.project_name, | ||||
|                              taskqueue=flag_values.taskqueue_name) | ||||
|  | ||||
|  | ||||
| def add_commands(): | ||||
|     appcommands.AddCmd('listtasks', ListTasksCommand) | ||||
|     appcommands.AddCmd('gettask', GetTaskCommand) | ||||
|     appcommands.AddCmd('deletetask', DeleteTaskCommand) | ||||
|     appcommands.AddCmd('leasetask', LeaseTaskCommand) | ||||
							
								
								
									
										189
									
								
								samples/gtaskqueue_sample/gtaskqueue/taskqueue_client.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								samples/gtaskqueue_sample/gtaskqueue/taskqueue_client.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,189 @@ | ||||
| #!/usr/bin/env python | ||||
| # | ||||
| # Copyright (C) 2010 Google Inc. | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #      http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| """Class to connect to TaskQueue API.""" | ||||
|  | ||||
|  | ||||
|  | ||||
| import os | ||||
| import sys | ||||
| import urlparse | ||||
| from apiclient.anyjson import simplejson as json | ||||
| from apiclient.discovery import build | ||||
| from apiclient.errors import HttpError | ||||
| import httplib2 | ||||
| from oauth2client.file import Storage | ||||
| from oauth2client.client import OAuth2WebServerFlow | ||||
| from oauth2client.tools import run | ||||
| from gtaskqueue.taskqueue_logger import logger | ||||
|  | ||||
| from google.apputils import app | ||||
| import gflags as flags | ||||
|  | ||||
| FLAGS = flags.FLAGS | ||||
| flags.DEFINE_string( | ||||
|         'service_version', | ||||
|         'v1beta1', | ||||
|         'Google taskqueue api version.') | ||||
| flags.DEFINE_string( | ||||
|         'api_host', | ||||
|         'https://www.googleapis.com/', | ||||
|         'API host name') | ||||
| flags.DEFINE_bool( | ||||
|         'use_developer_key', | ||||
|         False, | ||||
|         'User wants to use the developer key while accessing taskqueue apis') | ||||
| flags.DEFINE_string( | ||||
|         'developer_key_file', | ||||
|         '~/.taskqueue.apikey', | ||||
|         'Developer key provisioned from api console') | ||||
| flags.DEFINE_bool( | ||||
|         'dump_request', | ||||
|         False, | ||||
|         'Prints the outgoing HTTP request along with headers and body.') | ||||
| flags.DEFINE_string( | ||||
|         'credentials_file', | ||||
|         'taskqueue.dat', | ||||
|         'File where you want to store the auth credentails for later user') | ||||
|  | ||||
| # Set up a Flow object to be used if we need to authenticate. This | ||||
| # sample uses OAuth 2.0, and we set up the OAuth2WebServerFlow with | ||||
| # the information it needs to authenticate. Note that it is called | ||||
| # the Web Server Flow, but it can also handle the flow for native | ||||
| # applications <http://code.google.com/apis/accounts/docs/OAuth2.html#IA> | ||||
| # The client_id client_secret are copied from the Identity tab on | ||||
| # the Google APIs Console <http://code.google.com/apis/console> | ||||
| FLOW = OAuth2WebServerFlow( | ||||
|     client_id='157776985798.apps.googleusercontent.com', | ||||
|     client_secret='tlpVCmaS6yLjxnnPu0ARIhNw', | ||||
|     scope='https://www.googleapis.com/auth/taskqueue', | ||||
|     user_agent='taskqueue-cmdline-sample/1.0') | ||||
|  | ||||
|  | ||||
| class TaskQueueClient: | ||||
|     """Class to setup connection with taskqueue API.""" | ||||
|  | ||||
|     def __init__(self): | ||||
|         if not FLAGS.project_name: | ||||
|             raise app.UsageError('You must specify a project name' | ||||
|                                  ' using the "--project_name" flag.') | ||||
|         discovery_uri = ( | ||||
|                 FLAGS.api_host + 'discovery/v0.3/describe/{api}/{apiVersion}') | ||||
|         logger.info(discovery_uri) | ||||
|         try: | ||||
|             # If the Credentials don't exist or are invalid run through the | ||||
|             # native clien flow. The Storage object will ensure that if | ||||
|             # successful the good Credentials will get written back to a file. | ||||
|             # Setting FLAGS.auth_local_webserver to false since we can run our | ||||
|             # tool on Virtual Machines and we do not want to run the webserver | ||||
|             # on VMs. | ||||
|             FLAGS.auth_local_webserver = False | ||||
|             storage = Storage(FLAGS.credentials_file) | ||||
|             credentials = storage.get() | ||||
|             if credentials is None or credentials.invalid == True: | ||||
|                 credentials = run(FLOW, storage) | ||||
|             http = credentials.authorize(self._dump_request_wrapper( | ||||
|                     httplib2.Http())) | ||||
|             self.task_api = build('taskqueue', | ||||
|                                   FLAGS.service_version, | ||||
|                                   http=http, | ||||
|                                   discoveryServiceUrl=discovery_uri) | ||||
|         except HttpError, http_error: | ||||
|             logger.error('Error gettin task_api: %s' % http_error) | ||||
|  | ||||
|     def get_taskapi(self): | ||||
|         """Returns handler for tasks  API from taskqueue API collection.""" | ||||
|         return self.task_api | ||||
|  | ||||
|  | ||||
|     def _dump_request_wrapper(self, http): | ||||
|         """Dumps the outgoing HTTP request if requested. | ||||
|  | ||||
|         Args: | ||||
|             http: An instance of httplib2.Http or something that acts like it. | ||||
|  | ||||
|         Returns: | ||||
|             httplib2.Http like object. | ||||
|         """ | ||||
|         request_orig = http.request | ||||
|  | ||||
|         def new_request(uri, method='GET', body=None, headers=None, | ||||
|                         redirections=httplib2.DEFAULT_MAX_REDIRECTS, | ||||
|                         connection_type=None): | ||||
|             """Overrides the http.request method to add some utilities.""" | ||||
|             if (FLAGS.api_host + "discovery/" not in uri and | ||||
|                 FLAGS.use_developer_key): | ||||
|                 developer_key_path = os.path.expanduser( | ||||
|                     FLAGS.developer_key_file) | ||||
|                 if not os.path.isfile(developer_key_path): | ||||
|                     print 'Please generate developer key from the Google API' \ | ||||
|                     'Console and store it in %s' % (FLAGS.developer_key_file) | ||||
|                     sys.exit() | ||||
|                 developer_key_file = open(developer_key_path, 'r') | ||||
|                 try: | ||||
|                     developer_key = developer_key_file.read().strip() | ||||
|                 except IOError, io_error: | ||||
|                     print 'Error loading developer key from file %s' % ( | ||||
|                             FLAGS.developer_key_file) | ||||
|                     print 'Error details: %s' % str(io_error) | ||||
|                     sys.exit() | ||||
|                 finally: | ||||
|                     developer_key_file.close() | ||||
|                 s = urlparse.urlparse(uri) | ||||
|                 query = 'key=' + developer_key | ||||
|                 if s.query: | ||||
|                     query = s.query + '&key=' + developer_key | ||||
|                 d = urlparse.ParseResult(s.scheme, | ||||
|                                          s.netloc, | ||||
|                                          s.path, | ||||
|                                          s.params, | ||||
|                                          query, | ||||
|                                          s.fragment) | ||||
|                 uri = urlparse.urlunparse(d) | ||||
|             if FLAGS.dump_request: | ||||
|                 print '--request-start--' | ||||
|                 print '%s %s' % (method, uri) | ||||
|                 if headers: | ||||
|                     for (h, v) in headers.iteritems(): | ||||
|                         print '%s: %s' % (h, v) | ||||
|                 print '' | ||||
|                 if body: | ||||
|                     print json.dumps(json.loads(body), | ||||
|                                      sort_keys=True, | ||||
|                                      indent=2) | ||||
|                 print '--request-end--' | ||||
|             return request_orig(uri, | ||||
|                                 method, | ||||
|                                 body, | ||||
|                                 headers, | ||||
|                                 redirections, | ||||
|                                 connection_type) | ||||
|         http.request = new_request | ||||
|         return http | ||||
|  | ||||
|     def print_result(self, result): | ||||
|         """Pretty-print the result of the command. | ||||
|  | ||||
|         The default behavior is to dump a formatted JSON encoding | ||||
|         of the result. | ||||
|  | ||||
|         Args: | ||||
|             result: The JSON-serializable result to print. | ||||
|         """ | ||||
|         # We could have used the pprint module, but it produces | ||||
|         # noisy output due to all of our keys and values being | ||||
|         # unicode strings rather than simply ascii. | ||||
|         print json.dumps(result, sort_keys=True, indent=2) | ||||
							
								
								
									
										275
									
								
								samples/gtaskqueue_sample/gtaskqueue/taskqueue_cmd_base.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										275
									
								
								samples/gtaskqueue_sample/gtaskqueue/taskqueue_cmd_base.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,275 @@ | ||||
| #!/usr/bin/env python | ||||
| # | ||||
| # Copyright (C) 2010 Google Inc. | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #      http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
|  | ||||
| """Commands for interacting with Google TaskQueue.""" | ||||
|  | ||||
| __version__ = '0.0.1' | ||||
|  | ||||
|  | ||||
| import os | ||||
| import sys | ||||
| import urlparse | ||||
|  | ||||
|  | ||||
| from apiclient.discovery import build | ||||
| from apiclient.errors import HttpError | ||||
| from apiclient.anyjson import simplejson as json | ||||
| import httplib2 | ||||
| from oauth2client.file import Storage | ||||
| from oauth2client.client import OAuth2WebServerFlow | ||||
| from oauth2client.tools import run | ||||
|  | ||||
| from google.apputils import app | ||||
| from google.apputils import appcommands | ||||
| import gflags as flags | ||||
|  | ||||
|  | ||||
| FLAGS = flags.FLAGS | ||||
|  | ||||
| flags.DEFINE_string( | ||||
|         'service_version', | ||||
|         'v1beta1', | ||||
|         'Google taskqueue api version.') | ||||
| flags.DEFINE_string( | ||||
|         'api_host', | ||||
|         'https://www.googleapis.com/', | ||||
|         'API host name') | ||||
| flags.DEFINE_string( | ||||
|         'project_name', | ||||
|         'default', | ||||
|         'The name of the Taskqueue API project.') | ||||
| flags.DEFINE_bool( | ||||
|         'use_developer_key', | ||||
|         False, | ||||
|         'User wants to use the developer key while accessing taskqueue apis') | ||||
| flags.DEFINE_string( | ||||
|         'developer_key_file', | ||||
|         '~/.taskqueue.apikey', | ||||
|         'Developer key provisioned from api console') | ||||
| flags.DEFINE_bool( | ||||
|         'dump_request', | ||||
|         False, | ||||
|         'Prints the outgoing HTTP request along with headers and body.') | ||||
| flags.DEFINE_string( | ||||
|         'credentials_file', | ||||
|         'taskqueue.dat', | ||||
|         'File where you want to store the auth credentails for later user') | ||||
|  | ||||
| # Set up a Flow object to be used if we need to authenticate. This | ||||
| # sample uses OAuth 2.0, and we set up the OAuth2WebServerFlow with | ||||
| # the information it needs to authenticate. Note that it is called | ||||
| # the Web Server Flow, but it can also handle the flow for native | ||||
| # applications <http://code.google.com/apis/accounts/docs/OAuth2.html#IA> | ||||
| # The client_id client_secret are copied from the Identity tab on | ||||
| # the Google APIs Console <http://code.google.com/apis/console> | ||||
| FLOW = OAuth2WebServerFlow( | ||||
|     client_id='157776985798.apps.googleusercontent.com', | ||||
|     client_secret='tlpVCmaS6yLjxnnPu0ARIhNw', | ||||
|     scope='https://www.googleapis.com/auth/taskqueue', | ||||
|     user_agent='taskqueue-cmdline-sample/1.0') | ||||
|  | ||||
| class GoogleTaskQueueCommandBase(appcommands.Cmd): | ||||
|     """Base class for all the Google TaskQueue client commands.""" | ||||
|  | ||||
|     DEFAULT_PROJECT_PATH = 'projects/default' | ||||
|  | ||||
|     def __init__(self, name, flag_values): | ||||
|         super(GoogleTaskQueueCommandBase, self).__init__(name, flag_values) | ||||
|  | ||||
|     def _dump_request_wrapper(self, http): | ||||
|         """Dumps the outgoing HTTP request if requested. | ||||
|  | ||||
|         Args: | ||||
|             http: An instance of httplib2.Http or something that acts like it. | ||||
|  | ||||
|         Returns: | ||||
|             httplib2.Http like object. | ||||
|         """ | ||||
|         request_orig = http.request | ||||
|  | ||||
|         def new_request(uri, method='GET', body=None, headers=None, | ||||
|                         redirections=httplib2.DEFAULT_MAX_REDIRECTS, | ||||
|                         connection_type=None): | ||||
|             """Overrides the http.request method to add some utilities.""" | ||||
|             if (FLAGS.api_host + "discovery/" not in uri and | ||||
|                 FLAGS.use_developer_key): | ||||
|                 developer_key_path = os.path.expanduser( | ||||
|                     FLAGS.developer_key_file) | ||||
|                 if not os.path.isfile(developer_key_path): | ||||
|                     print 'Please generate developer key from the Google APIs' \ | ||||
|                     'Console and store it in %s' % (FLAGS.developer_key_file) | ||||
|                     sys.exit() | ||||
|                 developer_key_file = open(developer_key_path, 'r') | ||||
|                 try: | ||||
|                     developer_key = developer_key_file.read().strip() | ||||
|                 except IOError, io_error: | ||||
|                     print 'Error loading developer key from file %s' % ( | ||||
|                             FLAGS.developer_key_file) | ||||
|                     print 'Error details: %s' % str(io_error) | ||||
|                     sys.exit() | ||||
|                 finally: | ||||
|                     developer_key_file.close() | ||||
|                 s = urlparse.urlparse(uri) | ||||
|                 query = 'key=' + developer_key | ||||
|                 if s.query: | ||||
|                     query = s.query + '&key=' + developer_key | ||||
|                 d = urlparse.ParseResult(s.scheme, | ||||
|                                          s.netloc, | ||||
|                                          s.path, | ||||
|                                          s.params, | ||||
|                                          query, | ||||
|                                          s.fragment) | ||||
|                 uri = urlparse.urlunparse(d) | ||||
|  | ||||
|             if FLAGS.dump_request: | ||||
|                 print '--request-start--' | ||||
|                 print '%s %s' % (method, uri) | ||||
|                 if headers: | ||||
|                     for (h, v) in headers.iteritems(): | ||||
|                         print '%s: %s' % (h, v) | ||||
|                 print '' | ||||
|                 if body: | ||||
|                     print json.dumps(json.loads(body), sort_keys=True, indent=2) | ||||
|                 print '--request-end--' | ||||
|             return request_orig(uri, | ||||
|                                 method, | ||||
|                                 body, | ||||
|                                 headers, | ||||
|                                 redirections, | ||||
|                                 connection_type) | ||||
|         http.request = new_request | ||||
|         return http | ||||
|  | ||||
|     def Run(self, argv): | ||||
|         """Run the command, printing the result. | ||||
|  | ||||
|         Args: | ||||
|             argv: The non-flag arguments to the command. | ||||
|         """ | ||||
|         if not FLAGS.project_name: | ||||
|             raise app.UsageError('You must specify a project name' | ||||
|                                  ' using the "--project_name" flag.') | ||||
|         discovery_uri = ( | ||||
|                 FLAGS.api_host + 'discovery/v0.3/describe/{api}/{apiVersion}') | ||||
|         try: | ||||
|             # If the Credentials don't exist or are invalid run through the | ||||
|             # native client flow. The Storage object will ensure that if | ||||
|             # successful the good Credentials will get written back to a file. | ||||
|             # Setting FLAGS.auth_local_webserver to false since we can run our | ||||
|             # tool on Virtual Machines and we do not want to run the webserver | ||||
|             # on VMs. | ||||
|             FLAGS.auth_local_webserver = False | ||||
|             storage = Storage(FLAGS.credentials_file) | ||||
|             credentials = storage.get() | ||||
|             if credentials is None or credentials.invalid == True: | ||||
|                 credentials = run(FLOW, storage) | ||||
|             http = credentials.authorize(self._dump_request_wrapper( | ||||
|                     httplib2.Http())) | ||||
|             api = build('taskqueue', | ||||
|                        FLAGS.service_version, | ||||
|                        http=http, | ||||
|                        discoveryServiceUrl=discovery_uri) | ||||
|             result = self.run_with_api_and_flags_and_args(api, FLAGS, argv) | ||||
|             self.print_result(result) | ||||
|         except HttpError, http_error: | ||||
|             print 'Error Processing request: %s' % str(http_error) | ||||
|  | ||||
|     def run_with_api_and_flags_and_args(self, api, flag_values, unused_argv): | ||||
|         """Run the command given the API, flags, and args. | ||||
|  | ||||
|         The default implementation of this method discards the args and | ||||
|         calls into run_with_api_and_flags. | ||||
|  | ||||
|         Args: | ||||
|             api: The handle to the Google TaskQueue API. | ||||
|             flag_values: The parsed command flags. | ||||
|             unused_argv: The non-flag arguments to the command. | ||||
|         Returns: | ||||
|             The result of running the command | ||||
|         """ | ||||
|         return self.run_with_api_and_flags(api, flag_values) | ||||
|  | ||||
|     def print_result(self, result): | ||||
|         """Pretty-print the result of the command. | ||||
|  | ||||
|         The default behavior is to dump a formatted JSON encoding | ||||
|         of the result. | ||||
|  | ||||
|         Args: | ||||
|             result: The JSON-serializable result to print. | ||||
|         """ | ||||
|         # We could have used the pprint module, but it produces | ||||
|         # noisy output due to all of our keys and values being | ||||
|         # unicode strings rather than simply ascii. | ||||
|         print json.dumps(result, sort_keys=True, indent=2) | ||||
|  | ||||
|  | ||||
|  | ||||
| class GoogleTaskQueueCommand(GoogleTaskQueueCommandBase): | ||||
|     """Base command for working with the taskqueues collection.""" | ||||
|  | ||||
|     def __init__(self, name, flag_values): | ||||
|         super(GoogleTaskQueueCommand, self).__init__(name, flag_values) | ||||
|         flags.DEFINE_string('taskqueue_name', | ||||
|                                                 'myqueue', | ||||
|                                                 'TaskQueue name', | ||||
|                                                 flag_values=flag_values) | ||||
|  | ||||
|     def run_with_api_and_flags(self, api, flag_values): | ||||
|         """Run the command, returning the result. | ||||
|  | ||||
|         Args: | ||||
|             api: The handle to the Google TaskQueue API. | ||||
|             flag_values: The parsed command flags. | ||||
|         Returns: | ||||
|             The result of running the command. | ||||
|         """ | ||||
|         taskqueue_request = self.build_request(api.taskqueues(), flag_values) | ||||
|         return taskqueue_request.execute() | ||||
|  | ||||
|  | ||||
| class GoogleTaskCommand(GoogleTaskQueueCommandBase): | ||||
|     """Base command for working with the tasks collection.""" | ||||
|  | ||||
|     def __init__(self, name, flag_values, need_task_flag=True): | ||||
|         super(GoogleTaskCommand, self).__init__(name, flag_values) | ||||
|         # Common flags that are shared by all the Task commands. | ||||
|         flags.DEFINE_string('taskqueue_name', | ||||
|                             'myqueue', | ||||
|                             'TaskQueue name', | ||||
|                             flag_values=flag_values) | ||||
|         # Not all task commands need the task_name flag. | ||||
|         if need_task_flag: | ||||
|             flags.DEFINE_string('task_name', | ||||
|                                 None, | ||||
|                                 'Task name', | ||||
|                                 flag_values=flag_values) | ||||
|  | ||||
|     def run_with_api_and_flags(self, api, flag_values): | ||||
|         """Run the command, returning the result. | ||||
|  | ||||
|         Args: | ||||
|             api: The handle to the Google TaskQueue API. | ||||
|             flag_values: The parsed command flags. | ||||
|             flags.DEFINE_string('payload', | ||||
|             None, | ||||
|             'Payload of the task') | ||||
|         Returns: | ||||
|             The result of running the command. | ||||
|         """ | ||||
|         task_request = self.build_request(api.tasks(), flag_values) | ||||
|         return task_request.execute() | ||||
							
								
								
									
										56
									
								
								samples/gtaskqueue_sample/gtaskqueue/taskqueue_cmds.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								samples/gtaskqueue_sample/gtaskqueue/taskqueue_cmds.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| #!/usr/bin/env python | ||||
| # | ||||
| # Copyright (C) 2010 Google Inc. | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #      http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| """Commands to interact with the TaskQueue object of the TaskQueue API.""" | ||||
|  | ||||
|  | ||||
| __version__ = '0.0.1' | ||||
|  | ||||
|  | ||||
|  | ||||
| from gtaskqueue.taskqueue_cmd_base import GoogleTaskQueueCommand | ||||
|  | ||||
| from google.apputils import appcommands | ||||
| import gflags as flags | ||||
|  | ||||
| FLAGS = flags.FLAGS | ||||
|  | ||||
|  | ||||
| class GetTaskQueueCommand(GoogleTaskQueueCommand): | ||||
|     """Get properties of an existing task queue.""" | ||||
|  | ||||
|     def __init__(self, name, flag_values): | ||||
|         super(GetTaskQueueCommand, self).__init__(name, flag_values) | ||||
|         flags.DEFINE_boolean('get_stats', | ||||
|                              False, | ||||
|                              'Whether to get Stats') | ||||
|  | ||||
|     def build_request(self, taskqueue_api, flag_values): | ||||
|         """Build a request to get properties of a TaskQueue. | ||||
|  | ||||
|         Args: | ||||
|             taskqueue_api: The handle to the taskqueue collection API. | ||||
|             flag_values: The parsed command flags. | ||||
|         Returns: | ||||
|             The properties of the taskqueue. | ||||
|         """ | ||||
|         return taskqueue_api.get(project=flag_values.project_name, | ||||
|                                  taskqueue=flag_values.taskqueue_name, | ||||
|                                  getStats=flag_values.get_stats) | ||||
|  | ||||
|  | ||||
| def add_commands(): | ||||
|     appcommands.AddCmd('getqueue', GetTaskQueueCommand) | ||||
							
								
								
									
										54
									
								
								samples/gtaskqueue_sample/gtaskqueue/taskqueue_logger.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								samples/gtaskqueue_sample/gtaskqueue/taskqueue_logger.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| #!/usr/bin/env python | ||||
| # | ||||
| # Copyright (C) 2010 Google Inc. | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #      http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| """Log settings for taskqueue_puller module.""" | ||||
|  | ||||
|  | ||||
|  | ||||
| import logging | ||||
| import logging.config | ||||
| from google.apputils import app | ||||
| import gflags as flags | ||||
|  | ||||
| FLAGS = flags.FLAGS | ||||
| flags.DEFINE_string( | ||||
|         'log_output_file', | ||||
|         '/tmp/taskqueue-puller.log', | ||||
|         'Logfile name for taskqueue_puller.') | ||||
|  | ||||
|  | ||||
| logger = logging.getLogger('TaskQueueClient') | ||||
|  | ||||
|  | ||||
| def set_logger(): | ||||
|     """Settings for taskqueue_puller logger.""" | ||||
|     logger.setLevel(logging.INFO) | ||||
|  | ||||
|     # create formatter | ||||
|     formatter = logging.Formatter( | ||||
|             '%(asctime)s - %(name)s - %(levelname)s - %(message)s') | ||||
|  | ||||
|     # Set size of the log file and the backup count  for rotated log files. | ||||
|     handler = logging.handlers.RotatingFileHandler(FLAGS.log_output_file, | ||||
|                                                    maxBytes = 1024 * 1024, | ||||
|                                                    backupCount = 5) | ||||
|     # add formatter to handler | ||||
|     handler.setFormatter(formatter) | ||||
|     # add formatter to handler | ||||
|     logger.addHandler(handler) | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     app.run() | ||||
							
								
								
									
										53
									
								
								samples/gtaskqueue_sample/setup.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								samples/gtaskqueue_sample/setup.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| #!/usr/bin/env python | ||||
| # | ||||
| # Copyright (C) 2010 Google Inc. | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #      http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| """Setup script for the Google TaskQueue API command-line tool.""" | ||||
|  | ||||
| __version__ = '1.0.2' | ||||
|  | ||||
|  | ||||
| import sys | ||||
| try: | ||||
|     from setuptools import setup | ||||
|     print 'Loaded setuptools' | ||||
| except ImportError: | ||||
|     from distutils.core import setup | ||||
|     print 'Loaded distutils.core' | ||||
|  | ||||
|  | ||||
| PACKAGE_NAME = 'google-taskqueue-client' | ||||
| INSTALL_REQUIRES = ['google-apputils==0.1', | ||||
|                     'google-api-python-client', | ||||
|                     'httplib2', | ||||
|                     'oauth2', | ||||
|                     'python-gflags'] | ||||
| setup(name=PACKAGE_NAME, | ||||
|       version=__version__, | ||||
|       description='Google TaskQueue API command-line tool and utils', | ||||
|       author='Google Inc.', | ||||
|       author_email='google-appengine@googlegroups.com', | ||||
|       url='http://code.google.com/appengine/docs/python/taskqueue/pull/overview.html', | ||||
|       install_requires=INSTALL_REQUIRES, | ||||
|       packages=['gtaskqueue'], | ||||
|       scripts=['gtaskqueue/gtaskqueue', 'gtaskqueue/gtaskqueue_puller', | ||||
|                'gtaskqueue/gen_appengine_access_token'], | ||||
|       license='Apache 2.0', | ||||
|       keywords='google taskqueue api client', | ||||
|       classifiers=['Development Status :: 3 - Alpha', | ||||
|                    'Intended Audience :: Developers', | ||||
|                    'License :: OSI Approved :: Apache Software License', | ||||
|                    'Operating System :: POSIX', | ||||
|                    'Topic :: Internet :: WWW/HTTP']) | ||||
		Reference in New Issue
	
	Block a user
	 Joe Gregorio
					Joe Gregorio