-
Notifications
You must be signed in to change notification settings - Fork 0
Refactor construction of error-page proxy url to detention #94
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
Changes from all commits
23dae97
901b991
36bca3d
60a08df
9d8369a
c23a0eb
52ad014
8dff5a0
0093ccc
85438b3
689977a
a78789b
cafbbee
c1f756b
59154ed
228f9f9
82e600d
1ad7d69
2717f42
f604255
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -113,12 +113,18 @@ api._shouldBypassAuth = function (req) { | |
| /** | ||
| * Proxy request to detention if container is not running. | ||
| * Proxy request to container is running | ||
| * @param {Object} targetNaviEntryInstance | ||
| * @param {String} shortHash | ||
| * @param {String} reqUrl | ||
| * @param {Object} req | ||
| * @param {Function} next | ||
| */ | ||
| api._processTargetInstance = function (targetNaviEntryInstance, reqUrl, req, next) { | ||
| api._processTargetInstance = function (targetNaviEntryInstance, shortHash, reqUrl, req, next) { | ||
| var logData = { | ||
| tx: true, | ||
| targetNaviEntryInstance: targetNaviEntryInstance, | ||
| reqUrl: reqUrl | ||
| reqUrl: reqUrl, | ||
| shortHash: shortHash | ||
| }; | ||
| log.info(logData, 'api._processTargetInstance'); | ||
|
|
||
|
|
@@ -127,14 +133,17 @@ api._processTargetInstance = function (targetNaviEntryInstance, reqUrl, req, nex | |
| return next(ErrorCat.create(404, 'Not Found')); | ||
| } | ||
|
|
||
| // Adding these to req object to make values available in proxy module's error event handler. | ||
| req.shortHash = shortHash; | ||
| req.elasticUrl = reqUrl; | ||
|
|
||
| // for error-page module if container is unresponsive | ||
| req.targetBranch = targetNaviEntryInstance.branch; | ||
|
|
||
| if (!targetNaviEntryInstance.running) { | ||
| log.trace(logData, '_processTargetInstance !running'); | ||
| req.targetHost = errorPage.generateErrorUrl('not_running', { | ||
| elasticUrl: reqUrl, | ||
| targetBranch: targetNaviEntryInstance.branch | ||
| shortHash: shortHash | ||
| }); | ||
| return next(); | ||
| } | ||
|
|
@@ -194,29 +203,35 @@ api._getTargetHostElastic = function (logData, req, next) { | |
| log.trace(logData, | ||
| '_getTargetHostElastic redis.lrange mongo.fetchNaviEntry isBrowser !refererUrl'); | ||
| // document might not have a userMappings key yet | ||
| var mappedInstanceId = (naviEntry.userMappings) ? | ||
| var mappedInstanceShortHash = (naviEntry.userMappings) ? | ||
| naviEntry.userMappings[req.session.userId] : null; | ||
| if (!mappedInstanceId) { | ||
| if (!mappedInstanceShortHash) { | ||
| log.trace(logData, | ||
| '_getTargetHostElastic redis.lrange mongo.fetchNaviEntry isBrowser !refererUrl '+ | ||
| '!mappedInstanceId'); | ||
| '!mappedInstanceShortHash'); | ||
| // use master | ||
| targetNaviEntryInstance = mongo.constructor.findMasterPodBranch(naviEntry); | ||
| var findResult = mongo.constructor.findMasterPodBranch(naviEntry); | ||
| targetNaviEntryInstance = findResult.directUrlObj; | ||
| mappedInstanceShortHash = findResult.directUrlShortHash; | ||
| } else { | ||
| log.trace(put({ | ||
| mappedInstanceId: mappedInstanceId | ||
| mappedInstanceShortHash: mappedInstanceShortHash | ||
| }, logData), | ||
| '_getTargetHostElastic redis.lrange mongo.fetchNaviEntry isBrowser !refererUrl '+ | ||
| 'mappedInstanceId'); | ||
| targetNaviEntryInstance = naviEntry.directUrls[mappedInstanceId]; | ||
| 'mappedInstanceShortHash'); | ||
| targetNaviEntryInstance = naviEntry.directUrls[mappedInstanceShortHash]; | ||
| } | ||
| return api._processTargetInstance(targetNaviEntryInstance, reqUrl, req, next); | ||
| return api._processTargetInstance(targetNaviEntryInstance, mappedInstanceShortHash, | ||
| reqUrl, req, next); | ||
| } | ||
| } else { | ||
| // if not browser, proxy to master | ||
| log.trace(logData, '_getTargetHostElastic redis.lrange mongo.fetchNaviEntry !isBrowser'); | ||
| targetNaviEntryInstance = mongo.constructor.findMasterPodBranch(naviEntry); | ||
| return api._processTargetInstance(targetNaviEntryInstance, reqUrl, req, next); | ||
| log.trace(logData, 'getTargetHost redis.lrange mongo.fetchNaviEntry !isBrowser'); | ||
| var findResult = mongo.constructor.findMasterPodBranch(naviEntry); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in the other PR you check for shorthash, do you need to do same check here?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same answer as above so I copy/paste: Not here, our data * should * never exist in a state without 1 masterPodBranch. That other PR is checking for the event that the referer header is a valid formatted runnable elastic url but isn't actually a url that the target instance has an association with. Different situation. link you shared - that's an acceptable state that can occur. |
||
| targetNaviEntryInstance = findResult.directUrlObj; | ||
| return api._processTargetInstance(targetNaviEntryInstance, | ||
| findResult.directUrlShortHash, | ||
| reqUrl, req, next); | ||
| } | ||
| }); | ||
| }; | ||
|
|
@@ -251,9 +266,9 @@ api._getTargetHostElasticReferer = function (logData, naviEntry, req, next) { | |
| var refererUserMappedInstanceId = (naviEntry.refererNaviEntry.userMappings) ? | ||
| naviEntry.refererNaviEntry.userMappings[req.session.userId] : null; | ||
| var refererNaviEntryInstance; | ||
|
|
||
| if (refererUserMappedInstanceId) { | ||
| refererNaviEntryInstance = | ||
| naviEntry.refererNaviEntry.directUrls[refererUserMappedInstanceId]; | ||
| refererNaviEntryInstance = naviEntry.refererNaviEntry.directUrls[refererUserMappedInstanceId]; | ||
| log.trace(put({ | ||
| refererUserMappedInstanceId: refererUserMappedInstanceId, | ||
| refererNaviEntryInstance: refererNaviEntryInstance | ||
|
|
@@ -262,8 +277,9 @@ api._getTargetHostElasticReferer = function (logData, naviEntry, req, next) { | |
| 'refererNaviEntryInstance'); | ||
| } else { | ||
| // no user-mapping for current user and referer instance, use master | ||
| refererNaviEntryInstance = | ||
| mongo.constructor.findMasterPodBranch(naviEntry.refererNaviEntry); | ||
| var findResult = mongo.constructor.findMasterPodBranch(naviEntry.refererNaviEntry); | ||
| refererNaviEntryInstance = keypather.get(findResult, 'directUrlObj'); | ||
| refererUserMappedInstanceId = keypather.get(findResult, 'directUrlShortHash'); | ||
| log.trace(put({ | ||
| refererUserMappedInstanceId: refererUserMappedInstanceId, | ||
| refererNaviEntryInstance: refererNaviEntryInstance | ||
|
|
@@ -293,7 +309,9 @@ api._getTargetHostElasticReferer = function (logData, naviEntry, req, next) { | |
| * Referer url is a valid runnable elasticUrl however there might be no defined DNS mappings. | ||
| * Proxy to the masterPod instance if so. | ||
| */ | ||
| targetNaviEntryInstance = mongo.constructor.findMasterPodBranch(naviEntry); | ||
| //targetNaviEntryInstance = mongo.constructor.findMasterPodBranch(naviEntry); | ||
| var findResult = mongo.constructor.findMasterPodBranch(naviEntry.refererNaviEntry); | ||
| targetNaviEntryInstance = keypather.get(findResult, 'directUrlObj'); | ||
| } | ||
|
|
||
| if (!targetNaviEntryInstance) { | ||
|
|
@@ -304,9 +322,15 @@ api._getTargetHostElasticReferer = function (logData, naviEntry, req, next) { | |
| }, logData), | ||
| '_getTargetHostElasticReferer redis.lrange mongo.fetchNaviEntry isBrowser !targetNaviEntryInstance '+ | ||
| 'use master'); | ||
| targetNaviEntryInstance = mongo.constructor.findMasterPodBranch(naviEntry); | ||
|
|
||
| var findResult = mongo.constructor.findMasterPodBranch(naviEntry); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same note
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same answer |
||
| targetNaviEntryInstance = findResult.directUrlObj; | ||
| return api._processTargetInstance(targetNaviEntryInstance, | ||
| findResult.directUrlShortHash, | ||
| reqUrl, req, next); | ||
|
|
||
| } | ||
| return api._processTargetInstance(targetNaviEntryInstance, reqUrl, req, next); | ||
| return api._processTargetInstance(targetNaviEntryInstance, instanceShortHash, reqUrl, req, next); | ||
| }; | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -122,7 +122,8 @@ Mongo.prototype.setUserMapping = function (elasticUrl, userId, instanceShortHash | |
| }; | ||
|
|
||
| /** | ||
| * Find nested directUrl object on a naviEntry document that is a masterPod branch | ||
| * Find nested directUrl object and its key (shortHash on a naviEntry document that is a masterPod | ||
| * branch | ||
| * @param {String} branchName | ||
| * @return {Object|undefined} | ||
| */ | ||
|
|
@@ -136,7 +137,10 @@ Mongo.findMasterPodBranch = function (naviEntry) { | |
| for (var i = 0, len = shortHashes.length; i < len; i++) { | ||
| var directUrlObj = naviEntry.directUrls[shortHashes[i]]; | ||
| if (directUrlObj.masterPod) { | ||
| return directUrlObj; | ||
| return { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. update comment above saying what this returns.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good catch
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| directUrlShortHash: shortHashes[i], | ||
| directUrlObj: directUrlObj | ||
| }; | ||
| } | ||
| } | ||
| log.warn(logData, 'findMasterPodBranch !match'); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,7 @@ var lab = exports.lab = Lab.script(); | |
|
|
||
| //var errorPage = require('models/error-page.js'); | ||
| var api = require('models/api.js'); | ||
| var log = require('middlewares/logger')(__filename).log; | ||
| var mongo = require('models/mongo'); | ||
| var naviEntriesFixtures = require('../fixture/navi-entries'); | ||
| var naviRedisEntriesFixture = require('../fixture/navi-redis-entries'); | ||
|
|
@@ -148,6 +149,7 @@ describe('api.js unit test', function () { | |
| expect(test).to.equal(result); | ||
| done(); | ||
| }); | ||
|
|
||
| it('should add https', function (done) { | ||
| var test = api._getUrlFromRequest({ | ||
| isBrowser: true, | ||
|
|
@@ -219,23 +221,47 @@ describe('api.js unit test', function () { | |
| }); | ||
|
|
||
| describe('_processTargetInstance', function () { | ||
| beforeEach(function (done) { | ||
| sinon.stub(api, '_getDestinationProxyUrl'); | ||
| done(); | ||
| }); | ||
|
|
||
| afterEach(function (done) { | ||
| api._getDestinationProxyUrl.restore(); | ||
| done(); | ||
| }); | ||
|
|
||
| it('should next with error if !targetNaviEntryInstance', function (done) { | ||
| api._processTargetInstance(null, '', {}, function (err) { | ||
| api._processTargetInstance(null, '', '', {}, function (err) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this addition makes me think "is there a test for if this is missing or invalid?". I don't see one in the near vicinity...
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| expect(err.message).to.equal('Not Found'); | ||
| done(); | ||
| }); | ||
| }); | ||
|
|
||
| it('should set req.targetHost if !running', function (done) { | ||
| it('should set req.targetHost to error url if !running', function (done) { | ||
| var req = {}; | ||
| var reqUrl = 'api-staging-codenow.runnableapp.com'; | ||
| api._processTargetInstance({ | ||
| running: false, | ||
| branch: 'master' | ||
| }, reqUrl, req, function (err) { | ||
| }, '55555', reqUrl, req, function (err) { | ||
| expect(err).to.be.undefined(); | ||
| expect(req.targetHost).to.equal('http://localhost:55551?type=not_running&elasticUrl='+ | ||
| reqUrl+'&targetBranch=master'); | ||
| reqUrl+'&shortHash=55555'); | ||
| done(); | ||
| }); | ||
| }); | ||
|
|
||
| it('should set req.targetHost to container host & port if running', function (done) { | ||
| api._getDestinationProxyUrl.returns('http://0.0.0.0:600'); | ||
| var req = {}; | ||
| var reqUrl = 'api-staging-codenow.runnableapp.com'; | ||
| api._processTargetInstance({ | ||
| running: true, | ||
| branch: 'master' | ||
| }, '55555', reqUrl, req, function (err) { | ||
| expect(err).to.be.undefined(); | ||
| expect(req.targetHost).to.equal('http://0.0.0.0:600'); | ||
| done(); | ||
| }); | ||
| }); | ||
|
|
@@ -438,35 +464,45 @@ describe('api.js unit test', function () { | |
| it('should handle navientires document with no user-mappings', function (done) { | ||
| api._processTargetInstance.restore(); | ||
| mongo.constructor.findAssociationShortHashByElasticUrl.restore(); | ||
|
|
||
| var restore = put({}, naviEntriesFixtures.refererNaviEntry); | ||
| delete naviEntriesFixtures.refererNaviEntry.userMappings; | ||
|
|
||
| api.getTargetHost(req, {}, function (err) { | ||
| expect(err).to.be.undefined(); | ||
| expect(req.targetHost).to.equal('http://0.0.0.2:39942'); | ||
| naviEntriesFixtures.refererNaviEntry.userMappings = restore; | ||
| naviEntriesFixtures.refererNaviEntry = restore; | ||
| done(); | ||
| }); | ||
| }); | ||
|
|
||
| it('should next with error if navientries document with no user-mappings and no '+ | ||
| 'masterpod', function (done) { | ||
|
|
||
| api._processTargetInstance.restore(); | ||
| mongo.constructor.findAssociationShortHashByElasticUrl.restore(); | ||
|
|
||
| var restore = put({}, naviEntriesFixtures.refererNaviEntry); | ||
| delete naviEntriesFixtures.refererNaviEntry.userMappings; | ||
| naviEntriesFixtures.refererNaviEntry.directUrls.aaaaa1.masterPod = false; | ||
|
|
||
| api.getTargetHost(req, {}, function (err) { | ||
| expect(err.message).to.equal('Not Found'); | ||
| naviEntriesFixtures.refererNaviEntry.userMappings = restore; | ||
| naviEntriesFixtures.refererNaviEntry.directUrls.aaaaa1.masterPod = true; | ||
|
|
||
| naviEntriesFixtures.refererNaviEntry = restore; | ||
|
|
||
| done(); | ||
| }); | ||
| }); | ||
|
|
||
| it('should default to masterPod if !instanceShortHash', function (done) { | ||
| var mockNaviEntry = {}; | ||
| sinon.stub(mongo.constructor, 'findMasterPodBranch', function () { | ||
| return mockNaviEntry; | ||
|
|
||
| sinon.stub(mongo.constructor, 'findMasterPodBranch').returns({ | ||
| directUrlObj: mockNaviEntry, | ||
| directUrlShortHash: 'FFFF' | ||
| }); | ||
|
|
||
| api.getTargetHost(req, {}, function (err) { | ||
|
|
@@ -484,8 +520,10 @@ describe('api.js unit test', function () { | |
| sinon.stub(mongo.constructor, 'findMasterPodBranch'); | ||
| mongo.constructor.findMasterPodBranch.onFirstCall().returns({}); | ||
| mongo.constructor.findMasterPodBranch.onSecondCall().returns(undefined); | ||
| mongo.constructor.findMasterPodBranch.onThirdCall().returns({ | ||
| masterPod: true | ||
| mongo.constructor.findMasterPodBranch.onSecondCall().returns({ | ||
| directUrlObj: { | ||
| masterPod: true | ||
| } | ||
| }); | ||
|
|
||
| api.getTargetHost(req, {}, function () { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in the other PR you check for shorthash, do you need to do same check here?
https://github.com/CodeNow/navi/pull/96/files#diff-7ccf25494e1cbc5cba89bfd84e901eb9R293
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not here, our data * should * never exist in a state without 1 masterPodBranch. That other PR is checking for the event that the referer header is a valid formatted runnable elastic url but isn't actually a url that the target instance has an association with. Different situation. link you shared - that's an acceptable state that can occur.