Skip to content

Instantly share code, notes, and snippets.

@eveiga
Created February 26, 2013 14:57
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save eveiga/5039007 to your computer and use it in GitHub Desktop.
Save eveiga/5039007 to your computer and use it in GitHub Desktop.
#package.json
{
"name": "redis_nutcracker_agent",
"version": "0.0.1",
"description": "Redis agent for nutcracker update",
"dependencies": {
"node-sentinel": "0.0.3",
"underscore": "~1.4.4",
"async": "~0.2.5",
"nodemailer": "~0.3.42"
},
"engine": "node >= 0.8.16"
}
#config_development.js
module.exports = {
"nutcracker_config_file": "/etc/nutcracker/nutcracker.yml",
"redis_sentinel_ip": "127.0.0.1",
"redis_sentinel_port": "26379"
};
#index.js
var path = require("path"),
Agent = require(path.join(__dirname, "./lib/agent.js"));
var config = require(
path.join(__dirname, "./config_"+process.env.NODE_ENV)
);
module.exports = new Agent(config).bootstrap();
#lib/agent.js
/*jshint multistr:true */
var fs = require('fs'),
exec = require('child_process').exec,
path = require('path'),
os = require('os');
var Sentinel = require("node-sentinel"),
_ = require("underscore"),
async = require("async"),
nodemailer = require("nodemailer");
function Agent(config){
if(!_.isObject(config)){
return console.error("Bad config");
}
this.nutcracker_config_file = config.nutcracker_config_file;
this.redis_sentinel_ip = config.redis_sentinel_ip;
this.redis_sentinel_port = config.redis_sentinel_port;
this.log = "";
}
Agent.prototype.restart_nutcracker = function(callback){
var self = this;
var child = exec(
"/etc/init.d/nutcracker restart",
function(error, stdout, stderr) {
self.log += "<h2>Nutcracker restarted with outuput:</h2>";
self.log += "<div><pre>"+stdout+"</pre></div>";
if (error !== null) {
self.log += "<h2>Nutcracker failed restarting with error:</h2>";
self.log += "<div><pre>"+error+"</pre></div>";
}
return callback();
}
);
};
Agent.prototype.update_nutcracker_config = function(data, callback){
var old_content = fs.readFileSync(this.nutcracker_config_file, 'utf8');
var new_content = old_content.replace(
data.details["old-ip"]+":"+data.details["old-port"],
data.details["new-ip"]+":"+data.details["new-port"]
);
fs.writeFileSync(this.nutcracker_config_file, new_content, 'utf8');
this.log += "<h2>Nutcracker config updated with new content:</h2>";
this.log += "<div><pre>"+new_content+"</pre></div>";
return callback();
};
Agent.prototype.send_mail = function() {
var self = this;
var transport = nodemailer.createTransport("Sendmail");
var mailOptions = {
from: "from@mail.com",
to: "to@mail.com",
subject: "Warning: Nutcracker restarted forced on "+os.hostname(),
generateTextFromHTML: true,
html: "<h1>Nutcracker was restarted due to master switch in redis configuration.</h1>" + this.log
};
transport.sendMail(mailOptions, function(error, responseStatus){
self.log = "";
if(error) {
return console.error(error);
}
return console.info(
responseStatus.message+"\n"+responseStatus.messageId
);
});
};
Agent.prototype.switch_master_handler = function(){
var self = this;
return function(data) {
async.series([
function(callback) {
self.update_nutcracker_config(data, callback);
},
function(callback) {
self.restart_nutcracker(callback);
}
],
function(){
return self.send_mail();
});
};
};
Agent.prototype.start_sentinel = function(){
this.sentinel = new Sentinel(
this.redis_sentinel_ip, this.redis_sentinel_port
);
this.sentinel.on("switch-master", this.switch_master_handler());
};
Agent.prototype.check_nutcracker_config = function(cb){
fs.appendFile(this.nutcracker_config_file, "", cb);
};
Agent.prototype.bootstrap = function(){
var self = this;
this.check_nutcracker_config(
function(error){
if(error) {
return console.error("Nutcracker config file: "+error);
}
return self.start_sentinel();
}
);
};
module.exports = Agent;
@matschaffer
Copy link

btw, I've started seeing what I can do to generalize this as an npm module. Possibly even for publishing in the main npm repo. Are you okay licensing this under BSD?

@eveiga
Copy link
Author

eveiga commented Mar 1, 2013

Yes! No problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment