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)