Search code examples
python-2.7google-app-enginecron

Error 302 running cron and login:admin in app.yaml in google app engine


I added login: Admin to app.yaml like documentation is described, but I still have a 302 erro when runing a task with cron in google app engine.

I have this app.yaml

runtime: python27 
api_version: 1 
threadsafe: true

handlers:
- url: /.*   
  script: main.app   
  login: admin

And this cron.yaml

cron:
- description: "Dashboard"
  url: /processdate?from=2016-03-01&until=2016-03-31
  schedule: every day 23:46
  timezone: Europe/Madrid

I obtain this error

0.1.0.1 - - [26/Oct/2018:00:49:40 +0200] "GET /processdate?from=2016-03-01&until=2016-03-31 HTTP/1.1" 302 355 - "AppEngine-Google; (+http://code.google.com/appengine)" "p20000.appspot.com" ms=74 cpu_ms=12 cpm_usd=3.9674e-8 loading_request=0 instance=00c61b117c78f767097d6896daa1f8967a815c14a94d54578ac19efa9d50a5077d5a app_engine_release=1.9.65 trace_id=3c92edad090b5a57d249bd92be246e58

 httpRequest: {
  status:  302   
 }
 insertId:  "5bd248840005a3aae7fa2111"  
 labels: {
  clone_id:  "00c61b117c78f767097d6896daa1f8967a815c14a94d54578ac19efa9d50a5077d5a"   
 }
 logName:  "projects/p201309/logs/appengine.googleapis.com%2Frequest_log"  
 operation: {
  first:  true   
  id:  "5bd2488400ff047fe69ec5d94d0001657e62692d70682d3230313330390001323031383130323674303033383339000100"   
  last:  true   
  producer:  "appengine.googleapis.com/request_id"   
 }
 protoPayload: {
  @type:  "type.googleapis.com/google.appengine.logging.v1.RequestLog"   
  appEngineRelease:  "1.9.65"   
  appId:  "e~myappname"   
  cost:  3.9674e-8   
  endTime:  "2018-10-25T22:49:40.369327Z"   
  finished:  true   
  first:  true   
  host:  "p200000.appspot.com"   
  httpVersion:  "HTTP/1.1"   
  instanceId:  "00c61b117c78f767097d6896daa1f8967a815c14a94d54578ac19efa9d50a5077d5a"   
  instanceIndex:  -1   
  ip:  "0.1.0.1"   
  latency:  "0.074441s"   
  megaCycles:  "12"   
  method:  "GET"   
  requestId:  "5bd2488400ff047fe69ec5d94d0001657e62692d70682d3230313330390001323031383130323674303033383339000100"   
  resource:  "/processdate?from=2016-03-01&until=2016-03-31"   
  responseSize:  "355"   
  startTime:  "2018-10-25T22:49:40.294886Z"   
  status:  302   
  taskName:  "25ed634cde05b07d9a7906f2161d2b16"   
  taskQueueName:  "__cron"   
  traceId:  "3c92edad090b5a57d249bd92be246e58"   
  traceSampled:  true   
  urlMapEntry:  "main.app"   
  userAgent:  "AppEngine-Google; (+http://code.google.com/appengine)"   
  versionId:  "20181026t003839"   
 }
 receiveTimestamp:  "2018-10-25T22:49:40.376251430Z"  
 resource: {
  labels: {
   module_id:  "default"    
   project_id:  "myappname"    
   version_id:  "20181026t003839"    
   zone:  "eu2"    
  }
  type:  "gae_app"   
 }
 timestamp:  "2018-10-25T22:49:40.294886Z"  
 trace:  "projects/myappname/traces/3c92edad090b5a57d249bd92be246e58"  
 traceSampled:  true  
}

Any idea about what could be the problem or how to solve it?

I don't have any problem runing this script in my local machine.

------ UPDATED WITH A MUCH MORE SIMPLE APP ------

I tested something much more simple. This is working when I run https://myappname.appspot.com/hellocron and http://myappname.appspot.com/hellocron

With this the result it's what expected.

But when I run it with cron error 302 it's returned again

----------- app.yaml

runtime: python27
api_version: 1
threadsafe: true

handlers:
- url: /hellocron
  script: main.app
  login: admin
  secure: always

----------- cron.yaml

cron:
- description: "hellocron"
  url: /hellocron
  schedule: every day 23:46
  timezone: Europe/Madrid

