diff --git a/lib/models/mongo/context-version.js b/lib/models/mongo/context-version.js index d3f1d1776..fc1daed8a 100644 --- a/lib/models/mongo/context-version.js +++ b/lib/models/mongo/context-version.js @@ -719,9 +719,10 @@ ContextVersionSchema.statics.updateAndGetFailedBuild = (buildId, errorMessage) = /** * @param {string} buildId - build id associated with context version + * @param {object} imageData - the image data to attach to the context version, * @return {Promise} */ -ContextVersionSchema.statics.updateAndGetSuccessfulBuild = (buildId) => { +ContextVersionSchema.statics.updateAndGetSuccessfulBuild = (buildId, imageData) => { var log = logger.child({ buildId: buildId, method: 'updateAndGetSuccessfulBuild' @@ -732,7 +733,8 @@ ContextVersionSchema.statics.updateAndGetSuccessfulBuild = (buildId) => { $set: { 'build.completed': Date.now(), 'build.failed': false, - 'state': ContextVersion.states.buildSucceeded + 'state': ContextVersion.states.buildSucceeded, + 'imageData': imageData } } diff --git a/lib/models/mongo/schemas/context-version.js b/lib/models/mongo/schemas/context-version.js index 35e17eb02..cb17ca728 100644 --- a/lib/models/mongo/schemas/context-version.js +++ b/lib/models/mongo/schemas/context-version.js @@ -210,6 +210,34 @@ var ContextVersionSchema = module.exports = new Schema({ }, log: Schema.Types.Mixed, failed: Boolean + }, + imageData: { + type: { + ports: { + type: [{ + protocol: { + type: String + }, + port: { + type: String + } + }], + 'default': [] + }, + cmd: [{ + type: String, + 'default': [] + }], + entryPoint: [{ + type: String, + 'default': [] + }] + }, + 'default': { + ports: [], + cmd: [], + entryPoint: [] + } } }) diff --git a/lib/models/services/build-service.js b/lib/models/services/build-service.js index 57826114a..d6fc17f6c 100644 --- a/lib/models/services/build-service.js +++ b/lib/models/services/build-service.js @@ -335,13 +335,14 @@ BuildService._buildBuild = function (build, buildInfo, sessionUser) { /** * @param {String} buildId + * @param {object} imageData - the image data to attach to the context version, * @return {Promise} */ -BuildService.updateSuccessfulBuild = (buildId) => { +BuildService.updateSuccessfulBuild = (buildId, imageData) => { var log = logger.child({ method: 'updateSuccessfulBuild' }) log.info({ buildId }, 'updateSuccessfulBuild called') - return ContextVersion.updateAndGetSuccessfulBuild(buildId) + return ContextVersion.updateAndGetSuccessfulBuild(buildId, imageData) .tap((SuccessfullContextVersions) => { var contextVersionIds = SuccessfullContextVersions.map(pluck('_id')) diff --git a/lib/workers/build.container.died.js b/lib/workers/build.container.died.js index 6ac4459c8..34463cf8c 100644 --- a/lib/workers/build.container.died.js +++ b/lib/workers/build.container.died.js @@ -19,44 +19,26 @@ const Promise = require('bluebird') const error = require('error') const InstanceService = require('models/services/instance-service') const BuildService = require('models/services/build-service') + const Isolation = require('models/mongo/isolation') const logger = require('logger') const rabbitMQ = require('models/rabbitmq') -const ContainerImageBuilderDied = {} - -module.exports = ContainerImageBuilderDied - -ContainerImageBuilderDied.jobSchema = joi.object({ - from: joi.string().required(), - host: joi.string().uri({ scheme: 'http' }).required(), - id: joi.string().required(), - time: joi.number().required(), - inspectData: joi.object({ - Config: joi.object({ - Labels: joi.object({ - 'contextVersion.build._id': joi.string().required(), - 'ownerUsername': joi.string().required(), - 'sessionUserGithubId': joi.number().required() - }).unknown().required() - }).unknown().required() - }).unknown().required() -}).unknown().required() - class Worker { constructor (job) { + this.log = logger.child({ + job: job, + module: 'ContainerImageBuilderDied' + }) + this.host = job.host this.id = job.id + this.inspectImageData = this._getImageDataFromJob(job) this.inspectData = job.inspectData this.contextVersionBuildId = job.inspectData.Config.Labels['contextVersion.build._id'] this.ownerUsername = job.inspectData.Config.Labels.ownerUsername this.sessionUserGithubId = job.inspectData.Config.Labels.sessionUserGithubId this.dockerImageTag = job.inspectData.Config.Labels.dockerTag - - this.log = logger.child({ - job: job, - module: 'ContainerImageBuilderDied' - }) } /** @@ -103,7 +85,7 @@ class Worker { imageTag: this.dockerImageTag }) - return BuildService.updateSuccessfulBuild(this.contextVersionBuildId) + return BuildService.updateSuccessfulBuild(this.contextVersionBuildId, this.inspectImageData) } /** @@ -309,6 +291,48 @@ class Worker { return false } + + /** + * @param ports {Object} Object who's properties are in the format {/:} + * @returns {Array} Array of ports parsed into {protocol: , port: + * @private + */ + _parsePorts (ports) { + let portList = [] + let splitPort + + if (ports) { + for (let key of Object.keys(ports)) { + splitPort = key.split('/') + + portList.push({ + protocol: splitPort[1], + port: splitPort[0] + }) + } + } + + return portList + } + + /** + * Returns the image data formatted for the context version model. + * + * @param job + * @returns {{port: Array, cmd: Array, entryPoint: Array}} + * @private + */ + _getImageDataFromJob (job) { + const log = this.log.child({ job, method: '_getImageDataFromJob' }) + log.info('called') + + let rawImageData = keypather.get(job, 'inspectImageData.Config') + return { + port: this._parsePorts(keypather.get(rawImageData, 'ExposedPorts')), + cmd: keypather.get(rawImageData, 'Cmd'), + entryPoint: keypather.get(rawImageData, 'Entrypoint') + } + } } module.exports = { @@ -323,6 +347,12 @@ module.exports = { from: joi.string().required(), host: joi.string().uri({ scheme: 'http' }).required(), id: joi.string().required(), + time: joi.number().required(), + inspectImageData: joi.object({ + exposedPorts: joi.array(joi.object({}).unknown()).default([]), + cmd: joi.array(joi.string()).default([]), + entrypoint: joi.array(joi.string()).default([]) + }).unknown().required(), inspectData: joi.object({ Config: joi.object({ Labels: joi.object({ diff --git a/unit/models/mongo/context-version.js b/unit/models/mongo/context-version.js index 9999798a6..2195e5bde 100644 --- a/unit/models/mongo/context-version.js +++ b/unit/models/mongo/context-version.js @@ -309,7 +309,7 @@ describe('Context Version Unit Test', function () { done() }) - it('should save a successful build', (done) => { + it('should save a successful build with no image data', (done) => { const buildId = 12341 ContextVersion.updateAndGetSuccessfulBuild(buildId).asCallback(() => { @@ -320,12 +320,70 @@ describe('Context Version Unit Test', function () { $set: { 'build.failed': false, 'build.completed': sinon.match.number, - 'state': ContextVersion.states.buildSucceeded + 'state': ContextVersion.states.buildSucceeded, + imageData: undefined } }) sinon.assert.calledOnce(ContextVersion.findByAsync) - sinon.assert.calledWith(ContextVersion.findByAsync, 'build._id', buildId) + sinon.assert.calledWithExactly(ContextVersion.findByAsync, 'build._id', buildId) + done() + }) + }) + + it('should save a successful build with image data', (done) => { + const buildId = 12341 + const imageData = { + ports: [{ + protocol: 'Omega', + port: '13' + }], + cmd: ['cmd 1'], + entryPoint: ['entry 1'] + } + + ContextVersion.updateAndGetSuccessfulBuild(buildId, imageData).asCallback(() => { + sinon.assert.calledOnce(ContextVersion.updateByAsync) + sinon.assert.calledWith(ContextVersion.updateByAsync, + 'build._id', + buildId, { + $set: { + 'build.failed': false, + 'build.completed': sinon.match.number, + 'state': ContextVersion.states.buildSucceeded, + 'imageData': imageData + } + }) + + sinon.assert.calledOnce(ContextVersion.findByAsync) + sinon.assert.calledWithExactly(ContextVersion.findByAsync, 'build._id', buildId) + done() + }) + }) + + it('should save a successful build with empty image data', (done) => { + const buildId = 12341 + const imageData = { + ports: [], + cmd: [], + entryPoint: [] + } + + ContextVersion.updateAndGetSuccessfulBuild(buildId, imageData).asCallback(() => { + sinon.assert.calledOnce(ContextVersion.updateByAsync) + sinon.assert.calledWith(ContextVersion.updateByAsync, + 'build._id', + buildId, { + $set: { + 'build.failed': false, + 'build.completed': sinon.match.number, + 'state': ContextVersion.states.buildSucceeded, + 'imageData': imageData + } + }) + + sinon.assert.calledOnce(ContextVersion.findByAsync) + sinon.assert.calledWithExactly(ContextVersion.findByAsync, 'build._id', buildId) done() }) })