Symptom: I tried to use stock Google libraries to access other Google APIs, like Google Storage, but got bit by an obscure error "not an App Engine context". Here's a repro, and a commented out fix I eventually found after talking to @danjacques :
package lucigaeissue
import (
"net/http"
"golang.org/x/oauth2/google"
storage "google.golang.org/api/storage/v1"
// "github.com/luci/gae/impl/prod"
"github.com/luci/luci-go/appengine/gaemiddleware"
"github.com/luci/luci-go/common/logging"
"github.com/luci/luci-go/server/router"
)
func init() {
r := router.New()
mw := gaemiddleware.BaseProd()
gaemiddleware.InstallHandlers(r, mw)
r.GET("/", mw, handler)
http.DefaultServeMux.Handle("/", r)
}
func handler(c *router.Context) {
scope := storage.DevstorageFullControlScope
ctx := c.Context // What I'd expect to use
// ctx := prod.AEContext(c.Context) // What I should really use
client, _ := google.DefaultClient(ctx, scope)
service, _ := storage.New(client)
if _, err := service.Buckets.List("project-id").Do(); err != nil {
logging.Errorf(c.Context, "Buckets.List failed: %s", err)
} else {
logging.Infof(c.Context, "Buckets.List succeeded")
}
}
What happens: router.Handle() starts the handler with an empty context;
gaemiddleware.BaseProd() installs ProdServices which calls prod.Use which hides the true AppEngine context under a key.
As a result, it appears that c.Context is an App Engine context, because Datastore and other GAE services work just fine, yet calling a native Cloud API fails with "not an App Engine context".
This error is very non-intuitive, and cost me hours of debugging. Turns out, I simply needed to use prod.AEContext(c.Context) in DefaultClient(). I did not find any mention of it in the documentation, not even for AEContext itself.
The problem stems from the fact that c.Context appears to be the only way to get a context.Context value, and nothing indicates that it's not an App Engine context.
So, it's a UX / useability issue which could probably be fixed by better documentation, or simply allowing c.Context to be a derivative of the actual App Engine context. The latter might be a luci-go issue.
Thanks!
Symptom: I tried to use stock Google libraries to access other Google APIs, like Google Storage, but got bit by an obscure error "not an App Engine context". Here's a repro, and a commented out fix I eventually found after talking to @danjacques :
What happens: router.Handle() starts the handler with an empty context;
gaemiddleware.BaseProd() installs ProdServices which calls prod.Use which hides the true AppEngine context under a key.
As a result, it appears that c.Context is an App Engine context, because Datastore and other GAE services work just fine, yet calling a native Cloud API fails with "not an App Engine context".
This error is very non-intuitive, and cost me hours of debugging. Turns out, I simply needed to use
prod.AEContext(c.Context)inDefaultClient(). I did not find any mention of it in the documentation, not even forAEContextitself.The problem stems from the fact that c.Context appears to be the only way to get a
context.Contextvalue, and nothing indicates that it's not an App Engine context.So, it's a UX / useability issue which could probably be fixed by better documentation, or simply allowing
c.Contextto be a derivative of the actual App Engine context. The latter might be aluci-goissue.Thanks!