Skip to content

Instantly share code, notes, and snippets.

@sadasant
Created July 16, 2014 21:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sadasant/9cd0a66b26ee5600d7df to your computer and use it in GitHub Desktop.
Save sadasant/9cd0a66b26ee5600d7df to your computer and use it in GitHub Desktop.
Simple etcd client with tests
var request = require("request");
var qstr = require("querystring").stringify;
var Args = require("args-js");
var utils = require("../utils");
var etcd = module.exports = {};
var watchers = etcd.watchers = {};
var timeout_code = "ESOCKETTIMEDOUT";
etcd.host = process.env.ETCDHOST || "127.0.0.1";
etcd.port = process.env.ETCDPORT || "4001";
etcd.protocol = "http";
etcd.getURL = function(key, params) {
for (var k in params) {
if (params[k] === undefined) delete params[k];
}
return this.protocol + "://" + this.host + ":" + this.port + "/v2/keys/" + key + (params ? "?" + qstr(params) : "");
};
etcd.watch = function() {
var args = Args([
{key: Args.STRING | Args.Required},
{done: Args.FUNCTION | Args.Required}
], arguments);
var url = etcd.getURL(args.key, {
wait: true
});
watchers[args.key] = watcher;
watcher();
function watcher() {
if (!watchers[args.key]) return;
request.get(url, function(error, res, body) {
if (error && error.code === timeout_code) return watcher();
args.done(utils.parseJSON(body));
watcher();
});
}
};
etcd.unwatch = function(key) {
watchers[key] = undefined;
};
etcd.set = function() {
var original_arguments = arguments;
var args = Args([
{key: Args.STRING | Args.Required},
[
{value: Args.STRING | Args.Required},
{value: Args.OBJECT | Args.Required},
],
{prevValue: Args.STRING | Args.Optional},
{prevExist: Args.BOOL | Args.Optional},
{done: Args.FUNCTION | Args.Optional}
], arguments);
if (typeof args.value === "object") {
args.value = JSON.stringify(args.value);
}
request.put(etcd.getURL(args.key, {
value: args.value,
prevValue: args.prevValue,
prevExist: args.prevExist
}), function(error, res, body) {
if (error && error.code === timeout_code) return etcd.set.apply(etcd, original_arguments);
if (args.done) args.done(utils.parseJSON(body));
});
};
etcd.get = function() {
var original_arguments = arguments;
var args = Args([
{key: Args.STRING | Args.Required},
{done: Args.FUNCTION | Args.Required}
], arguments);
request.get(etcd.getURL(args.key), function(error, res, body) {
if (error && error.code === timeout_code) return etcd.get.apply(etcd, original_arguments);
args.done(utils.parseJSON(body));
});
};
var etcd = require("./etcd");
var assert = require("assert");
var tests = [];
tests.push(function(done) {
console.log("\nCASE1: watch and set");
etcd.watch("hello", function(data) {
assert.equal(data.node.value, "world!");
done();
});
etcd.set("hello", "world!");
etcd.unwatch("hello");
});
tests.push(function(done) {
console.log("\nCASE2: compareAndSwap checkSwap");
// As in https://github.com/coreos/etcd/blob/master/Documentation/api.md#atomic-compare-and-swap
// Here is a simple example. Let's create a key-value pair first: `hello=one`.
etcd.set("hello", "one");
// Trying to set this existing key with prevExist=false fails as expected:
etcd.set("hello", "three", false, function(data) {
// The error code explains the problem:
assert.equal(data.errorCode, 105);
assert.equal(data.message, "Key already exists");
// Now let's provide a prevValue parameter:
etcd.set("hello", "three", "two", function(data) {
assert.equal(data.errorCode, 101);
assert.equal(data.cause, "[two != one]");
// which means CompareAndSwap failed. cause explains why the test failed. Note: the condition prevIndex=0 always passes.
// Let's try a valid condition:
etcd.set("hello", "two", "one", function(data) {
assert.equal(data.node.value, "two");
assert.equal(data.prevNode.value, "one");
done();
});
});
});
});
tests.push(function(done) {
console.log("\nCASE3: etcd.get");
// Here is a simple example. Let's create a key-value pair first: `hello=one`.
etcd.get("hello", function(data) {
// console.log(data);
assert.equal(data.node.value, "two");
done();
});
});
function callNext() {
var test = tests.shift();
if (test) {
test(function() {
console.log("DONE!");
callNext();
});
}
}
callNext();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment