1.9.30 sync.
[gae.git] / python / google / appengine / tools / devappserver2 / admin / cron_handler.py
blobf5cce0872d2da602e0781ef896ddf0c3852eaf88
1 #!/usr/bin/env python
3 # Copyright 2007 Google Inc.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 """A handler that allows the user to see and test cron tasks."""
19 import datetime
20 import os.path
21 import traceback
23 from google.appengine.cron import groctimespecification
24 from google.appengine.api import croninfo
25 from google.appengine.api import yaml_errors
26 from google.appengine.tools.devappserver2.admin import admin_request_handler
28 try:
29 import pytz
30 except ImportError:
31 pytz = None
33 REMOTE_IP = '0.1.0.1'
36 class CronHandler(admin_request_handler.AdminRequestHandler):
38 def get(self):
39 values = {}
40 values['has_pytz'] = bool(pytz)
41 try:
42 values['cronjobs'] = self._get_cron_jobs()
43 except (StandardError, yaml_errors.Error):
44 values['cron_error'] = traceback.format_exc()
45 self.response.write(self.render('cron.html', values))
47 def _get_cron_jobs(self):
48 cron_info = self._parse_cron_yaml()
49 if not cron_info or not cron_info.cron:
50 return []
51 jobs = []
52 for entry in cron_info.cron:
53 job = entry.ToDict()
54 if not entry.timezone or pytz:
55 now = datetime.datetime.utcnow()
56 schedule = groctimespecification.GrocTimeSpecification(
57 entry.schedule, entry.timezone)
58 matches = schedule.GetMatches(now, 3)
59 job['times'] = []
60 for match in matches:
61 job['times'].append(
62 {'runtime': match.strftime('%Y-%m-%d %H:%M:%SZ'),
63 'difference': str(match - now)})
64 jobs.append(job)
65 return jobs
67 def _parse_cron_yaml(self):
68 """Loads the cron.yaml file and parses it.
70 Returns:
71 A croninfo.CronInfoExternal containing cron jobs.
73 Raises:
74 yaml_errors.Error, StandardError: The cron.yaml was invalid.
75 """
76 for cron_yaml in ('cron.yaml', 'cron.yml'):
77 try:
78 with open(os.path.join(self.configuration.modules[0].application_root,
79 cron_yaml)) as f:
80 cron_info = croninfo.LoadSingleCron(f)
81 return cron_info
82 except IOError:
83 continue
84 return None
86 def post(self):
87 self.response.status = self.dispatcher.add_request(
88 method='GET',
89 relative_url=self.request.get('url'),
90 headers=[('X-AppEngine-Cron', 'true')],
91 body='',
92 source_ip=REMOTE_IP).status