github.com/sym3tri/etcd@v0.2.1-0.20140422215517-a563d82f95d6/Documentation/api.md (about)

     1  # etcd API
     2  
     3  ## Running a Single Machine Cluster
     4  
     5  These examples will use a single machine cluster to show you the basics of the etcd REST API.
     6  Let's start etcd:
     7  
     8  ```sh
     9  ./bin/etcd -data-dir machine0 -name machine0
    10  ```
    11  
    12  This will bring up etcd listening on default ports (4001 for client communication and 7001 for server-to-server communication).
    13  The `-data-dir machine0` argument tells etcd to write machine configuration, logs and snapshots to the `./machine0/` directory.
    14  The `-name machine0` tells the rest of the cluster that this machine is named machine0.
    15  
    16  ## Key Space Operations
    17  
    18  The primary API of etcd is a hierarchical key space.
    19  The key space consists of directories and keys which are generically referred to as "nodes".
    20  
    21  
    22  ### Setting the value of a key
    23  
    24  Let's set the first key-value pair in the datastore.
    25  In this case the key is `/message` and the value is `Hello world`.
    26  
    27  ```sh
    28  curl -L http://127.0.0.1:4001/v2/keys/message -XPUT -d value="Hello world"
    29  ```
    30  
    31  ```json
    32  {
    33      "action": "set",
    34      "node": {
    35          "createdIndex": 2,
    36          "key": "/message",
    37          "modifiedIndex": 2,
    38          "value": "Hello world"
    39      }
    40  }
    41  ```
    42  
    43  The response object contains several attributes:
    44  
    45  1. `action`: the action of the request that was just made.
    46  The request attempted to modify `node.value` via a `PUT` HTTP request, thus the value of action is `set`.
    47  
    48  2. `node.key`: the HTTP path to which the request was made.
    49  We set `/message` to `Hello world`, so the key field is `/message`.
    50  etcd uses a file-system-like structure to represent the key-value pairs, therefore all keys start with `/`.
    51  
    52  3. `node.value`: the value of the key after resolving the request.
    53  In this case, a successful request was made that attempted to change the node's value to `Hello world`.
    54  
    55  4. `node.createdIndex`: an index is a unique, monotonically-incrementing integer created for each change to etcd.
    56  This specific index reflects the point in the etcd state machine at which a given key was created.
    57  You may notice that in this example the index is `2` even though it is the first request you sent to the server.
    58  This is because there are internal commands that also change the state behind the scenes, like adding and syncing servers.
    59  
    60  5. `node.modifiedIndex`: like `node.createdIndex`, this attribute is also an etcd index.
    61  Actions that cause the value to change include `set`, `delete`, `update`, `create`, `compareAndSwap` and `compareAndDelete`.
    62  Since the `get` and `watch` commands do not change state in the store, they do not change the value of `node.modifiedIndex`.
    63  
    64  
    65  ### Response Headers
    66  
    67  etcd includes a few HTTP headers in responses that provide global information about the etcd cluster that serviced a request:
    68  
    69  ```
    70  X-Etcd-Index: 35
    71  X-Raft-Index: 5398
    72  X-Raft-Term: 0
    73  ```
    74  
    75  - `X-Etcd-Index` is the current etcd index as explained above.
    76  - `X-Raft-Index` is similar to the etcd index but is for the underlying raft protocol
    77  - `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.
    78  
    79  [tuning]: #tuning
    80  
    81  
    82  ### Get the value of a key
    83  
    84  We can get the value that we just set in `/message` by issuing a `GET` request:
    85  
    86  ```sh
    87  curl -L http://127.0.0.1:4001/v2/keys/message
    88  ```
    89  
    90  ```json
    91  {
    92      "action": "get",
    93      "node": {
    94          "createdIndex": 2,
    95          "key": "/message",
    96          "modifiedIndex": 2,
    97          "value": "Hello world"
    98      }
    99  }
   100  ```
   101  
   102  
   103  ### Changing the value of a key
   104  
   105  You can change the value of `/message` from `Hello world` to `Hello etcd` with another `PUT` request to the key:
   106  
   107  ```sh
   108  curl -L http://127.0.0.1:4001/v2/keys/message -XPUT -d value="Hello etcd"
   109  ```
   110  
   111  ```json
   112  {
   113      "action": "set",
   114      "node": {
   115          "createdIndex": 3,
   116          "key": "/message",
   117          "modifiedIndex": 3,
   118          "value": "Hello etcd"
   119      },
   120      "prevNode": {
   121      	"createdIndex": 2
   122      	"key": "/message",
   123      	"value": "Hello world",
   124      	"modifiedIndex": 2,
   125      }
   126  }
   127  ```
   128  
   129  Here 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.
   130  
   131  ### Deleting a key
   132  
   133  You can remove the `/message` key with a `DELETE` request:
   134  
   135  ```sh
   136  curl -L http://127.0.0.1:4001/v2/keys/message -XDELETE
   137  ```
   138  
   139  ```json
   140  {
   141      "action": "delete",
   142      "node": {
   143          "createdIndex": 3,
   144          "key": "/message",
   145          "modifiedIndex": 4
   146      },
   147      "prevNode": {
   148      	"key": "/message",
   149      	"value": "Hello etcd",
   150      	"modifiedIndex": 3,
   151      	"createdIndex": 3
   152      }
   153  }
   154  ```
   155  
   156  
   157  ### Using key TTL
   158  
   159  Keys in etcd can be set to expire after a specified number of seconds.
   160  You can do this by setting a TTL (time to live) on the key when sending a `PUT` request:
   161  
   162  ```sh
   163  curl -L http://127.0.0.1:4001/v2/keys/foo -XPUT -d value=bar -d ttl=5
   164  ```
   165  
   166  ```json
   167  {
   168      "action": "set",
   169      "node": {
   170          "createdIndex": 5,
   171          "expiration": "2013-12-04T12:01:21.874888581-08:00",
   172          "key": "/foo",
   173          "modifiedIndex": 5,
   174          "ttl": 5,
   175          "value": "bar"
   176      }
   177  }
   178  ```
   179  
   180  Note the two new fields in response:
   181  
   182  1. The `expiration` is the time at which this key will expire and be deleted.
   183  
   184  2. The `ttl` is the specified time to live for the key, in seconds.
   185  
   186  _NOTE_: Keys can only be expired by a cluster leader, so if a machine gets disconnected from the cluster, its keys will not expire until it rejoins.
   187  
   188  Now you can try to get the key by sending a `GET` request:
   189  
   190  ```sh
   191  curl -L http://127.0.0.1:4001/v2/keys/foo
   192  ```
   193  
   194  If the TTL has expired, the key will have been deleted, and you will be returned a 100.
   195  
   196  ```json
   197  {
   198      "cause": "/foo",
   199      "errorCode": 100,
   200      "index": 6,
   201      "message": "Key Not Found"
   202  }
   203  ```
   204  
   205  The TTL could be unset to avoid expiration through update operation:
   206  
   207  ```sh
   208  curl -L http://127.0.0.1:4001/v2/keys/foo -XPUT -d value=bar -d ttl= -d prevExist=true
   209  ```
   210  
   211  ```json
   212  {
   213      "action": "update",
   214      "node": {
   215          "createdIndex": 5,
   216          "key": "/foo",
   217          "modifiedIndex": 6,
   218          "value": "bar"
   219      }
   220      "prevNode": {
   221          "createdIndex": 5,
   222          "expiration": "2013-12-04T12:01:21.874888581-08:00",
   223          "key": "/foo",
   224          "modifiedIndex": 5,
   225          "ttl": 3,
   226          "value": "bar"
   227      }
   228  }
   229  ```
   230  
   231  
   232  ### Waiting for a change
   233  
   234  We can watch for a change on a key and receive a notification by using long polling.
   235  This also works for child keys by passing `recursive=true` in curl.
   236  
   237  In one terminal, we send a `GET` with `wait=true` :
   238  
   239  ```sh
   240  curl -L http://127.0.0.1:4001/v2/keys/foo?wait=true
   241  ```
   242  
   243  Now we are waiting for any changes at path `/foo`.
   244  
   245  In another terminal, we set a key `/foo` with value `bar`:
   246  
   247  ```sh
   248  curl -L http://127.0.0.1:4001/v2/keys/foo -XPUT -d value=bar
   249  ```
   250  
   251  The first terminal should get the notification and return with the same response as the set request:
   252  
   253  ```json
   254  {
   255      "action": "set",
   256      "node": {
   257          "createdIndex": 7,
   258          "key": "/foo",
   259          "modifiedIndex": 7,
   260          "value": "bar"
   261      },
   262      "prevNode": {
   263          "createdIndex": 6,
   264          "key": "/foo",
   265          "modifiedIndex": 6,
   266          "value": "bar"
   267      }
   268  }
   269  ```
   270  
   271  However, the watch command can do more than this.
   272  Using the index, we can watch for commands that have happened in the past.
   273  This is useful for ensuring you don't miss events between watch commands.
   274  
   275  Let's try to watch for the set command of index 7 again:
   276  
   277  ```sh
   278  curl -L 'http://127.0.0.1:4001/v2/keys/foo?wait=true&waitIndex=7'
   279  ```
   280  
   281  The watch command returns immediately with the same response as previously.
   282  
   283  
   284  ### Atomically Creating In-Order Keys
   285  
   286  Using `POST` on a directory, you can create keys with key names that are created in-order.
   287  This can be used in a variety of useful patterns, like implementing queues of keys which need to be processed in strict order.
   288  An example use case is the [locking module][lockmod] which uses it to ensure clients get fair access to a mutex.
   289  
   290  Creating an in-order key is easy:
   291  
   292  ```sh
   293  curl http://127.0.0.1:4001/v2/keys/queue -XPOST -d value=Job1
   294  ```
   295  
   296  ```json
   297  {
   298      "action": "create",
   299      "node": {
   300          "createdIndex": 6,
   301          "key": "/queue/6",
   302          "modifiedIndex": 6,
   303          "value": "Job1"
   304      }
   305  }
   306  ```
   307  
   308  If you create another entry some time later, it is guaranteed to have a key name that is greater than the previous key.
   309  Also note the key names use the global etcd index, so the next key can be more than `previous + 1`.
   310  
   311  ```sh
   312  curl http://127.0.0.1:4001/v2/keys/queue -XPOST -d value=Job2
   313  ```
   314  
   315  ```json
   316  {
   317      "action": "create",
   318      "node": {
   319          "createdIndex": 29,
   320          "key": "/queue/29",
   321          "modifiedIndex": 29,
   322          "value": "Job2"
   323      }
   324  }
   325  ```
   326  
   327  To enumerate the in-order keys as a sorted list, use the "sorted" parameter.
   328  
   329  ```sh
   330  curl -s 'http://127.0.0.1:4001/v2/keys/queue?recursive=true&sorted=true'
   331  ```
   332  
   333  ```json
   334  {
   335      "action": "get",
   336      "node": {
   337          "createdIndex": 2,
   338          "dir": true,
   339          "key": "/queue",
   340          "modifiedIndex": 2,
   341          "nodes": [
   342              {
   343                  "createdIndex": 2,
   344                  "key": "/queue/2",
   345                  "modifiedIndex": 2,
   346                  "value": "Job1"
   347              },
   348              {
   349                  "createdIndex": 3,
   350                  "key": "/queue/3",
   351                  "modifiedIndex": 3,
   352                  "value": "Job2"
   353              }
   354          ]
   355      }
   356  }
   357  ```
   358  
   359  [lockmod]: #lock
   360  
   361  
   362  ### Using a directory TTL
   363  
   364  Like keys, directories in etcd can be set to expire after a specified number of seconds.
   365  You can do this by setting a TTL (time to live) on a directory when it is created with a `PUT`:
   366  
   367  ```sh
   368  curl -L http://127.0.0.1:4001/v2/keys/dir -XPUT -d ttl=30 -d dir=true
   369  ```
   370  
   371  ```json
   372  {
   373      "action": "set",
   374      "node": {
   375          "createdIndex": 17,
   376          "dir": true,
   377          "expiration": "2013-12-11T10:37:33.689275857-08:00",
   378          "key": "/newdir",
   379          "modifiedIndex": 17,
   380          "ttl": 30
   381      }
   382  }
   383  ```
   384  
   385  The directory's TTL can be refreshed by making an update.
   386  You can do this by making a PUT with `prevExist=true` and a new TTL.
   387  
   388  ```sh
   389  curl -L http://127.0.0.1:4001/v2/keys/dir -XPUT -d ttl=30 -d dir=true -d prevExist=true
   390  ```
   391  
   392  Keys 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:
   393  
   394  ```sh
   395  curl 'http://127.0.0.1:4001/v2/keys/dir/asdf?consistent=true&wait=true'
   396  ```
   397  
   398  ```json
   399  {
   400  	"action": "expire",
   401  	"node": {
   402  		"createdIndex": 8,
   403  		"key": "/dir",
   404  		"modifiedIndex": 15
   405  	},
   406  	"prevNode": {
   407  		"createdIndex": 8,
   408  		"key": "/dir",
   409  		"dir":true,
   410  		"modifiedIndex": 17,
   411  		"expiration": "2013-12-11T10:39:35.689275857-08:00"
   412  	},
   413  }
   414  ```
   415  
   416  
   417  ### Atomic Compare-and-Swap
   418  
   419  etcd 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.
   420  
   421  This command will set the value of a key only if the client-provided conditions are equal to the current conditions.
   422  
   423  The current comparable conditions are:
   424  
   425  1. `prevValue` - checks the previous value of the key.
   426  
   427  2. `prevIndex` - checks the previous modifiedIndex of the key.
   428  
   429  3. `prevExist` - checks existence of the key: if `prevExist` is true, it is an `update` request; if prevExist is `false`, it is a `create` request.
   430  
   431  Here is a simple example.
   432  Let's create a key-value pair first: `foo=one`.
   433  
   434  ```sh
   435  curl -L http://127.0.0.1:4001/v2/keys/foo -XPUT -d value=one
   436  ```
   437  
   438  Now let's try some invalid `CompareAndSwap` commands.
   439  
   440  Trying to set this existing key with `prevExist=false` fails as expected:
   441  ```sh
   442  curl -L http://127.0.0.1:4001/v2/keys/foo?prevExist=false -XPUT -d value=three
   443  ```
   444  
   445  The error code explains the problem:
   446  
   447  ```json
   448  {
   449      "cause": "/foo",
   450      "errorCode": 105,
   451      "index": 39776,
   452      "message": "Already exists"
   453  }
   454  ```
   455  
   456  Now let's provide a `prevValue` parameter:
   457  
   458  ```sh
   459  curl -L http://127.0.0.1:4001/v2/keys/foo?prevValue=two -XPUT -d value=three
   460  ```
   461  
   462  This 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.
   463  
   464  ```json
   465  {
   466      "cause": "[two != one]",
   467      "errorCode": 101,
   468      "index": 8,
   469      "message": "Test Failed"
   470  }
   471  ```
   472  
   473  which means `CompareAndSwap` failed. `cause` explains why the test failed.
   474  Note: the condition prevIndex=0 always passes.
   475  
   476  Let's try a valid condition:
   477  
   478  ```sh
   479  curl -L http://127.0.0.1:4001/v2/keys/foo?prevValue=one -XPUT -d value=two
   480  ```
   481  
   482  The response should be:
   483  
   484  ```json
   485  {
   486      "action": "compareAndSwap",
   487      "node": {
   488          "createdIndex": 8,
   489          "key": "/foo",
   490          "modifiedIndex": 9,
   491          "value": "two"
   492      },
   493      "prevNode": {
   494      	"createdIndex": 8,
   495      	"key": "/foo",
   496      	"modifiedIndex": 8,
   497      	"value": "one"
   498      }
   499  }
   500  ```
   501  
   502  We successfully changed the value from "one" to "two" since we gave the correct previous value.
   503  
   504  ### Atomic Compare-and-Delete
   505  
   506  This command will delete a key only if the client-provided conditions are equal to the current conditions.
   507  
   508  The current comparable conditions are:
   509  
   510  1. `prevValue` - checks the previous value of the key.
   511  
   512  2. `prevIndex` - checks the previous modifiedIndex of the key.
   513  
   514  Here is a simple example. Let's first create a key: `foo=one`.
   515  
   516  ```sh
   517  curl -L http://127.0.0.1:4001/v2/keys/foo -XPUT -d value=one
   518  ```
   519  
   520  Now let's try some `CompareAndDelete` commands.
   521  
   522  Trying to delete the key with `prevValue=two` fails as expected:
   523  ```sh
   524  curl -L http://127.0.0.1:4001/v2/keys/foo?prevValue=two -XDELETE
   525  ```
   526  
   527  The error code explains the problem:
   528  
   529  ```json
   530  {
   531  	"errorCode": 101,
   532  	"message": "Compare failed",
   533  	"cause": "[two != one]",
   534  	"index": 8
   535  }
   536  ```
   537  
   538  As does a `CompareAndDelete` with a mismatched `prevIndex`:
   539  
   540  ```sh
   541  curl -L http://127.0.0.1:4001/v2/keys/foo?prevIndex=1 -XDELETE
   542  ```
   543  
   544  ```json
   545  {
   546  	"errorCode": 101,
   547  	"message": "Compare failed",
   548  	"cause": "[1 != 8]",
   549  	"index": 8
   550  }
   551  ```
   552  
   553  And now a valid `prevValue` condition:
   554  
   555  ```sh
   556  curl -L http://127.0.0.1:4001/v2/keys/foo?prevValue=one -XDELETE
   557  ```
   558  
   559  The successful response will look something like:
   560  
   561  ```json
   562  {
   563  	"action": "compareAndDelete",
   564  	"node": {
   565  		"key": "/foo",
   566  		"modifiedIndex": 9,
   567  		"createdIndex": 8
   568  	},
   569  	"prevNode": {
   570  		"key": "/foo",
   571  		"value": "one",
   572  		"modifiedIndex": 8,
   573  		"createdIndex": 8
   574  	}
   575  }
   576  ```
   577  
   578  ### Creating Directories
   579  
   580  In most cases, directories for a key are automatically created.
   581  But there are cases where you will want to create a directory or remove one.
   582  
   583  Creating a directory is just like a key except you cannot provide a value and must add the `dir=true` parameter.
   584  
   585  ```sh
   586  curl -L http://127.0.0.1:4001/v2/keys/dir -XPUT -d dir=true
   587  ```
   588  ```json
   589  {
   590      "action": "set",
   591      "node": {
   592          "createdIndex": 30,
   593          "dir": true,
   594          "key": "/dir",
   595          "modifiedIndex": 30
   596      }
   597  }
   598  ```
   599  
   600  
   601  ### Listing a directory
   602  
   603  In etcd we can store two types of things: keys and directories.
   604  Keys store a single string value.
   605  Directories store a set of keys and/or other directories.
   606  
   607  In this example, let's first create some keys:
   608  
   609  We already have `/foo=two` so now we'll create another one called `/foo_dir/foo` with the value of `bar`:
   610  
   611  ```sh
   612  curl -L http://127.0.0.1:4001/v2/keys/foo_dir/foo -XPUT -d value=bar
   613  ```
   614  
   615  ```json
   616  {
   617      "action": "set",
   618      "node": {
   619          "createdIndex": 2,
   620          "key": "/foo_dir/foo",
   621          "modifiedIndex": 2,
   622          "value": "bar"
   623      }
   624  }
   625  ```
   626  
   627  Now we can list the keys under root `/`:
   628  
   629  ```sh
   630  curl -L http://127.0.0.1:4001/v2/keys/
   631  ```
   632  
   633  We should see the response as an array of items:
   634  
   635  ```json
   636  {
   637      "action": "get",
   638      "node": {
   639          "dir": true,
   640          "key": "/",
   641          "nodes": [
   642              {
   643                  "createdIndex": 2,
   644                  "dir": true,
   645                  "key": "/foo_dir",
   646                  "modifiedIndex": 2
   647              }
   648          ]
   649      }
   650  }
   651  ```
   652  
   653  Here we can see `/foo` is a key-value pair under `/` and `/foo_dir` is a directory.
   654  We can also recursively get all the contents under a directory by adding `recursive=true`.
   655  
   656  ```sh
   657  curl -L http://127.0.0.1:4001/v2/keys/?recursive=true
   658  ```
   659  
   660  ```json
   661  {
   662      "action": "get",
   663      "node": {
   664          "dir": true,
   665          "key": "/",
   666          "nodes": [
   667              {
   668                  "createdIndex": 2,
   669                  "dir": true,
   670                  "key": "/foo_dir",
   671                  "modifiedIndex": 2,
   672                  "nodes": [
   673                      {
   674                          "createdIndex": 2,
   675                          "key": "/foo_dir/foo",
   676                          "modifiedIndex": 2,
   677                          "value": "bar"
   678                      }
   679                  ]
   680              }
   681          ]
   682      }
   683  }
   684  ```
   685  
   686  
   687  ### Deleting a Directory
   688  
   689  Now let's try to delete the directory `/foo_dir`.
   690  
   691  You can remove an empty directory using the `DELETE` verb and the `dir=true` parameter.
   692  
   693  ```sh
   694  curl -L 'http://127.0.0.1:4001/v2/keys/foo_dir?dir=true' -XDELETE
   695  ```
   696  ```json
   697  {
   698      "action": "delete",
   699      "node": {
   700          "createdIndex": 30,
   701          "dir": true,
   702          "key": "/foo_dir",
   703          "modifiedIndex": 31
   704      },
   705      "prevNode": {
   706      	"createdIndex": 30,
   707      	"key": "/foo_dir",
   708      	"dir": true,
   709      	"modifiedIndex": 30
   710      }
   711  }
   712  ```
   713  
   714  To delete a directory that holds keys, you must add `recursive=true`.
   715  
   716  ```sh
   717  curl -L http://127.0.0.1:4001/v2/keys/dir?recursive=true -XDELETE
   718  ```
   719  
   720  ```json
   721  {
   722      "action": "delete",
   723      "node": {
   724          "createdIndex": 10,
   725          "dir": true,
   726          "key": "/dir",
   727          "modifiedIndex": 11
   728      },
   729      "prevNode": {
   730      	"createdIndex": 10,
   731      	"dir": true,
   732      	"key": "/dir",
   733      	"modifiedIndex": 10
   734      }
   735  }
   736  ```
   737  
   738  
   739  ### Creating a hidden node
   740  
   741  We can create a hidden key-value pair or directory by add a `_` prefix.
   742  The hidden item will not be listed when sending a `GET` request for a directory.
   743  
   744  First we'll add a hidden key named `/_message`:
   745  
   746  ```sh
   747  curl -L http://127.0.0.1:4001/v2/keys/_message -XPUT -d value="Hello hidden world"
   748  ```
   749  
   750  ```json
   751  {
   752      "action": "set",
   753      "node": {
   754          "createdIndex": 3,
   755          "key": "/_message",
   756          "modifiedIndex": 3,
   757          "value": "Hello hidden world"
   758      }
   759  }
   760  ```
   761  
   762  Next we'll add a regular key named `/message`:
   763  
   764  ```sh
   765  curl -L http://127.0.0.1:4001/v2/keys/message -XPUT -d value="Hello world"
   766  ```
   767  
   768  ```json
   769  {
   770      "action": "set",
   771      "node": {
   772          "createdIndex": 4,
   773          "key": "/message",
   774          "modifiedIndex": 4,
   775          "value": "Hello world"
   776      }
   777  }
   778  ```
   779  
   780  Now let's try to get a listing of keys under the root directory, `/`:
   781  
   782  ```sh
   783  curl -L http://127.0.0.1:4001/v2/keys/
   784  ```
   785  
   786  ```json
   787  {
   788      "action": "get",
   789      "node": {
   790          "dir": true,
   791          "key": "/",
   792          "nodes": [
   793              {
   794                  "createdIndex": 2,
   795                  "dir": true,
   796                  "key": "/foo_dir",
   797                  "modifiedIndex": 2
   798              },
   799              {
   800                  "createdIndex": 4,
   801                  "key": "/message",
   802                  "modifiedIndex": 4,
   803                  "value": "Hello world"
   804              }
   805          ]
   806      }
   807  }
   808  ```
   809  
   810  Here we see the `/message` key but our hidden `/_message` key is not returned.
   811  
   812  ### Setting a key from a file
   813  
   814  You can also use etcd to store small configuration files, json documents, XML documents, etc directly.
   815  For example you can use curl to upload a simple text file and encode it:
   816  
   817  ```
   818  echo "Hello\nWorld" > afile.txt
   819  curl -L http://127.0.0.1:4001/v2/keys/afile -XPUT --data-urlencode value@afile.txt
   820  ```
   821  
   822  ```json
   823  {
   824      "action": "get",
   825      "node": {
   826          "createdIndex": 2,
   827          "key": "/afile",
   828          "modifiedIndex": 2,
   829          "value": "Hello\nWorld\n"
   830      }
   831  }
   832  ```
   833  
   834  ### Read Consistency
   835  
   836  Followers in a cluster can be behind the leader in their copy of the keyspace.
   837  If your application wants or needs the most up-to-date version of a key then it should ensure it reads from the current leader.
   838  By using the `consistent=true` flag in your GET requests, etcd will make sure you are talking to the current master.
   839  
   840  As an example of how a machine can be behind the leader let's start with a three machine cluster: L, F1, and F2.
   841  A client makes a write to L and F1 acknowledges the request.
   842  The client is told the write was successful and the keyspace is updated.
   843  Meanwhile F2 has partitioned from the network and will have an out-of-date version of the keyspace until the partition resolves.
   844  Since F2 missed the most recent write, a client reading from F2 will have an out-of-date version of the keyspace.
   845  
   846  ## Lock Module (*Deprecated*)
   847  
   848  The lock module is used to serialize access to resources used by clients.
   849  Multiple clients can attempt to acquire a lock but only one can have it at a time.
   850  Once the lock is released, the next client waiting for the lock will receive it.
   851  
   852  **Warning:** This module is deprecated at v0.4. See [Modules][modules] for more details.
   853  
   854  
   855  ### Acquiring a Lock
   856  
   857  To acquire a lock, simply send a `POST` request to the lock module with the lock name and TTL:
   858  
   859  ```sh
   860  curl -L http://127.0.0.1:4001/mod/v2/lock/mylock -XPOST -d ttl=20
   861  ```
   862  
   863  You will receive the lock index when you acquire the lock:
   864  
   865  ```
   866  2
   867  ```
   868  
   869  If the TTL is not specified or is not a number then you'll receive the following error:
   870  
   871  ```json
   872  {
   873      "errorCode": 202,
   874      "message": "The given TTL in POST form is not a number",
   875      "cause": "Acquire",
   876  }
   877  ```
   878  
   879  If you specify a timeout that is not a number then you'll receive the following error:
   880  
   881  ```json
   882  {
   883      "errorCode": 205,
   884      "message": "The given timeout in POST form is not a number",
   885      "cause": "Acquire",
   886  }
   887  ```
   888  
   889  
   890  ### Renewing a Lock
   891  
   892  To extend the TTL of an already acquired lock, simply repeat your original request but with a `PUT` and the lock index instead:
   893  
   894  ```sh
   895  curl -L http://127.0.0.1:4001/mod/v2/lock/mylock -XPUT -d index=5 -d ttl=20
   896  ```
   897  
   898  If the index or value is not specified then you'll receive the following error:
   899  
   900  ```json
   901  {
   902      "errorCode": 207,
   903      "message": "Index or value is required",
   904      "cause": "Renew",
   905  }
   906  ```
   907  
   908  If the index or value does not exist then you'll receive the following error with a `404 Not Found` HTTP code:
   909  
   910  ```json
   911  {
   912      "errorCode": 100,
   913      "message": "Key not found",
   914      "index": 1
   915  }
   916  ```
   917  
   918  If the TTL is not specified or is not a number then you'll receive the following error:
   919  
   920  ```json
   921  {
   922      "errorCode": 202,
   923      "message": "The given TTL in POST form is not a number",
   924      "cause": "Renew",
   925  }
   926  ```
   927  
   928  
   929  ### Releasing a Lock
   930  
   931  When the client is finished with the lock, simply send a `DELETE` request to release the lock:
   932  
   933  ```sh
   934  curl -L http://127.0.0.1:4001/mod/v2/lock/mylock?index=5 -XDELETE
   935  ```
   936  
   937  If the index or value is not specified then you'll receive the following error:
   938  
   939  ```json
   940  {
   941      "errorCode": 207,
   942      "message": "Index or value is required",
   943      "cause": "Release",
   944  }
   945  ```
   946  
   947  If the index and value are both specified then you'll receive the following error:
   948  
   949  ```json
   950  {
   951      "errorCode": 208,
   952      "message": "Index and value cannot both be specified",
   953      "cause": "Release",
   954  }
   955  ```
   956  
   957  If the index or value does not exist then you'll receive the following error with a `404 Not Found` HTTP code:
   958  
   959  ```json
   960  {
   961      "errorCode": 100,
   962      "message": "Key not found",
   963      "index": 1
   964  }
   965  ```
   966  
   967  
   968  ### Retrieving a Lock
   969  
   970  To determine the current value or index of a lock, send a `GET` request to the lock.
   971  You can specify a `field` of `index` or `value`.
   972  The default is `value`.
   973  
   974  ```sh
   975  curl -L http://127.0.0.1:4001/mod/v2/lock/mylock?field=index
   976  ```
   977  
   978  Will return the current index:
   979  
   980  ```sh
   981  2
   982  ```
   983  
   984  If you specify a field other than `index` or `value` then you'll receive the following error:
   985  
   986  ```json
   987  {
   988      "errorCode": 209,
   989      "message": "Invalid field",
   990      "cause": "Get",
   991  }
   992  ```
   993  
   994  
   995  ## Leader Module (*Deprecated*)
   996  
   997  The leader module wraps the lock module to provide a simple interface for electing a single leader in a cluster.
   998  
   999  **Warning:** This module is deprecated at v0.4. See [Modules][modules] for more details.
  1000  [modules]: https://github.com/coreos/etcd/blob/master/Documentation/modules.md
  1001  
  1002  
  1003  ### Setting the Leader
  1004  
  1005  A client can attempt to become leader by sending a `PUT` request to the leader module with the name of the leader to elect:
  1006  
  1007  ```sh
  1008  curl -L http://127.0.0.1:4001/mod/v2/leader/myclustername -XPUT -d ttl=300 -d name=foo.mydomain.com
  1009  ```
  1010  
  1011  You will receive a successful `200` HTTP response code when the leader is elected.
  1012  
  1013  If the name is not specified then you'll receive the following error:
  1014  
  1015  ```json
  1016  {
  1017      "errorCode": 206,
  1018      "message": "Name is required in POST form",
  1019      "cause": "Set",
  1020  }
  1021  ```
  1022  
  1023  You can also receive any errors specified by the Lock module.
  1024  
  1025  
  1026  ### Retrieving the Current Leader
  1027  
  1028  A client can check to determine if there is a current leader by sending a `GET` request to the leader module:
  1029  
  1030  ```sh
  1031  curl -L http://127.0.0.1:4001/mod/v2/leader/myclustername
  1032  ```
  1033  
  1034  You will receive the name of the current leader:
  1035  
  1036  ```sh
  1037  foo.mydomain.com
  1038  ```
  1039  
  1040  
  1041  ### Relinquishing Leadership
  1042  
  1043  A client can give up leadership by sending a `DELETE` request with the leader name:
  1044  
  1045  ```sh
  1046  curl -L http://127.0.0.1:4001/mod/v2/leader/myclustername?name=foo.mydomain.com -XDELETE
  1047  ```
  1048  
  1049  If the name is not specified then you'll receive the following error:
  1050  
  1051  ```json
  1052  {
  1053      "errorCode": 206,
  1054      "message": "Name is required in POST form",
  1055      "cause": "Set",
  1056  }
  1057  ```
  1058  
  1059  
  1060  ## Statistics
  1061  
  1062  An etcd cluster keeps track of a number of statistics including latency, bandwidth and uptime.
  1063  These statistics are used in the `/mod/dashboard` endpoint to generate tables and graphs about the cluster state.
  1064  
  1065  
  1066  ### Leader Statistics
  1067  
  1068  The 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.
  1069  You can grab these statistics from the `/v2/stats/leader` endpoint:
  1070  
  1071  ```sh
  1072  curl -L http://127.0.0.1:4001/v2/stats/leader
  1073  ```
  1074  
  1075  ```json
  1076  {
  1077      "followers": {
  1078          "etcd-node1": {
  1079              "counts": {
  1080                  "fail": 1212,
  1081                  "success": 4163176
  1082              },
  1083              "latency": {
  1084                  "average": 2.7206299430775007,
  1085                  "current": 1.486487,
  1086                  "maximum": 2018.410279,
  1087                  "minimum": 1.011763,
  1088                  "standardDeviation": 6.246990702203536
  1089              }
  1090          },
  1091          "etcd-node3": {
  1092              "counts": {
  1093                  "fail": 1378,
  1094                  "success": 4164598
  1095              },
  1096              "latency": {
  1097                  "average": 2.707100125761001,
  1098                  "current": 1.666258,
  1099                  "maximum": 1409.054765,
  1100                  "minimum": 0.998415,
  1101                  "standardDeviation": 5.910089773061448
  1102              }
  1103          }
  1104      },
  1105      "leader": "etcd-node2"
  1106  }
  1107  ```
  1108  
  1109  
  1110  ### Self Statistics
  1111  
  1112  Each node keeps a number of internal statistics:
  1113  
  1114  - `leaderInfo.leader`: name of the current leader machine
  1115  - `leaderInfo.uptime`: amount of time the leader has been leader
  1116  - `name`: this machine's name
  1117  - `recvAppendRequestCnt`: number of append requests this node has processed
  1118  - `recvBandwidthRate`: number of bytes per second this node is receiving (follower only)
  1119  - `recvPkgRate`: number of requests per second this node is receiving (follower only)
  1120  - `sendAppendRequestCnt`: number of requests that this node has sent
  1121  - `sendBandwidthRate`: number of bytes per second this node is receiving (leader only). This value is undefined on single machine clusters.
  1122  - `sendPkgRate`: number of requests per second this node is receiving (leader only). This value is undefined on single machine clusters.
  1123  - `state`: either leader or follower
  1124  - `startTime`: the time when this node was started
  1125  
  1126  This is an example response from a follower machine:
  1127  
  1128  ```sh
  1129  curl -L http://127.0.0.1:4001/v2/stats/self
  1130  ```
  1131  
  1132  ```json
  1133  {
  1134      "leaderInfo": {
  1135          "leader": "machine1",
  1136          "uptime": "1m18.544996775s"
  1137      },
  1138      "name": "machine0",
  1139      "recvAppendRequestCnt": 5871307,
  1140      "recvBandwidthRate": 630.3121596542599,
  1141      "recvPkgRate": 19.272654323628185,
  1142      "sendAppendRequestCnt": 3175763,
  1143      "startTime": "2014-01-01T15:26:24.96569404Z",
  1144      "state": "follower"
  1145  }
  1146  ```
  1147  
  1148  And this is an example response from a leader machine:
  1149  
  1150  ```sh
  1151  curl -L http://127.0.0.1:4001/v2/stats/self
  1152  ```
  1153  
  1154  ```json
  1155  {
  1156      "leaderInfo": {
  1157          "leader": "machine0",
  1158          "uptime": "24.648619798s"
  1159      },
  1160      "name": "machine0",
  1161      "recvAppendRequestCnt": 5901116,
  1162      "sendAppendRequestCnt": 3212344,
  1163      "sendBandwidthRate": 1254.3151237301615,
  1164      "sendPkgRate": 38.71342974475808,
  1165      "startTime": "2014-01-01T15:26:24.96569404Z",
  1166      "state": "leader"
  1167  }
  1168  ```
  1169  
  1170  
  1171  ### Store Statistics
  1172  
  1173  The store statistics include information about the operations that this node has handled.
  1174  
  1175  Operations 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.
  1176  Operations like get and watch are node local and will only be seen on this node.
  1177  
  1178  ```sh
  1179  curl -L http://127.0.0.1:4001/v2/stats/store
  1180  ```
  1181  
  1182  ```json
  1183  {
  1184      "compareAndSwapFail": 0,
  1185      "compareAndSwapSuccess": 0,
  1186      "createFail": 0,
  1187      "createSuccess": 2,
  1188      "deleteFail": 0,
  1189      "deleteSuccess": 0,
  1190      "expireCount": 0,
  1191      "getsFail": 4,
  1192      "getsSuccess": 75,
  1193      "setsFail": 2,
  1194      "setsSuccess": 4,
  1195      "updateFail": 0,
  1196      "updateSuccess": 0,
  1197      "watchers": 0
  1198  }
  1199  ```