Giter Club home page Giter Club logo

node-etcd's Introduction

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 [email protected]

For nodejs == 0.8:

$ npm install [email protected]

Changes

  • 7.0.0

    • Fixing vulnerabilities
    • Drop support for nodejs version 4 &4
  • 6.0.0

    • Migrate from underscore to lodash for performance / @derektbrown
    • Updated package versions / @derektbrown
    • Update deasync call for newer node versions / @derektbrown
    • Add istanbul coverage reporting / @derektbrown
  • 5.1.0

    • Upgrade deasync dep (caused build problems on newer node) #67 / @jefflembeck
    • Upgrade request dep (security vulnerability) #71 / @esatterwhite
    • Sync functions no longer mutate input opts.
  • 5.0.3

    • Fix bug #56 (exception when calling mkdir with no options or callback)
  • 5.0.2

    • Update deasync dependency, possible fix for #47.
  • 5.0.1

    • Was forced to publish 5.0.0 as 5.0.1 because of previous beta tag.
  • 5.0.0

    • Supports basic auth, timeout, etc. See options.
    • Breaking: Constructor changes (see below)
    • Breaking: Must provide https url to use https
    • Breaking: Uses new default port 2379.
  • 4.2.1

    • Newer deasync fixes issues with iojs 3.3.0 and nodejs 4.0.0.
  • 4.1.0

    • Bumps request library version to v2.60.0, this solves an issue with HTTP proxies. HTTP_PROXY and NO_PROXY env variables should now work as expected for all requests. See issue #40
  • 4.0.2

    • 307 redirects from etcd 0.4.x clusters when using SSL didn't work properly because of a change in the underlying request library. See issue #39
  • 4.0.1

    • Minor fixes for syncronous operations, better handling of server failure.
  • 4.0.0

    • Adds support for synchronous operations (@brockwood) - See Synchronous Operations.
    • Adds support for iojs.
    • Drops support for nodejs 0.8 (use v3.x.x).
    • Upgrade dependencies.
  • 3.0.2 - Handle cluster leader election periods better (etcd will disconnect us and reject new connections until a new leader is chosen). The client will now retry 3 times with exp backoff if it believes a cluster election is in progress. Retry count is controllable via the { maxRetries: x } option for a request. (npm failed on me and I had to publish as 3.0.2)

  • 3.0.0 - Added cluster support, library now accepts a list of servers to connect to, see constructor changes below. All requests now return a cancellation token, meaning you can cancel requests by calling .cancel() or .abort(). This release might break something if you've previously depended on the leaky abstraction to the request library (request object from request library was returned on all api calls - this has been replaced by the cancellation token - the current request is still available under .req on the token if you really need it.).

  • 2.1.5 - Watcher: try to resync if etcd reports cleared index

  • 2.1.4 - Don't wait before reconnecting if Etcd server times out our watcher.

  • 2.1.3 - Etcd sends an empty response on timeout in recent versions. Parsing the empty message caused watcher to emit error. Now it reconnects instead.

  • 2.1.2 - Exponential backoff (retry), fix spinning reconnect on error. (@ptte)

  • 2.1.1 - Increase request pool.maxSockets to 100

  • 2.1.0 - Use proper error objects instead of strings for errors.

  • 2.0.10 - Fix error in documentation

  • 2.0.9 - Added .post() alias of .create(). Added .compareAndDelete() (for etcd v0.3.0)

  • 2.0.8 - Watchers can be canceled. In-order keys using #create(). Raw requests using #raw().

  • 2.0.7 - Avoid calling callback if callback not given.

  • 2.0.6 - Refactoring, fix responsehandler error.

  • 2.0.5 - Undo use of 'x-etcd-index', this refers to global state.

  • 2.0.4 - Use 'x-etcd-index' for index when watching a key.

  • 2.0.3 - Watcher supports options. Watcher emits etcd action type.

  • 2.0.2 - Mkdir and rmdir. Fix watcher for v2 api.

  • 2.0.1 - Watch, delete and stats now use new v2 api. Added testAndSet convenience method.

  • 2.0.0 - Basic support for etcd protocol v2. set, get, del now supports options.

  • 0.6.1 - Fixes issue #10, missing response caused error when server connection failed / server responded incorrectly.

  • 0.6.0 - Watcher now emits 'error' on invalid responses.

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:

  • ttl (time to live in seconds)
  • prevValue (previous value, for compare and swap)
  • prevExist (existance test, for compare and swap)
  • prevIndex (previous index, for compare and swap)

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:

  • recursive (bool, list all values in directory recursively)
  • wait (bool, wait for changes to key)
  • waitIndex (wait for changes after given index)

.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:

  • recursive (bool, delete recursively)

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:

  • recursive (bool, delete recursively)

.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:

  • change - emitted on value change
  • reconnect - emitted on reconnect
  • error - emitted on invalid content
  • <etcd action> - the etcd action that triggered the watcher (ex: set, delete).
  • stop - watcher was canceled.
  • resync - watcher lost sync (server cleared and outdated the index).

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:

  • timeout - Integer request timeout in milliseconds to wait for server response.
  • ca - Ca certificate
  • cert - Client certificate
  • key - Client key
  • passphrase - Client key passphrase
  • auth - A hash containing {user: "username", pass: "password"} for basic auth.
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:

  • Are there any order of execution guarantees when doing multiple requests without using callbacks?
    • No, order of execution is up to NodeJS and the network. Requests run from a connection pool, meaning that if one request is delayed for some reason they'll arrive at the server out of order. Use callbacks (and maybe even a nice async callback handling library for convenient syntax) if ordering is important to prevent race conditions.

node-etcd's People

Contributors

dependabot[bot] avatar derektbrown avatar dpb587 avatar esatterwhite avatar jefflembeck avatar jonmorehouse avatar mbiermann avatar mren avatar ptte avatar pvomhoff avatar smurthas avatar stianeikeland avatar trystanj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-etcd's Issues

Set crashes when master election is in progress.

Thanks for introducing the cluster support in node-etcd! There is just one issue.

I have a small test using an etcd cluster with 4 nodes and node-etcd 3.0 with the new cluster support. There is one node process setting random keys at a rate of 50Hz in a given directory. Then there is a separate process creating a watcher on that directory. This setup works as expected. The producer is writing random keys and the consumer is receiving all the random keys, even when I kill non-leader etcd processes. But as soon as I kill the current cluster leader, the next set will fail and crash the producer process.

{ [Error: All servers returned error]
  errors:
   [ { server: '127.0.0.1:4003',
       httperror: [Object],
       response: undefined },
     { server: '127.0.0.1:4002',
       httperror: [Object],
       response: undefined },
     { server: '127.0.0.1:4001',
       httperror: [Object],
       response: undefined },
     { server: '127.0.0.1:4004',
       httperror: [Object],
       response: undefined } ] }

Error: All servers returned error
    at Client._multiserverHelper (.../etcd-test/node_modules/node-etcd/lib/client.js:99:15)
    at Client._multiserverHelper (.../etcd-test/node_modules/node-etcd/lib/client.js:3:59)
    at Request._callback (.../etcd-test/node_modules/node-etcd/lib/client.js:110:22)
    at self.callback (.../etcd-test/node_modules/node-etcd/node_modules/request/request.js:237:22)
    at Request.emit (events.js:95:17)
    at ClientRequest.self.clientErrorHandler (.../etcd-test/node_modules/node-etcd/node_modules/request/request.js:342:10)
    at ClientRequest.emit (events.js:95:17)
    at Socket.socketErrorListener (http.js:1551:9)
    at Socket.emit (events.js:95:17)
    at net.js:440:14

The consumer is not receiving anything, but does not crash and will continue receiving values when the producer is restarted again.

Is it possible for node-etcd to detect that an election is in progress and delay or retry the set when the new leader is a elected?

build fail

npm WARN optional Skipping failed optional dependency /chokidar/fsevents:
npm WARN notsup Not compatible with your operating system or architecture: [email protected]
npm WARN [email protected] requires a peer of react@^15.3.2 but none was installed.
npm ERR! Linux 3.10.0-327.36.1.el7.x86_64
npm ERR! argv "/workstation/bin/node/node-v6.6.0-linux-x64/bin/node" "/workstation/bin/no" "i"
npm ERR! node v6.6.0
npm ERR! npm v3.10.3
npm ERR! code ELIFECYCLE

npm ERR! [email protected] install: node ./build.js
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] install script 'node ./build.js'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the deasync package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! node ./build.js
npm ERR! You can get information on how to open an issue for this project with:
npm ERR! npm bugs deasync
npm ERR! Or if that isn't available, you can get their info via:
npm ERR! npm owner ls deasync
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:

@node-etcd

cannot connect correctly with etcd on localhost

my etcd instance is running locally and I can perform get and set using the cli

// set
etcdctl set /services/myservice "{\"hostname\": \"127.0.0.1\", \"port\": 3000}"

//get 
etcdctl get services/myservice 
// results in -> {"hostname": "127.0.0.1", "port": 3000}

but when I use your module

var Etcd = require('node-etcd');
var etcd = new Etcd(['http://localhost:2379', 'http://localhost:4001']);
etc.get('services/myservice', { wait: true}, function (err, value){
    console.log(err, value);
});

Can you explain why my value is HTML (see below)
I also find that when I don't include hosts and just use new Etcd() I get an internal HTML page with references to proxy issues: "The requested website is blocked by [insert company name] Proxy due to potential malicious activity or other security reasons."

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" data-adblockkey="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKrfIMFkSaoTSqKmC+BrghK0CpDHc0MuVzmMHin8LIORhpXbped+iYhSnZurWnEO0zcKcVIrzp026LVc5pMB9bUCAwEAAQ==_mHzvOc3GBNo9sxVki+5Fe+E9GsbiT2+mBIEtU+yAIW6jw6Uds6VUD5RSkqMfuUSrcw4AYCrFOWaaWSRGDzU8pw==">

<head>
    <script type="text/javascript">
        var abp;
    </script>
    <script type="text/javascript" src="http://www.http.com/px.js?ch=1"></script>
    <script type="text/javascript" src="http://www.http.com/px.js?ch=2"></script>
    <script type="text/javascript">
        function handleABPDetect() {
            try {
                var imglog = document.createElement("img");
                imglog.src = "http://www.http.com/rg-logabpstatus.php?a=WVpqOEdZZldDTWo4VWF0M0pNa1pBek0xQnE1WVlqR2VaQ0Frd0V4TUxmcDAvOFN2WnhHYS8weFFEeTZTRHlleTM0UFk3UDhzemxqSWFRdXlFdXpIUGc9PQ==&b=" + abp;
                document.body.appendChild(imglog);
            } catch (err) {}
        }
        try {
            window.onload = handleABPDetect();
        } catch (err) {}
    </script>
    <title>http.com</title>
    <meta http-equiv="Content-Type" content="text/html; charset=">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable = no">
    <style type="text/css">
        * {
            margin: 0;
            padding: 0
        }

        a {
            text-decoration: none;
            outline: none
        }

        a:hover {
            text-indent: 0;
            cursor: pointer
        }

        .clearfix:after {
            visibility: hidden;
            display: block;
            font-size: 0;
            content: " ";
            clear: both;
            height: 0
        }

        * html .clearfix {
            zoom: 1
        }

        *:first-child+html .clearfix {
            zoom: 1
        }

        body {
            font-family: Arial, Helvetica, sans-serif;
            background: url(http://c.rmgserving.com/rmgpsc/7867/body-bg.gif) 0 0 repeat #000
        }
        /*.arrows{background:url(http://b.rmgserving.com/rmgpsc/7867/arrows.jpg)}*/

        #main-wrap {
            background: url(http://a.rmgserving.com/rmgpsc/7867/header-bg.jpg) top center no-repeat;
            background-size: 100% 100px
        }

        .container {
            width: 960px;
            margin: 0 auto
        }

        .header {
            height: 100px
        }
        /*commented for new design */
        /*.leftblk{float:left; overflow:hidden}
.leftblk img{float: left; margin-top: 23px; padding-right: 15px;}*/
        /*.domain_name{float:left; line-height:100px; font-size:26px; font-weight:normal; color:#fff}*/

        .searchbox {
            float: right;
            width: 410px;
            * width: 420px;
            _width: 420px;
            height: 28px !important;
            padding-top: 2px;
            margin-top: 35px;
            /*padding-left:33px;background:url(http://d.rmgserving.com/rmgpsc/7868/srch-bg-caf2.gif) 0 0 no-repeat*/
        }

        .content {
            padding-bottom: 10px;
            background: #202020
        }
        /**RESPOSIVE CHANGES MADE HERE**/

        .domain_name {
            line-height: normal;
            font-size: 26px;
            font-weight: normal;
            color: #fff;
            margin-top: 35px
        }

        .leftblk {
            float: left;
            width: 39%;
            word-wrap: break-word;
            background: url(http://c.rmgserving.com/rmgpsc/7867/logo1.png) no-repeat center left;
            padding-left: 70px;
            height: 100px;
            overflow: hidden;
        }

        .frt_arr {
            float: left;
            width: 30%;
            height: 425px;
            background: url(http://d.rmgserving.com/rmgpsc/7983/frst_arr.jpg);
            background-position: 10px 70px;
            background-repeat: no-repeat;
            background-size: 90%
        }

        .lst_arr {
            float: left;
            width: 30%;
            height: 425px;
            background: url(http://b.rmgserving.com/rmgpsc/7983/last_arr.jpg);
            background-position: 0px 70px;
            background-repeat: no-repeat;
            background-size: 90%
        }

        .kwd_bloack {
            float: left;
            width: 40%;
            margin-top: 74px
        }
        /**RESPOSIVE CHANGES END HERE**/

        .bottom_bg {
            height: 44px;
            /*background:#181818; */
            margin-top: 34px
        }

        .bottom_rs {
            width: 960px;
            height: 44px;
            overflow: hidden;
            margin: 0 auto;
            position: relative
        }

        #bot_rs {
            padding-top: 9px
        }

        .separator {
            position: absolute;
            top: 0;
            left: 156px;
            width: 5px;
            height: 44px;
            border-left: 2px solid #282828;
            background: url(http://a.rmgserving.com/rmgpsc/7867/sep-arw.gif) center center no-repeat
        }

        .footer-nav {
            width: 100%;
            height: 74px;
            text-align: center;
            color: #c0c0c0;
        }

        .footer-nav a {
            font-size: 12px;
            line-height: 74px;
            color: #c0c0c0;
            padding: 0 5px;
            text-decoration: underline
        }

        .footer-nav a:hover {
            text-decoration: none
        }

        .inquire {
            text-align: right;
            padding-top: 10px;
            color: #fff
        }

        .inquire a {
            font-size: 12px;
            font-weight: normal;
            color: #fff
        }

        .sale-msg {
            background: #fff;
            color: #4b4b4b;
            text-align: center;
            font-size: 14px;
            width: 100%;
            top: 0;
            left: 0
        }

        .sale-msg a {
            text-decoration: none;
            color: #079ce9;
            font-size: 14px;
        }

        .sale-msg a:hover,
        .bottom_rs ul li a:hover,
        .mid_rs ul li a:hover,
        .inquire a:hover {
            text-decoration: underline
        }

        @media not all and (min-width: 970px) {
            .container {
                width: 95%
            }
            .bottom_bg {
                display: none
            }
            .footer-nav a {
                line-height: 45px
            }
        }

        @media not all and (min-width: 840px) {
            .frt_arr {
                display: none
            }
            .lst_arr {
                display: none
            }
            .kwd_bloack {
                float: none;
                width: 95%;
                margin: 0 auto;
                padding-top: 10px
            }
            .leftblk {
                float: none;
                height: 50px;
                background-size: 35px;
                padding-left: 50px;
                width: auto
            }
            .domain_name {
                line-height: normal;
                font-size: 20px;
                margin-top: 0;
                padding-top: 15px
            }
            .searchbox {
                float: none;
                margin-top: 10px;
                padding-top: 0;
                width: auto;
            }
        }
    </style>
    <script type="text/javascript" src="http://www.google.com/adsense/domains/caf.js"></script>
</head>

<body onload="" onunload="" onBeforeUnload="">
    <noscript>
        <meta http-equiv="refresh" content="0;url=http://www.http.com/rg-erdr.php?_rpo=t ntZzFFI&_rdm=9f1NJXf43BJvmfNf4.JvV&p=J1c4gcvmfN9ffFGoFgXoYVa%7C%40%7CbzGzTE%2C5f95zbT%2C5f95Et%7C%40%7CX55g.JvV%7C%40%7C%7C%40%7C%7C%40%7CZzbHzEZHE%7C%40%7CzHZZFTH%7C%40%7CK-%7C%40%7C19c4NW4cGFHzTEtTEGZGzTbT%7C%40%7Ct+nh8llbj%7C%40%7Ct+7zFZKFH&ga=5rKI1sSSBwFmmNY4RDXg%2BB7VS0yzNgnQ9JpHpsLHSsvFu0NyshpFxWu0exObFAo5IdFZQrTZujcZjrXONxp3PxtPV7ezER14zh7kWG69e5lf08niAgSfUKiyBSByBIQgw92X314XjQy5h09a65wi7JIhzrLV0PReUb%2F7SMvquCNLeg70qvVfr7kkYTx9Z4NO&t=gnojs" />
        <center>
            <p style="padding:1em; font-size:1.5em;">For search results please <a href="http://www.http.com/rg-erdr.php?_rpo=t ntZzFFI&_rdm=9f1NJXf43BJvmfNf4.JvV&p=J1c4gcvmfN9ffFGoFgXoYVa%7C%40%7CbzGzTE%2C5f95zbT%2C5f95Et%7C%40%7CX55g.JvV%7C%40%7C%7C%40%7C%7C%40%7CZzbHzEZHE%7C%40%7CzHZZFTH%7C%40%7CK-%7C%40%7C19c4NW4cGFHzTEtTEGZGzTbT%7C%40%7Ct+nh8llbj%7C%40%7Ct+7zFZKFH&ga=5rKI1sSSBwFmmNY4RDXg%2BB7VS0yzNgnQ9JpHpsLHSsvFu0NyshpFxWu0exObFAo5IdFZQrTZujcZjrXONxp3PxtPV7ezER14zh7kWG69e5lf08niAgSfUKiyBSByBIQgw92X314XjQy5h09a65wi7JIhzrLV0PReUb%2F7SMvquCNLeg70qvVfr7kkYTx9Z4NO&t=gnojs" style="text-decoration:underline; color:#0000EE;">CLICK HERE</a>.</p>
        </center>
    </noscript>
    <script type="text/javascript" language="javascript">
        function __gpup(url, height, width, name) {
            sw = window.open(url, name, 'height=' + height + ',width=' + width + ',location=no,toolbar=0,resizable=1,scrollbars=1');
            if (window.focus) {
                sw.focus()
            };
            return false;
        };
    </script>
    <script text="text/javascript">
        var design = {
            'pageOptions': {
                'pubId': '',
                'resultsPageBaseUrl': '',
                'fontFamily': 'arial',
                'hl': 'en',
                'maxTermLength': 29,
                'adtest': 'on',
                'clicktrackUrl': '',
                'fontFamilyAttribution': 'arial',
                'type': 'pageoptions',
                'pageLoadedCallback': function(requestAccepted, status) {
                    document.body.style.visibility = 'visible';
                    if (!requestAccepted) {}
                }
            },
            'searchboxBlock': {
                'container': 'searchbox',
                'type': 'searchbox',
                'fontSizeSearchInput': 16,
                'fontSizeSearchButton': 13,
                'widthSearchInput': 215,
                'colorSearchButton': '#e2e2e2',
                'hideSearchInputBorder': false,
                'hideSearchButtonBorder': false
            },

            'mainrs': {
                'container': 'main_rs',
                'type': 'relatedsearch',
                'colorBackground': 'transparent',
                'number': 6,
                'fontSizeTitle': 19,
                'titleBold': true,
                'colorTitleLink': '#079ce9',
                'noTitleUnderline': false,
                'lineHeightTitle': 30,
                'fontFamily': 'arial',
                'horizontalAlignment': 'center',
                'fontSizeAttribution': 13,
                'colorAttribution': '#ababab',
                'attributionBold': true,
                'attributionUppercase': false,
                'attributionSpacingBelow': 36,
                'rolloverLinkUnderline': false,
                'rolloverLinkColor': '#00c800',
                'colorAdSeparator': '#202020'
            }
        };
    </script>
    <div id="main-wrap" class="clearfix">
        <div class="container clearfix">
            <div class="header clearfix">
                <div class="leftblk">
                    <!-- <img src="http://c.rmgserving.com/rmgpsc/7867/logo1.png" /> -->
                    <h3 class="domain_name">http.com</h3>
                </div>
                <div class="searchbox clearfix" id="searchbox"></div>
            </div>
            <div class="content clearfix">
                <div class="arrows frt_arr"></div>
                <div class="kwd_bloack clearfix" id="main_rs"></div>
                <div class="arrows lst_arr"></div>
            </div>
        </div>
        <div class="bottom_bg clearfix">
            <div class="bottom_rs clearfix">
                <!--<span class="separator"></span>-->

            </div>
        </div>
        <div class="footer-nav">
            <a href="#" onclick="return __gpup('http://www.http.com/rmgdsc/rprivacypolicy.php',600,800,'rpp');">Privacy Policy</a> </div>
    </div>
    <script type="text/javascript" language="javascript">
        window._debug = false;
        window._dumpdata = false;
        var _cflp = true;
        var pgld = true;
        var totRS = -1;
        var cntRS = 0;
        var _cfstc = false;
        var _cfblocker = true;
        var _cfrg = true;
        var _cfHelp = _cfHelp || {};
        _cfHelp.design = design || {};
        _cfHelp.servVars = {
            "webadfl": "webads.php",
            "_clhdl": "http:\/\/www.http.com\/rg-cltrack.php?&gr=%5B%7Crdr_url%7C%5D&gm=1WHI0lwrG0Sxkx4PsD8qyCOUd1dkaI2X1l8SGG1fMSd7bfeWMBF%2FyegsqR%2BZliS%2FkmMLg273bT8VsQ1oofKDtwu2BLulOOE9e9f%2FGbKVB3y9mwzTRLUiokCVqtb5Zk84C2EVcNaF2G3r9Bp3RsH1xfXrZC%2BE8YGoveyKL4ONQKcLbTlODzh%2BgHyFxmaFdMqH&gc=11101851242258318844884&gi=XYb9MaQozttVcq86LfylD8RNPuvlew8QArHjQzucy26g%2BlAY%2F2uHYh%2BA6ff50kcc1PxTBiLUWCU4jHCv3wduaWHfl%2Fk8mkRKtWu8EB0jglLzw7eeSqi3ynxhbG7655Fy%2FLKMke6nBiTt%2FuiCvqlrvF1W%2F0MGzePy07JWvEsPuPqNBujvQaw3gGby3VkjIxfm2atlkRoPbyOyKYholPIgVyyBcIBJQvM3kSCiRXOyaMpxjTprto%2B0LbFQmRT0%2Bv05GchdCqw0KwcBJr1GshmWISk5vXG28qmhuRBFtwmFZTdpEHObgOZuOhjtcRKzp6QcLHJxeH43ucmzlzBBC8rUhA%3D%3D",
            "kchst": "http:\/\/www.http.com\/",
            "kcpg": "render",
            "kcprm": "ga=5rKI1sSSBwFmmNY4RDXg%2BB7VS0yzNgnQ9JpHpsLHSsvFu0NyshpFxWu0exObFAo5IdFZQrTZujcZjrXONxp3PxtPV7ezER14zh7kWG69e5lf08niAgSfUKiyBSByBIQgw92X314XjQy5h09a65wi7JIhzrLV0PReUb%2F7SMvquCNLeg70qvVfr7kkYTx9Z4NO&gqsg=4OVo54jg6Fc8v4dgaRWvLlUoQfiT9l0g4KypdpyKIkp3XttitvahDJPyd8JV8AMP&maxads=0&gerf=NIVtBZ66fMb06L%2FzgSYcSUpDtBcVFLddp21rUKg8Zvs%3D&wait=true",
            "jtchdl": "0",
            "lkwtkn": null,
            "qry": null,
            "cntry": "IE",
            "prvid": 1566375,
            "lgky": "VFJIcUJEQUZtMGQ3dVY0amZaMmFIVi8vL2g2WUVmRkQxNVp6eEJRcSs1WFl3K3cvZFFISS9aN1Y4NE1KamNIUi95TW04Q3p6ek9RejR1N1pRemlJS1hORjIzNEF2Z3d3TGkyUGhGNkJxREdyRDJLNzZoWVMraXd0cFZGK1hiWTY5aGNYRTlmOHlDa3E5bmpLTHRtelJ3PT0%3D",
            "_aftrprss": "",
            "wclhdl": "http:\/\/www.http.com\/webclk?&gr=%5B%7Crdr_url%7C%5D&gm=N3DjGjxerDa%2B8Ln3%2B884CDaIWdGzXLcE6PGovrvm8cwEqFKj9%2FsSAw13RemOENdu59z53RIAX7qKedB%2BbC7k6lI6gFbOxQR7qkhujpZqsJMhUo0JnsgwBv6eY8R4QxT34RDgzTHG7pSdzqCdYGLMkjkrWeoByyf1I3drNmqLJoXF8CRTdNMoZwb5HxP8G2KL&gc=11101851242258318844501&gi=3asGzSvNXUezIegH6SkVMB9oHMTe%2BRtyB0XjQzqrg%2BegxXIIXBBR%2FNpmg%2FEpOC3SbbpbaUmlcSRdngRk3viiaUqqjkydC5SRcNAQIHAVCSz4CcvOsJgD4kJKepiaVN2MkCXSlbZfRbnV4Lj3QWLNCEpoUpJaD8GoKU2ZiKd%2B2wDKToaj236za8yEZZnAejv7CqvZi7bAnoT7LFHAT4YfVQYDvpwbpObRothY86AABfVVWr%2BDuudu2Z1HgnO7kRUJx945jHKd%2BHgj7szCxsb6xBb7wBlUblacTda5uwQKPLtiF5n7ChXCCJTf%2BYsC%2FDDegcmi71Z8FBC6SLSZ%2FYvsJQ%3D%3D",
            "is_webad_enabled": 0,
            "loaderimage": "http:\/\/c.rmgserving.com\/rmgisc\/loader.gif",
            "_afdad": 1,
            "noredir": 0,
            "erpub": "oversee11_3ph_adult_xml",
            "erch": "372",
            "erpubcln": "ca-dp-oversee11_3ph_xml",
            "erchcln": "000307",
            "ghu": "http:\/\/www.http.com\/rg-erdr.php?_rpo=t ntZzFFI&_rdm=9f1NJXf43BJvmfNf4.JvV&p=J1c4gcvmfN9ffFGoFgXoYVa%7C%40%7CbzGzTE%2C5f95zbT%2C5f95Et%7C%40%7CX55g.JvV%7C%40%7C%7C%40%7C%7C%40%7CZzbHzEZHE%7C%40%7CzHZZFTH%7C%40%7CK-%7C%40%7C19c4NW4cGFHzTEtTEGZGzTbT%7C%40%7Ct+nh8llbj%7C%40%7Ct+7zFZKFH&ga=5rKI1sSSBwFmmNY4RDXg%2BB7VS0yzNgnQ9JpHpsLHSsvFu0NyshpFxWu0exObFAo5IdFZQrTZujcZjrXONxp3PxtPV7ezER14zh7kWG69e5lf08niAgSfUKiyBSByBIQgw92X314XjQy5h09a65wi7JIhzrLV0PReUb%2F7SMvquCNLeg70qvVfr7kkYTx9Z4NO"
        };
        _cfHelp.newOpts = {
            "pageoptions": {
                "kw": "http",
                "pubId": "dp-oversee32_3ph_xml",
                "channel": "012174,test107,test49",
                "hl": "",
                "adtest": "off",
                "resultsPageBaseUrl": "http:\/\/www.http.com\/?ga=5rKI1sSSBwFmmNY4RDXg%2BB7VS0yzNgnQ9JpHpsLHSsvFu0NyshpFxWu0exObFAo5IdFZQrTZujcZjrXONxp3PxtPV7ezER14zh7kWG69e5lf08niAgSfUKiyBSByBIQgw92X314XjQy5h09a65wi7JIhzrLV0PReUb%2F7SMvquCNLeg70qvVfr7kkYTx9Z4NO&gqsg=4OVo54jg6Fc8v4dgaRWvLlUoQfiT9l0g4KypdpyKIkp3XttitvahDJPyd8JV8AMP&maxads=0&gerf=1NwSv6zgpkznlToCcC1LUPxAge73x0kzNUyoFwPpLQw%3D&wait=true",
                "clicktrackUrl": "http:\/\/www.http.com\/rg-cltrack.php?&gr=http%3A%2F%2Fgoogle.com%2F%3FRMGcaf%261437578625&gm=lCHzRGQVmF5GbI%2FoJNvHO9F0H1pK6b4imVg4sD83gr0zwhCg7kUY7A5JisFIua0ovWZYB4g4CbZlK6DDWhXlYS%2FoGwafEe2w6vLAAhtarOqSrags%2FXIb7w%2BHM0BEJgeyKmMXhVQya9xYRoVUupKo7SfWKOP26QW4BeaSRA7pvaleohDknqEJ8irgK41FOPBr&gc=11101851242258318844252&gi=dqJeJ2LIBm6EoVjrQxF%2FslKeVO2MMfAIGz5LwKTbfKTDn9L7haFS7W3vKNwbjSGhC5JthqkexETQM8mEun%2F4M5TCzM0Vphb237zGYUpoBtB1%2BdaJoSRcYUFKnr9lF6i32soKngUvevO7DHx9BHSz7sCMXYPLkJicrRb7WxfYNRWz0plNCCbrW8HYaPbhclR9gVbhSwIUdzpMjwGFrNyh%2B9iqRYF%2BX0wFzLunKbgTnLdmXJuP0Vm%2BjkU%2BC4rprcocV7pcHhlR0%2FKP2vHSKAlWTPcuCA9P04LbPqttMcdlol%2Fpm%2BAeIg79dx%2Bb28yVLKBEpMifhq6%2BT%2B2LndQdLFX%2FCoMvHjee%2BMfVwkRgY8%2F9hqFI%2B9UvBLgcgjCtTYSruCn7",
                "domainRegistrant": "as-drid-2351749742621707",
                "optimizeTerms": false,
                "terms": "[\"Domain Registration\",\"Network Monitoring\",\"Email Hosting\",\"Website Hosting\",\"Network Monitoring Software\",\"High Speed internet\",\"Cable Internet\",\"Broadband Internet\",\"Web Security\",\"Dial-Up Internet\",\"Wireless Internet Providers\",\"Unlimited Broadband\",\"Internet Speed Check\",\"Compare Broadband\",\"Cheap Internet Service\",\"Best Broadband Deals\",\"Internet Solutions\",\"Internet Music\",\"Internet Help\",\"Internet Telephony\",\"Business Internet Providers\",\"Broadband Availability\",\"Prepaid Wireless Internet\",\"Internet Florists\",\"Mobile Wireless Internet\"]",
                "uiOptimize": false,
                "domainName": "http.com"
            },
            "relatedsearch": {
                "adLoadedCallback": function(cnm, ld) {
                    if (pgld && !ld && _cfrg && !_cfstc && _cflp) {
                        cntRS++;
                        if (cntRS >= totRS && totRS != -1) {
                            window.location = "http://www.http.com/?_stc_=1"
                        }
                    }
                }
            },
            "textads": {
                "adLoadedCallback": function(cnm, ld) {}
            },
            "imagead": {
                "adLoadedCallback": function(cnm, ld) {}
            },
            "ads": {
                "adLoadedCallback": function(cnm, ld) {}
            }
        };
        _cfHelp.newOpts.pageoptions["pageLoadedCallback"] = function(requestAccepted, status) {
            this.onPageLoad(requestAccepted, status);
            _cfblocker = false
        };
        try {
            if (abp) {
                _cfHelp.newOpts.pageoptions['channel'] = _cfHelp.newOpts.pageoptions['channel'] + ',test101'
            }
        } catch (e) {}
    </script>
    <script type="text/javascript" src="http://a.rmgserving.com/rmgdsc/newcafv2.js?1.1"></script>
</body>
</html>

NSP vulnerabilities 309

If using node-etcd with version 5.0.3 the following vulnerabilities are exposed according to NSP:

    (+) 1 vulnerabilities found
┌───────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│               │ Remote Memory Exposure                                                                                                                            │
├───────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Name          │ request                                                                                                                                           │
├───────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Installed     │ 2.60.0                                                                                                                                            │
├───────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Vulnerable    │ >=2.2.6 <2.47.0 || >2.51.0 <=2.67.0                                                                                                               │
├───────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Patched       │ >=2.68.0                                                                                                                                          │
├───────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Path          │ @dsx/[email protected] > [email protected] > [email protected]                                                                                     │
├───────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ More Info     │ https://nodesecurity.io/advisories/309                                                                                                            │
└───────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘


[BUG] Cannot Set Property Dir of Undefined

I have the following line in my code:
etcd.mkdir(etcd_dir);

if I execute it, I receive the following error:

    options.dir = true;
                ^

TypeError: Cannot set property 'dir' of undefined
    at Etcd.mkdir (/home/dbrown/projects/LearnLinux/redbird/node_modules/node-etcd/lib/index.js:104:17)
    at /home/dbrown/projects/LearnLinux/redbird/lib/etcd-backend.js:26:12
    at Client._handleResponse (/home/dbrown/projects/LearnLinux/redbird/node_modules/node-etcd/lib/client.js:221:14)
    at Request._callback (/home/dbrown/projects/LearnLinux/redbird/node_modules/node-etcd/lib/client.js:136:22)
    at Request.self.callback (/home/dbrown/projects/LearnLinux/redbird/node_modules/request/request.js:198:22)
    at emitTwo (events.js:106:13)
    at Request.emit (events.js:191:7)
    at Request.<anonymous> (/home/dbrown/projects/LearnLinux/redbird/node_modules/request/request.js:1057:14)
    at emitOne (events.js:101:20)
    at Request.emit (events.js:188:7)
    at IncomingMessage.<anonymous> (/home/dbrown/projects/LearnLinux/redbird/node_modules/request/request.js:1003:12)
    at emitNone (events.js:91:20)
    at IncomingMessage.emit (events.js:185:7)
    at endReadableNT (_stream_readable.js:926:12)
    at _combinedTickCallback (internal/process/next_tick.js:74:11)
    at process._tickCallback (internal/process/next_tick.js:98:9)```

However, if I change the line to etcd.mkdir(etcd_dir,{});, I get no errors at all. Looks like the parameter needs to default to an empty object.

Passing options for request library instead of default values

Would it be possible to allow passing options for request library that would overwrite the defaultRequestOptions if specified. We would like to request an ability to pass desired options to request lib instead of using the defaultRequestOptions. Thank you.

what is the structure of the callback?

Hi,

Just put my hands on node-etcd library, and have couple of questions.

When I do the next:

etcd.get('key', (data, second) => {
    console.log(`data ${data}, second: ${JSON.stringify(second)}`);
});

I receive the next:
image

Why the 1st param is null? Where can I read about the callback format?
Where can I read about the actual data format? Currently, to get value I need to do second.node.value, is there a shortcut for the value?

Regards,

getSync with invalid keys

Heya!

I'm writing unit tests with lab and when I pass invalid keys to my function that uses the getSync function, lib doesn't return an error saying that it doesn't exist, neither dies. Any idea?

.machines() not working - bad URL

Using node-etcd "4.2.1" and etcd "2.2.3":

etcd.machines(console.log);

{ [Error: Key not found]
  errorCode: 100,
  error:
   { errorCode: 100,
     message: 'Key not found',
     cause: '/_etcd',
     index: 14 } } '' { 'content-type': 'application/json',
  'x-etcd-cluster-id': 'xxx',
  'x-etcd-index': '14',
  date: 'Tue, 12 Jan 2016 14:54:07 GMT',
  'content-length': '72' }

After changing the URL to "machines" instead of "keys/_etcd/machines" it's working - although I don't know whether the response format still is the same. Judging from this: etcd-io/etcd#1279 it changed around etcd v0.5.0.

Thanks for looking into it.

SSL broken

client.js uses the request module which has its own SSL support

Setting up an HttpAgent dont work (anymore)

Probably it should:

    if @sslopts?
      serverprotocol = "https"

    opt = {
      path: "#{apiVersion}/#{path}"
      serverprotocol: serverprotocol
      json: true
      agentOptions: #{sslopts}
      qs: queryString
      clientOptions: clientOptions
      synchronous: allOpts.synchronous
      form: { value: value } if value?
    }

sorry for not creating a pull-request but coffee is something to dring ;)

Multiple Watchers on different keys from same etcd client

Has anyone noticed issues where you have one etcd client and choose to create multiple watchers on that client?

When I do this, the watchers don't update correctly and when calling stop() on them, they make the node process hang.

Here's some background as to what I'm working on. The loadKeys methods grabs each value, sets it on a global object. It should set up a unique watcher for each value as well. I had to create a new instance in the setWatcher method to prevent weird clashing / buggy behavior when keys are updated.

https://github.com/jonmorehouse/node-config/blob/master/lib/etcd.coffee

Increase max http sockets

The request instance in node-etcd uses the default http agent, thus we are limited to 5 concurrent requests for a single etcd instance, which is rather low. I think it would be safe to set a high value using request pool.maxSockets option.

Better error handling when client is not able to reach the server.

TypeError: Cannot read property 'statusCode' of undefined
  at Request._callback (/private/tmp/kake/node_modules/node-etcd/lib/index.js:165:15)
  at self.callback (/private/tmp/kake/node_modules/node-etcd/node_modules/request/request.js:129:22)
  at Request.EventEmitter.emit (events.js:95:17)
  at ClientRequest.self.clientErrorHandler (/private/tmp/kake/node_modules/node-etcd/node_modules/request/request.js:239:10)
  at ClientRequest.EventEmitter.emit (events.js:95:17)
  at Socket.socketErrorListener (http.js:1547:9)
  at Socket.EventEmitter.emit (events.js:95:17)
  at net.js:441:14
  at process._tickCallback (node.js:415:13)

Published version on NPM does not include compiled JS files

Your prebuild step is supposed to compile your src/*.coffee files into lib/, but I don't think that happened for the version of this package that is currently published on NPM. I added node-etcd to my project's package.json, did a npm install, and then looked at node_modules/node-etcd. The lib/ directory was missing. I'm not familiar with publishing packages on NPM, but I think you can fix this with a republish.

TTL refresh etcd 2.3.x+ broken

If you want to refresh a TTL on 2.3.x+, you cannot send a key with the SET operation. There doesn't appear to be a way to do that with this lib

how to check if etcd is connected or we put some trash servers as hosts

Hi,

When I execute the code like this:

'use strict';

const Etcd = require('node-etcd');
const etcd = new Etcd(['yandex.ru:4001']);


etcd.set('key','value', (err, data) => {
        console.log('err', err);
        console.log('data', data);
});

It will just starts and waits for a long time. Then I see the error:

{ [Error: All servers returned error]
  errors:
   [ { server: 'yandex.ru:4001',
       httperror: [Object],
       httpstatus: undefined,
       httpbody: undefined,
       response: undefined,
       timestamp: Sun Dec 20 2015 21:23:07 GMT+0100 (CET) } ],
  retries: 0 }

From my point of view, it takes too long to identify that hosts are not okay.
Is there a way to synchronously check if something is wrong or not? Where it's possible to setup the error timeout?

Regards,

Uncaught Error!!! Error: Received unexpected response :

Getting this exception (crashing my node process) intermittently while connecting to etcd. I have 2 watchers connected to etcd server. Using node 0.10.29 and etcd 0.4.4 on macosx. I've pasted the contents of 'response' below.

error: Uncaught Error!!! Error: Received unexpected response :
at Watcher._respHandler (/Users/tomhowe/github/CC/cc-config/node_modules/node-etcd/lib/watcher.js:60:15)
at /Users/tomhowe/github/CC/cc-config/node_modules/node-etcd/lib/watcher.js:3:59
at Client._handleResponse (/Users/tomhowe/github/CC/cc-config/node_modules/node-etcd/lib/client.js:85:14)
at Request._callback (/Users/tomhowe/github/CC/cc-config/node_modules/node-etcd/lib/client.js:33:22)
at Request.self.callback (/Users/tomhowe/github/CC/cc-config/node_modules/node-etcd/node_modules/request/request.js:122:22)
at Request.emit (events.js:98:17)
at Request. (/Users/tomhowe/github/CC/cc-config/node_modules/node-etcd/node_modules/request/request.js:888:14)
at Request.emit (events.js:117:20)
at IncomingMessage. (/Users/tomhowe/github/CC/cc-config/node_modules/node-etcd/node_modules/request/request.js:839:12)
at IncomingMessage.emit (events.js:117:20)
DEBUG: Program node backend.js exited with code 0

{ _readableState:
{ highWaterMark: 16384,
buffer: [],
length: 0,
pipes: null,
pipesCount: 0,
flowing: false,
ended: true,
endEmitted: true,
reading: false,
calledRead: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
objectMode: false,
defaultEncoding: 'utf8',
ranOut: false,
awaitDrain: 0,
readingMore: false,
oldMode: true,
decoder: null,
encoding: null },
readable: false,
domain: null,
_events:
{ end: [ [Function: responseOnEnd], [Function], [Function] ],
readable: [Function],
close: [ [Function], [Function] ],
data: [Function] },
_maxListeners: 10,
socket:
{ _connecting: false,
_handle:
{ fd: 79,
writeQueueSize: 0,
owner: [Circular],
onread: [Function],
reading: true },
_readableState:
{ highWaterMark: 16384,
buffer: [],
length: 0,
pipes: null,
pipesCount: 0,
flowing: false,
ended: false,
endEmitted: false,
reading: true,
calledRead: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
objectMode: false,
defaultEncoding: 'utf8',
ranOut: false,
awaitDrain: 0,
readingMore: false,
oldMode: false,
decoder: null,
encoding: null },
readable: true,
domain: null,
_events:
{ end: [Object],
finish: [Function: onSocketFinish],
_socketEnd: [Function: onSocketEnd],
free: [Function],
close: [Object],
agentRemove: [Function],
drain: [Function: ondrain] },
_maxListeners: 10,
_writableState:
{ highWaterMark: 16384,
objectMode: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
sync: false,
bufferProcessing: false,
onwrite: [Function],
writecb: null,
writelen: 0,
buffer: [],
errorEmitted: false },
writable: true,
allowHalfOpen: false,
onend: null,
destroyed: false,
bytesRead: 176,
_bytesDispatched: 133,
_pendingData: null,
_pendingEncoding: '',
parser: null,
_httpMessage:
{ domain: null,
_events: [Object],
_maxListeners: 10,
output: [],
outputEncodings: [],
writable: true,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: true,
useChunkedEncodingByDefault: false,
sendDate: false,
_headerSent: true,
_header: 'GET /v2/keys/cc/default?recursive=true&wait=true HTTP/1.1\r\nhost: localhost:4001\r\naccept: application/json\r\nConnection: keep-alive\r\n\r\n',
_hasBody: true,
_trailer: '',
finished: true,
_hangupClose: false,
socket: [Circular],
connection: [Circular],
agent: [Object],
socketPath: undefined,
method: 'GET',
path: '/v2/keys/cc/default?recursive=true&wait=true',
_headers: [Object],
_headerNames: [Object],
parser: null,
res: [Circular] },
ondata: null },
connection:
{ _connecting: false,
_handle:
{ fd: 79,
writeQueueSize: 0,
owner: [Circular],
onread: [Function],
reading: true },
_readableState:
{ highWaterMark: 16384,
buffer: [],
length: 0,
pipes: null,
pipesCount: 0,
flowing: false,
ended: false,
endEmitted: false,
reading: true,
calledRead: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
objectMode: false,
defaultEncoding: 'utf8',
ranOut: false,
awaitDrain: 0,
readingMore: false,
oldMode: false,
decoder: null,
encoding: null },
readable: true,
domain: null,
_events:
{ end: [Object],
finish: [Function: onSocketFinish],
_socketEnd: [Function: onSocketEnd],
free: [Function],
close: [Object],
agentRemove: [Function],
drain: [Function: ondrain] },
_maxListeners: 10,
_writableState:
{ highWaterMark: 16384,
objectMode: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
sync: false,
bufferProcessing: false,
onwrite: [Function],
writecb: null,
writelen: 0,
buffer: [],
errorEmitted: false },
writable: true,
allowHalfOpen: false,
onend: null,
destroyed: false,
bytesRead: 176,
_bytesDispatched: 133,
_pendingData: null,
_pendingEncoding: '',
parser: null,
_httpMessage:
{ domain: null,
_events: [Object],
_maxListeners: 10,
output: [],
outputEncodings: [],
writable: true,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: true,
useChunkedEncodingByDefault: false,
sendDate: false,
_headerSent: true,
_header: 'GET /v2/keys/cc/default?recursive=true&wait=true HTTP/1.1\r\nhost: localhost:4001\r\naccept: application/json\r\nConnection: keep-alive\r\n\r\n',
_hasBody: true,
_trailer: '',
finished: true,
_hangupClose: false,
socket: [Circular],
connection: [Circular],
agent: [Object],
socketPath: undefined,
method: 'GET',
path: '/v2/keys/cc/default?recursive=true&wait=true',
_headers: [Object],
_headerNames: [Object],
parser: null,
res: [Circular] },
ondata: null },
httpVersion: '1.1',
complete: true,
headers:
{ 'content-type': 'application/json',
'x-etcd-index': '22',
'x-raft-index': '63283',
'x-raft-term': '1',
date: 'Fri, 25 Jul 2014 09:43:37 GMT',
'transfer-encoding': 'chunked' },
trailers: {},
_pendings: [],
_pendingIndex: 0,
url: '',
method: null,
statusCode: 200,
client:
{ _connecting: false,
_handle:
{ fd: 79,
writeQueueSize: 0,
owner: [Circular],
onread: [Function],
reading: true },
_readableState:
{ highWaterMark: 16384,
buffer: [],
length: 0,
pipes: null,
pipesCount: 0,
flowing: false,
ended: false,
endEmitted: false,
reading: true,
calledRead: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
objectMode: false,
defaultEncoding: 'utf8',
ranOut: false,
awaitDrain: 0,
readingMore: false,
oldMode: false,
decoder: null,
encoding: null },
readable: true,
domain: null,
_events:
{ end: [Object],
finish: [Function: onSocketFinish],
_socketEnd: [Function: onSocketEnd],
free: [Function],
close: [Object],
agentRemove: [Function],
drain: [Function: ondrain] },
_maxListeners: 10,
_writableState:
{ highWaterMark: 16384,
objectMode: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
sync: false,
bufferProcessing: false,
onwrite: [Function],
writecb: null,
writelen: 0,
buffer: [],
errorEmitted: false },
writable: true,
allowHalfOpen: false,
onend: null,
destroyed: false,
bytesRead: 176,
_bytesDispatched: 133,
_pendingData: null,
_pendingEncoding: '',
parser: null,
_httpMessage:
{ domain: null,
_events: [Object],
_maxListeners: 10,
output: [],
outputEncodings: [],
writable: true,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: true,
useChunkedEncodingByDefault: false,
sendDate: false,
_headerSent: true,
_header: 'GET /v2/keys/cc/default?recursive=true&wait=true HTTP/1.1\r\nhost: localhost:4001\r\naccept: application/json\r\nConnection: keep-alive\r\n\r\n',
_hasBody: true,
_trailer: '',
finished: true,
_hangupClose: false,
socket: [Circular],
connection: [Circular],
agent: [Object],
socketPath: undefined,
method: 'GET',
path: '/v2/keys/cc/default?recursive=true&wait=true',
_headers: [Object],
_headerNames: [Object],
parser: null,
res: [Circular] },
ondata: null },
_consuming: true,
_dumped: false,
httpVersionMajor: 1,
httpVersionMinor: 1,
upgrade: false,
req:
{ domain: null,
_events: { error: [Function], drain: [Function] },
_maxListeners: 10,
output: [],
outputEncodings: [],
writable: true,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: true,
useChunkedEncodingByDefault: false,
sendDate: false,
_headerSent: true,
_header: 'GET /v2/keys/cc/default?recursive=true&wait=true HTTP/1.1\r\nhost: localhost:4001\r\naccept: application/json\r\nConnection: keep-alive\r\n\r\n',
_hasBody: true,
_trailer: '',
finished: true,
_hangupClose: false,
socket:
{ _connecting: false,
_handle: [Object],
_readableState: [Object],
readable: true,
domain: null,
_events: [Object],
_maxListeners: 10,
_writableState: [Object],
writable: true,
allowHalfOpen: false,
onend: null,
destroyed: false,
bytesRead: 176,
_bytesDispatched: 133,
_pendingData: null,
_pendingEncoding: '',
parser: null,
_httpMessage: [Circular],
ondata: null },
connection:
{ _connecting: false,
_handle: [Object],
_readableState: [Object],
readable: true,
domain: null,
_events: [Object],
_maxListeners: 10,
_writableState: [Object],
writable: true,
allowHalfOpen: false,
onend: null,
destroyed: false,
bytesRead: 176,
_bytesDispatched: 133,
_pendingData: null,
_pendingEncoding: '',
parser: null,
_httpMessage: [Circular],
ondata: null },
agent:
{ domain: null,
_events: [Object],
_maxListeners: 10,
options: {},
requests: {},
sockets: [Object],
maxSockets: 100,
createConnection: [Function] },
socketPath: undefined,
method: 'GET',
path: '/v2/keys/cc/default?recursive=true&wait=true',
_headers: { host: 'localhost:4001', accept: 'application/json' },
_headerNames: { host: 'host', accept: 'accept' },
parser: null,
res: [Circular] },
pipe: [Function],
addListener: [Function: addListener],
on: [Function: addListener],
pause: [Function],
resume: [Function],
read: [Function],
request:
{ domain: null,
_events:
{ error: [Function],
complete: [Function],
pipe: [Function],
end: [Object],
data: [Function] },
_maxListeners: 10,
readable: true,
writable: true,
agent:
{ domain: null,
_events: [Object],
_maxListeners: 10,
options: {},
requests: {},
sockets: [Object],
maxSockets: 100,
createConnection: [Function] },
method: 'GET',
pool: { maxSockets: 100, 'http:': [Object] },
callback: [Function],
explicitMethod: true,
canTunnel:
{ httpOverHttp: [Function: httpOverHttp],
httpsOverHttp: [Function: httpsOverHttp],
httpOverHttps: [Function: httpOverHttps],
httpsOverHttps: [Function: httpsOverHttps],
debug: [Function] },
localAddress: undefined,
dests: [],
__isRequestRequest: true,
_callback: [Function],
uri:
{ protocol: 'http:',
slashes: true,
auth: null,
host: 'localhost:4001',
port: '4001',
hostname: 'localhost',
hash: null,
search: '?recursive=true&wait=true',
query: 'recursive=true&wait=true',
pathname: '/v2/keys/cc/default',
path: '/v2/keys/cc/default?recursive=true&wait=true',
href: 'http://localhost:4001/v2/keys/cc/default?recursive=true&wait=true' },
_redirectsFollowed: 0,
maxRedirects: 10,
followRedirect: true,
followAllRedirects: false,
redirects: [],
headers: { accept: 'application/json' },
setHost: true,
originalCookieHeader: undefined,
_disableCookies: true,
_jar: undefined,
port: '4001',
host: 'localhost',
clientErrorHandler: [Function],
_parserErrorHandler: [Function],
url:
{ protocol: 'http:',
slashes: true,
auth: null,
host: 'localhost:4001',
port: '4001',
hostname: 'localhost',
hash: null,
search: '?recursive=true&wait=true',
query: 'recursive=true&wait=true',
pathname: '/v2/keys/cc/default',
path: '/v2/keys/cc/default?recursive=true&wait=true',
href: 'http://localhost:4001/v2/keys/cc/default?recursive=true&wait=true' },
path: '/v2/keys/cc/default?recursive=true&wait=true',
_json: true,
httpModule:
{ parsers: [Object],
STATUS_CODES: [Object],
IncomingMessage: [Object],
OutgoingMessage: [Object],
ServerResponse: [Object],
Agent: [Object],
globalAgent: [Object],
ClientRequest: [Object],
request: [Object],
get: [Function],
Server: [Object],
createServer: [Object],
connectionListener: [Function: connectionListener],
Client: [Getter/Setter],
createClient: [Getter/Setter] },
agentClass: { [Function: Agent] super
: [Object], defaultMaxSockets: 5 },
_started: true,
href: 'http://localhost:4001/v2/keys/cc/default?recursive=true&wait=true',
req:
{ domain: null,
_events: [Object],
_maxListeners: 10,
output: [],
outputEncodings: [],
writable: true,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: true,
useChunkedEncodingByDefault: false,
sendDate: false,
_headerSent: true,
_header: 'GET /v2/keys/cc/default?recursive=true&wait=true HTTP/1.1\r\nhost: localhost:4001\r\naccept: application/json\r\nConnection: keep-alive\r\n\r\n',
_hasBody: true,
_trailer: '',
finished: true,
_hangupClose: false,
socket: [Object],
connection: [Object],
agent: [Object],
socketPath: undefined,
method: 'GET',
path: '/v2/keys/cc/default?recursive=true&wait=true',
_headers: [Object],
_headerNames: [Object],
parser: null,
res: [Circular] },
ntick: true,
response: [Circular],
_ended: true,
_callbackCalled: true },
toJSON: [Function: toJSON] }

Is there a way to subscribe for the key?

Hi,

In the library description the next options are described:
1/

etcd.get('key', {wait: true}, callbeck)

2/

let watcher = etcd.watcher("key");

watcher.on('change', (data) => {
    console.log(data);
});

Each of these allows us to receive a key on update, however, when the application is started - we would not receive any. In case of {wait: true} it would leave the event loop after the first change.

Is there a way to subscribe for the key update with the next criteria:

  1. We get the value when the application is started
  2. We receive any updates of the key each time the key is updated

Any thoughts?

Regards,

EventEmitter for watch

watch could be implemented as an eventemitter that handles index and reconnects, etc.

Timeout + watcher doesn't make sense

When setting a timeout through the constructor, the timeout is applied through the watcher as well (since it's sugar over the GET request).

This doesn't make sense. If the etcd directory had no activity within the timeout window, the request module closes the connection (and kicks off the exponential backoff, which means watches could be ridiculously delayed).

If this is intentional, it's easy enough for me to use a workaround and build my own timeout method and avoid the constructor option. If not, I'd be happy to work on a refactoring in a PR that separates out this configuration.

getSync is dying

By using the "lab" to perform unit testing, the getSync dies, allowing not continue testing.
Searching in the code, I found that the error occurs in the file "./node_modules/node-etcd/node_modules/deasync/index.js" on line 54, the command "binding.run ()", also found that the command exists but the run him to the "lab".

Watcher is missing updates in case etcd is unreachable for some time

With the following code snippet:

let watcher = etcd.watcher(path, null, {recursive: true}).on('reconnect', console.log('Reconnect'))
watcher.on('change', (change)=> {
  callback(change)
})

Watcher catches the updates and calls the 'change' event successfully. But if etcd is not accesible for a while (because it is down or due to some issue with the network), then the retry logic in watcher.coffee (https://github.com/stianeikeland/node-etcd/blob/master/src/watcher.coffee#L91) calls watch method again after some timeout without stating the lastIndex. So it misses all the changes until the exponential timeout triggers and it is reconnected again.

Address parameter and set key

Hi, it seems, on localhost, all the set functions give error if I declare the address with port integrated in the string

var EtcdModule = require('node-etcd');
var etcd = new EtcdModule("localhost:2379" );

// error 404 not found
console.log( etcd.setSync("mykey","mykey") );
etcd.set("mykey","mykey",console.log);

// works fine
etcd = new EtcdModule("localhost", 2379 );
console.log( etcd.setSync("mykey","mykey") );
etcd.set("mykey","mykey",console.log);

All the get functions work fine in both address declaration

Call without callback synchronous?

What I didn't get out of the documentation: Is a call to etcd without a callback a synchronous function call or is it asynchronous.

What guarantees do I have if I use the library without callbacks. Is the order of the execution guaranteed?

Best, Mark

How to watch changes within a directory recursively.

Try a few ways to set the options, only work if key is a property but not a directory.

Nothing get return, if I make changes under the directory under monitor

var dir = '/'
var options = {wait: true,recursive: true};
var watcher = etcd.watcher(dir, options);

watcher
.on('set', function (data) {
console.log('data: ', data);
})
.on('change', function (data) {
console.log('data: ', data);
})
.on('expire', function (data) {
console.log('Value expired.');
console.log('data: ', data);
})
.on('delete', function (data) {
console.log('Value deleted.');
console.log('data: ', data);
});

Error: Could not locate the bindings file.

HI,all
I hav got this error when I boot my application and details more like this,

privatecloud_1 | /server/node_modules/node-etcd/node_modules/deasync/node_modules/bindings/bindings.js:91
privatecloud_1 | throw err
privatecloud_1 | ^
privatecloud_1 | Error: Could not locate the bindings file. Tried:
privatecloud_1 | → /server/node_modules/node-etcd/node_modules/deasync/build/deasync.node
privatecloud_1 | → /server/node_modules/node-etcd/node_modules/deasync/build/Debug/deasync.node
privatecloud_1 | → /server/node_modules/node-etcd/node_modules/deasync/build/Release/deasync.node
privatecloud_1 | → /server/node_modules/node-etcd/node_modules/deasync/out/Debug/deasync.node
privatecloud_1 | → /server/node_modules/node-etcd/node_modules/deasync/Debug/deasync.node
privatecloud_1 | → /server/node_modules/node-etcd/node_modules/deasync/out/Release/deasync.node
privatecloud_1 | → /server/node_modules/node-etcd/node_modules/deasync/Release/deasync.node
privatecloud_1 | → /server/node_modules/node-etcd/node_modules/deasync/build/default/deasync.node
privatecloud_1 | → /server/node_modules/node-etcd/node_modules/deasync/compiled/2.5.0/linux/x64/deasync.node
privatecloud_1 | at bindings (/server/node_modules/node-etcd/node_modules/deasync/node_modules/bindings/bindings.js:88:9)
privatecloud_1 | at Object. (/server/node_modules/node-etcd/node_modules/deasync/index.js:23:31)
privatecloud_1 | at Module._compile (module.js:430:26)
privatecloud_1 | at Object.Module._extensions..js (module.js:448:10)
privatecloud_1 | at Module.load (/server/node_modules/coffee-script/lib/coffee-script/register.js:45:36)
privatecloud_1 | at Function.Module._load (module.js:310:12)
privatecloud_1 | at Module.require (module.js:365:17)
privatecloud_1 | at require (module.js:384:17)
privatecloud_1 | at Object. (/server/node_modules/node-etcd/lib/client.js:7:11)
privatecloud_1 | at Module._compile (module.js:430:26)
privatecloud_1 | at Object.Module._extensions..js (module.js:448:10)
privatecloud_1 | at Module.load (/server/node_modules/coffee-script/lib/coffee-script/register.js:45:36)
privatecloud_1 | at Function.Module._load (module.js:310:12)
privatecloud_1 | at Module.require (module.js:365:17)
privatecloud_1 | at require (module.js:384:17)
privatecloud_1 | at Object. (/server/node_modules/node-etcd/lib/index.js:9:10)
privatecloud_1 | at Module._compile (module.js:430:26)
privatecloud_1 | at Object.Module._extensions..js (module.js:448:10)
privatecloud_1 | at Module.load (/server/node_modules/coffee-script/lib/coffee-script/register.js:45:36)
privatecloud_1 | at Function.Module._load (module.js:310:12)
privatecloud_1 | at Module.require (module.js:365:17)
privatecloud_1 | at require (module.js:384:17)
privatecloud_1 | at Object. (/server/common/etcd.coffee:1:8)
privatecloud_1 | at Object. (/server/common/etcd.coffee:1:1)
privatecloud_1 | at Module._compile (module.js:430:26)
privatecloud_1 | at Object.loadFile (/server/node_modules/coffee-script/lib/coffee-script/register.js:16:19)
privatecloud_1 | at Module.load (/server/node_modules/coffee-script/lib/coffee-script/register.js:45:36)
privatecloud_1 | at Function.Module._load (module.js:310:12)
privatecloud_1 | at Module.require (module.js:365:17)
privatecloud_1 | at require (module.js:384:17)
privatecloud_1 | at Object. (/server/update-server.coffee:19:10)
privatecloud_1 | at Object. (/server/update-server.coffee:1:1)
privatecloud_1 | at Module._compile (module.js:430:26)
privatecloud_1 | at Object.loadFile (/server/node_modules/coffee-script/lib/coffee-script/register.js:16:19)
privatecloud_1 | at Module.load (/server/node_modules/coffee-script/lib/coffee-script/register.js:45:36)
privatecloud_1 | at Function.Module._load (module.js:310:12)
privatecloud_1 | at Module.require (module.js:365:17)
privatecloud_1 | at require (module.js:384:17)
privatecloud_1 | at Object. (/server/app.coffee:3:10)
privatecloud_1 | at Object. (/server/app.coffee:1:1)
privatecloud_1 | at Module._compile (module.js:430:26)
privatecloud_1 | at Object.loadFile (/server/node_modules/coffee-script/lib/coffee-script/register.js:16:19)
privatecloud_1 | at Module.load (/server/node_modules/coffee-script/lib/coffee-script/register.js:45:36)
privatecloud_1 | at Function.Module._load (module.js:310:12)
privatecloud_1 | at Module.require (module.js:365:17)
privatecloud_1 | at require (module.js:384:17)
privatecloud_1 | at Object. (/server/index.js:3:1)
privatecloud_1 | at Module._compile (module.js:430:26)
privatecloud_1 | at Object.Module._extensions..js (module.js:448:10)
privatecloud_1 | at Module.load (module.js:355:32)
privatecloud_1 | at Function.Module._load (module.js:310:12)
privatecloud_1 | at Function.Module.runMain (module.js:471:10)
privatecloud_1 | at startup (node.js:117:18)
privatecloud_1 | at node.js:953:3

how is this going ? I can not find the files which in node_modules/node-etcd/node_modules/deasync/build/ AND where are them ?

PS: I used Mac OX EI Captian

Timeouts can not reconnect if event in requested index has been cleared

If there are no changes in the directory you are watching and etcd index has changed more than 1000 times the reconnection will continuously fail. This can happen quite often when using Fleet as it writes heartbeats a lot.

{ [Error: Connection error, reconnecting.]
  error: 
   { [Error: The event in requested index is outdated and cleared]
     errorCode: 401,
     error: 
      { errorCode: 401,
        message: 'The event in requested index is outdated and cleared',
        cause: 'the requested history has been cleared [1300446/1297481]',
        index: 1301445 } },
  reconnectCount: 1 }

{ [Error: Connection error, reconnecting.]
  error: 
   { [Error: The event in requested index is outdated and cleared]
     errorCode: 401,
     error: 
      { errorCode: 401,
        message: 'The event in requested index is outdated and cleared',
        cause: 'the requested history has been cleared [1300466/1297481]',
        index: 1301465 } },
  reconnectCount: 2 }


...

{ [Error: Connection error, reconnecting.]
  error: 
   { [Error: The event in requested index is outdated and cleared]
     errorCode: 401,
     error: 
      { errorCode: 401,
        message: 'The event in requested index is outdated and cleared',
        cause: 'the requested history has been cleared [1316622/1297481]',
        index: 1317621 } },
  reconnectCount: 12 }

I think the reconnection should take the index returned in the 401 error.

Watcher does not detect unavailable server.

When creating a simple watcher like this:

var Etcd = require("node-etcd");
var etcd = new Etcd("127.0.0.1", 4001);
var watcher = etcd.watcher("/x/y/z", null, { recursive: true });
watcher.on("change", console.log);
watcher.on("error", console.error);

When the etcd server goes down, the watcher will not throw an error or notify about unavailable server in any way. I would expect the on error callback to be called.

LICENSE?

BSD? Which BSD? 2-Clause, 3-Clause or 4-Clause?

Update deasync dependency to 0.1.1 for io.js 3.3.0 support

deasync depends on a package called nan that was failing to build on the latest version of io.js until recently. nan has been fixed and a new version of deasync has been released to update the dependency, but currently node-etcd is pinned to 0.0.x versions of deasync.

Broken response in watcher doesn't back off

If the watcher catches a change and the response is broken, or for some reason can't be parsed, but the etcd server still responds with something, we end up in an endless loop.

It seems to me like it should use the _retry method here instead of directly calling _watch here https://github.com/stianeikeland/node-etcd/blob/master/src/watcher.coffee#L51

else
    error = new Error 'Received unexpected response'
    error.response = val;
    @emit 'error', error
    @_watch()

Behaviour we're experiencing is that it retries every tick, which crashes the server by using all available cpu.

At the same time, a back off algorithm would be nice. :)

Synchronous Support

Greetings,

I have added synchronous support to node-etcd and I was curious if there is any interest in a pull request to possibly take this work. Specifically, my changes add synchronous versions of get, set, del, mkdir, and rmdir. This work utilizes the requestsync module. Please let me know. Thanks!

https without a cert

I want to be able to specify a https connection string, but not have to pass in a certificate - at the moment it seems like passing in a https URL automatically requires me to supply a cert.

You can use the rejectUnauthorized param from here: https://nodejs.org/api/tls.html#tls_tls_connect_options_callback and pass it into the agentOptions of request in this instance to make this work (I think!).

I would attempt a PR, but Coffee script is very alien to me and I don't want to break things :)

Thanks!

Handle object/array values a bit smoother

I'm currently building out the ability to pass an object,array to the the api as the key value. This will be stringified behind the scenes. Upon return, this value will be serialized back to json. Is this something that makes sense for this module?

client.watch() gives `undefined` result after 5 minutes

Test script:

var Etcd = require('node-etcd');
var etcd = new Etcd();

var KEY_NOT_FOUND = 100;

function watchOps(cb) {
    var nextIndex = 0;
    etcd.get("/app/op/", {recursive:true}, function(err, val) {
        if(err && err.errorCode == KEY_NOT_FOUND) {
            // key not yet present, just wait for it to be created
        } else {
            if(err) return cb(err);
            nextIndex = val.node.modifiedIndex+1;
        }
        function loop() {
            console.log("watching (index " + nextIndex + ") ...");
            etcd.watch("/app/op/", {recursive:true, waitIndex:nextIndex}, function(err, change) {
                if(err) return cb(err);
                console.log("saw change: ", change);
                nextIndex = change.node.modifiedIndex+1;
                loop();
            });
        };
        loop();
    });
};

watchOps(function(err, change) {
    if(err) {
        console.log(err);
        process.exit(1);
    }
});

Running with node-etcd 3.0.0, etcd 0.4.6

Output:

watching (index 0) ...
saw change:  undefined
TypeError: Cannot read property 'node' of undefined

Or, when there is an existing key under /app/op:

watching (index 28380) ...
saw change:  undefined
TypeError: Cannot read property 'node' of undefined

Both of these runs took a fraction of a second over 5 minutes, so it definitely seems timeout related. But I don't know whether it's etcd, node or the OS which is dropping the connection.

I also did a curl:

$ curl 'http://localhost:4001/v2/keys/app/op/?recursive=true&waitIndex=28380&wait=true'
# time passes
curl: (18) transfer closed with outstanding read data remaining

Is this something I should deal with in my code, or should node-etcd automatically resubmit a watch when this happens? If it's up to my app code, is there a better value that node-etcd can return in this scenario than just undefined?

Forced to manually append the protocol

Using node-etcd@beta although I've also been testing on node 5.11.1, I did see that travis is only testing against 4 so not sure if 5 is officially supported, although I dont think its an issue here anyway.

Small one,

const Etcd = require( 'node-etcd' )
const etcd = new Etcd( '10.1.5.1:2379' )

Setting up with just the ip throws an error

[Error: All servers returned error]
  errors: 
   [ { server: '10.1.5.1:2379',
       httperror: [Error: Invalid protocol: 10.1.5.1:],
       httpstatus: undefined,
       httpbody: undefined,
       response: undefined,
       timestamp: Tue May 17 2016 16:02:39 GMT+0000 (UTC) } ],
  retries: 0 }

Manually adding the protocol works just fine.

Error: Received unexpected response

I got the error with "node-etcd": "^4.1.0":

events.js:141
      throw er; // Unhandled 'error' event
      ^

Error: Received unexpected response
    at Watcher._unexpectedData (/Users/goyoo/workspace/vagrant/all/sse/yun-engine/node_modules/node-etcd/lib/watcher.js:75:13)
    at Watcher._unexpectedData (/Users/goyoo/workspace/vagrant/all/sse/yun-engine/node_modules/node-etcd/lib/watcher.js:3:57)
    at Watcher._respHandler (/Users/goyoo/workspace/vagrant/all/sse/yun-engine/node_modules/node-etcd/lib/watcher.js:102:19)
    at /Users/goyoo/workspace/vagrant/all/sse/yun-engine/node_modules/node-etcd/lib/watcher.js:3:57
    at Client._handleResponse (/Users/goyoo/workspace/vagrant/all/sse/yun-engine/node_modules/node-etcd/lib/client.js:223:14)
    at Request._callback (/Users/goyoo/workspace/vagrant/all/sse/yun-engine/node_modules/node-etcd/lib/client.js:136:22)
    at Request.self.callback (/Users/goyoo/workspace/vagrant/all/sse/yun-engine/node_modules/node-etcd/node_modules/request/request.js:198:22)
    at emitTwo (events.js:87:13)
    at Request.emit (events.js:172:7)
    at Request.<anonymous> (/Users/goyoo/workspace/vagrant/all/sse/yun-engine/node_modules/node-etcd/node_modules/request/request.js:1057:14)

Process finished with exit code 1

Etcd errors should be error objects, too

If etcd returned an error the http body with the error details is returned as an error.
To be consistent with the rest of the api it would be nice if this would be an error object, too.

This would also give the consumers of your api all the relevant informations like stack traces.
More information on this topic can be found in the blog post A String is not an Error

An fix would be as easy as wrapping the body into a new Error object.

Best, Mark

auto add port

code:

function Watch(etcd_endpoint, name){
    console.log("etcd_endpoint",etcd_endpoint, "name",name);
    this.cacheEtcd = new Etcd(etcd_endpoint);
    this.name = name;
    this.etcdDir = '/load_balancer/swarm/'+name;
}

var watcher = new Watch("10.11.3.26:3379", "swarm-6");

watcher.delFailedService(function(){});

error:

{ Error: All servers returned error
    at Client._error (/wk/test/node_modules/node-etcd/lib/client.js:191:13)
    at Client._multiserverHelper (/wk/test/node_modules/node-etcd/lib/client.js:118:19)
    at Client._multiserverHelper (/wk/test/node_modules/node-etcd/lib/client.js:3:57)
    at Request._callback (/wk/test/node_modules/node-etcd/lib/client.js:134:24)
    at self.callback (/wk/test/node_modules/request/request.js:198:22)
    at emitOne (events.js:96:13)
    at Request.emit (events.js:188:7)
    at Request.onRequestError (/wk/test/node_modules/request/request.js:861:8)
    at emitOne (events.js:96:13)
    at ClientRequest.emit (events.js:188:7)
  errors:
   [ { server: 'http://10.11.3.26:3379:4001',
       httperror: [Object],
       httpstatus: undefined,
       httpbody: undefined,
       response: undefined,
       timestamp: 2016-05-18T05:54:42.151Z } ],
  retries: 0 }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.