Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

datastore: GAE prod and dev support for datastore #154

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions lib/common/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ function Connection(opts) {

this.isConnecting = false;

if (opts.credentials) {
if (opts.gaeApp) {
this.gaeApp = opts.gaeApp;
} else if (opts.credentials) {
if (opts.credentials.client_email && opts.credentials.private_key) {
this.credentials = opts.credentials;
} else {
Expand Down Expand Up @@ -149,8 +151,11 @@ Connection.prototype.connect = function() {
*/
Connection.prototype.fetchToken = function(callback) {
var that = this;
if (!this.opts.keyFilename && !this.credentials) {
// We need to fetch an access token only for regular and
// App Engine prod applications.
if (this.gaeApp && this.gaeApp.isProd) {

This comment was marked as spam.

// We should be on GCE, try to retrieve token from the metadata server.
// This should be GAE prod or dev

This comment was marked as spam.

req({
method: 'get',
uri: METADATA_TOKEN_URL,
Expand Down Expand Up @@ -251,6 +256,13 @@ Connection.prototype.createAuthorizedReq = function(reqOpts, callback) {
reqOpts.headers['User-Agent'] = USER_AGENT;
}

// devappserver doesn't require authorization,
// skip authorization header.
if (this.gaeApp && !this.gaeApp.isProd) {
callback(null, reqOpts);
return;
}

function onConnected(err) {
if (err) {
callback(err);
Expand Down
35 changes: 35 additions & 0 deletions lib/common/gae.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Copyright 2014 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* @private
*/

'use strict';

var gae = {};

gae.getInfo = function() {
if (process.env.GAE_LONG_APP_ID) {
return {
id: process.env.GAE_LONG_APP_ID,
isProd: process.env.GAE_VM !== undefined
};

This comment was marked as spam.

This comment was marked as spam.

}
return null;
};

module.exports = gae;
13 changes: 12 additions & 1 deletion lib/datastore/dataset.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ var conn = require('../common/connection.js');
*/
var entity = require('./entity.js');

/**
* @private
* @type module:common/gae
*/
var gae = require('../common/gae.js');

/**
* @private
* @type module:datastore/pb
Expand Down Expand Up @@ -92,12 +98,17 @@ var SCOPES = [
function Dataset(options) {
options = options || {};

var gaeInfo = gae.getInfo();
this.id = options.projectId;
if (gaeInfo) {
this.id = gaeInfo.id;
}
this.connection = new conn.Connection({
gaeApp: gaeInfo,
credentials: options.credentials,
keyFilename: options.keyFilename,
scopes: SCOPES
});
this.id = options.projectId;
this.namespace = options.namespace;
this.transaction = this.createTransaction_();
}
Expand Down
16 changes: 14 additions & 2 deletions lib/datastore/transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,21 @@ var https = require('https');
/** @type module:datastore/entity */
var entity = require('./entity.js');

/** @type module:datastore/gae */
var gae = require('../common/gae.js');

/** @type module:datastore/pb */
var pb = require('./pb.js');

/** @type module:common/util */
var util = require('../common/util.js');

/** @const {string} Host to send with API requests. */
/** @const {string} Host to talk to in prod. */
var GOOGLE_APIS_HOST = 'www.googleapis.com';

/** @const {string} Host to talk to in GAE dev. */
var GOOGLE_APIS_DEV_HOST = 'localhost';

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.


/** @const {string} Non-transaction mode key. */
var MODE_NON_TRANSACTIONAL = 'NON_TRANSACTIONAL';

Expand Down Expand Up @@ -428,9 +434,15 @@ Transaction.prototype.mapQuery = function() {
Transaction.prototype.makeReq = function(method, req, respType, callback) {
// TODO: Handle non-HTTP 200 cases.
callback = callback || util.noop;

var gaeInfo = gae.getInfo();
var host = GOOGLE_APIS_HOST;
if (gaeInfo && !gaeInfo.isProd) {
host = GOOGLE_APIS_DEV_HOST;
}
this.conn.createAuthorizedReq({
method: 'POST',
host: GOOGLE_APIS_HOST,
host: host,
path: '/datastore/v1beta2/datasets/' + this.datasetId + '/' + method,
headers: {
'content-type': 'application/x-protobuf'
Expand Down
43 changes: 43 additions & 0 deletions test/datastore/dataset.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,49 @@ var mockRespGet = require('../testdata/response_get.json');
var Transaction = require('../../lib/datastore/transaction.js');

describe('Dataset', function() {

describe('constructor', function() {

beforeEach(function() {
delete process.env.GAE_LONG_APP_ID;
delete process.env.GAE_VM;
});

it('should detect GAE prod', function(done) {
process.env.GAE_LONG_APP_ID = 'gae-app-id';
process.env.GAE_VM = true;
var ds = new datastore.Dataset();
assert.strictEqual(ds.id, 'gae-app-id');
ds.transaction.conn.createAuthorizedReq = function(req) {
assert.equal(req.host, 'www.googleapis.com');
done();
};
ds.get(ds.key('Kind', 123), function() {});
});

it('should detect GAE dev', function(done) {
process.env.GAE_LONG_APP_ID = 'gae-app-id';
var ds = new datastore.Dataset();
assert.strictEqual(ds.id, 'gae-app-id');
ds.transaction.conn.createAuthorizedReq = function(req) {
assert.equal(req.host, 'localhost');
done();
};
ds.get(ds.key('Kind', 123), function() {});
});

it ('should not set app id if GAE_LONG_APP_ID is not set', function(done) {
var ds = new datastore.Dataset();
assert.equal(!!ds.id, false);
ds.transaction.conn.createAuthorizedReq = function(req) {
assert.equal(req.host, 'www.googleapis.com');
done();
};
ds.get(ds.key('Kind', 123), function() {});
});

});

it('should return a key scoped by namespace', function() {
var ds = new datastore.Dataset({ projectId: 'test', namespace: 'my-ns' });
var key = ds.key('Company', 1);
Expand Down