1**This is the documentation for etcd2 releases. Read [etcd3 doc][v3-docs] for etcd3 releases.**
2
3[v3-docs]: ../docs.md#documentation
4
5
6# etcd API
7
8## Running a Single Machine Cluster
9
10These examples will use a single member cluster to show you the basics of the etcd REST API.
11Let's start etcd:
12
13```sh
14./bin/etcd
15```
16
17This will bring up etcd listening on the IANA assigned ports and listening on localhost.
18The IANA assigned ports for etcd are 2379 for client communication and 2380 for server-to-server communication.
19
20## Getting the etcd version
21
22The etcd version of a specific instance can be obtained from the `/version` endpoint.
23
24```sh
25curl -L http://127.0.0.1:2379/version
26```
27
28## Key Space Operations
29
30The primary API of etcd is a hierarchical key space.
31The key space consists of directories and keys which are generically referred to as "nodes".
32
33### Setting the value of a key
34
35Let's set the first key-value pair in the datastore.
36In this case the key is `/message` and the value is `Hello world`.
37
38```sh
39curl http://127.0.0.1:2379/v2/keys/message -XPUT -d value="Hello world"
40```
41
42```json
43{
44    "action": "set",
45    "node": {
46        "createdIndex": 2,
47        "key": "/message",
48        "modifiedIndex": 2,
49        "value": "Hello world"
50    }
51}
52```
53
54The response object contains several attributes:
55
561. `action`: the action of the request that was just made.
57The request attempted to modify `node.value` via a `PUT` HTTP request, thus the value of action is `set`.
58
592. `node.key`: the HTTP path to which the request was made.
60We set `/message` to `Hello world`, so the key field is `/message`.
61etcd uses a file-system-like structure to represent the key-value pairs, therefore all keys start with `/`.
62
633. `node.value`: the value of the key after resolving the request.
64In this case, a successful request was made that attempted to change the node's value to `Hello world`.
65
664. `node.createdIndex`: an index is a unique, monotonically-incrementing integer created for each change to etcd.
67This specific index reflects the point in the etcd state member at which a given key was created.
68You may notice that in this example the index is `2` even though it is the first request you sent to the server.
69This is because there are internal commands that also change the state behind the scenes, like adding and syncing servers.
70
715. `node.modifiedIndex`: like `node.createdIndex`, this attribute is also an etcd index.
72Actions that cause the value to change include `set`, `delete`, `update`, `create`, `compareAndSwap` and `compareAndDelete`.
73Since the `get` and `watch` commands do not change state in the store, they do not change the value of `node.modifiedIndex`.
74
75
76### Response Headers
77
78etcd includes a few HTTP headers in responses that provide global information about the etcd cluster that serviced a request:
79
80```
81X-Etcd-Index: 35
82X-Raft-Index: 5398
83X-Raft-Term: 1
84```
85
86* `X-Etcd-Index` is the current etcd index as explained above. When request is a watch on key space, `X-Etcd-Index` is the current etcd index when the watch starts, which means that the watched event may happen after `X-Etcd-Index`.
87* `X-Raft-Index` is similar to the etcd index but is for the underlying raft protocol.
88* `X-Raft-Term` is an integer that will increase whenever an etcd master election happens in the cluster. If this number is increasing rapidly, you may need to tune the election timeout. See the [tuning][tuning] section for details.
89
90### Get the value of a key
91
92We can get the value that we just set in `/message` by issuing a `GET` request:
93
94```sh
95curl http://127.0.0.1:2379/v2/keys/message
96```
97
98```json
99{
100    "action": "get",
101    "node": {
102        "createdIndex": 2,
103        "key": "/message",
104        "modifiedIndex": 2,
105        "value": "Hello world"
106    }
107}
108```
109
110
111### Changing the value of a key
112
113You can change the value of `/message` from `Hello world` to `Hello etcd` with another `PUT` request to the key:
114
115```sh
116curl http://127.0.0.1:2379/v2/keys/message -XPUT -d value="Hello etcd"
117```
118
119```json
120{
121    "action": "set",
122    "node": {
123        "createdIndex": 3,
124        "key": "/message",
125        "modifiedIndex": 3,
126        "value": "Hello etcd"
127    },
128    "prevNode": {
129    	"createdIndex": 2,
130    	"key": "/message",
131    	"value": "Hello world",
132    	"modifiedIndex": 2
133    }
134}
135```
136
137Here we introduce a new field: `prevNode`. The `prevNode` field represents what the state of a given node was before resolving the request at hand. The `prevNode` field follows the same format as the `node`, and is omitted in the event that there was no previous state for a given node.
138
139### Deleting a key
140
141You can remove the `/message` key with a `DELETE` request:
142
143```sh
144curl http://127.0.0.1:2379/v2/keys/message -XDELETE
145```
146
147```json
148{
149    "action": "delete",
150    "node": {
151        "createdIndex": 3,
152        "key": "/message",
153        "modifiedIndex": 4
154    },
155    "prevNode": {
156    	"key": "/message",
157    	"value": "Hello etcd",
158    	"modifiedIndex": 3,
159    	"createdIndex": 3
160    }
161}
162```
163
164
165### Using key TTL
166
167Keys in etcd can be set to expire after a specified number of seconds.
168You can do this by setting a TTL (time to live) on the key when sending a `PUT` request:
169
170```sh
171curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar -d ttl=5
172```
173
174```json
175{
176    "action": "set",
177    "node": {
178        "createdIndex": 5,
179        "expiration": "2013-12-04T12:01:21.874888581-08:00",
180        "key": "/foo",
181        "modifiedIndex": 5,
182        "ttl": 5,
183        "value": "bar"
184    }
185}
186```
187
188Note the two new fields in response:
189
1901. The `expiration` is the time at which this key will expire and be deleted.
191
1922. The `ttl` is the specified time to live for the key, in seconds.
193
194_NOTE_: Keys can only be expired by a cluster leader, so if a member gets disconnected from the cluster, its keys will not expire until it rejoins.
195
196Now you can try to get the key by sending a `GET` request:
197
198```sh
199curl http://127.0.0.1:2379/v2/keys/foo
200```
201
202If the TTL has expired, the key will have been deleted, and you will be returned a 100.
203
204```json
205{
206    "cause": "/foo",
207    "errorCode": 100,
208    "index": 6,
209    "message": "Key not found"
210}
211```
212
213The TTL can be unset to avoid expiration through update operation:
214
215```sh
216curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar -d ttl= -d prevExist=true
217```
218
219```json
220{
221    "action": "update",
222    "node": {
223        "createdIndex": 5,
224        "key": "/foo",
225        "modifiedIndex": 6,
226        "value": "bar"
227    },
228    "prevNode": {
229        "createdIndex": 5,
230        "expiration": "2013-12-04T12:01:21.874888581-08:00",
231        "key": "/foo",
232        "modifiedIndex": 5,
233        "ttl": 3,
234        "value": "bar"
235    }
236}
237```
238
239### Refreshing key TTL
240
241Keys in etcd can be refreshed without notifying current watchers.
242
243This can be achieved by setting the refresh to true when updating a TTL.
244
245You cannot update the value of a key when refreshing it.
246
247```sh
248curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar -d ttl=5
249curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d ttl=5 -d refresh=true -d prevExist=true
250```
251
252```json
253{
254    "action": "set",
255    "node": {
256        "createdIndex": 5,
257        "expiration": "2013-12-04T12:01:21.874888581-08:00",
258        "key": "/foo",
259        "modifiedIndex": 5,
260        "ttl": 5,
261        "value": "bar"
262    }
263}
264{
265   "action":"update",
266   "node":{
267       "key":"/foo",
268       "value":"bar",
269       "expiration": "2013-12-04T12:01:26.874888581-08:00",
270       "ttl":5,
271       "modifiedIndex":6,
272       "createdIndex":5
273    },
274   "prevNode":{
275       "key":"/foo",
276       "value":"bar",
277       "expiration":"2013-12-04T12:01:21.874888581-08:00",
278       "ttl":3,
279       "modifiedIndex":5,
280       "createdIndex":5
281     }
282}
283```
284
285### Waiting for a change
286
287We can watch for a change on a key and receive a notification by using long polling.
288This also works for child keys by passing `recursive=true` in curl.
289
290In one terminal, we send a `GET` with `wait=true` :
291
292```sh
293curl http://127.0.0.1:2379/v2/keys/foo?wait=true
294```
295
296Now we are waiting for any changes at path `/foo`.
297
298In another terminal, we set a key `/foo` with value `bar`:
299
300```sh
301curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar
302```
303
304The first terminal should get the notification and return with the same response as the set request:
305
306```json
307{
308    "action": "set",
309    "node": {
310        "createdIndex": 7,
311        "key": "/foo",
312        "modifiedIndex": 7,
313        "value": "bar"
314    },
315    "prevNode": {
316        "createdIndex": 6,
317        "key": "/foo",
318        "modifiedIndex": 6,
319        "value": "bar"
320    }
321}
322```
323
324However, the watch command can do more than this.
325Using the index, we can watch for commands that have happened in the past.
326This is useful for ensuring you don't miss events between watch commands.
327Typically, we watch again from the `modifiedIndex` + 1 of the node we got.
328
329Let's try to watch for the set command of index 7 again:
330
331```sh
332curl 'http://127.0.0.1:2379/v2/keys/foo?wait=true&waitIndex=7'
333```
334
335The watch command returns immediately with the same response as previously.
336
337If we were to restart the watch from index 8 with:
338
339```sh
340curl 'http://127.0.0.1:2379/v2/keys/foo?wait=true&waitIndex=8'
341```
342
343Then even if etcd is on index 9 or 800, the first event to occur to the `/foo`
344key between 8 and the current index will be returned.
345
346**Note**: etcd only keeps the responses of the most recent 1000 events across all etcd keys.
347It is recommended to send the response to another thread to process immediately
348instead of blocking the watch while processing the result.
349
350#### Watch from cleared event index
351
352If we miss all the 1000 events, we need to recover the current state of the
353watching key space through a get and then start to watch from the
354`X-Etcd-Index` + 1.
355
356For example, we set `/other="bar"` for 2000 times and try to wait from index 8.
357
358```sh
359curl 'http://127.0.0.1:2379/v2/keys/foo?wait=true&waitIndex=8'
360```
361
362We get the index is outdated response, since we miss the 1000 events kept in etcd.
363
364```
365{"errorCode":401,"message":"The event in requested index is outdated and cleared","cause":"the requested history has been cleared [1008/8]","index":2007}
366```
367
368To start watch, first we need to fetch the current state of key `/foo`:
369
370```sh
371curl 'http://127.0.0.1:2379/v2/keys/foo' -vv
372```
373
374```
375< HTTP/1.1 200 OK
376< Content-Type: application/json
377< X-Etcd-Cluster-Id: 7e27652122e8b2ae
378< X-Etcd-Index: 2007
379< X-Raft-Index: 2615
380< X-Raft-Term: 2
381< Date: Mon, 05 Jan 2015 18:54:43 GMT
382< Transfer-Encoding: chunked
383<
384{"action":"get","node":{"key":"/foo","value":"bar","modifiedIndex":7,"createdIndex":7}}
385```
386
387Unlike watches we use the `X-Etcd-Index` + 1 of the response as a `waitIndex`
388instead of the node's `modifiedIndex` + 1 for two reasons:
389
3901. The `X-Etcd-Index` is always greater than or equal to the `modifiedIndex` when
391   getting a key because `X-Etcd-Index` is the current etcd index, and the `modifiedIndex`
392   is the index of an event already stored in etcd.
3932. None of the events represented by indexes between `modifiedIndex` and
394   `X-Etcd-Index` will be related to the key being fetched.
395
396Using the `modifiedIndex` + 1 is functionally equivalent for subsequent
397watches, but since it is smaller than the `X-Etcd-Index` + 1, we may receive a
398`401 EventIndexCleared` error immediately.
399
400So the first watch after the get should be:
401
402```sh
403curl 'http://127.0.0.1:2379/v2/keys/foo?wait=true&waitIndex=2008'
404```
405
406#### Connection being closed prematurely
407
408The server may close a long polling connection before emitting any events.
409This can happen due to a timeout or the server being shutdown.
410Since the HTTP header is sent immediately upon accepting the connection, the response will be seen as empty: `200 OK` and empty body.
411The clients should be prepared to deal with this scenario and retry the watch.
412
413### Atomically Creating In-Order Keys
414
415Using `POST` on a directory, you can create keys with key names that are created in-order.
416This can be used in a variety of useful patterns, like implementing queues of keys which need to be processed in strict order.
417An example use case would be ensuring clients get fair access to a mutex.
418
419Creating an in-order key is easy:
420
421```sh
422curl http://127.0.0.1:2379/v2/keys/queue -XPOST -d value=Job1
423```
424
425```json
426{
427    "action": "create",
428    "node": {
429        "createdIndex": 6,
430        "key": "/queue/00000000000000000006",
431        "modifiedIndex": 6,
432        "value": "Job1"
433    }
434}
435```
436
437If you create another entry some time later, it is guaranteed to have a key name that is greater than the previous key.
438Also note the key names use the global etcd index, so the next key can be more than `previous + 1`.
439
440```sh
441curl http://127.0.0.1:2379/v2/keys/queue -XPOST -d value=Job2
442```
443
444```json
445{
446    "action": "create",
447    "node": {
448        "createdIndex": 29,
449        "key": "/queue/00000000000000000029",
450        "modifiedIndex": 29,
451        "value": "Job2"
452    }
453}
454```
455
456To enumerate the in-order keys as a sorted list, use the "sorted" parameter.
457
458```sh
459curl -s 'http://127.0.0.1:2379/v2/keys/queue?recursive=true&sorted=true'
460```
461
462```json
463{
464    "action": "get",
465    "node": {
466        "createdIndex": 2,
467        "dir": true,
468        "key": "/queue",
469        "modifiedIndex": 2,
470        "nodes": [
471            {
472                "createdIndex": 2,
473                "key": "/queue/00000000000000000002",
474                "modifiedIndex": 2,
475                "value": "Job1"
476            },
477            {
478                "createdIndex": 3,
479                "key": "/queue/00000000000000000003",
480                "modifiedIndex": 3,
481                "value": "Job2"
482            }
483        ]
484    }
485}
486```
487
488
489### Using a directory TTL
490
491Like keys, directories in etcd can be set to expire after a specified number of seconds.
492You can do this by setting a TTL (time to live) on a directory when it is created with a `PUT`:
493
494```sh
495curl http://127.0.0.1:2379/v2/keys/dir -XPUT -d ttl=30 -d dir=true
496```
497
498```json
499{
500    "action": "set",
501    "node": {
502        "createdIndex": 17,
503        "dir": true,
504        "expiration": "2013-12-11T10:37:33.689275857-08:00",
505        "key": "/dir",
506        "modifiedIndex": 17,
507        "ttl": 30
508    }
509}
510```
511
512The directory's TTL can be refreshed by making an update.
513You can do this by making a PUT with `prevExist=true` and a new TTL.
514
515```sh
516curl http://127.0.0.1:2379/v2/keys/dir -XPUT -d ttl=30 -d dir=true -d prevExist=true
517```
518
519Keys that are under this directory work as usual, but when the directory expires, a watcher on a key under the directory will get an expire event:
520
521```sh
522curl 'http://127.0.0.1:2379/v2/keys/dir?wait=true'
523```
524
525```json
526{
527    "action": "expire",
528    "node": {
529        "createdIndex": 8,
530        "key": "/dir",
531        "modifiedIndex": 15
532    },
533    "prevNode": {
534        "createdIndex": 8,
535        "key": "/dir",
536        "dir":true,
537        "modifiedIndex": 17,
538        "expiration": "2013-12-11T10:39:35.689275857-08:00"
539    }
540}
541```
542
543
544### Atomic Compare-and-Swap
545
546etcd can be used as a centralized coordination service in a cluster, and `CompareAndSwap` (CAS) is the most basic operation used to build a distributed lock service.
547
548This command will set the value of a key only if the client-provided conditions are equal to the current conditions.
549
550*Note that `CompareAndSwap` does not work with [directories][directories]. If an attempt is made to `CompareAndSwap` a directory, a 102 "Not a file" error will be returned.*
551
552The current comparable conditions are:
553
5541. `prevValue` - checks the previous value of the key.
555
5562. `prevIndex` - checks the previous modifiedIndex of the key.
557
5583. `prevExist` - checks existence of the key: if `prevExist` is true, it is an `update` request; if `prevExist` is `false`, it is a `create` request.
559
560Here is a simple example.
561Let's create a key-value pair first: `foo=one`.
562
563```sh
564curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d value=one
565```
566
567```json
568{
569    "action":"set",
570    "node":{
571        "key":"/foo",
572        "value":"one",
573        "modifiedIndex":4,
574        "createdIndex":4
575    }
576}
577```
578
579Specifying `noValueOnSuccess` option skips returning the node as value.
580
581```sh
582curl http://127.0.0.1:2379/v2/keys/foo?noValueOnSuccess=true -XPUT -d value=one
583# {"action":"set"}
584```
585
586Now let's try some invalid `CompareAndSwap` commands.
587
588Trying to set this existing key with `prevExist=false` fails as expected:
589```sh
590curl http://127.0.0.1:2379/v2/keys/foo?prevExist=false -XPUT -d value=three
591```
592
593The error code explains the problem:
594
595```json
596{
597    "cause": "/foo",
598    "errorCode": 105,
599    "index": 39776,
600    "message": "Key already exists"
601}
602```
603
604Now let's provide a `prevValue` parameter:
605
606```sh
607curl http://127.0.0.1:2379/v2/keys/foo?prevValue=two -XPUT -d value=three
608```
609
610This will try to compare the previous value of the key and the previous value we provided. If they are equal, the value of the key will change to three.
611
612```json
613{
614    "cause": "[two != one]",
615    "errorCode": 101,
616    "index": 8,
617    "message": "Compare failed"
618}
619```
620
621which means `CompareAndSwap` failed. `cause` explains why the test failed.
622Note: the condition prevIndex=0 always passes.
623
624Let's try a valid condition:
625
626```sh
627curl http://127.0.0.1:2379/v2/keys/foo?prevValue=one -XPUT -d value=two
628```
629
630The response should be:
631
632```json
633{
634    "action": "compareAndSwap",
635    "node": {
636        "createdIndex": 8,
637        "key": "/foo",
638        "modifiedIndex": 9,
639        "value": "two"
640    },
641    "prevNode": {
642    	"createdIndex": 8,
643    	"key": "/foo",
644    	"modifiedIndex": 8,
645    	"value": "one"
646    }
647}
648```
649
650We successfully changed the value from "one" to "two" since we gave the correct previous value.
651
652### Atomic Compare-and-Delete
653
654This command will delete a key only if the client-provided conditions are equal to the current conditions.
655
656*Note that `CompareAndDelete` does not work with [directories]. If an attempt is made to `CompareAndDelete` a directory, a 102 "Not a file" error will be returned.*
657
658The current comparable conditions are:
659
6601. `prevValue` - checks the previous value of the key.
661
6622. `prevIndex` - checks the previous modifiedIndex of the key.
663
664Here is a simple example. Let's first create a key: `foo=one`.
665
666```sh
667curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d value=one
668```
669
670Now let's try some `CompareAndDelete` commands.
671
672Trying to delete the key with `prevValue=two` fails as expected:
673```sh
674curl http://127.0.0.1:2379/v2/keys/foo?prevValue=two -XDELETE
675```
676
677The error code explains the problem:
678
679```json
680{
681	"errorCode": 101,
682	"message": "Compare failed",
683	"cause": "[two != one]",
684	"index": 8
685}
686```
687
688As does a `CompareAndDelete` with a mismatched `prevIndex`:
689
690```sh
691curl http://127.0.0.1:2379/v2/keys/foo?prevIndex=1 -XDELETE
692```
693
694```json
695{
696	"errorCode": 101,
697	"message": "Compare failed",
698	"cause": "[1 != 8]",
699	"index": 8
700}
701```
702
703And now a valid `prevValue` condition:
704
705```sh
706curl http://127.0.0.1:2379/v2/keys/foo?prevValue=one -XDELETE
707```
708
709The successful response will look something like:
710
711```json
712{
713	"action": "compareAndDelete",
714	"node": {
715		"key": "/foo",
716		"modifiedIndex": 9,
717		"createdIndex": 8
718	},
719	"prevNode": {
720		"key": "/foo",
721		"value": "one",
722		"modifiedIndex": 8,
723		"createdIndex": 8
724	}
725}
726```
727
728### Creating Directories
729
730In most cases, directories for a key are automatically created.
731But there are cases where you will want to create a directory or remove one.
732
733Creating a directory is just like a key except you cannot provide a value and must add the `dir=true` parameter.
734
735```sh
736curl http://127.0.0.1:2379/v2/keys/dir -XPUT -d dir=true
737```
738```json
739{
740    "action": "set",
741    "node": {
742        "createdIndex": 30,
743        "dir": true,
744        "key": "/dir",
745        "modifiedIndex": 30
746    }
747}
748```
749
750
751### Listing a directory
752
753In etcd we can store two types of things: keys and directories.
754Keys store a single string value.
755Directories store a set of keys and/or other directories.
756
757In this example, let's first create some keys:
758
759We already have `/foo=two` so now we'll create another one called `/foo_dir/foo` with the value of `bar`:
760
761```sh
762curl http://127.0.0.1:2379/v2/keys/foo_dir/foo -XPUT -d value=bar
763```
764
765```json
766{
767    "action": "set",
768    "node": {
769        "createdIndex": 2,
770        "key": "/foo_dir/foo",
771        "modifiedIndex": 2,
772        "value": "bar"
773    }
774}
775```
776
777Now we can list the keys under root `/`:
778
779```sh
780curl http://127.0.0.1:2379/v2/keys/
781```
782
783We should see the response as an array of items:
784
785```json
786{
787    "action": "get",
788    "node": {
789        "key": "/",
790        "dir": true,
791        "nodes": [
792            {
793                "key": "/foo_dir",
794                "dir": true,
795                "modifiedIndex": 2,
796                "createdIndex": 2
797            },
798            {
799                "key": "/foo",
800                "value": "two",
801                "modifiedIndex": 1,
802                "createdIndex": 1
803            }
804        ]
805    }
806}
807```
808
809Here we can see `/foo` is a key-value pair under `/` and `/foo_dir` is a directory.
810We can also recursively get all the contents under a directory by adding `recursive=true`.
811
812```sh
813curl http://127.0.0.1:2379/v2/keys/?recursive=true
814```
815
816```json
817{
818    "action": "get",
819    "node": {
820        "key": "/",
821        "dir": true,
822        "nodes": [
823            {
824                "key": "/foo_dir",
825                "dir": true,
826                "nodes": [
827                    {
828                        "key": "/foo_dir/foo",
829                        "value": "bar",
830                        "modifiedIndex": 2,
831                        "createdIndex": 2
832                    }
833                ],
834                "modifiedIndex": 2,
835                "createdIndex": 2
836            },
837            {
838                "key": "/foo",
839                "value": "two",
840                "modifiedIndex": 1,
841                "createdIndex": 1
842            }
843        ]
844    }
845}
846```
847
848
849### Deleting a Directory
850
851Now let's try to delete the directory `/foo_dir`.
852
853You can remove an empty directory using the `DELETE` verb and the `dir=true` parameter.
854
855```sh
856curl 'http://127.0.0.1:2379/v2/keys/foo_dir?dir=true' -XDELETE
857```
858```json
859{
860    "action": "delete",
861    "node": {
862        "createdIndex": 30,
863        "dir": true,
864        "key": "/foo_dir",
865        "modifiedIndex": 31
866    },
867    "prevNode": {
868    	"createdIndex": 30,
869    	"key": "/foo_dir",
870    	"dir": true,
871    	"modifiedIndex": 30
872    }
873}
874```
875
876To delete a directory that holds keys, you must add `recursive=true`.
877
878```sh
879curl http://127.0.0.1:2379/v2/keys/dir?recursive=true -XDELETE
880```
881
882```json
883{
884    "action": "delete",
885    "node": {
886        "createdIndex": 10,
887        "dir": true,
888        "key": "/dir",
889        "modifiedIndex": 11
890    },
891    "prevNode": {
892    	"createdIndex": 10,
893    	"dir": true,
894    	"key": "/dir",
895    	"modifiedIndex": 10
896    }
897}
898```
899
900
901### Creating a hidden node
902
903We can create a hidden key-value pair or directory by add a `_` prefix.
904The hidden item will not be listed when sending a `GET` request for a directory.
905
906First we'll add a hidden key named `/_message`:
907
908```sh
909curl http://127.0.0.1:2379/v2/keys/_message -XPUT -d value="Hello hidden world"
910```
911
912```json
913{
914    "action": "set",
915    "node": {
916        "createdIndex": 3,
917        "key": "/_message",
918        "modifiedIndex": 3,
919        "value": "Hello hidden world"
920    }
921}
922```
923
924Next we'll add a regular key named `/message`:
925
926```sh
927curl http://127.0.0.1:2379/v2/keys/message -XPUT -d value="Hello world"
928```
929
930```json
931{
932    "action": "set",
933    "node": {
934        "createdIndex": 4,
935        "key": "/message",
936        "modifiedIndex": 4,
937        "value": "Hello world"
938    }
939}
940```
941
942Now let's try to get a listing of keys under the root directory, `/`:
943
944```sh
945curl http://127.0.0.1:2379/v2/keys/
946```
947
948```json
949{
950    "action": "get",
951    "node": {
952        "dir": true,
953        "key": "/",
954        "nodes": [
955            {
956                "createdIndex": 2,
957                "dir": true,
958                "key": "/foo_dir",
959                "modifiedIndex": 2
960            },
961            {
962                "createdIndex": 4,
963                "key": "/message",
964                "modifiedIndex": 4,
965                "value": "Hello world"
966            }
967        ]
968    }
969}
970```
971
972Here we see the `/message` key but our hidden `/_message` key is not returned.
973
974### Setting a key from a file
975
976You can also use etcd to store small configuration files, JSON documents, XML documents, etc directly.
977For example you can use curl to upload a simple text file and encode it:
978
979```
980echo "Hello\nWorld" > afile.txt
981curl http://127.0.0.1:2379/v2/keys/afile -XPUT --data-urlencode value@afile.txt
982```
983
984```json
985{
986    "action": "get",
987    "node": {
988        "createdIndex": 2,
989        "key": "/afile",
990        "modifiedIndex": 2,
991        "value": "Hello\nWorld\n"
992    }
993}
994```
995
996### Read Linearization
997
998If you want a read that is fully linearized you can use a `quorum=true` GET.
999The read will take a very similar path to a write and will have a similar
1000speed. If you are unsure if you need this feature feel free to email etcd-dev
1001for advice.
1002
1003## Statistics
1004
1005An etcd cluster keeps track of a number of statistics including latency, bandwidth and uptime.
1006These are exposed via the statistics endpoint to understand the internal health of a cluster.
1007
1008### Leader Statistics
1009
1010The leader has a view of the entire cluster and keeps track of two interesting statistics: latency to each peer in the cluster, and the number of failed and successful Raft RPC requests.
1011You can grab these statistics from the `/v2/stats/leader` endpoint:
1012
1013```sh
1014curl http://127.0.0.1:2379/v2/stats/leader
1015```
1016
1017```json
1018{
1019    "followers": {
1020        "6e3bd23ae5f1eae0": {
1021            "counts": {
1022                "fail": 0,
1023                "success": 745
1024            },
1025            "latency": {
1026                "average": 0.017039507382550306,
1027                "current": 0.000138,
1028                "maximum": 1.007649,
1029                "minimum": 0,
1030                "standardDeviation": 0.05289178277920594
1031            }
1032        },
1033        "a8266ecf031671f3": {
1034            "counts": {
1035                "fail": 0,
1036                "success": 735
1037            },
1038            "latency": {
1039                "average": 0.012124141496598642,
1040                "current": 0.000559,
1041                "maximum": 0.791547,
1042                "minimum": 0,
1043                "standardDeviation": 0.04187900156583733
1044            }
1045        }
1046    },
1047    "leader": "924e2e83e93f2560"
1048}
1049```
1050
1051
1052### Self Statistics
1053
1054Each node keeps a number of internal statistics:
1055
1056- `id`: the unique identifier for the member
1057- `leaderInfo.leader`: id of the current leader member
1058- `leaderInfo.uptime`: amount of time the leader has been leader
1059- `name`: this member's name
1060- `recvAppendRequestCnt`: number of append requests this node has processed
1061- `recvBandwidthRate`: number of bytes per second this node is receiving (follower only)
1062- `recvPkgRate`: number of requests per second this node is receiving (follower only)
1063- `sendAppendRequestCnt`: number of requests that this node has sent
1064- `sendBandwidthRate`: number of bytes per second this node is sending (leader only). This value is undefined on single member clusters.
1065- `sendPkgRate`: number of requests per second this node is sending (leader only). This value is undefined on single member clusters.
1066- `state`: either leader or follower
1067- `startTime`: the time when this node was started
1068
1069This is an example response from a follower member:
1070
1071```sh
1072curl http://127.0.0.1:2379/v2/stats/self
1073```
1074
1075```json
1076{
1077    "id": "eca0338f4ea31566",
1078    "leaderInfo": {
1079        "leader": "8a69d5f6b7814500",
1080        "startTime": "2014-10-24T13:15:51.186620747-07:00",
1081        "uptime": "10m59.322358947s"
1082    },
1083    "name": "node3",
1084    "recvAppendRequestCnt": 5944,
1085    "recvBandwidthRate": 570.6254930219969,
1086    "recvPkgRate": 9.00892789741075,
1087    "sendAppendRequestCnt": 0,
1088    "startTime": "2014-10-24T13:15:50.072007085-07:00",
1089    "state": "StateFollower"
1090}
1091```
1092
1093And this is an example response from a leader member:
1094
1095```sh
1096curl http://127.0.0.1:2379/v2/stats/self
1097```
1098
1099```json
1100{
1101    "id": "924e2e83e93f2560",
1102    "leaderInfo": {
1103        "leader": "924e2e83e93f2560",
1104        "startTime": "2015-02-09T11:38:30.177534688-08:00",
1105        "uptime": "9m33.891343412s"
1106    },
1107    "name": "infra3",
1108    "recvAppendRequestCnt": 0,
1109    "sendAppendRequestCnt": 6535,
1110    "sendBandwidthRate": 824.1758351191694,
1111    "sendPkgRate": 11.111234716807138,
1112    "startTime": "2015-02-09T11:38:28.972034204-08:00",
1113    "state": "StateLeader"
1114}
1115```
1116
1117
1118### Store Statistics
1119
1120The store statistics include information about the operations that this node has handled.
1121Note that v2 `store Statistics` is stored in-memory. When a member stops, store statistics will reset on restart.
1122
1123Operations that modify the store's state like create, delete, set and update are seen by the entire cluster and the number will increase on all nodes.
1124Operations like get and watch are node local and will only be seen on this node.
1125
1126```sh
1127curl http://127.0.0.1:2379/v2/stats/store
1128```
1129
1130```json
1131{
1132    "compareAndSwapFail": 0,
1133    "compareAndSwapSuccess": 0,
1134    "createFail": 0,
1135    "createSuccess": 2,
1136    "deleteFail": 0,
1137    "deleteSuccess": 0,
1138    "expireCount": 0,
1139    "getsFail": 4,
1140    "getsSuccess": 75,
1141    "setsFail": 2,
1142    "setsSuccess": 4,
1143    "updateFail": 0,
1144    "updateSuccess": 0,
1145    "watchers": 0
1146}
1147```
1148
1149## Cluster Config
1150
1151See the [members API][members-api] for details on the cluster management.
1152
1153[directories]: #listing-a-directory
1154[members-api]: members_api.md
1155[tuning]: tuning.md
1156