Last active
January 27, 2016 22:13
-
-
Save battlecow/cd0c2233e9f197ec0049 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var constants = require('./constants'); | |
var logging = require('./logging'); | |
var cache = require('memory-cache'); | |
var Q = require('q'); | |
var Client = require('node-rest-client').Client; | |
var client = new Client(); | |
var artifactory = module.exports = {}; | |
artifactory.verifyWar = function (instance) { | |
var deferred = Q.defer(); | |
if (instance._branchName.indexOf('/') === -1 && instance._branchName !== 'develop') { | |
client.get(constants.ARTIFACTORY_API + 'storage/libs-release-local/' + instance._branchName + '/JSS/ROOT.war', function (data, response) { | |
if (response.statusCode !== 200) { | |
deferred.reject({ | |
error: { | |
errorCode: data.errors[0].message, | |
message: 'ROOT.war not found, please run a Bamboo build and try again' | |
} | |
}); | |
} else { | |
var marshaledData = marshalArtifactData(JSON.parse(data.toString('UTF8'))); | |
deferred.resolve(marshaledData); | |
} | |
}); | |
} else if (instance._branchName.indexOf('release/') !== -1) { | |
var releaseVersion = instance._branchName.split('release/').join(''); | |
client.get(constants.ARTIFACTORY_API + 'storage/libs-release-local/' + releaseVersion + '/JSS/ROOT.war', function (data, response) { | |
if (response.statusCode !== 200) { | |
deferred.reject({ | |
error: { | |
errorCode: data.errors[0].message, | |
message: 'ROOT.war not found, please run a Bamboo build and try again' | |
} | |
}); | |
} else { | |
var marshaledData = marshalArtifactData(JSON.parse(data.toString('UTF8'))); | |
deferred.resolve(marshaledData); | |
} | |
}); | |
} else { | |
client.get(constants.ARTIFACTORY_API + 'storage/libs-snapshot-local/' + instance._branchName + '/JSS/ROOT.war', function (data, response) { | |
if (response.statusCode !== 200) { | |
deferred.reject({ | |
error: { | |
errorCode: data.errors[0].message, | |
message: 'ROOT.war not found, please run a Bamboo build and try again' | |
} | |
}); | |
} else { | |
var marshaledData = marshalArtifactData(JSON.parse(data.toString('UTF8'))); | |
deferred.resolve(marshaledData); | |
} | |
}); | |
} | |
return deferred.promise; | |
}; | |
function marshalArtifactData(rawData) { | |
delete rawData.repo; | |
delete rawData.path; | |
delete rawData.mimeType; | |
delete rawData.checksums; | |
delete rawData.originalChecksums; | |
return rawData; | |
}; | |
artifactory.getBuildProperties = function (uri) { | |
var deferred = Q.defer(); | |
client.get(uri + '?properties', function (data, response) { | |
if (response.statusCode !== 200) { | |
deferred.reject({ | |
error: { | |
errorCode: data.errors[0].message, | |
message: 'Unable to retrieve artifact properties, please try your request again later' | |
} | |
}); | |
} else { | |
var buildProps = JSON.parse(data.toString('UTF8')); | |
var marshaledProps = { | |
buildName: buildProps.properties['build.name'][0], | |
buildNumber: buildProps.properties['build.number'][0] | |
}; | |
deferred.resolve(marshaledProps); | |
} | |
}).on('error', function (err) { | |
logging.error(err); | |
deferred.reject({ | |
error: { | |
errorCode: 500, | |
message: 'Unable to retrieve build properties from Artifactory' | |
} | |
}) | |
}); | |
return deferred.promise; | |
}; | |
artifactory.getBuildInfo = function (build) { | |
var deferred = Q.defer(); | |
client.get(constants.ARTIFACTORY_API + 'build/' + encodeURI(build.buildName) + '/' + build.buildNumber, function (data, response) { | |
if (response.statusCode !== 200) { | |
deferred.reject({ | |
error: { | |
errorCode: data.errors[0].message, | |
message: 'Unable to retrieve build information, please try your request again later' | |
} | |
}); | |
} else { | |
var rawBuildInfo = JSON.parse(data.toString('UTF8')); | |
var sha; | |
if (!rawBuildInfo.buildInfo.hasOwnProperty('properties')) { | |
sha = 'N/A'; | |
} else { | |
sha = rawBuildInfo.buildInfo.properties['buildInfo.env.planRepository.revision']; | |
} | |
var buildInfo = { | |
sha: sha, | |
link: rawBuildInfo.buildInfo.url | |
}; | |
deferred.resolve(buildInfo); | |
} | |
}).on('error', function (err) { | |
logging.error(err); | |
deferred.reject({ | |
error: { | |
errorCode: 500, | |
message: 'Unable to retrieve build information from Artifactory' | |
} | |
}) | |
}); | |
return deferred.promise; | |
}; | |
function getReleases(cacheBust) { | |
var cacheBust = cacheBust || false; | |
var deferred = Q.defer(); | |
var releases = cache.get('releases'); | |
if (releases && !cacheBust) { | |
logging.debug('Getting releases from cache'); | |
deferred.resolve(releases); | |
} else { | |
client.get(constants.ARTIFACTORY_API + 'storage/libs-release-local/', function (data, response) { | |
if (response.statusCode !== 200) { | |
logging.debug('Failed to retrieve releases Error: ' + data.errors[0].message); | |
deferred.reject({ | |
error: { | |
errorCode: data.errors[0].message, | |
message: 'Unable to retrieve release options from Artifactory' | |
} | |
}); | |
} else { | |
var releases = JSON.parse(data.toString('UTF8')).children; | |
cache.put('releases', releases); | |
deferred.resolve(releases); | |
} | |
}).on('error', function (err) { | |
logging.error(err); | |
deferred.reject({ | |
error: { | |
errorCode: 500, | |
message: 'Unable to retrieve release options from Artifactory' | |
} | |
}) | |
}); | |
} | |
return deferred.promise; | |
} | |
function filterReleases(releases, name, retried) { | |
var retried = retried || false; | |
var releaseVersion = name.split('release/').join(''); | |
var filteredReleases = releases.filter(function (element) { | |
return (element.uri.indexOf(releaseVersion) !== -1); | |
}); | |
if (filteredReleases.length === 0 && !retried) { | |
logging.info(name + ' not found in cache, busting cache and trying again'); | |
getReleases(true).then(function (response) { | |
filterReleases(response, name, true); | |
}); | |
} | |
return filteredReleases.map(function (r) { | |
return { | |
branchName: 'release' + r.uri, | |
version: r.uri.split('/')[1] | |
} | |
}); | |
} | |
artifactory.getReleaseOptions = function (name) { | |
logging.debug('Retrieving release options for: ' + name); | |
return getReleases().then(function (response) { | |
return filterReleases(response, name); | |
}); | |
}; | |
function queryDockerTags(image) { | |
var deferred = Q.defer(); | |
client.get(constants.ARTIFACTORY_API + 'docker/docker/v2/' + image + '/tags/list', function (data, response) { | |
if (response.statusCode !== 200) { | |
logging.debug('Failed to retrieve Docker tags for image: ' + image + ' Error: ' + data.errors[0].message); | |
deferred.reject({ | |
error: { | |
errorCode: data.errors[0].message, | |
message: 'Docker tags not found for image: ' + image | |
} | |
}); | |
} else { | |
deferred.resolve(data.tags); | |
} | |
}).on('error', function (err) { | |
logging.error(err); | |
deferred.reject({ | |
error: { | |
errorCode: 500, | |
message: 'Unable to retrieve Docker options from Artifactory' | |
} | |
}) | |
}); | |
return deferred.promise; | |
}; | |
artifactory.getDockerTags = function (image) { | |
logging.debug('Retrieving docker tags for image: ' + image); | |
return queryDockerTags(image).then(function (response) { | |
return response.filter(function (element) { | |
return ((element !== 'master') && (element !== 'latest')); | |
}); | |
}); | |
}; | |
artifactory.ping = function () { | |
logging.debug('Pinging artifactory api'); | |
var deferred = Q.defer(); | |
client.get(constants.ARTIFACTORY_API + 'system/version', function (data, response) { | |
if (response.statusCode !== 200) { | |
deferred.resolve({ | |
status: response.statusCode, | |
version: 'Unknown', | |
errorMessage: 'Unknown problem accessing Artifactory API' | |
}); | |
} else { | |
var info = JSON.parse(data.toString('UTF8')); | |
deferred.resolve({status: response.statusCode, version: info.version}); | |
} | |
}).on('error', function (err) { | |
logging.error(err); | |
deferred.resolve({ | |
status: 500, | |
version: 'Unknown', | |
errorMessage: 'Unknown problem accessing Artifactory API' | |
}) | |
}); | |
return deferred.promise; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Q = require('q'); | |
var fleetCtl = require('./fleetctl'); | |
var logging = require('./logging'); | |
var fleetapi = require('./fleetapi'); | |
var fleet = module.exports = {}; | |
fleet.createInstance = function (host) { | |
var deferred = Q.defer(); | |
var customUnits; | |
getRequiredUnits(host).then(function (units) { | |
customUnits = units.map(function (unit) { | |
return customReplace(unit, host); | |
}); | |
var promises = customUnits.map(function (unit) { | |
logging.debug('creating unit: ' + unit.name); | |
return fleetCtl.createUnit(unit); | |
}); | |
return Q.all(promises); | |
}).then(function (response) { | |
var units = customUnits.map(function (unit) { | |
delete unit.options; | |
unit.systemdActiveState = 'inactive'; | |
return unit; | |
}); | |
deferred.resolve(units); | |
}).catch(function (err) { | |
deferred.reject(err); | |
}); | |
return deferred.promise; | |
}; | |
fleet.upgradeInstance = function (host) { | |
var upgradeUnitName = {name: '[email protected]', _ID: host._ID}; | |
var jssUnitName = 'jss-app-' + host._tomcatVersion + '@' + host._ID + '.service'; | |
logging.info('Creating upgrade unit: ' + upgradeUnitName.name); | |
return fleet.createCustomUnit(upgradeUnitName).then(function (response) { | |
logging.debug('Upgrade unit created: ' + response.name); | |
upgradeUnitName.name = response.name; | |
logging.debug('Check if upgrade unit is inactive before starting JSS shutdown'); | |
return fleetCtl.retryState('inactive', upgradeUnitName.name); | |
}).then(function (response) { | |
logging.debug('Upgrade unit run completed, shutting down the JSS'); | |
return fleetCtl.toggleUnitState(jssUnitName, {desiredState: 'inactive'}); | |
}).then(function (response) { | |
logging.debug('JSS Shutdown started, ensure it is shutdown before attempting startup'); | |
return fleetCtl.retryState('inactive', jssUnitName); | |
}).then(function (response) { | |
logging.debug('JSS shutdown completed, starting up the JSS for upgrade'); | |
return fleetCtl.toggleUnitState(jssUnitName, {desiredState: 'launched'}); | |
}).then(function (response) { | |
logging.debug('JSS startup started, check to ensure it becomes active'); | |
return fleetCtl.retryState('active', jssUnitName); | |
}).finally(function (response) { | |
logging.debug('Remove upgrade unit from Fleet'); | |
return fleetCtl.deleteUnit(upgradeUnitName.name); | |
}); | |
}; | |
fleet.createCustomUnit = function (customUnit) { | |
var deferred = Q.defer(); | |
var units = customizedOptionalUnits(); | |
units = units.filter(function (u) { | |
return (u === customUnit.name); | |
}); | |
if (units.length !== 1) { | |
logging.error(customUnit.name + ' unit template does not exist'); | |
deferred.reject({ | |
errors: [ | |
{message: 'Customized unit template does not exist'} | |
] | |
}); | |
} else { | |
getOptionalUnit(units[0]).then(function (unit) { | |
var customU = customReplace(unit, customUnit); | |
customU.desiredState = 'launched'; | |
return fleetCtl.createUnit(customU).then(function (response) { | |
logging.info(customU.name + ' custom unit has been created'); | |
delete customU.options; | |
customU.systemdActiveState = 'inactive'; | |
deferred.resolve(customU); | |
}); | |
}).catch(function (err) { | |
logging.error(units[0] + ' ' + err.error.message); | |
deferred.reject({ | |
errors: [ | |
{message: err.error.message} | |
] | |
}); | |
}); | |
} | |
return deferred.promise; | |
}; | |
fleet.deleteUnits = function (host) { | |
var units = customizedRequiredUnits(host); | |
var promises = units.map(function (u) { | |
return fleetCtl.deleteUnit(u).then(function (response) { | |
logging.debug('Deleted unit: ' + u); | |
return response; | |
}).catch(function (err) { | |
logging.error('Error deleting unit ' + u + ': ' + JSON.stringify(err)); | |
return err; | |
}); | |
}); | |
return Q.allSettled(promises).then(function (promises) { | |
return promises.map(function (r) { | |
return r.value; | |
}); | |
}); | |
}; | |
fleet.deleteOrphanedUnits = function (units) { | |
var promises = units.map(function (u) { | |
return fleetCtl.deleteUnit(u); | |
}); | |
return Q.allSettled(promises).then(function (promises) { | |
var results = promises.map(function (r) { | |
return r.value; | |
}); | |
return {results: results}; | |
}); | |
}; | |
fleet.orphanedUnits = function () { | |
return fleetCtl.listCachedUnits().then(function (cachedUnits) { | |
var units = collateUnits(cachedUnits); | |
var promises = units.map(function (u) { | |
return fleetapi.verifyHost(u.id).then(function (response) { | |
Object.assign(u, response); | |
return u; | |
}); | |
}); | |
return Q.allSettled(promises).then(function (promises) { | |
return promises.map(function (r) { | |
return r.value; | |
}).filter(function (u) { | |
if (!u.exists) { | |
return true; | |
} | |
}); | |
}); | |
}); | |
}; | |
function validUnitTemplates() { | |
return [ | |
'mysql-data', | |
'mysql', | |
'jss-app-discovery', | |
'jss-app-6', | |
'jss-app-7', | |
'jss-app-8', | |
'jss-data', | |
'mysql-discovery', | |
'jss-load-computers']; | |
} | |
function checkValidName(templateName) { | |
var templates = validUnitTemplates(); | |
return !!(templates.find(function (t) { | |
if (t === templateName) { | |
return true; | |
} | |
})); | |
} | |
function collateUnits(units) { | |
var newArr = []; | |
units.map(function (unit) { | |
try { | |
var splitName = unit.name.split('@'); | |
var id; | |
if (checkValidName(splitName[0])) { | |
id = splitName[1].match(/\d+/g); | |
} | |
if (!id) { | |
return undefined; | |
} | |
} catch (err) { | |
return undefined; | |
} | |
return {id: Number(id[0]), name: unit.name}; | |
}).map(function (unit) { | |
if (!unit) { | |
return; | |
} | |
var found = newArr.find(function (u, index) { | |
if (u.id === unit.id) { | |
return true; | |
} | |
}); | |
if (!found) { | |
newArr.push({id: unit.id, units: [unit.name]}); | |
} else { | |
found.units.push(unit.name); | |
} | |
return; | |
}); | |
return newArr; | |
}; | |
function getOptionalUnit(unitName) { | |
return fleetCtl.getUnit(unitName); | |
} | |
function requiredUnitTemplates(host) { | |
return [ | |
'[email protected]', | |
'[email protected]', | |
'[email protected]', | |
'jss-app-' + host._tomcatVersion + '@.service', | |
'[email protected]', | |
'[email protected]']; | |
} | |
function getRequiredUnits(host) { | |
var deferred = Q.defer(); | |
var requiredUnits = requiredUnitTemplates(host); | |
var promises = requiredUnits.map(function (unit) { | |
return fleetCtl.getUnit(unit); | |
}); | |
Q.all(promises).then(function (response) { | |
deferred.resolve(response); | |
}).catch(function (err) { | |
deferred.reject(err); | |
}); | |
return deferred.promise; | |
} | |
var unitVars = [ | |
{name: '[email protected]', properties: [{name: '{{issueKey}}', replace: '_branchName'}]}, | |
{name: '[email protected]', properties: [{name: '{{issueKey}}', replace: '_branchName'}]}, | |
{ | |
name: '[email protected]', | |
properties: [ | |
{name: '{{war.file}}', replace: '_downloadUri'}, | |
{name: '{{tomcat.version}}', replace: '_tomcatFullVersion'} | |
] | |
}, | |
{ | |
name: '[email protected]', | |
properties: [ | |
{name: '{{war.file}}', replace: '_downloadUri'}, | |
{name: '{{tomcat.version}}', replace: '_tomcatFullVersion'} | |
] | |
}, | |
{ | |
name: '[email protected]', | |
properties: [ | |
{name: '{{war.file}}', replace: '_downloadUri'}, | |
{name: '{{tomcat.version}}', replace: '_tomcatFullVersion'} | |
] | |
}, | |
{ | |
name: '[email protected]', properties: [ | |
{name: '{{appVersion}}', replace: '_tomcatVersion'}, | |
{name: '{{hostname}}', replace: '_name'}] | |
}, | |
{ | |
name: '[email protected]', properties: [ | |
{name: '{{mysqlType}}', replace: '_mysqlType'}, | |
{name: '{{hostname}}', replace: '_name'}] | |
}, | |
{ | |
name: '[email protected]', properties: [ | |
{name: '{{appVersion}}', replace: '_tomcatVersion'}, | |
{name: '{{hostname}}', replace: '_name'}, | |
{name: '{{computers}}', replace: 'computers'}] | |
}, | |
{name: '[email protected]', properties: [{name: '{{hostname}}', replace: '_name'}]}, | |
{name: '[email protected]', properties: [{name: '{{machineID}}', replace: '_coreID'}]} | |
]; | |
var customReplace = function (unit, host) { | |
unitVars.map(function (uv) { | |
if (unit.name === uv.name) { | |
unit.options.map(function (o) { | |
for (var i = 0; i < uv.properties.length; i++) { | |
if (o.value.search(uv.properties[i].name) !== -1) { | |
o.value = o.value.split(uv.properties[i].name).join(host[uv.properties[i].replace]); | |
} | |
} | |
}); | |
} | |
}); | |
unit.name = unit.name.replace(/\@/, '@' + host._ID); | |
unit.desiredState = 'launched'; | |
return unit; | |
}; | |
function customizedRequiredUnits(host) { | |
var units = requiredUnitTemplates(host); | |
return units.map(function (u) { | |
return u.replace(/\@/, '@' + host._ID); | |
}); | |
} | |
function customizedOptionalUnits() { | |
return [ | |
'[email protected]', | |
'[email protected]', | |
'[email protected]' | |
]; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var constants = require('./constants'); | |
var Q = require('q'); | |
var logging = require('./logging'); | |
var cache = require('memory-cache'); | |
var CronJob = require('cron').CronJob; | |
var Client = require('node-rest-client').Client; | |
var client = new Client(); | |
var api = module.exports = {}; | |
api.startCronJobs = function () { | |
this.canListMachines = true; | |
this.canListUnits = true; | |
this.canListStates = true; | |
var fleet = this; | |
new CronJob('*/8 * * * * *', function () { | |
if (fleet.canListMachines) { | |
logging.debug('canListMachines CronJob fired, making request'); | |
fleet.canListMachines = false; | |
queryMachines().then(function () { | |
logging.debug('canListMachines CronJob completed'); | |
}).catch(function (err) { | |
logging.error('canListMachines error: ' + err.error.errorCode + ': ' + err.error.message); | |
}).finally(function (resp) { | |
fleet.canListMachines = true; | |
}); | |
} | |
else { | |
logging.debug('canListMachines CronJob fired but last request still pending'); | |
} | |
}, null, true); | |
new CronJob('*/13 * * * * *', function () { | |
if (fleet.canListUnits) { | |
logging.debug('canListUnits CronJob fired, making request'); | |
fleet.canListUnits = false; | |
getNextPage().then(function () { | |
logging.debug('canListUnits CronJob completed'); | |
}).catch(function (err) { | |
logging.error('canListUnits error: ' + err.error.errorCode + ': ' + err.error.message); | |
}).finally(function (resp) { | |
fleet.canListUnits = true; | |
}); | |
} | |
else { | |
logging.debug('canListUnits CronJob fired but last request still pending'); | |
} | |
}, null, true); | |
new CronJob('*/9 * * * * *', function () { | |
if (fleet.canListStates) { | |
logging.debug('canListStates CronJob fired, making request'); | |
fleet.canListStates = false; | |
getNextStatesPage().then(function () { | |
logging.debug('canListStates CronJob completed'); | |
}).catch(function (err) { | |
logging.error('canListStates error: ' + err.error.errorCode + ': ' + err.error.message); | |
}).finally(function (resp) { | |
fleet.canListStates = true; | |
}); | |
} | |
else { | |
logging.debug('canListUnits CronJob fired but last request still pending'); | |
} | |
}, null, true); | |
logging.info('fleetctl cronjobs started'); | |
}; | |
function getNextStatesPage(pagedStates, deferred, nextPageToken) { | |
var states = pagedStates || []; | |
var defer = deferred || Q.defer(); | |
var nextPageToken = nextPageToken || ''; | |
var nextPageTokenQuery = ''; | |
if (nextPageToken !== '') { | |
nextPageTokenQuery = '?nextPageToken=' + nextPageToken; | |
} | |
var success = false; | |
client.get(constants.FLEET_SERVER + 'state' + nextPageTokenQuery, function (data, response) { | |
if (data.error || response.statusCode !== 200) { | |
defer.reject(data); | |
} | |
states.push.apply(states, data.states); | |
if (typeof data.nextPageToken === 'undefined') { | |
logging.debug('Finished getting states, reached last page'); | |
success = true; | |
} | |
if (success) { | |
cache.put('states', states); | |
defer.resolve(states); | |
} else { | |
getNextStatesPage(states, defer, data.nextPageToken); | |
} | |
}).on('error', function (err) { | |
logging.error(err); | |
defer.reject({ | |
error: { | |
errorCode: err.code, | |
message: 'Unable to contact Fleet host, please try your request again later' | |
} | |
}); | |
}); | |
return defer.promise; | |
} | |
function getNextPage(pagedUnits, deferred, nextPageToken) { | |
var units = pagedUnits || []; | |
var defer = deferred || Q.defer(); | |
var nextPageToken = nextPageToken || ''; | |
var nextPageTokenQuery = ''; | |
if (nextPageToken !== '') { | |
nextPageTokenQuery = '?nextPageToken=' + nextPageToken; | |
} | |
var success = false; | |
logging.debug('Start getting unit page: ' + constants.FLEET_SERVER + 'units' + nextPageTokenQuery); | |
client.get(constants.FLEET_SERVER + 'units' + nextPageTokenQuery, function (data, response) { | |
logging.debug('Finished unit page: ' + constants.FLEET_SERVER + 'units' + nextPageTokenQuery); | |
if (data.error || response.statusCode !== 200) { | |
defer.reject(data); | |
} | |
units.push.apply(units, data.units); | |
if (typeof data.nextPageToken === 'undefined') { | |
logging.debug('Finished getting units, reached last page'); | |
success = true; | |
} | |
if (success) { | |
cache.put('units', units); | |
defer.resolve(units); | |
} else { | |
getNextPage(units, defer, data.nextPageToken); | |
} | |
}).on('error', function (err) { | |
logging.error(err); | |
defer.reject({ | |
error: { | |
errorCode: err.code, | |
message: 'Unable to contact Fleet host, please try your request again later' | |
} | |
}); | |
}); | |
return defer.promise; | |
} | |
api.listUnits = function () { | |
var units = cache.get('units'); | |
if (units) { | |
return Q(units); | |
} else { | |
return Q({error: 'Cache is priming, please wait...'}); | |
} | |
}; | |
api.listCachedUnits = function () { | |
var deferred = Q.defer(); | |
var units = cache.get('units'); | |
if (units) { | |
deferred.resolve(units); | |
} else { | |
deferred.reject({error: 'Cache is priming, please wait...'}); | |
} | |
return deferred.promise; | |
}; | |
queryUnit = function (unitName) { | |
var deferred = Q.defer(); | |
client.get(constants.FLEET_SERVER + 'units/' + unitName, function (data, response) { | |
if (response.statusCode !== 200) { | |
deferred.reject(data); | |
} else { | |
deferred.resolve(data); | |
} | |
}).on('error', function (err) { | |
logging.error(err); | |
deferred.reject({ | |
error: { | |
errorCode: err.code, | |
message: 'Unable to contact Fleet host, please try your request again later' | |
} | |
}); | |
}); | |
return deferred.promise; | |
}; | |
api.getUnit = function (unitName) { | |
return queryUnit(unitName); | |
}; | |
api.createUnit = function (unit) { | |
var deferred = Q.defer(); | |
client.put(constants.FLEET_SERVER + 'units/' + unit.name, { | |
headers: {'Content-Type': 'application/json'}, | |
data: unit | |
}, function (data, response) { | |
if (response.statusCode !== 201) { | |
deferred.reject(data); | |
} else { | |
deferred.resolve(data); | |
} | |
}).on('error', function (err) { | |
logging.error(err); | |
deferred.reject({ | |
error: { | |
errorCode: err.code, | |
message: 'Unable to contact Fleet host, please try your request again later' | |
} | |
}); | |
}); | |
return deferred.promise; | |
}; | |
api.toggleUnitState = function (unitName, unit) { | |
var deferred = Q.defer(); | |
client.put(constants.FLEET_SERVER + 'units/' + unitName, { | |
headers: {'Content-Type': 'application/json'}, | |
data: unit | |
}, function (data, response) { | |
if (response.statusCode !== 204) { | |
deferred.reject(data); | |
} else { | |
deferred.resolve(data); | |
} | |
}).on('error', function (err) { | |
logging.error(err); | |
deferred.reject({ | |
error: { | |
errorCode: err.code, | |
message: 'Unable to contact Fleet host, please try your request again later' | |
} | |
}); | |
}); | |
return deferred.promise; | |
}; | |
queryStates = function () { | |
var deferred = Q.defer(); | |
logging.debug('Getting all states'); | |
client.get(constants.FLEET_SERVER + 'state', function (data, response) { | |
if (response.statusCode !== 200) { | |
deferred.reject(data); | |
} else { | |
cache.put('states', data); | |
deferred.resolve(data); | |
} | |
}).on('error', function (err) { | |
logging.error(err); | |
deferred.reject({ | |
error: { | |
errorCode: err.code, | |
message: 'Unable to contact Fleet host, please try your request again later' | |
} | |
}); | |
}); | |
return deferred.promise; | |
} | |
api.getStates = function () { | |
var states = cache.get('states'); | |
if (states) { | |
return Q(states); | |
} else { | |
return Q({error: 'Cache is priming, please wait...'}); | |
} | |
}; | |
queryUnitState = function (unitName) { | |
var deferred = Q.defer(); | |
client.get(constants.FLEET_SERVER + 'state?unitName=' + unitName, function (data, response) { | |
if (response.statusCode !== 200) { | |
deferred.reject(data); | |
} else { | |
if (data.hasOwnProperty('states')) { | |
deferred.resolve(data.states[0]); | |
} else { | |
deferred.resolve(data); | |
} | |
} | |
}).on('error', function (err) { | |
logging.error(err); | |
deferred.reject({ | |
error: { | |
errorCode: err.code, | |
message: 'Unable to contact Fleet host, please try your request again later' | |
} | |
}); | |
}); | |
return deferred.promise; | |
}; | |
api.getUnitState = function (unitName) { | |
logging.debug('Getting unit state for: ' + unitName); | |
var states = cache.get('states'); | |
if (!states || states.length === 0) { | |
return queryUnitState(unitName); | |
} | |
var state = states.filter(function (element) { | |
return (element.name === unitName); | |
}); | |
if (state.length === 0) { | |
logging.debug(unitName + ' not found in state cache, trying fleet'); | |
return queryUnitState(unitName); | |
} else { | |
return Q(state[0]); | |
} | |
}; | |
api.queryUnitState = function (unitName) { | |
logging.debug('Querying unit state for: ' + unitName); | |
return queryUnitState(unitName); | |
}; | |
function queryMachines() { | |
var deferred = Q.defer(); | |
client.get(constants.FLEET_SERVER + 'machines', function (data, response) { | |
if (response.statusCode !== 200) { | |
deferred.reject(data); | |
} else { | |
cache.put('machines', data); | |
deferred.resolve(data); | |
} | |
}).on('error', function (err) { | |
logging.error(err); | |
deferred.reject({ | |
error: { | |
errorCode: err.code, | |
message: 'Unable to contact Fleet host, please try your request again later' | |
} | |
}); | |
}); | |
return deferred.promise; | |
} | |
api.getMachines = function () { | |
var machines = cache.get('machines'); | |
if (machines) { | |
return Q(machines); | |
} else { | |
return queryMachines(); | |
} | |
}; | |
api.getMachineState = function (machineID) { | |
var deferred = Q.defer(); | |
logging.debug('Getting machine state for: ' + machineID); | |
client.get(constants.FLEET_SERVER + 'state?machineID=' + machineID, function (data, response) { | |
if (response.statusCode !== 200) { | |
deferred.reject(data); | |
} else { | |
deferred.resolve(data); | |
} | |
}).on('error', function (err) { | |
logging.error(err); | |
deferred.reject({ | |
error: { | |
errorCode: err.code, | |
message: 'Unable to contact Fleet host, please try your request again later' | |
} | |
}); | |
}); | |
return deferred.promise; | |
}; | |
api.deleteUnit = function (unitName) { | |
var deferred = Q.defer(); | |
logging.debug('Deleting unit: ' + unitName); | |
client.delete(constants.FLEET_SERVER + 'units/' + unitName, function (data, response) { | |
if (response.statusCode !== 204) { | |
deferred.reject(data); | |
} else { | |
deferred.resolve({}); | |
} | |
}).on('error', function (err) { | |
logging.error(err); | |
deferred.reject({ | |
error: { | |
errorCode: err.code, | |
message: 'Unable to contact Fleet host, please try your request again later' | |
} | |
}); | |
}); | |
return deferred.promise; | |
}; | |
api.retryState = function (desiredState, unitName, maxRetries, maxFailures, deferred, backoff) { | |
maxRetries = (maxRetries || maxRetries === 0) ? maxRetries : 5; | |
maxFailures = (maxFailures || maxFailures === 0) ? maxFailures : 5; | |
deferred = deferred || Q.defer(); | |
backoff = backoff || 1; | |
var state; | |
var success = null; | |
queryUnitState(unitName).then(function (response) { | |
if (typeof (response) !== 'undefined') { | |
if (response.systemdActiveState === 'activating') { | |
maxFailures = 0; | |
} | |
if (response.systemdActiveState === desiredState || (desiredState === 'inactive' && isEmpty(response))) { | |
success = true; | |
state = response; | |
} else if (response.systemdActiveState === 'failed') { | |
maxFailures--; | |
if (maxFailures <= 0) { | |
deferred.reject(response); | |
return; | |
} | |
} | |
} | |
if (success) { | |
deferred.resolve(state); | |
} else if (maxRetries > 0) { | |
setTimeout(function () { | |
if (backoff < 30) { | |
backoff *= 2; | |
} else { | |
backoff = 30; | |
} | |
api.retryState(desiredState, unitName, maxRetries - 1, maxFailures, deferred, backoff); | |
}, backoff * 1000); | |
} else if (maxRetries === 0) { | |
deferred.reject(false); | |
} | |
}); | |
return deferred.promise; | |
}; | |
api.ping = function () { | |
var deferred = Q.defer(); | |
logging.debug('Pinging Fleetd api'); | |
client.get(constants.FLEET_SERVER + 'discovery', function (data, response) { | |
if (response.statusCode !== 200) { | |
deferred.resolve({ | |
status: response.statusCode, | |
version: response.headers.server.split('/')[1], | |
errorMessage: 'Unknown problem accessing Fleet API' | |
}); | |
} else { | |
deferred.resolve({ | |
status: response.statusCode, | |
version: response.headers.server.split('/')[1] | |
}); | |
} | |
}).on('error', function (err) { | |
logging.error(err); | |
deferred.resolve({ | |
status: 500, | |
version: 'Unknown', | |
errorMessage: err.code + ': Unknown problem accessing Fleet API' | |
}); | |
}); | |
return deferred.promise; | |
}; | |
function isEmpty(obj) { | |
for (var x in obj) { | |
return false; | |
} | |
return true; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var loggingLevel = process.env.LOGLEVEL || 'INFO'; | |
var logLevel; | |
(function init() { | |
switch (loggingLevel) { | |
case 'DEBUG': | |
logLevel = 0; | |
break; | |
case 'INFO': | |
logLevel = 1; | |
break; | |
case 'WARNING': | |
logLevel = 2; | |
break; | |
case 'ERROR': | |
logLevel = 3; | |
break; | |
} | |
return; | |
})(); | |
var api = module.exports = {}; | |
function timestamp() { | |
return '[' + new Date().toUTCString() + ']: '; | |
} | |
api.debug = function (msg) { | |
if (logLevel === 0) { | |
console.log((timestamp() + msg)); | |
} | |
}; | |
api.info = function (msg) { | |
if (logLevel <= 1) { | |
console.log(timestamp() + msg); | |
} | |
}; | |
api.warning = function (msg) { | |
if (logLevel <= 2) { | |
console.log(timestamp() + msg); | |
} | |
}; | |
api.error = function (msg) { | |
if (logLevel <= 3) { | |
console.log(timestamp() + msg); | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var zmq = require('zmq'); | |
var zmqResponder = zmq.socket('rep'); | |
var fleet = require('./fleet'); | |
var artifactory = require('./artifactory'); | |
var logging = require('./logging'); | |
var api = module.exports = {}; | |
// Register to monitoring events | |
zmqResponder.on('connect', function (fd, ep) { | |
console.log('connect, endpoint:', ep); | |
}); | |
zmqResponder.on('connect_delay', function (fd, ep) { | |
console.log('connect_delay, endpoint:', ep); | |
}); | |
zmqResponder.on('connect_retry', function (fd, ep) { | |
console.log('connect_retry, endpoint:', ep); | |
}); | |
zmqResponder.on('listen', function (fd, ep) { | |
console.log('listen, endpoint:', ep); | |
}); | |
zmqResponder.on('bind_error', function (fd, ep) { | |
console.log('bind_error, endpoint:', ep); | |
}); | |
zmqResponder.on('accept', function (fd, ep) { | |
console.log('accept, endpoint:', ep); | |
}); | |
zmqResponder.on('accept_error', function (fd, ep) { | |
console.log('accept_error, endpoint:', ep); | |
}); | |
zmqResponder.on('close', function (fd, ep) { | |
console.log('close, endpoint:', ep); | |
}); | |
zmqResponder.on('close_error', function (fd, ep) { | |
console.log('close_error, endpoint:', ep); | |
}); | |
zmqResponder.on('disconnect', function (fd, ep) { | |
console.log('disconnect, endpoint:', ep); | |
}); | |
// Handle monitor error | |
zmqResponder.on('monitor_error', function (err) { | |
console.log('Error in monitoring: %s, will restart monitoring in 5 seconds', err); | |
setTimeout(function () { | |
zmqResponder.monitor(500, 0); | |
}, 5000); | |
}); | |
// Call monitor, check for events every 500ms and get all available events. | |
console.log('Start monitoring...'); | |
zmqResponder.monitor(500, 0); | |
zmqResponder.connect('tcp://127.0.0.1:5668'); | |
zmqResponder.on('message', function (msg, data) { | |
var parsed = JSON.parse(msg); | |
logging.info('ZMQ Request received: ' + parsed.event); | |
switch (parsed.event) { | |
case 'create': | |
return artifactory.verifyWar(parsed.data).then(function (response) { | |
parsed.data['_downloadUri'] = response.downloadUri; | |
parsed.data['_lastModified'] = response.lastModified; | |
return artifactory.getBuildProperties(response.uri); | |
}).then(function (response) { | |
parsed.data['buildName'] = response.buildName; | |
parsed.data['buildNumber'] = response.buildNumber; | |
return artifactory.getBuildInfo(response); | |
}).then(function (response) { | |
parsed.data['sha'] = response.sha; | |
parsed.data['link'] = response.link; | |
return fleet.createInstance(parsed.data).then(function (response) { | |
var parsedResponse = { | |
downloadUri: parsed.data['_downloadUri'], | |
lastModified: parsed.data['_lastModified'], | |
sha: parsed.data['sha'], | |
link: parsed.data['link'], | |
buildName: parsed.data['buildName'], | |
buildNumber: parsed.data['buildNumber'], | |
units: response | |
}; | |
logging.info('Sending fleets creation response'); | |
zmqResponder.send(JSON.stringify(parsedResponse)); | |
}).catch(function (err) { | |
zmqResponder.send(JSON.stringify(err)); | |
logging.error(JSON.stringify(err)); | |
}); | |
}).catch(function (err) { | |
zmqResponder.send(JSON.stringify(err)); | |
logging.error(JSON.stringify(err)); | |
}); | |
break; | |
case 'delete': | |
return fleet.deleteUnits(parsed.data).then(function (response) { | |
logging.info('Removed units successfully'); | |
zmqResponder.send(JSON.stringify(response)); | |
}); | |
break; | |
case 'upgrade': | |
var parsedReponse = {}; | |
return fleet.upgradeInstance(parsed.data).then(function (response) { | |
logging.info('Upgraded: ' + parsed.data._ID); | |
return artifactory.verifyWar(parsed.data).then(function (response) { | |
parsedReponse.downloadUri = response.downloadUri; | |
parsedReponse.lastModified = response.lastModified; | |
return artifactory.getBuildProperties(response.uri); | |
}).then(function (response) { | |
parsedReponse.buildName = response.buildName; | |
parsedReponse.buildNumber = response.buildNumber; | |
return artifactory.getBuildInfo(response); | |
}).then(function (response) { | |
parsedReponse.sha = response.sha; | |
parsedReponse.link = response.link; | |
logging.info('Sending fleets upgrade response'); | |
zmqResponder.send(JSON.stringify(parsedReponse)); | |
}).catch(function (err) { | |
zmqResponder.send(JSON.stringify(err)); | |
logging.error(JSON.stringify(err)); | |
}); | |
}).catch(function (err) { | |
logging.error(JSON.stringify({error: {message: 'JSS Upgrade attempt failed'}})); | |
zmqResponder.send(JSON.stringify(err)); | |
}); | |
break; | |
case 'test': | |
setTimeout(function () { | |
console.log('received: ' + parsed.data); | |
zmqResponder.send(JSON.stringify('Message ID: ' + parsed.data)); | |
}, (Math.floor(Math.random() * (10 - 5 + 1)) + 5) * 1000); | |
break; | |
} | |
}); | |
zmqResponder.on('error', function (err) { | |
logging.error(err); | |
console.log(zmqResponder); | |
zmqResponder.send(JSON.stringify(err)); | |
}); | |
zmqResponder.bind('tcp://*:5668', function (err) { | |
if (err) { | |
logging.error(err); | |
} else { | |
logging.info("ZMQ awaiting orders on port 5668"); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment