Home

Awesome

node-etcd

A nodejs library for ETCD v2, written in coffee-script.

Travis

npm

Install

For nodes >= 6.x:

$ npm install node-etcd

For nodes 4.x <= node < 6.x:

$ npm install node-etcd@6

For 0.10.x <= nodejs <= 4.x and iojs:

$ npm install node-etcd@5.1.0

For nodejs == 0.8:

$ npm install node-etcd@3.0.2

Changes

Basic usage

var Etcd = require('node-etcd');
var etcd = new Etcd();
etcd.set("key", "value");
etcd.get("key", console.log);

Callbacks follows the default (error, result) nodejs convention:

function callback(err, res) {
    console.log("Error: ", err);
    console.log("Return: ", res);
}
etcd.get("key", callback);
// Error: null
// Return: { action: 'get', node: { key: '/key', value: 'value', modifiedIndex: 4, createdIndex: 4 } }

Methods

Etcd(hosts = ['127.0.0.1:2379'], [options])

Create a new etcd client for a single host etcd setup

etcd = new Etcd();
etcd = new Etcd("127.0.0.1:2379");
etcd = new Etcd("http://127.0.0.1:2379");
etcd = new Etcd("https://127.0.0.1:2379");
etcd = new Etcd(["http://127.0.0.1:2379"]);

Etcd(hosts, [options])

Create a new etcd client for a clustered etcd setup. Client will connect to servers in random order. On failure it will try the next server. When all servers have failed it will callback with error. If it suspects the cluster is in leader election mode it will retry up to 3 times with exp backoff. Number of retries can be controlled by adding { maxRetries: x } as an option to requests.

etcd = new Etcd(['127.0.0.1:2379','192.168.1.1:2379']);
etcd = new Etcd(['http://127.0.0.1:2379','http://192.168.1.1:2379']);

.set(key, value = null, [options], [callback])

Set key to value, or create key/directory.

etcd.set("key");
etcd.set("key", "value");
etcd.set("key", "value", console.log);
etcd.set("key", "value", { ttl: 60 }, console.log);
etcd.set("key", "value", { maxRetries: 3 }, console.log);

Available options include:

Will create a directory when used without value (value=null): etcd.set("directory/");

.compareAndSwap(key, value, oldvalue, [options], [callback])

Convenience method for test and set (set with {prevValue: oldvalue})

etcd.compareAndSwap("key", "newvalue", "oldvalue");
etcd.compareAndSwap("key", "newValue", "oldValue", options, console.log);

Alias: .testAndSet()

.get(key, [options], [callback])

Get a key or path.

etcd.get("key", console.log);
etcd.get("key", { recursive: true }, console.log);

Available options include:

.del(key, [options], [callback])

Delete a key or path

etcd.del("key");
etcd.del("key", console.log);
etcd.del("key/", { recursive: true }, console.log);

Available options include:

Alias: .delete()

.compareAndDelete(key, oldvalue, [options], [callback])

Convenience method for test and delete (delete with {prevValue: oldvalue})

etcd.compareAndDelete("key", "oldvalue");
etcd.compareAndDelete("key", "oldValue", options, console.log);

Alias: .testAndDelete()

.mkdir(dir, [options], [callback])

Create a directory

etcd.mkdir("dir");
etcd.mkdir("dir", console.log);
etcd.mkdir("dir/", options, console.log);

.rmdir(dir, [options], [callback])

Remove a directory

etcd.rmdir("dir");
etcd.rmdir("dir", console.log);
etcd.rmdir("dir/", { recursive: true }, console.log);

Available options include:

.create(path, value, [options], [callback])

Atomically create in-order keys.

etcd.create("queue", "first")
etcd.create("queue", "next", console.log)

Alias: .post()

.watch(key, [options], [callback])

This is a convenience method for get with {wait: true}.

etcd.watch("key");
etcd.watch("key", console.log);

The watch command is pretty low level, it does not handle reconnects or timeouts (Etcd will disconnect you after 5 minutes). Use the .watcher() below if you do not wish to handle this yourself.

.watchIndex(key, index, [options], callback)

This is a convenience method for get with {wait: true, waitIndex: index}.

etcd.watchIndex("key", 7, console.log);

See .watch() above.

.watcher(key, [index], [options])

Returns an eventemitter for watching for changes on a key

watcher = etcd.watcher("key");
watcher.on("change", console.log); // Triggers on all changes
watcher.on("set", console.log);    // Triggers on specific changes (set ops)
watcher.on("delete", console.log); // Triggers on delete.
watcher2 = etcd.watcher("key", null, {recursive: true});
watcher2.on("error", console.log);

You can cancel a watcher by calling .stop().

Signals:

It will handle reconnects and timeouts for you, it will also resync (best effort) if it loses sync with Etcd (Etcd only keeps 1000 items in its event history - for high frequency setups it's possible to fall behind).

Use the .watch() command in you need more direct control.

.raw(method, key, value, options, callback)

Bypass the API and do raw queries. Method must be one of: PUT, GET, POST, PATCH, DELETE

etcd.raw("GET", "v2/stats/leader", null, {}, callback)
etcd.raw("PUT", "v2/keys/key", "value", {}, callback)

Remember to provide the full path, without any leading '/'

.machines(callback)

Returns information about etcd nodes in the cluster

etcd.machines(console.log);

.leader(callback)

Return the leader in the cluster

etcd.leader(console.log);

.leaderStats(callback)

Return statistics about cluster leader

etcd.leaderStats(console.log);

.selfStats(callback)

Return statistics about connected etcd node

etcd.selfStats(console.log);

Synchronous operations

The library supports a set of basic synchronous/blocking operations that can be useful during program startup (used like fs.readFileSync).

Synchronous functions perform the etcd request immediately (blocking) and return the following:

{
  err // Error message or null if request completed successfully
  body // Body of the message or null if error
  headers // Headers from the response
}

.setSync(key, value = null, [options])

Synchronously set key to value, or create key/directory.

etcd.setSync("key");
etcd.setSync("key", "value");
etcd.setSync("key", "value", { ttl: 60 });
etcd.setSync("key", "value", { maxRetries: 3 });

Same options and function as .set().

.getSync(key, [options])

Get a key or path.

etcd.getSync("key");
etcd.getSync("key", { recursive: true });

.delSync(key, [options])

Synchronously delete a key or path

etcd.delSync("key");
etcd.delSync("key/", { recursive: true });

The available options are the same as .del() above.

.mkdirSync(dir, [options])

Synchronously create a directory

etcd.mkdirSync("dir");
etcd.mkdirSync("dir/", options);

.rmdirSync(dir, [options])

Synchronously remove a directory

etcd.rmdirSync("dir");
etcd.rmdirSync("dir/", { recursive: true });

The available options are the same as .rmdir() above.

Aborting a request

All async requests will return a cancellation token, to abort a request, do the following:

var token = etcd.get("key", console.log);
token.abort() // also aliased as token.cancel()

console.log("Request is cancelled: ", token.isAborted());

Note that there are no guarantees that aborted write operations won't have affected server state before they were aborted. They only guarantee here is that you won't get any callbacks from the request after calling .abort().

SSL support

Provide ca, cert, key as options. Remember to use https-url.

var fs = require('fs');

var options = {
    ca:   fs.readFileSync('ca.pem'),
    cert: fs.readFileSync('cert.pem'),
    key:  fs.readFileSync('key.pem')
};

var etcdssl = new Etcd("https://localhost:2379", options);

Basic auth

Pass a hash containing username and password as auth option to use basic auth.

var auth = {
    user: "username",
    pass: "password"
};

var etcd = new Etcd("localhost:2379", { auth: auth });

Constructor options

Pass in a hash after server in the constructor to set options. Some useful constructor options include:

var etcd = new Etcd("127.0.0.1:2379", { timeout: 1000, ... });'

Debugging

Nodejs console.log/console.dir truncates output to a couple of levels - often hiding nested errors. Use util.inspect to show inner errors.

etcd.get('key', function(err, val) {
    console.log(require('util').inspect(err, true, 10));
});

//{ [Error: All servers returned error]
//  [stack]: [Getter/Setter],
//  [message]: 'All servers returned error',
//  errors:
//   [ { server: 'https://localhost:2379',
//       httperror:
//        { [Error: Hostname/IP doesn't match certificate's altnames: "Host: localhost. is not cert's CN: undefined"]
//          [stack]: [Getter/Setter],
//          [message]: 'Hostname/IP doesn\'t match certificate\'s altnames: "Host: localhost. is not cert\'s CN: undefined"',
//          reason: 'Host: localhost. is not cert\'s CN: undefined',
//          host: 'localhost.',
//          cert:
//           { subject: { C: 'USA', O: 'etcd-ca', OU: 'CA' },
//             issuer: { C: 'USA', O: 'etcd-ca', OU: 'CA' } } },
//       httpstatus: undefined,
//       httpbody: undefined,
//       response: undefined,
//       timestamp: Sun Dec 27 2015 23:05:15 GMT+0100 (CET) },
//     [length]: 1 ],
//  retries: 0 }

FAQ: