4

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)
Aris
  • 156
  • 1
  • 13

4 Answers4

2

My name is Dan I'm from google cloud support.

As I could understand, you're receiving a 302 response when launching Cron jobs. Have you a custom domain with SSL enabled? I ask you this because we have received this report from some customers that are using HTTP instead of HTTPS. Are you running your application on App Engine flexible? This information will help me to better understand your current scenario.

I will be awaiting your reply.

  • Hi Dan, I'm using the default app domain in standard environment. I use https:\\myappname.appspot.com – Aris Oct 28 '18 at 13:07
  • When I run it on google chrome with this url (https://myappname.appspot.com/hellocron) it's working, it returns what is expected https://myappname.appspot.com/hellocron. I tested to deploy the same application to another project and the error is the same. – Aris Oct 30 '18 at 18:15
  • 1
    don't you have any router script redirecting http:// request to https://? – Dangelo Santana Oct 31 '18 at 00:54
  • 1
    I ask you this because this would justify the error. – Dangelo Santana Oct 31 '18 at 01:05
  • No I don't. How could I do that? – Aris Nov 01 '18 at 06:48
  • I tested this app.yaml but nothing changed `runtime: python27 api_version: 1 threadsafe: true handlers: - url: /hellocron script: main.app login: admin secure: always` – Aris Nov 01 '18 at 11:51
  • https://stackoverflow.com/questions/4083221/how-to-redirect-all-http-requests-to-https – Dangelo Santana Nov 03 '18 at 02:51
  • The article above is a great example. – Dangelo Santana Nov 03 '18 at 02:52
  • Thanks @DangeloSantana, I did have a redirect script in my app and your comment lead me to identify it as the cause of the problem. – TimSC Oct 25 '20 at 03:05
2

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.

Dan Cornilescu
  • 39,470
  • 12
  • 57
  • 97
  • Ok,but what is the method that you use to authenticate in google api, because i'm using decorators to connect to google big query api, but if I delete this decorator code, how could I connect to big query api https://developers.google.com/api-client-library/python/guide/google_app_engine#decorators – Aris Nov 04 '18 at 21:45
  • 1
    The decorators only work for real users, they can't work for cron as there is no user. Your cron handler code would need to load credentials differently. Take a look at using [service accounts](https://cloud.google.com/bigquery/docs/authentication/#service_accounts) – Dan Cornilescu Nov 05 '18 at 02:54
  • I used OAuth2ServiceAccount https://developers.google.com/identity/protocols/OAuth2ServiceAccount and it worked for cron servise and browser execution. Thanks! @DanConilescu – Aris Nov 05 '18 at 20:58
0

I wanted to post this solution as I was pulling my hair out yesterday trying to figure out why my GAE cron jobs kept failing and this thread helped me fine tune the solution that worked.

I am using Python, but the idea seems the same. In my cron script (i.e. the page visited with the cron logic), I had a redirect after successful execution of a report, due to this the cron would state it failed in GAE, but the logic would still execute correctly.

To fix the issue, all I did was return a simple HTTP response so the cron thought everything loaded correctly on the page instead of the redirect or not returning an HTTP response all together.

ViaTech
  • 2,143
  • 1
  • 16
  • 51
0

I was trying to execute a django admin endpoint from gcloud app engine. It seems there is no way to make gcloud crons login with any credentials before running so here is what you have to do if you find yourself in this situation (receiving 302 in your crons executions):

  1. Make the url public, that means: no credentials needed to run it.
  2. Gcloud crons send request including X-AppEngine-Cron in it's headers. They strip 'X-' from all their headers so you may trust this particular one. All you have to do is check for this header in your endpoint request as this guy does.

Doc: https://cloud.google.com/appengine/docs/flexible/go/scheduling-jobs-with-cron-yaml?hl=es-419#validating_cron_requests

Alvaro Rodriguez Scelza
  • 3,643
  • 2
  • 32
  • 47