Compare commits
1398 Commits
Author | SHA1 | Date | |
---|---|---|---|
9970141f76 | |||
16c2bcf951 | |||
868b7f7902 | |||
1c958f8fc3 | |||
dfeecd2537 | |||
ed58193ebe | |||
79c650d900 | |||
a451cf2333 | |||
3455431da3 | |||
9424a10f49 | |||
fbcfe8e1c4 | |||
757bb3af13 | |||
2cd367e9d9 | |||
a974bbfe4f | |||
99dcc8c322 | |||
3d2523e7e0 | |||
25e69d9659 | |||
707174b56a | |||
ce92cc3dc5 | |||
5bfbf3a48c | |||
e04a188358 | |||
a51fda3e5e | |||
ca44801650 | |||
2387ef3f21 | |||
d5bfca9465 | |||
7cb126967c | |||
444e017c05 | |||
356675b70f | |||
d7768635fd | |||
37796ed84c | |||
f007cf321d | |||
ca29691543 | |||
4bebb538eb | |||
c27db1ec5e | |||
a5fc1d214d | |||
1df0b941d7 | |||
3a71eb9d72 | |||
001cceb1cd | |||
98ff4af7f2 | |||
db4c5e0eaa | |||
b3c5ed60bd | |||
673d90728e | |||
22c944d8ef | |||
a2d16b52bb | |||
b637b3a607 | |||
0eba3c9000 | |||
c3aab42959 | |||
62560f9959 | |||
3c04f8b664 | |||
cc37c58103 | |||
07d1eb0edb | |||
9a006d673b | |||
6860bfdd28 | |||
aaedf32c04 | |||
16d89c906b | |||
516ebdb49e | |||
1e7a7b11dd | |||
4c953a7ca2 | |||
934c28d498 | |||
0c8b13c04f | |||
9e5b12f591 | |||
189fece683 | |||
ad27aa0f70 | |||
dffe460210 | |||
b4e4bf4b75 | |||
e9482167a8 | |||
cbcf55dabb | |||
1084e51320 | |||
ad9155c82a | |||
84f71b6c87 | |||
d2d68f96fc | |||
71679bcf56 | |||
a824be4c14 | |||
35cc81e22f | |||
716496ec42 | |||
e5ce4fca2e | |||
9940347eea | |||
d2a2cc13b0 | |||
b7d9fdbd39 | |||
7cf8a4a8d0 | |||
851026362a | |||
fc77b3e9e6 | |||
f6591b95c7 | |||
403f709ebd | |||
cbb706cd47 | |||
c0027bfc78 | |||
735ffb3092 | |||
6a64141962 | |||
5367c1c998 | |||
c6b1a738c3 | |||
6d4f018887 | |||
765cd5d8b3 | |||
baadf63912 | |||
5bd08a327d | |||
f1c13e2d9d | |||
6c950eaf97 | |||
5c7a963cf0 | |||
c92231c91a | |||
e960a0e03c | |||
015d228b04 | |||
e31249fa22 | |||
b3e66ee980 | |||
af33d61774 | |||
bc4a98c386 | |||
fb17ccf5ee | |||
04f09d2fd0 | |||
6450d6dfb9 | |||
0558b546ff | |||
5465201292 | |||
ae81f843f1 | |||
c9ce14c857 | |||
bed20b7837 | |||
206881bfec | |||
cf25650b3c | |||
7dce4c8fbb | |||
b0ffb4fd10 | |||
001b1fcd46 | |||
4e14604e5c | |||
b56aa62bcc | |||
ba36a16bc5 | |||
997e7d3bf4 | |||
c4cd86e094 | |||
17e299995c | |||
e11fd7cd40 | |||
d78116c35b | |||
6516cf854c | |||
e55512f60b | |||
43ad623965 | |||
2d5c7d7fb0 | |||
38b88589da | |||
c6be7887e5 | |||
da3bbc5206 | |||
8b5d9cc1fb | |||
c692a8f0a7 | |||
a563d82f95 | |||
c7116a37c0 | |||
9af9438ed0 | |||
fa54866e99 | |||
ff172ae3a5 | |||
32d23fdb11 | |||
14ae764283 | |||
b87972713e | |||
bd8d45ce28 | |||
7cebc3999a | |||
1b78cc1389 | |||
204f2d38af | |||
215ff2839d | |||
ece25833aa | |||
21693b70f7 | |||
7bf1936df3 | |||
000e3ba651 | |||
9f228550a2 | |||
a2749bad53 | |||
e0fbe27c99 | |||
5602d4a2ee | |||
b742af56ec | |||
b17703a9e4 | |||
0c95e1eabb | |||
b0ac8a4b4b | |||
3ae0a1e1a6 | |||
cc329bfa55 | |||
732fb7c160 | |||
6988676f43 | |||
273c293645 | |||
d368405d05 | |||
82dee82bfd | |||
93d1293b9d | |||
67600603c5 | |||
1eaa9c9899 | |||
a1a91ab75a | |||
9caa801469 | |||
65b872c8b5 | |||
3a5cb26973 | |||
26c77fcf9e | |||
68afedbd16 | |||
63d965133f | |||
adf4acf947 | |||
fa95ca0aa8 | |||
d88b52c5f3 | |||
d73390a674 | |||
66c552d048 | |||
f5ee9b97de | |||
8bcfb2ecaf | |||
03839ca806 | |||
de9c318436 | |||
0b790abd46 | |||
2dc182189a | |||
8d68e2f5f0 | |||
af6d5efb83 | |||
c08bcb6f5b | |||
ef99b9ac49 | |||
689de466de | |||
9e5ada880d | |||
151b9c6ed2 | |||
35ddb6627e | |||
d266f9dec7 | |||
1af51ca0c5 | |||
c8de5eee85 | |||
842dd5cab0 | |||
77270c6b00 | |||
d4b33c7e12 | |||
a05ff7f83d | |||
8071dd054c | |||
4fd9e627c0 | |||
56ef6fbcae | |||
bc70cdc242 | |||
dce461dbd7 | |||
79a89dcb82 | |||
fc84da29e8 | |||
2817baf3f8 | |||
a9dff278b5 | |||
af87fa40c2 | |||
6d08976cbe | |||
11525d357f | |||
2a8c2c6a0b | |||
bda8849c3b | |||
375aeb57af | |||
9540575690 | |||
8c0c427870 | |||
6d77e4dfd6 | |||
fe5eb31ca7 | |||
66ce075ce1 | |||
1eff547af6 | |||
d871324e93 | |||
b06d2796f8 | |||
84ad6ddd79 | |||
4ce8c3499b | |||
76ac1da7ea | |||
89d3df242c | |||
28f19dec60 | |||
3b2d039664 | |||
d66efc550d | |||
2c65e9852c | |||
ef98f6051c | |||
e650329eac | |||
d2c0a008ce | |||
1c40f327be | |||
be9ee58a52 | |||
5987917c0a | |||
12b106c0f0 | |||
dbaa2cbdee | |||
cbcd0aff9e | |||
e624d4ef33 | |||
fd9ad4fa2c | |||
0a4b6570e1 | |||
d8a53ca716 | |||
bec7d7f614 | |||
915cc53d83 | |||
f0dee63716 | |||
9129475a51 | |||
41ad9ebb48 | |||
3fece6a716 | |||
1f12e163de | |||
7c1b7d764a | |||
58e1e02688 | |||
d000ba3ed3 | |||
1b59eacb72 | |||
3eb74fc32c | |||
a9e77c022c | |||
dfbabc5a77 | |||
c5632b039a | |||
46623c00a8 | |||
ccb960f47f | |||
561ad16757 | |||
399f491fd7 | |||
c463293d39 | |||
094cc6347d | |||
022908f1fa | |||
2ad9ea8c57 | |||
b2f787a2fd | |||
ea701b3adb | |||
eb21381ddd | |||
534b5feca6 | |||
754159b60f | |||
fa7c77a6e0 | |||
5b4a473f14 | |||
eeca12a4c0 | |||
4e747d24dd | |||
4f1607b775 | |||
140329d927 | |||
b6053d6a86 | |||
1f10c4d352 | |||
4bce3e4810 | |||
99c8b097d1 | |||
f4aaef5955 | |||
85301dbc4e | |||
8afa93ed59 | |||
2bba9a984e | |||
303a3096d4 | |||
e86fe8e749 | |||
a3cbf02597 | |||
802aaf59db | |||
62b89a128a | |||
174b9ff343 | |||
a20ce3e7a5 | |||
aeb9e0633a | |||
38631395b6 | |||
7d4fda550d | |||
4b5765e2c7 | |||
df2b565397 | |||
1a8a6ce872 | |||
bb3b71a43f | |||
803aeb8fae | |||
15126a680f | |||
50d9e6a7fd | |||
838a945862 | |||
79e4c838f4 | |||
3ae792b159 | |||
a9d5cc5a50 | |||
b8f59340af | |||
c8e65c1315 | |||
0ea6141dc8 | |||
e9a1ac15d9 | |||
c0a59b3a27 | |||
074c78d725 | |||
312ac5d066 | |||
c91688315a | |||
653274b9f6 | |||
3fff1a8dcd | |||
12c334a141 | |||
e80a35edbe | |||
c3247755ea | |||
3cd83c61c4 | |||
2a7fdfe189 | |||
ac872b3855 | |||
b1916b30fb | |||
3a1d9e683b | |||
148ac97742 | |||
ddce52c44e | |||
fe4dee03ab | |||
c3b4afc139 | |||
063f3b574c | |||
49253d8fdf | |||
dbed0f7d6a | |||
c8d6b26dfd | |||
f3cc456385 | |||
349a802a82 | |||
69adb78433 | |||
e99bc99dcc | |||
df49265674 | |||
e5797a54a1 | |||
a60481c6b1 | |||
dde2b71850 | |||
fddbf35df2 | |||
23ffafefc0 | |||
f5698d3566 | |||
02a053a4b8 | |||
4c17dc3431 | |||
e6e6f7d8d0 | |||
1d961b8e56 | |||
f922a08a27 | |||
7289224af9 | |||
035bbc6913 | |||
ae8d416c57 | |||
46d817f91b | |||
f434177a9a | |||
8485987b74 | |||
9cfd8c5f0b | |||
04f21b5976 | |||
cf38910601 | |||
3a4df1612c | |||
bd56b15b6e | |||
a72f913a60 | |||
7599a285c3 | |||
efdc741e5c | |||
93a02b619e | |||
e69118ade7 | |||
8bed1e1f15 | |||
e73e61f238 | |||
9247486576 | |||
1cc60df5f3 | |||
b85eb2a44c | |||
5de1caf057 | |||
be069d5918 | |||
bb911e6ab8 | |||
7ad2dadabf | |||
98396e8367 | |||
fccecd4a05 | |||
db1b53fde7 | |||
c423f38700 | |||
193fe2df71 | |||
6f14467383 | |||
7015214fbb | |||
e1af3dbde6 | |||
040c1f591e | |||
f206db2cee | |||
ba8e5d7add | |||
ac5e35101c | |||
68383b1293 | |||
137f87c414 | |||
f5be7c9136 | |||
a00bf38f16 | |||
c34a2b85ed | |||
60a2709213 | |||
1fcbc83503 | |||
08818886b2 | |||
c6910a96de | |||
86546c68b4 | |||
0cc69abc70 | |||
f9d27c37aa | |||
ddc40e5b45 | |||
0c2287b201 | |||
102d8e543d | |||
b4d5534c75 | |||
4f72403acd | |||
4c0c256a9d | |||
d0f254a278 | |||
0696e5026f | |||
42363001b4 | |||
ed3d63248a | |||
2a2714a4bf | |||
27cb38f38c | |||
e8be43d4c6 | |||
76da437f29 | |||
b4635b0b80 | |||
147235f8f5 | |||
aa5c8b8ffd | |||
1b3481fe25 | |||
21d7d14178 | |||
14f15c33fe | |||
bfbc539321 | |||
5f124166eb | |||
468a68c96c | |||
da3fe920cb | |||
3d9fc3846c | |||
63fa35c99f | |||
68305181f9 | |||
c844fccf2a | |||
f2452a4a3c | |||
4e21405647 | |||
06f990236c | |||
8a172322ff | |||
1b5f9eb013 | |||
5851cb5b8d | |||
ba98de6ef0 | |||
d2a0f8f2fd | |||
445b584333 | |||
f7dae0de02 | |||
1c6a41dda4 | |||
1c91c167fc | |||
39518b463a | |||
cbdf4a738c | |||
1d4912b22f | |||
bc7297c2d0 | |||
39ddb29e63 | |||
fe35839a77 | |||
297832ff91 | |||
2d75ef0c7a | |||
2822b9c579 | |||
ff6090836c | |||
a8b07b1b48 | |||
8687dd3802 | |||
40021ab72e | |||
72514f8ab2 | |||
40a8542c22 | |||
f56965b1c0 | |||
69922340f6 | |||
0e50d9787a | |||
9e43e726a9 | |||
03cadc543f | |||
b61cf9cb8e | |||
8d2a8e1c7a | |||
72b393ca53 | |||
6398206e4f | |||
226c20c097 | |||
0b9c5c975e | |||
272dc343ef | |||
d7d20d1c3d | |||
2557992b70 | |||
33be0e09fe | |||
13b6c1e684 | |||
ea8a353545 | |||
0566bf2d5d | |||
93a129e55a | |||
58e1f12240 | |||
0fa6d38574 | |||
e1ed380f04 | |||
354a91290e | |||
3ec7004421 | |||
a542a7804b | |||
03ff4c8b76 | |||
7992448f6a | |||
9a0ddb3760 | |||
7ee7e910eb | |||
281b0e7e59 | |||
50e6256058 | |||
1b00c449a5 | |||
9848072d21 | |||
2652e46d66 | |||
d13dd50d51 | |||
8fece992eb | |||
3264b51a74 | |||
0692097a73 | |||
19ef1042d6 | |||
394e651591 | |||
2fe22f1890 | |||
089021ca6d | |||
f158dfcd77 | |||
19980a7033 | |||
a7d9efa900 | |||
0abd860f7e | |||
5c3a3db2d8 | |||
074099a1b2 | |||
a2ee620394 | |||
ffa2b07dc4 | |||
60bbc57aeb | |||
86718167e8 | |||
7bd4d05a38 | |||
d0c4916fe9 | |||
91fc6aabd2 | |||
c0ff8f6026 | |||
a93d60be90 | |||
c47760382e | |||
9c8a23c333 | |||
91f768f9ae | |||
6c48466bfe | |||
5bf667851c | |||
d77e3a203f | |||
c32dfa013d | |||
6b70efbe30 | |||
641edd4e6e | |||
823fdfab12 | |||
0cacb6cba4 | |||
7a948746a8 | |||
1273875a00 | |||
4c2942f9f9 | |||
139f59f7d1 | |||
80c22a4fb2 | |||
a417782151 | |||
e87f3231a1 | |||
fe39288ebf | |||
97bc5b260d | |||
47f24d1088 | |||
3a75d0a465 | |||
17c8f6d2e8 | |||
7eaad5c8e0 | |||
3e7c2dff96 | |||
14c96306a0 | |||
d122ed3bcd | |||
451e874696 | |||
290ca6bbc7 | |||
a2e5bae951 | |||
823e744ed9 | |||
35c89c7537 | |||
77887e8253 | |||
1e6c0dee24 | |||
e89e42382a | |||
184a5901e6 | |||
6f8b0dc7ef | |||
21f0c6f9d4 | |||
bd2b3793a6 | |||
25caac370f | |||
0c8329a3fb | |||
444b5d329c | |||
7a7f6aea00 | |||
b226b14eb2 | |||
72b165ad4c | |||
bd04905154 | |||
471c40735c | |||
c2d1dc4f51 | |||
000290dc94 | |||
3f3a324108 | |||
77477b3e43 | |||
c2077ed0b6 | |||
ceefa98c76 | |||
d3fb9f0f0f | |||
d9088a5f18 | |||
87113f985f | |||
4da933e4a4 | |||
56909bb6a3 | |||
ecd73acc01 | |||
e2e0853492 | |||
0f97e3528a | |||
89074ffcea | |||
6b14fe7747 | |||
48e36422b5 | |||
32df6f92fc | |||
cde184fdbf | |||
97f1363afa | |||
8b8b8d74fe | |||
5821a1390a | |||
ae2130952b | |||
b0cdf73565 | |||
c64c739fab | |||
feb6f2dad7 | |||
2c42271cea | |||
8597904bc2 | |||
227ea57c37 | |||
5b924dfd4e | |||
181805bb87 | |||
63c06d6c79 | |||
782166dadd | |||
7bfd11679b | |||
f250649a5e | |||
629a827ee2 | |||
c247d807af | |||
22a25a18b3 | |||
6b77b94127 | |||
2bfb8f5e4f | |||
dd6623be2f | |||
fa3b4a7941 | |||
8047cfd48e | |||
53477af1eb | |||
355bd6df9b | |||
8d25dac1ba | |||
b47042634a | |||
e02441acb1 | |||
ddd8e85146 | |||
68546de2cb | |||
7553a92232 | |||
c7e642baa2 | |||
0377ea751d | |||
5efad911d5 | |||
d38a260e00 | |||
0cc2e8887f | |||
3736b7678a | |||
e373c9ac8c | |||
5f2d9b38dc | |||
a7eeb01bc8 | |||
c26215a740 | |||
4e8828c5c4 | |||
2dde2cbb6f | |||
88e0263d08 | |||
28652ed7af | |||
60c2680bfd | |||
9a8bd96ad3 | |||
66271fe986 | |||
1caa3245e6 | |||
04720bd8bf | |||
ecc96df699 | |||
0b47d6888d | |||
e9b85264ab | |||
d397e83a05 | |||
801b642dea | |||
e7527ebb45 | |||
bfde27a99d | |||
c65f8fc7ad | |||
547c05685e | |||
5794d70881 | |||
009b84c5fc | |||
b5426d967e | |||
60827ebd5a | |||
ae10b6226d | |||
d32fd00bbb | |||
7c29d5bf5c | |||
f37d9df118 | |||
7da85d66fd | |||
cf656ccfdd | |||
d7087ed61a | |||
98351b9756 | |||
5260c7c939 | |||
78e2fc1bc8 | |||
c17ad07bdb | |||
5b105ed156 | |||
af3240fa18 | |||
45b4d6d194 | |||
04ad7a91dd | |||
fd0d0813ce | |||
5a4c41be37 | |||
57f94f65a8 | |||
189b98c03f | |||
f46fdbf078 | |||
ed2d7d64cd | |||
cc10b1084d | |||
c49711ae2c | |||
b7be38da12 | |||
6b8b6cda66 | |||
850cbf6018 | |||
dcabc6ae80 | |||
1ab3db18bb | |||
8edc1f30d9 | |||
5266968b61 | |||
9bd36f173e | |||
a9e20aecc6 | |||
e66f6d76e6 | |||
c62603ba73 | |||
4692d6e966 | |||
9049a2afd5 | |||
bbbf8fd574 | |||
d66dc3c1c7 | |||
59ccefee0f | |||
3b485e20bb | |||
44af8ea190 | |||
2504c4ad34 | |||
d447ba52ad | |||
5e499456f0 | |||
e96234382a | |||
78e2a27ee0 | |||
715b4d7bfc | |||
c36f306a1d | |||
bfa7d54b02 | |||
4ff773aaaf | |||
0611c81e88 | |||
6b4f7cf861 | |||
51406a3582 | |||
9ebac0b9fd | |||
4acfc26c5e | |||
5271378fc2 | |||
5ab2f5454c | |||
4748da1e09 | |||
c3b4d10b74 | |||
f026d1c14e | |||
e30bf19684 | |||
d4553714d9 | |||
e1d909eb0e | |||
317b34f4a0 | |||
0937b4d266 | |||
ef988020b7 | |||
70c8c09360 | |||
d89fa131ab | |||
3f85829e87 | |||
3cde996d21 | |||
39fb266776 | |||
557ffbb861 | |||
ddcf3975ed | |||
cc88215b46 | |||
3bd2d0da88 | |||
b7854354ff | |||
80bc68eb49 | |||
8c8ab6a4cb | |||
985db7838c | |||
04c98d0a75 | |||
53436af899 | |||
81a73dbc80 | |||
c4179829d6 | |||
9cf1fcc987 | |||
e2fa89d554 | |||
75c02ed0da | |||
c7536ff5e1 | |||
fd8ce5d11a | |||
838645f1b7 | |||
4fb8e79237 | |||
c352db9acd | |||
60813103e3 | |||
d816db07e3 | |||
296eaf7b34 | |||
2ce587ebc7 | |||
18bf886368 | |||
1de78fef4d | |||
54794d57fe | |||
412f56f971 | |||
e87ee6a86b | |||
418eccb3d7 | |||
61227d7477 | |||
931ae5fec3 | |||
bcf692d775 | |||
7e5aa3137d | |||
e24d2fdb6c | |||
fe80a868a0 | |||
468bfedf34 | |||
5e1fdf554d | |||
d204fa8438 | |||
dba5eb57cf | |||
0399593589 | |||
36dda352d9 | |||
44f050f59a | |||
3caf7745b6 | |||
c1508becd6 | |||
a5bca025b1 | |||
bb64e7b6e5 | |||
f66bd1689d | |||
3e4f8a382e | |||
44b08fea62 | |||
74bd0d95b8 | |||
f83e76eb60 | |||
06473ba6fe | |||
cb9f677cf6 | |||
9ea1ef8916 | |||
dd354c9e22 | |||
59e98fcc62 | |||
4bec461db1 | |||
8442e7a0dc | |||
aabd0faebe | |||
31bc0bb670 | |||
0fb8fc0b8d | |||
a06f5e74af | |||
5edaee79e6 | |||
0762c79e2e | |||
d646d7c16a | |||
1a7eb36b6f | |||
9db521ca04 | |||
e00296960c | |||
c305eda344 | |||
636dad190e | |||
b556252358 | |||
4ba7d85d56 | |||
40d297be66 | |||
d971d22849 | |||
e7839e8c57 | |||
af20be8123 | |||
70e31c71f3 | |||
b22c6fed4d | |||
0867b33de5 | |||
b784ced517 | |||
5d865e321c | |||
e76b7d1e8b | |||
f3d438a93f | |||
618def7ab0 | |||
7ec3f861e4 | |||
67f3fc349c | |||
0dc428b5d6 | |||
faab194247 | |||
46f8a354d1 | |||
e4f1e22401 | |||
aa4660d780 | |||
ded3cc24c0 | |||
73f04d5cec | |||
c6e1af8321 | |||
7875ba28c9 | |||
d5e4aef6c2 | |||
6729776e25 | |||
72bf216cb4 | |||
df20be775c | |||
cfb6eb6e50 | |||
e34d368a3e | |||
b929e71948 | |||
6252037376 | |||
577d08ea7d | |||
78e382cb6b | |||
fc562bd625 | |||
1d02a70802 | |||
3d16633a94 | |||
d2d7e37990 | |||
f8985d731f | |||
ff081dca88 | |||
cc9c75acbe | |||
08dffe85d6 | |||
5097a2adee | |||
373199fe46 | |||
171072c736 | |||
90a8f56c96 | |||
5b739f6166 | |||
702cf1cc36 | |||
7997fdc76f | |||
2a5030b3ca | |||
d5172849bc | |||
03571d3cda | |||
d8e9838c38 | |||
67b4c27d5d | |||
b7d07ea5c8 | |||
08c59895b5 | |||
22c2935ddb | |||
978cb54fc7 | |||
d3a83805cc | |||
e41b86fd68 | |||
74ad50efa6 | |||
32861246b9 | |||
0344e759d9 | |||
04711ecde5 | |||
da666d9143 | |||
c93f086032 | |||
7c07810958 | |||
0ed3509ec1 | |||
64e49726cd | |||
b4f3d02c1c | |||
a607c9eace | |||
4520705bdf | |||
40a574a8ca | |||
522a833ab2 | |||
8a0496cfae | |||
b190c4250a | |||
4c06e19cf2 | |||
a1ec895b91 | |||
68e7455374 | |||
ea6b11bbf6 | |||
228754a99c | |||
fca8506331 | |||
15eee885d7 | |||
a414b15f9a | |||
8952c1bd42 | |||
01a0f79efb | |||
1d34c82643 | |||
cba2611c68 | |||
48f5a47ff1 | |||
4f45de6953 | |||
1c1d3dd708 | |||
e90937a2b4 | |||
516f249403 | |||
3ce1132d5c | |||
39e4e0c3d9 | |||
5747b3b401 | |||
f499100426 | |||
aa047b124d | |||
256a0428dd | |||
d9c7796d56 | |||
b3704a7119 | |||
a5402435b9 | |||
6066862c34 | |||
a0bfe411f8 | |||
eecd9f7e35 | |||
5057036563 | |||
ca7e61052d | |||
df00306a71 | |||
954217fb73 | |||
ccc27a61f5 | |||
5abbaf59e3 | |||
811c577fe8 | |||
fe5fb6cfba | |||
8b2e1025ef | |||
d8157472fe | |||
b988f5b323 | |||
e427c85f03 | |||
27157e5e78 | |||
cb4b6f1fe4 | |||
06f1b7f2e8 | |||
d8e5994c35 | |||
e397e807ca | |||
fcba6436e8 | |||
d87e0e93d3 | |||
eca433cee5 | |||
6156d5c790 | |||
fc25ef8383 | |||
84be60c920 | |||
bfe33bd3c4 | |||
c91cb72ee2 | |||
d045f43cda | |||
7ca09579c2 | |||
4fab919fcb | |||
5620f88635 | |||
0372cdea23 | |||
56bbab74ca | |||
59b2eb4618 | |||
98d1209ca2 | |||
d12f97c8cf | |||
713d50951b | |||
40142cbacc | |||
478118497c | |||
cc9b5fca90 | |||
b7084fda45 | |||
8540249c4e | |||
b54a6a2ac8 | |||
f62095428f | |||
3f5c39afd9 | |||
4005312ee5 | |||
677590feb7 | |||
fa1b00cf91 | |||
b819bb1c8c | |||
26806a10fc | |||
55356465c6 | |||
bb275e3f45 | |||
0c676ac93a | |||
26c24dd889 | |||
ae05a9f003 | |||
5e604b7a18 | |||
13f7257dd7 | |||
6e278294af | |||
8acaf71a59 | |||
af3804d728 | |||
b2d72b3e55 | |||
53678ad134 | |||
bf5f0ab3f2 | |||
6a074d4f6f | |||
acd940a450 | |||
5a4e764d7a | |||
b4f4528ef4 | |||
28ac516f68 | |||
41695eb1c8 | |||
64875d39b0 | |||
4c1d864095 | |||
c307b6abca | |||
55058c64f5 | |||
779195eb4f | |||
49c55477e5 | |||
797d996535 | |||
8c6606ed12 | |||
1d49098954 | |||
07b52ee24c | |||
0d8510df33 | |||
efe431ead0 | |||
c5a6f9bb6b | |||
3f6d6cf4c6 | |||
c05df9e3f5 | |||
d3bfc49b7c | |||
35d9719707 | |||
6b5d6ecd8b | |||
bf76af8fd1 | |||
b9593b80ec | |||
5394c8a894 | |||
51f57629f9 | |||
235ffc234d | |||
52d5e05201 | |||
3d4e604607 | |||
44356dc654 | |||
3a29ce4d17 | |||
02abbb6a6c | |||
71a73d3904 | |||
e951b99bdd | |||
63768e3742 | |||
f3ce75f2b4 | |||
eb2fbcb575 | |||
fa0cd3ae87 | |||
8aeb4121cf | |||
9f3524fd11 | |||
6f054827a3 | |||
3062aab44f | |||
ae615eda62 | |||
0c4b45d4fb | |||
c10653ae0c | |||
c88a556917 | |||
f29ab366c3 | |||
9d0de611a7 | |||
0e15962cef | |||
0cd78e210a | |||
f723651a6d | |||
bd651edf80 | |||
107762e82a | |||
1a2a9d60e6 | |||
03c836faff | |||
90b49fa53c | |||
0435284a37 | |||
ddf527e092 | |||
d59134a5b5 | |||
576badd334 | |||
ec175d4c47 | |||
23dc0b9317 | |||
aa9ae32998 | |||
bd0d2e8494 | |||
a70aa3e0da | |||
7b60f8bdc3 | |||
1fb3799118 | |||
3be69f09ac | |||
e254b9cec6 | |||
9ed2776639 | |||
e40bb2e8d8 | |||
378c3d1dcf | |||
41e7266ff7 | |||
f99d24310f | |||
53b638558b | |||
65663b2dae | |||
c697767c47 | |||
32c2f89fe6 | |||
63456b5c4b | |||
98fad7b86a | |||
7d4908a6c3 | |||
bc0e07bca2 | |||
91cad59ada | |||
a659dec00b | |||
48b3e7f2ab | |||
e8a7230a1d | |||
6803d077b9 | |||
94accfcb23 | |||
90c5614cd4 | |||
23119d1672 | |||
f19567fd3e | |||
2cafdcd657 | |||
93bdce32a8 | |||
1119a86cc3 | |||
5767b4e245 | |||
61f238f22e | |||
0cdb865b4c | |||
b852a746ce | |||
8e12e4e480 | |||
acbc0c8846 | |||
6684186033 | |||
e931ff23d8 | |||
7b6e305d40 | |||
55f9045561 | |||
62b890839a | |||
97987e72a7 | |||
a6f7069264 | |||
58495d1dcf | |||
4135f425d3 | |||
dcef04b796 | |||
2eff77ea92 | |||
d5f0642524 | |||
87b2a0d9c5 | |||
a0d3488d94 | |||
088a01f19c | |||
4fb3a01f25 | |||
4479d72e93 | |||
28722e2127 | |||
7fa99b3794 | |||
c39f0963ae | |||
e0636ce655 | |||
7670c85d70 | |||
f998a19c3d | |||
4774466a75 | |||
3fa0d21049 | |||
bc8c338bed | |||
66becddac3 | |||
b4d311d6a1 | |||
f5fa89c0e1 | |||
5305b802b2 | |||
e680f28c2f | |||
0392c18794 | |||
4c3509ac09 | |||
baa683b484 | |||
45b0b35a0f | |||
36ae9e9437 | |||
53e9e1966f | |||
9838cae49d | |||
aa49d5c1bd | |||
1c401a05b1 | |||
01bbad31c7 | |||
c5f9afa0e8 | |||
fbf40fb74a | |||
278a089908 | |||
53a9bd0618 | |||
2aeb25e80c | |||
9ebdcb8ae3 | |||
545f8ed6a1 | |||
811d172a54 | |||
3f896cf586 | |||
fb7a91739a | |||
812fd4393e | |||
2b6c628342 | |||
c87a7a039e | |||
89660ce0cd | |||
e7598075ac | |||
ad5cfab5ba | |||
4f5ec77f87 | |||
12636ce89c | |||
1321c63f3b | |||
5a1338ce8a | |||
c434f2cae7 | |||
a6a32a592d | |||
56192b7f85 | |||
e1003a8623 | |||
6b55a47090 | |||
13b86f5360 | |||
1843f7bda5 | |||
375f7a73b9 | |||
63e128670e | |||
a0007dbeab | |||
259e1ce256 | |||
ef74464aea | |||
090d049b81 | |||
755c18d491 | |||
7565313290 | |||
a635f6b17c | |||
2b291aabea | |||
dc59bd8d77 | |||
0e49c49dce | |||
1a27c9de67 | |||
8475d9878e | |||
d44fd6661a | |||
013d07bc2a | |||
77572b01f8 | |||
e954d3d41f | |||
55c1f45805 | |||
ec24e76959 | |||
2b9c4bc90d | |||
0c5808eeec | |||
d58c4a9145 | |||
bd893986b2 | |||
d3b064c2e9 | |||
7416d2fdcc | |||
d8d712e8f0 | |||
b0793e2dd9 | |||
c7d3d3371b | |||
52b67ca307 | |||
34b99ee343 | |||
8670e1b7aa | |||
bb9401544a | |||
ba0c104cc8 | |||
eb78d96a20 | |||
e1186bbead | |||
89334df5ae | |||
0dfbb3f921 | |||
beac6d8589 | |||
188a903e97 | |||
d65c2451c4 | |||
594c2cab47 | |||
a113a51d73 | |||
a8b677f6e7 | |||
40c520ca1b | |||
e77b9aa020 | |||
45f0ff5679 | |||
52c34a2323 | |||
8ebbb96611 | |||
3d5087d488 | |||
777e03491f | |||
bc077b66b0 | |||
05202c9ce9 | |||
a3b07f71d2 | |||
4246d3a400 | |||
cb323e95ff | |||
255e14a5c4 | |||
61899d62c5 | |||
302347426e | |||
af30cb8725 | |||
1d6a6d20d1 | |||
b8e5794765 | |||
4bf57537b5 | |||
e597947bd8 | |||
a030a41153 | |||
75959f9948 | |||
c3e2332479 | |||
f8b0c876f7 | |||
52d5773cc6 | |||
32f562a013 | |||
8ee0845631 | |||
bed3980e9c | |||
d2904ae36e | |||
431eebf754 | |||
637650e2a9 | |||
65948d531c | |||
52da2acffd | |||
3c7f9215d1 | |||
48e6137f46 | |||
a07802a347 | |||
a71838a59b | |||
84ea824b96 | |||
5a4f096647 | |||
44c16dd30d | |||
41b9051686 | |||
0facc24016 | |||
baaaf24f70 | |||
5cc585af96 | |||
d64cf5f64c | |||
b8b81d5b03 | |||
512dede9ce | |||
c988b1e5b0 | |||
5a7ba24790 | |||
9412c86b97 | |||
558d30f33f | |||
d2407dff9f | |||
974d74befb | |||
6f591032ef | |||
6fdffbcc85 | |||
b8ac1d082b | |||
9a5775cff0 | |||
482afb44f3 | |||
68206a74e7 | |||
98eba608fc | |||
0959448855 | |||
3ae316ac38 | |||
35724319c9 | |||
c345203c27 | |||
dbf69907fa | |||
248992e380 | |||
4b2e53f29e | |||
33e010ebd8 | |||
2c9d57a9fe | |||
784d286f37 | |||
da83ee223b | |||
8a7e5fc227 | |||
c565ac23a7 | |||
266519c8d2 | |||
6f32b2d576 | |||
1d31b574ed | |||
6fb1d8a377 | |||
8fc1abd9b1 | |||
cc722a413f | |||
2eb0625f15 | |||
9825976e06 | |||
21f6b50607 | |||
da01fe6027 | |||
cbd8a4fb9c | |||
20488b498a | |||
0ef9d944f6 | |||
aff4af1d0b | |||
0b37c808dd | |||
a121cbb721 | |||
951d467917 | |||
a568c6dc75 | |||
a8ff1b27d4 | |||
3a0a8c89e8 | |||
24b34d0a1e | |||
c5c3604471 | |||
d3fbf6d997 | |||
940294d1cd | |||
48d234c836 | |||
ca84d11f8c | |||
fba31a8461 | |||
11f94d4720 | |||
f03481f733 | |||
2022c4bce6 | |||
1caf2a3364 | |||
e71dad9d32 | |||
cd0201df06 | |||
36329e9c6a | |||
09f31af88a | |||
cd6ed3d15b | |||
62b8b7a6a8 | |||
09414016c2 | |||
7588f2da47 | |||
232f83f99a | |||
e41ef9b733 | |||
a3545a7ffa | |||
eff09adf2e | |||
2d7c1be164 | |||
3ff100321c | |||
2c9c278e4d | |||
9caca30c8d | |||
f923548182 | |||
8d245b546f | |||
23e99b57a6 | |||
86e03d2298 | |||
a7eb09a557 | |||
643a92a490 | |||
38489bd846 | |||
1a7b3e8e08 | |||
31aa3dfe82 | |||
43cb2a353f | |||
7ad523270d | |||
effc8285f2 | |||
bd7c09e9c0 | |||
9a632351a6 | |||
9065c2e4f0 | |||
b7358ccd98 | |||
f41a9b9703 | |||
44e8c234ed | |||
db534fde3b | |||
380326b5d1 | |||
8ab6684bf5 | |||
4f7011fc2b | |||
08057fa642 | |||
f50cf0497d | |||
bd8ec6d67b | |||
948044093b | |||
4f99b60291 | |||
907e39edec | |||
8cf87921ff | |||
a623effaf1 | |||
d95485d511 | |||
ea4ab2a429 | |||
9138a75df4 | |||
9b80e1cd64 | |||
f50ea7d971 | |||
b366f10446 | |||
450d0eb0da | |||
6d27afd1c9 | |||
227d79e2bf | |||
adbcbefe92 | |||
4c286fde23 | |||
cc77613fd9 | |||
621cf57761 | |||
197b9106f9 | |||
7ce8389d83 | |||
03af286b03 | |||
b300d2877e | |||
4e2f9b4991 | |||
aed76d0e08 | |||
90f691fc2a | |||
c56312f09f | |||
23775dc776 | |||
b8967bc7d1 | |||
45c9ec9f29 | |||
dee496b5ae | |||
2f5015552e | |||
45ab5238fe | |||
329f8c4fa3 | |||
40dcde42aa | |||
90d7ebec47 | |||
8eaa9500e9 | |||
fec65d8717 | |||
0c39971363 | |||
51941fa613 | |||
946f9eaedc | |||
a90bb85bb3 | |||
43f808fa60 | |||
a22bd2b8b2 | |||
d56d79018e | |||
de0a8c60ac | |||
e28fd7cc2b | |||
bfeed190ea | |||
59599dc519 | |||
0166edce77 | |||
b8d85e627e | |||
32cf8ddfde | |||
351e84aece | |||
197689fcb5 | |||
8264156ce9 | |||
6108f8536f | |||
808eb64bd7 | |||
4a617979a9 | |||
a543d644b4 | |||
6345e02d20 | |||
91aed9e232 | |||
50d53f3ae0 | |||
29b7aab5fc | |||
4f436ae70a | |||
23995ffc59 | |||
4adc17eb01 | |||
e856acf05e | |||
6ef18b1ae3 | |||
9b7109b466 | |||
8eca7b2ca8 | |||
800c4718c1 | |||
7563a13621 | |||
10cdaea059 | |||
f75c309d26 | |||
896c944c7e | |||
2b66641b55 | |||
9a63723bbe | |||
d8cd744f2f | |||
e4b164c324 | |||
7a9fae9530 | |||
41b2175fe0 | |||
a97590ff50 | |||
dd2f856d63 | |||
798d52e695 | |||
fb9f09d240 | |||
49c160b50c | |||
64e6d54758 | |||
e7caa1475e | |||
57ef6e9f5a |
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,4 +1,6 @@
|
||||
src/
|
||||
pkg/
|
||||
./etcd
|
||||
release_version.go
|
||||
/gopath
|
||||
/go-bindata
|
||||
/machine*
|
||||
/bin
|
||||
.vagrant
|
||||
*.etcd
|
||||
|
20
.header
Normal file
20
.header
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright 2013 CoreOS Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package x
|
||||
|
||||
import (
|
||||
)
|
@ -1,8 +0,0 @@
|
||||
language: go
|
||||
go: 1.1
|
||||
|
||||
install:
|
||||
- echo "Skip install"
|
||||
|
||||
script:
|
||||
- ./test.sh
|
69
CHANGELOG
Normal file
69
CHANGELOG
Normal file
@ -0,0 +1,69 @@
|
||||
v0.4.3
|
||||
* Avoid panic() on truncated or unexpected log data (#834, #833)
|
||||
* Fix missing stats field (#807)
|
||||
* Lengthen default peer removal delay to 30mins (#835)
|
||||
* Reduce logging on heartbeat timeouts (#836)
|
||||
|
||||
v0.4.2
|
||||
* Improvements to the clustering documents
|
||||
* Set content-type properly on errors (#469)
|
||||
* Standbys re-join if they should be part of the cluster (#810, #815, #818)
|
||||
|
||||
v0.4.1
|
||||
* Re-introduce DELETE on the machines endpoint
|
||||
* Document the machines endpoint
|
||||
|
||||
v0.4.0
|
||||
* Introduced standby mode
|
||||
* Added HEAD requests
|
||||
* Set logs NOCOW flag when BTRFS is detected to avoid fsync overhead
|
||||
* Fix all known data races, and pass Go race detector (TODO: re-run race detector)
|
||||
* Fixed timeouts when using HTTPS
|
||||
* Improved snapshot stability
|
||||
* Migration of machine names to new IPs
|
||||
* Updated peer discovery ordering
|
||||
|
||||
v0.3.0
|
||||
* Add Compare-and-Delete support.
|
||||
* Added prevNode to response objects.
|
||||
* Added Discovery API.
|
||||
* Add tracing and debug endpoints (Documentation/debugging.md).
|
||||
* Improved logging of cluster events.
|
||||
* go get github.com/coreos/etcd works.
|
||||
* info file is no longer used.
|
||||
* Snapshots are on by default.
|
||||
* Statistics APIs documented.
|
||||
|
||||
v0.2.0
|
||||
* Support directory creation and removal.
|
||||
* Add Compare-and-Swap (CAS) support.
|
||||
* Support recursive GETs.
|
||||
* Support fully consistent GETs.
|
||||
* Allow clients to watch specific paths.
|
||||
* Allow clients to watch for key expiration.
|
||||
* Unique key generation.
|
||||
* Support hidden paths.
|
||||
* Refactor low-level data store.
|
||||
* Modularize store, server and API code.
|
||||
* Integrate Gorilla Web Toolkit.
|
||||
* Add tiered configuration (command line args, env variables, config file).
|
||||
* Add peer protocol versioning.
|
||||
* Add rolling upgrade support for future versions.
|
||||
* Sync key expiration across cluster.
|
||||
* Significantly improve test coverage.
|
||||
* Improve migration testing.
|
||||
* Configurable snapshot count.
|
||||
* Reduce TCP connection count.
|
||||
* Fix TCP connection leak.
|
||||
* Bug Fixes: https://github.com/coreos/etcd/issues?milestone=1&state=closed
|
||||
|
||||
Contributors:
|
||||
* Xiang Li (@xiangli-cmu)
|
||||
* Ben Johnson (@benbjohnson)
|
||||
* Brandon Philips (@philips)
|
||||
* Yifan (@yifan-gu)
|
||||
* Rob Szumski
|
||||
* Hongchao Deng (@fengjingchao)
|
||||
* Kelsey Hightower (@kelseyhightower)
|
||||
* Adrián (@adrianlzt)
|
||||
* Antonio Terreno (@aterreno)
|
76
CONTRIBUTING.md
Normal file
76
CONTRIBUTING.md
Normal file
@ -0,0 +1,76 @@
|
||||
# How to contribute
|
||||
|
||||
etcd is Apache 2.0 licensed and accepts contributions via Github pull requests. This document outlines some of the conventions on commit message formatting, contact points for developers and other resources to make getting your contribution into etcd easier.
|
||||
|
||||
# Email and chat
|
||||
|
||||
- Email: [etcd-dev](https://groups.google.com/forum/?hl=en#!forum/etcd-dev)
|
||||
- IRC: #[coreos](irc://irc.freenode.org:6667/#coreos) IRC channel on freenode.org
|
||||
|
||||
## Getting started
|
||||
|
||||
- Fork the repository on GitHub
|
||||
- Read the README.md for build instructions
|
||||
|
||||
## Contribution flow
|
||||
|
||||
This is a rough outline of what a contributor's workflow looks like:
|
||||
|
||||
- Create a topic branch from where you want to base your work. This is usually master.
|
||||
- Make commits of logical units.
|
||||
- Make sure your commit messages are in the proper format (see below).
|
||||
- Push your changes to a topic branch in your fork of the repository.
|
||||
- Submit a pull request to coreos/etcd.
|
||||
|
||||
Thanks for your contributions!
|
||||
|
||||
### Code style
|
||||
|
||||
The coding style suggested by the Golang community is used in etcd. See [style doc](https://code.google.com/p/go-wiki/wiki/Style) for details.
|
||||
|
||||
Please follow this style to make etcd easy to review, maintain and develop.
|
||||
|
||||
### Format of the commit message
|
||||
|
||||
etcd follows a rough convention for commit messages borrowed from Angularjs. This is an example of a commit:
|
||||
|
||||
```
|
||||
feat(scripts/test-cluster): add a cluster test command
|
||||
|
||||
this uses tmux to setup a test cluster that you can easily kill and
|
||||
start for debugging.
|
||||
```
|
||||
|
||||
The format can be more formally described as follows:
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
<BLANK LINE>
|
||||
<body>
|
||||
<BLANK LINE>
|
||||
<footer>
|
||||
```
|
||||
|
||||
The first line is the subject and should be no longer than 70 characters, the second line is always blank, and other lines should be wrapped at 80 characters. This allows the message to be easier to read on github as well as
|
||||
in various git tools.
|
||||
|
||||
### Subject line
|
||||
|
||||
The subject line contains a succinct description of the change.
|
||||
|
||||
### Allowed <type>s
|
||||
- feat (feature)
|
||||
- fix (bug fix)
|
||||
- docs (documentation)
|
||||
- style (formatting, missing semi colons, …)
|
||||
- refactor
|
||||
- test (when adding missing tests)
|
||||
- chore (maintain)
|
||||
|
||||
### Allowed <scope>s
|
||||
|
||||
Scopes can be anything specifying the place of the commit change within the repository. For example, "store", "API", etc.
|
||||
|
||||
### More details on commits
|
||||
|
||||
For more details see the [angularjs commit style guide](https://docs.google.com/a/coreos.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#).
|
36
DCO
Normal file
36
DCO
Normal file
@ -0,0 +1,36 @@
|
||||
Developer Certificate of Origin
|
||||
Version 1.1
|
||||
|
||||
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
||||
660 York Street, Suite 102,
|
||||
San Francisco, CA 94110 USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
14
Dockerfile
14
Dockerfile
@ -1,10 +1,12 @@
|
||||
FROM ubuntu:12.04
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y python-software-properties git
|
||||
RUN add-apt-repository -y ppa:duh/golang
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y golang
|
||||
# Let's install go just like Docker (from source).
|
||||
RUN apt-get update -q
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt-get install -qy build-essential curl git
|
||||
RUN curl -s https://go.googlecode.com/files/go1.2.1.src.tar.gz | tar -v -C /usr/local -xz
|
||||
RUN cd /usr/local/go/src && ./make.bash --no-clean 2>&1
|
||||
ENV PATH /usr/local/go/bin:$PATH
|
||||
ADD . /opt/etcd
|
||||
RUN cd /opt/etcd && ./build
|
||||
EXPOSE 4001 7001
|
||||
ENTRYPOINT ["/opt/etcd/etcd", "-c", "0.0.0.0:4001", "-s", "0.0.0.0:7001"]
|
||||
ENTRYPOINT ["/opt/etcd/bin/etcd"]
|
||||
|
||||
|
1291
Documentation/api.md
Normal file
1291
Documentation/api.md
Normal file
File diff suppressed because it is too large
Load Diff
46
Documentation/clients-matrix.md
Normal file
46
Documentation/clients-matrix.md
Normal file
@ -0,0 +1,46 @@
|
||||
# Client libraries support matrix for etcd
|
||||
|
||||
As etcd features support is really uneven between client libraries, a compatibility matrix can be important.
|
||||
We will consider in detail only the features of clients supporting the v2 API. Clients still supporting the v1 API *only* are listed below.
|
||||
|
||||
## v1-only clients
|
||||
|
||||
Clients supporting only the API version 1
|
||||
|
||||
- [justinsb/jetcd](https://github.com/justinsb/jetcd) Java
|
||||
- [transitorykris/etcd-py](https://github.com/transitorykris/etcd-py) Python
|
||||
- [russellhaering/txetcd](https://github.com/russellhaering/txetcd) Python
|
||||
- [iconara/etcd-rb](https://github.com/iconara/etcd-rb) Ruby
|
||||
- [jpfuentes2/etcd-ruby](https://github.com/jpfuentes2/etcd-ruby) Ruby
|
||||
- [aterreno/etcd-clojure](https://github.com/aterreno/etcd-clojure) Clojure
|
||||
- [marshall-lee/etcd.erl](https://github.com/marshall-lee/etcd.erl) Erlang
|
||||
|
||||
|
||||
## v2 clients
|
||||
|
||||
The v2 API has a lot of features, we will categorize them in a few categories:
|
||||
|
||||
- **HTTPS Auth**: Support for SSL-certificate based authentication
|
||||
- **Reconnect**: If the client is able to reconnect automatically to another server if one fails.
|
||||
- **Mod/Lock**: Support for the locking module
|
||||
- **Mod/Leader**: Support for the leader election module
|
||||
- **GET,PUT,POST,DEL Features**: Support for all the modifiers when calling the etcd server with said HTTP method.
|
||||
|
||||
|
||||
### Supported features matrix
|
||||
|
||||
| Client| [go-etcd](https://github.com/coreos/go-etcd) | [jetcd](https://github.com/diwakergupta/jetcd) | [python-etcd](https://github.com/jplana/python-etcd) | [python-etcd-client](https://github.com/dsoprea/PythonEtcdClient) | [node-etcd](https://github.com/stianeikeland/node-etcd) | [nodejs-etcd](https://github.com/lavagetto/nodejs-etcd) | [etcd-ruby](https://github.com/ranjib/etcd-ruby) | [etcd-api](https://github.com/jdarcy/etcd-api) | [cetcd](https://github.com/dwwoelfel/cetcd) | [clj-etcd](https://github.com/rthomas/clj-etcd) | [etcetera](https://github.com/drusellers/etcetera)| [Etcd.jl](https://github.com/forio/Etcd.jl) |
|
||||
| --- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
||||
| **HTTPS Auth** | Y | Y | Y | Y | Y | Y | - | - | - | - | - | - |
|
||||
| **Reconnect** | Y | - | Y | Y | - | - | - | Y | - | - | - | - |
|
||||
| **Mod/Lock** | - | - | Y | Y | - | - | - | - | - | - | - | Y |
|
||||
| **Mod/Leader** | - | - | - | Y | - | - | - | - | - | - | - | Y |
|
||||
| **GET Features** | F | B | F | F | F | F | F | B | F | G | F | F |
|
||||
| **PUT Features** | F | B | F | F | F | F | F | G | F | G | F | F |
|
||||
| **POST Features** | F | - | F | F | - | F | F | - | - | - | F | F |
|
||||
| **DEL Features** | F | B | F | F | F | F | F | B | G | B | F | F |
|
||||
|
||||
**Legend**
|
||||
|
||||
**F**: Full support **G**: Good support **B**: Basic support
|
||||
**Y**: Feature supported **-**: Feature not supported
|
61
Documentation/cluster-discovery.md
Normal file
61
Documentation/cluster-discovery.md
Normal file
@ -0,0 +1,61 @@
|
||||
# Cluster Discovery
|
||||
|
||||
## Overview
|
||||
|
||||
Starting an etcd cluster requires that each node knows another in the cluster. If you are trying to bring up a cluster all at once, say using a cloud formation, you also need to coordinate who will be the initial cluster leader. The discovery protocol helps you by providing an automated way to discover other existing peers in a cluster.
|
||||
|
||||
For more information on how etcd can locate the cluster, see the [finding the cluster][cluster-finding] documentation.
|
||||
|
||||
Please note - at least 3 nodes are required for [cluster availability][optimal-cluster-size].
|
||||
|
||||
[optimal-cluster-size]: https://github.com/coreos/etcd/blob/master/Documentation/optimal-cluster-size.md
|
||||
|
||||
## Using discovery.etcd.io
|
||||
|
||||
### Create a Token
|
||||
|
||||
To use the discovery API, you must first create a token for your etcd cluster. Visit [https://discovery.etcd.io/new](https://discovery.etcd.io/new) to create a new token.
|
||||
|
||||
You can inspect the list of peers by viewing `https://discovery.etcd.io/<token>`.
|
||||
|
||||
### Start etcd With the Discovery Flag
|
||||
|
||||
Specify the `-discovery` flag when you start each etcd instance. The list of existing peers in the cluster will be downloaded and configured. If the instance is the first peer, it will start as the leader of the cluster.
|
||||
|
||||
Here's a full example:
|
||||
|
||||
```
|
||||
TOKEN=$(curl https://discovery.etcd.io/new)
|
||||
./etcd -name instance1 -peer-addr 10.1.2.3:7001 -addr 10.1.2.3:4001 -discovery $TOKEN
|
||||
./etcd -name instance2 -peer-addr 10.1.2.4:7002 -addr 10.1.2.4:4002 -discovery $TOKEN
|
||||
./etcd -name instance3 -peer-addr 10.1.2.5:7002 -addr 10.1.2.5:4002 -discovery $TOKEN
|
||||
```
|
||||
|
||||
## Running Your Own Discovery Endpoint
|
||||
|
||||
The discovery API communicates with a separate etcd cluster to store and retrieve the list of peers. CoreOS provides [https://discovery.etcd.io](https://discovery.etcd.io) as a free service, but you can easily run your own etcd cluster for this purpose. Here's an example using an etcd cluster located at `10.10.10.10:4001`:
|
||||
|
||||
```
|
||||
TOKEN="testcluster"
|
||||
./etcd -name instance1 -peer-addr 10.1.2.3:7001 -addr 10.1.2.3:4001 -discovery http://10.10.10.10:4001/v2/keys/$TOKEN
|
||||
./etcd -name instance2 -peer-addr 10.1.2.4:7002 -addr 10.1.2.4:4002 -discovery http://10.10.10.10:4001/v2/keys/$TOKEN
|
||||
./etcd -name instance3 -peer-addr 10.1.2.5:7002 -addr 10.1.2.5:4002 -discovery http://10.10.10.10:4001/v2/keys/$TOKEN
|
||||
```
|
||||
|
||||
If you're interested in how to discovery API works behind the scenes, read about the [Discovery Protocol](https://github.com/coreos/etcd/blob/master/Documentation/discovery-protocol.md).
|
||||
|
||||
## Setting Peer Addresses Correctly
|
||||
|
||||
The Discovery API submits the `-peer-addr` of each etcd instance to the configured Discovery endpoint. It's important to select an address that *all* peers in the cluster can communicate with. For example, if you're located in two regions of a cloud provider, configuring a private `10.x` address will not work between the two regions, and communication will not be possible between all peers.
|
||||
|
||||
## Stale Peers
|
||||
|
||||
The discovery API will automatically clean up the address of a stale peer that is no longer part of the cluster. The TTL for this process is a week, which should be long enough to handle any extremely long outage you may encounter. There is no harm in having stale peers in the list until they are cleaned up, since an etcd instance only needs to connect to one valid peer in the cluster to join.
|
||||
|
||||
[discovery-design]: https://github.com/coreos/etcd/blob/master/Documentation/design/cluster-finding.md
|
||||
|
||||
## Lifetime of a Discovery URL
|
||||
|
||||
A discovery URL identifies a single etcd cluster. Do not re-use discovery URLs for new clusters.
|
||||
|
||||
When a machine starts with a new discovery URL the discovery URL will be activated and record the machine's metadata. If you destroy the whole cluster and attempt to bring the cluster back up with the same discovery URL it will fail. This is intentional because all of the registered machines are gone including their logs so there is nothing to recover the killed cluster.
|
169
Documentation/clustering.md
Normal file
169
Documentation/clustering.md
Normal file
@ -0,0 +1,169 @@
|
||||
## Clustering
|
||||
|
||||
### Example cluster of three machines
|
||||
|
||||
Let's explore the use of etcd clustering.
|
||||
We use Raft as the underlying distributed protocol which provides consistency and persistence of the data across all of the etcd instances.
|
||||
|
||||
Let start by creating 3 new etcd instances.
|
||||
|
||||
We use `-peer-addr` to specify server port and `-addr` to specify client port and `-data-dir` to specify the directory to store the log and info of the machine in the cluster:
|
||||
|
||||
```sh
|
||||
./etcd -peer-addr 127.0.0.1:7001 -addr 127.0.0.1:4001 -data-dir machines/machine1 -name machine1
|
||||
```
|
||||
|
||||
**Note:** If you want to run etcd on an external IP address and still have access locally, you'll need to add `-bind-addr 0.0.0.0` so that it will listen on both external and localhost addresses.
|
||||
A similar argument `-peer-bind-addr` is used to setup the listening address for the server port.
|
||||
|
||||
Let's join two more machines to this cluster using the `-peers` argument. A single connection to any peer will allow a new machine to join, but multiple can be specified for greater resiliency.
|
||||
|
||||
```sh
|
||||
./etcd -peer-addr 127.0.0.1:7002 -addr 127.0.0.1:4002 -peers 127.0.0.1:7001,127.0.0.1:7003 -data-dir machines/machine2 -name machine2
|
||||
./etcd -peer-addr 127.0.0.1:7003 -addr 127.0.0.1:4003 -peers 127.0.0.1:7001,127.0.0.1:7002 -data-dir machines/machine3 -name machine3
|
||||
```
|
||||
|
||||
We can retrieve a list of machines in the cluster using the HTTP API:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v2/machines
|
||||
```
|
||||
|
||||
We should see there are three machines in the cluster
|
||||
|
||||
```
|
||||
http://127.0.0.1:4001, http://127.0.0.1:4002, http://127.0.0.1:4003
|
||||
```
|
||||
|
||||
The machine list is also available via the main key API:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v2/keys/_etcd/machines
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "get",
|
||||
"node": {
|
||||
"createdIndex": 1,
|
||||
"dir": true,
|
||||
"key": "/_etcd/machines",
|
||||
"modifiedIndex": 1,
|
||||
"nodes": [
|
||||
{
|
||||
"createdIndex": 1,
|
||||
"key": "/_etcd/machines/machine1",
|
||||
"modifiedIndex": 1,
|
||||
"value": "raft=http://127.0.0.1:7001&etcd=http://127.0.0.1:4001"
|
||||
},
|
||||
{
|
||||
"createdIndex": 2,
|
||||
"key": "/_etcd/machines/machine2",
|
||||
"modifiedIndex": 2,
|
||||
"value": "raft=http://127.0.0.1:7002&etcd=http://127.0.0.1:4002"
|
||||
},
|
||||
{
|
||||
"createdIndex": 3,
|
||||
"key": "/_etcd/machines/machine3",
|
||||
"modifiedIndex": 3,
|
||||
"value": "raft=http://127.0.0.1:7003&etcd=http://127.0.0.1:4003"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We can also get the current leader in the cluster:
|
||||
|
||||
```
|
||||
curl -L http://127.0.0.1:4001/v2/leader
|
||||
```
|
||||
|
||||
The first server we set up should still be the leader unless it has died during these commands.
|
||||
|
||||
```
|
||||
http://127.0.0.1:7001
|
||||
```
|
||||
|
||||
Now we can do normal SET and GET operations on keys as we explored earlier.
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v2/keys/foo -XPUT -d value=bar
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "set",
|
||||
"node": {
|
||||
"createdIndex": 4,
|
||||
"key": "/foo",
|
||||
"modifiedIndex": 4,
|
||||
"value": "bar"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Rejoining to the Cluster
|
||||
|
||||
If one machine disconnects from the cluster, it could rejoin the cluster automatically when the communication is recovered.
|
||||
|
||||
If one machine is killed, it could rejoin the cluster when started with old name. If the peer address is changed, etcd will treat the new peer address as the refreshed one, which benefits instance migration, or virtual machine boot with different IP. The peer-address-changing functionality is only supported when the majority of the cluster is alive, because this behavior needs the consensus of the etcd cluster.
|
||||
|
||||
**Note:** For now, it is user responsibility to ensure that the machine doesn't join the cluster that has the member with the same name. Or unexpected error will happen. It would be improved sooner or later.
|
||||
|
||||
### Killing Nodes in the Cluster
|
||||
|
||||
Now if we kill the leader of the cluster, we can get the value from one of the other two machines:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4002/v2/keys/foo
|
||||
```
|
||||
|
||||
We can also see that a new leader has been elected:
|
||||
|
||||
```
|
||||
curl -L http://127.0.0.1:4002/v2/leader
|
||||
```
|
||||
|
||||
```
|
||||
http://127.0.0.1:7002
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
http://127.0.0.1:7003
|
||||
```
|
||||
|
||||
|
||||
### Testing Persistence
|
||||
|
||||
Next we'll kill all the machines to test persistence.
|
||||
Type `CTRL-C` on each terminal and then rerun the same command you used to start each machine.
|
||||
|
||||
Your request for the `foo` key will return the correct value:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4002/v2/keys/foo
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "get",
|
||||
"node": {
|
||||
"createdIndex": 4,
|
||||
"key": "/foo",
|
||||
"modifiedIndex": 4,
|
||||
"value": "bar"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Using HTTPS between servers
|
||||
|
||||
In the previous example we showed how to use SSL client certs for client-to-server communication.
|
||||
Etcd can also do internal server-to-server communication using SSL client certs.
|
||||
To do this just change the `-*-file` flags to `-peer-*-file`.
|
||||
|
||||
If you are using SSL for server-to-server communication, you must use it on all instances of etcd.
|
107
Documentation/configuration.md
Normal file
107
Documentation/configuration.md
Normal file
@ -0,0 +1,107 @@
|
||||
# Etcd Configuration
|
||||
|
||||
Configuration options can be set in three places:
|
||||
|
||||
1. Command line flags
|
||||
2. Environment variables
|
||||
3. Configuration file
|
||||
|
||||
Options set on the command line take precedence over all other sources.
|
||||
Options set in environment variables take precedence over options set in
|
||||
configuration files.
|
||||
|
||||
## Command Line Flags
|
||||
|
||||
### Required
|
||||
|
||||
* `-name` - The node name. Defaults to the hostname.
|
||||
|
||||
### Optional
|
||||
|
||||
* `-addr` - The advertised public hostname:port for client communication. Defaults to `127.0.0.1:4001`.
|
||||
* `-discovery` - A URL to use for discovering the peer list. (i.e `"https://discovery.etcd.io/your-unique-key"`).
|
||||
* `-bind-addr` - The listening hostname for client communication. Defaults to advertised IP.
|
||||
* `-peers` - A comma separated list of peers in the cluster (i.e `"203.0.113.101:7001,203.0.113.102:7001"`).
|
||||
* `-peers-file` - The file path containing a comma separated list of peers in the cluster.
|
||||
* `-ca-file` - The path of the client CAFile. Enables client cert authentication when present.
|
||||
* `-cert-file` - The cert file of the client.
|
||||
* `-key-file` - The key file of the client.
|
||||
* `-config` - The path of the etcd configuration file. Defaults to `/etc/etcd/etcd.conf`.
|
||||
* `-cors` - A comma separated white list of origins for cross-origin resource sharing.
|
||||
* `-cpuprofile` - The path to a file to output CPU profile data. Enables CPU profiling when present.
|
||||
* `-data-dir` - The directory to store log and snapshot. Defaults to the current working directory.
|
||||
* `-max-result-buffer` - The max size of result buffer. Defaults to `1024`.
|
||||
* `-max-cluster-size` - The max size of the cluster. Defaults to `9`.
|
||||
* `-max-retry-attempts` - The max retry attempts when trying to join a cluster. Defaults to `3`.
|
||||
* `-peer-addr` - The advertised public hostname:port for server communication. Defaults to `127.0.0.1:7001`.
|
||||
* `-peer-bind-addr` - The listening hostname for server communication. Defaults to advertised IP.
|
||||
* `-peer-ca-file` - The path of the CAFile. Enables client/peer cert authentication when present.
|
||||
* `-peer-cert-file` - The cert file of the server.
|
||||
* `-peer-key-file` - The key file of the server.
|
||||
* `-peer-election-timeout` - The number of milliseconds to wait before the leader is declared unhealthy.
|
||||
* `-peer-heartbeat-interval` - The number of milliseconds in between heartbeat requests
|
||||
* `-snapshot=false` - Disable log snapshots. Defaults to `true`.
|
||||
* `-v` - Enable verbose logging. Defaults to `false`.
|
||||
* `-vv` - Enable very verbose logging. Defaults to `false`.
|
||||
* `-version` - Print the version and exit.
|
||||
|
||||
## Configuration File
|
||||
|
||||
The etcd configuration file is written in [TOML](https://github.com/mojombo/toml)
|
||||
and read from `/etc/etcd/etcd.conf` by default.
|
||||
|
||||
```TOML
|
||||
addr = "127.0.0.1:4001"
|
||||
bind_addr = "127.0.0.1:4001"
|
||||
ca_file = ""
|
||||
cert_file = ""
|
||||
cors = []
|
||||
cpu_profile_file = ""
|
||||
data_dir = "."
|
||||
discovery = "http://etcd.local:4001/v2/keys/_etcd/registry/examplecluster"
|
||||
key_file = ""
|
||||
peers = []
|
||||
peers_file = ""
|
||||
max_cluster_size = 9
|
||||
max_result_buffer = 1024
|
||||
max_retry_attempts = 3
|
||||
name = "default-name"
|
||||
snapshot = false
|
||||
verbose = false
|
||||
very_verbose = false
|
||||
|
||||
[peer]
|
||||
addr = "127.0.0.1:7001"
|
||||
bind_addr = "127.0.0.1:7001"
|
||||
ca_file = ""
|
||||
cert_file = ""
|
||||
key_file = ""
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
* `ETCD_ADDR`
|
||||
* `ETCD_BIND_ADDR`
|
||||
* `ETCD_CA_FILE`
|
||||
* `ETCD_CERT_FILE`
|
||||
* `ETCD_CORS_ORIGINS`
|
||||
* `ETCD_CONFIG`
|
||||
* `ETCD_CPU_PROFILE_FILE`
|
||||
* `ETCD_DATA_DIR`
|
||||
* `ETCD_DISCOVERY`
|
||||
* `ETCD_KEY_FILE`
|
||||
* `ETCD_PEERS`
|
||||
* `ETCD_PEERS_FILE`
|
||||
* `ETCD_MAX_CLUSTER_SIZE`
|
||||
* `ETCD_MAX_RESULT_BUFFER`
|
||||
* `ETCD_MAX_RETRY_ATTEMPTS`
|
||||
* `ETCD_NAME`
|
||||
* `ETCD_SNAPSHOT`
|
||||
* `ETCD_VERBOSE`
|
||||
* `ETCD_VERY_VERBOSE`
|
||||
* `ETCD_PEER_ADDR`
|
||||
* `ETCD_PEER_BIND_ADDR`
|
||||
* `ETCD_PEER_CA_FILE`
|
||||
* `ETCD_PEER_CERT_FILE`
|
||||
* `ETCD_PEER_KEY_FILE`
|
||||
* `ETCD_PEER_ELECTION_TIMEOUT`
|
69
Documentation/debugging.md
Normal file
69
Documentation/debugging.md
Normal file
@ -0,0 +1,69 @@
|
||||
# Debugging etcd
|
||||
|
||||
Diagnosing issues in a distributed application is hard.
|
||||
etcd will help as much as it can - just enable these debug features using the CLI flag `-trace=*` or the config option `trace=*`.
|
||||
|
||||
## Logging
|
||||
|
||||
Log verbosity can be increased to the max using either the `-vvv` CLI flag or the `very_very_verbose=true` config option.
|
||||
|
||||
The only supported logging mode is to stdout.
|
||||
|
||||
## Metrics
|
||||
|
||||
etcd itself can generate a set of metrics.
|
||||
These metrics represent many different internal data points that can be helpful when debugging etcd servers.
|
||||
|
||||
#### Metrics reference
|
||||
|
||||
Each individual metric name is prefixed with `etcd.<NAME>`, where \<NAME\> is the configured name of the etcd server.
|
||||
|
||||
* `timer.appendentries.handle`: amount of time a peer takes to process an AppendEntriesRequest from the POV of the peer itself
|
||||
* `timer.peer.<PEER>.heartbeat`: amount of time a peer heartbeat operation takes from the POV of the leader that initiated that operation for peer \<PEER\>
|
||||
* `timer.command.<COMMAND>`: amount of time a given command took to be processed through the local server's raft state machine. This does not include time waiting on locks.
|
||||
|
||||
#### Fetching metrics over HTTP
|
||||
|
||||
Once tracing has been enabled on a given etcd server, all metric data is available at the server's `/debug/metrics` HTTP endpoint (i.e. `http://127.0.0.1:4001/debug/metrics`).
|
||||
Executing a GET HTTP command against the metrics endpoint will yield the current state of all metrics in the etcd server.
|
||||
|
||||
#### Sending metrics to Graphite
|
||||
|
||||
etcd supports [Graphite's Carbon plaintext protocol](https://graphite.readthedocs.org/en/latest/feeding-carbon.html#the-plaintext-protocol) - a TCP wire protocol designed for shipping metric data to an aggregator.
|
||||
To send metrics to a Graphite endpoint using this protocol, use of the `-graphite-host` CLI flag or the `graphite_host` config option (i.e. `graphite_host=172.17.0.19:2003`).
|
||||
|
||||
See an [example graphite deploy script](https://github.com/coreos/etcd/contrib/graphite).
|
||||
|
||||
#### Generating additional metrics with Collectd
|
||||
|
||||
[Collectd](http://collectd.org/documentation.shtml) gathers metrics from the host running etcd.
|
||||
While these aren't metrics generated by etcd itself, it can be invaluable to compare etcd's view of the world to that of a separate process running next to etcd.
|
||||
|
||||
See an [example collectd deploy script](https://github.com/coreos/etcd/contrib/collectd).
|
||||
|
||||
## Profiling
|
||||
|
||||
etcd exposes profiling information from the Go pprof package over HTTP.
|
||||
The basic browsable interface is served by etcd at the `/debug/pprof` HTTP endpoint (i.e. `http://127.0.0.1:4001/debug/pprof`).
|
||||
For more information on using profiling tools, see http://blog.golang.org/profiling-go-programs.
|
||||
|
||||
**NOTE**: In the following examples you need to ensure that the `./bin/etcd` is identical to the `./bin/etcd` that you are targeting (same git hash, arch, platform, etc).
|
||||
|
||||
#### Heap memory profile
|
||||
|
||||
```
|
||||
go tool pprof ./bin/etcd http://127.0.0.1:4001/debug/pprof/heap
|
||||
```
|
||||
|
||||
#### CPU profile
|
||||
|
||||
```
|
||||
go tool pprof ./bin/etcd http://127.0.0.1:4001/debug/pprof/profile
|
||||
```
|
||||
|
||||
#### Blocked goroutine profile
|
||||
|
||||
```
|
||||
go tool pprof ./bin/etcd http://127.0.0.1:4001/debug/pprof/block
|
||||
```
|
||||
|
34
Documentation/design/cluster-finding.md
Normal file
34
Documentation/design/cluster-finding.md
Normal file
@ -0,0 +1,34 @@
|
||||
## Cluster Finding Process
|
||||
|
||||
Peer discovery uses the following sources in this order: log data in `-data-dir`, `-discovery` and `-peers`.
|
||||
|
||||
If log data is provided, etcd will concatenate possible peers from three sources: the log data, the `-discovery` option, and `-peers`. Then it tries to join cluster through them one by one. If all connection attempts fail (which indicates that the majority of the cluster is currently down), it will restart itself based on the log data, which helps the cluster to recover from a full outage.
|
||||
|
||||
Without log data, the instance is assumed to be a brand new one. If possible targets are provided by `-discovery` and `-peers`, etcd will make a best effort attempt to join them, and if none is reachable it will exit. Otherwise, if no `-discovery` or `-peers` option is provided, a new cluster will always be started.
|
||||
|
||||
This ensures that users can always restart the node safely with the same command (without --force), and etcd will either reconnect to the old cluster if it is still running or recover its cluster from a outage.
|
||||
|
||||
## Logical Workflow
|
||||
|
||||
Start an etcd machine:
|
||||
|
||||
```
|
||||
If log data is given:
|
||||
Try to join via peers in previous cluster
|
||||
Try to join via peers found in discover URL
|
||||
Try to join via peers in peer list
|
||||
Restart the previous cluster which is down
|
||||
return
|
||||
|
||||
If discover URL is given:
|
||||
Fetch peers through discover URL
|
||||
If Success:
|
||||
Join via peers found
|
||||
return
|
||||
|
||||
If peer list is given:
|
||||
Join as follower via peers in peer list
|
||||
return
|
||||
|
||||
Start as the leader of a new cluster
|
||||
```
|
232
Documentation/design/standbys.md
Normal file
232
Documentation/design/standbys.md
Normal file
@ -0,0 +1,232 @@
|
||||
## Standbys
|
||||
|
||||
Adding peers in an etcd cluster adds network, CPU, and disk overhead to the leader since each one requires replication.
|
||||
Peers primarily provide resiliency in the event of a leader failure but the benefit of more failover nodes decreases as the cluster size increases.
|
||||
A lightweight alternative is the standby.
|
||||
|
||||
Standbys are a way for an etcd node to forward requests along to the cluster but the standbys are not part of the Raft cluster themselves.
|
||||
This provides an easier API for local applications while reducing the overhead required by a regular peer node.
|
||||
Standbys also act as standby nodes in the event that a peer node in the cluster has not recovered after a long duration.
|
||||
|
||||
|
||||
## Configuration Parameters
|
||||
|
||||
There are three configuration parameters used by standbys: active size, remove delay and standby sync interval.
|
||||
|
||||
The active size specifies a target size for the number of peers in the cluster.
|
||||
If there are not enough peers to meet the active size, standbys will send join requests until the peer count is equal to the active size.
|
||||
If there are more peers than the target active size then peers are removed by the leader and will become standbys.
|
||||
|
||||
The remove delay specifies how long the cluster should wait before removing a dead peer.
|
||||
By default this is 30 minutes.
|
||||
If a peer is inactive for 30 minutes then the peer is removed.
|
||||
|
||||
The standby sync interval specifies the synchronization interval of standbys with the cluster.
|
||||
By default this is 5 seconds.
|
||||
After each interval, standbys synchronize information with cluster.
|
||||
|
||||
|
||||
## Logical Workflow
|
||||
|
||||
### Start a etcd machine
|
||||
|
||||
#### Main logic
|
||||
|
||||
```
|
||||
If find existing standby cluster info:
|
||||
Goto standby loop
|
||||
|
||||
Find cluster as required
|
||||
If determine to start peer server:
|
||||
Goto peer loop
|
||||
Else:
|
||||
Goto standby loop
|
||||
|
||||
Peer loop:
|
||||
Start peer mode
|
||||
If running:
|
||||
Wait for stop
|
||||
Goto standby loop
|
||||
|
||||
Standby loop:
|
||||
Start standby mode
|
||||
If running:
|
||||
Wait for stop
|
||||
Goto peer loop
|
||||
```
|
||||
|
||||
|
||||
#### [Cluster finding logic][cluster-finding.md]
|
||||
|
||||
|
||||
#### Join request logic:
|
||||
|
||||
```
|
||||
Fetch machine info
|
||||
If cannot match version:
|
||||
return false
|
||||
If active size <= peer count:
|
||||
return false
|
||||
If it has existed in the cluster:
|
||||
return true
|
||||
If join request fails:
|
||||
return false
|
||||
return true
|
||||
```
|
||||
|
||||
**Note**
|
||||
1. [TODO] The running mode cannot be determined by log, because the log may be outdated. But the log could be used to estimate its state.
|
||||
2. Even if sync cluster fails, it will restart still for recovery from full outage.
|
||||
|
||||
|
||||
#### Peer mode start logic
|
||||
|
||||
```
|
||||
Start raft server
|
||||
Start other helper routines
|
||||
```
|
||||
|
||||
|
||||
#### Peer mode auto stop logic
|
||||
|
||||
```
|
||||
When removed from the cluster:
|
||||
Stop raft server
|
||||
Stop other helper routines
|
||||
```
|
||||
|
||||
|
||||
#### Standby mode run logic
|
||||
|
||||
```
|
||||
Loop:
|
||||
Sleep for some time
|
||||
|
||||
Sync cluster, and write cluster info into disk
|
||||
|
||||
Check active size and send join request if needed
|
||||
If succeed:
|
||||
Clear cluster info from disk
|
||||
Return
|
||||
```
|
||||
|
||||
|
||||
#### Serve Requests as Standby
|
||||
|
||||
Return '404 Page Not Found' always on peer address. This is because peer address is used for raft communication and cluster management, which should not be used in standby mode.
|
||||
|
||||
|
||||
Serve requests from client:
|
||||
|
||||
```
|
||||
Redirect all requests to client URL of leader
|
||||
```
|
||||
|
||||
**Note**
|
||||
1. The leader here implies the one in raft cluster when doing the latest successful synchronization.
|
||||
2. [IDEA] We could extend HTTP Redirect to multiple possible targets.
|
||||
|
||||
|
||||
### Join Request Handling
|
||||
|
||||
```
|
||||
If machine has existed in the cluster:
|
||||
Return
|
||||
If peer count < active size:
|
||||
Add peer
|
||||
Increase peer count
|
||||
```
|
||||
|
||||
|
||||
### Remove Request Handling
|
||||
|
||||
```
|
||||
If machine exists in the cluster:
|
||||
Remove peer
|
||||
Decrease peer count
|
||||
```
|
||||
|
||||
|
||||
## Cluster Monitor Logic
|
||||
|
||||
### Active Size Monitor:
|
||||
|
||||
This is only run by current cluster leader.
|
||||
|
||||
```
|
||||
Loop:
|
||||
Sleep for some time
|
||||
|
||||
If peer count > active size:
|
||||
Remove randomly selected peer
|
||||
```
|
||||
|
||||
|
||||
### Peer Activity Monitor
|
||||
|
||||
This is only run by current cluster leader.
|
||||
|
||||
```
|
||||
Loop:
|
||||
Sleep for some time
|
||||
|
||||
For each peer:
|
||||
If peer last activity time > remove delay:
|
||||
Remove the peer
|
||||
Goto Loop
|
||||
```
|
||||
|
||||
|
||||
## Cluster Cases
|
||||
|
||||
### Create Cluster with Thousands of Instances
|
||||
|
||||
First few machines run in peer mode.
|
||||
|
||||
All the others check the status of the cluster and run in standby mode.
|
||||
|
||||
|
||||
### Recover from full outage
|
||||
|
||||
Machines with log data restart with join failure.
|
||||
|
||||
Machines in peer mode recover heartbeat between each other.
|
||||
|
||||
Machines in standby mode always sync the cluster. If sync fails, it uses the first address from data log as redirect target.
|
||||
|
||||
|
||||
### Kill one peer machine
|
||||
|
||||
Leader of the cluster lose the connection with the peer.
|
||||
|
||||
When the time exceeds remove delay, it removes the peer from the cluster.
|
||||
|
||||
Machine in standby mode finds one available place of the cluster. It sends join request and joins the cluster.
|
||||
|
||||
**Note**
|
||||
1. [TODO] Machine which was divided from majority and was removed from the cluster will distribute running of the cluster if the new node uses the same name.
|
||||
|
||||
|
||||
### Kill one standby machine
|
||||
|
||||
No change for the cluster.
|
||||
|
||||
|
||||
## Cons
|
||||
|
||||
1. New instance cannot join immediately after one peer is kicked out of the cluster, because the leader doesn't know the info about the standby instances.
|
||||
|
||||
2. It may introduce join collision
|
||||
|
||||
3. Cluster needs a good interval setting to balance the join delay and join collision.
|
||||
|
||||
|
||||
## Future Attack Plans
|
||||
|
||||
1. Based on heartbeat miss and remove delay, standby could adjust its next check time.
|
||||
|
||||
2. Preregister the promotion target when heartbeat miss happens.
|
||||
|
||||
3. Get the estimated cluster size from the check happened in the sync interval, and adjust sync interval dynamically.
|
||||
|
||||
4. Accept join requests based on active size and alive peers.
|
12
Documentation/development-tools.md
Normal file
12
Documentation/development-tools.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Development tools
|
||||
|
||||
## Vagrant
|
||||
|
||||
For fast start you can use Vagrant. `vagrant up` will make etcd build and running on virtual machine. Required Vagrant version is 1.5.0.
|
||||
|
||||
Next lets set a single key and then retrieve it:
|
||||
|
||||
```
|
||||
curl -L http://127.0.0.1:4001/v2/keys/mykey -XPUT -d value="this is awesome"
|
||||
curl -L http://127.0.0.1:4001/v2/keys/mykey
|
||||
```
|
87
Documentation/discovery-protocol.md
Normal file
87
Documentation/discovery-protocol.md
Normal file
@ -0,0 +1,87 @@
|
||||
# Discovery Protocol
|
||||
|
||||
Starting a new etcd cluster can be painful since each machine needs to know of at least one live machine in the cluster. If you are trying to bring up a new cluster all at once, say using an AWS cloud formation, you also need to coordinate who will be the initial cluster leader. The discovery protocol uses an existing running etcd cluster to start a second etcd cluster.
|
||||
|
||||
To use this feature you add the command line flag `-discovery` to your etcd args. In this example we will use `http://example.com/v2/keys/_etcd/registry` as the URL prefix.
|
||||
|
||||
## The Protocol
|
||||
|
||||
By convention the etcd discovery protocol uses the key prefix `_etcd/registry`. A full URL to the keyspace will be `http://example.com/v2/keys/_etcd/registry`.
|
||||
|
||||
### Creating a New Cluster
|
||||
|
||||
Generate a unique token that will identify the new cluster. This will be used as a key prefix in the following steps. An easy way to do this is to use uuidgen:
|
||||
|
||||
```
|
||||
UUID=$(uuidgen)
|
||||
```
|
||||
|
||||
### Bringing up Machines
|
||||
|
||||
Now that you have your cluster ID you can start bringing up machines. Every machine will follow this protocol internally in etcd if given a `-discovery`.
|
||||
|
||||
### Registering your Machine
|
||||
|
||||
The first thing etcd must do is register your machine. This is done by using the machine name (from the `-name` arg) and posting it with a long TTL to the given key.
|
||||
|
||||
```
|
||||
curl -X PUT "http://example.com/v2/keys/_etcd/registry/${UUID}/${etcd_machine_name}?ttl=604800" -d value=${peer_addr}
|
||||
```
|
||||
|
||||
### Discovering Peers
|
||||
|
||||
Now that this etcd machine is registered it must discover its peers.
|
||||
|
||||
But, the tricky bit of starting a new cluster is that one machine needs to assume the initial role of leader and will have no peers. To figure out if another machine has already started the cluster etcd needs to create the `_state` key and set its value to "started":
|
||||
|
||||
```
|
||||
curl -X PUT "http://example.com/v2/keys/_etcd/registry/${UUID}/_state?prevExist=false" -d value=started
|
||||
```
|
||||
|
||||
If this returns a `200 OK` response then this machine is the initial leader and should start with no peers configured. If, however, this returns a `412 Precondition Failed` then you need to find all of the registered peers:
|
||||
|
||||
```
|
||||
curl -X GET "http://example.com/v2/keys/_etcd/registry/${UUID}?recursive=true"
|
||||
```
|
||||
|
||||
```
|
||||
{
|
||||
"action": "get",
|
||||
"node": {
|
||||
"createdIndex": 11,
|
||||
"dir": true,
|
||||
"key": "/_etcd/registry/9D4258A5-A1D3-4074-8837-31C1E091131D",
|
||||
"modifiedIndex": 11,
|
||||
"nodes": [
|
||||
{
|
||||
"createdIndex": 16,
|
||||
"expiration": "2014-02-03T13:19:57.631253589-08:00",
|
||||
"key": "/_etcd/registry/9D4258A5-A1D3-4074-8837-31C1E091131D/peer1",
|
||||
"modifiedIndex": 16,
|
||||
"ttl": 604765,
|
||||
"value": "127.0.0.1:7001"
|
||||
},
|
||||
{
|
||||
"createdIndex": 17,
|
||||
"expiration": "2014-02-03T13:19:57.631253589-08:00",
|
||||
"key": "/_etcd/registry/9D4258A5-A1D3-4074-8837-31C1E091131D/peer2",
|
||||
"modifiedIndex": 17,
|
||||
"ttl": 604765,
|
||||
"value": "127.0.0.1:7002"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Using this information you can connect to the rest of the peers in the cluster.
|
||||
|
||||
### Heartbeating
|
||||
|
||||
At this point etcd will start heart beating to your registration URL. The
|
||||
protocol uses a heartbeat so permanently deleted nodes get slowly removed from
|
||||
the discovery information cluster.
|
||||
|
||||
The heartbeat interval is about once per day and the TTL is one week. This
|
||||
should give a sufficiently wide window to protect against a discovery service
|
||||
taking a temporary outage yet provide adequate cleanup.
|
60
Documentation/errorcode.md
Normal file
60
Documentation/errorcode.md
Normal file
@ -0,0 +1,60 @@
|
||||
Error Code
|
||||
======
|
||||
|
||||
This document describes the error code in **Etcd** project.
|
||||
|
||||
It's categorized into four groups:
|
||||
|
||||
- Command Related Error
|
||||
- Post Form Related Error
|
||||
- Raft Related Error
|
||||
- Etcd Related Error
|
||||
|
||||
Error code corresponding strerror
|
||||
------
|
||||
|
||||
const (
|
||||
EcodeKeyNotFound = 100
|
||||
EcodeTestFailed = 101
|
||||
EcodeNotFile = 102
|
||||
EcodeNoMorePeer = 103
|
||||
EcodeNotDir = 104
|
||||
EcodeNodeExist = 105
|
||||
EcodeKeyIsPreserved = 106
|
||||
EcodeRootROnly = 107
|
||||
|
||||
EcodeValueRequired = 200
|
||||
EcodePrevValueRequired = 201
|
||||
EcodeTTLNaN = 202
|
||||
EcodeIndexNaN = 203
|
||||
|
||||
EcodeRaftInternal = 300
|
||||
EcodeLeaderElect = 301
|
||||
|
||||
EcodeWatcherCleared = 400
|
||||
EcodeEventIndexCleared = 401
|
||||
)
|
||||
|
||||
// command related errors
|
||||
errors[100] = "Key Not Found"
|
||||
errors[101] = "Test Failed" //test and set
|
||||
errors[102] = "Not A File"
|
||||
errors[103] = "Reached the max number of peers in the cluster"
|
||||
errors[104] = "Not A Directory"
|
||||
errors[105] = "Already exists" // create
|
||||
errors[106] = "The prefix of given key is a keyword in etcd"
|
||||
errors[107] = "Root is read only"
|
||||
|
||||
// Post form related errors
|
||||
errors[200] = "Value is Required in POST form"
|
||||
errors[201] = "PrevValue is Required in POST form"
|
||||
errors[202] = "The given TTL in POST form is not a number"
|
||||
errors[203] = "The given index in POST form is not a number"
|
||||
|
||||
// raft related errors
|
||||
errors[300] = "Raft Internal Error"
|
||||
errors[301] = "During Leader Election"
|
||||
|
||||
// etcd related errors
|
||||
errors[400] = "watcher is cleared due to etcd recovery"
|
||||
errors[401] = "The event in requested index is outdated and cleared"
|
101
Documentation/etcd-file-system.md
Normal file
101
Documentation/etcd-file-system.md
Normal file
@ -0,0 +1,101 @@
|
||||
#Etcd File System
|
||||
|
||||
## Structure
|
||||
[TODO]
|
||||

|
||||
|
||||
## Node
|
||||
In **etcd**, the **node** is the base from which the filesystem is constructed.
|
||||
**etcd**'s file system is Unix-like with two kinds of nodes: file and directories.
|
||||
|
||||
- A **file node** has data associated with it.
|
||||
- A **directory node** has child nodes associated with it.
|
||||
|
||||
All nodes, regardless of type, have the following attributes and operations:
|
||||
|
||||
### Attributes:
|
||||
- **Expiration Time** [optional]
|
||||
|
||||
The node will be deleted when it expires.
|
||||
|
||||
- **ACL**
|
||||
|
||||
The path to the node's access control list.
|
||||
|
||||
### Operation:
|
||||
- **Get** (path, recursive, sorted)
|
||||
|
||||
Get the content of the node
|
||||
- If the node is a file, the data of the file will be returned.
|
||||
- If the node is a directory, the child nodes of the directory will be returned.
|
||||
- If recursive is true, it will recursively get the nodes of the directory.
|
||||
- If sorted is true, the result will be sorted based on the path.
|
||||
|
||||
- **Create** (path, value[optional], ttl [optional])
|
||||
|
||||
Create a file. Create operation will help to create intermediate directories with no expiration time.
|
||||
- If the file already exists, create will fail.
|
||||
- If the value is given, set will create a file.
|
||||
- If the value is not given, set will crate a directory.
|
||||
- If ttl is given, the node will be deleted when it expires.
|
||||
|
||||
- **Update** (path, value[optional], ttl [optional])
|
||||
|
||||
Update the content of the node.
|
||||
- If the value is given, the value of the key will be updated.
|
||||
- If ttl is given, the expiration time of the node will be updated.
|
||||
|
||||
- **Delete** (path, recursive)
|
||||
|
||||
Delete the node of given path.
|
||||
- If the node is a directory:
|
||||
- If recursive is true, the operation will delete all nodes under the directory.
|
||||
- If recursive is false, error will be returned.
|
||||
|
||||
- **TestAndSet** (path, prevValue [prevIndex], value, ttl)
|
||||
|
||||
Atomic *test and set* value to a file. If test succeeds, this operation will change the previous value of the file to the given value.
|
||||
- If the prevValue is given, it will test against previous value of
|
||||
the node.
|
||||
- If the prevValue is empty, it will test if the node is not existing.
|
||||
- If the prevValue is not empty, it will test if the prevValue is equal to the current value of the file.
|
||||
- If the prevIndex is given, it will test if the create/last modified index of the node is equal to prevIndex.
|
||||
|
||||
- **Renew** (path, ttl)
|
||||
|
||||
Set the node's expiration time to (current time + ttl)
|
||||
|
||||
## ACL
|
||||
|
||||
### Theory
|
||||
Etcd exports a Unix-like file system interface consisting of files and directories, collectively called nodes.
|
||||
Each node has various meta-data, including three names of the access control lists used to control reading, writing and changing (change ACL names for the node).
|
||||
|
||||
We are storing the ACL names for nodes under a special *ACL* directory.
|
||||
Each node has ACL name corresponding to one file within *ACL* dir.
|
||||
Unless overridden, a node naturally inherits the ACL names of its parent directory on creation.
|
||||
|
||||
For each ACL name, it has three children: *R (Reading)*, *W (Writing)*, *C (Changing)*
|
||||
|
||||
Each permission is also a node. Under the node it contains the users who have this permission for the file referring to this ACL name.
|
||||
|
||||
### Example
|
||||
[TODO]
|
||||
### Diagram
|
||||
[TODO]
|
||||
|
||||
### Interface
|
||||
|
||||
Testing permissions:
|
||||
|
||||
- (node *Node) get_perm()
|
||||
- (node *Node) has_perm(perm string, user string)
|
||||
|
||||
Setting/Changing permissions:
|
||||
|
||||
- (node *Node) set_perm(perm string)
|
||||
- (node *Node) change_ACLname(aclname string)
|
||||
|
||||
|
||||
## User Group
|
||||
[TODO]
|
BIN
Documentation/img/etcd_fs_structure.jpg
Normal file
BIN
Documentation/img/etcd_fs_structure.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
@ -1,12 +1,12 @@
|
||||
# Versioning
|
||||
|
||||
Goal: We want to be able to upgrade an individual machine in an etcd cluster to a newer version of etcd.
|
||||
Goal: We want to be able to upgrade an individual peer in an etcd cluster to a newer version of etcd.
|
||||
The process will take the form of individual followers upgrading to the latest version until the entire cluster is on the new version.
|
||||
|
||||
Immediate need: etcd is moving too fast to version the internal API right now.
|
||||
But, we need to keep mixed version clusters from being started by a rollowing upgrade process (e.g. the CoreOS developer alpha).
|
||||
But, we need to keep mixed version clusters from being started by a rolling upgrade process (e.g. the CoreOS developer alpha).
|
||||
|
||||
Longer term need: Having a mixed version cluster where all machines are not be running the exact same version of etcd itself but are able to speak one version of the internal protocol.
|
||||
Longer term need: Having a mixed version cluster where all peers are not running the exact same version of etcd itself but are able to speak one version of the internal protocol.
|
||||
|
||||
Solution: The internal protocol needs to be versioned just as the client protocol is.
|
||||
Initially during the 0.\*.\* series of etcd releases we won't allow mixed versions at all.
|
||||
@ -26,7 +26,7 @@ Advantages
|
||||
|
||||
Disadvantages
|
||||
|
||||
- Follower knows better what versions of the interal protocol it can talk than the leader
|
||||
- Follower knows better what versions of the internal protocol it can talk than the leader
|
||||
|
||||
|
||||
### Follower Controlled
|
||||
@ -58,4 +58,4 @@ https://issues.apache.org/jira/browse/ZOOKEEPER-1633
|
||||
|
||||
## doozerd
|
||||
|
||||
doozerd stores the version number of the machine in the datastore for other clients to check, no decisions are made off of this number currently.
|
||||
doozerd stores the version number of the peers in the datastore for other clients to check, no decisions are made off of this number currently.
|
||||
|
92
Documentation/libraries-and-tools.md
Normal file
92
Documentation/libraries-and-tools.md
Normal file
@ -0,0 +1,92 @@
|
||||
## Libraries and Tools
|
||||
|
||||
**Tools**
|
||||
|
||||
- [etcdctl](https://github.com/coreos/etcdctl) - A command line client for etcd
|
||||
- [etcd-dump](https://npmjs.org/package/etcd-dump) - Command line utility for dumping/restoring etcd.
|
||||
- [etcd-fs](https://github.com/xetorthio/etcd-fs) - FUSE filesystem for etcd
|
||||
|
||||
**Go libraries**
|
||||
|
||||
- [go-etcd](https://github.com/coreos/go-etcd) - Supports v2
|
||||
|
||||
**Java libraries**
|
||||
|
||||
- [justinsb/jetcd](https://github.com/justinsb/jetcd)
|
||||
- [diwakergupta/jetcd](https://github.com/diwakergupta/jetcd) - Supports v2
|
||||
|
||||
**Python libraries**
|
||||
|
||||
- [transitorykris/etcd-py](https://github.com/transitorykris/etcd-py)
|
||||
- [jplana/python-etcd](https://github.com/jplana/python-etcd) - Supports v2
|
||||
- [russellhaering/txetcd](https://github.com/russellhaering/txetcd) - a Twisted Python library
|
||||
- [cholcombe973/autodock](https://github.com/cholcombe973/autodock) - A docker deployment automation tool
|
||||
|
||||
**Node libraries**
|
||||
|
||||
- [stianeikeland/node-etcd](https://github.com/stianeikeland/node-etcd) - Supports v2 (w Coffeescript)
|
||||
- [lavagetto/nodejs-etcd](https://github.com/lavagetto/nodejs-etcd) - Supports v2
|
||||
|
||||
**Ruby libraries**
|
||||
|
||||
- [iconara/etcd-rb](https://github.com/iconara/etcd-rb)
|
||||
- [jpfuentes2/etcd-ruby](https://github.com/jpfuentes2/etcd-ruby)
|
||||
- [ranjib/etcd-ruby](https://github.com/ranjib/etcd-ruby) - Supports v2
|
||||
|
||||
**C libraries**
|
||||
|
||||
- [jdarcy/etcd-api](https://github.com/jdarcy/etcd-api) - Supports v2
|
||||
|
||||
**Clojure libraries**
|
||||
|
||||
- [aterreno/etcd-clojure](https://github.com/aterreno/etcd-clojure)
|
||||
- [dwwoelfel/cetcd](https://github.com/dwwoelfel/cetcd) - Supports v2
|
||||
- [rthomas/clj-etcd](https://github.com/rthomas/clj-etcd) - Supports v2
|
||||
|
||||
**Erlang libraries**
|
||||
|
||||
- [marshall-lee/etcd.erl](https://github.com/marshall-lee/etcd.erl)
|
||||
|
||||
**.Net Libraries**
|
||||
|
||||
- [drusellers/etcetera](https://github.com/drusellers/etcetera)
|
||||
|
||||
**PHP Libraries**
|
||||
|
||||
- [linkorb/etcd-php](https://github.com/linkorb/etcd-php)
|
||||
|
||||
**Haskell libraries**
|
||||
|
||||
- [wereHamster/etcd-hs](https://github.com/wereHamster/etcd-hs)
|
||||
|
||||
A detailed recap of client functionalities can be found in the [clients compatibility matrix][clients-matrix.md].
|
||||
|
||||
[clients-matrix.md]: https://github.com/coreos/etcd/blob/master/Documentation/clients-matrix.md
|
||||
|
||||
**Chef Integration**
|
||||
|
||||
- [coderanger/etcd-chef](https://github.com/coderanger/etcd-chef)
|
||||
|
||||
**Chef Cookbook**
|
||||
|
||||
- [spheromak/etcd-cookbook](https://github.com/spheromak/etcd-cookbook)
|
||||
|
||||
**BOSH Releases**
|
||||
|
||||
- [cloudfoundry-community/etcd-boshrelease](https://github.com/cloudfoundry-community/etcd-boshrelease)
|
||||
- [cloudfoundry/cf-release](https://github.com/cloudfoundry/cf-release/tree/master/jobs/etcd)
|
||||
|
||||
**Projects using etcd**
|
||||
|
||||
- [binocarlos/yoda](https://github.com/binocarlos/yoda) - etcd + ZeroMQ
|
||||
- [calavera/active-proxy](https://github.com/calavera/active-proxy) - HTTP Proxy configured with etcd
|
||||
- [derekchiang/etcdplus](https://github.com/derekchiang/etcdplus) - A set of distributed synchronization primitives built upon etcd
|
||||
- [go-discover](https://github.com/flynn/go-discover) - service discovery in Go
|
||||
- [gleicon/goreman](https://github.com/gleicon/goreman/tree/etcd) - Branch of the Go Foreman clone with etcd support
|
||||
- [garethr/hiera-etcd](https://github.com/garethr/hiera-etcd) - Puppet hiera backend using etcd
|
||||
- [mattn/etcd-vim](https://github.com/mattn/etcd-vim) - SET and GET keys from inside vim
|
||||
- [mattn/etcdenv](https://github.com/mattn/etcdenv) - "env" shebang with etcd integration
|
||||
- [kelseyhightower/confd](https://github.com/kelseyhightower/confd) - Manage local app config files using templates and data from etcd
|
||||
- [configdb](https://git.autistici.org/ai/configdb/tree/master) - A REST relational abstraction on top of arbitrary database backends, aimed at storing configs and inventories.
|
||||
- [scrz](https://github.com/scrz/scrz) - Container manager, stores configuration in etcd.
|
||||
- [fleet](https://github.com/coreos/fleet) - Distributed init system
|
118
Documentation/modules.md
Normal file
118
Documentation/modules.md
Normal file
@ -0,0 +1,118 @@
|
||||
## Modules
|
||||
|
||||
etcd has a number of modules that are built on top of the core etcd API.
|
||||
These modules provide things like dashboards, locks and leader election.
|
||||
|
||||
**Warning**: Modules are deprecated from v0.4 until we have a solid base we can apply them back onto.
|
||||
For now, we are choosing to focus on raft algorithm and core etcd to make sure that it works correctly and fast.
|
||||
And it is time consuming to maintain these modules in this period, given that etcd's API changes from time to time.
|
||||
Moreover, the lock module has some unfixed bugs, which may mislead users.
|
||||
But we also notice that these modules are popular and useful, and plan to add them back with full functionality as soon as possible.
|
||||
|
||||
### Dashboard
|
||||
|
||||
An HTML dashboard can be found at `http://127.0.0.1:4001/mod/dashboard/`.
|
||||
This dashboard is compiled into the etcd binary and uses the same API as regular etcd clients.
|
||||
|
||||
Use the `-cors='*'` flag to allow your browser to request information from the current master as it changes.
|
||||
|
||||
### Lock
|
||||
|
||||
The Lock module implements a fair lock that can be used when lots of clients want access to a single resource.
|
||||
A lock can be associated with a value.
|
||||
The value is unique so if a lock tries to request a value that is already queued for a lock then it will find it and watch until that value obtains the lock.
|
||||
You may supply a `timeout` which will cancel the lock request if it is not obtained within `timeout` seconds. If `timeout` is not supplied, it is presumed to be infinite. If `timeout` is `0`, the lock request will fail if it is not immediately acquired.
|
||||
If you lock the same value on a key from two separate curl sessions they'll both return at the same time.
|
||||
|
||||
Here's the API:
|
||||
|
||||
**Acquire a lock (with no value) for "customer1"**
|
||||
|
||||
```sh
|
||||
curl -X POST http://127.0.0.1:4001/mod/v2/lock/customer1?ttl=60
|
||||
```
|
||||
|
||||
**Acquire a lock for "customer1" that is associated with the value "bar"**
|
||||
|
||||
```sh
|
||||
curl -X POST http://127.0.0.1:4001/mod/v2/lock/customer1?ttl=60 -d value=bar
|
||||
```
|
||||
|
||||
**Acquire a lock for "customer1" that is associated with the value "bar" only if it is done within 2 seconds**
|
||||
|
||||
```sh
|
||||
curl -X POST http://127.0.0.1:4001/mod/v2/lock/customer1?ttl=60 -d value=bar -d timeout=2
|
||||
```
|
||||
|
||||
**Renew the TTL on the "customer1" lock for index 2**
|
||||
|
||||
```sh
|
||||
curl -X PUT http://127.0.0.1:4001/mod/v2/lock/customer1?ttl=60 -d index=2
|
||||
```
|
||||
|
||||
**Renew the TTL on the "customer1" lock for value "bar"**
|
||||
|
||||
```sh
|
||||
curl -X PUT http://127.0.0.1:4001/mod/v2/lock/customer1?ttl=60 -d value=bar
|
||||
```
|
||||
|
||||
**Retrieve the current value for the "customer1" lock.**
|
||||
|
||||
```sh
|
||||
curl http://127.0.0.1:4001/mod/v2/lock/customer1
|
||||
```
|
||||
|
||||
**Retrieve the current index for the "customer1" lock**
|
||||
|
||||
```sh
|
||||
curl http://127.0.0.1:4001/mod/v2/lock/customer1?field=index
|
||||
```
|
||||
|
||||
**Delete the "customer1" lock with the index 2**
|
||||
|
||||
```sh
|
||||
curl -X DELETE http://127.0.0.1:4001/mod/v2/lock/customer1?index=2
|
||||
```
|
||||
|
||||
**Delete the "customer1" lock with the value "bar"**
|
||||
|
||||
```sh
|
||||
curl -X DELETE http://127.0.0.1:4001/mod/v2/lock/customer1?value=bar
|
||||
```
|
||||
|
||||
|
||||
### Leader Election
|
||||
|
||||
The Leader Election module wraps the Lock module to allow clients to come to consensus on a single value.
|
||||
This is useful when you want one server to process at a time but allow other servers to fail over.
|
||||
The API is similar to the Lock module but is limited to simple strings values.
|
||||
|
||||
Here's the API:
|
||||
|
||||
**Attempt to set a value for the "order_processing" leader key:**
|
||||
|
||||
```sh
|
||||
curl -X PUT http://127.0.0.1:4001/mod/v2/leader/order_processing?ttl=60 -d name=myserver1.foo.com
|
||||
```
|
||||
|
||||
**Retrieve the current value for the "order_processing" leader key:**
|
||||
|
||||
```sh
|
||||
curl http://127.0.0.1:4001/mod/v2/leader/order_processing
|
||||
myserver1.foo.com
|
||||
```
|
||||
|
||||
**Remove a value from the "order_processing" leader key:**
|
||||
|
||||
```sh
|
||||
curl -X DELETE http://127.0.0.1:4001/mod/v2/leader/order_processing?name=myserver1.foo.com
|
||||
```
|
||||
|
||||
If multiple clients attempt to set the value for a key then only one will succeed.
|
||||
The other clients will hang until the current value is removed because of TTL or because of a `DELETE` operation.
|
||||
Multiple clients can submit the same value and will all be notified when that value succeeds.
|
||||
|
||||
To update the TTL of a value simply reissue the same `PUT` command that you used to set the value.
|
||||
|
||||
|
||||
|
38
Documentation/optimal-cluster-size.md
Normal file
38
Documentation/optimal-cluster-size.md
Normal file
@ -0,0 +1,38 @@
|
||||
# Optimal etcd Cluster Size
|
||||
|
||||
etcd's Raft consensus algorithm is most efficient in small clusters between 3 and 9 peers. For clusters larger than 9, etcd will select a subset of instances to participate in the algorithm in order to keep it efficient. The end of this document briefly explores how etcd works internally and why these choices have been made.
|
||||
|
||||
## Cluster Management
|
||||
|
||||
You can manage the active cluster size through the [cluster config API](https://github.com/coreos/etcd/blob/master/Documentation/api.md#cluster-config). `activeSize` represents the etcd peers allowed to actively participate in the consensus algorithm.
|
||||
|
||||
If the total number of etcd instances exceeds this number, additional peers are started as [standbys](https://github.com/coreos/etcd/blob/master/Documentation/design/standbys.md), which can be promoted to active participation if one of the existing active instances has failed or been removed.
|
||||
|
||||
## Internals of etcd
|
||||
|
||||
### Writing to etcd
|
||||
|
||||
Writes to an etcd peer are always redirected to the leader of the cluster and distributed to all of the peers immediately. A write is only considered successful when a majority of the peers acknowledge the write.
|
||||
|
||||
For example, in a cluster with 5 peers, a write operation is only as fast as the 3rd fastest machine. This is the main reason for keeping the number of active peers below 9. In practice, you only need to worry about write performance in high latency environments such as a cluster spanning multiple data centers.
|
||||
|
||||
### Leader Election
|
||||
|
||||
The leader election process is similar to writing a key — a majority of the active peers must acknowledge the new leader before cluster operations can continue. The longer each peer takes to elect a new leader means you have to wait longer before you can write to the cluster again. In low latency environments this process takes milliseconds.
|
||||
|
||||
### Odd Active Cluster Size
|
||||
|
||||
The other important cluster optimization is to always have an odd active cluster size (i.e. `activeSize`). Adding an odd node to the number of peers doesn't change the size of the majority and therefore doesn't increase the total latency of the majority as described above. But, you gain a higher tolerance for peer failure by adding the extra machine. You can see this in practice when comparing two even and odd sized clusters:
|
||||
|
||||
| Active Peers | Majority | Failure Tolerance |
|
||||
|--------------|------------|-------------------|
|
||||
| 1 peers | 1 peers | None |
|
||||
| 3 peers | 2 peers | 1 peer |
|
||||
| 4 peers | 3 peers | 2 peers |
|
||||
| 5 peers | 3 peers | **3 peers** |
|
||||
| 6 peers | 4 peers | 2 peers |
|
||||
| 7 peers | 4 peers | **3 peers** |
|
||||
| 8 peers | 5 peers | 3 peers |
|
||||
| 9 peers | 5 peers | **4 peers** |
|
||||
|
||||
As you can see, adding another peer to bring the number of active peers up to an odd size is always worth it. During a network partition, an odd number of active peers also guarantees that there will almost always be a majority of the cluster that can continue to operate and be the source of truth when the partition ends.
|
62
Documentation/platforms/freebsd.md
Normal file
62
Documentation/platforms/freebsd.md
Normal file
@ -0,0 +1,62 @@
|
||||
# FreeBSD
|
||||
|
||||
Starting with version 0.1.2 both etcd and etcdctl have been ported to FreeBSD and can
|
||||
be installed either via packages or ports system. Their versions have been recently
|
||||
updated to 0.2.0 so now you can enjoy using etcd and etcdctl on FreeBSD 10.0 (RC4 as
|
||||
of now) and 9.x where they have been tested. They might also work when installed from
|
||||
ports on earlier versions of FreeBSD, but your mileage may vary.
|
||||
|
||||
## Installation
|
||||
|
||||
### Using pkgng package system
|
||||
|
||||
1. If you do not have pkgng installed, install it with command `pkg` and answering 'Y'
|
||||
when asked
|
||||
|
||||
2. Update your repository data with `pkg update`
|
||||
|
||||
3. Install etcd with `pkg install coreosetcd coreosetcdctl`
|
||||
|
||||
4. Verify successful installation with `pkg info | grep etcd` and you should get:
|
||||
|
||||
```
|
||||
r@fbsd10:/ # pkg info | grep etcd
|
||||
coreosetcd0.2.0 Highlyavailable key value store and service discovery
|
||||
coreosetcdctl0.2.0 Simple commandline client for etcd
|
||||
r@fbsd10:/ #
|
||||
```
|
||||
|
||||
5. You’re ready to use etcd and etcdctl! For more information about using pkgng, please
|
||||
see: http://www.freebsd.org/doc/handbook/pkgngintro.html
|
||||
|
||||
### Using ports system
|
||||
|
||||
1. If you do not have ports installed, install with with `portsnap fetch extract` (it
|
||||
may take some time depending on your hardware and network connection)
|
||||
|
||||
2. Build etcd with `cd /usr/ports/devel/etcd && make install clean`, you
|
||||
will get an option to build and install documentation and etcdctl with it.
|
||||
|
||||
3. If you haven't installed it with etcdctl, and you would like to install it later, you can build it
|
||||
with `cd /usr/ports/devel/etcdctl && make install clean`
|
||||
|
||||
4. Verify successful installation with `pkg info | grep etcd` and you should get:
|
||||
|
||||
|
||||
```
|
||||
r@fbsd10:/ # pkg info | grep etcd
|
||||
coreosetcd0.2.0 Highlyavailable key value store and service discovery
|
||||
coreosetcdctl0.2.0 Simple commandline client for etcd
|
||||
r@fbsd10:/ #
|
||||
```
|
||||
|
||||
5. You’re ready to use etcd and etcdctl! For more information about using ports system,
|
||||
please see: https://www.freebsd.org/doc/handbook/portsusing.html
|
||||
|
||||
## Issues
|
||||
|
||||
If you find any issues with the build/install procedure or you've found a problem that
|
||||
you've verified is local to FreeBSD version only (for example, by not being able to
|
||||
reproduce it on any other platform, like OSX or Linux), please sent a
|
||||
problem report using this page for more
|
||||
information: http://www.freebsd.org/sendpr.html
|
7
Documentation/production-ready.md
Normal file
7
Documentation/production-ready.md
Normal file
@ -0,0 +1,7 @@
|
||||
ectd is being used successfully by many companies in production. It is,
|
||||
however, under active development and systems like etcd are difficult to get
|
||||
correct. If you are comfortable with bleeding-edge software please use etcd and
|
||||
provide us with the feedback and testing young software needs.
|
||||
|
||||
When the etcd team feels confident removing this warning we will release etcd
|
||||
1.0.
|
131
Documentation/security.md
Normal file
131
Documentation/security.md
Normal file
@ -0,0 +1,131 @@
|
||||
# Reading and Writing over HTTPS
|
||||
|
||||
## Transport Security with HTTPS
|
||||
|
||||
Etcd supports SSL/TLS and client cert authentication for clients to server, as well as server to server communication.
|
||||
|
||||
First, you need to have a CA cert `clientCA.crt` and signed key pair `client.crt`, `client.key`.
|
||||
This site has a good reference for how to generate self-signed key pairs:
|
||||
http://www.g-loaded.eu/2005/11/10/be-your-own-ca/
|
||||
Or you could use [etcd-ca](https://github.com/coreos/etcd-ca) to generate certs and keys.
|
||||
|
||||
For testing you can use the certificates in the `fixtures/ca` directory.
|
||||
|
||||
Let's configure etcd to use this keypair:
|
||||
|
||||
```sh
|
||||
./etcd -f -name machine0 -data-dir machine0 -cert-file=./fixtures/ca/server.crt -key-file=./fixtures/ca/server.key.insecure
|
||||
```
|
||||
|
||||
There are a few new options we're using:
|
||||
|
||||
* `-f` - forces a new machine configuration, even if an existing configuration is found. (WARNING: data loss!)
|
||||
* `-cert-file` and `-key-file` specify the location of the cert and key files to be used for for transport layer security between the client and server.
|
||||
|
||||
You can now test the configuration using HTTPS:
|
||||
|
||||
```sh
|
||||
curl --cacert ./fixtures/ca/server-chain.pem https://127.0.0.1:4001/v2/keys/foo -XPUT -d value=bar -v
|
||||
```
|
||||
|
||||
You should be able to see the handshake succeed.
|
||||
|
||||
**OSX 10.9+ Users**: curl 7.30.0 on OSX 10.9+ doesn't understand certificates passed in on the command line.
|
||||
Instead you must import the dummy ca.crt directly into the keychain or add the `-k` flag to curl to ignore errors.
|
||||
If you want to test without the `-k` flag run `open ./fixtures/ca/ca.crt` and follow the prompts.
|
||||
Please remove this certificate after you are done testing!
|
||||
If you know of a workaround let us know.
|
||||
|
||||
```
|
||||
...
|
||||
SSLv3, TLS handshake, Finished (20):
|
||||
...
|
||||
```
|
||||
|
||||
And also the response from the etcd server:
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "set",
|
||||
"key": "/foo",
|
||||
"modifiedIndex": 3,
|
||||
"value": "bar"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Authentication with HTTPS Client Certificates
|
||||
|
||||
We can also do authentication using CA certs.
|
||||
The clients will provide their cert to the server and the server will check whether the cert is signed by the CA and decide whether to serve the request.
|
||||
|
||||
```sh
|
||||
./etcd -f -name machine0 -data-dir machine0 -ca-file=./fixtures/ca/ca.crt -cert-file=./fixtures/ca/server.crt -key-file=./fixtures/ca/server.key.insecure
|
||||
```
|
||||
|
||||
```-ca-file``` is the path to the CA cert.
|
||||
|
||||
Try the same request to this server:
|
||||
|
||||
```sh
|
||||
curl --cacert ./fixtures/ca/server-chain.pem https://127.0.0.1:4001/v2/keys/foo -XPUT -d value=bar -v
|
||||
```
|
||||
|
||||
The request should be rejected by the server.
|
||||
|
||||
```
|
||||
...
|
||||
routines:SSL3_READ_BYTES:sslv3 alert bad certificate
|
||||
...
|
||||
```
|
||||
|
||||
We need to give the CA signed cert to the server.
|
||||
|
||||
```sh
|
||||
curl --key ./fixtures/ca/server2.key.insecure --cert ./fixtures/ca/server2.crt --cacert ./fixtures/ca/server-chain.pem -L https://127.0.0.1:4001/v2/keys/foo -XPUT -d value=bar -v
|
||||
```
|
||||
|
||||
You should able to see:
|
||||
|
||||
```
|
||||
...
|
||||
SSLv3, TLS handshake, CERT verify (15):
|
||||
...
|
||||
TLS handshake, Finished (20)
|
||||
```
|
||||
|
||||
And also the response from the server:
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "set",
|
||||
"node": {
|
||||
"createdIndex": 12,
|
||||
"key": "/foo",
|
||||
"modifiedIndex": 12,
|
||||
"value": "bar"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Why SSLv3 alert handshake failure when using SSL client auth?
|
||||
|
||||
The `crypto/tls` package of `golang` checks the key usage of the certificate public key before using it.
|
||||
To use the certificate public key to do client auth, we need to add `clientAuth` to `Extended Key Usage` when creating the certificate public key.
|
||||
|
||||
Here is how to do it:
|
||||
|
||||
Add the following section to your openssl.cnf:
|
||||
|
||||
```
|
||||
[ ssl_client ]
|
||||
...
|
||||
extendedKeyUsage = clientAuth
|
||||
...
|
||||
```
|
||||
|
||||
When creating the cert be sure to reference it in the `-extensions` flag:
|
||||
|
||||
```
|
||||
openssl ca -config openssl.cnf -policy policy_anything -extensions ssl_client -out certs/machine.crt -infiles machine.csr
|
||||
```
|
93
Documentation/tuning.md
Normal file
93
Documentation/tuning.md
Normal file
@ -0,0 +1,93 @@
|
||||
## Tuning
|
||||
|
||||
The default settings in etcd should work well for installations on a local network where the average network latency is low.
|
||||
However, when using etcd across multiple data centers or over networks with high latency you may need to tweak the heartbeat interval and election timeout settings.
|
||||
|
||||
### Time Parameters
|
||||
|
||||
The underlying distributed consensus protocol relies on two separate time parameters to ensure that nodes can handoff leadership if one stalls or goes offline.
|
||||
The first parameter is called the *Heartbeat Interval*.
|
||||
This is the frequency with which the leader will notify followers that it is still the leader.
|
||||
etcd batches commands together for higher throughput so this heartbeat interval is also a delay for how long it takes for commands to be committed.
|
||||
By default, etcd uses a `50ms` heartbeat interval.
|
||||
|
||||
The second parameter is the *Election Timeout*.
|
||||
This timeout is how long a follower node will go without hearing a heartbeat before attempting to become leader itself.
|
||||
By default, etcd uses a `200ms` election timeout.
|
||||
|
||||
Adjusting these values is a trade off.
|
||||
Lowering the heartbeat interval will cause individual commands to be committed faster but it will lower the overall throughput of etcd.
|
||||
If your etcd instances have low utilization then lowering the heartbeat interval can improve your command response time.
|
||||
|
||||
The election timeout should be set based on the heartbeat interval and your network ping time between nodes.
|
||||
Election timeouts should be at least 10 times your ping time so it can account for variance in your network.
|
||||
For example, if the ping time between your nodes is 10ms then you should have at least a 100ms election timeout.
|
||||
|
||||
You should also set your election timeout to at least 4 to 5 times your heartbeat interval to account for variance in leader replication.
|
||||
For a heartbeat interval of 50ms you should set your election timeout to at least 200ms - 250ms.
|
||||
|
||||
You can override the default values on the command line:
|
||||
|
||||
```sh
|
||||
# Command line arguments:
|
||||
$ etcd -peer-heartbeat-interval=100 -peer-election-timeout=500
|
||||
|
||||
# Environment variables:
|
||||
$ ETCD_PEER_HEARTBEAT_INTERVAL=100 ETCD_PEER_ELECTION_TIMEOUT=500 etcd
|
||||
```
|
||||
|
||||
Or you can set the values within the configuration file:
|
||||
|
||||
```toml
|
||||
[peer]
|
||||
heartbeat_interval = 100
|
||||
election_timeout = 100
|
||||
```
|
||||
|
||||
The values are specified in milliseconds.
|
||||
|
||||
|
||||
### Snapshots
|
||||
|
||||
etcd appends all key changes to a log file.
|
||||
This log grows forever and is a complete linear history of every change made to the keys.
|
||||
A complete history works well for lightly used clusters but clusters that are heavily used would carry around a large log.
|
||||
|
||||
To avoid having a huge log etcd makes periodic snapshots.
|
||||
These snapshots provide a way for etcd to compact the log by saving the current state of the system and removing old logs.
|
||||
|
||||
### Snapshot Tuning
|
||||
|
||||
Creating snapshots can be expensive so they're only created after a given number of changes to etcd.
|
||||
By default, snapshots will be made after every 10,000 changes.
|
||||
If etcd's memory usage and disk usage are too high, you can lower the snapshot threshold by setting the following on the command line:
|
||||
|
||||
```sh
|
||||
# Command line arguments:
|
||||
$ etcd -snapshot-count=5000
|
||||
|
||||
# Environment variables:
|
||||
$ ETCD_SNAPSHOT_COUNT=5000 etcd
|
||||
```
|
||||
|
||||
Or you can change the setting in the configuration file:
|
||||
|
||||
```toml
|
||||
snapshot_count = 5000
|
||||
```
|
||||
|
||||
You can also disable snapshotting by adding the following to your command line:
|
||||
|
||||
```sh
|
||||
# Command line arguments:
|
||||
$ etcd -snapshot false
|
||||
|
||||
# Environment variables:
|
||||
$ ETCD_SNAPSHOT=false etcd
|
||||
```
|
||||
|
||||
You can also disable snapshotting within the configuration file:
|
||||
|
||||
```toml
|
||||
snapshot = false
|
||||
```
|
17
Documentation/upgrade.md
Normal file
17
Documentation/upgrade.md
Normal file
@ -0,0 +1,17 @@
|
||||
# Upgrading an Existing Cluster
|
||||
|
||||
etcd clusters can be upgraded by doing a rolling upgrade or all at once. We make every effort to test this process, but please be sure to backup your data [by etcd-dump](https://github.com/AaronO/etcd-dump), or make a copy of data directory beforehand.
|
||||
|
||||
## Upgrade Process
|
||||
|
||||
- Stop the old etcd processes
|
||||
- Upgrade the etcd binary
|
||||
- Restart the etcd instance using the original --name, --address, --peer-address and --data-dir.
|
||||
|
||||
## Rolling Upgrade
|
||||
|
||||
During an upgrade, etcd clusters are designed to continue working in a mix of old and new versions. It's recommended to converge on the new version quickly. Using new API features before the entire cluster has been upgraded is only supported as a best effort. Each instance's version can be found with `curl http://127.0.0.1:4001/version`.
|
||||
|
||||
## All at Once
|
||||
|
||||
If downtime is not an issue, the easiest way to upgrade your cluster is to shutdown all of the etcd instances and restart them with the new binary. The current state of the cluster is saved to disk and will be loaded into the cluster when it restarts.
|
528
README.md
528
README.md
@ -1,501 +1,135 @@
|
||||
# etcd
|
||||
|
||||
[](https://travis-ci.org/coreos/etcd)
|
||||
README version 0.4.3
|
||||
|
||||
A highly-available key value store for shared configuration and service discovery. etcd is inspired by zookeeper and doozer, with a focus on:
|
||||
A highly-available key value store for shared configuration and service discovery.
|
||||
etcd is inspired by [Apache ZooKeeper][zookeeper] and [doozer][doozer], with a focus on being:
|
||||
|
||||
* Simple: curl'able user facing API (HTTP+JSON)
|
||||
* Secure: optional SSL client cert authentication
|
||||
* Fast: benchmarked 1000s of writes/s per instance
|
||||
* Reliable: Properly distributed using Raft
|
||||
* *Simple*: curl'able user facing API (HTTP+JSON)
|
||||
* *Secure*: optional SSL client cert authentication
|
||||
* *Fast*: benchmarked 1000s of writes/s per instance
|
||||
* *Reliable*: properly distributed using Raft
|
||||
|
||||
Etcd is written in Go and uses the [raft][raft] consensus algorithm to manage a highly-available replicated log.
|
||||
etcd is written in Go and uses the [Raft][raft] consensus algorithm to manage a highly-available replicated log.
|
||||
|
||||
See [etcdctl][etcdctl] for a simple command line client. Or feel free to just use curl, as in the examples below.
|
||||
See [etcdctl][etcdctl] for a simple command line client.
|
||||
Or feel free to just use curl, as in the examples below.
|
||||
|
||||
[raft]: https://github.com/coreos/go-raft
|
||||
[etcdctl]: http://coreos.com/docs/etcdctl/
|
||||
[zookeeper]: http://zookeeper.apache.org/
|
||||
[doozer]: https://github.com/ha/doozerd
|
||||
[raft]: http://raftconsensus.github.io/
|
||||
[etcdctl]: http://github.com/coreos/etcdctl/
|
||||
|
||||
If you're considering etcd for production use, please see: [production-ready.md](./Documentation/production-ready.md)
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Getting etcd
|
||||
|
||||
The latest release is available as a binary at [Github][github-release].
|
||||
The latest release and setup instructions are available at [GitHub][github-release].
|
||||
|
||||
[github-release]: https://github.com/coreos/etcd/releases/
|
||||
|
||||
|
||||
### Building
|
||||
|
||||
You can build etcd from source:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/coreos/etcd
|
||||
cd etcd
|
||||
./build
|
||||
```
|
||||
|
||||
This will generate a binary in the base directory called `./etcd`.
|
||||
This will generate a binary called `./bin/etcd`.
|
||||
|
||||
_NOTE_: you need go 1.1+. Please check your installation with
|
||||
_NOTE_: you need go 1.2+. Please check your installation with
|
||||
|
||||
```
|
||||
go version
|
||||
```
|
||||
|
||||
### Running a single node
|
||||
See the [development tools documentation][development-tools] for alternative build methods like using Vagrant.
|
||||
|
||||
These examples will use a single node cluster to show you the basics of the etcd REST API. Lets start etcd:
|
||||
[development-tools]: https://github.com/coreos/etcd/blob/master/Documentation/development-tools.md
|
||||
|
||||
### Running
|
||||
|
||||
First start a single-machine cluster of etcd:
|
||||
|
||||
```sh
|
||||
./etcd -d node0 -n node0
|
||||
./bin/etcd
|
||||
```
|
||||
|
||||
This will bring up an etcd node listening on port 4001 for client communication and on port 7001 for server-to-server communication.
|
||||
The `-d node0` argument tells etcd to write node configuration, logs and snapshots to the `./node0/` directory.
|
||||
The `-n node0` tells the rest of the cluster that this node is named node0.
|
||||
This will bring up etcd listening on port 4001 for client communication and on port 7001 for server-to-server communication.
|
||||
|
||||
## Usage
|
||||
|
||||
### Setting the value to a key
|
||||
|
||||
Let’s set the first key-value pair to the node. In this case the key is `/message` and the value is `Hello world`.
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v1/keys/message -d value="Hello world"
|
||||
```
|
||||
|
||||
```json
|
||||
{"action":"SET","key":"/message","value":"Hello world","newKey":true,"index":3}
|
||||
```
|
||||
|
||||
This response contains five fields. We will introduce three more fields as we try more commands.
|
||||
|
||||
1. The action of the request; we set the value via a POST request, thus the action is `SET`.
|
||||
|
||||
2. The key of the request; we set `/message` to `Hello world!`, so the key field is `/message`.
|
||||
Notice we use a file system like structure to represent the key-value pairs. So each key starts with `/`.
|
||||
|
||||
3. The current value of the key; we set the value to`Hello world`.
|
||||
|
||||
4. If we set a new key; `/message` did not exist before, so this is a new key.
|
||||
|
||||
5. Index is the unique internal log index of the set request. Requests that change the log index include `SET`, `DELETE` and `TESTANDSET`. The `GET`, `LIST` and `WATCH` commands do not change state in the store and so they do not change the index. You may notice that in this example the index is 3, although it is the first request you sent to the server. This is because there are internal commands that also change the state like adding and syncing servers.
|
||||
|
||||
### Get the value of a key
|
||||
|
||||
Get the value that we just set in `/message` by issuing a GET:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v1/keys/message
|
||||
```
|
||||
|
||||
```json
|
||||
{"action":"GET","key":"/message","value":"Hello world","index":3}
|
||||
```
|
||||
### Change the value of a key
|
||||
|
||||
Change the value of `/message` from `Hello world` to `Hello etcd` with another POST to the key:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v1/keys/message -d value="Hello etcd"
|
||||
```
|
||||
|
||||
```json
|
||||
{"action":"SET","key":"/message","prevValue":"Hello world","value":"Hello etcd","index":4}
|
||||
```
|
||||
|
||||
Notice that the `prevValue` is set to `Hello world`.
|
||||
|
||||
### Delete a key
|
||||
|
||||
Remove the `/message` key with a DELETE:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v1/keys/message -X DELETE
|
||||
```
|
||||
|
||||
```json
|
||||
{"action":"DELETE","key":"/message","prevValue":"Hello etcd","index":5}
|
||||
```
|
||||
|
||||
### Using key TTL
|
||||
|
||||
Keys in etcd can be set to expire after a specified number of seconds. That is done by setting a TTL (time to live) on the key when you POST:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v1/keys/foo -d value=bar -d ttl=5
|
||||
```
|
||||
|
||||
```json
|
||||
{"action":"SET","key":"/foo","value":"bar","newKey":true,"expiration":"2013-07-11T20:31:12.156146039-07:00","ttl":4,"index":6}
|
||||
```
|
||||
|
||||
Note the last two new fields in response:
|
||||
|
||||
1. The expiration is the time that this key will expire and be deleted.
|
||||
|
||||
2. The ttl is the time to live of the key.
|
||||
|
||||
Now you can try to get the key by sending:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v1/keys/foo
|
||||
```
|
||||
|
||||
If the TTL has expired, the key will be deleted, and you will be returned a 404.
|
||||
|
||||
```json
|
||||
{"errorCode":100,"message":"Key Not Found","cause":"/foo"}
|
||||
```
|
||||
|
||||
### Watching a prefix
|
||||
|
||||
We can watch a path prefix and get notifications if any key change under that prefix.
|
||||
|
||||
In one terminal, we send a watch request:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v1/watch/foo
|
||||
```
|
||||
|
||||
Now, we are watching at the path prefix `/foo` and wait for any changes under this path.
|
||||
|
||||
In another terminal, we set a key `/foo/foo` to `barbar` to see what will happen:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v1/keys/foo/foo -d value=barbar
|
||||
```
|
||||
|
||||
The first terminal should get the notification and return with the same response as the set request.
|
||||
|
||||
```json
|
||||
{"action":"SET","key":"/foo/foo","value":"barbar","newKey":true,"index":7}
|
||||
```
|
||||
|
||||
However, the watch command can do more than this. Using the the index we can watch for commands that has happened in the past. This is useful for ensuring you don't miss events between watch commands.
|
||||
|
||||
Let's try to watch for the set command of index 6 again:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v1/watch/foo -d index=7
|
||||
```
|
||||
|
||||
The watch command returns immediately with the same response as previous.
|
||||
|
||||
### Atomic Test and Set
|
||||
|
||||
Etcd can be used as a centralized coordination service in a cluster and `TestAndSet` is the most basic operation to build distributed lock service. This command will set the value only if the client provided `prevValue` is equal the current key value.
|
||||
|
||||
Here is a simple example. Let's create a key-value pair first: `testAndSet=one`.
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v1/keys/testAndSet -d value=one
|
||||
```
|
||||
|
||||
Let's try an invaild `TestAndSet` command.
|
||||
We can give another parameter prevValue to set command to make it a TestAndSet command.
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v1/keys/testAndSet -d prevValue=two -d value=three
|
||||
```
|
||||
|
||||
This will try to test if the previous of the key is two, it is change it to three.
|
||||
|
||||
```json
|
||||
{"errorCode":101,"message":"The given PrevValue is not equal to the value of the key","cause":"TestAndSet: one!=two"}
|
||||
```
|
||||
|
||||
which means `testAndSet` failed.
|
||||
|
||||
Let us try a vaild one.
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v1/keys/testAndSet -d prevValue=one -d value=two
|
||||
```
|
||||
|
||||
The response should be
|
||||
|
||||
```json
|
||||
{"action":"SET","key":"/testAndSet","prevValue":"one","value":"two","index":10}
|
||||
```
|
||||
|
||||
We successfully changed the value from “one” to “two”, since we give the correct previous value.
|
||||
|
||||
### Listing a directory
|
||||
|
||||
Last we provide a simple List command to list all the keys under a prefix path.
|
||||
|
||||
Let us create some keys first.
|
||||
|
||||
We already have `/foo/foo=barbar`
|
||||
|
||||
We create another one `/foo/foo_dir/foo=barbarbar`
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v1/keys/foo/foo_dir/bar -d value=barbarbar
|
||||
```
|
||||
|
||||
Now list the keys under `/foo`
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v1/keys/foo/
|
||||
```
|
||||
|
||||
We should see the response as an array of items
|
||||
|
||||
```json
|
||||
[{"action":"GET","key":"/foo/foo","value":"barbar","index":10},{"action":"GET","key":"/foo/foo_dir","dir":true,"index":10}]
|
||||
```
|
||||
|
||||
which meas `foo=barbar` is a key-value pair under `/foo` and `foo_dir` is a directory.
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Transport security with HTTPS
|
||||
|
||||
Etcd supports SSL/TLS and client cert authentication for clients to server, as well as server to server communication
|
||||
|
||||
First, you need to have a CA cert `clientCA.crt` and signed key pair `client.crt`, `client.key`. This site has a good reference for how to generate self-signed key pairs:
|
||||
http://www.g-loaded.eu/2005/11/10/be-your-own-ca/
|
||||
|
||||
For testing you can use the certificates in the `fixtures/ca` directory.
|
||||
|
||||
Next, lets configure etcd to use this keypair:
|
||||
|
||||
```sh
|
||||
./etcd -n node0 -d node0 -clientCert=./fixtures/ca/server.crt -clientKey=./fixtures/ca/server.key.insecure -f
|
||||
```
|
||||
|
||||
`-f` forces new node configuration if existing configuration is found (WARNING: data loss!)
|
||||
`-clientCert` and `-clientKey` are the key and cert for transport layer security between client and server
|
||||
|
||||
You can now test the configuration using https:
|
||||
|
||||
```sh
|
||||
curl --cacert fixtures/ca/ca.crt https://127.0.0.1:4001/v1/keys/foo -F value=bar
|
||||
```
|
||||
|
||||
You should be able to see the handshake succeed.
|
||||
Next, let's set a single key, and then retrieve it:
|
||||
|
||||
```
|
||||
...
|
||||
SSLv3, TLS handshake, Finished (20):
|
||||
...
|
||||
curl -L http://127.0.0.1:4001/v2/keys/mykey -XPUT -d value="this is awesome"
|
||||
curl -L http://127.0.0.1:4001/v2/keys/mykey
|
||||
```
|
||||
|
||||
And also the response from the etcd server.
|
||||
|
||||
```json
|
||||
{"action":"SET","key":"/foo","value":"bar","newKey":true,"index":3}
|
||||
```
|
||||
|
||||
### Authentication with HTTPS client certificates
|
||||
|
||||
We can also do authentication using CA certs. The clients will provide their cert to the server and the server will check whether the cert is signed by the CA and decide whether to serve the request.
|
||||
|
||||
```sh
|
||||
./etcd -n node0 -d node0 -clientCAFile=./fixtures/ca/ca.crt -clientCert=./fixtures/ca/server.crt -clientKey=./fixtures/ca/server.key.insecure -f
|
||||
```
|
||||
|
||||
```-clientCAFile``` is the path to the CA cert.
|
||||
|
||||
Try the same request to this server:
|
||||
|
||||
```sh
|
||||
curl --cacert fixtures/ca/ca.crt https://127.0.0.1:4001/v1/keys/foo -F value=bar
|
||||
```
|
||||
|
||||
The request should be rejected by the server.
|
||||
|
||||
```
|
||||
...
|
||||
routines:SSL3_READ_BYTES:sslv3 alert bad certificate
|
||||
...
|
||||
```
|
||||
|
||||
We need to give the CA signed cert to the server.
|
||||
|
||||
```sh
|
||||
curl -L https://127.0.0.1:4001/v1/keys/foo -d value=bar -v --key myclient.key --cert myclient.crt -cacert clientCA.crt
|
||||
```
|
||||
|
||||
You should able to see
|
||||
```
|
||||
...
|
||||
SSLv3, TLS handshake, CERT verify (15):
|
||||
...
|
||||
TLS handshake, Finished (20)
|
||||
```
|
||||
|
||||
And also the response from the server:
|
||||
|
||||
```json
|
||||
{"action":"SET","key":"/foo","value":"bar","newKey":true,"index":3}
|
||||
```
|
||||
|
||||
## Clustering
|
||||
|
||||
### Example cluster of three machines
|
||||
|
||||
Let's explore the use of etcd clustering. We use go-raft as the underlying distributed protocol which provides consistency and persistence of the data across all of the etcd instances.
|
||||
|
||||
Let start by creating 3 new etcd instances.
|
||||
|
||||
We use -s to specify server port and -c to specify client port and -d to specify the directory to store the log and info of the node in the cluster
|
||||
|
||||
```sh
|
||||
./etcd -s 127.0.0.1:7001 -c 127.0.0.1:4001 -d nodes/node1 -n node1
|
||||
```
|
||||
|
||||
Let the join two more nodes to this cluster using the -C argument:
|
||||
|
||||
```sh
|
||||
./etcd -c 127.0.0.1:4002 -s 127.0.0.1:7002 -C 127.0.0.1:7001 -d nodes/node2 -n node2
|
||||
./etcd -c 127.0.0.1:4003 -s 127.0.0.1:7003 -C 127.0.0.1:7001 -d nodes/node3 -n node3
|
||||
```
|
||||
|
||||
Get the machines in the cluster:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/machines
|
||||
```
|
||||
|
||||
We should see there are three nodes in the cluster
|
||||
|
||||
```
|
||||
0.0.0.0:4001,0.0.0.0:4002,0.0.0.0:4003
|
||||
```
|
||||
|
||||
The machine list is also available via this API:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v1/keys/_etcd/machines
|
||||
```
|
||||
|
||||
```json
|
||||
[{"action":"GET","key":"/machines/node1","value":"0.0.0.0,7001,4001","index":4},{"action":"GET","key":"/machines/node3","value":"0.0.0.0,7002,4002","index":4},{"action":"GET","key":"/machines/node4","value":"0.0.0.0,7003,4003","index":4}]
|
||||
```
|
||||
|
||||
The key of the machine is based on the ```commit index``` when it was added. The value of the machine is ```hostname```, ```raft port``` and ```client port```.
|
||||
|
||||
Also try to get the current leader in the cluster
|
||||
|
||||
```
|
||||
curl -L http://127.0.0.1:4001/leader
|
||||
```
|
||||
The first server we set up should be the leader, if it has not dead during these commands.
|
||||
|
||||
```
|
||||
0.0.0.0:7001
|
||||
```
|
||||
|
||||
Now we can do normal SET and GET operations on keys as we explored earlier.
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001/v1/keys/foo -d value=bar
|
||||
```
|
||||
|
||||
```json
|
||||
{"action":"SET","key":"/foo","value":"bar","newKey":true,"index":5}
|
||||
```
|
||||
|
||||
### Killing Nodes in the Cluster
|
||||
|
||||
Let's kill the leader of the cluster and get the value from the other machine:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4002/v1/keys/foo
|
||||
```
|
||||
|
||||
A new leader should have been elected.
|
||||
|
||||
```
|
||||
curl -L http://127.0.0.1:4001/leader
|
||||
```
|
||||
|
||||
```
|
||||
0.0.0.0:7002 or 0.0.0.0:7003
|
||||
```
|
||||
|
||||
You should be able to see this:
|
||||
|
||||
```json
|
||||
{"action":"GET","key":"/foo","value":"bar","index":5}
|
||||
```
|
||||
|
||||
It succeeded!
|
||||
|
||||
### Testing Persistence
|
||||
|
||||
OK. Next let us kill all the nodes to test persistence. And restart all the nodes use the same command as before.
|
||||
|
||||
Your request for the `foo` key will return the correct value:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4002/v1/keys/foo
|
||||
```
|
||||
|
||||
```json
|
||||
{"action":"GET","key":"/foo","value":"bar","index":5}
|
||||
```
|
||||
|
||||
### Using HTTPS between servers
|
||||
|
||||
In the previous example we showed how to use SSL client certs for client to server communication. Etcd can also do internal server to server communication using SSL client certs. To do this just change the ```-client*``` flags to ```-server*```.
|
||||
|
||||
If you are using SSL for server to server communication, you must use it on all instances of etcd.
|
||||
|
||||
## Libraries and Tools
|
||||
|
||||
**Tools**
|
||||
|
||||
- [etcdctl](https://github.com/coreos/etcdctl) - A command line client for etcd
|
||||
|
||||
**Go libraries**
|
||||
|
||||
- [go-etcd](https://github.com/coreos/go-etcd)
|
||||
|
||||
**Node libraries**
|
||||
|
||||
- [stianeikeland/node-etcd](https://github.com/stianeikeland/node-etcd)
|
||||
|
||||
**Ruby libraries**
|
||||
|
||||
- [iconara/etcd-rb](https://github.com/iconara/etcd-rb)
|
||||
- [jpfuentes2/etcd-ruby](https://github.com/jpfuentes2/etcd-ruby)
|
||||
- [ranjib/etcd-ruby](https://github.com/ranjib/etcd-ruby)
|
||||
|
||||
**Chef Cookbook**
|
||||
|
||||
- [spheromak/etcd-cookbook](https://github.com/spheromak/etcd-cookbook)
|
||||
|
||||
**Projects using etcd**
|
||||
|
||||
- [calavera/active-proxy](https://github.com/calavera/active-proxy) - HTTP Proxy configured with etcd
|
||||
- [gleicon/goreman](https://github.com/gleicon/goreman/tree/etcd) - Branch of the Go Foreman clone with etcd support
|
||||
- [garethr/hiera-etcd](https://github.com/garethr/hiera-etcd) - Puppet hiera backend using etcd
|
||||
- [mattn/etcd-vim](https://github.com/mattn/etcd-vim) - SET and GET keys from inside vim
|
||||
- [mattn/etcdenv](https://github.com/mattn/etcdenv) - "env" shebang with etcd integration
|
||||
You have successfully started an etcd on a single machine and written a key to the store. Now it's time to dig into the full etcd API and other guides.
|
||||
|
||||
### Next Steps
|
||||
|
||||
- Explore the full [API][api].
|
||||
- Set up a [multi-machine cluster][clustering].
|
||||
- Learn the [config format, env variables and flags][configuration].
|
||||
- Find [language bindings and tools][libraries-and-tools].
|
||||
- Learn about the dashboard, lock and leader election [modules][modules].
|
||||
- Use TLS to [secure an etcd cluster][security].
|
||||
- [Tune etcd][tuning].
|
||||
- [Upgrade from old version][upgrade].
|
||||
|
||||
[api]: https://github.com/coreos/etcd/blob/master/Documentation/api.md
|
||||
[clustering]: https://github.com/coreos/etcd/blob/master/Documentation/clustering.md
|
||||
[configuration]: https://github.com/coreos/etcd/blob/master/Documentation/configuration.md
|
||||
[libraries-and-tools]: https://github.com/coreos/etcd/blob/master/Documentation/libraries-and-tools.md
|
||||
[modules]: https://github.com/coreos/etcd/blob/master/Documentation/modules.md
|
||||
[security]: https://github.com/coreos/etcd/blob/master/Documentation/security.md
|
||||
[tuning]: https://github.com/coreos/etcd/blob/master/Documentation/tuning.md
|
||||
[upgrade]: https://github.com/coreos/etcd/blob/master/Documentation/upgrade.md
|
||||
|
||||
## Contact
|
||||
|
||||
- Mailing list: [etcd-dev](https://groups.google.com/forum/?hl=en#!forum/etcd-dev)
|
||||
- IRC: #[coreos](irc://irc.freenode.org:6667/#coreos) oon freenode.org
|
||||
- Planning/Roadmap: [milestones](https://github.com/coreos/etcd/issues/milestones)
|
||||
- Bugs: [issues](https://github.com/coreos/etcd/issues)
|
||||
|
||||
## Contributing
|
||||
|
||||
See [CONTRIBUTING](CONTRIBUTING.md) for details on submitting patches and the contribution workflow.
|
||||
|
||||
## Project Details
|
||||
|
||||
### Versioning
|
||||
|
||||
etcd uses [semantic versioning][semver].
|
||||
When we release v1.0.0 of etcd we will promise not to break the "v1" REST API.
|
||||
New minor versions may add additional features to the API however.
|
||||
#### Service Versioning
|
||||
|
||||
You can get the version of etcd by requesting the root path of etcd:
|
||||
etcd uses [semantic versioning](http://semver.org)
|
||||
New minor versions may add additional features to the API.
|
||||
|
||||
You can get the version of etcd by issuing a request to /version:
|
||||
|
||||
```sh
|
||||
curl -L http://127.0.0.1:4001
|
||||
curl -L http://127.0.0.1:4001/version
|
||||
```
|
||||
|
||||
During the v0 series of releases we may break the API as we fix bugs and get feedback.
|
||||
#### API Versioning
|
||||
|
||||
[semver]: http://semver.org/
|
||||
Clients are encouraged to use the `v2` API. The `v1` API will not change.
|
||||
|
||||
The `v2` API responses should not change after the 0.2.0 release but new features will be added over time.
|
||||
|
||||
During the pre-v1.0.0 series of releases we may break the API as we fix bugs and get feedback.
|
||||
|
||||
#### 32bit systems
|
||||
|
||||
etcd has known issues on 32bit systems. We plan to address these issues after the 0.4 release.
|
||||
|
||||
### License
|
||||
|
||||
etcd is under the Apache 2.0 license. See the [LICENSE][license] file for details.
|
||||
|
||||
[license]: https://github.com/coreos/etcd/blob/master/LICENSE
|
||||
etcd is under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.
|
||||
|
27
Vagrantfile
vendored
Normal file
27
Vagrantfile
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
#
|
||||
Vagrant.require_version '>= 1.5.0'
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = "precise64"
|
||||
config.vm.box_url = "http://files.vagrantup.com/precise64.box"
|
||||
|
||||
config.vm.network :forwarded_port, host: 4001, guest: 4001
|
||||
config.vm.network :forwarded_port, host: 7001, guest: 7001
|
||||
|
||||
# Fix docker not being able to resolve private registry in VirtualBox
|
||||
config.vm.provider :virtualbox do |vb, override|
|
||||
vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
|
||||
vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
|
||||
end
|
||||
|
||||
config.vm.provision "docker" do |d|
|
||||
d.build_image "/vagrant", args: '-t etcd'
|
||||
d.run "etcd", args: "-p 4001:4001 -p 7001:7001", demonize: true
|
||||
end
|
||||
|
||||
# plugin conflict
|
||||
if Vagrant.has_plugin?("vagrant-vbguest")
|
||||
config.vbguest.auto_update = false
|
||||
end
|
||||
end
|
79
bench/bench.go
Normal file
79
bench/bench.go
Normal file
@ -0,0 +1,79 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd"
|
||||
)
|
||||
|
||||
var (
|
||||
// output debug to log
|
||||
verbose *bool
|
||||
)
|
||||
|
||||
func write(endpoint string, requests int, end chan int) {
|
||||
client := etcd.NewClient([]string{endpoint})
|
||||
|
||||
for i := 0; i < requests; i++ {
|
||||
key := strconv.Itoa(i)
|
||||
_, err := client.Set(key, key, 0)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
}
|
||||
}
|
||||
end <- 1
|
||||
}
|
||||
|
||||
func watch(endpoint string, key string) {
|
||||
client := etcd.NewClient([]string{endpoint})
|
||||
|
||||
receiver := make(chan *etcd.Response)
|
||||
go client.Watch(key, 0, true, receiver, nil)
|
||||
|
||||
if *verbose {
|
||||
log.Printf("watching: %s", key)
|
||||
}
|
||||
|
||||
received := 0
|
||||
for {
|
||||
<-receiver
|
||||
received++
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
endpoint := flag.String("endpoint", "http://127.0.0.1:4001", "etcd HTTP endpoint")
|
||||
|
||||
rWrites := flag.Int("write-requests", 50000, "number of writes")
|
||||
cWrites := flag.Int("concurrent-writes", 500, "number of concurrent writes")
|
||||
watches := flag.Int("watches", 500, "number of concurrent watches")
|
||||
verbose = flag.Bool("verbose", false, "output debug info")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
log.Printf("Benchmarking %v", *endpoint)
|
||||
log.Printf("%v writes with %v concurrent writers and %v watches", *rWrites, *cWrites, *watches)
|
||||
|
||||
t := time.Now()
|
||||
for i := 0; i < *watches; i++ {
|
||||
key := strconv.Itoa(i)
|
||||
go watch(*endpoint, key)
|
||||
}
|
||||
|
||||
wChan := make(chan int, *cWrites)
|
||||
for i := 0; i < *cWrites; i++ {
|
||||
go write(*endpoint, (*rWrites / *cWrites), wChan)
|
||||
}
|
||||
|
||||
for i := 0; i < *cWrites; i++ {
|
||||
<-wChan
|
||||
if *verbose {
|
||||
log.Printf("Completed %d writes", (*rWrites / *cWrites))
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("Took %v", time.Now().Sub(t))
|
||||
}
|
33
build
33
build
@ -1,25 +1,18 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh -e
|
||||
|
||||
ETCD_PACKAGE=github.com/coreos/etcd
|
||||
export GOPATH=${PWD}
|
||||
SRC_DIR=$GOPATH/src
|
||||
ETCD_DIR=$SRC_DIR/$ETCD_PACKAGE
|
||||
|
||||
ETCD_BASE=$(dirname ${ETCD_DIR})
|
||||
if [ ! -d ${ETCD_BASE} ]; then
|
||||
mkdir -p ${ETCD_BASE}
|
||||
if [ ! -h gopath/src/github.com/coreos/etcd ]; then
|
||||
mkdir -p gopath/src/github.com/coreos/
|
||||
ln -s ../../../.. gopath/src/github.com/coreos/etcd
|
||||
fi
|
||||
|
||||
if [ ! -h ${ETCD_DIR} ]; then
|
||||
ln -s ../../../ ${ETCD_DIR}
|
||||
export GOBIN=${PWD}/bin
|
||||
export GOPATH=${PWD}/gopath
|
||||
export GOFMTPATH="./bench ./config ./discovery ./etcd ./error ./http ./log main.go ./metrics ./mod ./server ./store ./tests"
|
||||
|
||||
# Don't surprise user by formatting their codes by stealth
|
||||
if [ "--fmt" = "$1" ]; then
|
||||
gofmt -s -w -l $GOFMTPATH
|
||||
fi
|
||||
|
||||
for i in third_party/*; do
|
||||
if [ $i = "third_party/src" ]; then
|
||||
continue
|
||||
fi
|
||||
cp -R $i src/
|
||||
done
|
||||
|
||||
./scripts/release-version > release_version.go
|
||||
go build ${ETCD_PACKAGE}
|
||||
go install github.com/coreos/etcd
|
||||
go install github.com/coreos/etcd/bench
|
||||
|
172
command.go
172
command.go
@ -1,172 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
etcdErr "github.com/coreos/etcd/error"
|
||||
"github.com/coreos/etcd/store"
|
||||
"github.com/coreos/go-raft"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
|
||||
const commandPrefix = "etcd:"
|
||||
|
||||
func commandName(name string) string {
|
||||
return commandPrefix + name
|
||||
}
|
||||
|
||||
// A command represents an action to be taken on the replicated state machine.
|
||||
type Command interface {
|
||||
CommandName() string
|
||||
Apply(server *raft.Server) (interface{}, error)
|
||||
}
|
||||
|
||||
// Set command
|
||||
type SetCommand struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
ExpireTime time.Time `json:"expireTime"`
|
||||
}
|
||||
|
||||
// The name of the set command in the log
|
||||
func (c *SetCommand) CommandName() string {
|
||||
return commandName("set")
|
||||
}
|
||||
|
||||
// Set the key-value pair
|
||||
func (c *SetCommand) Apply(server *raft.Server) (interface{}, error) {
|
||||
return etcdStore.Set(c.Key, c.Value, c.ExpireTime, server.CommitIndex())
|
||||
}
|
||||
|
||||
// TestAndSet command
|
||||
type TestAndSetCommand struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
PrevValue string `json: prevValue`
|
||||
ExpireTime time.Time `json:"expireTime"`
|
||||
}
|
||||
|
||||
// The name of the testAndSet command in the log
|
||||
func (c *TestAndSetCommand) CommandName() string {
|
||||
return commandName("testAndSet")
|
||||
}
|
||||
|
||||
// Set the key-value pair if the current value of the key equals to the given prevValue
|
||||
func (c *TestAndSetCommand) Apply(server *raft.Server) (interface{}, error) {
|
||||
return etcdStore.TestAndSet(c.Key, c.PrevValue, c.Value, c.ExpireTime, server.CommitIndex())
|
||||
}
|
||||
|
||||
// Get command
|
||||
type GetCommand struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// The name of the get command in the log
|
||||
func (c *GetCommand) CommandName() string {
|
||||
return commandName("get")
|
||||
}
|
||||
|
||||
// Get the value of key
|
||||
func (c *GetCommand) Apply(server *raft.Server) (interface{}, error) {
|
||||
return etcdStore.Get(c.Key)
|
||||
}
|
||||
|
||||
// Delete command
|
||||
type DeleteCommand struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// The name of the delete command in the log
|
||||
func (c *DeleteCommand) CommandName() string {
|
||||
return commandName("delete")
|
||||
}
|
||||
|
||||
// Delete the key
|
||||
func (c *DeleteCommand) Apply(server *raft.Server) (interface{}, error) {
|
||||
return etcdStore.Delete(c.Key, server.CommitIndex())
|
||||
}
|
||||
|
||||
// Watch command
|
||||
type WatchCommand struct {
|
||||
Key string `json:"key"`
|
||||
SinceIndex uint64 `json:"sinceIndex"`
|
||||
}
|
||||
|
||||
// The name of the watch command in the log
|
||||
func (c *WatchCommand) CommandName() string {
|
||||
return commandName("watch")
|
||||
}
|
||||
|
||||
func (c *WatchCommand) Apply(server *raft.Server) (interface{}, error) {
|
||||
// create a new watcher
|
||||
watcher := store.NewWatcher()
|
||||
|
||||
// add to the watchers list
|
||||
etcdStore.AddWatcher(c.Key, watcher, c.SinceIndex)
|
||||
|
||||
// wait for the notification for any changing
|
||||
res := <-watcher.C
|
||||
|
||||
if res == nil {
|
||||
return nil, fmt.Errorf("Clearing watch")
|
||||
}
|
||||
|
||||
return json.Marshal(res)
|
||||
}
|
||||
|
||||
// JoinCommand
|
||||
type JoinCommand struct {
|
||||
RaftVersion string `json:"raftVersion"`
|
||||
Name string `json:"name"`
|
||||
RaftURL string `json:"raftURL"`
|
||||
EtcdURL string `json:"etcdURL"`
|
||||
}
|
||||
|
||||
func newJoinCommand() *JoinCommand {
|
||||
return &JoinCommand{
|
||||
RaftVersion: r.version,
|
||||
Name: r.name,
|
||||
RaftURL: r.url,
|
||||
EtcdURL: e.url,
|
||||
}
|
||||
}
|
||||
|
||||
// The name of the join command in the log
|
||||
func (c *JoinCommand) CommandName() string {
|
||||
return commandName("join")
|
||||
}
|
||||
|
||||
// Join a server to the cluster
|
||||
func (c *JoinCommand) Apply(raftServer *raft.Server) (interface{}, error) {
|
||||
|
||||
// check if the join command is from a previous machine, who lost all its previous log.
|
||||
response, _ := etcdStore.RawGet(path.Join("_etcd/machines", c.Name))
|
||||
|
||||
if response != nil {
|
||||
return []byte("join success"), nil
|
||||
}
|
||||
|
||||
// check machine number in the cluster
|
||||
num := machineNum()
|
||||
if num == maxClusterSize {
|
||||
debug("Reject join request from ", c.Name)
|
||||
return []byte("join fail"), etcdErr.NewError(103, "")
|
||||
}
|
||||
|
||||
addNameToURL(c.Name, c.RaftVersion, c.RaftURL, c.EtcdURL)
|
||||
|
||||
// add peer in raft
|
||||
err := raftServer.AddPeer(c.Name, "")
|
||||
|
||||
// add machine in etcd storage
|
||||
key := path.Join("_etcd/machines", c.Name)
|
||||
value := fmt.Sprintf("raft=%s&etcd=%s&raftVersion=%s", c.RaftURL, c.EtcdURL, c.RaftVersion)
|
||||
etcdStore.Set(key, value, time.Unix(0, 0), raftServer.CommitIndex())
|
||||
|
||||
return []byte("join success"), err
|
||||
}
|
||||
|
||||
func (c *JoinCommand) NodeName() string {
|
||||
return c.Name
|
||||
}
|
140
config.go
140
config.go
@ -1,140 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
//--------------------------------------
|
||||
// Config
|
||||
//--------------------------------------
|
||||
|
||||
// Get the server info from previous conf file
|
||||
// or from the user
|
||||
func getInfo(path string) *Info {
|
||||
|
||||
infoPath := filepath.Join(path, "info")
|
||||
|
||||
if force {
|
||||
// Delete the old configuration if exist
|
||||
logPath := filepath.Join(path, "log")
|
||||
confPath := filepath.Join(path, "conf")
|
||||
snapshotPath := filepath.Join(path, "snapshot")
|
||||
os.Remove(infoPath)
|
||||
os.Remove(logPath)
|
||||
os.Remove(confPath)
|
||||
os.RemoveAll(snapshotPath)
|
||||
} else if info := readInfo(infoPath); info != nil {
|
||||
infof("Found node configuration in '%s'. Ignoring flags", infoPath)
|
||||
return info
|
||||
}
|
||||
|
||||
// Read info from command line
|
||||
info := &argInfo
|
||||
|
||||
// Write to file.
|
||||
content, _ := json.MarshalIndent(info, "", " ")
|
||||
content = []byte(string(content) + "\n")
|
||||
if err := ioutil.WriteFile(infoPath, content, 0644); err != nil {
|
||||
fatalf("Unable to write info to file: %v", err)
|
||||
}
|
||||
|
||||
infof("Wrote node configuration to '%s'", infoPath)
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
// readInfo reads from info file and decode to Info struct
|
||||
func readInfo(path string) *Info {
|
||||
file, err := os.Open(path)
|
||||
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
fatal(err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
info := &Info{}
|
||||
|
||||
content, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
fatalf("Unable to read info: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(content, &info); err != nil {
|
||||
fatalf("Unable to parse info: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
func tlsConfigFromInfo(info TLSInfo) (t TLSConfig, ok bool) {
|
||||
var keyFile, certFile, CAFile string
|
||||
var tlsCert tls.Certificate
|
||||
var err error
|
||||
|
||||
t.Scheme = "http"
|
||||
|
||||
keyFile = info.KeyFile
|
||||
certFile = info.CertFile
|
||||
CAFile = info.CAFile
|
||||
|
||||
// If the user do not specify key file, cert file and
|
||||
// CA file, the type will be HTTP
|
||||
if keyFile == "" && certFile == "" && CAFile == "" {
|
||||
return t, true
|
||||
}
|
||||
|
||||
// both the key and cert must be present
|
||||
if keyFile == "" || certFile == "" {
|
||||
return t, false
|
||||
}
|
||||
|
||||
tlsCert, err = tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
|
||||
t.Scheme = "https"
|
||||
t.Server.ClientAuth, t.Server.ClientCAs = newCertPool(CAFile)
|
||||
|
||||
// The client should trust the RootCA that the Server uses since
|
||||
// everyone is a peer in the network.
|
||||
t.Client.Certificates = []tls.Certificate{tlsCert}
|
||||
t.Client.RootCAs = t.Server.ClientCAs
|
||||
|
||||
return t, true
|
||||
}
|
||||
|
||||
// newCertPool creates x509 certPool and corresponding Auth Type.
|
||||
// If the given CAfile is valid, add the cert into the pool and verify the clients'
|
||||
// certs against the cert in the pool.
|
||||
// If the given CAfile is empty, do not verify the clients' cert.
|
||||
// If the given CAfile is not valid, fatal.
|
||||
func newCertPool(CAFile string) (tls.ClientAuthType, *x509.CertPool) {
|
||||
if CAFile == "" {
|
||||
return tls.NoClientCert, nil
|
||||
}
|
||||
pemByte, err := ioutil.ReadFile(CAFile)
|
||||
check(err)
|
||||
|
||||
block, pemByte := pem.Decode(pemByte)
|
||||
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
check(err)
|
||||
|
||||
certPool := x509.NewCertPool()
|
||||
|
||||
certPool.AddCert(cert)
|
||||
|
||||
return tls.RequireAndVerifyClientCert, certPool
|
||||
}
|
490
config/config.go
Normal file
490
config/config.go
Normal file
@ -0,0 +1,490 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/third_party/github.com/BurntSushi/toml"
|
||||
|
||||
"github.com/coreos/etcd/log"
|
||||
ustrings "github.com/coreos/etcd/pkg/strings"
|
||||
"github.com/coreos/etcd/server"
|
||||
)
|
||||
|
||||
// The default location for the etcd configuration file.
|
||||
const DefaultSystemConfigPath = "/etc/etcd/etcd.conf"
|
||||
|
||||
// A lookup of deprecated flags to their new flag name.
|
||||
var newFlagNameLookup = map[string]string{
|
||||
"C": "peers",
|
||||
"CF": "peers-file",
|
||||
"n": "name",
|
||||
"c": "addr",
|
||||
"cl": "bind-addr",
|
||||
"s": "peer-addr",
|
||||
"sl": "peer-bind-addr",
|
||||
"d": "data-dir",
|
||||
"m": "max-result-buffer",
|
||||
"r": "max-retry-attempts",
|
||||
"maxsize": "max-cluster-size",
|
||||
"clientCAFile": "ca-file",
|
||||
"clientCert": "cert-file",
|
||||
"clientKey": "key-file",
|
||||
"serverCAFile": "peer-ca-file",
|
||||
"serverCert": "peer-cert-file",
|
||||
"serverKey": "peer-key-file",
|
||||
"snapshotCount": "snapshot-count",
|
||||
"peer-heartbeat-timeout": "peer-heartbeat-interval",
|
||||
}
|
||||
|
||||
// Config represents the server configuration.
|
||||
type Config struct {
|
||||
SystemPath string
|
||||
|
||||
Addr string `toml:"addr" env:"ETCD_ADDR"`
|
||||
BindAddr string `toml:"bind_addr" env:"ETCD_BIND_ADDR"`
|
||||
CAFile string `toml:"ca_file" env:"ETCD_CA_FILE"`
|
||||
CertFile string `toml:"cert_file" env:"ETCD_CERT_FILE"`
|
||||
CPUProfileFile string
|
||||
CorsOrigins []string `toml:"cors" env:"ETCD_CORS"`
|
||||
DataDir string `toml:"data_dir" env:"ETCD_DATA_DIR"`
|
||||
Discovery string `toml:"discovery" env:"ETCD_DISCOVERY"`
|
||||
Force bool
|
||||
KeyFile string `toml:"key_file" env:"ETCD_KEY_FILE"`
|
||||
Peers []string `toml:"peers" env:"ETCD_PEERS"`
|
||||
PeersFile string `toml:"peers_file" env:"ETCD_PEERS_FILE"`
|
||||
MaxResultBuffer int `toml:"max_result_buffer" env:"ETCD_MAX_RESULT_BUFFER"`
|
||||
MaxRetryAttempts int `toml:"max_retry_attempts" env:"ETCD_MAX_RETRY_ATTEMPTS"`
|
||||
RetryInterval float64 `toml:"retry_interval" env:"ETCD_RETRY_INTERVAL"`
|
||||
Name string `toml:"name" env:"ETCD_NAME"`
|
||||
Snapshot bool `toml:"snapshot" env:"ETCD_SNAPSHOT"`
|
||||
SnapshotCount int `toml:"snapshot_count" env:"ETCD_SNAPSHOTCOUNT"`
|
||||
ShowHelp bool
|
||||
ShowVersion bool
|
||||
Verbose bool `toml:"verbose" env:"ETCD_VERBOSE"`
|
||||
VeryVerbose bool `toml:"very_verbose" env:"ETCD_VERY_VERBOSE"`
|
||||
VeryVeryVerbose bool `toml:"very_very_verbose" env:"ETCD_VERY_VERY_VERBOSE"`
|
||||
Peer struct {
|
||||
Addr string `toml:"addr" env:"ETCD_PEER_ADDR"`
|
||||
BindAddr string `toml:"bind_addr" env:"ETCD_PEER_BIND_ADDR"`
|
||||
CAFile string `toml:"ca_file" env:"ETCD_PEER_CA_FILE"`
|
||||
CertFile string `toml:"cert_file" env:"ETCD_PEER_CERT_FILE"`
|
||||
KeyFile string `toml:"key_file" env:"ETCD_PEER_KEY_FILE"`
|
||||
HeartbeatInterval int `toml:"heartbeat_interval" env:"ETCD_PEER_HEARTBEAT_INTERVAL"`
|
||||
ElectionTimeout int `toml:"election_timeout" env:"ETCD_PEER_ELECTION_TIMEOUT"`
|
||||
}
|
||||
strTrace string `toml:"trace" env:"ETCD_TRACE"`
|
||||
GraphiteHost string `toml:"graphite_host" env:"ETCD_GRAPHITE_HOST"`
|
||||
Cluster struct {
|
||||
ActiveSize int `toml:"active_size" env:"ETCD_CLUSTER_ACTIVE_SIZE"`
|
||||
RemoveDelay float64 `toml:"remove_delay" env:"ETCD_CLUSTER_REMOVE_DELAY"`
|
||||
SyncInterval float64 `toml:"sync_interval" env:"ETCD_CLUSTER_SYNC_INTERVAL"`
|
||||
}
|
||||
}
|
||||
|
||||
// New returns a Config initialized with default values.
|
||||
func New() *Config {
|
||||
c := new(Config)
|
||||
c.SystemPath = DefaultSystemConfigPath
|
||||
c.Addr = "127.0.0.1:4001"
|
||||
c.MaxResultBuffer = 1024
|
||||
c.MaxRetryAttempts = 3
|
||||
c.RetryInterval = 10.0
|
||||
c.Snapshot = true
|
||||
c.SnapshotCount = 10000
|
||||
c.Peer.Addr = "127.0.0.1:7001"
|
||||
c.Peer.HeartbeatInterval = defaultHeartbeatInterval
|
||||
c.Peer.ElectionTimeout = defaultElectionTimeout
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
// Make maximum twice as minimum.
|
||||
c.RetryInterval = float64(50+rand.Int()%50) * defaultHeartbeatInterval / 1000
|
||||
c.Cluster.ActiveSize = server.DefaultActiveSize
|
||||
c.Cluster.RemoveDelay = server.DefaultRemoveDelay
|
||||
c.Cluster.SyncInterval = server.DefaultSyncInterval
|
||||
return c
|
||||
}
|
||||
|
||||
// Loads the configuration from the system config, command line config,
|
||||
// environment variables, and finally command line arguments.
|
||||
func (c *Config) Load(arguments []string) error {
|
||||
var path string
|
||||
f := flag.NewFlagSet("etcd", -1)
|
||||
f.SetOutput(ioutil.Discard)
|
||||
f.StringVar(&path, "config", "", "path to config file")
|
||||
f.Parse(arguments)
|
||||
|
||||
// Load from system file.
|
||||
if err := c.LoadSystemFile(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Load from config file specified in arguments.
|
||||
if path != "" {
|
||||
if err := c.LoadFile(path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Load from the environment variables next.
|
||||
if err := c.LoadEnv(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Load from command line flags.
|
||||
if err := c.LoadFlags(arguments); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Loads peers if a peer file was specified.
|
||||
if err := c.LoadPeersFile(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Loads from the system etcd configuration file if it exists.
|
||||
func (c *Config) LoadSystemFile() error {
|
||||
if _, err := os.Stat(c.SystemPath); os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return c.LoadFile(c.SystemPath)
|
||||
}
|
||||
|
||||
// Loads configuration from a file.
|
||||
func (c *Config) LoadFile(path string) error {
|
||||
_, err := toml.DecodeFile(path, &c)
|
||||
return err
|
||||
}
|
||||
|
||||
// LoadEnv loads the configuration via environment variables.
|
||||
func (c *Config) LoadEnv() error {
|
||||
if err := c.loadEnv(c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.loadEnv(&c.Peer); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.loadEnv(&c.Cluster); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) loadEnv(target interface{}) error {
|
||||
value := reflect.Indirect(reflect.ValueOf(target))
|
||||
typ := value.Type()
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
field := typ.Field(i)
|
||||
|
||||
// Retrieve environment variable.
|
||||
v := strings.TrimSpace(os.Getenv(field.Tag.Get("env")))
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Set the appropriate type.
|
||||
switch field.Type.Kind() {
|
||||
case reflect.Bool:
|
||||
value.Field(i).SetBool(v != "0" && v != "false")
|
||||
case reflect.Int:
|
||||
newValue, err := strconv.ParseInt(v, 10, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Parse error: %s: %s", field.Tag.Get("env"), err)
|
||||
}
|
||||
value.Field(i).SetInt(newValue)
|
||||
case reflect.String:
|
||||
value.Field(i).SetString(v)
|
||||
case reflect.Slice:
|
||||
value.Field(i).Set(reflect.ValueOf(ustrings.TrimSplit(v, ",")))
|
||||
case reflect.Float64:
|
||||
newValue, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Parse error: %s: %s", field.Tag.Get("env"), err)
|
||||
}
|
||||
value.Field(i).SetFloat(newValue)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Loads configuration from command line flags.
|
||||
func (c *Config) LoadFlags(arguments []string) error {
|
||||
var peers, cors, path string
|
||||
|
||||
f := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
|
||||
f.SetOutput(ioutil.Discard)
|
||||
|
||||
f.BoolVar(&c.ShowHelp, "h", false, "")
|
||||
f.BoolVar(&c.ShowHelp, "help", false, "")
|
||||
f.BoolVar(&c.ShowVersion, "version", false, "")
|
||||
|
||||
f.BoolVar(&c.Force, "f", false, "")
|
||||
f.BoolVar(&c.Force, "force", false, "")
|
||||
|
||||
f.BoolVar(&c.Verbose, "v", c.Verbose, "")
|
||||
f.BoolVar(&c.VeryVerbose, "vv", c.VeryVerbose, "")
|
||||
f.BoolVar(&c.VeryVeryVerbose, "vvv", c.VeryVeryVerbose, "")
|
||||
|
||||
f.StringVar(&peers, "peers", "", "")
|
||||
f.StringVar(&c.PeersFile, "peers-file", c.PeersFile, "")
|
||||
|
||||
f.StringVar(&c.Name, "name", c.Name, "")
|
||||
f.StringVar(&c.Addr, "addr", c.Addr, "")
|
||||
f.StringVar(&c.Discovery, "discovery", c.Discovery, "")
|
||||
f.StringVar(&c.BindAddr, "bind-addr", c.BindAddr, "")
|
||||
f.StringVar(&c.Peer.Addr, "peer-addr", c.Peer.Addr, "")
|
||||
f.StringVar(&c.Peer.BindAddr, "peer-bind-addr", c.Peer.BindAddr, "")
|
||||
|
||||
f.StringVar(&c.CAFile, "ca-file", c.CAFile, "")
|
||||
f.StringVar(&c.CertFile, "cert-file", c.CertFile, "")
|
||||
f.StringVar(&c.KeyFile, "key-file", c.KeyFile, "")
|
||||
|
||||
f.StringVar(&c.Peer.CAFile, "peer-ca-file", c.Peer.CAFile, "")
|
||||
f.StringVar(&c.Peer.CertFile, "peer-cert-file", c.Peer.CertFile, "")
|
||||
f.StringVar(&c.Peer.KeyFile, "peer-key-file", c.Peer.KeyFile, "")
|
||||
|
||||
f.StringVar(&c.DataDir, "data-dir", c.DataDir, "")
|
||||
f.IntVar(&c.MaxResultBuffer, "max-result-buffer", c.MaxResultBuffer, "")
|
||||
f.IntVar(&c.MaxRetryAttempts, "max-retry-attempts", c.MaxRetryAttempts, "")
|
||||
f.Float64Var(&c.RetryInterval, "retry-interval", c.RetryInterval, "")
|
||||
f.IntVar(&c.Peer.HeartbeatInterval, "peer-heartbeat-interval", c.Peer.HeartbeatInterval, "")
|
||||
f.IntVar(&c.Peer.ElectionTimeout, "peer-election-timeout", c.Peer.ElectionTimeout, "")
|
||||
|
||||
f.StringVar(&cors, "cors", "", "")
|
||||
|
||||
f.BoolVar(&c.Snapshot, "snapshot", c.Snapshot, "")
|
||||
f.IntVar(&c.SnapshotCount, "snapshot-count", c.SnapshotCount, "")
|
||||
f.StringVar(&c.CPUProfileFile, "cpuprofile", "", "")
|
||||
|
||||
f.StringVar(&c.strTrace, "trace", "", "")
|
||||
f.StringVar(&c.GraphiteHost, "graphite-host", "", "")
|
||||
|
||||
f.IntVar(&c.Cluster.ActiveSize, "cluster-active-size", c.Cluster.ActiveSize, "")
|
||||
f.Float64Var(&c.Cluster.RemoveDelay, "cluster-remove-delay", c.Cluster.RemoveDelay, "")
|
||||
f.Float64Var(&c.Cluster.SyncInterval, "cluster-sync-interval", c.Cluster.SyncInterval, "")
|
||||
|
||||
// BEGIN IGNORED FLAGS
|
||||
f.StringVar(&path, "config", "", "")
|
||||
// BEGIN IGNORED FLAGS
|
||||
|
||||
// BEGIN DEPRECATED FLAGS
|
||||
f.StringVar(&peers, "C", "", "(deprecated)")
|
||||
f.StringVar(&c.PeersFile, "CF", c.PeersFile, "(deprecated)")
|
||||
f.StringVar(&c.Name, "n", c.Name, "(deprecated)")
|
||||
f.StringVar(&c.Addr, "c", c.Addr, "(deprecated)")
|
||||
f.StringVar(&c.BindAddr, "cl", c.BindAddr, "(deprecated)")
|
||||
f.StringVar(&c.Peer.Addr, "s", c.Peer.Addr, "(deprecated)")
|
||||
f.StringVar(&c.Peer.BindAddr, "sl", c.Peer.BindAddr, "(deprecated)")
|
||||
f.StringVar(&c.Peer.CAFile, "serverCAFile", c.Peer.CAFile, "(deprecated)")
|
||||
f.StringVar(&c.Peer.CertFile, "serverCert", c.Peer.CertFile, "(deprecated)")
|
||||
f.StringVar(&c.Peer.KeyFile, "serverKey", c.Peer.KeyFile, "(deprecated)")
|
||||
f.StringVar(&c.CAFile, "clientCAFile", c.CAFile, "(deprecated)")
|
||||
f.StringVar(&c.CertFile, "clientCert", c.CertFile, "(deprecated)")
|
||||
f.StringVar(&c.KeyFile, "clientKey", c.KeyFile, "(deprecated)")
|
||||
f.StringVar(&c.DataDir, "d", c.DataDir, "(deprecated)")
|
||||
f.IntVar(&c.MaxResultBuffer, "m", c.MaxResultBuffer, "(deprecated)")
|
||||
f.IntVar(&c.MaxRetryAttempts, "r", c.MaxRetryAttempts, "(deprecated)")
|
||||
f.IntVar(&c.SnapshotCount, "snapshotCount", c.SnapshotCount, "(deprecated)")
|
||||
f.IntVar(&c.Peer.HeartbeatInterval, "peer-heartbeat-timeout", c.Peer.HeartbeatInterval, "(deprecated)")
|
||||
// END DEPRECATED FLAGS
|
||||
|
||||
if err := f.Parse(arguments); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Print deprecation warnings on STDERR.
|
||||
f.Visit(func(f *flag.Flag) {
|
||||
if len(newFlagNameLookup[f.Name]) > 0 {
|
||||
fmt.Fprintf(os.Stderr, "[deprecated] use -%s, not -%s\n", newFlagNameLookup[f.Name], f.Name)
|
||||
}
|
||||
})
|
||||
|
||||
// Convert some parameters to lists.
|
||||
if peers != "" {
|
||||
c.Peers = ustrings.TrimSplit(peers, ",")
|
||||
}
|
||||
if cors != "" {
|
||||
c.CorsOrigins = ustrings.TrimSplit(cors, ",")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadPeersFile loads the peers listed in the peers file.
|
||||
func (c *Config) LoadPeersFile() error {
|
||||
if c.PeersFile == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadFile(c.PeersFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Peers file error: %s", err)
|
||||
}
|
||||
c.Peers = ustrings.TrimSplit(string(b), ",")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DataDirFromName sets the data dir from a machine name and issue a warning
|
||||
// that etcd is guessing.
|
||||
func (c *Config) DataDirFromName() {
|
||||
c.DataDir = c.Name + ".etcd"
|
||||
log.Warnf("Using the directory %s as the etcd curation directory because a directory was not specified. ", c.DataDir)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NameFromHostname sets the machine name from the hostname. This is to help
|
||||
// people get started without thinking up a name.
|
||||
func (c *Config) NameFromHostname() {
|
||||
host, err := os.Hostname()
|
||||
if err != nil && host == "" {
|
||||
log.Fatal("Node name required and hostname not set. e.g. '-name=name'")
|
||||
}
|
||||
c.Name = host
|
||||
}
|
||||
|
||||
// Reset removes all server configuration files.
|
||||
func (c *Config) Reset() error {
|
||||
if err := os.RemoveAll(filepath.Join(c.DataDir, "log")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.RemoveAll(filepath.Join(c.DataDir, "conf")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.RemoveAll(filepath.Join(c.DataDir, "snapshot")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.RemoveAll(filepath.Join(c.DataDir, "standby_info")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sanitize cleans the input fields.
|
||||
func (c *Config) Sanitize() error {
|
||||
var err error
|
||||
var url *url.URL
|
||||
|
||||
// Sanitize the URLs first.
|
||||
if c.Addr, url, err = sanitizeURL(c.Addr, c.EtcdTLSInfo().Scheme()); err != nil {
|
||||
return fmt.Errorf("Advertised URL: %s", err)
|
||||
}
|
||||
if c.BindAddr, err = sanitizeBindAddr(c.BindAddr, url); err != nil {
|
||||
return fmt.Errorf("Listen Host: %s", err)
|
||||
}
|
||||
if c.Peer.Addr, url, err = sanitizeURL(c.Peer.Addr, c.PeerTLSInfo().Scheme()); err != nil {
|
||||
return fmt.Errorf("Peer Advertised URL: %s", err)
|
||||
}
|
||||
if c.Peer.BindAddr, err = sanitizeBindAddr(c.Peer.BindAddr, url); err != nil {
|
||||
return fmt.Errorf("Peer Listen Host: %s", err)
|
||||
}
|
||||
|
||||
// Only guess the machine name if there is no data dir specified
|
||||
// because the info file should have our name
|
||||
if c.Name == "" && c.DataDir == "" {
|
||||
c.NameFromHostname()
|
||||
}
|
||||
|
||||
if c.DataDir == "" && c.Name != "" && !c.ShowVersion && !c.ShowHelp {
|
||||
c.DataDirFromName()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EtcdTLSInfo retrieves a TLSInfo object for the etcd server
|
||||
func (c *Config) EtcdTLSInfo() *server.TLSInfo {
|
||||
return &server.TLSInfo{
|
||||
CAFile: c.CAFile,
|
||||
CertFile: c.CertFile,
|
||||
KeyFile: c.KeyFile,
|
||||
}
|
||||
}
|
||||
|
||||
// PeerRaftInfo retrieves a TLSInfo object for the peer server.
|
||||
func (c *Config) PeerTLSInfo() *server.TLSInfo {
|
||||
return &server.TLSInfo{
|
||||
CAFile: c.Peer.CAFile,
|
||||
CertFile: c.Peer.CertFile,
|
||||
KeyFile: c.Peer.KeyFile,
|
||||
}
|
||||
}
|
||||
|
||||
// MetricsBucketName generates the name that should be used for a
|
||||
// corresponding MetricsBucket object
|
||||
func (c *Config) MetricsBucketName() string {
|
||||
return fmt.Sprintf("etcd.%s", c.Name)
|
||||
}
|
||||
|
||||
// Trace determines if any trace-level information should be emitted
|
||||
func (c *Config) Trace() bool {
|
||||
return c.strTrace == "*"
|
||||
}
|
||||
|
||||
func (c *Config) ClusterConfig() *server.ClusterConfig {
|
||||
return &server.ClusterConfig{
|
||||
ActiveSize: c.Cluster.ActiveSize,
|
||||
RemoveDelay: c.Cluster.RemoveDelay,
|
||||
SyncInterval: c.Cluster.SyncInterval,
|
||||
}
|
||||
}
|
||||
|
||||
// sanitizeURL will cleanup a host string in the format hostname[:port] and
|
||||
// attach a schema.
|
||||
func sanitizeURL(host string, defaultScheme string) (string, *url.URL, error) {
|
||||
// Blank URLs are fine input, just return it
|
||||
if len(host) == 0 {
|
||||
return host, &url.URL{}, nil
|
||||
}
|
||||
|
||||
p, err := url.Parse(host)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
// Make sure the host is in Host:Port format
|
||||
_, _, err = net.SplitHostPort(host)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
p = &url.URL{Host: host, Scheme: defaultScheme}
|
||||
return p.String(), p, nil
|
||||
}
|
||||
|
||||
// sanitizeBindAddr cleans up the BindAddr parameter and appends a port
|
||||
// if necessary based on the advertised port.
|
||||
func sanitizeBindAddr(bindAddr string, aurl *url.URL) (string, error) {
|
||||
// If it is a valid host:port simply return with no further checks.
|
||||
bhost, bport, err := net.SplitHostPort(bindAddr)
|
||||
if err == nil && bhost != "" {
|
||||
return bindAddr, nil
|
||||
}
|
||||
|
||||
// SplitHostPort makes the host optional, but we don't want that.
|
||||
if bhost == "" && bport != "" {
|
||||
return "", fmt.Errorf("IP required can't use a port only")
|
||||
}
|
||||
|
||||
// bindAddr doesn't have a port if we reach here so take the port from the
|
||||
// advertised URL.
|
||||
_, aport, err := net.SplitHostPort(aurl.Host)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return net.JoinHostPort(bindAddr, aport), nil
|
||||
}
|
797
config/config_test.go
Normal file
797
config/config_test.go
Normal file
@ -0,0 +1,797 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/etcd/third_party/github.com/BurntSushi/toml"
|
||||
"github.com/coreos/etcd/third_party/github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// Ensures that a configuration can be deserialized from TOML.
|
||||
func TestConfigTOML(t *testing.T) {
|
||||
content := `
|
||||
addr = "127.0.0.1:4002"
|
||||
ca_file = "/tmp/file.ca"
|
||||
cert_file = "/tmp/file.cert"
|
||||
cors = ["*"]
|
||||
cpu_profile_file = "XXX"
|
||||
data_dir = "/tmp/data"
|
||||
discovery = "http://example.com/foobar"
|
||||
key_file = "/tmp/file.key"
|
||||
bind_addr = "127.0.0.1:4003"
|
||||
peers = ["coreos.com:4001", "coreos.com:4002"]
|
||||
peers_file = "/tmp/peers"
|
||||
max_cluster_size = 10
|
||||
max_result_buffer = 512
|
||||
max_retry_attempts = 5
|
||||
name = "test-name"
|
||||
snapshot = true
|
||||
verbose = true
|
||||
very_verbose = true
|
||||
|
||||
[peer]
|
||||
addr = "127.0.0.1:7002"
|
||||
ca_file = "/tmp/peer/file.ca"
|
||||
cert_file = "/tmp/peer/file.cert"
|
||||
key_file = "/tmp/peer/file.key"
|
||||
bind_addr = "127.0.0.1:7003"
|
||||
|
||||
[cluster]
|
||||
active_size = 5
|
||||
remove_delay = 100.0
|
||||
sync_interval = 10.0
|
||||
`
|
||||
c := New()
|
||||
_, err := toml.Decode(content, &c)
|
||||
assert.Nil(t, err, "")
|
||||
assert.Equal(t, c.Addr, "127.0.0.1:4002", "")
|
||||
assert.Equal(t, c.CAFile, "/tmp/file.ca", "")
|
||||
assert.Equal(t, c.CertFile, "/tmp/file.cert", "")
|
||||
assert.Equal(t, c.CorsOrigins, []string{"*"}, "")
|
||||
assert.Equal(t, c.DataDir, "/tmp/data", "")
|
||||
assert.Equal(t, c.Discovery, "http://example.com/foobar", "")
|
||||
assert.Equal(t, c.KeyFile, "/tmp/file.key", "")
|
||||
assert.Equal(t, c.BindAddr, "127.0.0.1:4003", "")
|
||||
assert.Equal(t, c.Peers, []string{"coreos.com:4001", "coreos.com:4002"}, "")
|
||||
assert.Equal(t, c.PeersFile, "/tmp/peers", "")
|
||||
assert.Equal(t, c.MaxResultBuffer, 512, "")
|
||||
assert.Equal(t, c.MaxRetryAttempts, 5, "")
|
||||
assert.Equal(t, c.Name, "test-name", "")
|
||||
assert.Equal(t, c.Snapshot, true, "")
|
||||
assert.Equal(t, c.Verbose, true, "")
|
||||
assert.Equal(t, c.VeryVerbose, true, "")
|
||||
assert.Equal(t, c.Peer.Addr, "127.0.0.1:7002", "")
|
||||
assert.Equal(t, c.Peer.CAFile, "/tmp/peer/file.ca", "")
|
||||
assert.Equal(t, c.Peer.CertFile, "/tmp/peer/file.cert", "")
|
||||
assert.Equal(t, c.Peer.KeyFile, "/tmp/peer/file.key", "")
|
||||
assert.Equal(t, c.Peer.BindAddr, "127.0.0.1:7003", "")
|
||||
assert.Equal(t, c.Cluster.ActiveSize, 5, "")
|
||||
assert.Equal(t, c.Cluster.RemoveDelay, 100.0, "")
|
||||
assert.Equal(t, c.Cluster.SyncInterval, 10.0, "")
|
||||
}
|
||||
|
||||
// Ensures that a configuration can be retrieved from environment variables.
|
||||
func TestConfigEnv(t *testing.T) {
|
||||
os.Setenv("ETCD_CA_FILE", "/tmp/file.ca")
|
||||
os.Setenv("ETCD_CERT_FILE", "/tmp/file.cert")
|
||||
os.Setenv("ETCD_CPU_PROFILE_FILE", "XXX")
|
||||
os.Setenv("ETCD_CORS", "localhost:4001,localhost:4002")
|
||||
os.Setenv("ETCD_DATA_DIR", "/tmp/data")
|
||||
os.Setenv("ETCD_DISCOVERY", "http://example.com/foobar")
|
||||
os.Setenv("ETCD_KEY_FILE", "/tmp/file.key")
|
||||
os.Setenv("ETCD_BIND_ADDR", "127.0.0.1:4003")
|
||||
os.Setenv("ETCD_PEERS", "coreos.com:4001,coreos.com:4002")
|
||||
os.Setenv("ETCD_PEERS_FILE", "/tmp/peers")
|
||||
os.Setenv("ETCD_MAX_CLUSTER_SIZE", "10")
|
||||
os.Setenv("ETCD_MAX_RESULT_BUFFER", "512")
|
||||
os.Setenv("ETCD_MAX_RETRY_ATTEMPTS", "5")
|
||||
os.Setenv("ETCD_NAME", "test-name")
|
||||
os.Setenv("ETCD_SNAPSHOT", "true")
|
||||
os.Setenv("ETCD_VERBOSE", "1")
|
||||
os.Setenv("ETCD_VERY_VERBOSE", "yes")
|
||||
os.Setenv("ETCD_PEER_ADDR", "127.0.0.1:7002")
|
||||
os.Setenv("ETCD_PEER_CA_FILE", "/tmp/peer/file.ca")
|
||||
os.Setenv("ETCD_PEER_CERT_FILE", "/tmp/peer/file.cert")
|
||||
os.Setenv("ETCD_PEER_KEY_FILE", "/tmp/peer/file.key")
|
||||
os.Setenv("ETCD_PEER_BIND_ADDR", "127.0.0.1:7003")
|
||||
os.Setenv("ETCD_CLUSTER_ACTIVE_SIZE", "5")
|
||||
os.Setenv("ETCD_CLUSTER_REMOVE_DELAY", "100")
|
||||
os.Setenv("ETCD_CLUSTER_SYNC_INTERVAL", "10")
|
||||
|
||||
c := New()
|
||||
c.LoadEnv()
|
||||
assert.Equal(t, c.CAFile, "/tmp/file.ca", "")
|
||||
assert.Equal(t, c.CertFile, "/tmp/file.cert", "")
|
||||
assert.Equal(t, c.CorsOrigins, []string{"localhost:4001", "localhost:4002"}, "")
|
||||
assert.Equal(t, c.DataDir, "/tmp/data", "")
|
||||
assert.Equal(t, c.Discovery, "http://example.com/foobar", "")
|
||||
assert.Equal(t, c.KeyFile, "/tmp/file.key", "")
|
||||
assert.Equal(t, c.BindAddr, "127.0.0.1:4003", "")
|
||||
assert.Equal(t, c.Peers, []string{"coreos.com:4001", "coreos.com:4002"}, "")
|
||||
assert.Equal(t, c.PeersFile, "/tmp/peers", "")
|
||||
assert.Equal(t, c.MaxResultBuffer, 512, "")
|
||||
assert.Equal(t, c.MaxRetryAttempts, 5, "")
|
||||
assert.Equal(t, c.Name, "test-name", "")
|
||||
assert.Equal(t, c.Snapshot, true, "")
|
||||
assert.Equal(t, c.Verbose, true, "")
|
||||
assert.Equal(t, c.VeryVerbose, true, "")
|
||||
assert.Equal(t, c.Peer.Addr, "127.0.0.1:7002", "")
|
||||
assert.Equal(t, c.Peer.CAFile, "/tmp/peer/file.ca", "")
|
||||
assert.Equal(t, c.Peer.CertFile, "/tmp/peer/file.cert", "")
|
||||
assert.Equal(t, c.Peer.KeyFile, "/tmp/peer/file.key", "")
|
||||
assert.Equal(t, c.Peer.BindAddr, "127.0.0.1:7003", "")
|
||||
assert.Equal(t, c.Cluster.ActiveSize, 5, "")
|
||||
assert.Equal(t, c.Cluster.RemoveDelay, 100.0, "")
|
||||
assert.Equal(t, c.Cluster.SyncInterval, 10.0, "")
|
||||
|
||||
// Clear this as it will mess up other tests
|
||||
os.Setenv("ETCD_DISCOVERY", "")
|
||||
}
|
||||
|
||||
// Ensures that the "help" flag can be parsed.
|
||||
func TestConfigHelpFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-help"}), "")
|
||||
assert.True(t, c.ShowHelp)
|
||||
}
|
||||
|
||||
// Ensures that the abbreviated "help" flag can be parsed.
|
||||
func TestConfigAbbreviatedHelpFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-h"}), "")
|
||||
assert.True(t, c.ShowHelp)
|
||||
}
|
||||
|
||||
// Ensures that the "version" flag can be parsed.
|
||||
func TestConfigVersionFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-version"}), "")
|
||||
assert.True(t, c.ShowVersion)
|
||||
}
|
||||
|
||||
// Ensures that the "force config" flag can be parsed.
|
||||
func TestConfigForceFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-force"}), "")
|
||||
assert.True(t, c.Force)
|
||||
}
|
||||
|
||||
// Ensures that the abbreviated "force config" flag can be parsed.
|
||||
func TestConfigAbbreviatedForceFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-f"}), "")
|
||||
assert.True(t, c.Force)
|
||||
}
|
||||
|
||||
// Ensures that the advertised url can be parsed from the environment.
|
||||
func TestConfigAddrEnv(t *testing.T) {
|
||||
withEnv("ETCD_ADDR", "127.0.0.1:4002", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.Addr, "127.0.0.1:4002", "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the advertised flag can be parsed.
|
||||
func TestConfigAddrFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-addr", "127.0.0.1:4002"}), "")
|
||||
assert.Equal(t, c.Addr, "127.0.0.1:4002", "")
|
||||
}
|
||||
|
||||
// Ensures that the CA file can be parsed from the environment.
|
||||
func TestConfigCAFileEnv(t *testing.T) {
|
||||
withEnv("ETCD_CA_FILE", "/tmp/file.ca", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.CAFile, "/tmp/file.ca", "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the CA file flag can be parsed.
|
||||
func TestConfigCAFileFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-ca-file", "/tmp/file.ca"}), "")
|
||||
assert.Equal(t, c.CAFile, "/tmp/file.ca", "")
|
||||
}
|
||||
|
||||
// Ensures that the CA file can be parsed from the environment.
|
||||
func TestConfigCertFileEnv(t *testing.T) {
|
||||
withEnv("ETCD_CERT_FILE", "/tmp/file.cert", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.CertFile, "/tmp/file.cert", "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the Cert file flag can be parsed.
|
||||
func TestConfigCertFileFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-cert-file", "/tmp/file.cert"}), "")
|
||||
assert.Equal(t, c.CertFile, "/tmp/file.cert", "")
|
||||
}
|
||||
|
||||
// Ensures that the Key file can be parsed from the environment.
|
||||
func TestConfigKeyFileEnv(t *testing.T) {
|
||||
withEnv("ETCD_KEY_FILE", "/tmp/file.key", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.KeyFile, "/tmp/file.key", "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the Key file flag can be parsed.
|
||||
func TestConfigKeyFileFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-key-file", "/tmp/file.key"}), "")
|
||||
assert.Equal(t, c.KeyFile, "/tmp/file.key", "")
|
||||
}
|
||||
|
||||
// Ensures that the Listen Host can be parsed from the environment.
|
||||
func TestConfigBindAddrEnv(t *testing.T) {
|
||||
withEnv("ETCD_BIND_ADDR", "127.0.0.1:4003", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.BindAddr, "127.0.0.1:4003", "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the Listen Host file flag can be parsed.
|
||||
func TestConfigBindAddrFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-bind-addr", "127.0.0.1:4003"}), "")
|
||||
assert.Equal(t, c.BindAddr, "127.0.0.1:4003", "")
|
||||
}
|
||||
|
||||
// Ensures that the Listen Host port overrides the advertised port
|
||||
func TestConfigBindAddrOverride(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-addr", "127.0.0.1:4009", "-bind-addr", "127.0.0.1:4010"}), "")
|
||||
assert.Nil(t, c.Sanitize())
|
||||
assert.Equal(t, c.BindAddr, "127.0.0.1:4010", "")
|
||||
}
|
||||
|
||||
// Ensures that the Listen Host port overrides the advertised port
|
||||
func TestConfigBindIPv6AddrOverride(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-addr", "[::1]:4009", "-bind-addr", "[::1]:4010"}), "")
|
||||
assert.Nil(t, c.Sanitize())
|
||||
assert.Equal(t, c.BindAddr, "[::1]:4010", "")
|
||||
}
|
||||
|
||||
// Ensures that the Listen Host port overrides the advertised port
|
||||
func TestConfigBindIPv6WithZoneAddrOverride(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-addr", "[::1%25lo]:4009", "-bind-addr", "[::1%25lo]:4010"}), "")
|
||||
assert.Nil(t, c.Sanitize())
|
||||
assert.Equal(t, c.BindAddr, "[::1%25lo]:4010", "")
|
||||
}
|
||||
|
||||
// Ensures that the Listen Host inherits its port from the advertised addr
|
||||
func TestConfigBindAddrInheritPort(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-addr", "127.0.0.1:4009", "-bind-addr", "127.0.0.1"}), "")
|
||||
assert.Nil(t, c.Sanitize())
|
||||
assert.Equal(t, c.BindAddr, "127.0.0.1:4009", "")
|
||||
}
|
||||
|
||||
// Ensures that the Listen Host inherits its port from the advertised addr
|
||||
func TestConfigBindIPv6AddrInheritPort(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-addr", "[::1]:4009", "-bind-addr", "::1"}), "")
|
||||
assert.Nil(t, c.Sanitize())
|
||||
assert.Equal(t, c.BindAddr, "[::1]:4009", "")
|
||||
}
|
||||
|
||||
// Ensures that the Listen Host inherits its port from the advertised addr
|
||||
func TestConfigBindIPv6WithZoneAddrInheritPort(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-addr", "[::1%25lo]:4009", "-bind-addr", "::1%25lo"}), "")
|
||||
assert.Nil(t, c.Sanitize())
|
||||
assert.Equal(t, c.BindAddr, "[::1%25lo]:4009", "")
|
||||
}
|
||||
|
||||
// Ensures that a port only argument errors out
|
||||
func TestConfigBindAddrErrorOnNoHost(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-addr", "127.0.0.1:4009", "-bind-addr", ":4010"}), "")
|
||||
assert.Error(t, c.Sanitize())
|
||||
}
|
||||
|
||||
// Ensures that a bad IPv6 address will raise an error
|
||||
func TestConfigBindAddrErrorOnBadIPv6Addr(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-addr", "[::1%lo]:4009"}), "")
|
||||
assert.Error(t, c.Sanitize())
|
||||
}
|
||||
|
||||
// Ensures that the peers can be parsed from the environment.
|
||||
func TestConfigPeersEnv(t *testing.T) {
|
||||
withEnv("ETCD_PEERS", "coreos.com:4001,coreos.com:4002", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.Peers, []string{"coreos.com:4001", "coreos.com:4002"}, "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the Peers flag can be parsed.
|
||||
func TestConfigPeersFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-peers", "coreos.com:4001,coreos.com:4002"}), "")
|
||||
assert.Equal(t, c.Peers, []string{"coreos.com:4001", "coreos.com:4002"}, "")
|
||||
}
|
||||
|
||||
// Ensures that the Peers File can be parsed from the environment.
|
||||
func TestConfigPeersFileEnv(t *testing.T) {
|
||||
withEnv("ETCD_PEERS_FILE", "/tmp/peers", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.PeersFile, "/tmp/peers", "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the Peers File flag can be parsed.
|
||||
func TestConfigPeersFileFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-peers-file", "/tmp/peers"}), "")
|
||||
assert.Equal(t, c.PeersFile, "/tmp/peers", "")
|
||||
}
|
||||
|
||||
// Ensures that the Max Result Buffer can be parsed from the environment.
|
||||
func TestConfigMaxResultBufferEnv(t *testing.T) {
|
||||
withEnv("ETCD_MAX_RESULT_BUFFER", "512", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.MaxResultBuffer, 512, "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the Max Result Buffer flag can be parsed.
|
||||
func TestConfigMaxResultBufferFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-max-result-buffer", "512"}), "")
|
||||
assert.Equal(t, c.MaxResultBuffer, 512, "")
|
||||
}
|
||||
|
||||
// Ensures that the Max Retry Attempts can be parsed from the environment.
|
||||
func TestConfigMaxRetryAttemptsEnv(t *testing.T) {
|
||||
withEnv("ETCD_MAX_RETRY_ATTEMPTS", "10", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.MaxRetryAttempts, 10, "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the Max Retry Attempts flag can be parsed.
|
||||
func TestConfigMaxRetryAttemptsFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-max-retry-attempts", "10"}), "")
|
||||
assert.Equal(t, c.MaxRetryAttempts, 10, "")
|
||||
}
|
||||
|
||||
// Ensures that the Name can be parsed from the environment.
|
||||
func TestConfigNameEnv(t *testing.T) {
|
||||
withEnv("ETCD_NAME", "test-name", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.Name, "test-name", "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the Name flag can be parsed.
|
||||
func TestConfigNameFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-name", "test-name"}), "")
|
||||
assert.Equal(t, c.Name, "test-name", "")
|
||||
}
|
||||
|
||||
// Ensures that a Name gets guessed if not specified
|
||||
func TestConfigNameGuess(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{}), "")
|
||||
assert.Nil(t, c.Sanitize())
|
||||
name, _ := os.Hostname()
|
||||
assert.Equal(t, c.Name, name, "")
|
||||
}
|
||||
|
||||
// Ensures that a DataDir gets guessed if not specified
|
||||
func TestConfigDataDirGuess(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{}), "")
|
||||
assert.Nil(t, c.Sanitize())
|
||||
name, _ := os.Hostname()
|
||||
assert.Equal(t, c.DataDir, name+".etcd", "")
|
||||
}
|
||||
|
||||
// Ensures that Snapshot can be parsed from the environment.
|
||||
func TestConfigSnapshotEnv(t *testing.T) {
|
||||
withEnv("ETCD_SNAPSHOT", "1", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.Snapshot, true, "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the Snapshot flag can be parsed.
|
||||
func TestConfigSnapshotFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-snapshot"}), "")
|
||||
assert.Equal(t, c.Snapshot, true, "")
|
||||
}
|
||||
|
||||
// Ensures that Verbose can be parsed from the environment.
|
||||
func TestConfigVerboseEnv(t *testing.T) {
|
||||
withEnv("ETCD_VERBOSE", "true", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.Verbose, true, "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the Verbose flag can be parsed.
|
||||
func TestConfigVerboseFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-v"}), "")
|
||||
assert.Equal(t, c.Verbose, true, "")
|
||||
}
|
||||
|
||||
// Ensures that Very Verbose can be parsed from the environment.
|
||||
func TestConfigVeryVerboseEnv(t *testing.T) {
|
||||
withEnv("ETCD_VERY_VERBOSE", "true", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.VeryVerbose, true, "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the Very Verbose flag can be parsed.
|
||||
func TestConfigVeryVerboseFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-vv"}), "")
|
||||
assert.Equal(t, c.VeryVerbose, true, "")
|
||||
}
|
||||
|
||||
// Ensures that the Peer Advertised URL can be parsed from the environment.
|
||||
func TestConfigPeerAddrEnv(t *testing.T) {
|
||||
withEnv("ETCD_PEER_ADDR", "localhost:7002", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.Peer.Addr, "localhost:7002", "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the Peer Advertised URL flag can be parsed.
|
||||
func TestConfigPeerAddrFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-peer-addr", "localhost:7002"}), "")
|
||||
assert.Equal(t, c.Peer.Addr, "localhost:7002", "")
|
||||
}
|
||||
|
||||
// Ensures that the Peer CA File can be parsed from the environment.
|
||||
func TestConfigPeerCAFileEnv(t *testing.T) {
|
||||
withEnv("ETCD_PEER_CA_FILE", "/tmp/peer/file.ca", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.Peer.CAFile, "/tmp/peer/file.ca", "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the Peer CA file flag can be parsed.
|
||||
func TestConfigPeerCAFileFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-peer-ca-file", "/tmp/peer/file.ca"}), "")
|
||||
assert.Equal(t, c.Peer.CAFile, "/tmp/peer/file.ca", "")
|
||||
}
|
||||
|
||||
// Ensures that the Peer Cert File can be parsed from the environment.
|
||||
func TestConfigPeerCertFileEnv(t *testing.T) {
|
||||
withEnv("ETCD_PEER_CERT_FILE", "/tmp/peer/file.cert", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.Peer.CertFile, "/tmp/peer/file.cert", "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the Cert file flag can be parsed.
|
||||
func TestConfigPeerCertFileFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-peer-cert-file", "/tmp/peer/file.cert"}), "")
|
||||
assert.Equal(t, c.Peer.CertFile, "/tmp/peer/file.cert", "")
|
||||
}
|
||||
|
||||
// Ensures that the Peer Key File can be parsed from the environment.
|
||||
func TestConfigPeerKeyFileEnv(t *testing.T) {
|
||||
withEnv("ETCD_PEER_KEY_FILE", "/tmp/peer/file.key", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.Peer.KeyFile, "/tmp/peer/file.key", "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the Peer Key file flag can be parsed.
|
||||
func TestConfigPeerKeyFileFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-peer-key-file", "/tmp/peer/file.key"}), "")
|
||||
assert.Equal(t, c.Peer.KeyFile, "/tmp/peer/file.key", "")
|
||||
}
|
||||
|
||||
// Ensures that the Peer Listen Host can be parsed from the environment.
|
||||
func TestConfigPeerBindAddrEnv(t *testing.T) {
|
||||
withEnv("ETCD_PEER_BIND_ADDR", "localhost:7004", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.Peer.BindAddr, "localhost:7004", "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that a bad flag returns an error.
|
||||
func TestConfigBadFlag(t *testing.T) {
|
||||
c := New()
|
||||
err := c.LoadFlags([]string{"-no-such-flag"})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, err.Error(), `flag provided but not defined: -no-such-flag`)
|
||||
}
|
||||
|
||||
// Ensures that the Peer Listen Host file flag can be parsed.
|
||||
func TestConfigPeerBindAddrFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-peer-bind-addr", "127.0.0.1:4003"}), "")
|
||||
assert.Equal(t, c.Peer.BindAddr, "127.0.0.1:4003", "")
|
||||
}
|
||||
|
||||
// Ensures that the cluster active size can be parsed from the environment.
|
||||
func TestConfigClusterActiveSizeEnv(t *testing.T) {
|
||||
withEnv("ETCD_CLUSTER_ACTIVE_SIZE", "5", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.Cluster.ActiveSize, 5, "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the cluster active size flag can be parsed.
|
||||
func TestConfigClusterActiveSizeFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-cluster-active-size", "5"}), "")
|
||||
assert.Equal(t, c.Cluster.ActiveSize, 5, "")
|
||||
}
|
||||
|
||||
// Ensures that the cluster remove delay can be parsed from the environment.
|
||||
func TestConfigClusterRemoveDelayEnv(t *testing.T) {
|
||||
withEnv("ETCD_CLUSTER_REMOVE_DELAY", "100", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.Cluster.RemoveDelay, 100.0, "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the cluster remove delay flag can be parsed.
|
||||
func TestConfigClusterRemoveDelayFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-cluster-remove-delay", "100"}), "")
|
||||
assert.Equal(t, c.Cluster.RemoveDelay, 100.0, "")
|
||||
}
|
||||
|
||||
// Ensures that the cluster sync interval can be parsed from the environment.
|
||||
func TestConfigClusterSyncIntervalEnv(t *testing.T) {
|
||||
withEnv("ETCD_CLUSTER_SYNC_INTERVAL", "10", func(c *Config) {
|
||||
assert.Nil(t, c.LoadEnv(), "")
|
||||
assert.Equal(t, c.Cluster.SyncInterval, 10.0, "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that the cluster sync interval flag can be parsed.
|
||||
func TestConfigClusterSyncIntervalFlag(t *testing.T) {
|
||||
c := New()
|
||||
assert.Nil(t, c.LoadFlags([]string{"-cluster-sync-interval", "10"}), "")
|
||||
assert.Equal(t, c.Cluster.SyncInterval, 10.0, "")
|
||||
}
|
||||
|
||||
// Ensures that a system config field is overridden by a custom config field.
|
||||
func TestConfigCustomConfigOverrideSystemConfig(t *testing.T) {
|
||||
system := `addr = "127.0.0.1:5000"`
|
||||
custom := `addr = "127.0.0.1:6000"`
|
||||
withTempFile(system, func(p1 string) {
|
||||
withTempFile(custom, func(p2 string) {
|
||||
c := New()
|
||||
c.SystemPath = p1
|
||||
assert.Nil(t, c.Load([]string{"-config", p2}), "")
|
||||
assert.Equal(t, c.Addr, "127.0.0.1:6000", "")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that a custom config field is overridden by an environment variable.
|
||||
func TestConfigEnvVarOverrideCustomConfig(t *testing.T) {
|
||||
os.Setenv("ETCD_PEER_ADDR", "127.0.0.1:8000")
|
||||
defer os.Setenv("ETCD_PEER_ADDR", "")
|
||||
|
||||
custom := `[peer]` + "\n" + `advertised_url = "127.0.0.1:9000"`
|
||||
withTempFile(custom, func(path string) {
|
||||
c := New()
|
||||
c.SystemPath = ""
|
||||
assert.Nil(t, c.Load([]string{"-config", path}), "")
|
||||
assert.Equal(t, c.Peer.Addr, "127.0.0.1:8000", "")
|
||||
})
|
||||
}
|
||||
|
||||
// Ensures that an environment variable field is overridden by a command line argument.
|
||||
func TestConfigCLIArgsOverrideEnvVar(t *testing.T) {
|
||||
os.Setenv("ETCD_ADDR", "127.0.0.1:1000")
|
||||
defer os.Setenv("ETCD_ADDR", "")
|
||||
|
||||
c := New()
|
||||
c.SystemPath = ""
|
||||
assert.Nil(t, c.Load([]string{"-addr", "127.0.0.1:2000"}), "")
|
||||
assert.Equal(t, c.Addr, "127.0.0.1:2000", "")
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
// DEPRECATED (v1)
|
||||
//--------------------------------------
|
||||
|
||||
func TestConfigDeprecatedAddrFlag(t *testing.T) {
|
||||
_, stderr := capture(func() {
|
||||
c := New()
|
||||
err := c.LoadFlags([]string{"-c", "127.0.0.1:4002"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.Addr, "127.0.0.1:4002")
|
||||
})
|
||||
assert.Equal(t, stderr, "[deprecated] use -addr, not -c\n")
|
||||
}
|
||||
|
||||
func TestConfigDeprecatedBindAddrFlag(t *testing.T) {
|
||||
_, stderr := capture(func() {
|
||||
c := New()
|
||||
err := c.LoadFlags([]string{"-cl", "127.0.0.1:4003"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.BindAddr, "127.0.0.1:4003", "")
|
||||
})
|
||||
assert.Equal(t, stderr, "[deprecated] use -bind-addr, not -cl\n", "")
|
||||
}
|
||||
|
||||
func TestConfigDeprecatedCAFileFlag(t *testing.T) {
|
||||
_, stderr := capture(func() {
|
||||
c := New()
|
||||
err := c.LoadFlags([]string{"-clientCAFile", "/tmp/file.ca"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.CAFile, "/tmp/file.ca", "")
|
||||
})
|
||||
assert.Equal(t, stderr, "[deprecated] use -ca-file, not -clientCAFile\n", "")
|
||||
}
|
||||
|
||||
func TestConfigDeprecatedCertFileFlag(t *testing.T) {
|
||||
_, stderr := capture(func() {
|
||||
c := New()
|
||||
err := c.LoadFlags([]string{"-clientCert", "/tmp/file.cert"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.CertFile, "/tmp/file.cert", "")
|
||||
})
|
||||
assert.Equal(t, stderr, "[deprecated] use -cert-file, not -clientCert\n", "")
|
||||
}
|
||||
|
||||
func TestConfigDeprecatedKeyFileFlag(t *testing.T) {
|
||||
_, stderr := capture(func() {
|
||||
c := New()
|
||||
err := c.LoadFlags([]string{"-clientKey", "/tmp/file.key"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.KeyFile, "/tmp/file.key", "")
|
||||
})
|
||||
assert.Equal(t, stderr, "[deprecated] use -key-file, not -clientKey\n", "")
|
||||
}
|
||||
|
||||
func TestConfigDeprecatedPeersFlag(t *testing.T) {
|
||||
_, stderr := capture(func() {
|
||||
c := New()
|
||||
err := c.LoadFlags([]string{"-C", "coreos.com:4001,coreos.com:4002"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.Peers, []string{"coreos.com:4001", "coreos.com:4002"}, "")
|
||||
})
|
||||
assert.Equal(t, stderr, "[deprecated] use -peers, not -C\n", "")
|
||||
}
|
||||
|
||||
func TestConfigDeprecatedPeersFileFlag(t *testing.T) {
|
||||
_, stderr := capture(func() {
|
||||
c := New()
|
||||
err := c.LoadFlags([]string{"-CF", "/tmp/machines"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.PeersFile, "/tmp/machines", "")
|
||||
})
|
||||
assert.Equal(t, stderr, "[deprecated] use -peers-file, not -CF\n", "")
|
||||
}
|
||||
|
||||
func TestConfigDeprecatedMaxRetryAttemptsFlag(t *testing.T) {
|
||||
_, stderr := capture(func() {
|
||||
c := New()
|
||||
err := c.LoadFlags([]string{"-r", "10"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.MaxRetryAttempts, 10, "")
|
||||
})
|
||||
assert.Equal(t, stderr, "[deprecated] use -max-retry-attempts, not -r\n", "")
|
||||
}
|
||||
|
||||
func TestConfigDeprecatedNameFlag(t *testing.T) {
|
||||
_, stderr := capture(func() {
|
||||
c := New()
|
||||
err := c.LoadFlags([]string{"-n", "test-name"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.Name, "test-name", "")
|
||||
})
|
||||
assert.Equal(t, stderr, "[deprecated] use -name, not -n\n", "")
|
||||
}
|
||||
|
||||
func TestConfigDeprecatedPeerAddrFlag(t *testing.T) {
|
||||
_, stderr := capture(func() {
|
||||
c := New()
|
||||
err := c.LoadFlags([]string{"-s", "localhost:7002"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.Peer.Addr, "localhost:7002", "")
|
||||
})
|
||||
assert.Equal(t, stderr, "[deprecated] use -peer-addr, not -s\n", "")
|
||||
}
|
||||
|
||||
func TestConfigDeprecatedPeerBindAddrFlag(t *testing.T) {
|
||||
_, stderr := capture(func() {
|
||||
c := New()
|
||||
err := c.LoadFlags([]string{"-sl", "127.0.0.1:4003"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.Peer.BindAddr, "127.0.0.1:4003", "")
|
||||
})
|
||||
assert.Equal(t, stderr, "[deprecated] use -peer-bind-addr, not -sl\n", "")
|
||||
}
|
||||
|
||||
func TestConfigDeprecatedPeerCAFileFlag(t *testing.T) {
|
||||
_, stderr := capture(func() {
|
||||
c := New()
|
||||
err := c.LoadFlags([]string{"-serverCAFile", "/tmp/peer/file.ca"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.Peer.CAFile, "/tmp/peer/file.ca", "")
|
||||
})
|
||||
assert.Equal(t, stderr, "[deprecated] use -peer-ca-file, not -serverCAFile\n", "")
|
||||
}
|
||||
|
||||
func TestConfigDeprecatedPeerCertFileFlag(t *testing.T) {
|
||||
_, stderr := capture(func() {
|
||||
c := New()
|
||||
err := c.LoadFlags([]string{"-serverCert", "/tmp/peer/file.cert"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.Peer.CertFile, "/tmp/peer/file.cert", "")
|
||||
})
|
||||
assert.Equal(t, stderr, "[deprecated] use -peer-cert-file, not -serverCert\n", "")
|
||||
}
|
||||
|
||||
func TestConfigDeprecatedPeerKeyFileFlag(t *testing.T) {
|
||||
_, stderr := capture(func() {
|
||||
c := New()
|
||||
err := c.LoadFlags([]string{"-serverKey", "/tmp/peer/file.key"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.Peer.KeyFile, "/tmp/peer/file.key", "")
|
||||
})
|
||||
assert.Equal(t, stderr, "[deprecated] use -peer-key-file, not -serverKey\n", "")
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------
|
||||
|
||||
// Sets up the environment with a given environment variable set.
|
||||
func withEnv(key, value string, f func(c *Config)) {
|
||||
os.Setenv(key, value)
|
||||
defer os.Setenv(key, "")
|
||||
c := New()
|
||||
f(c)
|
||||
}
|
||||
|
||||
// Creates a temp file and calls a function with the context.
|
||||
func withTempFile(content string, fn func(string)) {
|
||||
f, _ := ioutil.TempFile("", "")
|
||||
f.WriteString(content)
|
||||
f.Close()
|
||||
defer os.Remove(f.Name())
|
||||
fn(f.Name())
|
||||
}
|
||||
|
||||
// Captures STDOUT & STDERR and returns the output as strings.
|
||||
func capture(fn func()) (string, string) {
|
||||
// Create temp files.
|
||||
tmpout, _ := ioutil.TempFile("", "")
|
||||
defer os.Remove(tmpout.Name())
|
||||
tmperr, _ := ioutil.TempFile("", "")
|
||||
defer os.Remove(tmperr.Name())
|
||||
|
||||
stdout, stderr := os.Stdout, os.Stderr
|
||||
os.Stdout, os.Stderr = tmpout, tmperr
|
||||
|
||||
// Execute function argument and then reassign stdout/stderr.
|
||||
fn()
|
||||
os.Stdout, os.Stderr = stdout, stderr
|
||||
|
||||
// Close temp files and read them.
|
||||
tmpout.Close()
|
||||
bout, _ := ioutil.ReadFile(tmpout.Name())
|
||||
tmperr.Close()
|
||||
berr, _ := ioutil.ReadFile(tmperr.Name())
|
||||
|
||||
return string(bout), string(berr)
|
||||
}
|
9
config/timeout.go
Normal file
9
config/timeout.go
Normal file
@ -0,0 +1,9 @@
|
||||
package config
|
||||
|
||||
const (
|
||||
// The amount of time (in ms) to elapse without a heartbeat before becoming a candidate
|
||||
defaultElectionTimeout = 200
|
||||
|
||||
// The frequency (in ms) by which heartbeats are sent to followers.
|
||||
defaultHeartbeatInterval = 50
|
||||
)
|
9
contrib/collectd/Dockerfile
Normal file
9
contrib/collectd/Dockerfile
Normal file
@ -0,0 +1,9 @@
|
||||
FROM stackbrew/ubuntu:raring
|
||||
|
||||
RUN apt-get update && apt-get install -y collectd
|
||||
RUN adduser --system --group --no-create-home collectd
|
||||
ADD collectd.conf /etc/collectd/collectd.conf.tmpl
|
||||
ADD collectd-wrapper /bin/collectd-wrapper
|
||||
RUN chown -R collectd:collectd /etc/collectd
|
||||
|
||||
CMD ["collectd-wrapper"]
|
20
contrib/collectd/README
Normal file
20
contrib/collectd/README
Normal file
@ -0,0 +1,20 @@
|
||||
We're going to use Docker to build a chroot env that can be run with systemd-nspawn since I cannot figure out how to run
|
||||
a container using docker in the global network namespace.
|
||||
|
||||
1. Build the collectd image using docker
|
||||
docker build -t collectd .
|
||||
|
||||
2. Run the container (since we have to run it to export it...)
|
||||
COLLECTD_CONTAINER=`docker run -name collectd-tmp -d collectd`
|
||||
|
||||
3. Export then kill the container
|
||||
docker export collectd-tmp > /tmp/collectd.tar
|
||||
|
||||
4. Kill the temporary container
|
||||
docker kill $COLLECTD_CONTAINER
|
||||
|
||||
5. Unpack the tar archive
|
||||
mkdir -p /tmp/collectd && tar -xvf /tmp/collectd.tar -C /tmp/collectd/
|
||||
|
||||
6. Run collectd with systemd-nspawn - replace the COLLECTD_* env vars with your parameters!
|
||||
sudo systemd-run --unit collectd systemd-nspawn -D /tmp/collectd /bin/bash -c "COLLECTD_GRAPHITE_HOSTNAME=172.31.13.241 COLLECTD_LOCAL_HOSTNAME=node1 /bin/collectd-wrapper"
|
16
contrib/collectd/collectd-wrapper
Executable file
16
contrib/collectd/collectd-wrapper
Executable file
@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
cat /etc/collectd/collectd.conf.tmpl > /etc/collectd/collectd.conf
|
||||
|
||||
cat << EOF >> /etc/collectd/collectd.conf
|
||||
Hostname "${COLLECTD_LOCAL_HOSTNAME}"
|
||||
|
||||
<Plugin write_graphite>
|
||||
<Carbon>
|
||||
Host "${COLLECTD_GRAPHITE_HOSTNAME}"
|
||||
Port "2003"
|
||||
</Carbon>
|
||||
</Plugin>
|
||||
EOF
|
||||
|
||||
collectd -C /etc/collectd/collectd.conf -f
|
898
contrib/collectd/collectd.conf
Normal file
898
contrib/collectd/collectd.conf
Normal file
@ -0,0 +1,898 @@
|
||||
# Config file for collectd(1).
|
||||
#
|
||||
# Some plugins need additional configuration and are disabled by default.
|
||||
# Please read collectd.conf(5) for details.
|
||||
#
|
||||
# You should also read /usr/share/doc/collectd-core/README.Debian.plugins
|
||||
# before enabling any more plugins.
|
||||
|
||||
#Hostname "localhost"
|
||||
#FQDNLookup true
|
||||
#BaseDir "/var/lib/collectd"
|
||||
#PluginDir "/usr/lib/collectd"
|
||||
#TypesDB "/usr/share/collectd/types.db" "/etc/collectd/my_types.db"
|
||||
#Interval 10
|
||||
#Timeout 2
|
||||
#ReadThreads 5
|
||||
|
||||
LoadPlugin logfile
|
||||
#LoadPlugin syslog
|
||||
|
||||
<Plugin logfile>
|
||||
LogLevel "info"
|
||||
File STDOUT
|
||||
Timestamp true
|
||||
PrintSeverity false
|
||||
</Plugin>
|
||||
|
||||
#<Plugin syslog>
|
||||
# LogLevel info
|
||||
#</Plugin>
|
||||
|
||||
#LoadPlugin amqp
|
||||
#LoadPlugin apache
|
||||
#LoadPlugin apcups
|
||||
#LoadPlugin ascent
|
||||
#LoadPlugin battery
|
||||
#LoadPlugin bind
|
||||
#LoadPlugin conntrack
|
||||
#LoadPlugin contextswitch
|
||||
LoadPlugin cpu
|
||||
#LoadPlugin cpufreq
|
||||
#LoadPlugin csv
|
||||
#LoadPlugin curl
|
||||
#LoadPlugin curl_json
|
||||
#LoadPlugin curl_xml
|
||||
#LoadPlugin dbi
|
||||
LoadPlugin df
|
||||
#LoadPlugin disk
|
||||
#LoadPlugin dns
|
||||
#LoadPlugin email
|
||||
#LoadPlugin entropy
|
||||
#LoadPlugin ethstat
|
||||
#LoadPlugin exec
|
||||
#LoadPlugin filecount
|
||||
#LoadPlugin fscache
|
||||
#LoadPlugin gmond
|
||||
#LoadPlugin hddtemp
|
||||
#LoadPlugin interface
|
||||
#LoadPlugin ipmi
|
||||
#LoadPlugin iptables
|
||||
#LoadPlugin ipvs
|
||||
#LoadPlugin irq
|
||||
#LoadPlugin java
|
||||
#LoadPlugin libvirt
|
||||
#LoadPlugin load
|
||||
#LoadPlugin madwifi
|
||||
#LoadPlugin mbmon
|
||||
#LoadPlugin md
|
||||
#LoadPlugin memcachec
|
||||
#LoadPlugin memcached
|
||||
LoadPlugin memory
|
||||
#LoadPlugin multimeter
|
||||
#LoadPlugin mysql
|
||||
#LoadPlugin netlink
|
||||
#LoadPlugin network
|
||||
#LoadPlugin nfs
|
||||
#LoadPlugin nginx
|
||||
#LoadPlugin notify_desktop
|
||||
#LoadPlugin notify_email
|
||||
#LoadPlugin ntpd
|
||||
#LoadPlugin numa
|
||||
#LoadPlugin nut
|
||||
#LoadPlugin olsrd
|
||||
#LoadPlugin openvpn
|
||||
#<LoadPlugin perl>
|
||||
# Globals true
|
||||
#</LoadPlugin>
|
||||
#LoadPlugin pinba
|
||||
#LoadPlugin ping
|
||||
#LoadPlugin postgresql
|
||||
#LoadPlugin powerdns
|
||||
#LoadPlugin processes
|
||||
#LoadPlugin protocols
|
||||
#<LoadPlugin python>
|
||||
# Globals true
|
||||
#</LoadPlugin>
|
||||
#LoadPlugin rrdcached
|
||||
#LoadPlugin rrdtool
|
||||
#LoadPlugin sensors
|
||||
#LoadPlugin serial
|
||||
#LoadPlugin snmp
|
||||
#LoadPlugin swap
|
||||
#LoadPlugin table
|
||||
#LoadPlugin tail
|
||||
LoadPlugin tcpconns
|
||||
#LoadPlugin teamspeak2
|
||||
#LoadPlugin ted
|
||||
#LoadPlugin thermal
|
||||
#LoadPlugin tokyotyrant
|
||||
#LoadPlugin unixsock
|
||||
#LoadPlugin uptime
|
||||
#LoadPlugin users
|
||||
#LoadPlugin uuid
|
||||
#LoadPlugin varnish
|
||||
#LoadPlugin vmem
|
||||
#LoadPlugin vserver
|
||||
#LoadPlugin wireless
|
||||
LoadPlugin write_graphite
|
||||
#LoadPlugin write_http
|
||||
#LoadPlugin write_mongodb
|
||||
|
||||
#<Plugin amqp>
|
||||
# <Publish "name">
|
||||
# Host "localhost"
|
||||
# Port "5672"
|
||||
# VHost "/"
|
||||
# User "guest"
|
||||
# Password "guest"
|
||||
# Exchange "amq.fanout"
|
||||
# RoutingKey "collectd"
|
||||
# Persistent false
|
||||
# StoreRates false
|
||||
# </Publish>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin apache>
|
||||
# <Instance "foo">
|
||||
# URL "http://localhost/server-status?auto"
|
||||
# User "www-user"
|
||||
# Password "secret"
|
||||
# VerifyPeer false
|
||||
# VerifyHost false
|
||||
# CACert "/etc/ssl/ca.crt"
|
||||
# Server "apache"
|
||||
# </Instance>
|
||||
#
|
||||
# <Instance "bar">
|
||||
# URL "http://some.domain.tld/status?auto"
|
||||
# Host "some.domain.tld"
|
||||
# Server "lighttpd"
|
||||
# </Instance>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin apcups>
|
||||
# Host "localhost"
|
||||
# Port "3551"
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin ascent>
|
||||
# URL "http://localhost/ascent/status/"
|
||||
# User "www-user"
|
||||
# Password "secret"
|
||||
# VerifyPeer false
|
||||
# VerifyHost false
|
||||
# CACert "/etc/ssl/ca.crt"
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin "bind">
|
||||
# URL "http://localhost:8053/"
|
||||
#
|
||||
# ParseTime false
|
||||
#
|
||||
# OpCodes true
|
||||
# QTypes true
|
||||
# ServerStats true
|
||||
# ZoneMaintStats true
|
||||
# ResolverStats false
|
||||
# MemoryStats true
|
||||
#
|
||||
# <View "_default">
|
||||
# QTypes true
|
||||
# ResolverStats true
|
||||
# CacheRRSets true
|
||||
#
|
||||
# Zone "127.in-addr.arpa/IN"
|
||||
# </View>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin csv>
|
||||
# DataDir "/var/lib/collectd/csv"
|
||||
# StoreRates false
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin curl>
|
||||
# <Page "stock_quotes">
|
||||
# URL "http://finance.google.com/finance?q=NYSE%3AAMD"
|
||||
# User "foo"
|
||||
# Password "bar"
|
||||
# VerifyPeer false
|
||||
# VerifyHost false
|
||||
# CACert "/etc/ssl/ca.crt"
|
||||
# MeasureResponseTime false
|
||||
# <Match>
|
||||
# Regex "<span +class=\"pr\"[^>]*> *([0-9]*\\.[0-9]+) *</span>"
|
||||
# DSType "GaugeAverage"
|
||||
# Type "stock_value"
|
||||
# Instance "AMD"
|
||||
# </Match>
|
||||
# </Page>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin curl_json>
|
||||
## See: http://wiki.apache.org/couchdb/Runtime_Statistics
|
||||
# <URL "http://localhost:5984/_stats">
|
||||
# Instance "httpd"
|
||||
# <Key "httpd/requests/count">
|
||||
# Type "http_requests"
|
||||
# </Key>
|
||||
#
|
||||
# <Key "httpd_request_methods/*/count">
|
||||
# Type "http_request_methods"
|
||||
# </Key>
|
||||
#
|
||||
# <Key "httpd_status_codes/*/count">
|
||||
# Type "http_response_codes"
|
||||
# </Key>
|
||||
# </URL>
|
||||
## Database status metrics:
|
||||
# <URL "http://localhost:5984/_all_dbs">
|
||||
# Instance "dbs"
|
||||
# <Key "*/doc_count">
|
||||
# Type "gauge"
|
||||
# </Key>
|
||||
# <Key "*/doc_del_count">
|
||||
# Type "counter"
|
||||
# </Key>
|
||||
# <Key "*/disk_size">
|
||||
# Type "bytes"
|
||||
# </Key>
|
||||
# </URL>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin "curl_xml">
|
||||
# <URL "http://localhost/stats.xml">
|
||||
# Host "my_host"
|
||||
# Instance "some_instance"
|
||||
# User "collectd"
|
||||
# Password "thaiNg0I"
|
||||
# VerifyPeer true
|
||||
# VerifyHost true
|
||||
# CACert "/path/to/ca.crt"
|
||||
#
|
||||
# <XPath "table[@id=\"magic_level\"]/tr">
|
||||
# Type "magic_level"
|
||||
# InstancePrefix "prefix-"
|
||||
# InstanceFrom "td[1]"
|
||||
# ValuesFrom "td[2]/span[@class=\"level\"]"
|
||||
# </XPath>
|
||||
# </URL>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin dbi>
|
||||
# <Query "num_of_customers">
|
||||
# Statement "SELECT 'customers' AS c_key, COUNT(*) AS c_value \
|
||||
# FROM customers_tbl"
|
||||
# MinVersion 40102
|
||||
# MaxVersion 50042
|
||||
# <Result>
|
||||
# Type "gauge"
|
||||
# InstancePrefix "customer"
|
||||
# InstancesFrom "c_key"
|
||||
# ValuesFrom "c_value"
|
||||
# </Result>
|
||||
# </Query>
|
||||
#
|
||||
# <Database "customers_db">
|
||||
# Driver "mysql"
|
||||
# DriverOption "host" "localhost"
|
||||
# DriverOption "username" "collectd"
|
||||
# DriverOption "password" "secret"
|
||||
# DriverOption "dbname" "custdb0"
|
||||
# SelectDB "custdb0"
|
||||
# Query "num_of_customers"
|
||||
# Query "..."
|
||||
# </Database>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin df>
|
||||
# Device "/dev/sda1"
|
||||
# Device "192.168.0.2:/mnt/nfs"
|
||||
# MountPoint "/home"
|
||||
# FSType "ext3"
|
||||
# IgnoreSelected false
|
||||
# ReportByDevice false
|
||||
# ReportReserved false
|
||||
# ReportInodes false
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin disk>
|
||||
# Disk "hda"
|
||||
# Disk "/sda[23]/"
|
||||
# IgnoreSelected false
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin dns>
|
||||
# Interface "eth0"
|
||||
# IgnoreSource "192.168.0.1"
|
||||
# SelectNumericQueryTypes false
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin email>
|
||||
# SocketFile "/var/run/collectd-email"
|
||||
# SocketGroup "collectd"
|
||||
# SocketPerms "0770"
|
||||
# MaxConns 5
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin ethstat>
|
||||
# Interface "eth0"
|
||||
# Map "rx_csum_offload_errors" "if_rx_errors" "checksum_offload"
|
||||
# Map "multicast" "if_multicast"
|
||||
# MappedOnly false
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin exec>
|
||||
# Exec user "/path/to/exec"
|
||||
# Exec "user:group" "/path/to/exec"
|
||||
# NotificationExec user "/path/to/exec"
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin filecount>
|
||||
# <Directory "/path/to/dir">
|
||||
# Instance "foodir"
|
||||
# Name "*.conf"
|
||||
# MTime "-5m"
|
||||
# Size "+10k"
|
||||
# Recursive true
|
||||
# IncludeHidden false
|
||||
# </Directory>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin gmond>
|
||||
# MCReceiveFrom "239.2.11.71" "8649"
|
||||
#
|
||||
# <Metric "swap_total">
|
||||
# Type "swap"
|
||||
# TypeInstance "total"
|
||||
# DataSource "value"
|
||||
# </Metric>
|
||||
#
|
||||
# <Metric "swap_free">
|
||||
# Type "swap"
|
||||
# TypeInstance "free"
|
||||
# DataSource "value"
|
||||
# </Metric>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin hddtemp>
|
||||
# Host "127.0.0.1"
|
||||
# Port 7634
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin interface>
|
||||
# Interface "eth0"
|
||||
# IgnoreSelected false
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin ipmi>
|
||||
# Sensor "some_sensor"
|
||||
# Sensor "another_one"
|
||||
# IgnoreSelected false
|
||||
# NotifySensorAdd false
|
||||
# NotifySensorRemove true
|
||||
# NotifySensorNotPresent false
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin iptables>
|
||||
# Chain "table" "chain"
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin irq>
|
||||
# Irq 7
|
||||
# Irq 8
|
||||
# Irq 9
|
||||
# IgnoreSelected true
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin java>
|
||||
# JVMArg "-verbose:jni"
|
||||
# JVMArg "-Djava.class.path=/usr/share/collectd/java/collectd-api.jar"
|
||||
#
|
||||
# LoadPlugin "org.collectd.java.GenericJMX"
|
||||
# <Plugin "GenericJMX">
|
||||
# # See /usr/share/doc/collectd/examples/GenericJMX.conf
|
||||
# # for an example config.
|
||||
# </Plugin>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin libvirt>
|
||||
# Connection "xen:///"
|
||||
# RefreshInterval 60
|
||||
# Domain "name"
|
||||
# BlockDevice "name:device"
|
||||
# InterfaceDevice "name:device"
|
||||
# IgnoreSelected false
|
||||
# HostnameFormat name
|
||||
# InterfaceFormat name
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin madwifi>
|
||||
# Interface "wlan0"
|
||||
# IgnoreSelected false
|
||||
# Source "SysFS"
|
||||
# WatchSet "None"
|
||||
# WatchAdd "node_octets"
|
||||
# WatchAdd "node_rssi"
|
||||
# WatchAdd "is_rx_acl"
|
||||
# WatchAdd "is_scan_active"
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin mbmon>
|
||||
# Host "127.0.0.1"
|
||||
# Port 411
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin md>
|
||||
# Device "/dev/md0"
|
||||
# IgnoreSelected false
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin memcachec>
|
||||
# <Page "plugin_instance">
|
||||
# Server "localhost"
|
||||
# Key "page_key"
|
||||
# <Match>
|
||||
# Regex "(\\d+) bytes sent"
|
||||
# ExcludeRegex "<lines to be excluded>"
|
||||
# DSType CounterAdd
|
||||
# Type "ipt_octets"
|
||||
# Instance "type_instance"
|
||||
# </Match>
|
||||
# </Page>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin memcached>
|
||||
# Socket "/var/run/memcached.sock"
|
||||
# or:
|
||||
# Host "127.0.0.1"
|
||||
# Port "11211"
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin mysql>
|
||||
# <Database db_name>
|
||||
# Host "database.serv.er"
|
||||
# Port "3306"
|
||||
# User "db_user"
|
||||
# Password "secret"
|
||||
# Database "db_name"
|
||||
# MasterStats true
|
||||
# </Database>
|
||||
#
|
||||
# <Database db_name2>
|
||||
# Host "localhost"
|
||||
# Socket "/var/run/mysql/mysqld.sock"
|
||||
# SlaveStats true
|
||||
# SlaveNotifications true
|
||||
# </Database>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin netlink>
|
||||
# Interface "All"
|
||||
# VerboseInterface "All"
|
||||
# QDisc "eth0" "pfifo_fast-1:0"
|
||||
# Class "ppp0" "htb-1:10"
|
||||
# Filter "ppp0" "u32-1:0"
|
||||
# IgnoreSelected false
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin network>
|
||||
# # client setup:
|
||||
# Server "ff18::efc0:4a42" "25826"
|
||||
# <Server "239.192.74.66" "25826">
|
||||
# SecurityLevel Encrypt
|
||||
# Username "user"
|
||||
# Password "secret"
|
||||
# Interface "eth0"
|
||||
# </Server>
|
||||
# TimeToLive "128"
|
||||
#
|
||||
# # server setup:
|
||||
# Listen "0.0.0.0" "25826"
|
||||
# <Listen "239.192.74.66" "25826">
|
||||
# SecurityLevel Sign
|
||||
# AuthFile "/etc/collectd/passwd"
|
||||
# Interface "eth0"
|
||||
# </Listen>
|
||||
# MaxPacketSize 1024
|
||||
#
|
||||
# # proxy setup (client and server as above):
|
||||
# Forward true
|
||||
#
|
||||
# # statistics about the network plugin itself
|
||||
# ReportStats false
|
||||
#
|
||||
# # "garbage collection"
|
||||
# CacheFlush 1800
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin nginx>
|
||||
# URL "http://localhost/status?auto"
|
||||
# User "www-user"
|
||||
# Password "secret"
|
||||
# VerifyPeer false
|
||||
# VerifyHost false
|
||||
# CACert "/etc/ssl/ca.crt"
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin notify_desktop>
|
||||
# OkayTimeout 1000
|
||||
# WarningTimeout 5000
|
||||
# FailureTimeout 0
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin notify_email>
|
||||
# SMTPServer "localhost"
|
||||
# SMTPPort 25
|
||||
# SMTPUser "my-username"
|
||||
# SMTPPassword "my-password"
|
||||
# From "collectd@main0server.com"
|
||||
# # <WARNING/FAILURE/OK> on <hostname>.
|
||||
# # Beware! Do not use not more than two placeholders (%)!
|
||||
# Subject "[collectd] %s on %s!"
|
||||
# Recipient "email1@domain1.net"
|
||||
# Recipient "email2@domain2.com"
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin ntpd>
|
||||
# Host "localhost"
|
||||
# Port 123
|
||||
# ReverseLookups false
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin nut>
|
||||
# UPS "upsname@hostname:port"
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin olsrd>
|
||||
# Host "127.0.0.1"
|
||||
# Port "2006"
|
||||
# CollectLinks "Summary"
|
||||
# CollectRoutes "Summary"
|
||||
# CollectTopology "Summary"
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin openvpn>
|
||||
# StatusFile "/etc/openvpn/openvpn-status.log"
|
||||
# ImprovedNamingSchema false
|
||||
# CollectCompression true
|
||||
# CollectIndividualUsers true
|
||||
# CollectUserCount false
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin perl>
|
||||
# IncludeDir "/my/include/path"
|
||||
# BaseName "Collectd::Plugins"
|
||||
# EnableDebugger ""
|
||||
# LoadPlugin Monitorus
|
||||
# LoadPlugin OpenVZ
|
||||
#
|
||||
# <Plugin foo>
|
||||
# Foo "Bar"
|
||||
# Qux "Baz"
|
||||
# </Plugin>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin pinba>
|
||||
# Address "::0"
|
||||
# Port "30002"
|
||||
# <View "name">
|
||||
# Host "host name"
|
||||
# Server "server name"
|
||||
# Script "script name"
|
||||
# <View>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin ping>
|
||||
# Host "host.foo.bar"
|
||||
# Host "host.baz.qux"
|
||||
# Interval 1.0
|
||||
# Timeout 0.9
|
||||
# TTL 255
|
||||
# SourceAddress "1.2.3.4"
|
||||
# Device "eth0"
|
||||
# MaxMissed -1
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin postgresql>
|
||||
# <Query magic>
|
||||
# Statement "SELECT magic FROM wizard WHERE host = $1;"
|
||||
# Param hostname
|
||||
#
|
||||
# <Result>
|
||||
# Type gauge
|
||||
# InstancePrefix "magic"
|
||||
# ValuesFrom "magic"
|
||||
# </Result>
|
||||
# </Query>
|
||||
#
|
||||
# <Query rt36_tickets>
|
||||
# Statement "SELECT COUNT(type) AS count, type \
|
||||
# FROM (SELECT CASE \
|
||||
# WHEN resolved = 'epoch' THEN 'open' \
|
||||
# ELSE 'resolved' END AS type \
|
||||
# FROM tickets) type \
|
||||
# GROUP BY type;"
|
||||
#
|
||||
# <Result>
|
||||
# Type counter
|
||||
# InstancePrefix "rt36_tickets"
|
||||
# InstancesFrom "type"
|
||||
# ValuesFrom "count"
|
||||
# </Result>
|
||||
# </Query>
|
||||
#
|
||||
# <Database foo>
|
||||
# Host "hostname"
|
||||
# Port 5432
|
||||
# User "username"
|
||||
# Password "secret"
|
||||
#
|
||||
# SSLMode "prefer"
|
||||
# KRBSrvName "kerberos_service_name"
|
||||
#
|
||||
# Query magic
|
||||
# </Database>
|
||||
#
|
||||
# <Database bar>
|
||||
# Interval 60
|
||||
# Service "service_name"
|
||||
#
|
||||
# Query backend # predefined
|
||||
# Query rt36_tickets
|
||||
# </Database>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin powerdns>
|
||||
# <Server "server_name">
|
||||
# Collect "latency"
|
||||
# Collect "udp-answers" "udp-queries"
|
||||
# Socket "/var/run/pdns.controlsocket"
|
||||
# </Server>
|
||||
# <Recursor "recursor_name">
|
||||
# Collect "questions"
|
||||
# Collect "cache-hits" "cache-misses"
|
||||
# Socket "/var/run/pdns_recursor.controlsocket"
|
||||
# </Recursor>
|
||||
# LocalSocket "/opt/collectd/var/run/collectd-powerdns"
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin processes>
|
||||
# Process "name"
|
||||
# ProcessMatch "foobar" "/usr/bin/perl foobar\\.pl.*"
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin protocols>
|
||||
# Value "/^Tcp:/"
|
||||
# IgnoreSelected false
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin python>
|
||||
# ModulePath "/path/to/your/python/modules"
|
||||
# LogTraces true
|
||||
# Interactive true
|
||||
# Import "spam"
|
||||
#
|
||||
# <Module spam>
|
||||
# spam "wonderful" "lovely"
|
||||
# </Module>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin rrdcached>
|
||||
# DaemonAddress "unix:/var/run/rrdcached.sock"
|
||||
# DataDir "/var/lib/rrdcached/db/collectd"
|
||||
# CreateFiles true
|
||||
# CollectStatistics true
|
||||
#</Plugin>
|
||||
|
||||
<Plugin rrdtool>
|
||||
DataDir "/var/lib/collectd/rrd"
|
||||
# CacheTimeout 120
|
||||
# CacheFlush 900
|
||||
# WritesPerSecond 30
|
||||
# RandomTimeout 0
|
||||
#
|
||||
# The following settings are rather advanced
|
||||
# and should usually not be touched:
|
||||
# StepSize 10
|
||||
# HeartBeat 20
|
||||
# RRARows 1200
|
||||
# RRATimespan 158112000
|
||||
# XFF 0.1
|
||||
</Plugin>
|
||||
|
||||
#<Plugin sensors>
|
||||
# SensorConfigFile "/etc/sensors3.conf"
|
||||
# Sensor "it8712-isa-0290/temperature-temp1"
|
||||
# Sensor "it8712-isa-0290/fanspeed-fan3"
|
||||
# Sensor "it8712-isa-0290/voltage-in8"
|
||||
# IgnoreSelected false
|
||||
#</Plugin>
|
||||
|
||||
# See /usr/share/doc/collectd/examples/snmp-data.conf.gz for a
|
||||
# comprehensive sample configuration.
|
||||
#<Plugin snmp>
|
||||
# <Data "powerplus_voltge_input">
|
||||
# Type "voltage"
|
||||
# Table false
|
||||
# Instance "input_line1"
|
||||
# Scale 0.1
|
||||
# Values "SNMPv2-SMI::enterprises.6050.5.4.1.1.2.1"
|
||||
# </Data>
|
||||
# <Data "hr_users">
|
||||
# Type "users"
|
||||
# Table false
|
||||
# Instance ""
|
||||
# Shift -1
|
||||
# Values "HOST-RESOURCES-MIB::hrSystemNumUsers.0"
|
||||
# </Data>
|
||||
# <Data "std_traffic">
|
||||
# Type "if_octets"
|
||||
# Table true
|
||||
# InstancePrefix "traffic"
|
||||
# Instance "IF-MIB::ifDescr"
|
||||
# Values "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets"
|
||||
# </Data>
|
||||
#
|
||||
# <Host "some.switch.mydomain.org">
|
||||
# Address "192.168.0.2"
|
||||
# Version 1
|
||||
# Community "community_string"
|
||||
# Collect "std_traffic"
|
||||
# Inverval 120
|
||||
# </Host>
|
||||
# <Host "some.server.mydomain.org">
|
||||
# Address "192.168.0.42"
|
||||
# Version 2
|
||||
# Community "another_string"
|
||||
# Collect "std_traffic" "hr_users"
|
||||
# </Host>
|
||||
# <Host "some.ups.mydomain.org">
|
||||
# Address "192.168.0.3"
|
||||
# Version 1
|
||||
# Community "more_communities"
|
||||
# Collect "powerplus_voltge_input"
|
||||
# Interval 300
|
||||
# </Host>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin swap>
|
||||
# ReportByDevice false
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin table>
|
||||
# <Table "/proc/slabinfo">
|
||||
# Instance "slabinfo"
|
||||
# Separator " "
|
||||
# <Result>
|
||||
# Type gauge
|
||||
# InstancePrefix "active_objs"
|
||||
# InstancesFrom 0
|
||||
# ValuesFrom 1
|
||||
# </Result>
|
||||
# <Result>
|
||||
# Type gauge
|
||||
# InstancePrefix "objperslab"
|
||||
# InstancesFrom 0
|
||||
# ValuesFrom 4
|
||||
# </Result>
|
||||
# </Table>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin "tail">
|
||||
# <File "/var/log/exim4/mainlog">
|
||||
# Instance "exim"
|
||||
# <Match>
|
||||
# Regex "S=([1-9][0-9]*)"
|
||||
# DSType "CounterAdd"
|
||||
# Type "ipt_bytes"
|
||||
# Instance "total"
|
||||
# </Match>
|
||||
# <Match>
|
||||
# Regex "\\<R=local_user\\>"
|
||||
# ExcludeRegex "\\<R=local_user\\>.*mail_spool defer"
|
||||
# DSType "CounterInc"
|
||||
# Type "counter"
|
||||
# Instance "local_user"
|
||||
# </Match>
|
||||
# </File>
|
||||
#</Plugin>
|
||||
|
||||
<Plugin tcpconns>
|
||||
LocalPort "4001"
|
||||
LocalPort "7001"
|
||||
</Plugin>
|
||||
|
||||
#<Plugin teamspeak2>
|
||||
# Host "127.0.0.1"
|
||||
# Port "51234"
|
||||
# Server "8767"
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin ted>
|
||||
# Device "/dev/ttyUSB0"
|
||||
# Retries 0
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin thermal>
|
||||
# ForceUseProcfs false
|
||||
# Device "THRM"
|
||||
# IgnoreSelected false
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin tokyotyrant>
|
||||
# Host "localhost"
|
||||
# Port "1978"
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin unixsock>
|
||||
# SocketFile "/var/run/collectd-unixsock"
|
||||
# SocketGroup "collectd"
|
||||
# SocketPerms "0660"
|
||||
# DeleteSocket false
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin uuid>
|
||||
# UUIDFile "/etc/uuid"
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin varnish>
|
||||
# <Instance>
|
||||
# CollectCache true
|
||||
# CollectBackend true
|
||||
# CollectConnections true
|
||||
# CollectSHM true
|
||||
# CollectESI false
|
||||
# CollectFetch false
|
||||
# CollectHCB false
|
||||
# CollectSMA false
|
||||
# CollectSMS false
|
||||
# CollectSM false
|
||||
# CollectTotals false
|
||||
# CollectWorkers false
|
||||
# </Instance>
|
||||
#
|
||||
# <Instance "myinstance">
|
||||
# CollectCache true
|
||||
# </Instance>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin vmem>
|
||||
# Verbose false
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin write_graphite>
|
||||
# <Carbon>
|
||||
# Host "127.0.01"
|
||||
# Port "2003"
|
||||
# Prefix "collectd"
|
||||
# Postfix "collectd"
|
||||
# StoreRates false
|
||||
# AlwaysAppendDS false
|
||||
# EscapeCharacter "_"
|
||||
# </Carbon>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin write_http>
|
||||
# <URL "http://example.com/collectd-post">
|
||||
# User "collectd"
|
||||
# Password "secret"
|
||||
# VerifyPeer true
|
||||
# VerifyHost true
|
||||
# CACert "/etc/ssl/ca.crt"
|
||||
# Format "Command"
|
||||
# StoreRates false
|
||||
# </URL>
|
||||
#</Plugin>
|
||||
|
||||
#<Plugin write_mongodb>
|
||||
# <Node "example">
|
||||
# Host "localhost"
|
||||
# Port "27017"
|
||||
# Timeout 1000
|
||||
# StoreRates false
|
||||
# <Node>
|
||||
#</Plugin>
|
||||
|
||||
Include "/etc/collectd/filters.conf"
|
||||
Include "/etc/collectd/thresholds.conf"
|
31
contrib/graphite/Dockerfile
Normal file
31
contrib/graphite/Dockerfile
Normal file
@ -0,0 +1,31 @@
|
||||
from stackbrew/ubuntu:precise
|
||||
|
||||
run echo 'deb http://us.archive.ubuntu.com/ubuntu/ precise universe' >> /etc/apt/sources.list
|
||||
run apt-get -y update
|
||||
|
||||
# Install required packages
|
||||
run apt-get -y install python-cairo python-django python-twisted python-django-tagging python-simplejson python-pysqlite2 python-support python-pip gunicorn supervisor nginx-light
|
||||
run pip install whisper
|
||||
run pip install --install-option="--prefix=/var/lib/graphite" --install-option="--install-lib=/var/lib/graphite/lib" carbon
|
||||
run pip install --install-option="--prefix=/var/lib/graphite" --install-option="--install-lib=/var/lib/graphite/webapp" graphite-web
|
||||
|
||||
# Add system service config
|
||||
add ./nginx.conf /etc/nginx/nginx.conf
|
||||
add ./supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
|
||||
# Add graphite config
|
||||
add ./initial_data.json /var/lib/graphite/webapp/graphite/initial_data.json
|
||||
add ./local_settings.py /var/lib/graphite/webapp/graphite/local_settings.py
|
||||
add ./carbon.conf /var/lib/graphite/conf/carbon.conf
|
||||
add ./storage-schemas.conf /var/lib/graphite/conf/storage-schemas.conf
|
||||
run mkdir -p /var/lib/graphite/storage/whisper
|
||||
run touch /var/lib/graphite/storage/graphite.db /var/lib/graphite/storage/index
|
||||
run chown -R www-data /var/lib/graphite/storage
|
||||
run chmod 0775 /var/lib/graphite/storage /var/lib/graphite/storage/whisper
|
||||
run chmod 0664 /var/lib/graphite/storage/graphite.db
|
||||
run cd /var/lib/graphite/webapp/graphite && python manage.py syncdb --noinput
|
||||
|
||||
expose :80
|
||||
expose :2003
|
||||
|
||||
cmd ["/usr/bin/supervisord"]
|
7
contrib/graphite/README
Normal file
7
contrib/graphite/README
Normal file
@ -0,0 +1,7 @@
|
||||
Running graphite under Docker is straightforward:
|
||||
|
||||
1. Build the graphite image using Docker
|
||||
docker build -t graphite .
|
||||
|
||||
2. Run a graphite container. Be sure to replace the $IP field with the IP address at which you wish to expose your graphite web service.
|
||||
docker run -p $IP:8080:80 -p $IP:2003:2003 -d graphite
|
62
contrib/graphite/carbon.conf
Normal file
62
contrib/graphite/carbon.conf
Normal file
@ -0,0 +1,62 @@
|
||||
[cache]
|
||||
LOCAL_DATA_DIR = /var/lib/graphite/storage/whisper/
|
||||
|
||||
# Specify the user to drop privileges to
|
||||
# If this is blank carbon runs as the user that invokes it
|
||||
# This user must have write access to the local data directory
|
||||
USER =
|
||||
|
||||
# Limit the size of the cache to avoid swapping or becoming CPU bound.
|
||||
# Sorts and serving cache queries gets more expensive as the cache grows.
|
||||
# Use the value "inf" (infinity) for an unlimited cache size.
|
||||
MAX_CACHE_SIZE = inf
|
||||
|
||||
# Limits the number of whisper update_many() calls per second, which effectively
|
||||
# means the number of write requests sent to the disk. This is intended to
|
||||
# prevent over-utilizing the disk and thus starving the rest of the system.
|
||||
# When the rate of required updates exceeds this, then carbon's caching will
|
||||
# take effect and increase the overall throughput accordingly.
|
||||
MAX_UPDATES_PER_SECOND = 1000
|
||||
|
||||
# Softly limits the number of whisper files that get created each minute.
|
||||
# Setting this value low (like at 50) is a good way to ensure your graphite
|
||||
# system will not be adversely impacted when a bunch of new metrics are
|
||||
# sent to it. The trade off is that it will take much longer for those metrics'
|
||||
# database files to all get created and thus longer until the data becomes usable.
|
||||
# Setting this value high (like "inf" for infinity) will cause graphite to create
|
||||
# the files quickly but at the risk of slowing I/O down considerably for a while.
|
||||
MAX_CREATES_PER_MINUTE = inf
|
||||
|
||||
LINE_RECEIVER_INTERFACE = 0.0.0.0
|
||||
LINE_RECEIVER_PORT = 2003
|
||||
|
||||
#PICKLE_RECEIVER_INTERFACE = 0.0.0.0
|
||||
#PICKLE_RECEIVER_PORT = 2004
|
||||
|
||||
#CACHE_QUERY_INTERFACE = 0.0.0.0
|
||||
#CACHE_QUERY_PORT = 7002
|
||||
|
||||
LOG_UPDATES = False
|
||||
|
||||
# Enable AMQP if you want to receve metrics using an amqp broker
|
||||
# ENABLE_AMQP = False
|
||||
|
||||
# Verbose means a line will be logged for every metric received
|
||||
# useful for testing
|
||||
# AMQP_VERBOSE = False
|
||||
|
||||
# AMQP_HOST = localhost
|
||||
# AMQP_PORT = 5672
|
||||
# AMQP_VHOST = /
|
||||
# AMQP_USER = guest
|
||||
# AMQP_PASSWORD = guest
|
||||
# AMQP_EXCHANGE = graphite
|
||||
|
||||
# Patterns for all of the metrics this machine will store. Read more at
|
||||
# http://en.wikipedia.org/wiki/Advanced_Message_Queuing_Protocol#Bindings
|
||||
#
|
||||
# Example: store all sales, linux servers, and utilization metrics
|
||||
# BIND_PATTERNS = sales.#, servers.linux.#, #.utilization
|
||||
#
|
||||
# Example: store everything
|
||||
# BIND_PATTERNS = #
|
20
contrib/graphite/initial_data.json
Normal file
20
contrib/graphite/initial_data.json
Normal file
@ -0,0 +1,20 @@
|
||||
[
|
||||
{
|
||||
"pk": 1,
|
||||
"model": "auth.user",
|
||||
"fields": {
|
||||
"username": "admin",
|
||||
"first_name": "",
|
||||
"last_name": "",
|
||||
"is_active": true,
|
||||
"is_superuser": true,
|
||||
"is_staff": true,
|
||||
"last_login": "2011-09-20 17:02:14",
|
||||
"groups": [],
|
||||
"user_permissions": [],
|
||||
"password": "sha1$1b11b$edeb0a67a9622f1f2cfeabf9188a711f5ac7d236",
|
||||
"email": "root@example.com",
|
||||
"date_joined": "2011-09-20 17:02:14"
|
||||
}
|
||||
}
|
||||
]
|
1
contrib/graphite/local_settings.py
Normal file
1
contrib/graphite/local_settings.py
Normal file
@ -0,0 +1 @@
|
||||
TIME_ZONE = 'UTC'
|
69
contrib/graphite/nginx.conf
Normal file
69
contrib/graphite/nginx.conf
Normal file
@ -0,0 +1,69 @@
|
||||
daemon off;
|
||||
user www-data;
|
||||
worker_processes 1;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
server_tokens off;
|
||||
|
||||
server_names_hash_bucket_size 32;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
gzip on;
|
||||
gzip_disable "msie6";
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
server_name _;
|
||||
|
||||
open_log_file_cache max=1000 inactive=20s min_uses=2 valid=1m;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8000;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Server $host;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
client_max_body_size 10m;
|
||||
client_body_buffer_size 128k;
|
||||
|
||||
proxy_connect_timeout 90;
|
||||
proxy_send_timeout 90;
|
||||
proxy_read_timeout 90;
|
||||
|
||||
proxy_buffer_size 4k;
|
||||
proxy_buffers 4 32k;
|
||||
proxy_busy_buffers_size 64k;
|
||||
proxy_temp_file_write_size 64k;
|
||||
}
|
||||
|
||||
add_header Access-Control-Allow-Origin "*";
|
||||
add_header Access-Control-Allow-Methods "GET, OPTIONS";
|
||||
add_header Access-Control-Allow-Headers "origin, authorization, accept";
|
||||
|
||||
location /content {
|
||||
alias /var/lib/graphite/webapp/content;
|
||||
}
|
||||
|
||||
location /media {
|
||||
alias /usr/share/pyshared/django/contrib/admin/media;
|
||||
}
|
||||
}
|
||||
}
|
7
contrib/graphite/storage-schemas.conf
Normal file
7
contrib/graphite/storage-schemas.conf
Normal file
@ -0,0 +1,7 @@
|
||||
[carbon]
|
||||
pattern = ^carbon\..*
|
||||
retentions = 1m:31d,10m:1y,1h:5y
|
||||
|
||||
[default]
|
||||
pattern = .*
|
||||
retentions = 10s:8d,1m:31d,10m:1y,1h:5y
|
25
contrib/graphite/supervisord.conf
Normal file
25
contrib/graphite/supervisord.conf
Normal file
@ -0,0 +1,25 @@
|
||||
[supervisord]
|
||||
nodaemon = true
|
||||
environment = GRAPHITE_STORAGE_DIR='/var/lib/graphite/storage',GRAPHITE_CONF_DIR='/var/lib/graphite/conf'
|
||||
|
||||
[program:nginx]
|
||||
command = /usr/sbin/nginx
|
||||
stdout_logfile = /var/log/supervisor/%(program_name)s.log
|
||||
stderr_logfile = /var/log/supervisor/%(program_name)s.log
|
||||
autorestart = true
|
||||
|
||||
[program:carbon-cache]
|
||||
user = www-data
|
||||
command = /var/lib/graphite/bin/carbon-cache.py --debug start
|
||||
stdout_logfile = /var/log/supervisor/%(program_name)s.log
|
||||
stderr_logfile = /var/log/supervisor/%(program_name)s.log
|
||||
autorestart = true
|
||||
|
||||
[program:graphite-webapp]
|
||||
user = www-data
|
||||
directory = /var/lib/graphite/webapp
|
||||
environment = PYTHONPATH='/var/lib/graphite/webapp'
|
||||
command = /usr/bin/gunicorn_django -b127.0.0.1:8000 -w2 graphite/settings.py
|
||||
stdout_logfile = /var/log/supervisor/%(program_name)s.log
|
||||
stderr_logfile = /var/log/supervisor/%(program_name)s.log
|
||||
autorestart = true
|
148
discovery/discovery.go
Normal file
148
discovery/discovery.go
Normal file
@ -0,0 +1,148 @@
|
||||
package discovery
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
etcdErr "github.com/coreos/etcd/error"
|
||||
"github.com/coreos/etcd/log"
|
||||
"github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd"
|
||||
)
|
||||
|
||||
const (
|
||||
stateKey = "_state"
|
||||
startedState = "started"
|
||||
defaultTTL = 604800 // One week TTL
|
||||
)
|
||||
|
||||
type Discoverer struct {
|
||||
client *etcd.Client
|
||||
name string
|
||||
peer string
|
||||
prefix string
|
||||
discoveryURL string
|
||||
}
|
||||
|
||||
var defaultDiscoverer *Discoverer
|
||||
|
||||
func init() {
|
||||
defaultDiscoverer = &Discoverer{}
|
||||
}
|
||||
|
||||
func (d *Discoverer) Do(discoveryURL string, name string, peer string, closeChan <-chan bool, startRoutine func(func())) (peers []string, err error) {
|
||||
d.name = name
|
||||
d.peer = peer
|
||||
d.discoveryURL = discoveryURL
|
||||
|
||||
u, err := url.Parse(discoveryURL)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// prefix is prepended to all keys for this discovery
|
||||
d.prefix = strings.TrimPrefix(u.Path, "/v2/keys/")
|
||||
|
||||
// keep the old path in case we need to set the KeyPrefix below
|
||||
oldPath := u.Path
|
||||
u.Path = ""
|
||||
|
||||
// Connect to a scheme://host not a full URL with path
|
||||
log.Infof("Discovery via %s using prefix %s.", u.String(), d.prefix)
|
||||
d.client = etcd.NewClient([]string{u.String()})
|
||||
|
||||
if !strings.HasPrefix(oldPath, "/v2/keys") {
|
||||
d.client.SetKeyPrefix("")
|
||||
}
|
||||
|
||||
// Register this machine first and announce that we are a member of
|
||||
// this cluster
|
||||
err = d.heartbeat()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Start the very slow heartbeat to the cluster now in anticipation
|
||||
// that everything is going to go alright now
|
||||
startRoutine(func() { d.startHeartbeat(closeChan) })
|
||||
|
||||
// Attempt to take the leadership role, if there is no error we are it!
|
||||
resp, err := d.client.Create(path.Join(d.prefix, stateKey), startedState, 0)
|
||||
|
||||
// Bail out on unexpected errors
|
||||
if err != nil {
|
||||
if clientErr, ok := err.(*etcd.EtcdError); !ok || clientErr.ErrorCode != etcdErr.EcodeNodeExist {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// If we got a response then the CAS was successful, we are leader
|
||||
if resp != nil && resp.Node.Value == startedState {
|
||||
// We are the leader, we have no peers
|
||||
log.Infof("Discovery _state was empty, so this machine is the initial leader.")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Fall through to finding the other discovery peers
|
||||
return d.findPeers()
|
||||
}
|
||||
|
||||
func (d *Discoverer) findPeers() (peers []string, err error) {
|
||||
resp, err := d.client.Get(path.Join(d.prefix), false, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
node := resp.Node
|
||||
|
||||
if node == nil {
|
||||
return nil, fmt.Errorf("%s key doesn't exist.", d.prefix)
|
||||
}
|
||||
|
||||
for _, n := range node.Nodes {
|
||||
// Skip our own entry in the list, there is no point
|
||||
if strings.HasSuffix(n.Key, "/"+d.name) {
|
||||
continue
|
||||
}
|
||||
peers = append(peers, n.Value)
|
||||
}
|
||||
|
||||
if len(peers) == 0 {
|
||||
return nil, errors.New("Discovery found an initialized cluster but no reachable peers are registered.")
|
||||
}
|
||||
|
||||
log.Infof("Discovery found peers %v", peers)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d *Discoverer) startHeartbeat(closeChan <-chan bool) {
|
||||
// In case of errors we should attempt to heartbeat fairly frequently
|
||||
heartbeatInterval := defaultTTL / 8
|
||||
ticker := time.NewTicker(time.Second * time.Duration(heartbeatInterval))
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
err := d.heartbeat()
|
||||
if err != nil {
|
||||
log.Warnf("Discovery heartbeat failed: %v", err)
|
||||
}
|
||||
case <-closeChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Discoverer) heartbeat() error {
|
||||
_, err := d.client.Set(path.Join(d.prefix, d.name), d.peer, defaultTTL)
|
||||
return err
|
||||
}
|
||||
|
||||
func Do(discoveryURL string, name string, peer string, closeChan <-chan bool, startRoutine func(func())) ([]string, error) {
|
||||
return defaultDiscoverer.Do(discoveryURL, name, peer, closeChan, startRoutine)
|
||||
}
|
132
error/error.go
132
error/error.go
@ -1,52 +1,115 @@
|
||||
/*
|
||||
Copyright 2013 CoreOS Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package error
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var errors map[int]string
|
||||
|
||||
const ()
|
||||
|
||||
func init() {
|
||||
errors = make(map[int]string)
|
||||
|
||||
var errors = map[int]string{
|
||||
// command related errors
|
||||
errors[100] = "Key Not Found"
|
||||
errors[101] = "The given PrevValue is not equal to the value of the key"
|
||||
errors[102] = "Not A File"
|
||||
errors[103] = "Reached the max number of machines in the cluster"
|
||||
EcodeKeyNotFound: "Key not found",
|
||||
EcodeTestFailed: "Compare failed", //test and set
|
||||
EcodeNotFile: "Not a file",
|
||||
EcodeNoMorePeer: "Reached the max number of peers in the cluster",
|
||||
EcodeNotDir: "Not a directory",
|
||||
EcodeNodeExist: "Key already exists", // create
|
||||
EcodeRootROnly: "Root is read only",
|
||||
EcodeKeyIsPreserved: "The prefix of given key is a keyword in etcd",
|
||||
EcodeDirNotEmpty: "Directory not empty",
|
||||
EcodeExistingPeerAddr: "Peer address has existed",
|
||||
|
||||
// Post form related errors
|
||||
errors[200] = "Value is Required in POST form"
|
||||
errors[201] = "PrevValue is Required in POST form"
|
||||
errors[202] = "The given TTL in POST form is not a number"
|
||||
errors[203] = "The given index in POST form is not a number"
|
||||
EcodeValueRequired: "Value is Required in POST form",
|
||||
EcodePrevValueRequired: "PrevValue is Required in POST form",
|
||||
EcodeTTLNaN: "The given TTL in POST form is not a number",
|
||||
EcodeIndexNaN: "The given index in POST form is not a number",
|
||||
EcodeValueOrTTLRequired: "Value or TTL is required in POST form",
|
||||
EcodeTimeoutNaN: "The given timeout in POST form is not a number",
|
||||
EcodeNameRequired: "Name is required in POST form",
|
||||
EcodeIndexOrValueRequired: "Index or value is required",
|
||||
EcodeIndexValueMutex: "Index and value cannot both be specified",
|
||||
EcodeInvalidField: "Invalid field",
|
||||
|
||||
// raft related errors
|
||||
errors[300] = "Raft Internal Error"
|
||||
errors[301] = "During Leader Election"
|
||||
|
||||
// keyword
|
||||
errors[400] = "The prefix of the given key is a keyword in etcd"
|
||||
EcodeRaftInternal: "Raft Internal Error",
|
||||
EcodeLeaderElect: "During Leader Election",
|
||||
|
||||
// etcd related errors
|
||||
errors[500] = "watcher is cleared due to etcd recovery"
|
||||
EcodeWatcherCleared: "watcher is cleared due to etcd recovery",
|
||||
EcodeEventIndexCleared: "The event in requested index is outdated and cleared",
|
||||
EcodeStandbyInternal: "Standby Internal Error",
|
||||
EcodeInvalidActiveSize: "Invalid active size",
|
||||
EcodeInvalidRemoveDelay: "Standby remove delay",
|
||||
|
||||
// client related errors
|
||||
EcodeClientInternal: "Client Internal Error",
|
||||
}
|
||||
|
||||
const (
|
||||
EcodeKeyNotFound = 100
|
||||
EcodeTestFailed = 101
|
||||
EcodeNotFile = 102
|
||||
EcodeNoMorePeer = 103
|
||||
EcodeNotDir = 104
|
||||
EcodeNodeExist = 105
|
||||
EcodeKeyIsPreserved = 106
|
||||
EcodeRootROnly = 107
|
||||
EcodeDirNotEmpty = 108
|
||||
EcodeExistingPeerAddr = 109
|
||||
|
||||
EcodeValueRequired = 200
|
||||
EcodePrevValueRequired = 201
|
||||
EcodeTTLNaN = 202
|
||||
EcodeIndexNaN = 203
|
||||
EcodeValueOrTTLRequired = 204
|
||||
EcodeTimeoutNaN = 205
|
||||
EcodeNameRequired = 206
|
||||
EcodeIndexOrValueRequired = 207
|
||||
EcodeIndexValueMutex = 208
|
||||
EcodeInvalidField = 209
|
||||
|
||||
EcodeRaftInternal = 300
|
||||
EcodeLeaderElect = 301
|
||||
|
||||
EcodeWatcherCleared = 400
|
||||
EcodeEventIndexCleared = 401
|
||||
EcodeStandbyInternal = 402
|
||||
EcodeInvalidActiveSize = 403
|
||||
EcodeInvalidRemoveDelay = 404
|
||||
|
||||
EcodeClientInternal = 500
|
||||
)
|
||||
|
||||
type Error struct {
|
||||
ErrorCode int `json:"errorCode"`
|
||||
Message string `json:"message"`
|
||||
Cause string `json:"cause,omitempty"`
|
||||
Index uint64 `json:"index"`
|
||||
}
|
||||
|
||||
func NewError(errorCode int, cause string) Error {
|
||||
return Error{
|
||||
func NewError(errorCode int, cause string, index uint64) *Error {
|
||||
return &Error{
|
||||
ErrorCode: errorCode,
|
||||
Message: errors[errorCode],
|
||||
Cause: cause,
|
||||
Index: index,
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +119,7 @@ func Message(code int) string {
|
||||
|
||||
// Only for error interface
|
||||
func (e Error) Error() string {
|
||||
return e.Message
|
||||
return e.Message + " (" + e.Cause + ")"
|
||||
}
|
||||
|
||||
func (e Error) toJsonString() string {
|
||||
@ -65,10 +128,21 @@ func (e Error) toJsonString() string {
|
||||
}
|
||||
|
||||
func (e Error) Write(w http.ResponseWriter) {
|
||||
// 3xx is reft internal error
|
||||
if e.ErrorCode/100 == 3 {
|
||||
http.Error(w, e.toJsonString(), http.StatusInternalServerError)
|
||||
} else {
|
||||
http.Error(w, e.toJsonString(), http.StatusBadRequest)
|
||||
w.Header().Add("X-Etcd-Index", fmt.Sprint(e.Index))
|
||||
// 3xx is raft internal error
|
||||
status := http.StatusBadRequest
|
||||
switch e.ErrorCode {
|
||||
case EcodeKeyNotFound:
|
||||
status = http.StatusNotFound
|
||||
case EcodeNotFile, EcodeDirNotEmpty:
|
||||
status = http.StatusForbidden
|
||||
case EcodeTestFailed, EcodeNodeExist:
|
||||
status = http.StatusPreconditionFailed
|
||||
default:
|
||||
if e.ErrorCode/100 == 3 {
|
||||
status = http.StatusInternalServerError
|
||||
}
|
||||
}
|
||||
w.WriteHeader(status)
|
||||
fmt.Fprintln(w, e.toJsonString())
|
||||
}
|
||||
|
200
etcd.go
200
etcd.go
@ -1,200 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"flag"
|
||||
"github.com/coreos/etcd/store"
|
||||
"github.com/coreos/go-raft"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Initialization
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
var (
|
||||
verbose bool
|
||||
veryVerbose bool
|
||||
|
||||
machines string
|
||||
machinesFile string
|
||||
|
||||
cluster []string
|
||||
|
||||
argInfo Info
|
||||
dirPath string
|
||||
|
||||
force bool
|
||||
|
||||
maxSize int
|
||||
|
||||
snapshot bool
|
||||
|
||||
retryTimes int
|
||||
|
||||
maxClusterSize int
|
||||
|
||||
cpuprofile string
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.BoolVar(&verbose, "v", false, "verbose logging")
|
||||
flag.BoolVar(&veryVerbose, "vv", false, "very verbose logging")
|
||||
|
||||
flag.StringVar(&machines, "C", "", "the ip address and port of a existing machines in the cluster, sepearate by comma")
|
||||
flag.StringVar(&machinesFile, "CF", "", "the file contains a list of existing machines in the cluster, seperate by comma")
|
||||
|
||||
flag.StringVar(&argInfo.Name, "n", "default-name", "the node name (required)")
|
||||
flag.StringVar(&argInfo.EtcdURL, "c", "127.0.0.1:4001", "the hostname:port for etcd client communication")
|
||||
flag.StringVar(&argInfo.RaftURL, "s", "127.0.0.1:7001", "the hostname:port for raft server communication")
|
||||
flag.StringVar(&argInfo.WebURL, "w", "", "the hostname:port of web interface")
|
||||
|
||||
flag.StringVar(&argInfo.RaftTLS.CAFile, "serverCAFile", "", "the path of the CAFile")
|
||||
flag.StringVar(&argInfo.RaftTLS.CertFile, "serverCert", "", "the cert file of the server")
|
||||
flag.StringVar(&argInfo.RaftTLS.KeyFile, "serverKey", "", "the key file of the server")
|
||||
|
||||
flag.StringVar(&argInfo.EtcdTLS.CAFile, "clientCAFile", "", "the path of the client CAFile")
|
||||
flag.StringVar(&argInfo.EtcdTLS.CertFile, "clientCert", "", "the cert file of the client")
|
||||
flag.StringVar(&argInfo.EtcdTLS.KeyFile, "clientKey", "", "the key file of the client")
|
||||
|
||||
flag.StringVar(&dirPath, "d", ".", "the directory to store log and snapshot")
|
||||
|
||||
flag.BoolVar(&force, "f", false, "force new node configuration if existing is found (WARNING: data loss!)")
|
||||
|
||||
flag.BoolVar(&snapshot, "snapshot", false, "open or close snapshot")
|
||||
|
||||
flag.IntVar(&maxSize, "m", 1024, "the max size of result buffer")
|
||||
|
||||
flag.IntVar(&retryTimes, "r", 3, "the max retry attempts when trying to join a cluster")
|
||||
|
||||
flag.IntVar(&maxClusterSize, "maxsize", 9, "the max size of the cluster")
|
||||
|
||||
flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to file")
|
||||
}
|
||||
|
||||
const (
|
||||
ElectionTimeout = 200 * time.Millisecond
|
||||
HeartbeatTimeout = 50 * time.Millisecond
|
||||
|
||||
// Timeout for internal raft http connection
|
||||
// The original timeout for http is 45 seconds
|
||||
// which is too long for our usage.
|
||||
HTTPTimeout = 10 * time.Second
|
||||
RetryInterval = 10
|
||||
)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Typedefs
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type TLSInfo struct {
|
||||
CertFile string `json:"CertFile"`
|
||||
KeyFile string `json:"KeyFile"`
|
||||
CAFile string `json:"CAFile"`
|
||||
}
|
||||
|
||||
type Info struct {
|
||||
Name string `json:"name"`
|
||||
|
||||
RaftURL string `json:"raftURL"`
|
||||
EtcdURL string `json:"etcdURL"`
|
||||
WebURL string `json:"webURL"`
|
||||
|
||||
RaftTLS TLSInfo `json:"raftTLS"`
|
||||
EtcdTLS TLSInfo `json:"etcdTLS"`
|
||||
}
|
||||
|
||||
type TLSConfig struct {
|
||||
Scheme string
|
||||
Server tls.Config
|
||||
Client tls.Config
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Variables
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
var etcdStore *store.Store
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Functions
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------
|
||||
// Main
|
||||
//--------------------------------------
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
if cpuprofile != "" {
|
||||
runCPUProfile()
|
||||
}
|
||||
|
||||
if veryVerbose {
|
||||
verbose = true
|
||||
raft.SetLogLevel(raft.Debug)
|
||||
}
|
||||
|
||||
if machines != "" {
|
||||
cluster = strings.Split(machines, ",")
|
||||
} else if machinesFile != "" {
|
||||
b, err := ioutil.ReadFile(machinesFile)
|
||||
if err != nil {
|
||||
fatalf("Unable to read the given machines file: %s", err)
|
||||
}
|
||||
cluster = strings.Split(string(b), ",")
|
||||
}
|
||||
|
||||
// Check TLS arguments
|
||||
raftTLSConfig, ok := tlsConfigFromInfo(argInfo.RaftTLS)
|
||||
if !ok {
|
||||
fatal("Please specify cert and key file or cert and key file and CAFile or none of the three")
|
||||
}
|
||||
|
||||
etcdTLSConfig, ok := tlsConfigFromInfo(argInfo.EtcdTLS)
|
||||
if !ok {
|
||||
fatal("Please specify cert and key file or cert and key file and CAFile or none of the three")
|
||||
}
|
||||
|
||||
argInfo.Name = strings.TrimSpace(argInfo.Name)
|
||||
if argInfo.Name == "" {
|
||||
fatal("ERROR: server name required. e.g. '-n=server_name'")
|
||||
}
|
||||
|
||||
// Check host name arguments
|
||||
argInfo.RaftURL = sanitizeURL(argInfo.RaftURL, raftTLSConfig.Scheme)
|
||||
argInfo.EtcdURL = sanitizeURL(argInfo.EtcdURL, etcdTLSConfig.Scheme)
|
||||
argInfo.WebURL = sanitizeURL(argInfo.WebURL, "http")
|
||||
|
||||
// Read server info from file or grab it from user.
|
||||
if err := os.MkdirAll(dirPath, 0744); err != nil {
|
||||
fatalf("Unable to create path: %s", err)
|
||||
}
|
||||
|
||||
info := getInfo(dirPath)
|
||||
|
||||
// Create etcd key-value store
|
||||
etcdStore = store.CreateStore(maxSize)
|
||||
snapConf = newSnapshotConf()
|
||||
|
||||
// Create etcd and raft server
|
||||
e = newEtcdServer(info.Name, info.EtcdURL, &etcdTLSConfig, &info.EtcdTLS)
|
||||
r = newRaftServer(info.Name, info.RaftURL, &raftTLSConfig, &info.RaftTLS)
|
||||
|
||||
startWebInterface()
|
||||
r.ListenAndServe()
|
||||
e.ListenAndServe()
|
||||
|
||||
}
|
416
etcd/etcd.go
Normal file
416
etcd/etcd.go
Normal file
@ -0,0 +1,416 @@
|
||||
/*
|
||||
Copyright 2013 CoreOS Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
goetcd "github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd"
|
||||
golog "github.com/coreos/etcd/third_party/github.com/coreos/go-log/log"
|
||||
"github.com/coreos/etcd/third_party/github.com/goraft/raft"
|
||||
httpclient "github.com/coreos/etcd/third_party/github.com/mreiferson/go-httpclient"
|
||||
|
||||
"github.com/coreos/etcd/config"
|
||||
ehttp "github.com/coreos/etcd/http"
|
||||
"github.com/coreos/etcd/log"
|
||||
"github.com/coreos/etcd/metrics"
|
||||
"github.com/coreos/etcd/server"
|
||||
"github.com/coreos/etcd/store"
|
||||
)
|
||||
|
||||
// TODO(yichengq): constant extraTimeout is a hack.
|
||||
// Current problem is that there is big lag between join command
|
||||
// execution and join success.
|
||||
// Fix it later. It should be removed when proper method is found and
|
||||
// enough tests are provided. It is expected to be calculated from
|
||||
// heartbeatInterval and electionTimeout only.
|
||||
const extraTimeout = time.Duration(1000) * time.Millisecond
|
||||
|
||||
type Etcd struct {
|
||||
Config *config.Config // etcd config
|
||||
|
||||
Store store.Store // data store
|
||||
Registry *server.Registry // stores URL information for nodes
|
||||
Server *server.Server // http server, runs on 4001 by default
|
||||
PeerServer *server.PeerServer // peer server, runs on 7001 by default
|
||||
StandbyServer *server.StandbyServer
|
||||
|
||||
server *http.Server
|
||||
peerServer *http.Server
|
||||
|
||||
mode Mode
|
||||
modeMutex sync.Mutex
|
||||
closeChan chan bool
|
||||
readyNotify chan bool // To signal when server is ready to accept connections
|
||||
onceReady sync.Once
|
||||
stopNotify chan bool // To signal when server is stopped totally
|
||||
}
|
||||
|
||||
// New returns a new Etcd instance.
|
||||
func New(c *config.Config) *Etcd {
|
||||
if c == nil {
|
||||
c = config.New()
|
||||
}
|
||||
return &Etcd{
|
||||
Config: c,
|
||||
closeChan: make(chan bool),
|
||||
readyNotify: make(chan bool),
|
||||
stopNotify: make(chan bool),
|
||||
}
|
||||
}
|
||||
|
||||
// Run the etcd instance.
|
||||
func (e *Etcd) Run() {
|
||||
// Sanitize all the input fields.
|
||||
if err := e.Config.Sanitize(); err != nil {
|
||||
log.Fatalf("failed sanitizing configuration: %v", err)
|
||||
}
|
||||
|
||||
// Force remove server configuration if specified.
|
||||
if e.Config.Force {
|
||||
e.Config.Reset()
|
||||
}
|
||||
|
||||
// Enable options.
|
||||
if e.Config.VeryVeryVerbose {
|
||||
log.Verbose = true
|
||||
raft.SetLogLevel(raft.Trace)
|
||||
goetcd.SetLogger(
|
||||
golog.New(
|
||||
"go-etcd",
|
||||
false,
|
||||
golog.CombinedSink(
|
||||
os.Stdout,
|
||||
"[%s] %s %-9s | %s\n",
|
||||
[]string{"prefix", "time", "priority", "message"},
|
||||
),
|
||||
),
|
||||
)
|
||||
} else if e.Config.VeryVerbose {
|
||||
log.Verbose = true
|
||||
raft.SetLogLevel(raft.Debug)
|
||||
} else if e.Config.Verbose {
|
||||
log.Verbose = true
|
||||
}
|
||||
|
||||
if e.Config.CPUProfileFile != "" {
|
||||
profile(e.Config.CPUProfileFile)
|
||||
}
|
||||
|
||||
if e.Config.DataDir == "" {
|
||||
log.Fatal("The data dir was not set and could not be guessed from machine name")
|
||||
}
|
||||
|
||||
// Create data directory if it doesn't already exist.
|
||||
if err := os.MkdirAll(e.Config.DataDir, 0744); err != nil {
|
||||
log.Fatalf("Unable to create path: %s", err)
|
||||
}
|
||||
|
||||
// Warn people if they have an info file
|
||||
info := filepath.Join(e.Config.DataDir, "info")
|
||||
if _, err := os.Stat(info); err == nil {
|
||||
log.Warnf("All cached configuration is now ignored. The file %s can be removed.", info)
|
||||
}
|
||||
|
||||
var mbName string
|
||||
if e.Config.Trace() {
|
||||
mbName = e.Config.MetricsBucketName()
|
||||
runtime.SetBlockProfileRate(1)
|
||||
}
|
||||
|
||||
mb := metrics.NewBucket(mbName)
|
||||
|
||||
if e.Config.GraphiteHost != "" {
|
||||
err := mb.Publish(e.Config.GraphiteHost)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve CORS configuration
|
||||
corsInfo, err := ehttp.NewCORSInfo(e.Config.CorsOrigins)
|
||||
if err != nil {
|
||||
log.Fatal("CORS:", err)
|
||||
}
|
||||
|
||||
// Create etcd key-value store and registry.
|
||||
e.Store = store.New()
|
||||
e.Registry = server.NewRegistry(e.Store)
|
||||
|
||||
// Create stats objects
|
||||
followersStats := server.NewRaftFollowersStats(e.Config.Name)
|
||||
serverStats := server.NewRaftServerStats(e.Config.Name)
|
||||
|
||||
// Calculate all of our timeouts
|
||||
heartbeatInterval := time.Duration(e.Config.Peer.HeartbeatInterval) * time.Millisecond
|
||||
electionTimeout := time.Duration(e.Config.Peer.ElectionTimeout) * time.Millisecond
|
||||
dialTimeout := (3 * heartbeatInterval) + electionTimeout
|
||||
responseHeaderTimeout := (3 * heartbeatInterval) + electionTimeout
|
||||
|
||||
clientTransporter := &httpclient.Transport{
|
||||
ResponseHeaderTimeout: responseHeaderTimeout + extraTimeout,
|
||||
// This is a workaround for Transport.CancelRequest doesn't work on
|
||||
// HTTPS connections blocked. The patch for it is in progress,
|
||||
// and would be available in Go1.3
|
||||
// More: https://codereview.appspot.com/69280043/
|
||||
ConnectTimeout: dialTimeout + extraTimeout,
|
||||
RequestTimeout: responseHeaderTimeout + dialTimeout + 2*extraTimeout,
|
||||
}
|
||||
if e.Config.PeerTLSInfo().Scheme() == "https" {
|
||||
clientTLSConfig, err := e.Config.PeerTLSInfo().ClientConfig()
|
||||
if err != nil {
|
||||
log.Fatal("client TLS error: ", err)
|
||||
}
|
||||
clientTransporter.TLSClientConfig = clientTLSConfig
|
||||
clientTransporter.DisableCompression = true
|
||||
}
|
||||
client := server.NewClient(clientTransporter)
|
||||
|
||||
// Create peer server
|
||||
psConfig := server.PeerServerConfig{
|
||||
Name: e.Config.Name,
|
||||
Scheme: e.Config.PeerTLSInfo().Scheme(),
|
||||
URL: e.Config.Peer.Addr,
|
||||
SnapshotCount: e.Config.SnapshotCount,
|
||||
RetryTimes: e.Config.MaxRetryAttempts,
|
||||
RetryInterval: e.Config.RetryInterval,
|
||||
}
|
||||
e.PeerServer = server.NewPeerServer(psConfig, client, e.Registry, e.Store, &mb, followersStats, serverStats)
|
||||
|
||||
// Create raft transporter and server
|
||||
raftTransporter := server.NewTransporter(followersStats, serverStats, e.Registry, heartbeatInterval, dialTimeout, responseHeaderTimeout)
|
||||
if e.Config.PeerTLSInfo().Scheme() == "https" {
|
||||
raftClientTLSConfig, err := e.Config.PeerTLSInfo().ClientConfig()
|
||||
if err != nil {
|
||||
log.Fatal("raft client TLS error: ", err)
|
||||
}
|
||||
raftTransporter.SetTLSConfig(*raftClientTLSConfig)
|
||||
}
|
||||
raftServer, err := raft.NewServer(e.Config.Name, e.Config.DataDir, raftTransporter, e.Store, e.PeerServer, "")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
raftServer.SetElectionTimeout(electionTimeout)
|
||||
raftServer.SetHeartbeatInterval(heartbeatInterval)
|
||||
e.PeerServer.SetRaftServer(raftServer, e.Config.Snapshot)
|
||||
|
||||
// Create etcd server
|
||||
e.Server = server.New(e.Config.Name, e.Config.Addr, e.PeerServer, e.Registry, e.Store, &mb)
|
||||
|
||||
if e.Config.Trace() {
|
||||
e.Server.EnableTracing()
|
||||
}
|
||||
|
||||
e.PeerServer.SetServer(e.Server)
|
||||
|
||||
// Create standby server
|
||||
ssConfig := server.StandbyServerConfig{
|
||||
Name: e.Config.Name,
|
||||
PeerScheme: e.Config.PeerTLSInfo().Scheme(),
|
||||
PeerURL: e.Config.Peer.Addr,
|
||||
ClientURL: e.Config.Addr,
|
||||
DataDir: e.Config.DataDir,
|
||||
}
|
||||
e.StandbyServer = server.NewStandbyServer(ssConfig, client)
|
||||
e.StandbyServer.SetRaftServer(raftServer)
|
||||
|
||||
// Generating config could be slow.
|
||||
// Put it here to make listen happen immediately after peer-server starting.
|
||||
peerTLSConfig := server.TLSServerConfig(e.Config.PeerTLSInfo())
|
||||
etcdTLSConfig := server.TLSServerConfig(e.Config.EtcdTLSInfo())
|
||||
|
||||
if !e.StandbyServer.IsRunning() {
|
||||
startPeerServer, possiblePeers, err := e.PeerServer.FindCluster(e.Config.Discovery, e.Config.Peers)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if startPeerServer {
|
||||
e.setMode(PeerMode)
|
||||
} else {
|
||||
e.StandbyServer.SyncCluster(possiblePeers)
|
||||
e.setMode(StandbyMode)
|
||||
}
|
||||
} else {
|
||||
e.setMode(StandbyMode)
|
||||
}
|
||||
|
||||
serverHTTPHandler := &ehttp.CORSHandler{e.Server.HTTPHandler(), corsInfo}
|
||||
peerServerHTTPHandler := &ehttp.CORSHandler{e.PeerServer.HTTPHandler(), corsInfo}
|
||||
standbyServerHTTPHandler := &ehttp.CORSHandler{e.StandbyServer.ClientHTTPHandler(), corsInfo}
|
||||
|
||||
log.Infof("etcd server [name %s, listen on %s, advertised url %s]", e.Server.Name, e.Config.BindAddr, e.Server.URL())
|
||||
listener := server.NewListener(e.Config.EtcdTLSInfo().Scheme(), e.Config.BindAddr, etcdTLSConfig)
|
||||
e.server = &http.Server{Handler: &ModeHandler{e, serverHTTPHandler, standbyServerHTTPHandler}}
|
||||
log.Infof("peer server [name %s, listen on %s, advertised url %s]", e.PeerServer.Config.Name, e.Config.Peer.BindAddr, e.PeerServer.Config.URL)
|
||||
peerListener := server.NewListener(e.Config.PeerTLSInfo().Scheme(), e.Config.Peer.BindAddr, peerTLSConfig)
|
||||
e.peerServer = &http.Server{Handler: &ModeHandler{e, peerServerHTTPHandler, http.NotFoundHandler()}}
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
<-e.readyNotify
|
||||
defer wg.Done()
|
||||
if err := e.server.Serve(listener); err != nil {
|
||||
if !isListenerClosing(err) {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
<-e.readyNotify
|
||||
defer wg.Done()
|
||||
if err := e.peerServer.Serve(peerListener); err != nil {
|
||||
if !isListenerClosing(err) {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
e.runServer()
|
||||
|
||||
listener.Close()
|
||||
peerListener.Close()
|
||||
wg.Wait()
|
||||
log.Infof("etcd instance is stopped [name %s]", e.Config.Name)
|
||||
close(e.stopNotify)
|
||||
}
|
||||
|
||||
func (e *Etcd) runServer() {
|
||||
var removeNotify <-chan bool
|
||||
for {
|
||||
if e.mode == PeerMode {
|
||||
log.Infof("%v starting in peer mode", e.Config.Name)
|
||||
// Starting peer server should be followed close by listening on its port
|
||||
// If not, it may leave many requests unaccepted, or cannot receive heartbeat from the cluster.
|
||||
// One severe problem caused if failing receiving heartbeats is when the second node joins one-node cluster,
|
||||
// the cluster could be out of work as long as the two nodes cannot transfer messages.
|
||||
e.PeerServer.Start(e.Config.Snapshot, e.Config.ClusterConfig())
|
||||
removeNotify = e.PeerServer.RemoveNotify()
|
||||
} else {
|
||||
log.Infof("%v starting in standby mode", e.Config.Name)
|
||||
e.StandbyServer.Start()
|
||||
removeNotify = e.StandbyServer.RemoveNotify()
|
||||
}
|
||||
|
||||
// etcd server is ready to accept connections, notify waiters.
|
||||
e.onceReady.Do(func() { close(e.readyNotify) })
|
||||
|
||||
select {
|
||||
case <-e.closeChan:
|
||||
e.PeerServer.Stop()
|
||||
e.StandbyServer.Stop()
|
||||
return
|
||||
case <-removeNotify:
|
||||
}
|
||||
|
||||
if e.mode == PeerMode {
|
||||
peerURLs := e.Registry.PeerURLs(e.PeerServer.RaftServer().Leader(), e.Config.Name)
|
||||
e.StandbyServer.SyncCluster(peerURLs)
|
||||
e.setMode(StandbyMode)
|
||||
} else {
|
||||
// Create etcd key-value store and registry.
|
||||
e.Store = store.New()
|
||||
e.Registry = server.NewRegistry(e.Store)
|
||||
e.PeerServer.SetStore(e.Store)
|
||||
e.PeerServer.SetRegistry(e.Registry)
|
||||
e.Server.SetStore(e.Store)
|
||||
e.Server.SetRegistry(e.Registry)
|
||||
|
||||
// Generate new peer server here.
|
||||
// TODO(yichengq): raft server cannot be started after stopped.
|
||||
// It should be removed when raft restart is implemented.
|
||||
heartbeatInterval := time.Duration(e.Config.Peer.HeartbeatInterval) * time.Millisecond
|
||||
electionTimeout := time.Duration(e.Config.Peer.ElectionTimeout) * time.Millisecond
|
||||
raftServer, err := raft.NewServer(e.Config.Name, e.Config.DataDir, e.PeerServer.RaftServer().Transporter(), e.Store, e.PeerServer, "")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
raftServer.SetElectionTimeout(electionTimeout)
|
||||
raftServer.SetHeartbeatInterval(heartbeatInterval)
|
||||
e.PeerServer.SetRaftServer(raftServer, e.Config.Snapshot)
|
||||
e.StandbyServer.SetRaftServer(raftServer)
|
||||
|
||||
e.PeerServer.SetJoinIndex(e.StandbyServer.JoinIndex())
|
||||
e.setMode(PeerMode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stop the etcd instance.
|
||||
func (e *Etcd) Stop() {
|
||||
close(e.closeChan)
|
||||
<-e.stopNotify
|
||||
}
|
||||
|
||||
// ReadyNotify returns a channel that is going to be closed
|
||||
// when the etcd instance is ready to accept connections.
|
||||
func (e *Etcd) ReadyNotify() <-chan bool {
|
||||
return e.readyNotify
|
||||
}
|
||||
|
||||
func (e *Etcd) Mode() Mode {
|
||||
e.modeMutex.Lock()
|
||||
defer e.modeMutex.Unlock()
|
||||
return e.mode
|
||||
}
|
||||
|
||||
func (e *Etcd) setMode(m Mode) {
|
||||
e.modeMutex.Lock()
|
||||
defer e.modeMutex.Unlock()
|
||||
e.mode = m
|
||||
}
|
||||
|
||||
func isListenerClosing(err error) bool {
|
||||
// An error string equivalent to net.errClosing for using with
|
||||
// http.Serve() during server shutdown. Need to re-declare
|
||||
// here because it is not exported by "net" package.
|
||||
const errClosing = "use of closed network connection"
|
||||
|
||||
return strings.Contains(err.Error(), errClosing)
|
||||
}
|
||||
|
||||
type ModeGetter interface {
|
||||
Mode() Mode
|
||||
}
|
||||
|
||||
type ModeHandler struct {
|
||||
ModeGetter
|
||||
PeerModeHandler http.Handler
|
||||
StandbyModeHandler http.Handler
|
||||
}
|
||||
|
||||
func (h *ModeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
switch h.Mode() {
|
||||
case PeerMode:
|
||||
h.PeerModeHandler.ServeHTTP(w, r)
|
||||
case StandbyMode:
|
||||
h.StandbyModeHandler.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
type Mode int
|
||||
|
||||
const (
|
||||
PeerMode Mode = iota
|
||||
StandbyMode
|
||||
)
|
41
etcd/etcd_test.go
Normal file
41
etcd/etcd_test.go
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright 2013 CoreOS Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/etcd/config"
|
||||
)
|
||||
|
||||
func TestRunStop(t *testing.T) {
|
||||
path, _ := ioutil.TempDir("", "etcd-")
|
||||
defer os.RemoveAll(path)
|
||||
|
||||
config := config.New()
|
||||
config.Name = "ETCDTEST"
|
||||
config.DataDir = path
|
||||
config.Addr = "localhost:0"
|
||||
config.Peer.Addr = "localhost:0"
|
||||
|
||||
etcd := New(config)
|
||||
go etcd.Run()
|
||||
<-etcd.ReadyNotify()
|
||||
etcd.Stop()
|
||||
}
|
27
etcd/profile.go
Normal file
27
etcd/profile.go
Normal file
@ -0,0 +1,27 @@
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime/pprof"
|
||||
|
||||
"github.com/coreos/etcd/log"
|
||||
)
|
||||
|
||||
// profile starts CPU profiling.
|
||||
func profile(path string) {
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
pprof.StartCPUProfile(f)
|
||||
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
go func() {
|
||||
sig := <-c
|
||||
log.Infof("captured %v, stopping profiler and exiting..", sig)
|
||||
pprof.StopCPUProfile()
|
||||
os.Exit(1)
|
||||
}()
|
||||
}
|
288
etcd_handlers.go
288
etcd_handlers.go
@ -1,288 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
etcdErr "github.com/coreos/etcd/error"
|
||||
"github.com/coreos/etcd/store"
|
||||
"github.com/coreos/go-raft"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Handlers to handle etcd-store related request via etcd url
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
func NewEtcdMuxer() *http.ServeMux {
|
||||
// external commands
|
||||
etcdMux := http.NewServeMux()
|
||||
etcdMux.Handle("/"+version+"/keys/", errorHandler(Multiplexer))
|
||||
etcdMux.Handle("/"+version+"/watch/", errorHandler(WatchHttpHandler))
|
||||
etcdMux.Handle("/"+version+"/leader", errorHandler(LeaderHttpHandler))
|
||||
etcdMux.Handle("/"+version+"/machines", errorHandler(MachinesHttpHandler))
|
||||
etcdMux.Handle("/"+version+"/stats", errorHandler(StatsHttpHandler))
|
||||
etcdMux.Handle("/version", errorHandler(VersionHttpHandler))
|
||||
etcdMux.HandleFunc("/test/", TestHttpHandler)
|
||||
return etcdMux
|
||||
}
|
||||
|
||||
type errorHandler func(http.ResponseWriter, *http.Request) error
|
||||
|
||||
func (fn errorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if e := fn(w, r); e != nil {
|
||||
if etcdErr, ok := e.(etcdErr.Error); ok {
|
||||
debug("Return error: ", etcdErr.Error())
|
||||
etcdErr.Write(w)
|
||||
} else {
|
||||
http.Error(w, e.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Multiplex GET/POST/DELETE request to corresponding handlers
|
||||
func Multiplexer(w http.ResponseWriter, req *http.Request) error {
|
||||
|
||||
switch req.Method {
|
||||
case "GET":
|
||||
return GetHttpHandler(w, req)
|
||||
case "POST":
|
||||
return SetHttpHandler(w, req)
|
||||
case "DELETE":
|
||||
return DeleteHttpHandler(w, req)
|
||||
default:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
// State sensitive handlers
|
||||
// Set/Delete will dispatch to leader
|
||||
//--------------------------------------
|
||||
|
||||
// Set Command Handler
|
||||
func SetHttpHandler(w http.ResponseWriter, req *http.Request) error {
|
||||
key := req.URL.Path[len("/v1/keys/"):]
|
||||
|
||||
if store.CheckKeyword(key) {
|
||||
return etcdErr.NewError(400, "Set")
|
||||
}
|
||||
|
||||
debugf("[recv] POST %v/v1/keys/%s [%s]", e.url, key, req.RemoteAddr)
|
||||
|
||||
value := req.FormValue("value")
|
||||
|
||||
if len(value) == 0 {
|
||||
return etcdErr.NewError(200, "Set")
|
||||
}
|
||||
|
||||
prevValue := req.FormValue("prevValue")
|
||||
|
||||
strDuration := req.FormValue("ttl")
|
||||
|
||||
expireTime, err := durationToExpireTime(strDuration)
|
||||
|
||||
if err != nil {
|
||||
return etcdErr.NewError(202, "Set")
|
||||
}
|
||||
|
||||
if len(prevValue) != 0 {
|
||||
command := &TestAndSetCommand{
|
||||
Key: key,
|
||||
Value: value,
|
||||
PrevValue: prevValue,
|
||||
ExpireTime: expireTime,
|
||||
}
|
||||
|
||||
return dispatch(command, w, req, true)
|
||||
|
||||
} else {
|
||||
command := &SetCommand{
|
||||
Key: key,
|
||||
Value: value,
|
||||
ExpireTime: expireTime,
|
||||
}
|
||||
|
||||
return dispatch(command, w, req, true)
|
||||
}
|
||||
}
|
||||
|
||||
// Delete Handler
|
||||
func DeleteHttpHandler(w http.ResponseWriter, req *http.Request) error {
|
||||
key := req.URL.Path[len("/v1/keys/"):]
|
||||
|
||||
debugf("[recv] DELETE %v/v1/keys/%s [%s]", e.url, key, req.RemoteAddr)
|
||||
|
||||
command := &DeleteCommand{
|
||||
Key: key,
|
||||
}
|
||||
|
||||
return dispatch(command, w, req, true)
|
||||
}
|
||||
|
||||
// Dispatch the command to leader
|
||||
func dispatch(c Command, w http.ResponseWriter, req *http.Request, etcd bool) error {
|
||||
|
||||
if r.State() == raft.Leader {
|
||||
if body, err := r.Do(c); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if body == nil {
|
||||
return etcdErr.NewError(300, "Empty result from raft")
|
||||
} else {
|
||||
body, _ := body.([]byte)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(body)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
leader := r.Leader()
|
||||
// current no leader
|
||||
if leader == "" {
|
||||
return etcdErr.NewError(300, "")
|
||||
}
|
||||
|
||||
// tell the client where is the leader
|
||||
path := req.URL.Path
|
||||
|
||||
var url string
|
||||
|
||||
if etcd {
|
||||
etcdAddr, _ := nameToEtcdURL(leader)
|
||||
url = etcdAddr + path
|
||||
} else {
|
||||
raftAddr, _ := nameToRaftURL(leader)
|
||||
url = raftAddr + path
|
||||
}
|
||||
|
||||
debugf("Redirect to %s", url)
|
||||
|
||||
http.Redirect(w, req, url, http.StatusTemporaryRedirect)
|
||||
return nil
|
||||
}
|
||||
return etcdErr.NewError(300, "")
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
// State non-sensitive handlers
|
||||
// will not dispatch to leader
|
||||
// TODO: add sensitive version for these
|
||||
// command?
|
||||
//--------------------------------------
|
||||
|
||||
// Handler to return the current leader's raft address
|
||||
func LeaderHttpHandler(w http.ResponseWriter, req *http.Request) error {
|
||||
leader := r.Leader()
|
||||
|
||||
if leader != "" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
raftURL, _ := nameToRaftURL(leader)
|
||||
w.Write([]byte(raftURL))
|
||||
return nil
|
||||
} else {
|
||||
return etcdErr.NewError(301, "")
|
||||
}
|
||||
}
|
||||
|
||||
// Handler to return all the known machines in the current cluster
|
||||
func MachinesHttpHandler(w http.ResponseWriter, req *http.Request) error {
|
||||
machines := getMachines()
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(strings.Join(machines, ", ")))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handler to return the current version of etcd
|
||||
func VersionHttpHandler(w http.ResponseWriter, req *http.Request) error {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintf(w, "etcd %s", releaseVersion)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handler to return the basic stats of etcd
|
||||
func StatsHttpHandler(w http.ResponseWriter, req *http.Request) error {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(etcdStore.Stats())
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get Handler
|
||||
func GetHttpHandler(w http.ResponseWriter, req *http.Request) error {
|
||||
key := req.URL.Path[len("/v1/keys/"):]
|
||||
|
||||
debugf("[recv] GET %s/v1/keys/%s [%s]", e.url, key, req.RemoteAddr)
|
||||
|
||||
command := &GetCommand{
|
||||
Key: key,
|
||||
}
|
||||
|
||||
if body, err := command.Apply(r.Server); err != nil {
|
||||
return err
|
||||
} else {
|
||||
body, _ := body.([]byte)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(body)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Watch handler
|
||||
func WatchHttpHandler(w http.ResponseWriter, req *http.Request) error {
|
||||
key := req.URL.Path[len("/v1/watch/"):]
|
||||
|
||||
command := &WatchCommand{
|
||||
Key: key,
|
||||
}
|
||||
|
||||
if req.Method == "GET" {
|
||||
debugf("[recv] GET %s/watch/%s [%s]", e.url, key, req.RemoteAddr)
|
||||
command.SinceIndex = 0
|
||||
|
||||
} else if req.Method == "POST" {
|
||||
// watch from a specific index
|
||||
|
||||
debugf("[recv] POST %s/watch/%s [%s]", e.url, key, req.RemoteAddr)
|
||||
content := req.FormValue("index")
|
||||
|
||||
sinceIndex, err := strconv.ParseUint(string(content), 10, 64)
|
||||
if err != nil {
|
||||
return etcdErr.NewError(203, "Watch From Index")
|
||||
}
|
||||
command.SinceIndex = sinceIndex
|
||||
|
||||
} else {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return nil
|
||||
}
|
||||
|
||||
if body, err := command.Apply(r.Server); err != nil {
|
||||
return etcdErr.NewError(500, key)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
body, _ := body.([]byte)
|
||||
w.Write(body)
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TestHandler
|
||||
func TestHttpHandler(w http.ResponseWriter, req *http.Request) {
|
||||
testType := req.URL.Path[len("/test/"):]
|
||||
|
||||
if testType == "speed" {
|
||||
directSet()
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("speed test success"))
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type etcdServer struct {
|
||||
http.Server
|
||||
name string
|
||||
url string
|
||||
tlsConf *TLSConfig
|
||||
tlsInfo *TLSInfo
|
||||
}
|
||||
|
||||
var e *etcdServer
|
||||
|
||||
func newEtcdServer(name string, urlStr string, tlsConf *TLSConfig, tlsInfo *TLSInfo) *etcdServer {
|
||||
u, err := url.Parse(urlStr)
|
||||
|
||||
if err != nil {
|
||||
fatalf("invalid url '%s': %s", e.url, err)
|
||||
}
|
||||
|
||||
return &etcdServer{
|
||||
Server: http.Server{
|
||||
Handler: NewEtcdMuxer(),
|
||||
TLSConfig: &tlsConf.Server,
|
||||
Addr: u.Host,
|
||||
},
|
||||
name: name,
|
||||
url: urlStr,
|
||||
tlsConf: tlsConf,
|
||||
tlsInfo: tlsInfo,
|
||||
}
|
||||
}
|
||||
|
||||
// Start to listen and response etcd client command
|
||||
func (e *etcdServer) ListenAndServe() {
|
||||
|
||||
infof("etcd server [%s:%s]", e.name, e.url)
|
||||
|
||||
if e.tlsConf.Scheme == "http" {
|
||||
fatal(e.Server.ListenAndServe())
|
||||
} else {
|
||||
fatal(e.Server.ListenAndServeTLS(e.tlsInfo.CertFile, e.tlsInfo.KeyFile))
|
||||
}
|
||||
}
|
409
etcd_test.go
409
etcd_test.go
@ -1,409 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/coreos/etcd/test"
|
||||
"github.com/coreos/go-etcd/etcd"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Create a single node and try to set value
|
||||
func TestSingleNode(t *testing.T) {
|
||||
procAttr := new(os.ProcAttr)
|
||||
procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
|
||||
args := []string{"etcd", "-n=node1", "-f", "-d=/tmp/node1"}
|
||||
|
||||
process, err := os.StartProcess("etcd", args, procAttr)
|
||||
if err != nil {
|
||||
t.Fatal("start process failed:" + err.Error())
|
||||
return
|
||||
}
|
||||
defer process.Kill()
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
c := etcd.NewClient()
|
||||
|
||||
c.SyncCluster()
|
||||
// Test Set
|
||||
result, err := c.Set("foo", "bar", 100)
|
||||
|
||||
if err != nil || result.Key != "/foo" || result.Value != "bar" || result.TTL < 95 {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Fatalf("Set 1 failed with %s %s %v", result.Key, result.Value, result.TTL)
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
result, err = c.Set("foo", "bar", 100)
|
||||
|
||||
if err != nil || result.Key != "/foo" || result.Value != "bar" || result.PrevValue != "bar" || result.TTL != 99 {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Fatalf("Set 2 failed with %s %s %v", result.Key, result.Value, result.TTL)
|
||||
}
|
||||
}
|
||||
|
||||
// TestInternalVersionFail will ensure that etcd does not come up if the internal raft
|
||||
// versions do not match.
|
||||
func TestInternalVersionFail(t *testing.T) {
|
||||
checkedVersion := false
|
||||
testMux := http.NewServeMux()
|
||||
|
||||
testMux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, "This is not a version number")
|
||||
checkedVersion = true
|
||||
})
|
||||
|
||||
testMux.HandleFunc("/join", func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Fatal("should not attempt to join!")
|
||||
})
|
||||
|
||||
ts := httptest.NewServer(testMux)
|
||||
defer ts.Close()
|
||||
|
||||
fakeURL, _ := url.Parse(ts.URL)
|
||||
|
||||
procAttr := new(os.ProcAttr)
|
||||
procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
|
||||
args := []string{"etcd", "-n=node1", "-f", "-d=/tmp/node1", "-vv", "-C="+fakeURL.Host}
|
||||
|
||||
process, err := os.StartProcess("etcd", args, procAttr)
|
||||
if err != nil {
|
||||
t.Fatal("start process failed:" + err.Error())
|
||||
return
|
||||
}
|
||||
defer process.Kill()
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
_, err = http.Get("http://127.0.0.1:4001")
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("etcd node should not be up")
|
||||
return
|
||||
}
|
||||
|
||||
if checkedVersion == false {
|
||||
t.Fatal("etcd did not check the version")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This test creates a single node and then set a value to it.
|
||||
// Then this test kills the node and restart it and tries to get the value again.
|
||||
func TestSingleNodeRecovery(t *testing.T) {
|
||||
procAttr := new(os.ProcAttr)
|
||||
procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
|
||||
args := []string{"etcd", "-n=node1", "-d=/tmp/node1"}
|
||||
|
||||
process, err := os.StartProcess("etcd", append(args, "-f"), procAttr)
|
||||
if err != nil {
|
||||
t.Fatal("start process failed:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
c := etcd.NewClient()
|
||||
|
||||
c.SyncCluster()
|
||||
// Test Set
|
||||
result, err := c.Set("foo", "bar", 100)
|
||||
|
||||
if err != nil || result.Key != "/foo" || result.Value != "bar" || result.TTL < 95 {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Fatalf("Set 1 failed with %s %s %v", result.Key, result.Value, result.TTL)
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
process.Kill()
|
||||
|
||||
process, err = os.StartProcess("etcd", args, procAttr)
|
||||
defer process.Kill()
|
||||
if err != nil {
|
||||
t.Fatal("start process failed:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
results, err := c.Get("foo")
|
||||
if err != nil {
|
||||
t.Fatal("get fail: " + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
result = results[0]
|
||||
|
||||
if err != nil || result.Key != "/foo" || result.Value != "bar" || result.TTL > 99 {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Fatalf("Recovery Get failed with %s %s %v", result.Key, result.Value, result.TTL)
|
||||
}
|
||||
}
|
||||
|
||||
// Create a three nodes and try to set value
|
||||
func templateTestSimpleMultiNode(t *testing.T, tls bool) {
|
||||
procAttr := new(os.ProcAttr)
|
||||
procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
|
||||
|
||||
clusterSize := 3
|
||||
|
||||
_, etcds, err := test.CreateCluster(clusterSize, procAttr, tls)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("cannot create cluster")
|
||||
}
|
||||
|
||||
defer test.DestroyCluster(etcds)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
c := etcd.NewClient()
|
||||
|
||||
c.SyncCluster()
|
||||
|
||||
// Test Set
|
||||
result, err := c.Set("foo", "bar", 100)
|
||||
|
||||
if err != nil || result.Key != "/foo" || result.Value != "bar" || result.TTL < 95 {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Fatalf("Set 1 failed with %s %s %v", result.Key, result.Value, result.TTL)
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
result, err = c.Set("foo", "bar", 100)
|
||||
|
||||
if err != nil || result.Key != "/foo" || result.Value != "bar" || result.PrevValue != "bar" || result.TTL != 99 {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Fatalf("Set 2 failed with %s %s %v", result.Key, result.Value, result.TTL)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSimpleMultiNode(t *testing.T) {
|
||||
templateTestSimpleMultiNode(t, false)
|
||||
}
|
||||
|
||||
func TestSimpleMultiNodeTls(t *testing.T) {
|
||||
templateTestSimpleMultiNode(t, true)
|
||||
}
|
||||
|
||||
// Create a five nodes
|
||||
// Randomly kill one of the node and keep on sending set command to the cluster
|
||||
func TestMultiNodeRecovery(t *testing.T) {
|
||||
procAttr := new(os.ProcAttr)
|
||||
procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
|
||||
|
||||
clusterSize := 5
|
||||
argGroup, etcds, err := test.CreateCluster(clusterSize, procAttr, false)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("cannot create cluster")
|
||||
}
|
||||
|
||||
defer test.DestroyCluster(etcds)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
c := etcd.NewClient()
|
||||
|
||||
c.SyncCluster()
|
||||
|
||||
stop := make(chan bool)
|
||||
// Test Set
|
||||
go test.Set(stop)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
num := rand.Int() % clusterSize
|
||||
fmt.Println("kill node", num+1)
|
||||
|
||||
// kill
|
||||
etcds[num].Kill()
|
||||
etcds[num].Release()
|
||||
time.Sleep(time.Second)
|
||||
|
||||
// restart
|
||||
etcds[num], err = os.StartProcess("etcd", argGroup[num], procAttr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
fmt.Println("stop")
|
||||
stop <- true
|
||||
<-stop
|
||||
}
|
||||
|
||||
// This test will kill the current leader and wait for the etcd cluster to elect a new leader for 200 times.
|
||||
// It will print out the election time and the average election time.
|
||||
func TestKillLeader(t *testing.T) {
|
||||
procAttr := new(os.ProcAttr)
|
||||
procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
|
||||
|
||||
clusterSize := 5
|
||||
argGroup, etcds, err := test.CreateCluster(clusterSize, procAttr, false)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("cannot create cluster")
|
||||
}
|
||||
|
||||
defer test.DestroyCluster(etcds)
|
||||
|
||||
stop := make(chan bool)
|
||||
leaderChan := make(chan string, 1)
|
||||
all := make(chan bool, 1)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
go test.Monitor(clusterSize, 1, leaderChan, all, stop)
|
||||
|
||||
var totalTime time.Duration
|
||||
|
||||
leader := "http://127.0.0.1:7001"
|
||||
|
||||
for i := 0; i < clusterSize; i++ {
|
||||
fmt.Println("leader is ", leader)
|
||||
port, _ := strconv.Atoi(strings.Split(leader, ":")[2])
|
||||
num := port - 7001
|
||||
fmt.Println("kill server ", num)
|
||||
etcds[num].Kill()
|
||||
etcds[num].Release()
|
||||
|
||||
start := time.Now()
|
||||
for {
|
||||
newLeader := <-leaderChan
|
||||
if newLeader != leader {
|
||||
leader = newLeader
|
||||
break
|
||||
}
|
||||
}
|
||||
take := time.Now().Sub(start)
|
||||
|
||||
totalTime += take
|
||||
avgTime := totalTime / (time.Duration)(i+1)
|
||||
|
||||
fmt.Println("Leader election time is ", take, "with election timeout", ElectionTimeout)
|
||||
fmt.Println("Leader election time average is", avgTime, "with election timeout", ElectionTimeout)
|
||||
etcds[num], err = os.StartProcess("etcd", argGroup[num], procAttr)
|
||||
}
|
||||
stop <- true
|
||||
}
|
||||
|
||||
// TestKillRandom kills random machines in the cluster and
|
||||
// restart them after all other machines agree on the same leader
|
||||
func TestKillRandom(t *testing.T) {
|
||||
procAttr := new(os.ProcAttr)
|
||||
procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
|
||||
|
||||
clusterSize := 9
|
||||
argGroup, etcds, err := test.CreateCluster(clusterSize, procAttr, false)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("cannot create cluster")
|
||||
}
|
||||
|
||||
defer test.DestroyCluster(etcds)
|
||||
|
||||
stop := make(chan bool)
|
||||
leaderChan := make(chan string, 1)
|
||||
all := make(chan bool, 1)
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
go test.Monitor(clusterSize, 4, leaderChan, all, stop)
|
||||
|
||||
toKill := make(map[int]bool)
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
fmt.Printf("TestKillRandom Round[%d/20]\n", i)
|
||||
|
||||
j := 0
|
||||
for {
|
||||
|
||||
r := rand.Int31n(9)
|
||||
if _, ok := toKill[int(r)]; !ok {
|
||||
j++
|
||||
toKill[int(r)] = true
|
||||
}
|
||||
|
||||
if j > 3 {
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for num, _ := range toKill {
|
||||
err := etcds[num].Kill()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
etcds[num].Wait()
|
||||
}
|
||||
|
||||
time.Sleep(ElectionTimeout)
|
||||
|
||||
<-leaderChan
|
||||
|
||||
for num, _ := range toKill {
|
||||
etcds[num], err = os.StartProcess("etcd", argGroup[num], procAttr)
|
||||
}
|
||||
|
||||
toKill = make(map[int]bool)
|
||||
<-all
|
||||
}
|
||||
|
||||
stop <- true
|
||||
}
|
||||
|
||||
func templateBenchmarkEtcdDirectCall(b *testing.B, tls bool) {
|
||||
procAttr := new(os.ProcAttr)
|
||||
procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
|
||||
|
||||
clusterSize := 3
|
||||
_, etcds, _ := test.CreateCluster(clusterSize, procAttr, tls)
|
||||
|
||||
defer test.DestroyCluster(etcds)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
resp, _ := http.Get("http://127.0.0.1:4001/test/speed")
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func BenchmarkEtcdDirectCall(b *testing.B) {
|
||||
templateBenchmarkEtcdDirectCall(b, false)
|
||||
}
|
||||
|
||||
func BenchmarkEtcdDirectCallTls(b *testing.B) {
|
||||
templateBenchmarkEtcdDirectCall(b, true)
|
||||
}
|
@ -1,18 +1,13 @@
|
||||
Testing x509 certs for luacrypto
|
||||
The steps to regenerate this CA:
|
||||
|
||||
# Make the CA cert
|
||||
openssl genrsa -des3 -out ca.key 4096
|
||||
openssl req -new -x509 -days 365 -key ca.key -out ca.crt -extfile openssl.cnf -extensions v3_ca
|
||||
1. Get etcd-ca source code and generate binary.
|
||||
|
||||
# Make server cert and signing request
|
||||
openssl genrsa -des3 -out server.key 4096
|
||||
openssl req -new -key server.key -out server.csr -config openssl.cnf
|
||||
$ go get github.com/coreos/etcd-ca
|
||||
|
||||
# Sign the server csr and generate a crt
|
||||
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt -extfile openssl.cnf -extensions v3_req
|
||||
2. Run generate_testing_certs.sh with etcd-ca binary location.
|
||||
|
||||
# Output unencrypted server key
|
||||
openssl rsa -in server.key -out server.key.insecure
|
||||
$ ./generate_testing_certs.sh
|
||||
|
||||
# Output "raw" public key from server crt
|
||||
openssl x509 -pubkey -noout -in server.crt > server.pub
|
||||
Details about generation are in the generate_testing_certs.sh script.
|
||||
|
||||
3. Check current directory to see regenerated files.
|
||||
|
@ -1,21 +0,0 @@
|
||||
## Testing x509 certs for luvit
|
||||
|
||||
# Make the CA cert
|
||||
openssl genrsa -out ca.key 4096
|
||||
openssl req -new -x509 -days 365 -key ca.key -out ca.crt
|
||||
|
||||
# Make server cert and signing request
|
||||
openssl genrsa -out server.key 4096
|
||||
openssl req -new -key server.key -out server.csr
|
||||
|
||||
# Sign the server csr and generate a crt
|
||||
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
|
||||
|
||||
# Output unencrypted server key
|
||||
openssl rsa -in server.key -out server.key.insecure
|
||||
|
||||
# Output "raw" public key from server crt
|
||||
openssl x509 -pubkey -noout -in server.crt > server.pub
|
||||
|
||||
# Sign the public key with the key (just for testing signatures)
|
||||
openssl dgst -sign server.key.insecure -sha256 server.pub > server.pub.sig
|
@ -1,33 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFtTCCA52gAwIBAgIJANfWYo0ePBBqMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
|
||||
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
|
||||
aWRnaXRzIFB0eSBMdGQwHhcNMTIwMzE1MjMxMzMwWhcNMTMwMzE1MjMxMzMwWjBF
|
||||
MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
|
||||
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
|
||||
CgKCAgEAyzBV/DH0PWmPxdnr3BTogxPYKVJQ4OQjiiALRRtYPjvQYKPWWsbt4Zlw
|
||||
kfYsc6ihIKUL1tGEnjD6YDTtTwWH7DXeq0mWebFr3kQg/ssoTM5oHN9VglwPMRnx
|
||||
7qqbBG0/LO/K2Go/UMFGmWHiRYRWcOYegq6DXJpj1sRJz8o3uk4Fxz/xr1sjng1l
|
||||
EfAfE4segFLRhmXy1e6Ooy2U5WcpDeKGrD1O01DKsYdR+RavcgkmFYfZ5rdtaKrE
|
||||
wpYLylJNmOAkss7w5tOyEEDLoZHtkRFX5Ss38wuU2h9Li8P9vhyL4Ylzcuy/pBXW
|
||||
MA89D8bBXjR3G4Hk7qX7gqlI9GdRXtPqnRpgEy/vw/+6aJVfNJtLIRdabSr3vStL
|
||||
rhF1y4ocr8OJdNjHGp8tssc9I0LhhItT7bWgjQLHTRezVXV5kzpggAlDCQc48bdc
|
||||
aYjBoLuu8jH9mgGCnPtrJMyV+T96rV5V4XJieA9k4IQ3nWJk1Nslqm5S/FSQbM32
|
||||
+ineL0ZlT/x8qXNnL3FHQFDOKCng3Ww6wC7M9BDf9+Di04lNtd37pri/i5dcvsn1
|
||||
WaYzvHpSGom234Bl4NQSoupKlEhfgTc5w/uuhbGSWcsH+wB4Yi7dg5U7voNkwtVo
|
||||
loEaZ58ldd4Dkz16lZSSg4wzwDbMQWpGCPRAfVDAVk/AxpfOiOsCAwEAAaOBpzCB
|
||||
pDAdBgNVHQ4EFgQUpahFGYUWGD8RygULRRlo6TlAkxowdQYDVR0jBG4wbIAUpahF
|
||||
GYUWGD8RygULRRlo6TlAkxqhSaRHMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpT
|
||||
b21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGSCCQDX
|
||||
1mKNHjwQajAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQAvdXT3GIjK
|
||||
diHYGurJKSGhja8nVcZ9vm0SICyMQU3nOaMhNdrFXUP21dqO1xP+uqgc7vHGOyPg
|
||||
MNLvamCY7JtmcLEgByG5Z+aeNESdwGjP4Rl4YRB83JUyOHke0cONiJXYTjGwF7FL
|
||||
vCXjJm/3t5rTj+gPPMkcN3FtYpiVUn2Ra5LURCiRucsqnStEKiLeIM3WluKOFssZ
|
||||
AHGkUEGXpYyuobdBvejCqdc02+ywyqGuV05mOHB7dDAt0eS0tUqaEyoKlWgIuVlN
|
||||
770LJGjQkQqa0oYwrbsgKuPjH4zu7MDjzooZsYkEpgPCaK64HQ03mdWYWiqW3KY5
|
||||
JxT4TdOwSXQfvmeLbT/By1Qo0m9R2Sqb4Q0t3VDILyJmvTr4dLCRjAMfDaADxiPI
|
||||
58cXUeT5kLbF2kHQ8GZIFXpWQRhX5Go0sETlv35HtL9szNK/p2ngob6XkbxJf8rC
|
||||
ygP96Xa09J94CPrJF34slRM3hsdf/t92ytG8HTOf+42QjT60zgApibVVXwEYwx2S
|
||||
M/1FZbt9xR2nfvrKBZG4luyPuIVbAI3VbtgfP2ywIxQI7OkBQec52Ck2e4AvZk9q
|
||||
PUgxRqZbzpQSdEr3U3bhEtKf/Yq3Lgx/4Luo11BlZkWRKViBpK1yTUe1C4UkFo5Z
|
||||
gZO0oCwwO5YWxTCA1xCJDJeSuz16snOXpw==
|
||||
-----END CERTIFICATE-----
|
@ -1,51 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
@ -1,29 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIE/jCCAuYCAQEwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV
|
||||
BAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
|
||||
ZDAeFw0xMjAzMTUyMzEzNDZaFw0xMzAzMTUyMzEzNDZaMEUxCzAJBgNVBAYTAkFV
|
||||
MRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRz
|
||||
IFB0eSBMdGQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDOwQ+StykH
|
||||
YPBXIQPgD+ZqU4RBgbwpT94p9Fvf5/OZIenI2Ujv9wCEeRbwdtbKj+RlvcM8BX2I
|
||||
27MNp0dd5G9+dLizKbDgigjDRJXVNk4d9RPd7r/51jBT3WIkkI+4qkbTMjqfhkJn
|
||||
iBQZisAajucaO02F6FGxdqlFcU/l92CG12MRbvmNqmJ9odWniylKHwAfV1jSbnQS
|
||||
ckvtsxAc9bCNm3mDrjAwZlZCaHWEy0sq3VoBA7y1IWxOSg7aXR5t6NHEMs61ARfQ
|
||||
/bdGR4ww4haGVdflS68oSZtOa9TJytv0BaMnIFLkFDvEpq39KXjP0yrSGqJQC5cA
|
||||
3yh3uJQxUcZ9A2rPRR7LoS6ZVEk+4OWRP0kPW6FILDRiHMOlj0jeMmfLzLGLW/NW
|
||||
WBPBAG6pwNJaO1Y4LLHZRUJE3dM70v/lNMmB/T1S3kJ7TX+pluTgdCKo2qjxvnQI
|
||||
A0CnQeeQSV7TiefuIixXwAGGdg7dZO0MSkX8NASPiS/B3KWP4pSDDEzsRmz4UqRG
|
||||
0tnkFRfCKHtkBPJ7OWdHapgXnlUBImQWO2MStPenmZBzuVcCkv52QwuFC8g/EKlr
|
||||
tvzRl11Ajgg9LZApI0BaOtXE/LGkBpPpXNh0Pi10ETniPhvfZhX/RYb4g6WeVGsx
|
||||
oD6V9vHrD1Psp4u+QKZRldsD0d1aRvXvzwIDAQABMA0GCSqGSIb3DQEBBQUAA4IC
|
||||
AQCAzJrMHAIZVPupdJiiooCHvLc3M/4wn02Wws/NgvkIO3mNs+9uZvJ/IsLSOS/0
|
||||
x9gIVIXscoT0y/RRCg9IUwCGmCp9XkfL0MzBNPfhOXZ2/SXLGv2ubBTv7nyXAeF9
|
||||
Oh719bbir+vmEKoMXej0LBQ3qGT6zS8Zs2iKGj1bXZjZXiTt67YkYZgr65uZTYW4
|
||||
XtywTnJ+vUg9Mp6fReXgOWDlM8BiJ6JKnRn9f5Y66INSePV4NvtcIrqNNvrBEDqX
|
||||
LOWuh1Vs32gOySF8A1jM/GdSCdV1Wsng5HxGMMuGAKnw35YguW598Fk8LLfE8w5V
|
||||
x9Gth2RdxvimMu+qsNMq0mc78C1yPDSfRXC51t8J8d5+hke/apb6KfB/47gooQeH
|
||||
TCRMorOzO8tWhK6NDPp9iKoNSYznmtWq+0Lc4Upa+cc3ktIOCiTWh9OBaFsFd8jB
|
||||
Dlhw3sqwhMtqxJEoEJIZMGSE0W9p9y+D1XeNqfHmJ04NaTvuqfkt2z6ROd+pPdqb
|
||||
A+b6aFZfBdh+ynOq2g6Epwq8rNe338E23gVGgNfcw4pdFq9NmpdVKREIQKObQWCQ
|
||||
oElaQwIgyPI9rkpkT3QsHHJnEb9mRn05tlEplOi6S05/NIb+yz07Jb09UdAjxHDR
|
||||
4MiUfXVXZwUAvuWKBnKK4ZjjgEZe21aoliLDl3yekewVqA==
|
||||
-----END CERTIFICATE-----
|
@ -1,27 +0,0 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIEijCCAnICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUx
|
||||
ITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCAiIwDQYJKoZIhvcN
|
||||
AQEBBQADggIPADCCAgoCggIBAM7BD5K3KQdg8FchA+AP5mpThEGBvClP3in0W9/n
|
||||
85kh6cjZSO/3AIR5FvB21sqP5GW9wzwFfYjbsw2nR13kb350uLMpsOCKCMNEldU2
|
||||
Th31E93uv/nWMFPdYiSQj7iqRtMyOp+GQmeIFBmKwBqO5xo7TYXoUbF2qUVxT+X3
|
||||
YIbXYxFu+Y2qYn2h1aeLKUofAB9XWNJudBJyS+2zEBz1sI2beYOuMDBmVkJodYTL
|
||||
SyrdWgEDvLUhbE5KDtpdHm3o0cQyzrUBF9D9t0ZHjDDiFoZV1+VLryhJm05r1MnK
|
||||
2/QFoycgUuQUO8Smrf0peM/TKtIaolALlwDfKHe4lDFRxn0Das9FHsuhLplUST7g
|
||||
5ZE/SQ9boUgsNGIcw6WPSN4yZ8vMsYtb81ZYE8EAbqnA0lo7VjgssdlFQkTd0zvS
|
||||
/+U0yYH9PVLeQntNf6mW5OB0IqjaqPG+dAgDQKdB55BJXtOJ5+4iLFfAAYZ2Dt1k
|
||||
7QxKRfw0BI+JL8HcpY/ilIMMTOxGbPhSpEbS2eQVF8Ioe2QE8ns5Z0dqmBeeVQEi
|
||||
ZBY7YxK096eZkHO5VwKS/nZDC4ULyD8QqWu2/NGXXUCOCD0tkCkjQFo61cT8saQG
|
||||
k+lc2HQ+LXQROeI+G99mFf9FhviDpZ5UazGgPpX28esPU+yni75AplGV2wPR3VpG
|
||||
9e/PAgMBAAGgADANBgkqhkiG9w0BAQUFAAOCAgEAyqppt9mxmlqAUkYCbNxPnc+M
|
||||
1d5OQZ1Fqy0a4eF9/WxK+PqjRTKbD+rvGEulYdeCGiz8wP5HxVCdT2xzdVZdhMUX
|
||||
opZGG3x5H1xXy0YLzBsxB9rkYjz+NeVtl8lKXvWDfgZ1vjjRHOIc261Eq6CPoXjT
|
||||
5ENHnTyT0xbDmdkyjGNT0qowl50rlZotx6Vb2VPquAtau1m2nrvx5t0wkbJPocPA
|
||||
XTndphgdH0aecJXZOgN8MWh9LYObNM5UqIFPaiNHHAetJIOLoDDIpEl5ZVj4PwtU
|
||||
uiiaWpNjz3ODx2j5tmEz1SUF+6vS0OfvKx/pInQzFFRLfudgphzGYLf9rwOswBI7
|
||||
8d0sEfrUNEladzvIz/IvJpuRrWJ/uLfpE4LXYTNbGWP50d1YRGxv7Zl8Bio0CU34
|
||||
q+Du1CXpWce5bcOJ25KYZd7Lrf0YVzQjneuyNbBCPrp2gbweeydQWd6LGdtUab0l
|
||||
gjQ3lj4E8Y1vIpTOL2K3bvkqJxJYoaYdzzGEzuv6/FS7ATYVn5sBYxJrsUqgYdjp
|
||||
SMx6RS6ImNbHVy56nb6MiaztwAE4uo59vkrdKdvIETvP5duD4qDBsZL3WzJwhMxl
|
||||
d9An+z3VAqEABzNtM7/Cdq7pZmgdPAHgGFasB3eihdmHsONWqExRPhcmW4H1hpVQ
|
||||
pkguJFDOpRqebdLHZPI=
|
||||
-----END CERTIFICATE REQUEST-----
|
@ -1,51 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
@ -1,51 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
@ -1,14 +0,0 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAzsEPkrcpB2DwVyED4A/m
|
||||
alOEQYG8KU/eKfRb3+fzmSHpyNlI7/cAhHkW8HbWyo/kZb3DPAV9iNuzDadHXeRv
|
||||
fnS4symw4IoIw0SV1TZOHfUT3e6/+dYwU91iJJCPuKpG0zI6n4ZCZ4gUGYrAGo7n
|
||||
GjtNhehRsXapRXFP5fdghtdjEW75japifaHVp4spSh8AH1dY0m50EnJL7bMQHPWw
|
||||
jZt5g64wMGZWQmh1hMtLKt1aAQO8tSFsTkoO2l0ebejRxDLOtQEX0P23RkeMMOIW
|
||||
hlXX5UuvKEmbTmvUycrb9AWjJyBS5BQ7xKat/Sl4z9Mq0hqiUAuXAN8od7iUMVHG
|
||||
fQNqz0Uey6EumVRJPuDlkT9JD1uhSCw0YhzDpY9I3jJny8yxi1vzVlgTwQBuqcDS
|
||||
WjtWOCyx2UVCRN3TO9L/5TTJgf09Ut5Ce01/qZbk4HQiqNqo8b50CANAp0HnkEle
|
||||
04nn7iIsV8ABhnYO3WTtDEpF/DQEj4kvwdylj+KUgwxM7EZs+FKkRtLZ5BUXwih7
|
||||
ZATyezlnR2qYF55VASJkFjtjErT3p5mQc7lXApL+dkMLhQvIPxCpa7b80ZddQI4I
|
||||
PS2QKSNAWjrVxPyxpAaT6VzYdD4tdBE54j4b32YV/0WG+IOlnlRrMaA+lfbx6w9T
|
||||
7KeLvkCmUZXbA9HdWkb1788CAwEAAQ==
|
||||
-----END PUBLIC KEY-----
|
Binary file not shown.
30
fixtures/ca/broken_ca.crt
Normal file
30
fixtures/ca/broken_ca.crt
Normal file
@ -0,0 +1,30 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
54
fixtures/ca/broken_ca.key
Normal file
54
fixtures/ca/broken_ca.key
Normal file
@ -0,0 +1,54 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: DES-EDE3-CBC,29382520d522b331
|
||||
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
31
fixtures/ca/broken_server.crt
Normal file
31
fixtures/ca/broken_server.crt
Normal file
@ -0,0 +1,31 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
51
fixtures/ca/broken_server.key.insecure
Normal file
51
fixtures/ca/broken_server.key.insecure
Normal file
@ -0,0 +1,51 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
@ -1,31 +1,30 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
|
@ -1,54 +1,54 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: DES-EDE3-CBC,90DB77765661F24C
|
||||
DEK-Info: DES-EDE3-CBC,d2e70acc12a86116
|
||||
|
||||
f0pCWQG7S6EdHqlN0tHfpowMyEFR/WYtQTjYws93+2MBcEDa9fqecN1mqNkskWsA
|
||||
As1HVdp6o357bJ3VtoFHBRvv4iql6xutkZV8NoVAQseLjjZkYGFbIJ8Dv/O6xnXy
|
||||
XDqm3WopCQB9hLKjORcwJN3Q9SRKmmRCxkndVcNkCjoY/TdN1jPEmQqtfWfmLy5S
|
||||
GVmTHmoTPVvJh34mvkUsLrNkQ6XOrIisz93zmFO0VpskvxUmE2lOdLzTALbz2MZP
|
||||
TJalI2zZSfoU6ZaF8eUG8DA5+3PknGNSRP4ivbA0CYkYn0Wssatf6+YUg1kMJ5+B
|
||||
nPhh1tTeeE9bMaTEmcrJiDQFqn+EBmzXBzLDxYsUIEzCzcc4bPbvuHpZSThXFTQa
|
||||
D6bakKXYW/bmO190o3XxpfQkLqzRQLWhURqjx57k2uXdxftqosoyPEcxW+o/L9am
|
||||
z1PaL0EtpyQUdX0T51vjmOhe5tgtQXNXdcGkL4nkR9p75kVPCKYpPv5PBcNE/PWR
|
||||
zsCJWVERknr1ZMVWdOfcOGdaINK/WcFSzK2NUpTI1urqPuvXq1Uc0hxYdkWo3GU2
|
||||
vKSqYPIOZHC6QcwQILD8xukPMjncf0vA/K1XV5WLfLwQIZLo9XoFVWESr6sOCXTU
|
||||
qJ/hYB+yUQSOJD0+gBptJLu15z854YpoHoFrHpjzrSaw7NXrNex5cMzjQSNsUzDQ
|
||||
p0zP3lrnftLUdSZRrPR8Uq2usv3tSRrZmQGU/We26CuajrJVB3uui8uj8i/lABJD
|
||||
Ikvq/Xse5krjrlX2LTtUpE1YGfl7jE556AuDI46V2e81io0yqMDQiEU22+0REB0s
|
||||
4u4Rzg8g5XFGt+gnG+RnZ+Z6/o0RgKsmilq82EuHl2WHnmCyTU3tl/t7vlPGkHa9
|
||||
D7pvMF3OkW9/tAKISx/KkDEEIlTYAnNjFhA5wd0din0xR1WpeAx6qkEwbFPzBZZi
|
||||
nhgP22bX66+ST+dQ6h4+jTupiKFJX7uXo7B7ptTO4eo73+5H8xOujdtEaZ2two6a
|
||||
VYUre+/ZyhmCBwdKqpXcTwXs2osqTrvkgWktVCTQYYIWNbjy+gSvuYWK+RJbzFLc
|
||||
gwxASDyledtgpC+PhK9O3BxWTwqU+j4YdhjYxX5ZBdVqp5dlQVPN6fseYDjaEvrS
|
||||
wgPtHpXueOCJv7vhltc5ABS4ZbxSUCQphiXYdof9FVPh9jwYF8SOlP3WWAP5opec
|
||||
Vk91CWUNcTi1AgLgt/1L/FzOE6bf/x+bWIvOHLZKDO+9hT635NlQ6+HIzPbeLA0P
|
||||
KksFuQ2WDjh2xHG/RAdNG6eWavzPuAKom+LiEiOQFBDNhnDTaURPSSxPhwQNYaEw
|
||||
++WupENWp31GLRF1BKmZwP7hgO5fkh3Zy0Ah/fEiGIw59QLjl7bCHNBeGyl1CIKJ
|
||||
h5v2zFo6PNpd6Hcxj8Wf1WKQcSJgZdZ+QjUbK4pdr1OokulgNZyL04LNndTFqh6z
|
||||
PrX12xhkjxxv4xlTuyW26VMA9YJYKA+9Pg13LSTFQKklxTg/j1CK88c7IOYk8X2k
|
||||
mH+fioME9sy5wDvpuAF5ufrANqeUdhn0/MrKExNDVCh4i4BDYJck/qt21w03sdx3
|
||||
jCQF32S4ltGoEA6AQCALqgfuSLUUWVuOu71dl9a08zR52MP/2pLnzF+PsHoiih09
|
||||
OA+9395WoiRvip5ei+JQGLwXfC8C9zX6kGSPeckju9v/72Gv8M5QxHvAakHZFpxe
|
||||
FWG3y4BEG6TeNgSAlXYvGwDlpjSF8osjlNWubMYY7pbbM9WhNZ35NUU6fWQ8KtVL
|
||||
coqQgJc07f3liv+TNiXjNsxVu72rE3L/6efbtwNnCpPO1kRcs0w1q99S/j+kVzAv
|
||||
8bdfEm8S63m6+OR8AUe0EzJrLu2KA5WqkMUgtDM4Rk8fvcEMhyIGbwyRQEB8NCpT
|
||||
4MQqz7fpnZZ6YZadQ8F8HI2YeOhl2M8iVWG4BhRX05MEkd9mqf8qvqmEmj2PCkKT
|
||||
5vAI25LY/lwidvdCpzYOFpSFSQf4YuzHRvYnF8qKCDDdE1x9TAV4DZsjoeRnjgEq
|
||||
TNXCYMxzyBw8WYxWB3e8emgK/9lHmROzb46LDVixmu9l84dx7S8SL/f+R2K4yqQ0
|
||||
jajSzMrDlBUXtjm1RHMhyTZq7PQxQxau49V+N7SCS2eej549XH5pPb2g/LwYUtr4
|
||||
UVtYYE5CH7RuS3pBBdXsAE9GnkW7JOXaUt91w831JlLofuZLn1JEGJCoVk4j+fuR
|
||||
LHuHmKdbPJUacgqMYFf+XvVq7JERnhO0/MeQBoKyYy9C9x1JAPfyuThO5HHEotQa
|
||||
vnaVt5S2TjTSaKAoiq1x1IkFus1yVyrRNCHIfaOKv/L/ty62Q0LVNX+7xrZrkwPp
|
||||
KlWIQuhFAGVts8H6dub+M167tatDK0I0V4iHSExKLLJn3EV8yX1/7wwW3qpy6Lmm
|
||||
Kt+Dme9NpTFXP3ejV3n3tpIxCUsihaeecYB7G6LnVGOMRZ5cDjv6SU0kE6MEwczd
|
||||
p2tghbaNKAdV2AnhohDxVFTMVcUuMI9qdnixSMIBdx6Nax+JeFAT9dec0Hk+U8x4
|
||||
rYOZ6UV5IWrteF+I0r1oD9HL0BL0C8Va6rMq5wDhOfs1Cy5ccek/1HmcYlI5DV9D
|
||||
JNAQyfH1ut3yFRusS4rgJP6GpfUeJm7EIsY4jI3uI3Z4o1zSDCOCO4mCnXfq3Lgc
|
||||
Pn6CcQKxNrPCiefs7EOiPRWWbffwlpUakkTyAaU057Ge3lqBUL++bHIP9yek/UEn
|
||||
26qDVzbiWRFsKWx1wvoXTAURIhAlzdjKwjje5P6GKpJcc3bUw3HsprA9JFmOPlvZ
|
||||
LKCxk4ew6/7IeGYZT1L1rzziV8DBq8pqio1M0VMTxLnXfc7P9wdHXE9A2wL2dFdJ
|
||||
gP9utDzrZLvP2sOf/Bz/WJB7IAPMZOTBSlRquKQjDqBpXjHWSEaknLxYxmyF0HN7
|
||||
3iutUpLtDR3KebLoW3P0lgcPj8cv6xEyGUDV8tZHkUkw7chGn0LfEQxyVWhcQbYv
|
||||
69by3FV4wnTATAnWMzoYHCP+e42uLWD/a3WDpsDuasddhyHCAineUHmHMoWliMVY
|
||||
z7nBoJttya5IiB1oh4ksCGjkCaqPpbtdOqXMc/KBWi75fV8GidFH4UgGPADUKa1Z
|
||||
uAmKZ41MiYTa7CappCFEcLL/kWRX4rE8DJG3sL59lv3j/6bYFkdczy3kgrEWm4Pn
|
||||
+pveJEssQkszXHkjA3vHx8nlTvfQOwa7ggcc76LNYj1sPHawVRNA0pb6WvjDzN7D
|
||||
JMgAnptVuZGP8N6ZIzFvr5Rf58ar5Y2aI7Ti6KxLZvqYojgvz5dzGimC3+SwDlFy
|
||||
Q2kwBA/HT4X9w2qSxpQ7WGPw2pkYILZ4Nxfqh9PWHd0Pk1d9KoLhbU5LEtGSy/y9
|
||||
9jqKsUqBzp9905t7d2KmFDF9Nd7XvHrDZDPILlKcQYnBxg6c1ChH1NkIqdAW7lQ6
|
||||
dAKAFZlMpVb/ArFBjhioljBIO+gLcWxYseHXbteOgbC1cw5xcBTHqH+7RotFH1VO
|
||||
ya0DFeW2CyPj4mp7vORD+IOVQaG4H5j1vJXqA9OPBziZR+lHvD0gVJqZIquXIQlW
|
||||
MBpX5CfV/3xITb6o0wA2OG2qlNM+VbKzg/cqh/kkusAqcfXIByh16K85k4jwPrBG
|
||||
wsYWABgw1vLlrCJ7ug6P2rb6VmzTbMqe4gpqUROgCS36ARjs5eDBDYZsX6NaGSh6
|
||||
twAUfzpwoGNuHwUpIYf5BjH1me+tnM0S8tAEtCFf9hy88nCg6v22cWQuAD6+6P6B
|
||||
Skl/UYT4sxeeETFv7Vf70wLnBMA3/uymBM75FhPyD5Vvg9fxz7aAJbfB2ovUVZ/v
|
||||
l3HCsCo8y7DtEXoiBmPCH28JWVhIZbmP3dYnU8c86SubhNWm0yjJIIwoghyFmCcO
|
||||
Wjs0XkVUUa9fGrl6Mc6XQIGsS6UdQkFoIcO+dtIFPg5C5GWnPnF53ro0J4pGcyR0
|
||||
zgt9ubCcFKNz5Cbcfw7fKJwswMt6zXtFxE/tVvOq2EPAPrmYYwPrnvbSNbuVL+as
|
||||
OT5ukITR9MDsYR/19jFUsdRDjSvUQVwqH7PiKwTnZouuJUhYHfj3Bjhz6cWzadcd
|
||||
pNdxqSgEeSzvaz390p1dOpN/0d1ItXlp3za6JZUarVkx8yH9UCFfpEEisPYgTASf
|
||||
F2xIrWHgZY+87OjPluU+Gym12ldcs0dbySgsxhKZMyAUd0DB2Knnmug+cqVvN+xo
|
||||
rJ2pD7J08zmQSRGyAUsbeUnuGb6fGNxaD5QpEN7nK4x3K1Q5N9QQ3RwL4Ik6jV0N
|
||||
eO0LzXF/BZbOAvl/OXAse1f5c7FO21oUw6u6iI0xvTJAcnaH/0eE2N6Y9Lwt507K
|
||||
HxhuN5j58/sOeb6kfkX563SoKSdYSrBqIaogDZFCtKpEBevsRM+QRdzAc//Fm67U
|
||||
Zs2K/ADM8+IaQN7uhm8IAPtWEnJ5+9rM2PCF0NX+7qa9HtZxTd0cqbeL8Ayx4i/T
|
||||
dHvN8k3kPuC+6He7+eZR6EQpN5GPt5SX3QGgKOQbbwBgF8mS/R0zaZpHvaqTY4Bi
|
||||
RfsLbRBGoTvR8YjqaQW91tExe5FghH7k02slSGzEzgs/ZhqPMCLNC7uFcSKcx9jA
|
||||
Bj+GmrYOMrUOYLQPT1iRtBFjLEUGPlvUGlaJS/JcvBN6DPW375tQHk7kbpVcudPh
|
||||
6vVXftuDiYEJk1TIQLt3QdC9s6ieVuAds4KDjYaTZz4s5W2Lkwo5AZzwLeMRank1
|
||||
96okoO1qRaDgagHsG8yPIwq+8/b/8dNl7E+wsbAWwLXLhYZGqDmHm/16pv/Ck59W
|
||||
LXLoJfrOdKBoxTTZulIsTISZ14Bj87QWPW26kI6So9V5vN60rb2MWrd+HU46Qapi
|
||||
JCsfCVsi715GUh4IkqAnec26TuXW2THcOp3p19SyubuJ33XqUR9H7BOZuBsIFeZV
|
||||
8sihbgjJ/zb7fZ7AGT3VmAxEtgFi8u2NOBN/WqYb++khtXgnIbOhBx9PuhOBofrO
|
||||
4M0R5s6F2SpbX2LEBJFN48wIlRmSMTsKdmZmA7f0IuxjYIcotBdRCGoXRlJJnZeH
|
||||
7WriXQJsq0517GlrqgYMDx26xHJy/ao+zcDxsCtftzAQvENuGr1lzsCdIcGXs+FU
|
||||
7C8qdmqSXgZgltFQpyR7+PMikXcdYdzkT3BjFh+VKJNiAeGXNnVXQH7L/V49zaij
|
||||
BRYWWtHwEDz50vSzZz3fnrFl6Pk8tny4bKoLjB4vBjMlb4yte7LcK+vbfDdreISD
|
||||
cDqfpzjAmIpv1GoQFKWGLQjagvwiAfOA8GUivEG9SQSAAImkV9qkr5qYzM7Jn2WU
|
||||
icA8D0YfuILpGxTOQc1SgDMOiGboCB+f7cxPsjXHbVahNyxxAbDbTjbc6v7q1oiy
|
||||
PESoLaBR0Bi0tdKivvbB63ok2Kq9XneFrQeCIyrhkXIvYDEwdcoCBpL1DEotbU+D
|
||||
YjZTLr4UW92xi1M4d94zmG6pyJsfC4sHGflY5paml9dLiEy78rCPfrJkrSSUplf+
|
||||
8CjfUoZsbq3haE0N4TbqV0I0W2Fm/a6U113CTRYxj9DeA3m/HFU3TLzk9Vg/vGxP
|
||||
/xltsu/wd/GoyoD9OhWhW1Ck9dtQ0G64hQjeXVd/pzsDCMT8hrtKSlX1Q7vK96ml
|
||||
OJ9Ju/CdhX2lJA8BrGVh4HS1fsuNFjr5KqZAY6MwFpjAPqvqD7WFE3Yflk5/7VtX
|
||||
bsvBZoN2vp9hprXsgm8/KmSNnWxzQY1Nps4XjRJVYeTmND5EyQClGJyCYKg0QVDo
|
||||
7L/2GAhnOrSLkAHOcYAlrNhZ85yBiLhjJcvWyT6DDcMpCusgictI2Qv2ZjMmz46v
|
||||
62PzHm0/Z3yQMcJnpRO79OdodbY22Eg9xZGGhBp1Xbm/OXYLaEpGW9S7DqPvlD5v
|
||||
O+VxENxJNwDELK9H2auGJAQdORwgF0VfvZxN6tGRyb7eI6aJj04YYMBkg5Nds+AR
|
||||
sNEdGNzqKm8sWvINSoX+BCOyjElOSRW0glK+ala5Y7/mM3+KOWgMas2LZBcLZfBr
|
||||
1/Z0DPIA2CkFtT1VsBKa+fSkEN0s+PRLRV/QWrcMbkSvIaKcswMwoyvI6OcddUEz
|
||||
YgjAOZ3TdnRm1DMqZHIsPOj+3xQv6nETqSwhvLJT1wJwnJQVbxjZwoUmJKSsZDEB
|
||||
2xL9OWlhFNY2qS7F77vv2ZUJYLYniiTGrC09AAQ4ti8zWnY1gqtaCp+1wynt/Abs
|
||||
9gGcbEIaQGWhpVjPtlKjNm86jGP0IXPaAgaOViIuBH+0GeVOLuUMLvb0nL0NWMJa
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
@ -1,61 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFMDCCAxigAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJBVTET
|
||||
MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
|
||||
dHkgTHRkMB4XDTEzMDgxMTA1MTE0OVoXDTE0MDgxMTA1MTE0OVowRTELMAkGA1UE
|
||||
BhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdp
|
||||
ZGdpdHMgUHR5IEx0ZDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMeY
|
||||
u5Nby4uG4s5HFuky6eiLf7bMiTl4cDomb6keKMaHuSYN0zEr8jdw4r8TDSguv5MO
|
||||
E3xWSLvQwLgkOQT0N7opDeEqm5Yj458+M9Z5lqYUSshWpnFNUyu8GBCfARB80YCy
|
||||
8dLbYp5ORJ2AWzS5fxtp4TXEf8qlrAMoeJz2ZXMvGHMUuv8TFa3KPAajQ5n2DPSu
|
||||
iFevaDitiRamz6aT48bnOowMO0Enek8UkfpTeR7uh0vOPbWOUIjzuqr7G4MnJkYD
|
||||
yd7R3KscZN4iXf6NRMj2f6V4PGY0WljUbli/fT7bC8IbBgLkQxT8mO7dcJ9QHKte
|
||||
Jgdju/9eto3zC3kDC3Yh2RaxfxM1vtmgZm3QT5oz95QjjskzW1gz2giE45wojbOg
|
||||
nTI+QRtw2EMBX6mzaP/YU6vCvPCqhJ9zrVMsM88EK0TTdkE/NWC25JUmsPXX37Z5
|
||||
jFXIFamM0FWE/zhDip8Xfl3yqAM+NVQ5xnmWGMpqyHn/A1EaRv0ASVTMsg413N3j
|
||||
r815qKy/xSCbyRIFhrBmKkwy0bSZVP+9Y0sC8+bBTZNdbNwrdp0It7BH/xKmG0Ma
|
||||
TNpAgVdkbnnSt5DlqS91Sbta5i+kHibkFml4KnZ6OvJgQuTbC+UsbpD5B1vM8Rd2
|
||||
64xOQmH9KFNgouDhiBOtwAL3bn+76Pdt8OnMbO0JAgMBAAGjKzApMAkGA1UdEwQC
|
||||
MAAwCwYDVR0PBAQDAgXgMA8GA1UdEQQIMAaHBH8AAAEwDQYJKoZIhvcNAQEFBQAD
|
||||
ggIBAJIVOwXJkpI9bPRq6FxN7a0/2NcEU5cC9NvtvEZEjgMFkZwiPMsguwHbbsK/
|
||||
Hmg+UBo9HdOCleaPq0HhrhqDzqDGzuzCCwqDinYJl/MaTs7dBE5sJw5sCn+oESF0
|
||||
5S1rCKvvF82o1KSzj458aTWKYpOJpdJYPVu8QEm9sBPPAFcQHhevFRuVp8QBdRJD
|
||||
6H4+6b4eZyADL1yM+Txt/ucuyx/6A8S/G+Uqe5Lnh1pvhZXFfWO1UF8QmYNUb0H2
|
||||
7soxruLh4k2mwF8MPSmKw8D3k4rCAMZ7W1P6OEV55Jc4OMVQ5es8tRuj9e2SHD0c
|
||||
gL84rv9lNYfA/4DEKEviJTko+dD/NyIKrZCyc39Q3MmSBR+ekCNRhdCHWL5IyMB9
|
||||
o2u5g2ffsKLLjqBNIrOcGQ8vYSTsuX+y1Tonml6FiBHCgtDv7ZcwxXq37jmeorMt
|
||||
QqpGJsndMObmvTVkYDN8vgEoia/nndhU7SGgi9NIYDLarDzWrU9baLta8Oq7BHaR
|
||||
oMV44flX7/2Co6SOzK4y2WgQngCUaAxezN0tZPFIhZjwGwc3CbaigIaF8LTKHQ8a
|
||||
cGIBGQmZ3670IDQ/vgtjHqG6LlMiJ+WR9GtWSJl3cb+4yHM/wu4oFgjYoB1MSWl2
|
||||
f5fczxP6ZXwER7NwcRaooJ/0C7XDE7ux2HsN422jgDaGT/Zw
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
@ -1,61 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFMDCCAxigAwIBAgIBAjANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJBVTET
|
||||
MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
|
||||
dHkgTHRkMB4XDTEzMDgxMTA1MzE1OVoXDTE0MDgxMTA1MzE1OVowRTELMAkGA1UE
|
||||
BhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdp
|
||||
ZGdpdHMgUHR5IEx0ZDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALRv
|
||||
lwJo+lU+QkAol+sFEAyW+qTNxdTKiSqeHhigpbyuo18/ILvXJRRz4Slrx1sqLjf4
|
||||
ne00N0wTy3l+DGi9kI39BrVrj8Lg9mTlfJQy/JJSDVIMli/lnkbfjNlsC3miRLmY
|
||||
YxqKLZJH5onErIR+XCTJ3o4kVk6QMy3oR0LPWWz/cs4PrXNVosL6jl4tTTOyqWAC
|
||||
4dtDGlDElSFui78KuSQCKO+9sepVvSFXE8Wo32LZWQ1vahg/+J/eagbw6rakl+uu
|
||||
VJgfin7JH+bFsiBCkOAN4v0QF3JYchMIBeXwQzEq/HpN73Es2wPGuyglB0OGkxpu
|
||||
nZ0B7bAJSOQMMNL7NkGIu6HNqORt2FzXypiXaIMUCVcIvvf2VqGBpULe+4fdLvbc
|
||||
Ho/F6MzmmxfDNMwvBb1P+1nPOKc78pKWO2mqN+hOudxTbdzAiYURtjIp6oyEzvl3
|
||||
Hdgf3UUVmBQe6jPw9Cm17c7y58icPdRERoxCSdhOfwYFuls/fenPwBhMZ53+cRYG
|
||||
eP2f3TT6cMzcEUkz2ZIZa4XZp0JCox1yQxy8vrmWfLo9sghqE2iRGWqRKexhr7IM
|
||||
Iv9Q2wL5qcGaX1wA1gOMfpuqySb6zp8LouVEXAII9RfiRFundqYjJjtZg2sosjRJ
|
||||
Eab94wfwLu9d0lKZtNBkAh65q02+Ys4Ah94IEu+ZAgMBAAGjKzApMAkGA1UdEwQC
|
||||
MAAwCwYDVR0PBAQDAgXgMA8GA1UdEQQIMAaHBH8AAAEwDQYJKoZIhvcNAQEFBQAD
|
||||
ggIBALWlvNm8kp3bdzymrJnvE4+sV5p+2AnKx1yZIs3h62rUM22ROU1wCAoJfyCA
|
||||
LuXQNaXuWVOWUq96BCzlTScTSa1xhB/vbn9RPJVo0t+uni5fx/Pm2CHLAUijrT8z
|
||||
10BHbaIPjYnmvz0lkii4Y5+Tb4WQ6yLrUYm2dpLexYwyOUhmGQNGRgY750dwf8Fe
|
||||
2TBFOV9rkXlhgdopWYPhUv0ZmciYGwrJ2+9jULDFhT+PDrdAjbeDARPKcMi0jpZ1
|
||||
zBHyC6lNT167Gdj9LVV6dIFEHozzrqdMecz5CJrgKPL0s5bM88DRssupS1WgT1RG
|
||||
qGVxfcuBYRLtz10W5+JBXvA3JRHgaPotkqvKsUqeII/nqvu+qSRDnh7O+i1PJUTr
|
||||
D+5CSMxUK9DvxH1gUYhnQ5asP9PXZxp8hlGGwyDVu2rYTQpDyiJnHGmsWfSZuSOy
|
||||
W8ViseuFe3WmdsD0wo6VguyPFMHGzh5Sx/onb4eeASz/BtcGYVPApD4WByF9WlVF
|
||||
Cg3SfvNPj2fvI92DP6KAKtDgOdcHidzwPAh3XCZGikN19Oz3cCYf+AT+s/KNfvMt
|
||||
B6DplYeleAlKTXYsS4ycGojGp4DpRzrxSb2mhHdHsz51H/gn9+Rgx4+QAIJGKqxk
|
||||
yNRnW/UpsJbN7G7hI3pgBEFRD+QE4zvGwkn6+SwxxozhtZZ4
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
58
fixtures/ca/generate_testing_certs.sh
Executable file
58
fixtures/ca/generate_testing_certs.sh
Executable file
@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# This script is used to generate all cert related files for etcd testing.
|
||||
|
||||
# location for temporary depot
|
||||
depot=".depot"
|
||||
# The passphrases for the keys are `asdf`.
|
||||
passphrase="--passphrase asdf"
|
||||
|
||||
# etcd-ca could be found at github.com/coreos/etcd-ca
|
||||
if [ $# -eq 0 ]; then
|
||||
# try to find it through $GOPATH
|
||||
IFS=':' read -a paths <<< "${GOPATH}"
|
||||
for path in ${paths[@]}; do
|
||||
if [ -f "${path}/bin/etcd-ca" ]; then
|
||||
ca="${path}/bin/etcd-ca --depot-path $depot"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ "$ca" == "" ]; then echo "Failed finding etcd-ca binary"; exit 1; fi
|
||||
else
|
||||
# treat the first argument as the path to etcd-ca binary
|
||||
ca="$1 --depot-path $depot"
|
||||
fi
|
||||
|
||||
rm -rf $depot 2>/dev/null
|
||||
# create ca, which is assumed to be the broken one
|
||||
$ca init $passphrase
|
||||
# export out and rename files
|
||||
$ca export | tar xvf -
|
||||
mv ca.crt broken_ca.crt
|
||||
mv ca.key broken_ca.key
|
||||
|
||||
# create certificate
|
||||
$ca new-cert $passphrase --ip 127.0.0.1 server
|
||||
$ca sign $passphrase server
|
||||
# export out and rename files
|
||||
$ca export --insecure $passphrase server | tar xvf -
|
||||
mv server.crt broken_server.crt
|
||||
mv server.key.insecure broken_server.key.insecure
|
||||
|
||||
rm -rf $depot 2>/dev/null
|
||||
# create ca
|
||||
$ca init $passphrase
|
||||
$ca export | tar xvf -
|
||||
|
||||
# create certificate for server
|
||||
$ca new-cert $passphrase --ip 127.0.0.1 server
|
||||
$ca sign $passphrase server
|
||||
$ca export --insecure $passphrase server | tar xvf -
|
||||
$ca chain server > server-chain.pem
|
||||
|
||||
# create certificate for server2
|
||||
$ca new-cert $passphrase --ip 127.0.0.1 server2
|
||||
$ca sign $passphrase server2
|
||||
$ca export --insecure $passphrase server2 | tar xvf -
|
||||
|
||||
rm -rf $depot 2>/dev/null
|
@ -1,337 +0,0 @@
|
||||
[ new_oids ]
|
||||
|
||||
# We can add new OIDs in here for use by 'ca', 'req' and 'ts'.
|
||||
# Add a simple OID like this:
|
||||
# testoid1=1.2.3.4
|
||||
# Or use config file substitution like this:
|
||||
# testoid2=${testoid1}.5.6
|
||||
|
||||
# Policies used by the TSA examples.
|
||||
tsa_policy1 = 1.2.3.4.1
|
||||
tsa_policy2 = 1.2.3.4.5.6
|
||||
tsa_policy3 = 1.2.3.4.5.7
|
||||
|
||||
####################################################################
|
||||
[ ca ]
|
||||
default_ca = CA_default # The default ca section
|
||||
|
||||
####################################################################
|
||||
[ CA_default ]
|
||||
|
||||
dir = ./demoCA # Where everything is kept
|
||||
certs = $dir/certs # Where the issued certs are kept
|
||||
crl_dir = $dir/crl # Where the issued crl are kept
|
||||
database = $dir/index.txt # database index file.
|
||||
#unique_subject = no # Set to 'no' to allow creation of
|
||||
# several ctificates with same subject.
|
||||
new_certs_dir = $dir/newcerts # default place for new certs.
|
||||
|
||||
certificate = $dir/cacert.pem # The CA certificate
|
||||
serial = $dir/serial # The current serial number
|
||||
crlnumber = $dir/crlnumber # the current crl number
|
||||
# must be commented out to leave a V1 CRL
|
||||
crl = $dir/crl.pem # The current CRL
|
||||
private_key = $dir/private/cakey.pem# The private key
|
||||
RANDFILE = $dir/private/.rand # private random number file
|
||||
|
||||
x509_extensions = usr_cert # The extentions to add to the cert
|
||||
|
||||
# Comment out the following two lines for the "traditional"
|
||||
# (and highly broken) format.
|
||||
name_opt = ca_default # Subject Name options
|
||||
cert_opt = ca_default # Certificate field options
|
||||
|
||||
# Extension copying option: use with caution.
|
||||
# copy_extensions = copy
|
||||
|
||||
# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
|
||||
# so this is commented out by default to leave a V1 CRL.
|
||||
# crlnumber must also be commented out to leave a V1 CRL.
|
||||
# crl_extensions = crl_ext
|
||||
|
||||
default_days = 365 # how long to certify for
|
||||
default_crl_days= 30 # how long before next CRL
|
||||
default_md = default # use public key default MD
|
||||
preserve = no # keep passed DN ordering
|
||||
|
||||
# A few difference way of specifying how similar the request should look
|
||||
# For type CA, the listed attributes must be the same, and the optional
|
||||
# and supplied fields are just that :-)
|
||||
policy = policy_match
|
||||
|
||||
# For the CA policy
|
||||
[ policy_match ]
|
||||
countryName = match
|
||||
stateOrProvinceName = match
|
||||
organizationName = match
|
||||
organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
# For the 'anything' policy
|
||||
# At this point in time, you must list all acceptable 'object'
|
||||
# types.
|
||||
[ policy_anything ]
|
||||
countryName = optional
|
||||
stateOrProvinceName = optional
|
||||
localityName = optional
|
||||
organizationName = optional
|
||||
organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
####################################################################
|
||||
[ req ]
|
||||
default_bits = 1024
|
||||
default_keyfile = privkey.pem
|
||||
distinguished_name = req_distinguished_name
|
||||
attributes = req_attributes
|
||||
x509_extensions = v3_ca # The extentions to add to the self signed cert
|
||||
|
||||
# Passwords for private keys if not present they will be prompted for
|
||||
# input_password = secret
|
||||
# output_password = secret
|
||||
|
||||
# This sets a mask for permitted string types. There are several options.
|
||||
# default: PrintableString, T61String, BMPString.
|
||||
# pkix : PrintableString, BMPString (PKIX recommendation before 2004)
|
||||
# utf8only: only UTF8Strings (PKIX recommendation after 2004).
|
||||
# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
|
||||
# MASK:XXXX a literal mask value.
|
||||
# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings.
|
||||
string_mask = utf8only
|
||||
|
||||
req_extensions = v3_req # The extensions to add to a certificate request
|
||||
|
||||
[ req_distinguished_name ]
|
||||
countryName = Country Name (2 letter code)
|
||||
countryName_default = AU
|
||||
countryName_min = 2
|
||||
countryName_max = 2
|
||||
|
||||
stateOrProvinceName = State or Province Name (full name)
|
||||
stateOrProvinceName_default = Some-State
|
||||
|
||||
localityName = Locality Name (eg, city)
|
||||
|
||||
0.organizationName = Organization Name (eg, company)
|
||||
0.organizationName_default = Internet Widgits Pty Ltd
|
||||
|
||||
# we can do this but it is not needed normally :-)
|
||||
#1.organizationName = Second Organization Name (eg, company)
|
||||
#1.organizationName_default = World Wide Web Pty Ltd
|
||||
|
||||
organizationalUnitName = Organizational Unit Name (eg, section)
|
||||
#organizationalUnitName_default =
|
||||
|
||||
commonName = Common Name (e.g. server FQDN or YOUR name)
|
||||
commonName_max = 64
|
||||
|
||||
emailAddress = Email Address
|
||||
emailAddress_max = 64
|
||||
|
||||
# SET-ex3 = SET extension number 3
|
||||
|
||||
[ req_attributes ]
|
||||
challengePassword = A challenge password
|
||||
challengePassword_min = 4
|
||||
challengePassword_max = 20
|
||||
|
||||
unstructuredName = An optional company name
|
||||
|
||||
[ usr_cert ]
|
||||
|
||||
# This is required for TSA certificates.
|
||||
# This is required for client Auth and server Auth
|
||||
extendedKeyUsage = critical,timeStamping,serverAuth,clientAuth
|
||||
|
||||
# These extensions are added when 'ca' signs a request.
|
||||
|
||||
# This goes against PKIX guidelines but some CAs do it and some software
|
||||
# requires this to avoid interpreting an end user certificate as a CA.
|
||||
|
||||
basicConstraints=CA:FALSE
|
||||
|
||||
# Here are some examples of the usage of nsCertType. If it is omitted
|
||||
# the certificate can be used for anything *except* object signing.
|
||||
|
||||
# This is OK for an SSL server.
|
||||
# nsCertType = server
|
||||
|
||||
# For an object signing certificate this would be used.
|
||||
# nsCertType = objsign
|
||||
|
||||
# For normal client use this is typical
|
||||
# nsCertType = client, email
|
||||
|
||||
# and for everything including object signing:
|
||||
# nsCertType = client, email, objsign
|
||||
|
||||
# This is typical in keyUsage for a client certificate.
|
||||
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
|
||||
# This will be displayed in Netscape's comment listbox.
|
||||
nsComment = "OpenSSL Generated Certificate"
|
||||
|
||||
# PKIX recommendations harmless if included in all certificates.
|
||||
subjectKeyIdentifier=hash
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
|
||||
# This stuff is for subjectAltName and issuerAltname.
|
||||
# Import the email address.
|
||||
# subjectAltName=email:copy
|
||||
# An alternative to produce certificates that aren't
|
||||
# deprecated according to PKIX.
|
||||
# subjectAltName=email:move
|
||||
|
||||
# Copy subject details
|
||||
# issuerAltName=issuer:copy
|
||||
|
||||
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
|
||||
#nsBaseUrl
|
||||
#nsRevocationUrl
|
||||
#nsRenewalUrl
|
||||
#nsCaPolicyUrl
|
||||
#nsSslServerName
|
||||
|
||||
[ v3_req ]
|
||||
|
||||
# Extensions to add to a certificate request
|
||||
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
extendedKeyUsage = critical,timeStamping,serverAuth,clientAuth
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[ v3_ca ]
|
||||
|
||||
|
||||
# Extensions for a typical CA
|
||||
|
||||
|
||||
# PKIX recommendation.
|
||||
|
||||
subjectKeyIdentifier=hash
|
||||
|
||||
authorityKeyIdentifier=keyid:always,issuer
|
||||
|
||||
# This is what PKIX recommends but some broken software chokes on critical
|
||||
# extensions.
|
||||
#basicConstraints = critical,CA:true
|
||||
# So we do this instead.
|
||||
basicConstraints = CA:true
|
||||
keyUsage = keyCertSign, cRLSign
|
||||
|
||||
# Key usage: this is typical for a CA certificate. However since it will
|
||||
# prevent it being used as an test self-signed certificate it is best
|
||||
# left out by default.
|
||||
# keyUsage = cRLSign, keyCertSign
|
||||
|
||||
# Some might want this also
|
||||
# nsCertType = sslCA, emailCA
|
||||
|
||||
# Include email address in subject alt name: another PKIX recommendation
|
||||
# subjectAltName=email:copy
|
||||
# Copy issuer details
|
||||
# issuerAltName=issuer:copy
|
||||
|
||||
# DER hex encoding of an extension: beware experts only!
|
||||
# obj=DER:02:03
|
||||
# Where 'obj' is a standard or added object
|
||||
# You can even override a supported extension:
|
||||
# basicConstraints= critical, DER:30:03:01:01:FF
|
||||
|
||||
[ crl_ext ]
|
||||
|
||||
# CRL extensions.
|
||||
# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
|
||||
|
||||
# issuerAltName=issuer:copy
|
||||
authorityKeyIdentifier=keyid:always
|
||||
|
||||
[ proxy_cert_ext ]
|
||||
# These extensions should be added when creating a proxy certificate
|
||||
|
||||
# This goes against PKIX guidelines but some CAs do it and some software
|
||||
# requires this to avoid interpreting an end user certificate as a CA.
|
||||
|
||||
basicConstraints=CA:FALSE
|
||||
|
||||
# Here are some examples of the usage of nsCertType. If it is omitted
|
||||
# the certificate can be used for anything *except* object signing.
|
||||
|
||||
# This is OK for an SSL server.
|
||||
# nsCertType = server
|
||||
|
||||
# For an object signing certificate this would be used.
|
||||
# nsCertType = objsign
|
||||
|
||||
# For normal client use this is typical
|
||||
# nsCertType = client, email
|
||||
|
||||
# and for everything including object signing:
|
||||
# nsCertType = client, email, objsign
|
||||
|
||||
# This is typical in keyUsage for a client certificate.
|
||||
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
|
||||
# This will be displayed in Netscape's comment listbox.
|
||||
nsComment = "OpenSSL Generated Certificate"
|
||||
|
||||
# PKIX recommendations harmless if included in all certificates.
|
||||
subjectKeyIdentifier=hash
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
|
||||
# This stuff is for subjectAltName and issuerAltname.
|
||||
# Import the email address.
|
||||
# subjectAltName=email:copy
|
||||
# An alternative to produce certificates that aren't
|
||||
# deprecated according to PKIX.
|
||||
# subjectAltName=email:move
|
||||
|
||||
# Copy subject details
|
||||
# issuerAltName=issuer:copy
|
||||
|
||||
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
|
||||
#nsBaseUrl
|
||||
#nsRevocationUrl
|
||||
#nsRenewalUrl
|
||||
#nsCaPolicyUrl
|
||||
#nsSslServerName
|
||||
|
||||
# This really needs to be in place for it to be a proxy certificate.
|
||||
proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo
|
||||
|
||||
####################################################################
|
||||
[ tsa ]
|
||||
|
||||
default_tsa = tsa_config1 # the default TSA section
|
||||
|
||||
[ tsa_config1 ]
|
||||
|
||||
# These are used by the TSA reply generation only.
|
||||
dir = ./demoCA # TSA root directory
|
||||
serial = $dir/tsaserial # The current serial number (mandatory)
|
||||
crypto_device = builtin # OpenSSL engine to use for signing
|
||||
signer_cert = $dir/tsacert.pem # The TSA signing certificate
|
||||
# (optional)
|
||||
certs = $dir/cacert.pem # Certificate chain to include in reply
|
||||
# (optional)
|
||||
signer_key = $dir/private/tsakey.pem # The TSA private key (optional)
|
||||
|
||||
default_policy = tsa_policy1 # Policy if request did not specify it
|
||||
# (optional)
|
||||
other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional)
|
||||
digests = md5, sha1 # Acceptable message digests (mandatory)
|
||||
accuracy = secs:1, millisecs:500, microsecs:100 # (optional)
|
||||
clock_precision_digits = 0 # number of digits after dot. (optional)
|
||||
ordering = yes # Is ordering defined for timestamps?
|
||||
# (optional, default: no)
|
||||
tsa_name = yes # Must the TSA name be included in the reply?
|
||||
# (optional, default: no)
|
||||
ess_cert_id_chain = no # Must the ESS cert id chain be included?
|
||||
# (optional, default: no)
|
||||
|
||||
|
||||
[alt_names]
|
||||
IP.1 = 127.0.0.1
|
61
fixtures/ca/server-chain.pem
Normal file
61
fixtures/ca/server-chain.pem
Normal file
@ -0,0 +1,61 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
@ -1,31 +1,31 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
|
@ -1,29 +0,0 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIE8DCCAtgCAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
|
||||
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCAiIwDQYJKoZIhvcN
|
||||
AQEBBQADggIPADCCAgoCggIBAMeYu5Nby4uG4s5HFuky6eiLf7bMiTl4cDomb6ke
|
||||
KMaHuSYN0zEr8jdw4r8TDSguv5MOE3xWSLvQwLgkOQT0N7opDeEqm5Yj458+M9Z5
|
||||
lqYUSshWpnFNUyu8GBCfARB80YCy8dLbYp5ORJ2AWzS5fxtp4TXEf8qlrAMoeJz2
|
||||
ZXMvGHMUuv8TFa3KPAajQ5n2DPSuiFevaDitiRamz6aT48bnOowMO0Enek8UkfpT
|
||||
eR7uh0vOPbWOUIjzuqr7G4MnJkYDyd7R3KscZN4iXf6NRMj2f6V4PGY0WljUbli/
|
||||
fT7bC8IbBgLkQxT8mO7dcJ9QHKteJgdju/9eto3zC3kDC3Yh2RaxfxM1vtmgZm3Q
|
||||
T5oz95QjjskzW1gz2giE45wojbOgnTI+QRtw2EMBX6mzaP/YU6vCvPCqhJ9zrVMs
|
||||
M88EK0TTdkE/NWC25JUmsPXX37Z5jFXIFamM0FWE/zhDip8Xfl3yqAM+NVQ5xnmW
|
||||
GMpqyHn/A1EaRv0ASVTMsg413N3jr815qKy/xSCbyRIFhrBmKkwy0bSZVP+9Y0sC
|
||||
8+bBTZNdbNwrdp0It7BH/xKmG0MaTNpAgVdkbnnSt5DlqS91Sbta5i+kHibkFml4
|
||||
KnZ6OvJgQuTbC+UsbpD5B1vM8Rd264xOQmH9KFNgouDhiBOtwAL3bn+76Pdt8OnM
|
||||
bO0JAgMBAAGgZjBkBgkqhkiG9w0BCQ4xVzBVMAkGA1UdEwQCMAAwCwYDVR0PBAQD
|
||||
AgXgMCoGA1UdJQEB/wQgMB4GCCsGAQUFBwMIBggrBgEFBQcDAQYIKwYBBQUHAwIw
|
||||
DwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQUFAAOCAgEAL5fYwydR3LaAEX0N
|
||||
RNYbAyeunF0oYSKFz7vL3XF+nDHN8WBd49wfApBb9VCEcjINRInC7/i57xNlw4Bw
|
||||
phdQiPGTG4dUdtfMw56n9z47RmZpmMs1sfS3CdPuJFb5NcrLGfBJRjRZ9+UgkbmA
|
||||
+4LP2QHMi4viS3r2DmRhIrKl8Ov+S2TTyY4QdazK4PjtmtqYrB6XeE4I5cT4UsK2
|
||||
6jB32U4JCK7mUwaFenSkMKOSXNKBz4dzM1508WuO8z+lbTQSoUBW6YK89XHzhye3
|
||||
URDlLzSQy0BYZ/J4djpEDbJ/t+52vQrXU/mAbSZMuiRaacVs90b2r8MkYqTH/BCM
|
||||
3e5dtZIk28K27mR54/K0noS46l2TXPbDZIxaCVyaBjw/ogC2FoIEVOcVdISZ7XOj
|
||||
NigTBW1ndBRqXYpKAAlGVV3dIxe54OH7awt+Arn63S9YXprjXn78N6ohl1OMxG/8
|
||||
ES+FAY+0Oly7pOZsbg9W08Ao3CTqW5cobVcQE36ZWO2lahb1w6Ya7B843g7S56WS
|
||||
GatSli9UHN5bUrb135elwwzDixeb/PPnYqBIGG2hOSZJz5oxwnWqxiGR/pApHuRx
|
||||
Beta1BwPNZ897jbZ/M+JuOep52OGsZYKdJ1dDICrVdnSmEUPbS6L3vG6ZH1SdAix
|
||||
LRTenXfl/mlG3QW2aLSn+kjtGW8=
|
||||
-----END CERTIFICATE REQUEST-----
|
@ -1,54 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: DES-EDE3-CBC,34239066AD971D20
|
||||
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
@ -1,51 +1,51 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIJKgIBAAKCAgEAx5i7k1vLi4bizkcW6TLp6It/tsyJOXhwOiZvqR4oxoe5Jg3T
|
||||
MSvyN3DivxMNKC6/kw4TfFZIu9DAuCQ5BPQ3uikN4SqbliPjnz4z1nmWphRKyFam
|
||||
cU1TK7wYEJ8BEHzRgLLx0ttink5EnYBbNLl/G2nhNcR/yqWsAyh4nPZlcy8YcxS6
|
||||
/xMVrco8BqNDmfYM9K6IV69oOK2JFqbPppPjxuc6jAw7QSd6TxSR+lN5Hu6HS849
|
||||
tY5QiPO6qvsbgycmRgPJ3tHcqxxk3iJd/o1EyPZ/pXg8ZjRaWNRuWL99PtsLwhsG
|
||||
AuRDFPyY7t1wn1Acq14mB2O7/162jfMLeQMLdiHZFrF/EzW+2aBmbdBPmjP3lCOO
|
||||
yTNbWDPaCITjnCiNs6CdMj5BG3DYQwFfqbNo/9hTq8K88KqEn3OtUywzzwQrRNN2
|
||||
QT81YLbklSaw9dfftnmMVcgVqYzQVYT/OEOKnxd+XfKoAz41VDnGeZYYymrIef8D
|
||||
URpG/QBJVMyyDjXc3eOvzXmorL/FIJvJEgWGsGYqTDLRtJlU/71jSwLz5sFNk11s
|
||||
3Ct2nQi3sEf/EqYbQxpM2kCBV2RuedK3kOWpL3VJu1rmL6QeJuQWaXgqdno68mBC
|
||||
5NsL5SxukPkHW8zxF3brjE5CYf0oU2Ci4OGIE63AAvduf7vo923w6cxs7QkCAwEA
|
||||
AQKCAgEAlrAifUACTdaKCP32uBxuJ9iZlSKaPz9ES0KVbnKMikYRbD9nwGnTNjQN
|
||||
nAAAIOQaUiWAZJCn3NPfi6YdPjY6lFtGVUZbrGBwCttlO3kUWVJcmx+ADW45an1Z
|
||||
FcNVhGMXsDhpBa4HqEii2N38/bNF2SZ4lqVBbXbihIfbd3U2Zl2Z8dgmzUhVR520
|
||||
77X25ZezdE8INFsDLjcllmpdvv9MKfCMbQsW+TuaxXVcOEco3Eds8bhFMnq9JogL
|
||||
1+Y4gS3fYWCe2ZBLLwwCwwnjOLjiw24GNKCvyOGhjArlPC9lmTy6hdLtGOXIF2IU
|
||||
+9FGo6BR5LbxswaC+mtBG63wbW31CedPjm/3xei8gCGvTsdvPYMbh9gDd4MPTfkU
|
||||
a1zAhTvDWdw46ld7bLbvjNb9h+uvbyEbd7cpsrFxFsqSjLWf5iAgxiZtfDYZaNzz
|
||||
GQuit+Q1uN68ULThfrWZDYfnGOX5RR+A8D4pZgcGtTF/ephRzxEIKhpzIrhACKHr
|
||||
+X1mU7cYbuaVgs278TdP45ZId/02Jfe1hi1vhEHs7upnX0pifBoFWaOg4Qvn8EL0
|
||||
b0LvD8HHOqqW33tw9ZB23UXRyg4xdk3aO93Vc6uVBnPMut4SESt7/BJl/NbwAFIo
|
||||
87hTk7w9a4s1EJNSrlOOiddxc4XP99vFz9ia9+nRsln9R7fxkgECggEBAOjp21OI
|
||||
7IBi1PvPDJluQmU+BF2ZTCiJ0OwqoRX05Lbv/dqAXyFxC5s1Qw986/Mrvh8FZZ1B
|
||||
mLj/xzgT3titpkV7BTKb1jEI34SeJW22mH9X0nr5VYEwS+qBXbG4XyTU8skiks7Y
|
||||
XpsCpAQKCgjChzRJTVZ55+/TDvJ6RpbmKuYrSA+pLe2cIfsDNBNnuIuxLiVh8et/
|
||||
C/W6xDlSDBWv4t+oZvai67KA6uss3wSbop21Gr7n5t4X4798MjUl3Sl4mvoTKrhd
|
||||
X8oZ0t0FuZKNdym62Wjyp/12YRlPFhX72ksaZy/N7g5X3cWnQmKKpDPP+MF6NGtX
|
||||
Y8wM/A9iP0JrxSkCggEBANthdxPg/XgI7eWhsb/Qz/JGeekFimtnHUCIW85yCH+d
|
||||
Kd7kYjFYLcpLPUERIxfhT2v+FTURqOkwnEcuqpnOBGcGj1/ZRs7wYKuwVpVZ1omF
|
||||
Ob8H+mdGHzrPBOZ4FxwHVYYCjaq4Y93worxW/lXWn2t7kUTjnnDQyeCgS7ja8EUg
|
||||
qTxiN4MIMOOxQkvdW+N/QHiqJbdKSe0pFS4K7LvQR73ALv5qdwN5MpzXFNGHABAP
|
||||
1QEpcFXWNvdoXM4DXZPVvg2KuhwGG8URorhaF7RKKk1xFbb9X+jZRLExZKHLO+L1
|
||||
lB4XyxiWSQkBh6ybickc8CfmVny4HzFIFkFTdMugBOECggEBANYhij72d1hhhKYs
|
||||
6Mx2jhw+NA1JTrdGXQmC964UA+IcKiqkMtGv+JetFAY9Nz/NS3GBqLY3BI2wuhtY
|
||||
SVyz6VWfkFvC4d0a50QpkQeZBAKvXxcn+/BV0rW6UcV+WBqonL1GR+pbCj9A4kHE
|
||||
aQ08qsjrS2rhkNbwF6HdwOAio/YQfKPJSixVivgXLd1ZUlU7g81iiuOTXg+Asb5x
|
||||
LCMUHWS6kk7V4hOuakvkaPT3kT2krv4sfhhZpkz5hb9PHFFwTCr1TCVL0zEfJLmG
|
||||
9eFCpfd7jT3rOX7RQtvd1dRIQ50gnRVaIi6VoZKB/4pRJD1uSqi2DVNSeLG0jlgm
|
||||
XzpVkmECggEAWpCW5vb3zIjrJOQmjAg5AEyF4WOvK/2KfuyL8eLzjTMlaOWhf7tm
|
||||
U9/Rrr3TXfVeozdmK91ZfMLbkSs7tHjvKlTz9V6uM5naXqZSaB+JSIZeO3Wgsueo
|
||||
1s9Ft5sV9zUz4jnFoBe06pd/pv7GykrqzyVY6DaLXwlifb/O4sZHcFI2az4kqoxE
|
||||
Gos/0i/U0krjI60iGtOpRyWxn6tU5YfrRfNDszXiYeWztjm4V3NC3F6c0Xj47gab
|
||||
9HD59vY+uFwBtHdzs0P2TNml8jMHHB+N7SBlFYDuCiM/j2LTp1NOKri05+NsrX7F
|
||||
MdmW1/Px4rt2jRIy3BPqlJ6syVUZn0I1IQKCAQEAsLejmPoaWxfDxLxFsdH/bozg
|
||||
89DFvWRVjAoU1EWmVQ6d1DdS2TkG0iLgomoyg8hI6SmJ1cxPZBA9aFSTnomZizxL
|
||||
CfeFV0lIyDwHD/d4gtuG2+los9Y5dwLKI2HT0eFumyMIWdtPRelmzS9rJGXEJjKU
|
||||
YKbDyne6Fn/2HfrUFwVVe1RTg5vN/9nOKQoxP9i9N25GuklHSPRWb0KUSj+qV1rP
|
||||
SHI2wixMm789GLuWZQaH2LntS0tu9IitrTGccXa+CJev06Pw2tQjWrFBAOdp3cZl
|
||||
aJXR3MR1b6bQyOUpoL2hcg/jZhQLup/Y7RPNGNqvV5PMpL7YArpBMd6uhWH1Sg==
|
||||
MIIJKAIBAAKCAgEAyNxL6iay1rJz24wE/BDYjEcgSDYYWn7m4uTW/oJRM5GwtpL9
|
||||
s15FZKZAbmw0cMod3qJkm3cCmJN8s/iKKU++d7XibnkaTD6vQMq//j2ZeGNbRtOC
|
||||
nI3zrzpbOsz7A3x85bkfExO9OSH+cMGbtwXcMc3bcfU9ETsyBIEbdAMbnHuapIPd
|
||||
yFjcTqyK/uCwsWH06b6U1zttJc9CLkDZtTqaPT1aFp+z13Tprgs0htoVtQ3Cqksk
|
||||
D+yJKZQSUtBIaKLyLF2r0pDyibLL0I+92RSAVYCoV7h5jzXa8qWkJArcbKm1XTjp
|
||||
aIyLamE0wwImncEUFpGIAzkkAhiYj6mFScfqx+DJc8UOp/cdqiHJ3pXzK/lRQxHN
|
||||
WLx7tVyzIOW9SJg+gobrWFtEYRSdwkFXUEdouJCfE9Q0iWCyEjDg2bsdXGWlKEi/
|
||||
xJKwuf/DzlmZj/JyVzugOMK2Qxxd9P6lqaPk+T77AOnAAX19Y5HE8TwVxitajmfK
|
||||
06E8aayds3N87mTcUoDN9p843D1IJ+efTIHZdB0eHOCXk2RrHm1psTFppM//wVeH
|
||||
lGhh6gqc0UB392CMcrLwwtl3+M9gJZPAJS0V6e/5LGrXcQLcnPsvPjFgnOjdGGyP
|
||||
c47/nswgakfprtT+U29B3mzxc93TnSKYgt5FPEMjBGoMPLucZYmbOAMcHTcCAwEA
|
||||
AQKCAgBS1vCESKOXgo/f61ae8v+skyUQQyc2I4Jr739wBiUhRKQCGIuDr4ylHyAR
|
||||
qpTSM7mv+X/O0n2CmcljnEy3Dwl568zQTSf4bB3xde1LGPKzwR6DDnaexLjM+x9n
|
||||
F+UqoewM/pV/U7PF3WxH6sGi8UrIS6OG02L1OVm+m9TLuwBnQF8eHLiaiXOLCwRk
|
||||
bBzTe5f70zslrX+tiVY9J0fiw6GbQjNmg0UzxicePcbTGxy6yEsR2t2rp51GRahs
|
||||
+TPz28hPXe6gcGFnQxNmF/JvllH7cY18aDvSQZ7kVkZlCwmv0ypWoUM6eESDgkW1
|
||||
a6yrgVccm7bhxW5BYw2AqqSrMkV0oMcCUjh2rYvex7w6dM374Ok3DD/dXjTHLNV5
|
||||
+0tHMxXUiCKwe7hVEg+iGD4E1jap5n5c4RzpEtAXsGEK5WUBksHi9qOBv+lubjZn
|
||||
Kcfbos+BbnmUCU3MmU48EZwyFQIu9djkLXfJV2Cbbg9HmkrIOYgi4tFjoBKeQLE4
|
||||
6GCucMWnNfMO7Kq/z7c+7sfWOAA55pu0Ojel8VH6US+Y/1mEuSUhQudrJn8GxAmc
|
||||
4t+C2Ie1Q1bK3iJbd0NUqtlwd9xI9wQgCbaxfQceUmBBjuTUu3YFctZ7Jia7h18I
|
||||
gZ3wsKfySDhW29XTFvnT3FUpc+AN9Pv4sB7uobm6qOBV8/AdKQKCAQEA1zwIuJki
|
||||
bSgXxsD4cfKgQsyIk0eMj8bDOlf/A8AFursXliH3rRASoixXNgzWrMhaEIE2BeeT
|
||||
InE13YCUjNCKoz8oZJqKYpjh3o/diZf1vCo6m/YUSR+4amynWE4FEAa58Og2WCJ3
|
||||
Nx8/IMpmch2VZ+hSQuNr5uvpH84+eZADQ1GB6ypzqxb5HjIEeryLJecDQGe4ophd
|
||||
JCo3loezq/K0XJQI8GTBe2GQPjXSmLMZKksyZoWEXAaC1Q+sdJWZvBpm3GfVQbXu
|
||||
q7wyqTMknVIlEOy0sHxstsbayysSFFQ/fcgKjyQb8f4efOkyQg8mH5vQOZghbHJ+
|
||||
7I8wVSSBt+bE2wKCAQEA7udRoo2NIoIpJH+2+SPqJJVq1gw/FHMM4oXNZp+AAjR1
|
||||
hTWcIzIXleMyDATl5ZFzZIY1U2JMifS5u2R7fDZEu9vfZk4e6BJUJn+5/ahjYFU8
|
||||
m8WV4rFWR6XN0SZxPb43Mn6OO7EoMqr8InRufiN4LwIqnPqDm2D9Fdijb9QFJ2UG
|
||||
QLKNnIkLTcUfx1RYP4T48CHkeZdxV8Cp49SzSSV8PbhIVBx32bm/yO6nLHoro7Wl
|
||||
YqXGW0wItf2BUA5a5eYNO0ezVkOkTp2aj/p9i+0rqbsYa480hzlnOzYI5F72Z8V2
|
||||
iPltUAeQn53Vg1azySa1x8/0Xp5nVsgQSh18CH3p1QKCAQBxZv4pVPXgkXlFjTLZ
|
||||
xr5Ns7pZ7x7OOiluuiJw9WGPazgYMDlxA8DtlXM11Tneu4lInOu73LGXOhLpa+/Y
|
||||
6Z/CN2qu5wX2wRpwy1gsQNaGl7FdryAtDvt5h1n8ms7sDL83gQHxGee6MUpvmnSz
|
||||
t4aawrtk5rJZbv7bdS1Rm2E8vNs47psXD/mdwTi++kxOYhNCgeO0N5cLkPrM4x71
|
||||
f+ErzguPrWaL/XGkdXNKZULjF8+sWLjOS9fvLlzs6E2h4D9F7addAeCIt5XxtDKc
|
||||
eUVyT2U8f7I/8zIgTccu0tzJBvcZSCs5K20g3zVNvPGXQd9KGS+zFfht51vN4HhA
|
||||
TuR1AoIBAGuQBKZeexP1bJa9VeF4dRxBldeHrgMEBeIbgi5ZU+YqPltaltEV5Z6b
|
||||
q1XUArpIsZ6p+mpvkKxwXgtsI1j6ihnW1g+Wzr2IOxEWYuQ9I3klB2PPIzvswj8B
|
||||
/NfVKhk1gl6esmVXzxR4/Yp5x6HNUHhBznPdKtITaf+jCXr5B9UD3DvW6IF5Bnje
|
||||
bv9tD0qSEQ71A4xnTiXHXfZxNsOROA4F4bLVGnUR97J9GRGic/GCgFMY9mT2p9lg
|
||||
qQ8lV3G5EW4GS01kqR6oQQXgLxSIFSeXUFhlIq5bfwoeuwQvaVuxgTwMqVXmAgyL
|
||||
oK1ApTPE1QWAsLLFORvOed8UxVqBbn0CggEBALfr/wheXCKLdzFzm03sO1i9qVz2
|
||||
vnpxzexXW3V/TtM6Dff2ojgkDC+CVximtAiLA/Wj60hXnQxw53g5VVT5rESx0J3c
|
||||
pq+azbi1eWzFeOrqJvKQhMfYc0nli7YuGnPkKzeepJJtWZHYkAjL4QZAn1jt0RqV
|
||||
DQmlGPGiOuGP8uh59c23pbjgh4eSJnvhOT2BFKhKZpBdTBYeiQiZBqIyme8rNTFr
|
||||
NmpBxtUr77tccVTrcWWhhViG36UNpetAP7b5QCHScIXZJXrEqyK5HaePqi5UMH8o
|
||||
alSz6s2REG/xP7x54574TvRG/3cIamv1AfZAOjin7BwhlSLhPl2eeh4Cgas=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
@ -1,14 +0,0 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAmmCdKFi6X1mpk5AU6EEH
|
||||
exou9NTRyiQVaHmTQvyPu6rd9krXB47/TgBDXcGIstkhFkGLwAh3cHDEPEF2jEcw
|
||||
W27S+/MvQdVgC4SJaN83pmk6ZYOvr0AX6zmPschoLxl84AT9xKHhFJuH5X1eCzP5
|
||||
DY1rAvNLdB9lFC/DM8m2AySwKHc1kAPhs//j6RPcI8R37yDOEta7e/ikhbAwnOFv
|
||||
/rs3Aob/nYE0ql2CMpO68uU9vbDYQt2bFdiX/zau402Zi9kU1lAaeNBNM0UP9thU
|
||||
/SSOYuDFqy+XbRVvItLhjvo5hP46GOw9GLz9ICQQohiXjC33e4Hs8sq2XkM+jYyk
|
||||
DGRiPEtVwt95x9h/ReCYJowJzJWnaSvQKEPNQaMvwGCV5ZLZ0IlI8cqS3m+ns4ZK
|
||||
gTQDQjeRJADz0JY3jBpBhLebH2HfrYJGp3EWC7CdhhTvYXN5ZkBK6A7xkzPY0mZj
|
||||
RAvS5K417LkAc+G0gO6qyJtXplkL4G/Q07Vdt8zc7ZAg5rbGWY83lw8E/7h0Gpu2
|
||||
JXfANZzdPKiV5P2tB6ZEwdxTABY/kHEk0u0WoPjqqgNv9I/zwLCbjefon8RcIJ5D
|
||||
EXXm9DibcaCpRYUkq5redFXDG8VHVzYVce2CJdrko8GvWUIOsAh0Y4CbyrXgXepV
|
||||
BvDtjEvMJUJ/iI33Ytzi6w0CAwEAAQ==
|
||||
-----END PUBLIC KEY-----
|
@ -1,14 +0,0 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtG+XAmj6VT5CQCiX6wUQ
|
||||
DJb6pM3F1MqJKp4eGKClvK6jXz8gu9clFHPhKWvHWyouN/id7TQ3TBPLeX4MaL2Q
|
||||
jf0GtWuPwuD2ZOV8lDL8klINUgyWL+WeRt+M2WwLeaJEuZhjGootkkfmicSshH5c
|
||||
JMnejiRWTpAzLehHQs9ZbP9yzg+tc1WiwvqOXi1NM7KpYALh20MaUMSVIW6Lvwq5
|
||||
JAIo772x6lW9IVcTxajfYtlZDW9qGD/4n95qBvDqtqSX665UmB+Kfskf5sWyIEKQ
|
||||
4A3i/RAXclhyEwgF5fBDMSr8ek3vcSzbA8a7KCUHQ4aTGm6dnQHtsAlI5Aww0vs2
|
||||
QYi7oc2o5G3YXNfKmJdogxQJVwi+9/ZWoYGlQt77h90u9twej8XozOabF8M0zC8F
|
||||
vU/7Wc84pzvykpY7aao36E653FNt3MCJhRG2MinqjITO+Xcd2B/dRRWYFB7qM/D0
|
||||
KbXtzvLnyJw91ERGjEJJ2E5/BgW6Wz996c/AGExnnf5xFgZ4/Z/dNPpwzNwRSTPZ
|
||||
khlrhdmnQkKjHXJDHLy+uZZ8uj2yCGoTaJEZapEp7GGvsgwi/1DbAvmpwZpfXADW
|
||||
A4x+m6rJJvrOnwui5URcAgj1F+JEW6d2piMmO1mDayiyNEkRpv3jB/Au713SUpm0
|
||||
0GQCHrmrTb5izgCH3ggS75kCAwEAAQ==
|
||||
-----END PUBLIC KEY-----
|
Binary file not shown.
@ -1,31 +1,31 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
|
@ -1,29 +0,0 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIE8DCCAtgCAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
|
||||
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCAiIwDQYJKoZIhvcN
|
||||
AQEBBQADggIPADCCAgoCggIBALRvlwJo+lU+QkAol+sFEAyW+qTNxdTKiSqeHhig
|
||||
pbyuo18/ILvXJRRz4Slrx1sqLjf4ne00N0wTy3l+DGi9kI39BrVrj8Lg9mTlfJQy
|
||||
/JJSDVIMli/lnkbfjNlsC3miRLmYYxqKLZJH5onErIR+XCTJ3o4kVk6QMy3oR0LP
|
||||
WWz/cs4PrXNVosL6jl4tTTOyqWAC4dtDGlDElSFui78KuSQCKO+9sepVvSFXE8Wo
|
||||
32LZWQ1vahg/+J/eagbw6rakl+uuVJgfin7JH+bFsiBCkOAN4v0QF3JYchMIBeXw
|
||||
QzEq/HpN73Es2wPGuyglB0OGkxpunZ0B7bAJSOQMMNL7NkGIu6HNqORt2FzXypiX
|
||||
aIMUCVcIvvf2VqGBpULe+4fdLvbcHo/F6MzmmxfDNMwvBb1P+1nPOKc78pKWO2mq
|
||||
N+hOudxTbdzAiYURtjIp6oyEzvl3Hdgf3UUVmBQe6jPw9Cm17c7y58icPdRERoxC
|
||||
SdhOfwYFuls/fenPwBhMZ53+cRYGeP2f3TT6cMzcEUkz2ZIZa4XZp0JCox1yQxy8
|
||||
vrmWfLo9sghqE2iRGWqRKexhr7IMIv9Q2wL5qcGaX1wA1gOMfpuqySb6zp8LouVE
|
||||
XAII9RfiRFundqYjJjtZg2sosjRJEab94wfwLu9d0lKZtNBkAh65q02+Ys4Ah94I
|
||||
Eu+ZAgMBAAGgZjBkBgkqhkiG9w0BCQ4xVzBVMAkGA1UdEwQCMAAwCwYDVR0PBAQD
|
||||
AgXgMCoGA1UdJQEB/wQgMB4GCCsGAQUFBwMIBggrBgEFBQcDAQYIKwYBBQUHAwIw
|
||||
DwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQUFAAOCAgEARkq8KI9Oy6Hjx83L
|
||||
Kq/+532CEv/vz750uwc3MzejQJYDL9x7tkZR4ujDy1uspCUwAfAmq+EWsj0qMiLS
|
||||
d1GYEEJAxGsWMxj2dRIgCnbXLsS4r08JMxzPVES1kgpiHw0neuT1q7jlfioqoIUG
|
||||
WBMKV3PW4JqcxblBUCZzx0hTeEmvKP/aDikyw57kfUHJZG4P/TUzjBOn+afha7Ly
|
||||
ptpdlNNFEZzmEOttrbu3V/KA2QjQEsN2Q73Sga595OUGaFLFbLtsvQ4Udj16M6gW
|
||||
Z0Ays4XgjItsODS0W/q/InHKCP0dQyuyIb2PrWF5hZ7XcXb+iNExYN4E/WlG4vF6
|
||||
3EVIZPeL4TsPRK4lleQkCDyCfm7Ihrac1fhuzlacSyqz9Fp0fH7COyBltRvjrBPD
|
||||
eqqUWZ5ZmxzT+GEG8tZJCxmMTNF6Lhqrq5n7E3t7kn73q7ikXjmkaVqlOFKR530z
|
||||
Q5EXw6IFRrUnmbZGWdIdPMG3W1bkwYV5hhpytr2LsB7C0QZEu0phPje5eSsuh5SY
|
||||
MX8cVh34T2vVqLURLf53N0cQBOR6UBeTa5YPSTuABlHwsGDEXwQdWGYSVVSFrf+o
|
||||
d0hdZoAbDwXGGximscpQX8t3nUe3R/3lQtem3dxJ+lGq+rxamEgltXnjoOwSXFaU
|
||||
djj5eM7u0qX1tjAezwt7OYAHEco=
|
||||
-----END CERTIFICATE REQUEST-----
|
@ -1,54 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: DES-EDE3-CBC,6357944A31F1FA4D
|
||||
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
@ -1,51 +1,51 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
@ -1,14 +0,0 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtG+XAmj6VT5CQCiX6wUQ
|
||||
DJb6pM3F1MqJKp4eGKClvK6jXz8gu9clFHPhKWvHWyouN/id7TQ3TBPLeX4MaL2Q
|
||||
jf0GtWuPwuD2ZOV8lDL8klINUgyWL+WeRt+M2WwLeaJEuZhjGootkkfmicSshH5c
|
||||
JMnejiRWTpAzLehHQs9ZbP9yzg+tc1WiwvqOXi1NM7KpYALh20MaUMSVIW6Lvwq5
|
||||
JAIo772x6lW9IVcTxajfYtlZDW9qGD/4n95qBvDqtqSX665UmB+Kfskf5sWyIEKQ
|
||||
4A3i/RAXclhyEwgF5fBDMSr8ek3vcSzbA8a7KCUHQ4aTGm6dnQHtsAlI5Aww0vs2
|
||||
QYi7oc2o5G3YXNfKmJdogxQJVwi+9/ZWoYGlQt77h90u9twej8XozOabF8M0zC8F
|
||||
vU/7Wc84pzvykpY7aao36E653FNt3MCJhRG2MinqjITO+Xcd2B/dRRWYFB7qM/D0
|
||||
KbXtzvLnyJw91ERGjEJJ2E5/BgW6Wz996c/AGExnnf5xFgZ4/Z/dNPpwzNwRSTPZ
|
||||
khlrhdmnQkKjHXJDHLy+uZZ8uj2yCGoTaJEZapEp7GGvsgwi/1DbAvmpwZpfXADW
|
||||
A4x+m6rJJvrOnwui5URcAgj1F+JEW6d2piMmO1mDayiyNEkRpv3jB/Au713SUpm0
|
||||
0GQCHrmrTb5izgCH3ggS75kCAwEAAQ==
|
||||
-----END PUBLIC KEY-----
|
@ -1,3 +1,3 @@
|
||||
// +build !go1.1
|
||||
// +build !go1.2
|
||||
|
||||
"etcd requires go 1.1 or greater to build"
|
||||
"etcd requires go 1.2 or greater to build"
|
||||
|
79
http/cors.go
Normal file
79
http/cors.go
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
Copyright 2013 CoreOS Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type CORSInfo map[string]bool
|
||||
|
||||
func NewCORSInfo(origins []string) (*CORSInfo, error) {
|
||||
// Construct a lookup of all origins.
|
||||
m := make(map[string]bool)
|
||||
for _, v := range origins {
|
||||
if v != "*" {
|
||||
if _, err := url.Parse(v); err != nil {
|
||||
return nil, fmt.Errorf("Invalid CORS origin: %s", err)
|
||||
}
|
||||
}
|
||||
m[v] = true
|
||||
}
|
||||
|
||||
info := CORSInfo(m)
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
// OriginAllowed determines whether the server will allow a given CORS origin.
|
||||
func (c CORSInfo) OriginAllowed(origin string) bool {
|
||||
return c["*"] || c[origin]
|
||||
}
|
||||
|
||||
type CORSHandler struct {
|
||||
Handler http.Handler
|
||||
Info *CORSInfo
|
||||
}
|
||||
|
||||
// addHeader adds the correct cors headers given an origin
|
||||
func (h *CORSHandler) addHeader(w http.ResponseWriter, origin string) {
|
||||
w.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
|
||||
w.Header().Add("Access-Control-Allow-Origin", origin)
|
||||
}
|
||||
|
||||
// ServeHTTP adds the correct CORS headers based on the origin and returns immediately
|
||||
// with a 200 OK if the method is OPTIONS.
|
||||
func (h *CORSHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
// It is important to flush before leaving the goroutine.
|
||||
// Or it may miss the latest info written.
|
||||
defer w.(http.Flusher).Flush()
|
||||
|
||||
// Write CORS header.
|
||||
if h.Info.OriginAllowed("*") {
|
||||
h.addHeader(w, "*")
|
||||
} else if origin := req.Header.Get("Origin"); h.Info.OriginAllowed(origin) {
|
||||
h.addHeader(w, origin)
|
||||
}
|
||||
|
||||
if req.Method == "OPTIONS" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
h.Handler.ServeHTTP(w, req)
|
||||
}
|
36
http/query_params.go
Normal file
36
http/query_params.go
Normal file
@ -0,0 +1,36 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func NewLowerQueryParamsHandler(hdlr http.Handler) *LowerQueryParamsHandler {
|
||||
return &LowerQueryParamsHandler{hdlr}
|
||||
}
|
||||
|
||||
type LowerQueryParamsHandler struct {
|
||||
Handler http.Handler
|
||||
}
|
||||
|
||||
func (h *LowerQueryParamsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
err := req.ParseForm()
|
||||
if err == nil {
|
||||
lowerBoolQueryParams(req)
|
||||
}
|
||||
h.Handler.ServeHTTP(w, req)
|
||||
}
|
||||
|
||||
func lowerBoolQueryParams(req *http.Request) {
|
||||
form := req.Form
|
||||
for key, vals := range form {
|
||||
for i, val := range vals {
|
||||
lowered := strings.ToLower(val)
|
||||
if lowered == "true" || lowered == "false" {
|
||||
req.Form[key][i] = lowered
|
||||
} else {
|
||||
req.Form[key][i] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
46
http/query_params_test.go
Normal file
46
http/query_params_test.go
Normal file
@ -0,0 +1,46 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type NilResponseWriter struct{}
|
||||
|
||||
func (w NilResponseWriter) Header() http.Header {
|
||||
return http.Header{}
|
||||
}
|
||||
|
||||
func (w NilResponseWriter) Write(data []byte) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (w NilResponseWriter) WriteHeader(code int) {
|
||||
return
|
||||
}
|
||||
|
||||
type FunctionHandler struct {
|
||||
f func(*http.Request)
|
||||
}
|
||||
|
||||
func (h FunctionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
h.f(r)
|
||||
}
|
||||
|
||||
func TestQueryParamsLowered(t *testing.T) {
|
||||
assertFunc := func(req *http.Request) {
|
||||
if len(req.Form["One"]) != 1 || req.Form["One"][0] != "true" {
|
||||
t.Errorf("Unexpected value for One: %s", req.Form["One"])
|
||||
} else if len(req.Form["TWO"]) != 1 || req.Form["TWO"][0] != "false" {
|
||||
t.Errorf("Unexpected value for TWO")
|
||||
} else if len(req.Form["three"]) != 2 || req.Form["three"][0] != "true" || req.Form["three"][1] != "false" {
|
||||
t.Errorf("Unexpected value for three")
|
||||
}
|
||||
}
|
||||
assertHdlr := FunctionHandler{assertFunc}
|
||||
hdlr := NewLowerQueryParamsHandler(assertHdlr)
|
||||
respWriter := NilResponseWriter{}
|
||||
|
||||
req, _ := http.NewRequest("GET", "http://example.com?One=TRUE&TWO=False&three=true&three=FALSE", nil)
|
||||
hdlr.ServeHTTP(respWriter, req)
|
||||
}
|
45
log/log.go
Normal file
45
log/log.go
Normal file
@ -0,0 +1,45 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
golog "github.com/coreos/etcd/third_party/github.com/coreos/go-log/log"
|
||||
)
|
||||
|
||||
// The Verbose flag turns on verbose logging.
|
||||
var Verbose bool = false
|
||||
|
||||
var logger *golog.Logger = golog.New("etcd", false,
|
||||
golog.CombinedSink(os.Stdout, "[%s] %s %-9s | %s\n", []string{"prefix", "time", "priority", "message"}))
|
||||
|
||||
func Infof(format string, v ...interface{}) {
|
||||
logger.Infof(format, v...)
|
||||
}
|
||||
|
||||
func Debugf(format string, v ...interface{}) {
|
||||
if Verbose {
|
||||
logger.Debugf(format, v...)
|
||||
}
|
||||
}
|
||||
|
||||
func Debug(v ...interface{}) {
|
||||
if Verbose {
|
||||
logger.Debug(v...)
|
||||
}
|
||||
}
|
||||
|
||||
func Warnf(format string, v ...interface{}) {
|
||||
logger.Warningf(format, v...)
|
||||
}
|
||||
|
||||
func Warn(v ...interface{}) {
|
||||
logger.Warning(v...)
|
||||
}
|
||||
|
||||
func Fatalf(format string, v ...interface{}) {
|
||||
logger.Fatalf(format, v...)
|
||||
}
|
||||
|
||||
func Fatal(v ...interface{}) {
|
||||
logger.Fatalln(v...)
|
||||
}
|
42
machines.go
42
machines.go
@ -1,42 +0,0 @@
|
||||
package main
|
||||
|
||||
// machineNum returns the number of machines in the cluster
|
||||
func machineNum() int {
|
||||
response, _ := etcdStore.RawGet("_etcd/machines")
|
||||
|
||||
return len(response)
|
||||
}
|
||||
|
||||
// getMachines gets the current machines in the cluster
|
||||
func getMachines() []string {
|
||||
|
||||
peers := r.Peers()
|
||||
|
||||
machines := make([]string, len(peers)+1)
|
||||
|
||||
leader, ok := nameToEtcdURL(r.Leader())
|
||||
self := e.url
|
||||
i := 1
|
||||
|
||||
if ok {
|
||||
machines[0] = leader
|
||||
if leader != self {
|
||||
machines[1] = self
|
||||
i = 2
|
||||
}
|
||||
} else {
|
||||
machines[0] = self
|
||||
}
|
||||
|
||||
// Add all peers to the slice
|
||||
for peerName, _ := range peers {
|
||||
if machine, ok := nameToEtcdURL(peerName); ok {
|
||||
// do not add leader twice
|
||||
if machine != leader {
|
||||
machines[i] = machine
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
return machines
|
||||
}
|
44
main.go
Normal file
44
main.go
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright 2013 CoreOS Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/coreos/etcd/config"
|
||||
"github.com/coreos/etcd/etcd"
|
||||
"github.com/coreos/etcd/server"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var config = config.New()
|
||||
if err := config.Load(os.Args[1:]); err != nil {
|
||||
fmt.Println(server.Usage() + "\n")
|
||||
fmt.Println(err.Error() + "\n")
|
||||
os.Exit(1)
|
||||
} else if config.ShowVersion {
|
||||
fmt.Println("etcd version", server.ReleaseVersion)
|
||||
os.Exit(0)
|
||||
} else if config.ShowHelp {
|
||||
fmt.Println(server.Usage() + "\n")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
var etcd = etcd.New(config)
|
||||
etcd.Run()
|
||||
}
|
42
metrics/metrics.go
Normal file
42
metrics/metrics.go
Normal file
@ -0,0 +1,42 @@
|
||||
// Package metrics provides both a means of generating metrics and the ability
|
||||
// to send metric data to a graphite endpoint.
|
||||
// The usage of this package without providing a graphite_addr when calling
|
||||
// NewBucket results in NOP metric objects. No data will be collected.
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
gometrics "github.com/coreos/etcd/third_party/github.com/rcrowley/go-metrics"
|
||||
)
|
||||
|
||||
type Timer gometrics.Timer
|
||||
type Gauge gometrics.Gauge
|
||||
|
||||
type Bucket interface {
|
||||
// If a timer exists in this Bucket, return it. Otherwise, create
|
||||
// a new timer with the given name and store it in this Bucket.
|
||||
// The returned object will fulfull the Timer interface.
|
||||
Timer(name string) Timer
|
||||
|
||||
// This acts similarly to Timer, but with objects that fufill the
|
||||
// Gauge interface.
|
||||
Gauge(name string) Gauge
|
||||
|
||||
// Write the current state of all Metrics in a human-readable format
|
||||
// to the provide io.Writer.
|
||||
Dump(io.Writer)
|
||||
|
||||
// Instruct the Bucket to periodically push all metric data to the
|
||||
// provided graphite endpoint.
|
||||
Publish(string) error
|
||||
}
|
||||
|
||||
// Create a new Bucket object that periodically
|
||||
func NewBucket(name string) Bucket {
|
||||
if name == "" {
|
||||
return nilBucket{}
|
||||
}
|
||||
|
||||
return newStandardBucket(name)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user