------------ I had the same error result

    0.1.0.1 - - [01/Nov/2018:12:29:49 +0100] "GET /hellocron HTTP/1.1" 302 267 - "AppEngine-Google; (+http://code.google.com/appengine)" "myappname.appspot.com" ms=8 cpu_ms=9 cpm_usd=2.9839e-8 loading_request=0 instance=00c61b117cb863320ce80ff59a2b5b4b20ee440529428f43d612baa0e980733727302b27 app_engine_release=1.9.65 trace_id=9b9fa8ad127ad41f7907529c3863a0a9
   {
     httpRequest: {
      status:  302   
     }
     insertId:  "5bdae3ad0004cfe52d64d457"  
     labels: {
      clone_id:  "00c61b117cb863320ce80ff59a2b5b4b20ee440529428f43d612baa0e980733727302b27"   
     }
     logName:  "projects/myappname/logs/appengine.googleapis.com%2Frequest_log"  
     operation: {
      first:  true   
      id:  "5bdae3ad00ff04ac4decaecea60001657e62692d70682d3230313330390001323031383131303174313135363535000100"   
      last:  true   
      producer:  "appengine.googleapis.com/request_id"   
     }
     protoPayload: {
      @type:  "type.googleapis.com/google.appengine.logging.v1.RequestLog"   
      appEngineRelease:  "1.9.65"   
      appId:  "e~myappname"   
      cost:  2.9839e-8   
      endTime:  "2018-11-01T11:29:49.315161Z"   
      finished:  true   
      first:  true   
      host:  "myappname.appspot.com"   
      httpVersion:  "HTTP/1.1"   
      instanceId:  "00c61b117cb863320ce80ff59a2b5b4b20ee440529428f43d612baa0e980733727302b27"   
      instanceIndex:  -1   
      ip:  "0.1.0.1"   
      latency:  "0.008908s"   
      megaCycles:  "9"   
      method:  "GET"   
      requestId:  "5bdae3ad00ff04ac4decaecea60001657e62692d70682d3230313330390001323031383131303174313135363535000100"   
      resource:  "/hellocron"   
      responseSize:  "267"   
      startTime:  "2018-11-01T11:29:49.306253Z"   
      status:  302   
      taskName:  "b0467e8a57f53a8ee2b827ca35db275f"   
      taskQueueName:  "__cron"   
      traceId:  "9b9fa8ad127ad41f7907529c3863a0a9"   
      traceSampled:  true   
      urlMapEntry:  "main.app"   
      userAgent:  "AppEngine-Google; (+http://code.google.com/appengine)"   
      versionId:  "20181101t115655"   
     }
     receiveTimestamp:  "2018-11-01T11:29:49.321937019Z"  
     resource: {
      labels: {
       module_id:  "default"    
       project_id:  "myappname"    
       version_id:  "20181101t115655"    
       zone:  "eu2"    
      }
      type:  "gae_app"   
     }
     timestamp:  "2018-11-01T11:29:49.306253Z"  
     trace:  "projects/myappname/traces/9b9fa8ad127ad41f7907529c3863a0a9"  
     traceSampled:  true  
    }

The code for /hellocron in python is this one basically:

decorator = OAuth2DecoratorFromClientSecrets(
    os.path.join(os.path.dirname(__file__), 'client_secrets.json'),
    scope='https://www.googleapis.com/auth/bigquery')

class hellocron (webapp2.RequestHandler):

    @decorator.oauth_required

    def get(self):

        self.response.write('hellocron')  

app = webapp2.WSGIApplication([
    ('/hellocron', hellocron),
    (decorator.callback_path, decorator.callback_handler()) ], debug=True)

Solution

  • You want to drop the @decorator.oauth_required from the cron url handler code.

    The cron service does not have any user credentials (it doesn't run as a user) so that decorator will cause a re-direction to a login service - hence the 302 response. You should be able to verify this by re-trying your manual check but from an incognito browser window.

    To secure the cron service URLs you can't use regular user authentication for this reason. But you can use login: admin in the app.yaml file and, if you want, also check for the X-Appengine-Cron: true header or the 0.1.0.1 source IP address, see Securing URLs for cron.

    Similarly you might need to drop the secure: always from the respective app.yaml handler definition (I don't have it enabled for my app): I'm not sure if the cron service makes its GET request using http or https. If it makes it using http the secure: always config will also cause a redirection to a https URL. You can easily check if this is correct or not following my earlier comment after you drop the decorator.