rascal
Version:
A friendly wrapper around amqplib with (mostly) safe defaults
138 lines (108 loc) • 8.86 kB
JavaScript
var debug = require('debug')('rascal:config:validate')
var format = require('util').format
var _ = require('lodash')
var async = require('async')
module.exports = _.curry(function(config, next) {
try {
validateVhosts(config.vhosts)
validatePublications(config.publications)
validateSubscriptions(config.subscriptions)
validateShovels(config.shovels)
next(null, config)
} catch (err) {
next(err, config)
}
function validateVhosts(vhosts) {
_.each(vhosts, validateVhost)
}
function validateVhost(vhost, vhostName) {
validateAttributes('Vhost', vhost, vhostName, ['defaults', 'namespace', 'name', 'connection', 'exchanges', 'queues', 'bindings'])
validateConnectionAttributes(vhost.connection, vhostName, ['slashes', 'protocol', 'hostname', 'user', 'password', 'port', 'vhost', 'options', 'retry', 'auth', 'pathname', 'query', 'url', 'loggableUrl'])
validateExchanges(vhost, vhostName, vhost.exchanges)
validateQueues(vhost, vhostName, vhost.queues)
validateBindings(vhost, vhostName, vhost.bindings)
}
function validateAttributes(type, object, objectName, valid) {
var invalid = _.chain(object).omit(valid).keys().value()
if (invalid.length) throw new Error(format('%s: %s refers to an unsupported attribute: %s', type, objectName, invalid[0]))
}
function validateConnectionAttributes(connection, vhostName, valid) {
var invalid = _.chain(connection).omit(valid).keys().value()
if (invalid.length) throw new Error(format('Vhost: %s connection refers to an unsupported attribute: %s', vhostName, invalid[0]))
}
function validateVhostChildAttributes(vhostName, type, child, childName, valid) {
var invalid = _.chain(child).omit(valid).keys().value()
if (invalid.length) throw new Error(format('%s: %s in vhost: %s refers to an unsupported attribute: %s', type, childName, vhostName, invalid[0]))
}
function validateExchanges(vhost, vhostName, exchanges) {
_.each(exchanges, validateExchange.bind(null, vhost, vhostName))
}
function validateExchange(vhost, vhostName, exchange, exchangeName) {
validateVhostChildAttributes(vhostName, 'Exchange', exchange, exchangeName, ['fullyQualifiedName', 'name', 'assert', 'check', 'type', 'options'])
}
function validateQueues(vhost, vhostName, queues) {
_.each(queues, validateQueue.bind(null, vhost, vhostName))
}
function validateQueue(vhost, vhostName, queue, queueName) {
validateVhostChildAttributes(vhostName, 'Queue', queue, queueName, ['fullyQualifiedName', 'name', 'assert', 'check', 'type', 'purge', 'replyTo', 'options'])
}
function validateBindings(vhost, vhostName, bindings) {
_.each(bindings, validateBinding.bind(null, vhost, vhostName))
}
function validateBinding(vhost, vhostName, binding, bindingName) {
validateVhostChildAttributes(vhostName, 'Binding', binding, bindingName, ['fullyQualifiedName', 'name', 'source', 'destination', 'destinationType', 'bindingKey', 'bindingKeys', 'qualifyBindingKeys', 'options'])
if (!binding.source) throw new Error(format('Binding: %s in vhost: %s is missing a source', bindingName, vhostName))
if (!binding.destination) throw new Error(format('Binding: %s in vhost: %s is missing a destination', bindingName, vhostName))
if (!binding.destinationType) throw new Error(format('Binding: %s in vhost: %s is missing a destination type', bindingName, vhostName))
if (['queue', 'exchange'].indexOf(binding.destinationType) < 0) throw new Error(format('Binding: %s in vhost: %s has an invalid destination type: %s', bindingName, vhostName, binding.destinationType))
if (!vhost.exchanges) throw new Error(format('Binding: %s in vhost: %s refers to an unknown exchange: %s', bindingName, vhostName, binding.source))
if (!vhost.exchanges[binding.source]) throw new Error(format('Binding: %s in vhost: %s refers to an unknown exchange: %s', bindingName, vhostName, binding.source))
if (binding.destinationType === 'queue') {
if (!vhost.queues) throw new Error(format('Binding: %s in vhost: %s refers to an unknown queue: %s', bindingName, vhostName, binding.destination))
if (!vhost.queues[binding.destination]) throw new Error(format('Binding: %s in vhost: %s refers to an unknown queue: %s', bindingName, vhostName, binding.destination))
} else {
if (!vhost.exchanges[binding.destination]) throw new Error(format('Binding: %s in vhost: %s refers to an unknown exchange: %s', bindingName, vhostName, binding.destination))
}
}
function validatePublications(publications) {
_.each(publications, validatePublication)
}
function validatePublication(publication, publicationName) {
validateAttributes('Publication', publication, publicationName, ['name', 'vhost', 'exchange', 'queue', 'routingKey', 'confirm', 'options', 'destination'])
if (!publication.vhost) throw new Error(format('Publication: %s is missing a vhost', publicationName))
if (!(publication.exchange || publication.queue)) throw new Error(format('Publication: %s is missing an exchange or a queue', publicationName))
if ((publication.exchange && publication.queue)) throw new Error(format('Publication: %s has an exchange and a queue', publicationName))
if (!config.vhosts) throw new Error(format('Publication: %s refers to an unknown vhost: %s', publicationName, publication.vhost))
if (!config.vhosts[publication.vhost]) throw new Error(format('Publication: %s refers to an unknown vhost: %s', publicationName, publication.vhost))
if (publication.exchange) {
if (!config.vhosts[publication.vhost].exchanges) throw new Error(format('Publication: %s refers to an unknown exchange: %s in vhost: %s', publicationName, publication.exchange, publication.vhost))
if (!config.vhosts[publication.vhost].exchanges[publication.exchange]) throw new Error(format('Publication: %s refers to an unknown exchange: %s in vhost: %s', publicationName, publication.exchange, publication.vhost))
} else {
if (!config.vhosts[publication.vhost].queues) throw new Error(format('Publication: %s refers to an unknown queue: %s in vhost: %s', publicationName, publication.queue, publication.vhost))
if (!config.vhosts[publication.vhost].queues[publication.queue]) throw new Error(format('Publication: %s refers to an unknown queue: %s in vhost: %s', publicationName, publication.queue, publication.vhost))
}
}
function validateSubscriptions(subscriptions) {
_.each(subscriptions, validateSubscription)
}
function validateSubscription(subscription, subscriptionName) {
validateAttributes('Subscription', subscription, subscriptionName, ['name', 'vhost', 'queue', 'contentType', 'options', 'prefetch', 'retry', 'source', 'recovery', 'workflow', 'handler', 'workflows', 'handlers'])
if (!subscription.vhost) throw new Error(format('Subscription: %s is missing a vhost', subscriptionName))
if (!subscription.queue) throw new Error(format('Subscription: %s is missing a queue', subscriptionName))
if (!config.vhosts) throw new Error(format('Subscription: %s refers to an unknown vhost: %s', subscriptionName, subscription.vhost))
if (!config.vhosts[subscription.vhost]) throw new Error(format('Subscription: %s refers to an unknown vhost: %s', subscriptionName, subscription.vhost))
if (!config.vhosts[subscription.vhost].queues) throw new Error(format('Subscription: %s refers to an unknown queue: %s in vhost: %s', subscriptionName, subscription.queue, subscription.vhost))
if (!config.vhosts[subscription.vhost].queues[subscription.queue]) throw new Error(format('Subscription: %s refers to an unknown queue: %s in vhost: %s', subscriptionName, subscription.queue, subscription.vhost))
}
function validateShovels(shovels) {
_.each(shovels, validateShovel)
}
function validateShovel(shovel, shovelName) {
validateAttributes('Shovel', shovel, shovelName, ['name', 'subscription', 'publication'])
if (!shovel.subscription) throw new Error(format('Shovel: %s is missing a subscription', shovelName))
if (!shovel.publication) throw new Error(format('Shovel: %s is missing a publication', shovelName))
if (!config.subscriptions[shovel.subscription]) throw new Error(format('Shovel: %s refers to an unknown subscription: %s', shovelName, shovel.subscription))
if (!config.publications[shovel.publication]) throw new Error(format('Shovel: %s refers to an unknown publication: %s', shovelName, shovel.publication))
}
})