github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/gubernator/view_base.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 functools
    16  import logging
    17  import os
    18  import re
    19  
    20  import cloudstorage as gcs
    21  import jinja2
    22  import webapp2
    23  
    24  from google.appengine.api import urlfetch
    25  from google.appengine.api import memcache
    26  from webapp2_extras import sessions
    27  
    28  import filters as jinja_filters
    29  
    30  JINJA_ENVIRONMENT = jinja2.Environment(
    31      loader=jinja2.FileSystemLoader(os.path.dirname(__file__) + '/templates'),
    32      extensions=['jinja2.ext.autoescape', 'jinja2.ext.loopcontrols'],
    33      trim_blocks=True,
    34      autoescape=True)
    35  JINJA_ENVIRONMENT.line_statement_prefix = '%'
    36  jinja_filters.register(JINJA_ENVIRONMENT.filters)
    37  
    38  
    39  class BaseHandler(webapp2.RequestHandler):
    40      """Base class for Handlers that render Jinja templates."""
    41      def __init__(self, *args, **kwargs):
    42          super(BaseHandler, self).__init__(*args, **kwargs)
    43          # The default deadline of 5 seconds is too aggressive of a target for GCS
    44          # directory listing operations.
    45          urlfetch.set_default_fetch_deadline(60)
    46  
    47      # This example code is from:
    48      # http://webapp2.readthedocs.io/en/latest/api/webapp2_extras/sessions.html
    49      def dispatch(self):
    50          # pylint: disable=attribute-defined-outside-init
    51          # Get a session store for this request.
    52          self.session_store = sessions.get_store(request=self.request)
    53  
    54          try:
    55              # Dispatch the request.
    56              webapp2.RequestHandler.dispatch(self)
    57          finally:
    58              # Save all sessions.
    59              self.session_store.save_sessions(self.response)
    60  
    61      @webapp2.cached_property
    62      def session(self):
    63          # Returns a session using the default cookie key.
    64          return self.session_store.get_session()
    65  
    66      def render(self, template, context):
    67          """Render a context dictionary using a given template."""
    68          template = JINJA_ENVIRONMENT.get_template(template)
    69          self.response.write(template.render(context))
    70  
    71  
    72  class IndexHandler(BaseHandler):
    73      """Render the index."""
    74      def get(self):
    75          self.render("index.html", {'jobs': self.app.config['jobs']})
    76  
    77  
    78  def memcache_memoize(prefix, expires=60 * 60, neg_expires=60):
    79      """Decorate a function to memoize its results using memcache.
    80  
    81      The function must take a single string as input, and return a pickleable
    82      type.
    83  
    84      Args:
    85          prefix: A prefix for memcache keys to use for memoization.
    86          expires: How long to memoized values, in seconds.
    87          neg_expires: How long to memoize falsey values, in seconds
    88      Returns:
    89          A decorator closure to wrap the function.
    90      """
    91      # setting the namespace based on the current version prevents different
    92      # versions from sharing cache values -- meaning there's no need to worry
    93      # about incompatible old key/value pairs
    94      namespace = os.environ['CURRENT_VERSION_ID']
    95      def wrapper(func):
    96          @functools.wraps(func)
    97          def wrapped(*args):
    98              key = '%s%s' % (prefix, args)
    99              data = memcache.get(key, namespace=namespace)
   100              if data is not None:
   101                  return data
   102              else:
   103                  data = func(*args)
   104                  try:
   105                      if data:
   106                          memcache.add(key, data, expires, namespace=namespace)
   107                      else:
   108                          memcache.add(key, data, neg_expires, namespace=namespace)
   109                  except ValueError:
   110                      logging.exception('unable to write to memcache')
   111                  return data
   112          return wrapped
   113      return wrapper
   114  
   115  
   116  @memcache_memoize('gs-ls://', expires=60)
   117  def gcs_ls(path):
   118      """Enumerate files in a GCS directory. Returns a list of FileStats."""
   119      if path[-1] != '/':
   120          path += '/'
   121      return list(gcs.listbucket(path, delimiter='/'))
   122  
   123  
   124  def pad_numbers(s):
   125      """Modify a string to make its numbers suitable for natural sorting."""
   126      return re.sub(r'\d+', lambda m: m.group(0).rjust(16, '0'), s)