github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/gubernator/github/admin.py (about) 1 # Copyright 2016 The Kubernetes Authors. 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 15 import collections 16 import cPickle as pickle 17 import logging 18 import os 19 20 from google.appengine.api import urlfetch 21 from google.appengine.ext import deferred 22 from google.appengine.ext import ndb 23 24 import webapp2 25 import models 26 import handlers 27 28 # ndb model.query likes to use == True 29 # pylint: disable=singleton-comparison 30 31 class RecomputeOpenPRs(object): 32 keys_only = True 33 34 @staticmethod 35 def query(): 36 return models.GHIssueDigest.query( 37 models.GHIssueDigest.is_open == True, 38 models.GHIssueDigest.is_pr == True 39 ) 40 41 @staticmethod 42 def handle_entity(entity): 43 repo, number = entity.id().split(' ') 44 handlers.update_issue_digest(repo, number, always_put=True) 45 return {'puts': 1} 46 47 @ndb.toplevel 48 def migrate(migration, cursor=None, last_parent=None, stop=False): 49 entities, next_cursor, more = migration.query().fetch_page( 50 10, start_cursor=cursor, keys_only=migration.keys_only) 51 52 counters = collections.Counter() 53 54 for entity in entities: 55 changes = migration.handle_entity(entity) 56 counters.update(changes) 57 58 summary = ', '.join('%s: %d' % x for x in sorted(counters.items())) 59 if entities: 60 logging.info('fetched %d. %s. (%r-%r)', 61 len(entities), summary, entities[0], entities[-1]) 62 63 if stop: 64 return 65 66 if more and next_cursor: 67 deferred.defer(migrate, migration, cursor=next_cursor, last_parent=last_parent) 68 69 70 class Digest(webapp2.RequestHandler): 71 def get(self): 72 results = models.GHIssueDigest.query( 73 models.GHIssueDigest.is_open == True) 74 self.response.headers['content-type'] = 'text/plain' 75 self.response.write(pickle.dumps(list(results), pickle.HIGHEST_PROTOCOL)) 76 77 78 class AdminDash(webapp2.RequestHandler): 79 def get(self): 80 self.response.write(''' 81 <form action="/admin/reprocess" method="post"> 82 <button>Reprocess Open Issues/PRs</button><input type="checkbox" name="background">Background 83 </form> 84 <form action="/admin/digest_sync" method="post"> 85 <button>Download GHIssueDigest from production</button> 86 </form> 87 ''') 88 89 def check_csrf(self): 90 # https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet 91 # #Checking_The_Referer_Header 92 origin = self.request.headers.get('origin') + '/' 93 expected = self.request.host_url + '/' 94 print expected 95 if not (origin and origin == expected): 96 logging.error('csrf check failed for %s, origin: %r', self.request.url, origin) 97 self.abort(403) 98 99 100 class Reprocessor(AdminDash): 101 def post(self): 102 self.check_csrf() 103 migration = RecomputeOpenPRs() 104 if self.request.get('background'): 105 deferred.defer(migrate, migration) 106 self.response.write('running.') 107 else: 108 migrate(migration, stop=True) 109 110 111 class DigestSync(AdminDash): 112 def post(self): 113 if not os.environ['SERVER_SOFTWARE'].startswith('Development/'): 114 self.abort(400) 115 # For local development, download GHIssueDigests from the production 116 # server. 117 result = urlfetch.fetch( 118 'https://github-dot-k8s-gubernator.appspot.com/digest', deadline=60) 119 if result.status_code != 200: 120 self.abort(result.status_code) 121 body = result.content 122 self.response.headers['content-type'] = 'text/plain' 123 self.response.write('%s\n' % len(body)) 124 self.response.write(repr(body[:8])) 125 results = pickle.loads(body) 126 for res in results: 127 res.key = ndb.Key(models.GHIssueDigest, res.key.id()) 128 self.response.write('%s\n' % res.key) 129 res.put() 130 131 132 app = webapp2.WSGIApplication([ 133 (r'/digest', Digest), 134 (r'/admin/?', AdminDash), 135 (r'/admin/reprocess', Reprocessor), 136 (r'/admin/digest_sync', DigestSync), 137 ], debug=True)