Compare commits
957 commits
Author | SHA1 | Date | |
---|---|---|---|
a47660a1e5 | |||
3575d65ffb | |||
|
938a29ed96 | ||
|
ff58ecd5f2 | ||
|
df6b78c4ed | ||
|
4d53acb9fb | ||
|
b88d50fb68 | ||
4e3306ed74 | |||
|
c167ac7f83 | ||
|
a112b072aa | ||
|
f750bf406c | ||
|
2a5510b34c | ||
|
a1aa60ded5 | ||
|
61c921ac6f | ||
|
437b5e7a2e | ||
|
2c2630a788 | ||
|
5a1f6ab2cb | ||
|
f71de429a1 | ||
|
50cbe5a0d6 | ||
|
44eefd81fb | ||
|
a84f8b59bf | ||
|
c1dd7baf2a | ||
|
8a1e1863a7 | ||
|
b812a6934a | ||
|
8cfe577b17 | ||
|
dd24cdc3d6 | ||
|
208edd49e5 | ||
|
484b868100 | ||
|
b5f2a9006c | ||
|
2e20f96fec | ||
|
d3409ace2a | ||
|
530a899467 | ||
|
9e215ae1a1 | ||
|
8fa42b1ab4 | ||
|
2ae84fcc51 | ||
|
582e3b368a | ||
|
6738febaa2 | ||
|
49ebf3488e | ||
|
bd42317ec2 | ||
|
1c27047f4b | ||
|
fef11bf7ef | ||
|
c74ddbf2fc | ||
|
2b08ae199f | ||
|
aa777653f4 | ||
|
7e1eb1d373 | ||
|
4ff412e2d2 | ||
|
bd4aa8167c | ||
|
2423464cdb | ||
|
0b5087f72e | ||
|
c8801ba8b2 | ||
|
97b5882262 | ||
|
6eb7ec1a2e | ||
|
fe7d638b35 | ||
|
f8a78e520b | ||
|
dbf2dfb8ff | ||
|
d3788f55f3 | ||
|
f224fc5ea5 | ||
|
1c64ea1b2c | ||
|
b96ba86f72 | ||
|
8b93206c18 | ||
|
e4c566ebc9 | ||
|
d35ee4aed0 | ||
|
03c23d7df8 | ||
|
10c53c54d7 | ||
|
2ce460bc30 | ||
|
553f1b5ed0 | ||
|
1f805f6deb | ||
|
43aa9bfb3e | ||
|
851f58d42a | ||
|
fdb7222965 | ||
|
4fd0635204 | ||
|
ae18c05b2b | ||
|
6d8580a294 | ||
|
cac4910296 | ||
|
2d63603d85 | ||
|
a68a1de21f | ||
|
671bd55cea | ||
|
1c2208a30e | ||
|
0cdd4d352c | ||
|
62535b6465 | ||
|
932a7808be | ||
|
9dd12bfcdf | ||
|
6dcf584b25 | ||
|
544c061e65 | ||
|
848383e081 | ||
|
d4e5122c6c | ||
|
aa5fb7a932 | ||
|
81d70d26d3 | ||
|
4c969a6ae7 | ||
|
1fb64dbbdf | ||
|
d11b6f2dc7 | ||
|
ad39aa9645 | ||
|
050c160de2 | ||
|
3d924985dd | ||
|
95bfdfd54d | ||
|
25d10cd3bc | ||
|
86381bfeee | ||
|
7c778dfb4d | ||
|
9e5637a9fe | ||
|
3257bd25bb | ||
|
06bbc7a5ef | ||
|
6136ebb966 | ||
|
9b70f3daab | ||
|
2accd886fa | ||
|
993e430ccc | ||
|
ea99d13f76 | ||
|
fddd8cc257 | ||
|
611a86ce84 | ||
|
e5a55d1020 | ||
|
64f561073c | ||
|
0c353598f8 | ||
|
78ef85aa97 | ||
|
366a98a052 | ||
|
40ced9d3d1 | ||
|
bbff802b5d | ||
|
eb503e42fd | ||
|
5329e8837e | ||
|
d2c032a073 | ||
|
7eb3be37de | ||
|
31bb4eadf9 | ||
|
5fb0bcbcbc | ||
|
eba671c54d | ||
|
4b78c04a47 | ||
|
9c67e13fb8 | ||
|
5cd32c76df | ||
|
2b91983cae | ||
|
64240323f0 | ||
|
6718fed241 | ||
|
81f2c13541 | ||
|
c3508870fd | ||
|
fb661300e7 | ||
|
bb21906ec4 | ||
|
0365ad4a17 | ||
|
fd22ccc073 | ||
|
52cca8e7f6 | ||
|
55bbadef6f | ||
|
f52df5df14 | ||
|
8cb0afeb39 | ||
|
8ccafecd9e | ||
|
497f750248 | ||
|
caa3c53a8f | ||
|
7d017ada1e | ||
|
05fdb3e000 | ||
|
5da3fc8be5 | ||
|
c9cd671a32 | ||
|
3b45b92d1a | ||
|
156bc015c8 | ||
|
fb23e606cc | ||
|
ef06ea622e | ||
|
7a09375ae7 | ||
|
f4b738ebd9 | ||
|
555499d04a | ||
|
447d0dfc42 | ||
|
bf3a9a5039 | ||
|
28bdbe371d | ||
|
758703ea6b | ||
|
01d53a783c | ||
|
8b37056294 | ||
|
2a667b88b6 | ||
|
2a48f366d4 | ||
|
92685472ec | ||
|
67523019aa | ||
|
fe532525c8 | ||
|
188a1eb089 | ||
|
622366bd64 | ||
|
2f0eccb236 | ||
|
71e210f683 | ||
|
186d453621 | ||
|
80ca559258 | ||
|
b4a642bc8a | ||
|
8421291c52 | ||
|
dc55c914e4 | ||
|
f454924a59 | ||
|
e76a18185c | ||
|
5fa6f0dd09 | ||
|
5e155ec02e | ||
|
dd5a8d16d0 | ||
|
8ffc9ef92a | ||
|
86b169d358 | ||
|
46640fbd3d | ||
|
e297ea52b2 | ||
|
ec4a52559a | ||
|
96b2c7175a | ||
|
3f7c7ecabf | ||
|
0a017e476d | ||
|
80d54bb261 | ||
|
aac8c31410 | ||
|
d0642c95fd | ||
|
d3b9d53097 | ||
|
752fa9b4e5 | ||
|
95b18a5d5c | ||
|
89f3e98679 | ||
|
a3252c3593 | ||
|
5232f2c7b1 | ||
|
d22d6588f8 | ||
|
0bd071f95d | ||
|
044322d70f | ||
|
09f855dc76 | ||
|
b4376ef995 | ||
|
3e22f424e6 | ||
|
212d31543e | ||
|
a284d66f9e | ||
|
e52ba97b13 | ||
|
235f268942 | ||
|
4cb28b88c6 | ||
|
f49585db51 | ||
|
3fe6cc094e | ||
|
a4768c26ca | ||
|
3a4c0ca79d | ||
|
8eabac91d6 | ||
|
7bccdd2f71 | ||
|
be0b1a2abc | ||
|
2db9aa89a1 | ||
|
4d45a4082b | ||
|
d7935e55f3 | ||
|
9111261f79 | ||
|
c94e765391 | ||
|
c580865ab2 | ||
|
1cf8ce50e4 | ||
|
638e134265 | ||
|
8e9abe9129 | ||
|
e1a29898a4 | ||
|
6b5c00089d | ||
|
b210b260b1 | ||
|
3bd22955dd | ||
|
5eef1524d7 | ||
|
b17fb7baa8 | ||
|
856a847bc8 | ||
|
4c3143aa34 | ||
|
529558e8b0 | ||
|
7870d59184 | ||
|
9838d32c2d | ||
|
a0fe2f9cf0 | ||
|
84bdb5cb22 | ||
|
ee63d2b2ae | ||
|
127b23c66c | ||
|
1688a79efc | ||
|
251dec55fe | ||
|
80171fcf90 | ||
|
9dbd5e409f | ||
|
b288c05921 | ||
|
0b1fffc6e3 | ||
|
a9248cb697 | ||
|
3b311ad840 | ||
|
2666f9e38d | ||
|
0eae5c0926 | ||
|
94e175dc07 | ||
|
9f9cb1c791 | ||
|
47cf361b98 | ||
|
8c6e9724bd | ||
|
bc6e2e9d7c | ||
|
b35e5dbb55 | ||
|
69ba4d8f70 | ||
|
2260282a7c | ||
|
d8d371984b | ||
|
7e9d790f6a | ||
|
9b6d1bb117 | ||
|
6508324d6d | ||
|
36b38b7664 | ||
|
962d87b72e | ||
|
457e75ca96 | ||
|
12df76752d | ||
|
5d255dec30 | ||
|
c13f4591b1 | ||
|
328477172e | ||
|
697d8bde08 | ||
|
28bd6c87ef | ||
|
5a56b72360 | ||
|
77beb13906 | ||
|
c7c1d8a1c6 | ||
|
8b1573c536 | ||
|
17a6a35c92 | ||
|
64de0fca3c | ||
|
02fefd10c0 | ||
|
19bccc9ca5 | ||
|
b7dbfc84af | ||
|
674e0cef4e | ||
|
c2d0e0a02c | ||
|
41716e9100 | ||
|
164afc7839 | ||
|
44ad630db7 | ||
|
dd31e1f74a | ||
|
a8a2f55f21 | ||
|
9849426078 | ||
|
fd948f8552 | ||
|
8590c87132 | ||
|
2e2c2fad56 | ||
|
60f3a67bb0 | ||
|
2cdbf84848 | ||
|
eb274e879c | ||
|
64fbe180f1 | ||
|
ebdf50297f | ||
|
4f49be03ad | ||
|
da96e8c1a4 | ||
|
d6a22c9f88 | ||
|
d0be2f3dbe | ||
|
20d4547044 | ||
|
623eb1570a | ||
|
03907eeb62 | ||
|
c9fe9e552e | ||
|
ad63452651 | ||
|
5df28390e2 | ||
|
dfd93d087c | ||
|
bfb9b6be73 | ||
|
c69b1bd014 | ||
|
e3f0e6df32 | ||
|
be12f11ced | ||
|
5b24cf6136 | ||
|
7e79d59365 | ||
|
e84f9e2b4a | ||
|
2f401b5b6c | ||
|
f20f6aaa40 | ||
|
14430908f8 | ||
|
c48261a5e5 | ||
|
0aac50fa76 | ||
|
165f647c2d | ||
|
38ae9441fc | ||
|
100d5223ce | ||
|
61002b9bb8 | ||
|
35741ba5c5 | ||
|
803e446dc5 | ||
|
71b02ab511 | ||
|
9288d1e56c | ||
|
fb58d6c878 | ||
|
23e82594e1 | ||
|
5c6855eb4c | ||
|
f2c1f70cc7 | ||
|
f67c6a1f31 | ||
|
35feb11367 | ||
|
37ffd4e477 | ||
|
36f7daa528 | ||
|
320a698f49 | ||
|
bb8514b518 | ||
|
d5abb523de | ||
|
056e47d364 | ||
|
8f1b54395e | ||
|
a0acc571b2 | ||
|
891403f10d | ||
|
fca401ac50 | ||
|
4fbd7c0182 | ||
|
f5661280bc | ||
|
1072a42ed2 | ||
|
aef40d5b42 | ||
|
10599a5ba7 | ||
|
40fd5a2faf | ||
|
b5a0a8de6f | ||
|
5422d272d2 | ||
|
6fbe048175 | ||
|
2c0b2bd026 | ||
|
28c5df5132 | ||
|
735475d333 | ||
|
438ef64c25 | ||
|
b0372a10c0 | ||
|
0ae0288af9 | ||
|
b82e86cb8e | ||
|
cfa1d2e02f | ||
|
82b49b7242 | ||
|
4f5d95b7f3 | ||
|
deac5930cc | ||
|
d5faf1db66 | ||
|
02a65820bf | ||
|
2c934d4ec4 | ||
|
d0939622a5 | ||
|
c7f5a567a9 | ||
|
85d36bfd41 | ||
|
ff3baf1cd4 | ||
|
74cf06b148 | ||
|
2c7e6fb600 | ||
|
e69441a99b | ||
|
7effe1f092 | ||
|
e598086913 | ||
|
a7074545ed | ||
|
3ff6046228 | ||
|
cd23804046 | ||
|
dbb6d1f131 | ||
|
921e08bdb4 | ||
|
1b8fb6137b | ||
|
8d3d84aef2 | ||
|
f927f65ec1 | ||
|
4a18c7a05a | ||
|
3b1055c843 | ||
|
420a49c870 | ||
|
8fec240ae6 | ||
|
bd9b2e8957 | ||
|
dce843db12 | ||
|
12bc88805a | ||
|
f070e9ec5b | ||
|
1d28e3d213 | ||
|
1d3e3901c7 | ||
|
773e717fd9 | ||
|
bba250255a | ||
|
9ed8f0c205 | ||
|
b7c29be732 | ||
|
774e8175eb | ||
|
ba2569c222 | ||
|
c2f4cfda4f | ||
|
7ef475c7e1 | ||
|
910a6c54ba | ||
|
4a84d95ff2 | ||
|
d391e840cc | ||
|
39a5946399 | ||
|
6704cd9869 | ||
|
46e77bf9e5 | ||
|
f8021b3f31 | ||
|
11cebb5bf7 | ||
|
b5c7a50a74 | ||
|
186b01e192 | ||
|
44f00bd7ed | ||
|
005140099c | ||
|
70a92132d7 | ||
|
2fbbd56891 | ||
|
13e7ffedea | ||
|
95e111c322 | ||
|
5db318d26f | ||
|
6e7ab85dad | ||
|
7e00b96520 | ||
|
786bb8a3fe | ||
|
e3b8ead93b | ||
|
2be86bb7d0 | ||
|
20a558097c | ||
|
b34dd7d8e7 | ||
|
ffb573a7f1 | ||
|
1083f100ad | ||
|
6d7bf5d188 | ||
|
a436e30214 | ||
|
c19bc91e70 | ||
|
6066d22ad9 | ||
|
0e759e681b | ||
|
c7fff4d935 | ||
|
d8a8dbaa9b | ||
|
e4e4551aea | ||
|
9b7491c2e8 | ||
|
6779556650 | ||
|
324cddcb9d | ||
|
06d43df632 | ||
|
f7e62c0324 | ||
|
bf70156395 | ||
|
6cba594f44 | ||
|
61f7b73f2a | ||
|
3d017ce3bd | ||
|
4a9e4b3394 | ||
|
366d1dc3a5 | ||
|
3215b99534 | ||
|
afd302529c | ||
|
b86b83eba1 | ||
|
0e57cfc2b0 | ||
|
6428da893b | ||
|
bf6e4b5c89 | ||
|
6b5db24a6b | ||
|
c61ade8ef4 | ||
|
f8bd5bf40a | ||
|
c8f379c764 | ||
|
02f85e4e59 | ||
|
1c5c73b08a | ||
|
86083fbe36 | ||
|
4a3d5d827e | ||
|
1d9af8f0af | ||
|
24daffc92c | ||
|
744b4331d7 | ||
|
2790261e58 | ||
|
ecdf83e1c7 | ||
|
17ae9ac403 | ||
|
f52835cb58 | ||
|
4ca375ec50 | ||
|
b5f21f268a | ||
|
5a6b2791e4 | ||
|
2b062487bc | ||
|
5833e262aa | ||
|
9e3b371e11 | ||
|
3375a9c40c | ||
|
225af56227 | ||
|
a9d7dff53a | ||
|
86be628cf2 | ||
|
4c5f9c9e49 | ||
|
0cb430a4ca | ||
|
39515cc1da | ||
|
c5a89a54ce | ||
|
23e25c40ab | ||
|
add4908912 | ||
|
7bca20a166 | ||
|
bdedae40b2 | ||
|
79006095f5 | ||
|
0f1239a1e3 | ||
|
b928aa8901 | ||
|
c194b3a24a | ||
|
8bcb8b5328 | ||
|
79aa4d8866 | ||
|
ca0d8d53a5 | ||
|
f9dd5392ff | ||
|
a087023365 | ||
|
175c40765a | ||
|
18bb9482d5 | ||
|
c76df6358c | ||
|
6bbc7c5e91 | ||
|
a6c95bff50 | ||
|
ecc862f6cb | ||
|
bcfb7b3e00 | ||
|
cd53ad2efd | ||
|
019c23b74b | ||
|
0330ec55e1 | ||
|
a6bd483275 | ||
|
93ba8414bf | ||
|
24b814122b | ||
|
d44d067ad8 | ||
|
7511ee41f0 | ||
|
2e5e5920d7 | ||
|
2116737989 | ||
|
6b823e8dcb | ||
|
9b20771bde | ||
|
6680858184 | ||
|
518cd3cbe3 | ||
|
aa8638ed20 | ||
|
d02a9d575f | ||
|
bda01dbc4d | ||
|
1af1c91d90 | ||
|
d803119f50 | ||
|
2c0000b8cc | ||
|
5f42f2b4dd | ||
|
c49dfc59ea | ||
|
22040ba4c2 | ||
|
0f31b51e2d | ||
|
2f3d1c27ce | ||
|
50e82f61b1 | ||
|
076a9e38df | ||
|
e1f91efc3a | ||
|
7efef2a489 | ||
|
379b030f64 | ||
|
37aeabbeff | ||
|
03b262319f | ||
|
61e7cbce42 | ||
|
739e602794 | ||
|
a1c7a4ece0 | ||
|
dbc6c8b231 | ||
|
bcdb4ca5bd | ||
|
4eb066a076 | ||
|
59c5a1e144 | ||
|
3f99124117 | ||
|
660fb3f6c4 | ||
|
e4ee20c7ad | ||
|
cf73a843d0 | ||
|
791a93fe9e | ||
|
1da7b60cd8 | ||
|
f13806626c | ||
|
2064dbf05a | ||
|
7f3f7b1558 | ||
|
7bd738aa8e | ||
|
05c472042d | ||
|
e5790d3ad1 | ||
|
ce3e061cae | ||
|
2c32f1caa6 | ||
|
6a7535843f | ||
|
ce581b426d | ||
|
36b67f2d35 | ||
|
5c53e52ea1 | ||
|
8fcb6d2a06 | ||
|
5c6556f08b | ||
|
280702061d | ||
|
5ae82681cd | ||
|
5eaf0a26bf | ||
|
e615c55ad4 | ||
|
a31b784377 | ||
|
1f3d3ead92 | ||
|
5b088ebd17 | ||
|
b5378c7c42 | ||
|
1ef2c5bcad | ||
|
4bb70fb252 | ||
|
b301ee8e0f | ||
|
2082a5a81d | ||
|
c4429fa158 | ||
|
5f102d3e10 | ||
|
251fe68035 | ||
|
23f531b38c | ||
|
0385a64d31 | ||
|
b374bba4ec | ||
|
ae7a3b0795 | ||
|
e1f756cdc3 | ||
|
97f6edeed8 | ||
|
dee099ce96 | ||
|
7f58f7a26e | ||
|
14e8c41ee0 | ||
|
d62a053674 | ||
|
98f1df47a1 | ||
|
2dbfd23915 | ||
|
d2e354839f | ||
|
bff0f8019b | ||
|
258c822a54 | ||
|
9058c5763c | ||
|
681c490cdc | ||
|
e68e4f8f05 | ||
|
900db67d10 | ||
|
c7087a6802 | ||
|
ee37b9e2e7 | ||
|
9207ed49ba | ||
|
d2d131cefb | ||
|
5b5719295d | ||
|
ef3b97dff8 | ||
|
7ceed8d6d9 | ||
|
72555fdeb5 | ||
|
eb0854b6fb | ||
|
17211387d0 | ||
|
041f185395 | ||
|
a2a9cb99d1 | ||
|
ad41c445a4 | ||
|
003de9476a | ||
|
494bc07e5f | ||
|
e3597e08a7 | ||
|
4598644143 | ||
|
09208a0d28 | ||
|
c14ca57d17 | ||
|
4bd6bffcb6 | ||
|
0e66eb675b | ||
|
4bbbb4cbf6 | ||
|
e504ce3e8d | ||
|
e3665f88ae | ||
|
6c52ef8255 | ||
|
78499202b6 | ||
|
b97081be0d | ||
|
e4504090f8 | ||
|
1348bb910b | ||
|
3e73a85d52 | ||
|
b8b545c277 | ||
|
8dc0d09632 | ||
|
e10822df32 | ||
|
44bedfe7c6 | ||
|
ecfa53970f | ||
|
16c8ff9013 | ||
|
14c1ebfd7c | ||
|
8006766691 | ||
|
c3e6eb4e51 | ||
|
36f8472614 | ||
|
198ef66cad | ||
|
288308ce91 | ||
|
123c3afda4 | ||
|
027fa8a347 | ||
|
83377bf8a4 | ||
|
f3ff5c9f24 | ||
|
1c5727dd7b | ||
|
8512c5ace7 | ||
|
51d26b00cd | ||
|
a5eb824fa4 | ||
|
7bd9377fa6 | ||
|
433cf3f9df | ||
|
dcc0ce281f | ||
|
b8d58d8a13 | ||
|
e4e64d69eb | ||
|
93003caec3 | ||
|
e159a9b534 | ||
|
8e51384802 | ||
|
58435e3462 | ||
|
bb51a51ecb | ||
|
06f2063d53 | ||
|
1bef25364a | ||
|
70f3b90f6f | ||
|
1bb2bc244a | ||
|
d61d029333 | ||
|
ed4a8ae729 | ||
|
cb1f72923a | ||
|
5c2973108b | ||
|
75a2d0c65d | ||
|
c6af4fab08 | ||
|
663ff1fc0d | ||
|
ba7bc580f5 | ||
|
aca88e2407 | ||
|
5eb15d8667 | ||
|
ba92ca171b | ||
|
d9f5e672f4 | ||
|
c2bf4229a3 | ||
|
e0473a1567 | ||
|
6d0dc0877b | ||
|
c7f8611480 | ||
|
0df24c795d | ||
|
ea467db17c | ||
|
d7ab06df16 | ||
|
709f09bdc9 | ||
|
5df2fc1c71 | ||
|
46904874fe | ||
|
88440f6c62 | ||
|
035b87d0a7 | ||
|
86be140f86 | ||
|
4e53cc83fe | ||
|
30b76899e3 | ||
|
2f88a060c9 | ||
|
b749ae20ab | ||
|
f191e51443 | ||
|
31c0d8d1a6 | ||
|
471c0ca158 | ||
|
95ca973801 | ||
|
b190f45f45 | ||
|
2e55585eff | ||
|
b086c4a38b | ||
|
5aa5803a4c | ||
|
1382f6b14f | ||
|
7c1a18dc1a | ||
|
0e6b14643f | ||
|
ed46b1cdfb | ||
|
aa222974eb | ||
|
ebad7b1a07 | ||
|
a230a48411 | ||
|
8a8fd73351 | ||
|
056c492dfc | ||
|
3cca168248 | ||
|
7a069957d7 | ||
|
5a48128dcf | ||
|
80d77828d8 | ||
|
70f7aeb66a | ||
|
3be5fb0abd | ||
|
ee498a2e29 | ||
|
e02b2d7b3c | ||
|
f2be75a45d | ||
|
116fd68d41 | ||
|
de8c8982c0 | ||
|
582fce124e | ||
|
7d5f64b14c | ||
|
9a731ec989 | ||
|
0e066e7a1c | ||
|
495c6f6b3e | ||
|
878b701b65 | ||
|
53484d3caf | ||
|
2df893e4f4 | ||
|
72b06dfa69 | ||
|
cb665ecdd5 | ||
|
f07179e582 | ||
|
f141443564 | ||
|
32ff855968 | ||
|
f6be69286e | ||
|
5cda7ded90 | ||
|
acc5f055b7 | ||
|
2de9e88190 | ||
|
37cf1e4e31 | ||
|
06a0d66616 | ||
|
4759adf143 | ||
|
1fe6537c93 | ||
|
c9933a3add | ||
|
9da9cb7795 | ||
|
d0fb7ef750 | ||
|
4707068d25 | ||
|
6736d34a99 | ||
|
199012e045 | ||
|
224f73e0ff | ||
|
c5a316f1ae | ||
|
f27bbbb599 | ||
|
4487ac5751 | ||
|
624eb05afe | ||
|
14bd12e4ce | ||
|
a5fd547859 | ||
|
14afc0b814 | ||
|
7f338da734 | ||
|
22c8934633 | ||
|
9f7f1dd315 | ||
|
95873537e1 | ||
|
a6162d712c | ||
|
4712aa0792 | ||
|
04826af3c9 | ||
|
8c884a2e8c | ||
|
2807f88212 | ||
|
21c998f7f1 | ||
|
3e46ed3c87 | ||
|
76c250a89c | ||
|
8bd7cc1085 | ||
|
0cd93e8fb8 | ||
|
cf8ee170b9 | ||
|
b3254ad1e2 | ||
|
aedaeb06da | ||
|
7416c2e22f | ||
|
5cc7f76df1 | ||
|
e3b16db8c9 | ||
|
2fd3db12f0 | ||
|
f46af90ec3 | ||
|
399ac72376 | ||
|
7e6df6a141 | ||
|
637db00e87 | ||
|
4e136452cd | ||
|
098e3a633d | ||
|
b95b43fe87 | ||
|
1561944967 | ||
|
51367454e8 | ||
|
ad5422ece4 | ||
|
60841387c5 | ||
|
c0121f5953 | ||
|
b97c27871d | ||
|
6f2068d5ec | ||
|
b0490c8639 | ||
|
7ce99c4e99 | ||
|
8c7cfd7720 | ||
|
6adebb695c | ||
|
8c8c11f07c | ||
|
3909a26ea3 | ||
|
e86edb7087 | ||
|
a1c19371c6 | ||
|
ae46fff7c0 | ||
|
c1d841271b | ||
|
7f6713e9bb | ||
|
ba19285d53 | ||
|
48a344ab8c | ||
|
c85de745b6 | ||
|
8762a2d942 | ||
|
af8e787cb2 | ||
|
72bbfe42de | ||
|
99bfe0fc4a | ||
|
89ff86121f | ||
|
cd19ca4eda | ||
|
f09e722691 | ||
|
243701a3f8 | ||
|
560f945b16 | ||
|
5679158ea1 | ||
|
454edec6bb | ||
|
895c0ad58f | ||
|
62402db802 | ||
|
face7316f6 | ||
|
bea5873af8 | ||
|
a12391638a | ||
|
10914d53b0 | ||
|
ecc127321f | ||
|
3a458df621 | ||
|
b5cc9c0ac3 | ||
|
75503a2902 | ||
|
8629e4612a | ||
|
012f9cda54 | ||
|
1ac9c70cc6 | ||
|
6c59cd2f53 | ||
|
e87b923b8e | ||
|
6e7490f16e | ||
|
e10d6863e9 | ||
|
5508e031b7 | ||
|
f6bf58700e | ||
|
27b44c1466 | ||
|
c6248e8962 | ||
|
f1c23aa799 | ||
|
b9715d2304 | ||
|
2e14c974d7 | ||
|
a9c4745b78 | ||
|
e4dd0620ce | ||
|
e4c74dadd2 | ||
|
0ce7629859 | ||
|
116bde9655 | ||
|
6932749ac4 | ||
|
215756aca2 | ||
|
a700d88783 | ||
|
7187556b6a | ||
|
c53f9456b7 | ||
|
3ab6022138 | ||
|
dd5c1b1c6b | ||
|
fd0c863f34 | ||
|
a8825b0b28 | ||
|
1eb7b52da9 | ||
|
d4edab4979 | ||
|
ed552b6af0 | ||
|
ee9bfa4189 | ||
|
2147ec0ba5 | ||
|
670a43da00 | ||
|
04cdd1f3db | ||
|
c0a3622413 | ||
|
14f769ee0d | ||
|
514736bdd6 | ||
|
082f7dc5d3 | ||
|
4ebc691bda | ||
|
71057d0e0f | ||
|
c433465432 | ||
|
4077feaca2 | ||
|
164e57695e | ||
|
0ad76b753a | ||
|
1fcdc07a3a | ||
|
5081754665 | ||
|
a72421c225 | ||
|
a23d38e263 | ||
|
efdcf035c3 | ||
|
d0867c3c1d | ||
|
783bc1fbc0 | ||
|
31a514f1f5 | ||
|
2edf16f980 | ||
|
77e9a9864a | ||
|
666482304d | ||
|
4ea3395872 | ||
|
8ecb88a760 | ||
|
7626cda4e6 | ||
|
6c654b5908 | ||
|
152d4197ad | ||
|
2f546bc10c | ||
|
aa69226e44 | ||
|
ead9dd4980 | ||
|
edec52f004 | ||
|
23bb2e0733 | ||
|
0d9d80846e | ||
|
9705483b21 | ||
|
08a949ab82 | ||
|
37173cb8ee | ||
|
fcaf98d669 | ||
|
b54dcdc57b | ||
|
31238039a8 | ||
|
6c8f9d695a | ||
|
8bc04707fa | ||
|
846dc40d9b | ||
|
e514f00487 | ||
|
3da1d20c38 | ||
|
b5b7fc76e3 | ||
|
57e1394e70 | ||
|
a168f3f74c | ||
|
78f8393536 | ||
|
31f60022d8 | ||
|
306deaa0e2 | ||
|
c7c54457ce | ||
|
844e6d3463 | ||
|
d0f662a8c4 | ||
|
976a6ebed7 | ||
|
a33b32c164 | ||
|
b227d1b7cb | ||
|
84f79869d5 | ||
|
6416febb9c | ||
|
a84cb346bb | ||
|
007e1f23aa | ||
|
769e0af57e | ||
|
e61bd73f13 | ||
|
086bfe5ed1 | ||
|
ad8d8cde81 | ||
|
cb83681b26 | ||
|
dcfd7347c6 | ||
|
004ad783e3 | ||
|
399ab86d60 | ||
|
0f3b99b376 | ||
|
dd99c56cda | ||
|
e9cb7b0bfb | ||
|
d9df348500 | ||
|
14bde8c1bd | ||
|
cc069a5caa | ||
|
b63ed73521 | ||
|
75e0502b1a | ||
|
bdb8150a06 | ||
|
b4eb38e551 | ||
|
58ff80dfdd | ||
|
8e7c5b2e83 | ||
|
dc2d8f8572 | ||
|
185b47dfc7 | ||
|
0f0845b7d1 | ||
|
a6da7978ad | ||
|
0e6a00d8b7 | ||
|
59d9c3c892 | ||
|
e6f4c93e9c | ||
|
43a13e4d77 | ||
|
3aeca86910 | ||
|
dd465be5d4 | ||
|
fcf503223e | ||
|
84726776c7 | ||
|
b5465ddab2 | ||
|
1609e6bdcb | ||
|
b4161ac8af | ||
|
e8388743ca | ||
|
555d7d61e2 | ||
|
3fe5977b8b | ||
|
83076f4312 | ||
|
bee1e98e35 | ||
|
d168e6a47e | ||
|
83c9bf7530 | ||
|
c6ec597182 | ||
|
6a1b24aaac | ||
|
2689bcff1a | ||
|
f9d118840b | ||
|
ef19c1e0b3 |
95 changed files with 4367 additions and 2524 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -19,11 +19,13 @@ doc/
|
|||
|
||||
/tags
|
||||
/gems.tags
|
||||
/Gemfile.lock
|
||||
|
||||
.vagrant
|
||||
/cache
|
||||
|
||||
/boxes/**/*.tar.gz
|
||||
/boxes/quantal64/rootfs-amd64/
|
||||
/boxes/**/partial/
|
||||
/boxes/**/rootfs/
|
||||
/boxes/temp/
|
||||
/boxes/output/
|
||||
/development/Vagrantfile
|
||||
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -1,3 +0,0 @@
|
|||
[submodule "vendor/vagrant"]
|
||||
path = vendor/vagrant
|
||||
url = git://github.com/mitchellh/vagrant.git
|
12
.travis.yml
12
.travis.yml
|
@ -1,8 +1,10 @@
|
|||
language: ruby
|
||||
rvm:
|
||||
- 1.9.3
|
||||
- 2.0.0
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rvm: 2.0.0
|
||||
- 2.2
|
||||
- 2.3
|
||||
- 2.4
|
||||
- 2.5
|
||||
install:
|
||||
- gem install -v 1.12.5 bundler
|
||||
- bundle _1.12.5_ install --jobs=3 --retry=3
|
||||
script: "bundle exec rake ci"
|
||||
|
|
2
.vimrc
2
.vimrc
|
@ -1 +1 @@
|
|||
set wildignore+=*/vagrant-1.1/*
|
||||
set wildignore+=*/boxes/*/rootfs/*,*/boxes/*/partial/*
|
||||
|
|
47
BOXES.md
Normal file
47
BOXES.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
# vagrant-lxc base boxes
|
||||
|
||||
Although the official documentation says it is only supported for VirtualBox
|
||||
environments, you can use the [`vagrant package`](http://docs.vagrantup.com/v2/cli/package.html)
|
||||
command to export a `.box` file from an existing vagrant-lxc container.
|
||||
|
||||
There is also a set of [bash scripts](https://github.com/fgrehm/vagrant-lxc-base-boxes)
|
||||
that you can use to build base boxes as needed. By default it won't include any
|
||||
provisioning tool and you can pick the ones you want by providing some environment
|
||||
variables. Please refer to the [base boxes repository](https://github.com/fgrehm/vagrant-lxc-base-boxes)
|
||||
for more information.
|
||||
|
||||
## "Anatomy" of a box
|
||||
|
||||
If you need to go deeper and build your scripts from scratch or if you are interested
|
||||
on knowing what makes a base box for vagrant-lxc, here's what's needed:
|
||||
|
||||
### Expected `.box` contents
|
||||
|
||||
| FILE | REQUIRED? | DESCRIPTION |
|
||||
| --- | --- | --- |
|
||||
| `metadata.json` | Yes | Required by Vagrant |
|
||||
| `rootfs.tar.gz` | Yes | Compressed container rootfs tarball (need to remeber to pass in `--numeric-owner` when creating it) |
|
||||
| `lxc-template` | No, a ["generic script"](scripts/lxc-template) is provided by the plugin if it doesn't exist on the base box | Script responsible for creating and setting up the container (used with `lxc-create`). |
|
||||
| `lxc-config` | No | Box specific configuration to be _appended_ to the system's generated container config file |
|
||||
| `lxc.conf` | No | File passed in to `lxc-create -f` |
|
||||
|
||||
### metadata.json
|
||||
|
||||
```json
|
||||
{
|
||||
"provider": "lxc",
|
||||
"version": "1.0.0",
|
||||
"built-on": "Sat Sep 21 21:10:00 UTC 2013",
|
||||
"template-opts": {
|
||||
"--arch": "amd64",
|
||||
"--release": "quantal"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| KEY | REQUIRED? | DESCRIPTION |
|
||||
| --- | --- | --- |
|
||||
| `provider` | Yes | Required by Vagrant |
|
||||
| `version` | Yes | Tracks backward incompatibilities |
|
||||
| `built-on` | No | Date / time when the box was packaged for the first time |
|
||||
| `template-opts` | No | Extra options to be passed to the `lxc-template` script |
|
523
CHANGELOG.md
Normal file
523
CHANGELOG.md
Normal file
|
@ -0,0 +1,523 @@
|
|||
## [1.4.2](https://github.com/fgrehm/vagrant-lxc/compare/v1.4.1...v1.4.2) (Jul 17, 2018)
|
||||
|
||||
FIXES:
|
||||
- Fix problems with `redir` 3.x command line. [[GH-467]]
|
||||
|
||||
## [1.4.1](https://github.com/fgrehm/vagrant-lxc/compare/v1.4.0...v1.4.1) (Apr 30, 2018)
|
||||
|
||||
FEATURES:
|
||||
- Add support for LXC v3.0
|
||||
- Add support for `redir` 3.x command line. [[GH-460]]
|
||||
|
||||
[GH-460]: https://github.com/fgrehm/vagrant-lxc/issues/460
|
||||
|
||||
## [1.4.0](https://github.com/fgrehm/vagrant-lxc/compare/v1.3.1...v1.4.0) (Mar 04, 2018)
|
||||
|
||||
FEATURES:
|
||||
- Add support for unprivileged containers. [[GH-312]]
|
||||
|
||||
[GH-312]: https://github.com/fgrehm/vagrant-lxc/issues/312
|
||||
|
||||
## [1.3.1](https://github.com/fgrehm/vagrant-lxc/compare/v1.3.0...v1.3.1) (Fev 06, 2018)
|
||||
|
||||
FIXES:
|
||||
- Fix problems with `tmpfs` fiddling in v1.3.0. [[GH-455]]
|
||||
|
||||
[GH-455]: https://github.com/fgrehm/vagrant-lxc/pull/455
|
||||
|
||||
## [1.3.0](https://github.com/fgrehm/vagrant-lxc/compare/v1.2.4...v1.3.0) (Jan 20, 2018)
|
||||
|
||||
FEATURES:
|
||||
- lxc-template: make runnable by unprivileged users [[GH-447]]
|
||||
- Use `lxc-info` instead of `lxc-attach` to retrieve container IP
|
||||
- Add support for LXC v2.1+ [[GH-445]]
|
||||
- Remove 2Gb limitation on `/tmp`. [[GH-406]]
|
||||
|
||||
OTHERS:
|
||||
- Bump Vagrant requirements to v1.8+
|
||||
- Bump LXC requirements to v1.0+
|
||||
|
||||
|
||||
[GH-447]: https://github.com/fgrehm/vagrant-lxc/pull/447
|
||||
[GH-445]: https://github.com/fgrehm/vagrant-lxc/pull/445
|
||||
[GH-406]: https://github.com/fgrehm/vagrant-lxc/pull/406
|
||||
|
||||
## [1.2.4](https://github.com/fgrehm/vagrant-lxc/compare/v1.2.3...v1.2.4) (Dec 20, 2017)
|
||||
|
||||
BUGFIX:
|
||||
- Support alternative `lxcpath` [[GH-413]]
|
||||
- Update `pipework` regexp in sudo wrapper for Vagrant 1.9+ [[GH-438]]
|
||||
- Work around restrictive `umask` values [[GH-435]]
|
||||
- Make `--config` in `lxc-template` optional [[GH-421]]
|
||||
- Fix sudo wrapper binpath construction logic [[GH-410]]
|
||||
- Fix bug causing CTRL-C on `vagrant up` to destroy the VM [[GH-449]]
|
||||
|
||||
[GH-413]: https://github.com/fgrehm/vagrant-lxc/pull/413
|
||||
[GH-438]: https://github.com/fgrehm/vagrant-lxc/pull/438
|
||||
[GH-435]: https://github.com/fgrehm/vagrant-lxc/pull/435
|
||||
[GH-421]: https://github.com/fgrehm/vagrant-lxc/pull/421
|
||||
[GH-410]: https://github.com/fgrehm/vagrant-lxc/pull/410
|
||||
[GH-449]: https://github.com/fgrehm/vagrant-lxc/pull/449
|
||||
|
||||
## [1.2.3](https://github.com/fgrehm/vagrant-lxc/compare/v1.2.2...v1.2.3) (Dec 20, 2016)
|
||||
|
||||
- Fix bug in Gemfile.lock
|
||||
|
||||
## [1.2.2](https://github.com/fgrehm/vagrant-lxc/compare/v1.2.1...v1.2.2) (Dec 20, 2016)
|
||||
|
||||
BUGFIX:
|
||||
- Make the timeout for fetching container IP's configurable [[GH-426]]
|
||||
- Load locale file only once [[GH-423]]
|
||||
- Preserve xattrs in container filesystems [[GH-411]]
|
||||
- Forward port latest pipework script [[GH-408]]
|
||||
- Fix handling of non-fatal lxc-stop return code [[GH-405]]
|
||||
|
||||
[GH-426]: https://github.com/fgrehm/vagrant-lxc/pull/426
|
||||
[GH-423]: https://github.com/fgrehm/vagrant-lxc/pull/423
|
||||
[GH-411]: https://github.com/fgrehm/vagrant-lxc/pull/411
|
||||
[GH-408]: https://github.com/fgrehm/vagrant-lxc/pull/408
|
||||
[GH-405]: https://github.com/fgrehm/vagrant-lxc/pull/405
|
||||
|
||||
## [1.2.1](https://github.com/fgrehm/vagrant-lxc/compare/v1.2.0...v1.2.1) (Sep 24, 2015)
|
||||
|
||||
BUGFIX:
|
||||
- Fix sudo Wrapper [[GH-393]]
|
||||
|
||||
[GH-393]: https://github.com/fgrehm/vagrant-lxc/pull/393
|
||||
|
||||
## [1.2.0](https://github.com/fgrehm/vagrant-lxc/compare/v1.1.0...v1.2.0) (Sep 15, 2015)
|
||||
|
||||
FEATURES:
|
||||
- Support private networking using DHCP [[GH-352]]
|
||||
|
||||
[GH-352]: https://github.com/fgrehm/vagrant-lxc/pull/352
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Move mountpoint creation to lxc template for lvm rootfs support [[GH-361]] / [[GH-359]]
|
||||
- Mount selinux sys dir read-only [[GH-357]] / [[GH-301]]
|
||||
- Use correct ruby interpreter when generating sudoers file [[GH-355]]
|
||||
- Fix shebangs to be more portable [[GH-376]]
|
||||
- Fix removal of lxcbr0/virbr0 when using private networking [[GH-383]]
|
||||
- Improve /tmp handling by using tmpfs [[GH-362]]
|
||||
|
||||
[GH-301]: https://github.com/fgrehm/vagrant-lxc/issues/301
|
||||
[GH-355]: https://github.com/fgrehm/vagrant-lxc/pull/355
|
||||
[GH-357]: https://github.com/fgrehm/vagrant-lxc/pull/357
|
||||
[GH-359]: https://github.com/fgrehm/vagrant-lxc/issues/359
|
||||
[GH-361]: https://github.com/fgrehm/vagrant-lxc/pull/361
|
||||
[GH-376]: https://github.com/fgrehm/vagrant-lxc/pull/376
|
||||
[GH-383]: https://github.com/fgrehm/vagrant-lxc/pull/383
|
||||
[GH-362]: https://github.com/fgrehm/vagrant-lxc/pull/362
|
||||
|
||||
## [1.1.0](https://github.com/fgrehm/vagrant-lxc/compare/v1.0.1...v1.1.0) (Jan 14, 2015)
|
||||
|
||||
BACKWARDS INCOMPATIBILITIES:
|
||||
|
||||
- Support for Vagrant versions prior to 1.5 have been removed. The plugin now targets
|
||||
Vagrant 1.7+ but it _might_ work on 1.5+.
|
||||
|
||||
FEATURES:
|
||||
|
||||
- New experimental support for private networking [[GH-298]] / [[GH-120]].
|
||||
- Support for formatted overlayfs path [[GH-329]]
|
||||
|
||||
|
||||
[GH-298]: https://github.com/fgrehm/vagrant-lxc/pull/298
|
||||
[GH-120]: https://github.com/fgrehm/vagrant-lxc/issues/120
|
||||
[GH-329]: https://github.com/fgrehm/vagrant-lxc/pull/329
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- The provider will now have a higher priority over the VirtualBox provider
|
||||
in case VirtualBox is installed alongside lxc dependecies.
|
||||
- Show an user friendly message when trying to use the plugin on non-Linux
|
||||
environments.
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Allow backingstore options to be used along with the sudo wrapper script [[GH-310]]
|
||||
- Trim automatically generated container names to 64 chars [[GH-337]]
|
||||
|
||||
[GH-337]: https://github.com/fgrehm/vagrant-lxc/issues/337
|
||||
[GH-310]: https://github.com/fgrehm/vagrant-lxc/issues/310
|
||||
|
||||
|
||||
## [1.0.1](https://github.com/fgrehm/vagrant-lxc/compare/v1.0.0...v1.0.1) (Oct 15, 2014)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Avoid lock race condition when fetching container's IP [[GH-318]] and SSH execution [[GH-321]]
|
||||
- Support for custom containers storage path by reading `lxc.lxcpath` [[GH-317]]
|
||||
|
||||
|
||||
[GH-317]: https://github.com/fgrehm/vagrant-lxc/pull/317
|
||||
[GH-318]: https://github.com/fgrehm/vagrant-lxc/pull/318
|
||||
[GH-321]: https://github.com/fgrehm/vagrant-lxc/issues/321
|
||||
|
||||
## [1.0.0](https://github.com/fgrehm/vagrant-lxc/compare/v1.0.0.alpha.3...v1.0.0) (Sep 23, 2014)
|
||||
|
||||
DEPRECATIONS:
|
||||
|
||||
- Support to **all Vagrant versions prior to 1.5 are deprecated**, there is a
|
||||
[small layer](lib/vagrant-backports) that ensures compatibility with versions
|
||||
starting with 1.1.5 that will be removed on a future release.
|
||||
- Official base boxes that were made available from http://bit.ly are no longer
|
||||
supported and were removed from @fgrehm's Dropbox, please upgrade your Vagrant
|
||||
and vagrant-lxc installation and use a base box from [VagrantCloud](https://vagrantcloud.com/search?provider=lxc)
|
||||
|
||||
BACKWARDS INCOMPATIBILITIES:
|
||||
|
||||
- Remove plugin version from config file name generated by the `vagrant lxc sudoers`
|
||||
command. Manual removal of `/usr/local/bin/vagrant-lxc-wrapper-*` / `/etc/sudoers.d/vagrant-lxc-*`
|
||||
files are required.
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- `vagrant-mounted` upstart event is now emited on containers that support it [[GH-302]]
|
||||
- Add support for specifying the `--strip-parameters` used by the [default template](scripts/lxc-template)
|
||||
when extracting rootfs tarballs [[GH-311]]
|
||||
|
||||
[GH-302]: https://github.com/fgrehm/vagrant-lxc/issues/302
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Check for outdated base boxes when starting containers [[GH-314]]
|
||||
|
||||
[GH-311]: https://github.com/fgrehm/vagrant-lxc/pull/311
|
||||
[GH-314]: https://github.com/fgrehm/vagrant-lxc/pull/314
|
||||
|
||||
|
||||
## [1.0.0.alpha.3](https://github.com/fgrehm/vagrant-lxc/compare/v1.0.0.alpha.2...v1.0.0.alpha.3) (Aug 9, 2014)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Remove `lxc-shutdown` usage in favor of Vagrant's built in graceful halt
|
||||
- Add fallback mechanism for platforms without `lxc-attach` support [[GH-294]]
|
||||
|
||||
[GH-294]: https://github.com/fgrehm/vagrant-lxc/pull/294
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Figure out the real executable paths for whitelisted commands on the sudo
|
||||
wrapper script instead of hardcoding Ubuntu paths [[GH-304]] / [[GH-305]]
|
||||
- Attach to containers using the `MOUNT` namespace when attempting to fetch
|
||||
container's IP [[GH-300]]
|
||||
- Escape space characters for synced folders [[GH-291]]
|
||||
- Use Vagrant's ruby on the sudoers file so that it works on systems that don't
|
||||
have a global ruby installation [[GH-289]]
|
||||
|
||||
[GH-304]: https://github.com/fgrehm/vagrant-lxc/issues/304
|
||||
[GH-305]: https://github.com/fgrehm/vagrant-lxc/issues/305
|
||||
[GH-300]: https://github.com/fgrehm/vagrant-lxc/issues/300
|
||||
[GH-291]: https://github.com/fgrehm/vagrant-lxc/issues/291
|
||||
[GH-289]: https://github.com/fgrehm/vagrant-lxc/issues/289
|
||||
|
||||
|
||||
## [1.0.0.alpha.2](https://github.com/fgrehm/vagrant-lxc/compare/v1.0.0.alpha.1...v1.0.0.alpha.2) (May 13, 2014)
|
||||
|
||||
BACKWARDS INCOMPATIBILITIES:
|
||||
|
||||
- The `sudo_wrapper` provider configuration was removed in favor of using the
|
||||
secure wrapper generated by `vagrant lxc sudoers` [[GH-272]]
|
||||
- Support for specifying backingstore parameters from `Vagrantfile`s for `lxc-create`
|
||||
was added and it defaults to the `best` option. On older lxc versions that does not
|
||||
support that value, it needs to be set to `none`.
|
||||
|
||||
FEATURES:
|
||||
|
||||
- Add support for specifying backingstore parameters from `Vagrantfile`s [[GH-277]]
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Make `dnsmasq` leases MAC address regex check case insensitive [[GH-283]]
|
||||
- Use relative paths for `lxc.mount.entry` to avoid issues with `lxc-clone` [[GH-258]].
|
||||
- Sort synced folders when mounting [[GH-271]]
|
||||
- Privileged ports can now be forwarded with `sudo` [[GH-259]]
|
||||
- The `vagrant lxc sudoers` generated sudoers configuration and wrapper script
|
||||
are safer and properly whitelists the commands required by vagrant-lxc to run.
|
||||
[[GH-272]] / [[GH-269]]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fix `lxc-create` issues with pre 1.0.0 versions [[GH-282]]
|
||||
|
||||
[GH-283]: https://github.com/fgrehm/vagrant-lxc/pull/283
|
||||
[GH-282]: https://github.com/fgrehm/vagrant-lxc/pull/282
|
||||
[GH-269]: https://github.com/fgrehm/vagrant-lxc/issues/269
|
||||
[GH-272]: https://github.com/fgrehm/vagrant-lxc/pull/272
|
||||
[GH-259]: https://github.com/fgrehm/vagrant-lxc/pull/259
|
||||
[GH-271]: https://github.com/fgrehm/vagrant-lxc/pull/271
|
||||
[GH-277]: https://github.com/fgrehm/vagrant-lxc/pull/277
|
||||
[GH-258]: https://github.com/fgrehm/vagrant-lxc/issues/258
|
||||
|
||||
|
||||
## [1.0.0.alpha.1](https://github.com/fgrehm/vagrant-lxc/compare/v0.8.0...v1.0.0.alpha.1) (Apr 06, 2014)
|
||||
|
||||
DEPRECATIONS:
|
||||
|
||||
- Support to **all Vagrant versions prior to 1.5 are now deprecated**, there is a
|
||||
[small layer](lib/vagrant-backports) that ensures compatibility with versions
|
||||
starting with 1.1.5 but there is no guarantee that it will stick for too long.
|
||||
- Boxes released prior to this version are now deprecated and won't be available
|
||||
after the final 1.0.0 release.
|
||||
- `--auth-key` argument is no longer provided to `lxc-template`. This will cause
|
||||
all official base boxes prior to 09/28/2013 to break.
|
||||
|
||||
FEATURES:
|
||||
|
||||
- New `vagrant lxc sudoers` command for creating a policy for users in order to
|
||||
avoid `sudo` passwords [[GH-237]] / [[GH-257]]
|
||||
- Support for NFS and rsync synced folders.
|
||||
- Support for synced folder mount options allowing for using read only synced
|
||||
folders [[GH-193]]
|
||||
|
||||
[GH-237]: https://github.com/fgrehm/vagrant-lxc/issues/237
|
||||
[GH-257]: https://github.com/fgrehm/vagrant-lxc/pull/257
|
||||
[GH-193]: https://github.com/fgrehm/vagrant-lxc/issues/193
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- `lxc-template` is now optional for base boxes and are bundled with the plugin,
|
||||
allowing us to roll out updates without the need to rebuild boxes [[GH-254]]
|
||||
- Set container's `utsname` to `config.vm.hostname` by default [[GH-253]]
|
||||
- Added libvirt dnsmasq leases file to the lookup paths [[GH-251]]
|
||||
- Improved compatibility with Vagrant 1.4 / 1.5 including the ability
|
||||
to use `rsync` and `nfs` shared folders to work around synced folders
|
||||
permission problems. More information can be found on the following
|
||||
issues: [[GH-151]] [[GH-191]] [[GH-241]] [[GH-242]]
|
||||
- Warn in case `:group` or `:owner` are specified for synced folders [[GH-196]]
|
||||
- Acceptance specs are now powered by `vagrant-spec` [[GH-213]]
|
||||
- Base boxes creation scripts were moved out to https://github.com/fgrehm/vagrant-lxc-base-boxes.
|
||||
|
||||
[GH-254]: https://github.com/fgrehm/vagrant-lxc/issues/254
|
||||
[GH-196]: https://github.com/fgrehm/vagrant-lxc/issues/196
|
||||
[GH-251]: https://github.com/fgrehm/vagrant-lxc/pull/251
|
||||
[GH-253]: https://github.com/fgrehm/vagrant-lxc/pull/253
|
||||
[GH-151]: https://github.com/fgrehm/vagrant-lxc/issues/151
|
||||
[GH-213]: https://github.com/fgrehm/vagrant-lxc/issues/213
|
||||
[GH-191]: https://github.com/fgrehm/vagrant-lxc/issues/191
|
||||
[GH-241]: https://github.com/fgrehm/vagrant-lxc/issues/241
|
||||
[GH-242]: https://github.com/fgrehm/vagrant-lxc/issues/242
|
||||
|
||||
|
||||
## [0.8.0](https://github.com/fgrehm/vagrant-lxc/compare/v0.7.0...v0.8.0) (Feb 26, 2014)
|
||||
|
||||
FEATURES:
|
||||
|
||||
- Support for naming containers from Vagrantfiles [#132](https://github.com/fgrehm/vagrant-lxc/issues/132)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Use a safer random name for containers [#152](https://github.com/fgrehm/vagrant-lxc/issues/152)
|
||||
- Improve Ubuntu 13.10 compatibility [#190](https://github.com/fgrehm/vagrant-lxc/pull/190) / [#197](https://github.com/fgrehm/vagrant-lxc/pull/197)
|
||||
- Improved mac address detection from lxc configs [#226](https://github.com/fgrehm/vagrant-lxc/pull/226)
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Properly detect if lxc is installed on hosts that do not have `lxc-version` on their paths [#186](https://github.com/fgrehm/vagrant-lxc/issues/186)
|
||||
|
||||
|
||||
## [0.7.0](https://github.com/fgrehm/vagrant-lxc/compare/v0.6.4...v0.7.0) (Nov 8, 2013)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Support for `vagrant up` in parallel [#152](https://github.com/fgrehm/vagrant-lxc/issues/152)
|
||||
- Warn users about unsupported private / public networking configs [#154](https://github.com/fgrehm/vagrant-lxc/issues/154)
|
||||
- Respect Vagrantfile options to disable forwarded port [#149](https://github.com/fgrehm/vagrant-lxc/issues/149)
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Nicely handle blank strings provided to `:host_ip` when specifying forwarded ports [#170](https://github.com/fgrehm/vagrant-lxc/issues/170)
|
||||
- Fix "Permission denied" when starting/destroying containers after lxc
|
||||
security update in Ubuntu [#180](https://github.com/fgrehm/vagrant-lxc/issues/180)
|
||||
- Fix `vagrant package` [#172](https://github.com/fgrehm/vagrant-lxc/issues/172)
|
||||
|
||||
|
||||
## [0.6.4](https://github.com/fgrehm/vagrant-lxc/compare/v0.6.3...v0.6.4) (Oct 27, 2013)
|
||||
|
||||
FEATURES:
|
||||
|
||||
- New script for building OpenMandriva base boxes [#167](https://github.com/fgrehm/vagrant-lxc/issues/167)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Make `lxc-template` compatible with Ubuntu 13.10 [#150](https://github.com/fgrehm/vagrant-lxc/issues/150)
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fix force halt for hosts that do not have `lxc-shutdown` around (like Ubuntu 13.10) [#150](https://github.com/fgrehm/vagrant-lxc/issues/150)
|
||||
|
||||
## [0.6.3](https://github.com/fgrehm/vagrant-lxc/compare/v0.6.2...v0.6.3) (Oct 12, 2013)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Respect Vagrantfile option to disable synced folders [#147](https://github.com/fgrehm/vagrant-lxc/issues/147)
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fix error raised when fetching container's IP with the sudo wrapper disabled [#157](https://github.com/fgrehm/vagrant-lxc/issues/157)
|
||||
|
||||
## [0.6.2](https://github.com/fgrehm/vagrant-lxc/compare/v0.6.1...v0.6.2) (Oct 03, 2013)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Cache the result of `lxc-attach --namespaces` parameter support checking to
|
||||
avoid excessive logging.
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fix detection of `lxc-attach --namespaces` parameter support checking.
|
||||
|
||||
## [0.6.1](https://github.com/fgrehm/vagrant-lxc/compare/v0.6.0...v0.6.1) (Oct 03, 2013)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Fall back to `dnsmasq` leases file if not able to fetch IP with `lxc-attach` [#118](https://github.com/fgrehm/vagrant-lxc/issues/118)
|
||||
- Make sure lxc templates are executable prior to `lxc-create` [#128](https://github.com/fgrehm/vagrant-lxc/issues/128)
|
||||
- New base boxes with support for lxc 1.0+
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fix various issues related to detecting whether the container is running
|
||||
and is "SSHable" [#142](https://github.com/fgrehm/vagrant-lxc/issues/142)
|
||||
- Nicely handle missing templates path [#139](https://github.com/fgrehm/vagrant-lxc/issues/139)
|
||||
|
||||
## [0.6.0](https://github.com/fgrehm/vagrant-lxc/compare/v0.5.0...v0.6.0) (Sep 12, 2013)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Compatibility with Vagrant 1.3+ [#136](https://github.com/fgrehm/vagrant-lxc/pull/136)
|
||||
- Set plugin name to `vagrant-lxc` so that it is easier to check if the plugin is
|
||||
installed with the newly added `Vagrant.has_plugin?`
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fix box package ownership on `vagrant package` [#140](https://github.com/fgrehm/vagrant-lxc/pull/140)
|
||||
- Fix error while compressing container's rootfs under Debian hosts [#131](https://github.com/fgrehm/vagrant-lxc/issues/131) /
|
||||
[#133](https://github.com/fgrehm/vagrant-lxc/issues/133)
|
||||
|
||||
## [0.5.0](https://github.com/fgrehm/vagrant-lxc/compare/v0.4.0...v0.5.0) (Aug 1, 2013)
|
||||
|
||||
BACKWARDS INCOMPATIBILITIES:
|
||||
|
||||
- To align with Vagrant's core behaviour, forwarded ports are no longer attached
|
||||
to 127.0.0.1 and `redir`'s `--laddr` parameter is skipped in case the `:host_ip`
|
||||
config is not provided, that means `redir` will listen on connections coming
|
||||
from any of the host's IPs.
|
||||
|
||||
FEATURES:
|
||||
|
||||
- Add support for salt-minion and add latest dev release for ubuntu codenamed saucy [#116](https://github.com/fgrehm/vagrant-lxc/pull/116)
|
||||
- Add support for using a sudo wrapper script [#90](https://github.com/fgrehm/vagrant-lxc/issues/90)
|
||||
- `redir` will log to `/var/log/syslog` if `REDIR_LOG` env var is provided
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Error out if dependencies are not installed [#11](https://github.com/fgrehm/vagrant-lxc/issues/11) / [#112](https://github.com/fgrehm/vagrant-lxc/issues/112)
|
||||
- Support for specifying host interface/ip for binding `redir` [#76](https://github.com/fgrehm/vagrant-lxc/issues/76)
|
||||
- Add Vagrantfile VM name to the container name [#115](https://github.com/fgrehm/vagrant-lxc/issues/115)
|
||||
- Properly handle forwarded port collisions [#5](https://github.com/fgrehm/vagrant-lxc/issues/5)
|
||||
- Container's customizations are now written to the config file (usually
|
||||
kept under `/var/lib/lxc/CONTAINER/config`) instead of passed in as a `-s`
|
||||
parameter to `lxc-start`
|
||||
|
||||
## [0.4.0](https://github.com/fgrehm/vagrant-lxc/compare/v0.3.4...v0.4.0) (Jul 18, 2013)
|
||||
|
||||
FEATURES:
|
||||
|
||||
- New box format [#89](https://github.com/fgrehm/vagrant-lxc/issues/89)
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Add translation for stopped status [#97](https://github.com/fgrehm/vagrant-lxc/issues/97)
|
||||
- Enable retries when fetching container state [#74](https://github.com/fgrehm/vagrant-lxc/issues/74)
|
||||
- Fix error when setting Debian boxes hostname from Vagrantfile [#91](https://github.com/fgrehm/vagrant-lxc/issues/91)
|
||||
- BTRFS-friendly base boxes [#81](https://github.com/fgrehm/vagrant-lxc/issues/81)
|
||||
- Extended templates path lookup [#77](https://github.com/fgrehm/vagrant-lxc/issues/77) (tks to @aries1980)
|
||||
- Fix default group for packaged boxes tarballs on the rake task [#82](https://github.com/fgrehm/vagrant-lxc/issues/82) (tks to @cduez)
|
||||
|
||||
## [0.3.4](https://github.com/fgrehm/vagrant-lxc/compare/v0.3.3...v0.3.4) (May 08, 2013)
|
||||
|
||||
FEATURES:
|
||||
|
||||
- Support for building Debian boxes (tks to @Val)
|
||||
- Support for installing babushka on base boxes (tks to @Val)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Replace `lxc-wait` usage with a "[retry mechanism](https://github.com/fgrehm/vagrant-lxc/commit/3cca16824879731315dac32bc2df1c643f30d461#L2R88)" [#22](https://github.com/fgrehm/vagrant-lxc/issues/22)
|
||||
- Remove `/tmp` files after the machine has been successfully shut down [#68](https://github.com/fgrehm/vagrant-lxc/issues/68)
|
||||
- Clean up base boxes files after they've been configured, resulting in smaller packages
|
||||
- Bump development dependency to Vagrant 1.2+ series
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Issue a `lxc-stop` in case the container cannot shutdown gracefully [#72](https://github.com/fgrehm/vagrant-lxc/issues/72)
|
||||
|
||||
## [0.3.3](https://github.com/fgrehm/vagrant-lxc/compare/v0.3.2...v0.3.3) (April 23, 2013)
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Properly kill `redir` child processes [#59](https://github.com/fgrehm/vagrant-lxc/issues/59)
|
||||
- Use `uname -m` on base Ubuntu lxc-template [#53](https://github.com/fgrehm/vagrant-lxc/issues/53)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Initial acceptance test suite
|
||||
- New rake tasks for building Ubuntu precise and raring base amd64 boxes
|
||||
|
||||
## [0.3.2](https://github.com/fgrehm/vagrant-lxc/compare/v0.3.1...v0.3.2) (April 18, 2013)
|
||||
|
||||
- Do not display port forwarding message in case no forwarded ports were set
|
||||
|
||||
## [0.3.1](https://github.com/fgrehm/vagrant-lxc/compare/v0.3.0...v0.3.1) (April 18, 2013)
|
||||
|
||||
- Improved output to match lxc "verbiage"
|
||||
|
||||
## [0.3.0](https://github.com/fgrehm/vagrant-lxc/compare/v0.2.0...v0.3.0) (April 10, 2013)
|
||||
|
||||
BACKWARDS INCOMPATIBILITIES:
|
||||
|
||||
- Boxes `lxc-template` should support a `--tarball` parameter
|
||||
- `start_opts` config was renamed to `customize`, please check the README for the expected parameters
|
||||
- V1 boxes are no longer supported
|
||||
- `target_rootfs_path` is no longer supported, just symlink `/var/lib/lxc` to the desired folder in case you want to point it to another partition
|
||||
- Removed support for configuring private networks. It will come back at some point in the future but if you need it you should be able to set using `customize 'network.ipv4', '1.2.3.4/24'`
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- lxc templates are removed from lxc template dir after container is created
|
||||
- Treat NFS shared folders as a normal shared folder instead of ignoring it so we can share the same Vagrantfile with VBox environments
|
||||
- Support for lxc 0.7.5 (tested on Ubuntu 12.04) [#49](https://github.com/fgrehm/vagrant-lxc/issues/49)
|
||||
- Remove `/tmp` files when packaging quantal64 base box [#48](https://github.com/fgrehm/vagrant-lxc/issues/48)
|
||||
- Avoid picking the best mirror on quantal64 base box [#38](https://github.com/fgrehm/vagrant-lxc/issues/38)
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Redirect `redir`'s stderr output to `/dev/null` [#51](https://github.com/fgrehm/vagrant-lxc/issues/51)
|
||||
- Switch from `ifconfig` to `ip` to grab container's IP to avoid localization issues [#50](https://github.com/fgrehm/vagrant-lxc/issues/50)
|
||||
|
||||
## [0.2.0](https://github.com/fgrehm/vagrant-lxc/compare/v0.1.1...v0.2.0) (March 30, 2013)
|
||||
|
||||
- Experimental box packaging (only tested with Ubuntu 64 base box)
|
||||
|
||||
## [0.1.1](https://github.com/fgrehm/vagrant-lxc/compare/v0.1.0...v0.1.1) (March 29, 2013)
|
||||
|
||||
- Removed support for development under Vagrant < 1.1
|
||||
- Removed rsync from base quantal64 box to speed up containers creation [#40](https://github.com/fgrehm/vagrant-lxc/issues/40)
|
||||
- Containers are now named after project's root dir [#14](https://github.com/fgrehm/vagrant-lxc/issues/14)
|
||||
- Skip Vagrant's built in SSH redirect
|
||||
- Allow setting rootfs from Vagrantfile [#30](https://github.com/fgrehm/vagrant-lxc/issues/30)
|
||||
|
||||
## [0.1.0](https://github.com/fgrehm/vagrant-lxc/compare/v0.0.3...v0.1.0) (March 27, 2013)
|
||||
|
||||
- Support for chef added to base quantal64 box
|
||||
- Puppet upgraded to 3.1.1 on base quantal64 box
|
||||
- Port forwarding support added [#6](https://github.com/fgrehm/vagrant-lxc/issues/6)
|
||||
|
||||
## Previous
|
||||
|
||||
The changelog began with version 0.1.0 so any changes prior to that
|
||||
can be seen by checking the tagged releases and reading git commit
|
||||
messages.
|
24
CONTRIBUTING.md
Normal file
24
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,24 @@
|
|||
### Please read before contributing
|
||||
|
||||
* If you have an issue with base boxes, please create it on https://github.com/fgrehm/vagrant-lxc-base-boxes,
|
||||
this repository is for the Vagrant plugin only.
|
||||
|
||||
* Try not to post questions in the issues tracker. I will probably answer you
|
||||
but I'll most likely close the issue right away and will continue the discussion
|
||||
with the issue closed. If you have any questions about the plugin, make sure
|
||||
you go through the [Wiki](https://github.com/fgrehm/vagrant-lxc/wiki) pages
|
||||
first (specially the [Troubleshooting Section](https://github.com/fgrehm/vagrant-lxc/wiki/Troubleshooting))
|
||||
and if you still need answers please ask a question on [Stack Overflow](http://stackoverflow.com/questions/tagged/vagrant-lxc)
|
||||
using the `vagrant` / `lxc` tag on it so that I get notified :)
|
||||
|
||||
* Please do a search on the issues tracker before submitting your issue to
|
||||
check if it was already reported / fixed.
|
||||
|
||||
* When reporting a bug, please include **all** information that you can get
|
||||
about your environment. Things like vagrant / vagrant-lxc / kernel / lxc /
|
||||
distro versions, the list of plugins you have installed, a [gist](https://gist.github.com/)
|
||||
with the output of running `VAGRANT_LOG=debug vagrant COMMAND`, the `Vagrantfile`
|
||||
you are using and / or base box URL are really useful when tracking down what's
|
||||
going on on your side of the globe and will get bonus points :)
|
||||
|
||||
Thanks!
|
34
Gemfile
34
Gemfile
|
@ -1,19 +1,23 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
gemspec
|
||||
group :development do
|
||||
gem 'vagrant', git: 'https://github.com/mitchellh/vagrant.git'
|
||||
gem 'guard'
|
||||
gem 'guard-rspec'
|
||||
gem 'rb-inotify'
|
||||
end
|
||||
|
||||
# TODO: Group gems
|
||||
group :development, :test do
|
||||
gem 'rake', '~> 10.4.2'
|
||||
gem 'rspec', '~> 3.5.0'
|
||||
gem 'coveralls', '~> 0.7.2', require: (ENV['COVERAGE'] == 'true')
|
||||
gem 'vagrant-spec', git: 'https://github.com/mitchellh/vagrant-spec.git'
|
||||
end
|
||||
|
||||
gem 'rake'
|
||||
# TODO: setup rake-notes
|
||||
gem 'net-ssh'
|
||||
gem 'rspec'
|
||||
gem 'rspec-fire', require: 'rspec/fire'
|
||||
gem 'rspec-spies', require: false
|
||||
gem 'simplecov', require: false
|
||||
gem 'guard'
|
||||
gem 'guard-rspec'
|
||||
gem 'guard-bundler'
|
||||
gem 'guard-ctags-bundler'
|
||||
gem 'rb-inotify'
|
||||
gem 'log4r'
|
||||
group :plugins do
|
||||
acceptance = (ENV['ACCEPTANCE'] == 'true')
|
||||
gem 'vagrant-cachier', git: 'https://github.com/fgrehm/vagrant-cachier.git', require: !acceptance
|
||||
gem 'vagrant-pristine', git: 'https://github.com/fgrehm/vagrant-pristine.git', require: !acceptance
|
||||
gem 'vagrant-omnibus', require: !acceptance
|
||||
gemspec
|
||||
end
|
||||
|
|
89
Gemfile.lock
89
Gemfile.lock
|
@ -1,89 +0,0 @@
|
|||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
vagrant-lxc (0.0.1)
|
||||
childprocess (~> 0.3.7)
|
||||
erubis (~> 2.7.0)
|
||||
i18n (~> 0.6.0)
|
||||
json (>= 1.5.1, < 1.8.0)
|
||||
log4r (~> 1.1.9)
|
||||
net-scp (~> 1.0.4)
|
||||
net-ssh (~> 2.2.2)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
childprocess (0.3.9)
|
||||
ffi (~> 1.0, >= 1.0.11)
|
||||
coderay (1.0.9)
|
||||
diff-lcs (1.2.1)
|
||||
erubis (2.7.0)
|
||||
ffi (1.4.0)
|
||||
guard (1.6.2)
|
||||
listen (>= 0.6.0)
|
||||
lumberjack (>= 1.0.2)
|
||||
pry (>= 0.9.10)
|
||||
terminal-table (>= 1.4.3)
|
||||
thor (>= 0.14.6)
|
||||
guard-bundler (1.0.0)
|
||||
bundler (~> 1.0)
|
||||
guard (~> 1.1)
|
||||
guard-ctags-bundler (0.1.6)
|
||||
guard (>= 1.1)
|
||||
guard-rspec (2.5.0)
|
||||
guard (>= 1.1)
|
||||
rspec (~> 2.11)
|
||||
i18n (0.6.4)
|
||||
json (1.7.7)
|
||||
listen (0.7.3)
|
||||
log4r (1.1.10)
|
||||
lumberjack (1.0.2)
|
||||
method_source (0.8.1)
|
||||
multi_json (1.6.1)
|
||||
net-scp (1.0.4)
|
||||
net-ssh (>= 1.99.1)
|
||||
net-ssh (2.2.2)
|
||||
pry (0.9.12)
|
||||
coderay (~> 1.0.5)
|
||||
method_source (~> 0.8)
|
||||
slop (~> 3.4)
|
||||
rake (10.0.3)
|
||||
rb-inotify (0.9.0)
|
||||
ffi (>= 0.5.0)
|
||||
rspec (2.13.0)
|
||||
rspec-core (~> 2.13.0)
|
||||
rspec-expectations (~> 2.13.0)
|
||||
rspec-mocks (~> 2.13.0)
|
||||
rspec-core (2.13.0)
|
||||
rspec-expectations (2.13.0)
|
||||
diff-lcs (>= 1.1.3, < 2.0)
|
||||
rspec-fire (1.1.3)
|
||||
rspec (~> 2.11)
|
||||
rspec-mocks (2.13.0)
|
||||
rspec-spies (2.1.3)
|
||||
rspec (~> 2.0)
|
||||
simplecov (0.7.1)
|
||||
multi_json (~> 1.0)
|
||||
simplecov-html (~> 0.7.1)
|
||||
simplecov-html (0.7.1)
|
||||
slop (3.4.3)
|
||||
terminal-table (1.4.5)
|
||||
thor (0.17.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
guard
|
||||
guard-bundler
|
||||
guard-ctags-bundler
|
||||
guard-rspec
|
||||
log4r
|
||||
net-ssh
|
||||
rake
|
||||
rb-inotify
|
||||
rspec
|
||||
rspec-fire
|
||||
rspec-spies
|
||||
simplecov
|
||||
vagrant-lxc!
|
35
Guardfile
35
Guardfile
|
@ -1,34 +1,7 @@
|
|||
# A sample Guardfile
|
||||
# More info at https://github.com/guard/guard#readme
|
||||
|
||||
guard 'bundler' do
|
||||
watch('Gemfile')
|
||||
watch(/^.+\.gemspec/)
|
||||
end
|
||||
|
||||
guard 'ctags-bundler', :src_path => ["lib"] do
|
||||
watch(/^(lib|spec\/support)\/.*\.rb$/)
|
||||
watch('Gemfile.lock')
|
||||
end
|
||||
|
||||
guard 'rspec' do
|
||||
watch(%r{^spec/.+_spec\.rb$})
|
||||
guard 'rspec', :spec_paths => ["spec/unit"] do
|
||||
watch(%r{^spec/unit/.+_spec\.rb$})
|
||||
watch(%r{^lib/vagrant-lxc/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
|
||||
watch('spec/unit_helper.rb') { "spec/unit" }
|
||||
watch('spec/spec_helper.rb') { "spec/" }
|
||||
|
||||
# Rails example
|
||||
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
||||
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
||||
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
||||
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
||||
watch('config/routes.rb') { "spec/routing" }
|
||||
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
||||
|
||||
# Capybara features specs
|
||||
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
|
||||
|
||||
# Turnip features and steps
|
||||
watch(%r{^spec/acceptance/(.+)\.feature$})
|
||||
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
||||
watch('spec/spec_helper.rb') { "spec/unit" }
|
||||
watch(%r{^spec/support/(.+)\.rb$}) { "spec/unit" }
|
||||
end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2013 Fábio Rehm
|
||||
Copyright (c) 2013-2014 Fábio Rehm
|
||||
|
||||
MIT License
|
||||
|
||||
|
|
287
README.md
287
README.md
|
@ -1,203 +1,186 @@
|
|||
🟢 We plan to support and maintain vagrant-lxc, as well as clean it up.<br/>
|
||||
🟢 Please feel free to contribute Issues and pull requests.<br/>
|
||||
🟢 P.S: Thanks [Fabio Rehm](https://fabiorehm.com) for the amazing initial project.
|
||||
|
||||
# vagrant-lxc
|
||||
|
||||
[](https://travis-ci.org/fgrehm/vagrant-lxc)
|
||||
[](https://travis-ci.org/fgrehm/vagrant-lxc) [](http://badge.fury.io/rb/vagrant-lxc) [](https://codeclimate.com/github/fgrehm/vagrant-lxc) [](https://coveralls.io/r/fgrehm/vagrant-lxc) [](https://gitter.im/fgrehm/vagrant-lxc)
|
||||
|
||||
Highly experimental, soon to come, Linux Containers support for the unreleased
|
||||
Vagrant 1.1.
|
||||
[LXC](http://lxc.sourceforge.net/) provider for [Vagrant](http://www.vagrantup.com/) 1.9+
|
||||
|
||||
Please refer to the [closed issues](https://github.com/fgrehm/vagrant-lxc/issues?labels=&milestone=&page=1&state=closed)
|
||||
to find out whats currently supported.
|
||||
This is a Vagrant plugin that allows it to control and provision Linux Containers
|
||||
as an alternative to the built in VirtualBox provider for Linux hosts. Check out
|
||||
[this blog post](http://fabiorehm.com/blog/2013/04/28/lxc-provider-for-vagrant/)
|
||||
to see it in action.
|
||||
|
||||
## Features
|
||||
|
||||
* Provides the same workflow as the Vagrant VirtualBox provider
|
||||
* Port forwarding via [`redir`](https://github.com/troglobit/redir)
|
||||
* Private networking via [`pipework`](https://github.com/jpetazzo/pipework)
|
||||
|
||||
## Requirements
|
||||
|
||||
* [Vagrant 1.9+](http://www.vagrantup.com/downloads.html)
|
||||
* lxc >=2.1
|
||||
* `redir` (if you are planning to use port forwarding)
|
||||
* `brctl` (if you are planning to use private networks, on Ubuntu this means `apt-get install bridge-utils`)
|
||||
|
||||
The plugin is known to work better and pretty much out of the box on Ubuntu 14.04+
|
||||
hosts and installing the dependencies on it basically means a
|
||||
`apt-get install lxc lxc-templates cgroup-lite redir`. For setting up other
|
||||
types of hosts please have a look at the [Wiki](https://github.com/fgrehm/vagrant-lxc/wiki).
|
||||
|
||||
If you are on a Mac or Windows machine, you might want to have a look at [this](http://the.taoofmac.com/space/HOWTO/Vagrant)
|
||||
blog post for some ideas on how to set things up or check out [this other repo](https://github.com/fgrehm/vagrant-lxc-vbox-hosts)
|
||||
for a set of Vagrant VirtualBox machines ready for vagrant-lxc usage.
|
||||
|
||||
|
||||
## WARNING
|
||||
|
||||
Please keep in mind that although I'm already using this on my laptop, this is
|
||||
"almost alpha" software and things might go wrong.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
LXC, `bsdtar` and `fping` packages and a Kernel [higher than 3.5.0-17.28](#im-unable-to-restart-containers),
|
||||
which on Ubuntu 12.10 means:
|
||||
## Installation
|
||||
|
||||
```
|
||||
sudo apt-get update && sudo apt-get dist-upgrade
|
||||
sudo apt-get install lxc bsdtar fping
|
||||
vagrant plugin install vagrant-lxc
|
||||
```
|
||||
|
||||
|
||||
## What is currently supported?
|
||||
|
||||
* Vagrant's `up`, `halt`, `reload`, `destroy`, and `ssh` commands
|
||||
* Shared folders
|
||||
* Provisioners
|
||||
* Setting container's host name
|
||||
* Host-only / private networking
|
||||
|
||||
|
||||
## Current limitations
|
||||
|
||||
* Ruby >= 1.9.3 only, patches for 1.8.7 are welcome
|
||||
* Port forwarding does not work [yet](https://github.com/fgrehm/vagrant-lxc/issues/4)
|
||||
* A hell lot of `sudo`s
|
||||
* Only a [single ubuntu box supported](boxes), I'm still [figuring out what should go
|
||||
on the .box file](https://github.com/fgrehm/vagrant-lxc/issues/4)
|
||||
* "[works on my machine](https://github.com/fgrehm/vagrant-lxc/issues/20)" (TM)
|
||||
* + bunch of other [core features](https://github.com/fgrehm/vagrant-lxc/issues?labels=core&milestone=&page=1&state=open)
|
||||
and some known [bugs](https://github.com/fgrehm/vagrant-lxc/issues?labels=bug&page=1&state=open)
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
For now you'll need to install the gem from sources:
|
||||
## Quick start
|
||||
|
||||
```
|
||||
git clone git://github.com/fgrehm/vagrant-lxc.git --recurse
|
||||
cd vagrant-lxc
|
||||
bundle install
|
||||
bundle exec rake install
|
||||
vagrant init fgrehm/precise64-lxc
|
||||
vagrant up --provider=lxc
|
||||
```
|
||||
|
||||
Since Vagrant 1.1 has not been released yet and to avoid messing up with you
|
||||
current Vagrant installation, I've vendored Vagrant's sources from the master
|
||||
and made it available from [`vagrant-lxc`](bin/vagrant-lxc). So after installing
|
||||
`vagrant-lxc`, create a `Vagrantfile` like the one below and run
|
||||
`vagrant-lxc up --provider=lxc`:
|
||||
_More information about skipping the `--provider` argument can be found at the
|
||||
"DEFAULT PROVIDER" section of [Vagrant docs](https://docs.vagrantup.com/v2/providers/basic_usage.html)_
|
||||
|
||||
## Base boxes
|
||||
|
||||
Base boxes provided on Atlas haven't been refreshed for a good while and shouldn't be relied on.
|
||||
Your best best is to build your boxes yourself. Some scripts to build your own are available at
|
||||
[hsoft/vagrant-lxc-base-boxes](https://github.com/hsoft/vagrant-lxc-base-boxes).
|
||||
|
||||
If you want to build your own boxes, please have a look at [`BOXES.md`](https://github.com/fgrehm/vagrant-lxc/tree/master/BOXES.md)
|
||||
for more information.
|
||||
|
||||
## Advanced configuration
|
||||
|
||||
You can modify container configurations from within your Vagrantfile using the
|
||||
[provider block](http://docs.vagrantup.com/v2/providers/configuration.html):
|
||||
|
||||
```ruby
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = "lxc-quantal64"
|
||||
config.vm.box_url = 'http://dl.dropbox.com/u/13510779/lxc-quantal64-2013-03-10.box'
|
||||
|
||||
# Share an additional folder to the guest Container. The first argument
|
||||
# is the path on the host to the actual folder. The second argument is
|
||||
# the path on the guest to mount the folder. And the optional third
|
||||
# argument is a set of non-required options.
|
||||
config.vm.synced_folder "/tmp", "/host_tmp"
|
||||
|
||||
config.vm.box = "fgrehm/trusty64-lxc"
|
||||
config.vm.provider :lxc do |lxc|
|
||||
# Same as 'customize ["modifyvm", :id, "--memory", "1024"]' for VirtualBox
|
||||
lxc.start_opts << 'lxc.cgroup.memory.limit_in_bytes=400M'
|
||||
# Limits swap size
|
||||
lxc.start_opts << 'lxc.cgroup.memory.memsw.limit_in_bytes=500M'
|
||||
# Same effect as 'customize ["modifyvm", :id, "--memory", "1024"]' for VirtualBox
|
||||
lxc.customize 'cgroup.memory.limit_in_bytes', '1024M'
|
||||
end
|
||||
|
||||
# ... your puppet / chef / shell provisioner configs here ...
|
||||
end
|
||||
```
|
||||
|
||||
If you don't trust me and believe that it will mess up with your current Vagrant
|
||||
installation and / or are afraid that something might go wrong with your machine,
|
||||
fire up the [same Vagrant VirtualBox machine I'm using for development](#using-virtualbox-and-vagrant-10-for-development)
|
||||
to try things out and do the same as above. That might also get you up and running
|
||||
if you are working on a mac or windows host ;)
|
||||
vagrant-lxc will then write out `lxc.cgroup.memory.limit_in_bytes='1024M'` to the
|
||||
container config file (usually kept under `/var/lib/lxc/<container>/config`)
|
||||
prior to starting it.
|
||||
|
||||
For other configuration options, please check the [lxc.conf manpages](http://manpages.ubuntu.com/manpages/precise/man5/lxc.conf.5.html).
|
||||
|
||||
## Development
|
||||
### Private Networks
|
||||
|
||||
If want to develop from your physical machine, just sing that same old song:
|
||||
Starting with vagrant-lxc 1.1.0, there is some rudimentary support for configuring
|
||||
[Private Networks](https://docs.vagrantup.com/v2/networking/private_network.html)
|
||||
by leveraging the [pipework](https://github.com/jpetazzo/pipework) project.
|
||||
|
||||
```
|
||||
git clone git://github.com/fgrehm/vagrant-lxc.git --recurse
|
||||
cd vagrant-lxc
|
||||
bundle install
|
||||
bundle exec rake # to run all specs
|
||||
On its current state, there is a requirement for setting the bridge name that
|
||||
will be created and will allow your machine to comunicate with the container
|
||||
|
||||
For example:
|
||||
|
||||
```ruby
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.network "private_network", ip: "192.168.2.100", lxc__bridge_name: 'vlxcbr1'
|
||||
end
|
||||
```
|
||||
|
||||
To build the provided quantal64 box:
|
||||
Will create a new `veth` device for the container and will set up (or reuse)
|
||||
a `vlxcbr1` bridge between your machine and the `veth` device. Once the last
|
||||
vagrant-lxc container attached to the bridge gets `vagrant halt`ed, the plugin
|
||||
will delete the bridge.
|
||||
|
||||
```
|
||||
bundle exec rake boxes:quantal64:build
|
||||
vagrant-lxc box add quantal64 boxes/output/lxc-quantal64.box
|
||||
### Container naming
|
||||
|
||||
By default vagrant-lxc will attempt to generate a unique container name
|
||||
for you. However, if the container name is important to you, you may use the
|
||||
`container_name` attribute to set it explicitly from the `provider` block:
|
||||
|
||||
```ruby
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.define "db" do |node|
|
||||
node.vm.provider :lxc do |lxc|
|
||||
lxc.container_name = :machine # Sets the container name to 'db'
|
||||
lxc.container_name = 'mysql' # Sets the container name to 'mysql'
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
_Please note that there is a 64 chars limit and the container name will be
|
||||
trimmed down to that to ensure we can always bring the container up.
|
||||
|
||||
### Using `vagrant-lxc` to develop itself
|
||||
### Backingstore options
|
||||
|
||||
Yes! The gem has been [bootstrapped](http://en.wikipedia.org/wiki/Bootstrapping_(compilers)
|
||||
and since you can boot a container from within another, after cloning the
|
||||
project you can run the commands below from the host machine to get a container
|
||||
ready for development:
|
||||
Support for setting `lxc-create`'s backingstore option (`-B` and related) can be
|
||||
specified from the provider block and it defaults to `best`, to change it:
|
||||
|
||||
```sh
|
||||
bundle install
|
||||
cd development
|
||||
cp Vagrantfile.1.1 Vagrantfile
|
||||
# Required in order to allow nested containers to be started
|
||||
sudo apt-get install apparmor-utils
|
||||
sudo aa-complain /usr/bin/lxc-start
|
||||
bundle exec vagrant-lxc up lxc --provider=lxc
|
||||
bundle exec vagrant-lxc ssh lxc
|
||||
```ruby
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.provider :lxc do |lxc|
|
||||
lxc.backingstore = 'lvm' # or 'btrfs', 'overlayfs', ...
|
||||
# lvm specific options
|
||||
lxc.backingstore_option '--vgname', 'schroots'
|
||||
lxc.backingstore_option '--fssize', '5G'
|
||||
lxc.backingstore_option '--fstype', 'xfs'
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
That should result in a container ready to be `bundle exec vagrant-lxc ssh`ed.
|
||||
Once you've SSH into the guest container, you'll be already on the project's root.
|
||||
Keep in mind that you'll probably need to run `sudo aa-complain /usr/bin/lxc-start`
|
||||
on the host whenever you want to hack on it, otherwise you won't be able to
|
||||
start nested containers there to try things out.
|
||||
## Unprivileged containers support
|
||||
|
||||
Since v1.4.0, `vagrant-lxc` gained support for unprivileged containers. For now, since it's a new
|
||||
feature, privileged containers are still the default, but you can have your `Vagrantfile` use
|
||||
unprivileged containers with the `privileged` flag (which defaults to `true`). Example:
|
||||
|
||||
### Using VirtualBox and Vagrant 1.0 for development
|
||||
|
||||
```
|
||||
cd development
|
||||
cp Vagrantfile.1.0 Vagrantfile
|
||||
vagrant up
|
||||
vagrant reload
|
||||
vagrant ssh
|
||||
```ruby
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.provider :lxc do |lxc|
|
||||
lxc.privileged = false
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### Using VirtualBox and Vagrant 1.1 for development
|
||||
For unprivileged containers to work with `vagrant-lxc`, you need a properly configured system. On
|
||||
some distros, it can be somewhat of a challenge. Your journey to configuring your system can start
|
||||
with [Stéphane Graber's blog post about it](https://stgraber.org/2014/01/17/lxc-1-0-unprivileged-containers/).
|
||||
|
||||
```
|
||||
cd development
|
||||
cp Vagrantfile.1.1 Vagrantfile
|
||||
bundle exec vagrant-lxc up vbox
|
||||
bundle exec vagrant-lxc reload vbox
|
||||
bundle exec vagrant-lxc ssh vbox
|
||||
```
|
||||
## Avoiding `sudo` passwords
|
||||
|
||||
If you're not using unprivileged containers, this plugin requires **a lot** of `sudo`ing To work
|
||||
around that, you can use the `vagrant lxc sudoers` command which will create a file under
|
||||
`/etc/sudoers.d/vagrant-lxc` whitelisting all commands required by `vagrant-lxc` to run.
|
||||
|
||||
If you are interested on what will be generated by that command, please check
|
||||
[this code](lib/vagrant-lxc/command/sudoers.rb).
|
||||
|
||||
|
||||
## Protips
|
||||
## More information
|
||||
|
||||
If you want to find out more about what's going on under the hood on vagrant,
|
||||
prepend `VAGRANT_LOG=debug` to your `vagrant-lxc` commands. For `lxc-start`s
|
||||
debugging set `LXC_START_LOG_FILE`:
|
||||
|
||||
```
|
||||
LXC_START_LOG_FILE=/tmp/lxc-start.log VAGRANT_LOG=debug vagrant-lxc up
|
||||
```
|
||||
|
||||
This will output A LOT of information on your terminal and some useful information
|
||||
about `lxc-start` to `/tmp/lxc-start.log`.
|
||||
Please refer the [wiki](https://github.com/fgrehm/vagrant-lxc/wiki).
|
||||
|
||||
|
||||
## Help!
|
||||
## Problems / ideas?
|
||||
|
||||
### I've accidentaly ran `vagrant-lxc` on a Vagrant 1.0 project and I can't use it anymore
|
||||
|
||||
That happened to me before so here's how to recover:
|
||||
|
||||
```
|
||||
rm -rf .vagrant
|
||||
mv .vagrant.v1* .vagrant
|
||||
```
|
||||
|
||||
### I'm unable to restart containers!
|
||||
|
||||
It happened to me quite a few times in the past and it seems that it is related
|
||||
to a bug on linux kernel, so make sure you are using a bug-free kernel
|
||||
(>= 3.5.0-17.28). More information can be found on:
|
||||
|
||||
* https://bugzilla.kernel.org/show_bug.cgi?id=47181
|
||||
* https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1021471
|
||||
* https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1065434
|
||||
|
||||
Sometimes the dev boxes I'm using are not able to `lxc-start` containers
|
||||
anymore. Most of the times it was an issue with the arguments [I provided](https://github.com/fgrehm/vagrant-lxc/blob/master/example/Vagrantfile#L14-L18)
|
||||
to it (or a *buggy* kernel). If you run into that, rollback your changes
|
||||
and try to `vagrant reload` the dev box. If it still doesn't work,
|
||||
please file a bug at the [issue tracker](https://github.com/fgrehm/vagrant-lxc/issues).
|
||||
Please review the [Troubleshooting](https://github.com/fgrehm/vagrant-lxc/wiki/Troubleshooting)
|
||||
wiki page + [known bugs](https://github.com/fgrehm/vagrant-lxc/issues?labels=bug&page=1&state=open)
|
||||
list if you have a problem and feel free to use the [issue tracker](https://github.com/fgrehm/vagrant-lxc/issues)
|
||||
propose new functionality and / or report bugs.
|
||||
|
||||
|
||||
## Contributing
|
||||
|
|
2
Rakefile
2
Rakefile
|
@ -1,5 +1,3 @@
|
|||
Dir['./tasks/**/*.rake'].each { |f| load f }
|
||||
|
||||
require 'bundler/gem_tasks'
|
||||
|
||||
task :ci => ['spec:unit']
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
if File.exists?(File.join(File.expand_path('../../', __FILE__), '.git'))
|
||||
$:.unshift(File.expand_path('../../lib', __FILE__))
|
||||
end
|
||||
|
||||
require 'vagrant-lxc'
|
||||
|
||||
load Vagrant.source_root.join('bin/vagrant').to_s
|
|
@ -1,103 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This is the code extracted from /usr/share/lxc/templates/lxc-ubuntu
|
||||
# that comes with Ubuntu 12.10 which is responsible for downloading the
|
||||
# rootfs files / packages
|
||||
|
||||
set -e
|
||||
|
||||
suggest_flush()
|
||||
{
|
||||
echo "Container upgrade failed. The container cache may be out of date,"
|
||||
echo "in which case flushing the case (see -F in the hep output) may help."
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
rm -rf $cache/partial-$arch
|
||||
rm -rf $cache/rootfs-$arch
|
||||
}
|
||||
|
||||
write_sourceslist()
|
||||
{
|
||||
# $1 => path to the rootfs
|
||||
# $2 => architecture we want to add
|
||||
|
||||
MIRROR=${MIRROR:-mirror://mirrors.ubuntu.com/mirrors.txt}
|
||||
SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.ubuntu.com/ubuntu}
|
||||
|
||||
cat >> "$1/etc/apt/sources.list" << EOF
|
||||
deb $MIRROR ${release} main restricted universe multiverse
|
||||
deb $MIRROR ${release}-updates main restricted universe multiverse
|
||||
deb $SECURITY_MIRROR ${release}-security main restricted universe multiverse
|
||||
EOF
|
||||
}
|
||||
|
||||
download_ubuntu()
|
||||
{
|
||||
packages=vim,ssh,curl,wget,bash-completion,manpages,puppet
|
||||
echo "installing packages: $packages"
|
||||
|
||||
trap cleanup EXIT SIGHUP SIGINT SIGTERM
|
||||
# check the mini ubuntu was not already downloaded
|
||||
mkdir -p "$cache/partial-$arch"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to create '$cache/partial-$arch' directory"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# download a mini ubuntu into a cache
|
||||
echo "Downloading ubuntu $release minimal ..."
|
||||
if [ -n "$(which qemu-debootstrap)" ]; then
|
||||
qemu-debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR
|
||||
else
|
||||
debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR
|
||||
fi
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to download the rootfs, aborting."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Serge isn't sure whether we should avoid doing this when
|
||||
# $release == `distro-info -d`
|
||||
echo "Installing updates"
|
||||
> $cache/partial-$arch/etc/apt/sources.list
|
||||
write_sourceslist $cache/partial-$arch/ $arch
|
||||
|
||||
chroot "$1/partial-${arch}" apt-get update
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to update the apt cache"
|
||||
return 1
|
||||
fi
|
||||
cat > "$1/partial-${arch}"/usr/sbin/policy-rc.d << EOF
|
||||
#!/bin/sh
|
||||
exit 101
|
||||
EOF
|
||||
chmod +x "$1/partial-${arch}"/usr/sbin/policy-rc.d
|
||||
|
||||
lxc-unshare -s MOUNT -- chroot "$1/partial-${arch}" apt-get dist-upgrade -y || { suggest_flush; false; }
|
||||
|
||||
rm -f "$1/partial-${arch}"/usr/sbin/policy-rc.d
|
||||
|
||||
chroot "$1/partial-${arch}" apt-get clean
|
||||
|
||||
mv "$1/partial-$arch" "$1/rootfs-$arch"
|
||||
trap EXIT
|
||||
trap SIGINT
|
||||
trap SIGTERM
|
||||
trap SIGHUP
|
||||
echo "Download complete"
|
||||
return 0
|
||||
}
|
||||
|
||||
declare cache=`readlink -f .` \
|
||||
arch=amd64 \
|
||||
release=quantal
|
||||
|
||||
if [ -d "${cache}/rootfs-${arch}" ]; then
|
||||
echo 'The rootfs cache has been downloaded already, please remove it if you want to update'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
download_ubuntu $cache $arch $release
|
|
@ -1,567 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This is a modified version of /usr/share/lxc/templates/lxc-ubuntu
|
||||
# that comes with Ubuntu 12.10 changed to suit vagrant-lxc needs
|
||||
|
||||
#
|
||||
# template script for generating ubuntu container for LXC
|
||||
#
|
||||
# This script consolidates and extends the existing lxc ubuntu scripts
|
||||
#
|
||||
|
||||
# Copyright © 2011 Serge Hallyn <serge.hallyn@canonical.com>
|
||||
# Copyright © 2010 Wilhelm Meier
|
||||
# Author: Wilhelm Meier <wilhelm.meier@fh-kl.de>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2, as
|
||||
# published by the Free Software Foundation.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
if [ -r /etc/default/lxc ]; then
|
||||
. /etc/default/lxc
|
||||
fi
|
||||
|
||||
configure_ubuntu()
|
||||
{
|
||||
rootfs=$1
|
||||
release=$3
|
||||
hostname='quantal64'
|
||||
|
||||
# configure the network using the dhcp
|
||||
cat <<EOF > $rootfs/etc/network/interfaces
|
||||
# This file describes the network interfaces available on your system
|
||||
# and how to activate them. For more information, see interfaces(5).
|
||||
|
||||
# The loopback network interface
|
||||
auto lo
|
||||
iface lo inet loopback
|
||||
|
||||
auto eth0
|
||||
iface eth0 inet dhcp
|
||||
EOF
|
||||
|
||||
# set the hostname
|
||||
cat <<EOF > $rootfs/etc/hostname
|
||||
$hostname
|
||||
EOF
|
||||
# set minimal hosts
|
||||
cat <<EOF > $rootfs/etc/hosts
|
||||
127.0.0.1 localhost
|
||||
127.0.1.1 $hostname
|
||||
|
||||
# The following lines are desirable for IPv6 capable hosts
|
||||
::1 ip6-localhost ip6-loopback
|
||||
fe00::0 ip6-localnet
|
||||
ff00::0 ip6-mcastprefix
|
||||
ff02::1 ip6-allnodes
|
||||
ff02::2 ip6-allrouters
|
||||
EOF
|
||||
|
||||
if [ ! -f $rootfs/etc/init/container-detect.conf ]; then
|
||||
# suppress log level output for udev
|
||||
sed -i "s/=\"err\"/=0/" $rootfs/etc/udev/udev.conf
|
||||
|
||||
# remove jobs for consoles 5 and 6 since we only create 4 consoles in
|
||||
# this template
|
||||
rm -f $rootfs/etc/init/tty{5,6}.conf
|
||||
fi
|
||||
|
||||
chroot $rootfs useradd --create-home -s /bin/bash vagrant
|
||||
echo "vagrant:vagrant" | chroot $rootfs chpasswd
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# finish setting up the user in the container by injecting ssh key and
|
||||
# adding sudo group membership.
|
||||
# passed-in user is 'vagrant'
|
||||
finalize_user()
|
||||
{
|
||||
user=$1
|
||||
|
||||
sudo_version=$(chroot $rootfs dpkg-query -W -f='${Version}' sudo)
|
||||
|
||||
if chroot $rootfs dpkg --compare-versions $sudo_version gt "1.8.3p1-1"; then
|
||||
groups="sudo"
|
||||
else
|
||||
groups="sudo admin"
|
||||
fi
|
||||
|
||||
for group in $groups; do
|
||||
chroot $rootfs groupadd --system $group >/dev/null 2>&1 || true
|
||||
chroot $rootfs adduser ${user} $group >/dev/null 2>&1 || true
|
||||
done
|
||||
|
||||
chroot $rootfs cp /etc/sudoers /etc/sudoers.orig >/dev/null 2>&1 || true
|
||||
chroot $rootfs sed -i -e 's/%sudo\s\+ALL=(ALL:ALL)\s\+ALL/%sudo ALL=NOPASSWD:ALL/g' /etc/sudoers >/dev/null 2>&1 || true
|
||||
chroot $rootfs locale-gen en_US en_US.UTF-8 hu_HU hu_HU.UTF-8 >/dev/null 2>&1 || true
|
||||
chroot $rootfs dpkg-reconfigure locales >/dev/null 2>&1 || true
|
||||
|
||||
if [ -n "$auth_key" -a -f "$auth_key" ]; then
|
||||
u_path="/home/${user}/.ssh"
|
||||
root_u_path="$rootfs/$u_path"
|
||||
|
||||
mkdir -p $root_u_path
|
||||
cp $auth_key "$root_u_path/authorized_keys"
|
||||
chroot $rootfs chown -R ${user}: "$u_path"
|
||||
|
||||
echo "Inserted SSH public key from $auth_key into /home/${user}/.ssh/authorized_keys"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
write_sourceslist()
|
||||
{
|
||||
# $1 => path to the rootfs
|
||||
# $2 => architecture we want to add
|
||||
# $3 => whether to use the multi-arch syntax or not
|
||||
|
||||
case $2 in
|
||||
amd64|i386)
|
||||
MIRROR=${MIRROR:-http://archive.ubuntu.com/ubuntu}
|
||||
SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.ubuntu.com/ubuntu}
|
||||
;;
|
||||
*)
|
||||
MIRROR=${MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
|
||||
SECURITY_MIRROR=${SECURITY_MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
|
||||
;;
|
||||
esac
|
||||
if [ -n "$3" ]; then
|
||||
cat >> "$1/etc/apt/sources.list" << EOF
|
||||
deb [arch=$2] $MIRROR ${release} main restricted universe multiverse
|
||||
deb [arch=$2] $MIRROR ${release}-updates main restricted universe multiverse
|
||||
deb [arch=$2] $SECURITY_MIRROR ${release}-security main restricted universe multiverse
|
||||
EOF
|
||||
else
|
||||
cat >> "$1/etc/apt/sources.list" << EOF
|
||||
deb $MIRROR ${release} main restricted universe multiverse
|
||||
deb $MIRROR ${release}-updates main restricted universe multiverse
|
||||
deb $SECURITY_MIRROR ${release}-security main restricted universe multiverse
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
copy_ubuntu()
|
||||
{
|
||||
cache=$1
|
||||
arch=$2
|
||||
rootfs=$3
|
||||
|
||||
# make a local copy of the miniubuntu
|
||||
echo "Copying rootfs to $rootfs ..."
|
||||
mkdir -p $rootfs
|
||||
rsync -a $cache/rootfs-$arch/ $rootfs/ || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
install_ubuntu()
|
||||
{
|
||||
rootfs=$1
|
||||
release=$2
|
||||
cache=$3 # "/var/cache/lxc/$release"
|
||||
mkdir -p /var/lock/subsys/
|
||||
|
||||
(
|
||||
flock -x 200
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Cache repository is busy."
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "Copy $cache/rootfs-$arch to $rootfs ... "
|
||||
copy_ubuntu $cache $arch $rootfs
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to copy rootfs"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
|
||||
) 200>/var/lock/subsys/lxc
|
||||
|
||||
return $?
|
||||
}
|
||||
|
||||
copy_configuration()
|
||||
{
|
||||
path=$1
|
||||
rootfs=$2
|
||||
name=$3
|
||||
arch=$4
|
||||
release=$5
|
||||
|
||||
if [ $arch = "i386" ]; then
|
||||
arch="i686"
|
||||
fi
|
||||
|
||||
ttydir=""
|
||||
if [ -f $rootfs/etc/init/container-detect.conf ]; then
|
||||
ttydir=" lxc"
|
||||
fi
|
||||
|
||||
# if there is exactly one veth network entry, make sure it has an
|
||||
# associated hwaddr.
|
||||
nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' $path/config | wc -l`
|
||||
if [ $nics -eq 1 ]; then
|
||||
grep -q "^lxc.network.hwaddr" $path/config || cat <<EOF >> $path/config
|
||||
lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')
|
||||
EOF
|
||||
fi
|
||||
|
||||
grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config
|
||||
cat <<EOF >> $path/config
|
||||
lxc.utsname = $name
|
||||
|
||||
lxc.devttydir =$ttydir
|
||||
lxc.tty = 4
|
||||
lxc.pts = 1024
|
||||
lxc.mount = $path/fstab
|
||||
lxc.arch = $arch
|
||||
lxc.cap.drop = sys_module mac_admin mac_override
|
||||
lxc.pivotdir = lxc_putold
|
||||
|
||||
# uncomment the next line to run the container unconfined:
|
||||
#lxc.aa_profile = unconfined
|
||||
|
||||
lxc.cgroup.devices.deny = a
|
||||
# Allow any mknod (but not using the node)
|
||||
lxc.cgroup.devices.allow = c *:* m
|
||||
lxc.cgroup.devices.allow = b *:* m
|
||||
# /dev/null and zero
|
||||
lxc.cgroup.devices.allow = c 1:3 rwm
|
||||
lxc.cgroup.devices.allow = c 1:5 rwm
|
||||
# consoles
|
||||
lxc.cgroup.devices.allow = c 5:1 rwm
|
||||
lxc.cgroup.devices.allow = c 5:0 rwm
|
||||
#lxc.cgroup.devices.allow = c 4:0 rwm
|
||||
#lxc.cgroup.devices.allow = c 4:1 rwm
|
||||
# /dev/{,u}random
|
||||
lxc.cgroup.devices.allow = c 1:9 rwm
|
||||
lxc.cgroup.devices.allow = c 1:8 rwm
|
||||
lxc.cgroup.devices.allow = c 136:* rwm
|
||||
lxc.cgroup.devices.allow = c 5:2 rwm
|
||||
# rtc
|
||||
lxc.cgroup.devices.allow = c 254:0 rwm
|
||||
#fuse
|
||||
lxc.cgroup.devices.allow = c 10:229 rwm
|
||||
#tun
|
||||
lxc.cgroup.devices.allow = c 10:200 rwm
|
||||
#full
|
||||
lxc.cgroup.devices.allow = c 1:7 rwm
|
||||
#hpet
|
||||
lxc.cgroup.devices.allow = c 10:228 rwm
|
||||
#kvm
|
||||
lxc.cgroup.devices.allow = c 10:232 rwm
|
||||
EOF
|
||||
|
||||
cat <<EOF > $path/fstab
|
||||
proc proc proc nodev,noexec,nosuid 0 0
|
||||
sysfs sys sysfs defaults 0 0
|
||||
EOF
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to add configuration"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
trim()
|
||||
{
|
||||
rootfs=$1
|
||||
release=$2
|
||||
|
||||
# provide the lxc service
|
||||
cat <<EOF > $rootfs/etc/init/lxc.conf
|
||||
# fake some events needed for correct startup other services
|
||||
|
||||
description "Container Upstart"
|
||||
|
||||
start on startup
|
||||
|
||||
script
|
||||
rm -rf /var/run/*.pid
|
||||
rm -rf /var/run/network/*
|
||||
/sbin/initctl emit stopped JOB=udevtrigger --no-wait
|
||||
/sbin/initctl emit started JOB=udev --no-wait
|
||||
end script
|
||||
EOF
|
||||
|
||||
# fix buggus runlevel with sshd
|
||||
cat <<EOF > $rootfs/etc/init/ssh.conf
|
||||
# ssh - OpenBSD Secure Shell server
|
||||
#
|
||||
# The OpenSSH server provides secure shell access to the system.
|
||||
|
||||
description "OpenSSH server"
|
||||
|
||||
start on filesystem
|
||||
stop on runlevel [!2345]
|
||||
|
||||
expect fork
|
||||
respawn
|
||||
respawn limit 10 5
|
||||
umask 022
|
||||
# replaces SSHD_OOM_ADJUST in /etc/default/ssh
|
||||
oom never
|
||||
|
||||
pre-start script
|
||||
test -x /usr/sbin/sshd || { stop; exit 0; }
|
||||
test -e /etc/ssh/sshd_not_to_be_run && { stop; exit 0; }
|
||||
test -c /dev/null || { stop; exit 0; }
|
||||
|
||||
mkdir -p -m0755 /var/run/sshd
|
||||
end script
|
||||
|
||||
# if you used to set SSHD_OPTS in /etc/default/ssh, you can change the
|
||||
# 'exec' line here instead
|
||||
exec /usr/sbin/sshd
|
||||
EOF
|
||||
|
||||
cat <<EOF > $rootfs/etc/init/console.conf
|
||||
# console - getty
|
||||
#
|
||||
# This service maintains a console on tty1 from the point the system is
|
||||
# started until it is shut down again.
|
||||
|
||||
start on stopped rc RUNLEVEL=[2345]
|
||||
stop on runlevel [!2345]
|
||||
|
||||
respawn
|
||||
exec /sbin/getty -8 38400 /dev/console
|
||||
EOF
|
||||
|
||||
cat <<EOF > $rootfs/lib/init/fstab
|
||||
# /lib/init/fstab: cleared out for bare-bones lxc
|
||||
EOF
|
||||
|
||||
# reconfigure some services
|
||||
if [ -z "$LANG" ]; then
|
||||
chroot $rootfs locale-gen en_US.UTF-8
|
||||
chroot $rootfs update-locale LANG=en_US.UTF-8
|
||||
else
|
||||
chroot $rootfs locale-gen $LANG
|
||||
chroot $rootfs update-locale LANG=$LANG
|
||||
fi
|
||||
|
||||
# remove pointless services in a container
|
||||
chroot $rootfs /usr/sbin/update-rc.d -f ondemand remove
|
||||
|
||||
chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls u*.conf); do mv $f $f.orig; done'
|
||||
chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls tty[2-9].conf); do mv $f $f.orig; done'
|
||||
chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls plymouth*.conf); do mv $f $f.orig; done'
|
||||
chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls hwclock*.conf); do mv $f $f.orig; done'
|
||||
chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls module*.conf); do mv $f $f.orig; done'
|
||||
|
||||
# if this isn't lucid, then we need to twiddle the network upstart bits :(
|
||||
if [ $release != "lucid" ]; then
|
||||
sed -i 's/^.*emission handled.*$/echo Emitting lo/' $rootfs/etc/network/if-up.d/upstart
|
||||
fi
|
||||
}
|
||||
|
||||
post_process()
|
||||
{
|
||||
rootfs=$1
|
||||
release=$2
|
||||
trim_container=$3
|
||||
|
||||
if [ $trim_container -eq 1 ]; then
|
||||
trim $rootfs $release
|
||||
elif [ ! -f $rootfs/etc/init/container-detect.conf ]; then
|
||||
# Make sure we have a working resolv.conf
|
||||
cresolvonf="${rootfs}/etc/resolv.conf"
|
||||
mv $cresolvonf ${cresolvonf}.lxcbak
|
||||
cat /etc/resolv.conf > ${cresolvonf}
|
||||
|
||||
# for lucid, if not trimming, then add the ubuntu-virt
|
||||
# ppa and install lxcguest
|
||||
if [ $release = "lucid" ]; then
|
||||
chroot $rootfs apt-get update
|
||||
chroot $rootfs apt-get install --force-yes -y python-software-properties
|
||||
chroot $rootfs add-apt-repository ppa:ubuntu-virt/ppa
|
||||
fi
|
||||
|
||||
chroot $rootfs apt-get update
|
||||
chroot $rootfs apt-get install --force-yes -y lxcguest
|
||||
|
||||
# Restore old resolv.conf
|
||||
rm -f ${cresolvonf}
|
||||
mv ${cresolvonf}.lxcbak ${cresolvonf}
|
||||
fi
|
||||
|
||||
# If the container isn't running a native architecture, setup multiarch
|
||||
if [ -x "$(ls -1 ${rootfs}/usr/bin/qemu-*-static 2>/dev/null)" ]; then
|
||||
dpkg_version=$(chroot $rootfs dpkg-query -W -f='${Version}' dpkg)
|
||||
if chroot $rootfs dpkg --compare-versions $dpkg_version ge "1.16.2"; then
|
||||
chroot $rootfs dpkg --add-architecture ${hostarch}
|
||||
else
|
||||
mkdir -p ${rootfs}/etc/dpkg/dpkg.cfg.d
|
||||
echo "foreign-architecture ${hostarch}" > ${rootfs}/etc/dpkg/dpkg.cfg.d/lxc-multiarch
|
||||
fi
|
||||
|
||||
# Save existing value of MIRROR and SECURITY_MIRROR
|
||||
DEFAULT_MIRROR=$MIRROR
|
||||
DEFAULT_SECURITY_MIRROR=$SECURITY_MIRROR
|
||||
|
||||
# Write a new sources.list containing both native and multiarch entries
|
||||
> ${rootfs}/etc/apt/sources.list
|
||||
write_sourceslist $rootfs $arch "native"
|
||||
|
||||
MIRROR=$DEFAULT_MIRROR
|
||||
SECURITY_MIRROR=$DEFAULT_SECURITY_MIRROR
|
||||
write_sourceslist $rootfs $hostarch "multiarch"
|
||||
|
||||
# Finally update the lists and install upstart using the host architecture
|
||||
chroot $rootfs apt-get update
|
||||
chroot $rootfs apt-get install --force-yes -y --no-install-recommends upstart:${hostarch} mountall:${hostarch} iproute:${hostarch} isc-dhcp-client:${hostarch}
|
||||
fi
|
||||
|
||||
# rmdir /dev/shm for containers that have /run/shm
|
||||
# I'm afraid of doing rm -rf $rootfs/dev/shm, in case it did
|
||||
# get bind mounted to the host's /run/shm. So try to rmdir
|
||||
# it, and in case that fails move it out of the way.
|
||||
if [ ! -L $rootfs/dev/shm ] && [ -d $rootfs/run/shm ] && [ -e $rootfs/dev/shm ]; then
|
||||
mv $rootfs/dev/shm $rootfs/dev/shm.bak
|
||||
ln -s /run/shm $rootfs/dev/shm
|
||||
fi
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
cat <<EOF
|
||||
$1 -h|--help [-a|--arch] [--trim] [-d|--debug]
|
||||
[-F | --flush-cache] [-r|--release <release>] [ -S | --auth-key <keyfile>]
|
||||
release: the ubuntu release (e.g. precise): defaults to host release on ubuntu, otherwise uses latest LTS
|
||||
trim: make a minimal (faster, but not upgrade-safe) container
|
||||
arch: the container architecture (e.g. amd64): defaults to host arch
|
||||
auth-key: SSH Public key file to inject into container
|
||||
EOF
|
||||
return 0
|
||||
}
|
||||
|
||||
options=$(getopt -o a:b:hp:r:xn:FS:d:C -l arch:,help,path:,release:,trim,name:,flush-cache,auth-key:,debug:,cache: -- "$@")
|
||||
if [ $? -ne 0 ]; then
|
||||
usage $(basename $0)
|
||||
exit 1
|
||||
fi
|
||||
eval set -- "$options"
|
||||
|
||||
release=precise # Default to the last Ubuntu LTS release for non-Ubuntu systems
|
||||
if [ -f /etc/lsb-release ]; then
|
||||
. /etc/lsb-release
|
||||
if [ "$DISTRIB_ID" = "Ubuntu" ]; then
|
||||
release=$DISTRIB_CODENAME
|
||||
fi
|
||||
fi
|
||||
|
||||
arch=$(arch)
|
||||
|
||||
# Code taken from debootstrap
|
||||
if [ -x /usr/bin/dpkg ] && /usr/bin/dpkg --print-architecture >/dev/null 2>&1; then
|
||||
arch=`/usr/bin/dpkg --print-architecture`
|
||||
elif type udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then
|
||||
arch=`/usr/bin/udpkg --print-architecture`
|
||||
else
|
||||
arch=$(arch)
|
||||
if [ "$arch" = "i686" ]; then
|
||||
arch="i386"
|
||||
elif [ "$arch" = "x86_64" ]; then
|
||||
arch="amd64"
|
||||
elif [ "$arch" = "armv7l" ]; then
|
||||
arch="armel"
|
||||
fi
|
||||
fi
|
||||
|
||||
debug=0
|
||||
trim_container=0
|
||||
hostarch=$arch
|
||||
while true
|
||||
do
|
||||
case "$1" in
|
||||
-h|--help) usage $0 && exit 0;;
|
||||
-p|--path) path=$2; shift 2;;
|
||||
-n|--name) name=$2; shift 2;;
|
||||
-C|--cache) cache=$2; shift 2;;
|
||||
-r|--release) release=$2; shift 2;;
|
||||
-a|--arch) arch=$2; shift 2;;
|
||||
-x|--trim) trim_container=1; shift 1;;
|
||||
-S|--auth-key) auth_key=$2; shift 2;;
|
||||
-d|--debug) debug=1; shift 1;;
|
||||
--) shift 1; break ;;
|
||||
*) break ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ $debug -eq 1 ]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
|
||||
if [ "$arch" == "i686" ]; then
|
||||
arch=i386
|
||||
fi
|
||||
|
||||
if [ $hostarch = "i386" -a $arch = "amd64" ]; then
|
||||
echo "can't create amd64 container on i386"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$path" ]; then
|
||||
echo "'path' parameter is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$(id -u)" != "0" ]; then
|
||||
echo "This script should be run as 'root'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# detect rootfs
|
||||
config="$path/config"
|
||||
if grep -q '^lxc.rootfs' $config 2>/dev/null ; then
|
||||
rootfs=`grep 'lxc.rootfs =' $config | awk -F= '{ print $2 }'`
|
||||
else
|
||||
rootfs=$path/rootfs
|
||||
fi
|
||||
|
||||
install_ubuntu $rootfs $release $cache
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "failed to install ubuntu $release"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
configure_ubuntu $rootfs $release
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "failed to configure ubuntu $release for a container"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
copy_configuration $path $rootfs $name $arch $release
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "failed write configuration file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
post_process $rootfs $release $trim_container
|
||||
|
||||
finalize_user vagrant
|
||||
|
||||
echo ""
|
||||
echo "##"
|
||||
echo "# The default user is 'vagrant' with password 'vagrant'!"
|
||||
echo "# Use the 'sudo' command to run tasks as root in the container."
|
||||
echo "##"
|
||||
echo ""
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"provider": "lxc",
|
||||
"vagrant-lxc-version": "0.0.1",
|
||||
|
||||
"template-opts": {
|
||||
"--arch": "amd64",
|
||||
"--release": "quantal"
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
def local_cache(box_name)
|
||||
cache_dir = File.join(File.expand_path(Vagrant::Environment::DEFAULT_HOME),
|
||||
'cache',
|
||||
'apt',
|
||||
box_name)
|
||||
partial_dir = File.join(cache_dir, 'partial')
|
||||
FileUtils.mkdir_p(partial_dir) unless File.exists? partial_dir
|
||||
cache_dir
|
||||
end
|
||||
|
||||
Vagrant::Config.run do |config|
|
||||
config.vm.box = "quantal64"
|
||||
config.vm.box_url = "https://github.com/downloads/roderik/VagrantQuantal64Box/quantal64.box"
|
||||
|
||||
cache_dir = local_cache(config.vm.box)
|
||||
config.vm.share_folder "v-root", "/vagrant", "../"
|
||||
config.vm.share_folder "v-cache", "/var/cache/apt/archives", cache_dir
|
||||
|
||||
if defined? VagrantVbguest::Config
|
||||
config.vbguest.auto_update = false
|
||||
config.vbguest.no_remote = true
|
||||
end
|
||||
|
||||
config.vm.provision :shell, :path => 'shell-provisioning/upgrade-kernel'
|
||||
|
||||
config.vm.provision :puppet do |puppet|
|
||||
puppet.manifests_path = "."
|
||||
puppet.manifest_file = "site.pp"
|
||||
# Pass DEBUG=1 to vagrant commands if you want to make some debugging noise
|
||||
puppet.options << [ "--verbose", "--debug" ] if ENV["DEBUG"] == '1'
|
||||
end
|
||||
end
|
|
@ -1,55 +0,0 @@
|
|||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
def local_cache(box_name)
|
||||
cache_dir = File.join(File.expand_path(Vagrant::Environment::DEFAULT_HOME),
|
||||
'cache',
|
||||
'apt',
|
||||
box_name)
|
||||
partial_dir = File.join(cache_dir, 'partial')
|
||||
FileUtils.mkdir_p(partial_dir) unless File.exists? partial_dir
|
||||
cache_dir
|
||||
end
|
||||
|
||||
Vagrant.require_plugin 'vagrant-lxc'
|
||||
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = "quantal64"
|
||||
|
||||
config.vm.synced_folder "../", "/vagrant", name: 'vagrant-root'
|
||||
|
||||
cache_dir = local_cache(config.vm.box)
|
||||
config.vm.synced_folder cache_dir, "/var/cache/apt/archives", name: "vagrant-cache"
|
||||
|
||||
config.vm.define :vbox do |vb_config|
|
||||
vb_config.vm.box_url = "https://github.com/downloads/roderik/VagrantQuantal64Box/quantal64.box"
|
||||
vb_config.vm.hostname = 'vbox'
|
||||
|
||||
vb_config.vm.provider :virtualbox do |vb|
|
||||
# Configure VM to use 1.5gb of ram and 3 cpus
|
||||
vb.customize [
|
||||
"modifyvm", :id,
|
||||
"--memory", '1536',
|
||||
"--cpus", '4'
|
||||
]
|
||||
end
|
||||
|
||||
vb_config.vm.provision :shell, :path => 'shell-provisioning/upgrade-kernel'
|
||||
end
|
||||
|
||||
config.vm.define :lxc do |lxc_config|
|
||||
lxc_config.vm.hostname = 'lxc-dev-box'
|
||||
lxc_config.vm.box_url = 'http://dl.dropbox.com/u/13510779/lxc-quantal64-2013-03-10.box'
|
||||
|
||||
lxc_config.vm.provider :lxc do |lxc|
|
||||
# Required to boot nested containers
|
||||
lxc.start_opts << 'lxc.aa_profile=unconfined'
|
||||
end
|
||||
end
|
||||
|
||||
config.vm.provision :puppet do |puppet|
|
||||
puppet.manifests_path = "."
|
||||
puppet.manifest_file = "site.pp"
|
||||
puppet.options << [ '--verbose', '--debug' ]
|
||||
end
|
||||
end
|
|
@ -1,37 +0,0 @@
|
|||
###############################################################################
|
||||
# This file has the same configs as the built in /etc/default/lxc on Ubuntu,
|
||||
# we only changed IPs to 10.0.254.* to avoid collision with LXC default 10.0.3.*
|
||||
# which is likely to be running from the host machine
|
||||
###############################################################################
|
||||
|
||||
|
||||
# MIRROR to be used by ubuntu template at container creation:
|
||||
# Leaving it undefined is fine
|
||||
#MIRROR="http://archive.ubuntu.com/ubuntu"
|
||||
# or
|
||||
#MIRROR="http://<host-ip-addr>:3142/archive.ubuntu.com/ubuntu"
|
||||
|
||||
# LXC_AUTO - whether or not to start containers symlinked under
|
||||
# /etc/lxc/auto
|
||||
LXC_AUTO="true"
|
||||
|
||||
# Leave USE_LXC_BRIDGE as "true" if you want to use lxcbr0 for your
|
||||
# containers. Set to "false" if you'll use virbr0 or another existing
|
||||
# bridge, or mavlan to your host's NIC.
|
||||
USE_LXC_BRIDGE="true"
|
||||
|
||||
# If you change the LXC_BRIDGE to something other than lxcbr1, then
|
||||
# you will also need to update your /etc/lxc/lxc.conf as well as the
|
||||
# configuration (/var/lib/lxc/<container>/config) for any containers
|
||||
# already created using the default config to reflect the new bridge
|
||||
# name.
|
||||
# If you have the dnsmasq daemon installed, you'll also have to update
|
||||
# /etc/dnsmasq.d/lxc and restart the system wide dnsmasq daemon.
|
||||
LXC_BRIDGE="lxcbr0"
|
||||
LXC_ADDR="10.0.253.1"
|
||||
LXC_NETMASK="255.255.255.0"
|
||||
LXC_NETWORK="10.0.253.0/24"
|
||||
LXC_DHCP_RANGE="10.0.253.2,10.0.253.254"
|
||||
LXC_DHCP_MAX="253"
|
||||
|
||||
LXC_SHUTDOWN_TIMEOUT=120
|
|
@ -1,37 +0,0 @@
|
|||
###############################################################################
|
||||
# This file has the same configs as the built in /etc/default/lxc on Ubuntu,
|
||||
# we only changed IPs to 10.0.254.* to avoid collision with LXC default 10.0.3.*
|
||||
# which is likely to be running from the host machine
|
||||
###############################################################################
|
||||
|
||||
|
||||
# MIRROR to be used by ubuntu template at container creation:
|
||||
# Leaving it undefined is fine
|
||||
#MIRROR="http://archive.ubuntu.com/ubuntu"
|
||||
# or
|
||||
#MIRROR="http://<host-ip-addr>:3142/archive.ubuntu.com/ubuntu"
|
||||
|
||||
# LXC_AUTO - whether or not to start containers symlinked under
|
||||
# /etc/lxc/auto
|
||||
LXC_AUTO="true"
|
||||
|
||||
# Leave USE_LXC_BRIDGE as "true" if you want to use lxcbr0 for your
|
||||
# containers. Set to "false" if you'll use virbr0 or another existing
|
||||
# bridge, or mavlan to your host's NIC.
|
||||
USE_LXC_BRIDGE="true"
|
||||
|
||||
# If you change the LXC_BRIDGE to something other than lxcbr1, then
|
||||
# you will also need to update your /etc/lxc/lxc.conf as well as the
|
||||
# configuration (/var/lib/lxc/<container>/config) for any containers
|
||||
# already created using the default config to reflect the new bridge
|
||||
# name.
|
||||
# If you have the dnsmasq daemon installed, you'll also have to update
|
||||
# /etc/dnsmasq.d/lxc and restart the system wide dnsmasq daemon.
|
||||
LXC_BRIDGE="lxcbr0"
|
||||
LXC_ADDR="10.0.254.1"
|
||||
LXC_NETMASK="255.255.255.0"
|
||||
LXC_NETWORK="10.0.254.0/24"
|
||||
LXC_DHCP_RANGE="10.0.254.2,10.0.254.254"
|
||||
LXC_DHCP_MAX="253"
|
||||
|
||||
LXC_SHUTDOWN_TIMEOUT=120
|
|
@ -1,14 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
|
||||
if [[ `uname -r` != "3.5.0-17-generic" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
echo 'An old kernel was found on the guest machine and it will be upgraded' 1>&2
|
||||
echo 'Please reload the box after provisioning when finished' 1>&2
|
||||
sudo apt-get update
|
||||
sudo apt-get install linux-image-3.5.0-25-generic linux-headers-3.5.0-25-generic -y
|
||||
sudo apt-get dist-upgrade -y
|
||||
sudo apt-get autoremove -y
|
|
@ -1,125 +0,0 @@
|
|||
Exec { path => [ '/bin/', '/sbin/' , '/usr/bin/', '/usr/sbin/', '/usr/local/bin'] }
|
||||
|
||||
# Because I'm lazy ;)
|
||||
exec {
|
||||
'echo "alias be=\"bundle exec\"" >> /home/vagrant/.bashrc':
|
||||
unless => 'grep -q "bundle exec" /home/vagrant/.bashrc';
|
||||
|
||||
'echo "cd /vagrant" >> /home/vagrant/.bashrc':
|
||||
unless => 'grep -q "cd /vagrant" /home/vagrant/.bashrc';
|
||||
}
|
||||
|
||||
# Overwrite LXC default configs
|
||||
exec {
|
||||
'config-lxc':
|
||||
# We need to do this otherwise IPs will collide with the host's lxc dhcp server.
|
||||
# If we install the package prior to setting this configs the container will go crazy.
|
||||
command => "cp /vagrant/development/lxc-configs/${hostname} /etc/default/lxc"
|
||||
;
|
||||
}
|
||||
|
||||
# Install dependencies
|
||||
package {
|
||||
[ 'libffi-dev', 'bsdtar', 'exuberant-ctags', 'ruby1.9.1-dev', 'htop', 'git',
|
||||
'build-essential', 'dnsutils', 'fping' ]:
|
||||
ensure => 'installed'
|
||||
;
|
||||
|
||||
'lxc':
|
||||
require => Exec['config-lxc']
|
||||
;
|
||||
|
||||
'bundler':
|
||||
ensure => 'installed',
|
||||
provider => 'gem'
|
||||
;
|
||||
}
|
||||
|
||||
# Make sure we can create and boot nested containers
|
||||
if $hostname == 'vbox' {
|
||||
package { 'apparmor-utils': }
|
||||
exec { 'aa-complain /usr/bin/lxc-start': }
|
||||
}
|
||||
|
||||
# TMUX
|
||||
package {
|
||||
'tmux': ensure => 'installed';
|
||||
}
|
||||
|
||||
# Allow gems to be installed on vagrant user home avoiding "sudo"s
|
||||
# Tks to http://wiki.railsplayground.com/railsplayground/show/How+to+install+gems+and+non+root+user
|
||||
file {
|
||||
'/home/vagrant/gems':
|
||||
ensure => directory,
|
||||
owner => 'vagrant',
|
||||
group => 'vagrant'
|
||||
;
|
||||
|
||||
'/home/vagrant/.gemrc':
|
||||
content => '
|
||||
---
|
||||
:verbose: true
|
||||
gem: --no-ri --no-rdoc
|
||||
:update_sources: true
|
||||
:sources:
|
||||
- http://gems.rubyforge.org
|
||||
- http://gems.github.com
|
||||
:backtrace: false
|
||||
:bulk_threshold: 1000
|
||||
:benchmark: false
|
||||
gemhome: /home/vagrant/gems
|
||||
gempath:
|
||||
- /home/vagrant/gems
|
||||
- /usr/local/lib/ruby/gems/1.8
|
||||
'
|
||||
}
|
||||
exec {
|
||||
'set-gem-paths':
|
||||
command => 'cat << EOF >> /home/vagrant/.profile
|
||||
export GEM_HOME=/home/vagrant/gems
|
||||
export GEM_PATH=/home/vagrant/gems:/var/lib/gems/1.9.1
|
||||
export PATH=$PATH:/home/vagrant/gems/bin
|
||||
EOF',
|
||||
unless => 'grep -q "GEM_HOME" /home/vagrant/.profile'
|
||||
}
|
||||
|
||||
# Bundle!
|
||||
exec {
|
||||
'su -l vagrant -c "cd /vagrant && bundle install"':
|
||||
# We are checking for guard-rspec here but it could be any gem...
|
||||
unless => 'gem list guard | grep -q rspec',
|
||||
cwd => '/vagrant',
|
||||
require => [
|
||||
Exec['set-gem-paths'],
|
||||
File['/home/vagrant/gems', '/home/vagrant/.gemrc'],
|
||||
Package['bundler']
|
||||
]
|
||||
}
|
||||
|
||||
# Setup vagrant default ssh key
|
||||
file {
|
||||
'/home/vagrant/.ssh':
|
||||
ensure => directory,
|
||||
owner => 'vagrant',
|
||||
group => 'vagrant'
|
||||
}
|
||||
exec {
|
||||
'download-private-key':
|
||||
command => 'wget https://raw.github.com/mitchellh/vagrant/master/keys/vagrant -O /home/vagrant/.ssh/id_rsa',
|
||||
creates => '/home/vagrant/.ssh/id_rsa',
|
||||
require => File['/home/vagrant/.ssh'],
|
||||
user => 'vagrant'
|
||||
;
|
||||
|
||||
'wget https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub -O /home/vagrant/.ssh/id_rsa.pub':
|
||||
creates => '/home/vagrant/.ssh/id_rsa.pub',
|
||||
require => File['/home/vagrant/.ssh'],
|
||||
user => 'vagrant'
|
||||
;
|
||||
}
|
||||
file {
|
||||
'/home/vagrant/.ssh/id_rsa':
|
||||
ensure => 'present',
|
||||
mode => '0600',
|
||||
require => Exec['download-private-key']
|
||||
}
|
42
example/Vagrantfile
vendored
42
example/Vagrantfile
vendored
|
@ -1,42 +0,0 @@
|
|||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
def local_cache(box_name)
|
||||
cache_dir = File.join(File.expand_path(Vagrant::Environment::DEFAULT_HOME),
|
||||
'cache',
|
||||
'apt',
|
||||
box_name)
|
||||
partial_dir = File.join(cache_dir, 'partial')
|
||||
FileUtils.mkdir_p(partial_dir) unless File.exists? partial_dir
|
||||
cache_dir
|
||||
end
|
||||
|
||||
Vagrant.require_plugin 'vagrant-lxc'
|
||||
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = "quantal64"
|
||||
config.vm.box_url = 'http://dl.dropbox.com/u/13510779/lxc-quantal64-2013-03-10.box'
|
||||
config.vm.hostname = 'lxc-quantal64'
|
||||
|
||||
config.vm.synced_folder "/tmp", "/vagrant_data"
|
||||
|
||||
cache_dir = local_cache(config.vm.box)
|
||||
config.vm.synced_folder cache_dir, "/var/cache/apt/archives"
|
||||
|
||||
config.vm.provider :lxc do |lxc|
|
||||
lxc.start_opts << 'lxc.cgroup.memory.limit_in_bytes=400M'
|
||||
lxc.start_opts << 'lxc.cgroup.memory.memsw.limit_in_bytes=500M'
|
||||
end
|
||||
|
||||
config.vm.provision :shell, :inline => <<-SCRIPT
|
||||
echo "Hi there I'm a shell script used for provisioning"
|
||||
SCRIPT
|
||||
|
||||
config.vm.provision :puppet do |puppet|
|
||||
puppet.module_path = "puppet/modules"
|
||||
puppet.manifests_path = "puppet/manifests"
|
||||
puppet.manifest_file = "site.pp"
|
||||
# If you want to make some debugging noise
|
||||
# puppet.options << [ '--verbose', '--debug' ]
|
||||
end
|
||||
end
|
|
@ -1,5 +0,0 @@
|
|||
Exec { path => [ '/bin/', '/sbin/' , '/usr/bin/', '/usr/sbin/'] }
|
||||
|
||||
notice "Hi there! puppet here"
|
||||
|
||||
require hello_world
|
|
@ -1,3 +0,0 @@
|
|||
class hello_world {
|
||||
notice "Puppet module here. Things seem to be working just fine ;-)"
|
||||
}
|
|
@ -1,6 +1,10 @@
|
|||
require "vendored_vagrant"
|
||||
|
||||
require "vagrant-lxc/version"
|
||||
require "vagrant-lxc/plugin"
|
||||
|
||||
I18n.load_path << File.expand_path(File.dirname(__FILE__) + '/../locales/en.yml')
|
||||
module Vagrant
|
||||
module LXC
|
||||
def self.source_root
|
||||
@source_root ||= Pathname.new(File.dirname(__FILE__)).join('..').expand_path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,83 +1,82 @@
|
|||
require 'vagrant-lxc/action/base_action'
|
||||
|
||||
require 'vagrant-lxc/action/boot'
|
||||
require 'vagrant-lxc/action/check_created'
|
||||
require 'vagrant-lxc/action/check_running'
|
||||
require 'vagrant-lxc/action/clear_forwarded_ports'
|
||||
require 'vagrant-lxc/action/create'
|
||||
require 'vagrant-lxc/action/created'
|
||||
require 'vagrant-lxc/action/destroy'
|
||||
require 'vagrant-lxc/action/destroy_confirm'
|
||||
require 'vagrant-lxc/action/compress_rootfs'
|
||||
require 'vagrant-lxc/action/fetch_ip_with_lxc_info'
|
||||
require 'vagrant-lxc/action/forced_halt'
|
||||
require 'vagrant-lxc/action/forward_ports'
|
||||
require 'vagrant-lxc/action/gc_private_network_bridges'
|
||||
require 'vagrant-lxc/action/handle_box_metadata'
|
||||
require 'vagrant-lxc/action/is_running'
|
||||
require 'vagrant-lxc/action/network'
|
||||
require 'vagrant-lxc/action/share_folders'
|
||||
require 'vagrant-lxc/action/prepare_nfs_settings'
|
||||
require 'vagrant-lxc/action/prepare_nfs_valid_ids'
|
||||
require 'vagrant-lxc/action/private_networks'
|
||||
require 'vagrant-lxc/action/setup_package_files'
|
||||
require 'vagrant-lxc/action/warn_networks'
|
||||
|
||||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
# Shortcuts
|
||||
Builtin = Vagrant::Action::Builtin
|
||||
Builder = Vagrant::Action::Builder
|
||||
|
||||
# This action is responsible for reloading the machine, which
|
||||
# brings it down, sucks in new configuration, and brings the
|
||||
# machine back up with the new configuration.
|
||||
def self.action_reload
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
# b.use CheckLXC
|
||||
b.use Vagrant::Action::Builtin::Call, Created do |env1, b2|
|
||||
if !env1[:result]
|
||||
b2.use VagrantPlugins::ProviderVirtualBox::Action::MessageNotCreated
|
||||
Builder.new.tap do |b|
|
||||
b.use Builtin::Call, Builtin::IsState, :not_created do |env1, b2|
|
||||
if env1[:result]
|
||||
b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created")
|
||||
next
|
||||
end
|
||||
|
||||
b2.use Vagrant::Action::Builtin::ConfigValidate
|
||||
b2.use Builtin::ConfigValidate
|
||||
b2.use action_halt
|
||||
b2.use action_start
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# We could do this here as VirtualBox does, but at least for now its better
|
||||
# to be explicit and have the full constant name in order to easily spot
|
||||
# what we implemented and what is builtin on Vagrant.
|
||||
#
|
||||
# include Vagrant::Action::Builtin
|
||||
|
||||
# This action boots the VM, assuming the VM is in a state that requires
|
||||
# a bootup (i.e. not saved).
|
||||
def self.action_boot
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
# b.use ClearForwardedPorts
|
||||
b.use Vagrant::Action::Builtin::Provision
|
||||
b.use Vagrant::Action::Builtin::EnvSet, :port_collision_repair => true
|
||||
# b.use PrepareForwardedPortCollisionParams
|
||||
# b.use ClearSharedFolders
|
||||
b.use ShareFolders
|
||||
b.use Network
|
||||
# b.use ForwardPorts
|
||||
b.use Vagrant::Action::Builtin::SetHostname
|
||||
# b.use SaneDefaults
|
||||
# b.use Customize
|
||||
Builder.new.tap do |b|
|
||||
b.use Builtin::Provision
|
||||
b.use Builtin::EnvSet, :port_collision_repair => true
|
||||
b.use Builtin::HandleForwardedPortCollisions
|
||||
b.use PrepareNFSValidIds
|
||||
b.use Builtin::SyncedFolderCleanup
|
||||
b.use Builtin::SyncedFolders
|
||||
b.use PrepareNFSSettings
|
||||
b.use Builtin::SetHostname
|
||||
b.use WarnNetworks
|
||||
b.use ForwardPorts
|
||||
b.use PrivateNetworks
|
||||
b.use Boot
|
||||
b.use Builtin::WaitForCommunicator
|
||||
end
|
||||
end
|
||||
|
||||
# This action just runs the provisioners on the machine.
|
||||
def self.action_provision
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
# b.use CheckLXC
|
||||
b.use Vagrant::Action::Builtin::ConfigValidate
|
||||
b.use Vagrant::Action::Builtin::Call, Created do |env1, b2|
|
||||
if !env1[:result]
|
||||
b2.use VagrantPlugins::ProviderVirtualBox::Action::MessageNotCreated
|
||||
Builder.new.tap do |b|
|
||||
b.use Builtin::ConfigValidate
|
||||
b.use Builtin::Call, Builtin::IsState, :not_created do |env1, b2|
|
||||
if env1[:result]
|
||||
b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created")
|
||||
next
|
||||
end
|
||||
|
||||
b2.use Vagrant::Action::Builtin::Call, IsRunning do |env2, b3|
|
||||
b2.use Builtin::Call, Builtin::IsState, :running do |env2, b3|
|
||||
if !env2[:result]
|
||||
b3.use VagrantPlugins::ProviderVirtualBox::Action::MessageNotRunning
|
||||
b3.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_running")
|
||||
next
|
||||
end
|
||||
|
||||
# b3.use CheckAccessible
|
||||
b3.use Vagrant::Action::Builtin::Provision
|
||||
b3.use Builtin::Provision
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -86,13 +85,12 @@ module Vagrant
|
|||
# This action starts a container, assuming it is already created and exists.
|
||||
# A precondition of this action is that the container exists.
|
||||
def self.action_start
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
# b.use CheckLXC
|
||||
b.use Vagrant::Action::Builtin::ConfigValidate
|
||||
b.use Vagrant::Action::Builtin::Call, IsRunning do |env, b2|
|
||||
Builder.new.tap do |b|
|
||||
b.use Builtin::ConfigValidate
|
||||
b.use Builtin::BoxCheckOutdated
|
||||
b.use Builtin::Call, Builtin::IsState, :running do |env, b2|
|
||||
# If the VM is running, then our work here is done, exit
|
||||
next if env[:result]
|
||||
# TODO: Check if has been saved / frozen and resume
|
||||
b2.use action_boot
|
||||
end
|
||||
end
|
||||
|
@ -101,13 +99,12 @@ module Vagrant
|
|||
# This action brings the machine up from nothing, including creating the
|
||||
# container, configuring metadata, and booting.
|
||||
def self.action_up
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
# b.use CheckLXC
|
||||
b.use Vagrant::Action::Builtin::ConfigValidate
|
||||
b.use Vagrant::Action::Builtin::Call, Created do |env, b2|
|
||||
Builder.new.tap do |b|
|
||||
b.use Builtin::ConfigValidate
|
||||
b.use Builtin::Call, Builtin::IsState, :not_created do |env, b2|
|
||||
# If the VM is NOT created yet, then do the setup steps
|
||||
if !env[:result]
|
||||
b2.use Vagrant::Action::Builtin::HandleBoxUrl
|
||||
if env[:result]
|
||||
b2.use Builtin::HandleBox
|
||||
b2.use HandleBoxMetadata
|
||||
b2.use Create
|
||||
end
|
||||
|
@ -119,17 +116,19 @@ module Vagrant
|
|||
# This is the action that is primarily responsible for halting
|
||||
# the virtual machine, gracefully or by force.
|
||||
def self.action_halt
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
# b.use CheckLXC
|
||||
b.use Vagrant::Action::Builtin::Call, Created do |env, b2|
|
||||
Builder.new.tap do |b|
|
||||
b.use Builtin::Call, Builtin::IsState, :not_created do |env, b2|
|
||||
if env[:result]
|
||||
b2.use Vagrant::Action::Builtin::Call, Vagrant::Action::Builtin::GracefulHalt, :stopped, :running do |env2, b3|
|
||||
if !env2[:result] && env2[:machine].provider.state.running?
|
||||
b3.use ForcedHalt
|
||||
end
|
||||
b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created")
|
||||
next
|
||||
end
|
||||
|
||||
b2.use ClearForwardedPorts
|
||||
b2.use GcPrivateNetworkBridges
|
||||
b2.use Builtin::Call, Builtin::GracefulHalt, :stopped, :running do |env2, b3|
|
||||
if !env2[:result]
|
||||
b3.use ForcedHalt
|
||||
end
|
||||
else
|
||||
b2.use VagrantPlugins::ProviderVirtualBox::Action::MessageNotCreated
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -138,49 +137,96 @@ module Vagrant
|
|||
# This is the action that is primarily responsible for completely
|
||||
# freeing the resources of the underlying virtual machine.
|
||||
def self.action_destroy
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
# b.use CheckLXC
|
||||
b.use Vagrant::Action::Builtin::Call, Created do |env1, b2|
|
||||
if !env1[:result]
|
||||
b2.use VagrantPlugins::ProviderVirtualBox::Action::MessageNotCreated
|
||||
Builder.new.tap do |b|
|
||||
b.use Builtin::Call, Builtin::IsState, :not_created do |env1, b2|
|
||||
if env1[:result]
|
||||
b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created")
|
||||
next
|
||||
end
|
||||
|
||||
# TODO: Implement our own DestroyConfirm
|
||||
b2.use Vagrant::Action::Builtin::Call, VagrantPlugins::ProviderVirtualBox::Action::DestroyConfirm do |env2, b3|
|
||||
b2.use Builtin::Call, DestroyConfirm do |env2, b3|
|
||||
if env2[:result]
|
||||
b3.use Vagrant::Action::Builtin::ConfigValidate
|
||||
b3.use Vagrant::Action::Builtin::EnvSet, :force_halt => true
|
||||
b3.use Builtin::ConfigValidate
|
||||
b3.use Builtin::EnvSet, :force_halt => true
|
||||
b3.use action_halt
|
||||
b3.use Destroy
|
||||
b3.use Builtin::ProvisionerCleanup
|
||||
else
|
||||
# TODO: Implement our own MessageWillNotDestroy
|
||||
b3.use VagrantPlugins::ProviderVirtualBox::Action::MessageWillNotDestroy
|
||||
b3.use Builtin::Message, I18n.t("vagrant_lxc.messages.will_not_destroy")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This action packages the virtual machine into a single box file.
|
||||
def self.action_package
|
||||
Builder.new.tap do |b|
|
||||
b.use Builtin::Call, Builtin::IsState, :not_created do |env1, b2|
|
||||
if env1[:result]
|
||||
b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created")
|
||||
next
|
||||
end
|
||||
|
||||
b2.use action_halt
|
||||
b2.use CompressRootFS
|
||||
b2.use SetupPackageFiles
|
||||
b2.use Vagrant::Action::General::Package
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This action is called to read the IP of the container. The IP found
|
||||
# is expected to be put into the `:machine_ip` key.
|
||||
def self.action_ssh_ip
|
||||
Builder.new.tap do |b|
|
||||
b.use Builtin::Call, Builtin::ConfigValidate do |env, b2|
|
||||
b2.use FetchIpWithLxcInfo
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This is the action that will exec into an SSH shell.
|
||||
def self.action_ssh
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
# b.use CheckLXC
|
||||
b.use CheckCreated
|
||||
# b.use CheckAccessible
|
||||
b.use CheckRunning
|
||||
b.use Vagrant::Action::Builtin::SSHExec
|
||||
Builder.new.tap do |b|
|
||||
b.use Builtin::ConfigValidate
|
||||
b.use Builtin::Call, Builtin::IsState, :not_created do |env, b2|
|
||||
if env[:result]
|
||||
b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created")
|
||||
next
|
||||
end
|
||||
|
||||
b2.use Builtin::Call, Builtin::IsState, :running do |env1, b3|
|
||||
if !env1[:result]
|
||||
b3.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_running")
|
||||
next
|
||||
end
|
||||
|
||||
b3.use Builtin::SSHExec
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This is the action that will run a single SSH command.
|
||||
def self.action_ssh_run
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
# b.use CheckLXC
|
||||
b.use CheckCreated
|
||||
# b.use CheckAccessible
|
||||
b.use CheckRunning
|
||||
b.use Vagrant::Action::Builtin::SSHRun
|
||||
Builder.new.tap do |b|
|
||||
b.use Builtin::ConfigValidate
|
||||
b.use Builtin::Call, Builtin::IsState, :not_created do |env, b2|
|
||||
if env[:result]
|
||||
b2.use Builtin::Message, I18n.t("vagrant_lxc.messages.not_created")
|
||||
next
|
||||
end
|
||||
|
||||
b2.use Builtin::Call, Builtin::IsState, :running do |env1, b3|
|
||||
if !env1[:result]
|
||||
raise Vagrant::Errors::VMNotRunningError
|
||||
next
|
||||
end
|
||||
|
||||
b3.use Builtin::SSHRun
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class BaseAction
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,53 +1,44 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class Boot < BaseAction
|
||||
def call(env)
|
||||
@env = env
|
||||
|
||||
config = env[:machine].provider_config
|
||||
|
||||
# Allows this middleware to be called multiple times. We need to
|
||||
# support this as base boxes might have after create scripts which
|
||||
# require SSH access
|
||||
unless env[:machine].state.running?
|
||||
env[:ui].info I18n.t("vagrant.actions.vm.boot.booting")
|
||||
env[:machine].provider.container.start(config)
|
||||
raise Vagrant::Errors::VMFailedToBoot if !wait_for_boot
|
||||
end
|
||||
|
||||
@app.call env
|
||||
class Boot
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
# Stolen from on VagrantPlugins::ProviderVirtualBox::Action::Boot
|
||||
def wait_for_boot
|
||||
@env[:ui].info I18n.t("vagrant.actions.vm.boot.waiting")
|
||||
def call(env)
|
||||
@env = env
|
||||
driver = env[:machine].provider.driver
|
||||
config = env[:machine].provider_config
|
||||
|
||||
@env[:machine].config.ssh.max_tries.to_i.times do |i|
|
||||
if @env[:machine].communicate.ready?
|
||||
@env[:ui].info I18n.t("vagrant.actions.vm.boot.ready")
|
||||
return true
|
||||
end
|
||||
|
||||
# Return true so that the vm_failed_to_boot error doesn't
|
||||
# get shown
|
||||
return true if @env[:interrupted]
|
||||
|
||||
# TODO: Find out if there is a command to check if the machine is
|
||||
# starting, `lxc-monitor` shows this information, but I've
|
||||
# never seen it on `lxc-info` which is what it is being used
|
||||
# to determine container status
|
||||
|
||||
# If the VM is not starting or running, something went wrong
|
||||
# and we need to show a useful error.
|
||||
state = @env[:machine].provider.state.id
|
||||
raise Vagrant::Errors::VMFailedToRun if state != :starting && state != :running
|
||||
|
||||
sleep 2 if !@env["vagrant.test"]
|
||||
utsname = env[:machine].config.vm.hostname || env[:machine].id
|
||||
if driver.supports_new_config_format
|
||||
config.customize 'uts.name', utsname
|
||||
else
|
||||
config.customize 'utsname', utsname
|
||||
end
|
||||
|
||||
@env[:ui].error I18n.t("vagrant.actions.vm.boot.failed")
|
||||
false
|
||||
# Fix apparmor issues when starting Ubuntu 14.04 containers
|
||||
# See https://github.com/fgrehm/vagrant-lxc/issues/278 for more information
|
||||
if Dir.exists?('/sys/fs/pstore')
|
||||
config.customize 'mount.entry', '/sys/fs/pstore sys/fs/pstore none bind,optional 0 0'
|
||||
end
|
||||
|
||||
# Make selinux read-only, see
|
||||
# https://github.com/fgrehm/vagrant-lxc/issues/301
|
||||
if Dir.exists?('/sys/fs/selinux')
|
||||
config.customize 'mount.entry', '/sys/fs/selinux sys/fs/selinux none bind,ro 0 0'
|
||||
end
|
||||
|
||||
if config.tmpfs_mount_size && !config.tmpfs_mount_size.empty?
|
||||
# Make /tmp a tmpfs to prevent init scripts from nuking synced folders mounted in here
|
||||
config.customize 'mount.entry', "tmpfs tmp tmpfs nodev,nosuid,size=#{config.tmpfs_mount_size} 0 0"
|
||||
end
|
||||
|
||||
env[:ui].info I18n.t("vagrant_lxc.messages.starting")
|
||||
driver.start(config.customizations)
|
||||
|
||||
@app.call env
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class CheckCreated < BaseAction
|
||||
def call(env)
|
||||
unless env[:machine].state.created?
|
||||
raise Vagrant::Errors::VMNotCreatedError
|
||||
end
|
||||
|
||||
# Call the next if we have one (but we shouldn't, since this
|
||||
# middleware is built to run with the Call-type middlewares)
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,17 +0,0 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class CheckRunning < BaseAction
|
||||
def call(env)
|
||||
unless env[:machine].state.running?
|
||||
raise Vagrant::Errors::VMNotRunningError
|
||||
end
|
||||
|
||||
# Call the next if we have one (but we shouldn't, since this
|
||||
# middleware is built to run with the Call-type middlewares)
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
56
lib/vagrant-lxc/action/clear_forwarded_ports.rb
Normal file
56
lib/vagrant-lxc/action/clear_forwarded_ports.rb
Normal file
|
@ -0,0 +1,56 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class ClearForwardedPorts
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::lxc::action::clear_forwarded_ports")
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@env = env
|
||||
|
||||
if redir_pids.any?
|
||||
env[:ui].info I18n.t("vagrant.actions.vm.clear_forward_ports.deleting")
|
||||
redir_pids.each do |pid|
|
||||
next unless is_redir_pid?(pid[0])
|
||||
@logger.debug "Killing pid #{pid[0]}"
|
||||
if pid[1]
|
||||
system "sudo pkill -TERM -P #{pid[0]}"
|
||||
else
|
||||
system "pkill -TERM -P #{pid[0]}"
|
||||
end
|
||||
end
|
||||
|
||||
@logger.info "Removing redir pids files"
|
||||
remove_redir_pids
|
||||
else
|
||||
@logger.info "No redir pids found"
|
||||
end
|
||||
|
||||
@app.call env
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def redir_pids
|
||||
@redir_pids = Dir[@env[:machine].data_dir.join('pids').to_s + "/redir_*.pid"].map do |file|
|
||||
port_number = File.basename(file).split(/[^\d]/).join
|
||||
[ File.read(file).strip.chomp , Integer(port_number) <= 1024 ]
|
||||
end
|
||||
end
|
||||
|
||||
def is_redir_pid?(pid)
|
||||
@logger.debug "Checking if #{pid} is a redir process with `ps -o cmd= #{pid}`"
|
||||
`ps -o cmd= #{pid}`.strip.chomp =~ /redir/
|
||||
end
|
||||
|
||||
def remove_redir_pids
|
||||
Dir[@env[:machine].data_dir.join('pids').to_s + "/redir_*.pid"].each do |file|
|
||||
File.delete file
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
30
lib/vagrant-lxc/action/compress_rootfs.rb
Normal file
30
lib/vagrant-lxc/action/compress_rootfs.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
require "fileutils"
|
||||
|
||||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class CompressRootFS
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
raise Vagrant::Errors::VMPowerOffToPackage if env[:machine].provider.state.id != :stopped
|
||||
|
||||
env[:ui].info I18n.t("vagrant.actions.lxc.compressing_rootfs")
|
||||
@rootfs = env['package.rootfs'] = env[:machine].provider.driver.compress_rootfs
|
||||
|
||||
@app.call env
|
||||
|
||||
recover # called to remove the rootfs tarball
|
||||
end
|
||||
|
||||
def recover(*)
|
||||
if @rootfs && File.exist?(@rootfs)
|
||||
FileUtils.rm_rf(File.dirname @rootfs)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,13 +1,64 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class Create < BaseAction
|
||||
class Create
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
machine_id = env[:machine].provider.container.create(env[:machine].box.metadata)
|
||||
env[:machine].id = machine_id
|
||||
env[:just_created] = true
|
||||
config = env[:machine].provider_config
|
||||
container_name = config.container_name
|
||||
|
||||
case container_name
|
||||
when :machine
|
||||
container_name = env[:machine].name.to_s
|
||||
when String
|
||||
# Nothing to do here, move along...
|
||||
else
|
||||
container_name = generate_container_name(env)
|
||||
end
|
||||
|
||||
backingstore = config.backingstore
|
||||
if backingstore.nil?
|
||||
backingstore = config.privileged ? "best" : "dir"
|
||||
end
|
||||
driver = env[:machine].provider.driver
|
||||
template_options = env[:lxc_template_opts]
|
||||
if driver.supports_new_config_format
|
||||
if env[:lxc_box_config]
|
||||
driver.update_config_keys(env[:lxc_box_config])
|
||||
end
|
||||
else
|
||||
template_options['--oldconfig'] = ''
|
||||
end
|
||||
driver.create(
|
||||
container_name,
|
||||
backingstore,
|
||||
config.backingstore_options,
|
||||
env[:lxc_template_src],
|
||||
env[:lxc_template_config],
|
||||
template_options
|
||||
)
|
||||
driver.update_config_keys
|
||||
|
||||
env[:machine].id = container_name
|
||||
|
||||
@app.call env
|
||||
end
|
||||
|
||||
def generate_container_name(env)
|
||||
container_name = "#{env[:root_path].basename}_#{env[:machine].name}"
|
||||
container_name.gsub!(/[^-a-z0-9_]/i, "")
|
||||
|
||||
# milliseconds + random number suffix to allow for simultaneous
|
||||
# `vagrant up` of the same box in different dirs
|
||||
container_name << "_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
|
||||
|
||||
# Trim container name to 64 chars, keeping "randomness"
|
||||
trim_point = container_name.size > 64 ? -64 : -(container_name.size)
|
||||
container_name[trim_point..-1]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class Created < BaseAction
|
||||
def call(env)
|
||||
# Set the result to be true if the machine is created.
|
||||
env[:result] = env[:machine].state.created?
|
||||
|
||||
# Call the next if we have one (but we shouldn't, since this
|
||||
# middleware is built to run with the Call-type middlewares)
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,10 +1,14 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class Destroy < BaseAction
|
||||
class Destroy
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env[:ui].info I18n.t("vagrant.actions.vm.destroy.destroying")
|
||||
env[:machine].provider.container.destroy
|
||||
env[:machine].provider.driver.destroy
|
||||
env[:machine].id = nil
|
||||
@app.call env
|
||||
end
|
||||
|
|
17
lib/vagrant-lxc/action/destroy_confirm.rb
Normal file
17
lib/vagrant-lxc/action/destroy_confirm.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
require "vagrant/action/builtin/confirm"
|
||||
|
||||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class DestroyConfirm < Vagrant::Action::Builtin::Confirm
|
||||
def initialize(app, env)
|
||||
force_key = :force_confirm_destroy
|
||||
message = I18n.t("vagrant.commands.destroy.confirmation",
|
||||
:name => env[:machine].name)
|
||||
|
||||
super(app, env, message, force_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
44
lib/vagrant-lxc/action/fetch_ip_with_lxc_info.rb
Normal file
44
lib/vagrant-lxc/action/fetch_ip_with_lxc_info.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class FetchIpWithLxcInfo
|
||||
# Include this so we can use `Subprocess` more easily.
|
||||
include Vagrant::Util::Retryable
|
||||
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::lxc::action::fetch_ip_with_lxc_info")
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env[:machine_ip] ||= assigned_ip(env)
|
||||
ensure
|
||||
@app.call(env)
|
||||
end
|
||||
|
||||
def assigned_ip(env)
|
||||
config = env[:machine].provider_config
|
||||
fetch_ip_tries = config.fetch_ip_tries
|
||||
driver = env[:machine].provider.driver
|
||||
ip = ''
|
||||
return config.ssh_ip_addr if not config.ssh_ip_addr.nil?
|
||||
retryable(:on => LXC::Errors::ExecuteError, :tries => fetch_ip_tries, :sleep => 3) do
|
||||
unless ip = get_container_ip_from_ip_addr(driver)
|
||||
# retry
|
||||
raise LXC::Errors::ExecuteError, :command => "lxc-info"
|
||||
end
|
||||
end
|
||||
ip
|
||||
end
|
||||
|
||||
# From: https://github.com/lxc/lxc/blob/staging/src/python-lxc/lxc/__init__.py#L371-L385
|
||||
def get_container_ip_from_ip_addr(driver)
|
||||
output = driver.info '-iH'
|
||||
if output =~ /^([0-9.]+)/
|
||||
return $1.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -7,11 +7,9 @@ module Vagrant
|
|||
end
|
||||
|
||||
def call(env)
|
||||
if env[:machine].provider.state.running?
|
||||
env[:ui].info I18n.t("vagrant.actions.vm.halt.force")
|
||||
# TODO: Container#halt is kinda graceful as well, if it doesn't
|
||||
# work we can issue a lxc-stop.
|
||||
env[:machine].provider.container.halt
|
||||
if env[:machine].provider.state.id == :running
|
||||
env[:ui].info I18n.t("vagrant_lxc.messages.force_shutdown")
|
||||
env[:machine].provider.driver.forced_halt
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
|
|
121
lib/vagrant-lxc/action/forward_ports.rb
Normal file
121
lib/vagrant-lxc/action/forward_ports.rb
Normal file
|
@ -0,0 +1,121 @@
|
|||
require 'open3'
|
||||
|
||||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class ForwardPorts
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::lxc::action::forward_ports")
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@env = env
|
||||
|
||||
# Get the ports we're forwarding
|
||||
env[:forwarded_ports] = compile_forwarded_ports(env[:machine].config)
|
||||
|
||||
if @env[:forwarded_ports].any? and not redir_installed?
|
||||
raise Errors::RedirNotInstalled
|
||||
end
|
||||
|
||||
# Warn if we're port forwarding to any privileged ports
|
||||
env[:forwarded_ports].each do |fp|
|
||||
if fp[:host] <= 1024
|
||||
env[:ui].warn I18n.t("vagrant.actions.vm.forward_ports.privileged_ports")
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
# Continue, we need the VM to be booted in order to grab its IP
|
||||
@app.call env
|
||||
|
||||
if @env[:forwarded_ports].any?
|
||||
env[:ui].info I18n.t("vagrant.actions.vm.forward_ports.forwarding")
|
||||
forward_ports
|
||||
end
|
||||
end
|
||||
|
||||
def forward_ports
|
||||
@env[:forwarded_ports].each do |fp|
|
||||
message_attributes = {
|
||||
# TODO: Add support for multiple adapters
|
||||
:adapter => 'eth0',
|
||||
:guest_port => fp[:guest],
|
||||
:host_port => fp[:host]
|
||||
}
|
||||
|
||||
# TODO: Remove adapter from logging
|
||||
@env[:ui].info(I18n.t("vagrant.actions.vm.forward_ports.forwarding_entry",
|
||||
message_attributes))
|
||||
|
||||
redir_pid = redirect_port(
|
||||
fp[:host_ip],
|
||||
fp[:host],
|
||||
fp[:guest_ip] || @env[:machine].provider.ssh_info[:host],
|
||||
fp[:guest]
|
||||
)
|
||||
store_redir_pid(fp[:host], redir_pid)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def compile_forwarded_ports(config)
|
||||
mappings = {}
|
||||
|
||||
config.vm.networks.each do |type, options|
|
||||
next if options[:disabled]
|
||||
|
||||
# TODO: Deprecate this behavior of "automagically" skipping ssh forwarded ports
|
||||
if type == :forwarded_port && options[:id] != 'ssh'
|
||||
if options.fetch(:host_ip, '').to_s.strip.empty?
|
||||
options[:host_ip] = '127.0.0.1'
|
||||
end
|
||||
mappings[options[:host]] = options
|
||||
end
|
||||
end
|
||||
|
||||
mappings.values
|
||||
end
|
||||
|
||||
def redirect_port(host_ip, host_port, guest_ip, guest_port)
|
||||
if redir_version >= 3
|
||||
params = %W( -n #{host_ip}:#{host_port} #{guest_ip}:#{guest_port} )
|
||||
else
|
||||
params = %W( --lport=#{host_port} --caddr=#{guest_ip} --cport=#{guest_port} )
|
||||
params.unshift "--laddr=#{host_ip}" if host_ip
|
||||
end
|
||||
params << '--syslog' if ENV['REDIR_LOG']
|
||||
if host_port < 1024
|
||||
redir_cmd = "sudo redir #{params.join(' ')} 2>/dev/null"
|
||||
else
|
||||
redir_cmd = "redir #{params.join(' ')} 2>/dev/null"
|
||||
end
|
||||
@logger.debug "Forwarding port with `#{redir_cmd}`"
|
||||
spawn redir_cmd
|
||||
end
|
||||
|
||||
def store_redir_pid(host_port, redir_pid)
|
||||
data_dir = @env[:machine].data_dir.join('pids')
|
||||
data_dir.mkdir unless data_dir.directory?
|
||||
|
||||
data_dir.join("redir_#{host_port}.pid").open('w') do |pid_file|
|
||||
pid_file.write(redir_pid)
|
||||
end
|
||||
end
|
||||
|
||||
def redir_version
|
||||
stdout, stderr, _ = Open3.capture3 "redir --version"
|
||||
# For some weird reason redir printed version information in STDERR prior to 3.2
|
||||
version = stdout.empty? ? stderr : stdout
|
||||
version.split('.')[0].to_i
|
||||
end
|
||||
|
||||
def redir_installed?
|
||||
system "which redir > /dev/null"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
47
lib/vagrant-lxc/action/gc_private_network_bridges.rb
Normal file
47
lib/vagrant-lxc/action/gc_private_network_bridges.rb
Normal file
|
@ -0,0 +1,47 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class GcPrivateNetworkBridges
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
was_running = env[:machine].provider.state.id == :running
|
||||
|
||||
# Continue execution, we need the container to be stopped
|
||||
@app.call(env)
|
||||
|
||||
was_running = was_running && env[:machine].provider.state.id != :running
|
||||
|
||||
if was_running && private_network_configured?(env[:machine].config)
|
||||
private_network_configured?(env[:machine].config)
|
||||
remove_bridges_that_are_not_in_use(env)
|
||||
end
|
||||
end
|
||||
|
||||
def private_network_configured?(config)
|
||||
config.vm.networks.find do |type, _|
|
||||
type.to_sym == :private_network
|
||||
end
|
||||
end
|
||||
|
||||
def remove_bridges_that_are_not_in_use(env)
|
||||
env[:machine].config.vm.networks.find do |type, config|
|
||||
next if type.to_sym != :private_network
|
||||
|
||||
bridge = config.fetch(:lxc__bridge_name)
|
||||
driver = env[:machine].provider.driver
|
||||
|
||||
if ! driver.bridge_is_in_use?(bridge)
|
||||
env[:ui].info I18n.t("vagrant_lxc.messages.remove_bridge", name: bridge)
|
||||
unless ['lxcbr0', 'virbr0'].include? bridge
|
||||
driver.remove_bridge(bridge)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,44 +2,93 @@ module Vagrant
|
|||
module LXC
|
||||
module Action
|
||||
# Prepare arguments to be used for lxc-create
|
||||
class HandleBoxMetadata < BaseAction
|
||||
LXC_TEMPLATES_PATH = Pathname.new("/usr/share/lxc/templates")
|
||||
TEMP_PREFIX = "vagrant-lxc-rootfs-temp-"
|
||||
class HandleBoxMetadata
|
||||
SUPPORTED_VERSIONS = ['1.0.0', '2', '3']
|
||||
|
||||
def initialize(app, env)
|
||||
super
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::lxc::action::handle_box_metadata")
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env[:ui].info I18n.t("vagrant.actions.vm.import.importing",
|
||||
:name => env[:machine].box.name)
|
||||
@env = env
|
||||
@box = @env[:machine].box
|
||||
|
||||
rootfs_cache = Dir.mktmpdir(TEMP_PREFIX)
|
||||
box = env[:machine].box
|
||||
template_name = "vagrant-#{box.name}"
|
||||
@env[:ui].info I18n.t("vagrant.actions.vm.import.importing",
|
||||
:name => @env[:machine].box.name)
|
||||
|
||||
# Prepends "lxc-" to the template file so that `lxc-create` is able to find it
|
||||
lxc_template_src = box.directory.join('lxc-template').to_s
|
||||
unless File.exists?(lxc_template_src)
|
||||
raise Errors::TemplateFileMissing.new name: box.name
|
||||
@logger.info 'Validating box contents'
|
||||
validate_box
|
||||
|
||||
@logger.info 'Setting box options on environment'
|
||||
@env[:lxc_template_src] = template_src
|
||||
@env[:lxc_template_opts] = template_opts
|
||||
|
||||
# FIXME: Remove support for pre 1.0.0 boxes
|
||||
if box_version != '1.0.0'
|
||||
@env[:ui].warn "WARNING: You are using a base box that has a format that has been deprecated, please upgrade to a new one."
|
||||
@env[:lxc_template_opts].merge!(
|
||||
'--auth-key' => Vagrant.source_root.join('keys', 'vagrant.pub').expand_path.to_s
|
||||
)
|
||||
end
|
||||
dest = LXC_TEMPLATES_PATH.join("lxc-#{template_name}").to_s
|
||||
@logger.debug('Copying LXC template into place')
|
||||
system(%Q[sudo su root -c "cp #{lxc_template_src} #{dest}"])
|
||||
|
||||
@logger.debug('Extracting rootfs')
|
||||
system(%Q[sudo su root -c "cd #{box.directory} && tar xfz rootfs.tar.gz -C #{rootfs_cache}"])
|
||||
if template_config_file.exist?
|
||||
@env[:lxc_box_config] = template_config_file.to_s
|
||||
@env[:lxc_template_opts].merge!('--config' => template_config_file.to_s)
|
||||
elsif old_template_config_file.exist?
|
||||
@env[:lxc_box_config] = old_template_config_file.to_s
|
||||
@env[:lxc_template_config] = old_template_config_file.to_s
|
||||
end
|
||||
|
||||
box.metadata.merge!(
|
||||
'template-name' => template_name,
|
||||
'rootfs-cache-path' => rootfs_cache
|
||||
@app.call env
|
||||
end
|
||||
|
||||
def template_src
|
||||
@template_src ||=
|
||||
if (box_template = @box.directory.join('lxc-template')).exist?
|
||||
box_template.to_s
|
||||
else
|
||||
Vagrant::LXC.source_root.join('scripts/lxc-template').to_s
|
||||
end
|
||||
end
|
||||
|
||||
def template_config_file
|
||||
@template_config_file ||= @box.directory.join('lxc-config')
|
||||
end
|
||||
|
||||
# TODO: Remove this once we remove compatibility for < 1.0.0 boxes
|
||||
def old_template_config_file
|
||||
@old_template_config_file ||= @box.directory.join('lxc.conf')
|
||||
end
|
||||
|
||||
def template_opts
|
||||
@template_opts ||= @box.metadata.fetch('template-opts', {}).dup.merge!(
|
||||
'--tarball' => rootfs_tarball
|
||||
)
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
def rootfs_tarball
|
||||
@rootfs_tarball ||= @box.directory.join('rootfs.tar.gz').to_s
|
||||
end
|
||||
|
||||
ensure
|
||||
system %Q[sudo su root -c "rm -rf #{rootfs_cache}"]
|
||||
def validate_box
|
||||
unless SUPPORTED_VERSIONS.include? box_version
|
||||
raise Errors::IncompatibleBox.new name: @box.name,
|
||||
found: box_version,
|
||||
supported: SUPPORTED_VERSIONS.join(', ')
|
||||
end
|
||||
|
||||
unless File.exists?(template_src)
|
||||
raise Errors::TemplateFileMissing.new name: @box.name
|
||||
end
|
||||
|
||||
unless File.exists?(rootfs_tarball)
|
||||
raise Errors::RootFSTarballMissing.new name: @box.name
|
||||
end
|
||||
end
|
||||
|
||||
def box_version
|
||||
@box.metadata.fetch('version')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class IsRunning < BaseAction
|
||||
def call(env)
|
||||
env[:result] = env[:machine].state.running?
|
||||
|
||||
# Call the next if we have one (but we shouldn't, since this
|
||||
# middleware is built to run with the Call-type middlewares)
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,21 +0,0 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class Network < BaseAction
|
||||
def call(env)
|
||||
# TODO: Validate network configuration prior to anything below
|
||||
@env = env
|
||||
|
||||
env[:machine].config.vm.networks.each do |type, options|
|
||||
# We only handle private networks
|
||||
next if type != :private_network
|
||||
env[:machine].provider_config.start_opts << "lxc.network.ipv4=#{options[:ip]}/24"
|
||||
end
|
||||
|
||||
# Continue the middleware chain.
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
64
lib/vagrant-lxc/action/prepare_nfs_settings.rb
Normal file
64
lib/vagrant-lxc/action/prepare_nfs_settings.rb
Normal file
|
@ -0,0 +1,64 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class PrepareNFSSettings
|
||||
include Vagrant::Util::Retryable
|
||||
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::action::vm::nfs")
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@machine = env[:machine]
|
||||
|
||||
@app.call(env)
|
||||
|
||||
# if using_nfs? # TODO: && !privileged_container?
|
||||
# raise Errors::NfsWithoutPrivilegedError
|
||||
# end
|
||||
|
||||
if using_nfs?
|
||||
@logger.info("Using NFS, preparing NFS settings by reading host IP and machine IP")
|
||||
add_ips_to_env!(env)
|
||||
end
|
||||
end
|
||||
|
||||
# We're using NFS if we have any synced folder with NFS configured. If
|
||||
# we are not using NFS we don't need to do the extra work to
|
||||
# populate these fields in the environment.
|
||||
def using_nfs?
|
||||
@machine.config.vm.synced_folders.any? { |_, opts| opts[:type] == :nfs }
|
||||
end
|
||||
|
||||
# TODO:
|
||||
# def privileged_container?
|
||||
# @machine.provider.driver.privileged?(@machine.id)
|
||||
# end
|
||||
|
||||
# Extracts the proper host and guest IPs for NFS mounts and stores them
|
||||
# in the environment for the SyncedFolder action to use them in
|
||||
# mounting.
|
||||
#
|
||||
# The ! indicates that this method modifies its argument.
|
||||
def add_ips_to_env!(env)
|
||||
provider = @machine.provider
|
||||
|
||||
host_ip = read_host_ip
|
||||
machine_ip = provider.ssh_info[:host]
|
||||
|
||||
raise Vagrant::Errors::NFSNoHostonlyNetwork if !host_ip || !machine_ip
|
||||
|
||||
env[:nfs_host_ip] = host_ip
|
||||
env[:nfs_machine_ip] = machine_ip
|
||||
end
|
||||
|
||||
def read_host_ip
|
||||
@machine.communicate.execute 'echo $SSH_CLIENT' do |buffer, output|
|
||||
return output.chomp.split(' ')[0] if buffer == :stdout
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
19
lib/vagrant-lxc/action/prepare_nfs_valid_ids.rb
Normal file
19
lib/vagrant-lxc/action/prepare_nfs_valid_ids.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class PrepareNFSValidIds
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::action::vm::nfs")
|
||||
end
|
||||
|
||||
def call(env)
|
||||
machine = env[:machine]
|
||||
env[:nfs_valid_ids] = machine.provider.driver.all_containers
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
46
lib/vagrant-lxc/action/private_networks.rb
Normal file
46
lib/vagrant-lxc/action/private_networks.rb
Normal file
|
@ -0,0 +1,46 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class PrivateNetworks
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@app.call(env)
|
||||
|
||||
if private_network_configured?(env[:machine].config)
|
||||
env[:ui].output(I18n.t("vagrant_lxc.messages.setup_private_network"))
|
||||
configure_private_networks(env)
|
||||
end
|
||||
end
|
||||
|
||||
def private_network_configured?(config)
|
||||
config.vm.networks.find do |type, _|
|
||||
type.to_sym == :private_network
|
||||
end
|
||||
end
|
||||
|
||||
def configure_private_networks(env)
|
||||
env[:machine].config.vm.networks.find do |type, config|
|
||||
next if type.to_sym != :private_network
|
||||
|
||||
container_name = env[:machine].provider.driver.container_name
|
||||
address_type = config[:type]
|
||||
ip = config[:ip]
|
||||
bridge_ip = config.fetch(:lxc__bridge_ip) { build_bridge_ip(ip) }
|
||||
bridge = config.fetch(:lxc__bridge_name)
|
||||
|
||||
env[:machine].provider.driver.configure_private_network(bridge, bridge_ip, container_name, address_type, ip)
|
||||
end
|
||||
end
|
||||
|
||||
def build_bridge_ip(ip)
|
||||
if ip
|
||||
ip.sub(/^(\d+\.\d+\.\d+)\.\d+/, '\1.254')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
60
lib/vagrant-lxc/action/setup_package_files.rb
Normal file
60
lib/vagrant-lxc/action/setup_package_files.rb
Normal file
|
@ -0,0 +1,60 @@
|
|||
require 'fileutils'
|
||||
|
||||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class SetupPackageFiles
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
|
||||
env["package.include"] ||= []
|
||||
env["package.vagrantfile"] ||= nil
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@env = env
|
||||
|
||||
create_package_temp_dir
|
||||
move_rootfs_to_pkg_dir
|
||||
copy_box_files_to_pkg_dir
|
||||
|
||||
@app.call env
|
||||
|
||||
recover # called to cleanup temp directory
|
||||
end
|
||||
|
||||
def recover(*)
|
||||
if @temp_dir && File.exist?(@temp_dir)
|
||||
FileUtils.rm_rf(@temp_dir)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_package_temp_dir
|
||||
@env[:ui].info I18n.t("vagrant.actions.vm.export.create_dir")
|
||||
@temp_dir = @env["package.directory"] = @env[:tmp_path].join("container-export-#{Time.now.to_i.to_s}")
|
||||
FileUtils.mkpath(@temp_dir)
|
||||
end
|
||||
|
||||
def move_rootfs_to_pkg_dir
|
||||
FileUtils.mv @env['package.rootfs'].to_s, @env['package.directory'].to_s
|
||||
end
|
||||
|
||||
def copy_box_files_to_pkg_dir
|
||||
box_dir = @env[:machine].box.directory
|
||||
FileUtils.cp box_dir.join('metadata.json').to_s, @env['package.directory'].to_s
|
||||
if (template = box_dir.join('lxc-template')).exist?
|
||||
FileUtils.cp template.to_s, @env['package.directory'].to_s
|
||||
end
|
||||
if (conf = box_dir.join('lxc.conf')).exist?
|
||||
FileUtils.cp conf.to_s, @env['package.directory'].to_s
|
||||
end
|
||||
if (conf = box_dir.join('lxc-config')).exist?
|
||||
FileUtils.cp conf.to_s, @env['package.directory'].to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,65 +0,0 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class ShareFolders < BaseAction
|
||||
def call(env)
|
||||
@env = env
|
||||
prepare_folders
|
||||
add_start_opts
|
||||
@app.call env
|
||||
end
|
||||
|
||||
# This method returns an actual list of VirtualBox shared
|
||||
# folders to create and their proper path.
|
||||
def shared_folders
|
||||
{}.tap do |result|
|
||||
@env[:machine].config.vm.synced_folders.each do |id, data|
|
||||
# Ignore NFS shared folders
|
||||
next if data[:nfs]
|
||||
|
||||
# This to prevent overwriting the actual shared folders data
|
||||
result[id] = data.dup
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Prepares the shared folders by verifying they exist and creating them
|
||||
# if they don't.
|
||||
def prepare_folders
|
||||
shared_folders.each do |id, options|
|
||||
hostpath = Pathname.new(options[:hostpath]).expand_path(@env[:root_path])
|
||||
|
||||
if !hostpath.directory? && options[:create]
|
||||
# Host path doesn't exist, so let's create it.
|
||||
@logger.debug("Host path doesn't exist, creating: #{hostpath}")
|
||||
|
||||
begin
|
||||
hostpath.mkpath
|
||||
rescue Errno::EACCES
|
||||
raise Vagrant::Errors::SharedFolderCreateFailed,
|
||||
:path => hostpath.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def add_start_opts
|
||||
@env[:ui].info I18n.t("vagrant.actions.lxc.share_folders.preparing")
|
||||
|
||||
folders = []
|
||||
shared_folders.each do |id, data|
|
||||
folders << {
|
||||
:name => id,
|
||||
:hostpath => File.expand_path(data[:hostpath], @env[:root_path]),
|
||||
:guestpath => data[:guestpath]
|
||||
}
|
||||
@env[:ui].info(I18n.t("vagrant.actions.vm.share_folders.mounting_entry",
|
||||
:guest_path => data[:guestpath]))
|
||||
end
|
||||
config = @env[:machine].provider_config
|
||||
@env[:machine].provider.container.share_folders(folders, config)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
25
lib/vagrant-lxc/action/warn_networks.rb
Normal file
25
lib/vagrant-lxc/action/warn_networks.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Action
|
||||
class WarnNetworks
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
if public_network_configured?(env[:machine].config)
|
||||
env[:ui].warn(I18n.t("vagrant_lxc.messages.warn_networks"))
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
|
||||
def public_network_configured?(config)
|
||||
config.vm.networks.find do |type, _|
|
||||
type.to_sym == :public_network
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
58
lib/vagrant-lxc/command/root.rb
Normal file
58
lib/vagrant-lxc/command/root.rb
Normal file
|
@ -0,0 +1,58 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
module Command
|
||||
class Root < Vagrant.plugin("2", :command)
|
||||
def self.synopsis
|
||||
'vagrant-lxc specific commands'
|
||||
end
|
||||
|
||||
def initialize(argv, env)
|
||||
@args, @sub_command, @sub_args = split_main_and_subcommand(argv)
|
||||
@subcommands = Vagrant::Registry.new.tap do |registry|
|
||||
registry.register(:sudoers) do
|
||||
require_relative 'sudoers'
|
||||
Sudoers
|
||||
end
|
||||
end
|
||||
super(argv, env)
|
||||
end
|
||||
|
||||
def execute
|
||||
# Print the help
|
||||
return help if @args.include?("-h") || @args.include?("--help")
|
||||
|
||||
klazz = @subcommands.get(@sub_command.to_sym) if @sub_command
|
||||
return help unless klazz
|
||||
|
||||
@logger.debug("Executing command: #{klazz} #{@sub_args.inspect}")
|
||||
|
||||
# Initialize and execute the command class
|
||||
klazz.new(@sub_args, @env).execute
|
||||
end
|
||||
|
||||
def help
|
||||
opts = OptionParser.new do |opts|
|
||||
opts.banner = "Usage: vagrant lxc <subcommand> [<args>]"
|
||||
opts.separator ""
|
||||
opts.separator "Available subcommands:"
|
||||
|
||||
# REFACTOR Use @subcommands.keys.sort
|
||||
# https://github.com/mitchellh/vagrant/commit/4194da19c60956f6e59239c0145f772be257e79d
|
||||
keys = []
|
||||
@subcommands.each { |key, value| keys << key }
|
||||
|
||||
keys.sort.each do |key|
|
||||
opts.separator " #{key}"
|
||||
end
|
||||
|
||||
opts.separator ""
|
||||
opts.separator "For help on any individual subcommand run `vagrant lxc <subcommand> -h`"
|
||||
end
|
||||
|
||||
@env.ui.info(opts.help, :prefix => false)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
97
lib/vagrant-lxc/command/sudoers.rb
Normal file
97
lib/vagrant-lxc/command/sudoers.rb
Normal file
|
@ -0,0 +1,97 @@
|
|||
require 'tempfile'
|
||||
|
||||
require "vagrant-lxc/driver"
|
||||
require "vagrant-lxc/sudo_wrapper"
|
||||
|
||||
module Vagrant
|
||||
module LXC
|
||||
module Command
|
||||
class Sudoers < Vagrant.plugin("2", :command)
|
||||
|
||||
def initialize(argv, env)
|
||||
super
|
||||
@argv
|
||||
@env = env
|
||||
end
|
||||
|
||||
def execute
|
||||
options = { user: ENV['USER'] }
|
||||
|
||||
opts = OptionParser.new do |opts|
|
||||
opts.banner = "Usage: vagrant lxc sudoers"
|
||||
opts.separator ""
|
||||
opts.on('-u user', '--user user', String, "The user for which to create the policy (defaults to '#{options[:user]}')") do |u|
|
||||
options[:user] = u
|
||||
end
|
||||
end
|
||||
|
||||
argv = parse_options(opts)
|
||||
return unless argv
|
||||
|
||||
wrapper_path = SudoWrapper.dest_path
|
||||
wrapper = create_wrapper!
|
||||
sudoers = create_sudoers!(options[:user], wrapper_path)
|
||||
|
||||
su_copy([
|
||||
{source: wrapper, target: wrapper_path, mode: "0555"},
|
||||
{source: sudoers, target: sudoers_path, mode: "0440"}
|
||||
])
|
||||
end
|
||||
|
||||
def sudoers_path
|
||||
"/etc/sudoers.d/vagrant-lxc"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# This requires vagrant 1.5.2+ https://github.com/mitchellh/vagrant/commit/3371c3716278071680af9b526ba19235c79c64cb
|
||||
def create_wrapper!
|
||||
lxc_base_path = Driver.new("").containers_path
|
||||
wrapper = Tempfile.new('lxc-wrapper').tap do |file|
|
||||
template = Vagrant::Util::TemplateRenderer.new(
|
||||
'sudoers.rb',
|
||||
:template_root => Vagrant::LXC.source_root.join('templates').to_s,
|
||||
:cmd_paths => build_cmd_paths_hash,
|
||||
:lxc_base_path => lxc_base_path,
|
||||
:pipework_regex => "#{ENV['HOME']}/\.vagrant\.d/gems/(?:\\d+?\\.\\d+?\\.\\d+?/)?gems/vagrant-lxc.+/scripts/pipework"
|
||||
)
|
||||
file.puts template.render
|
||||
end
|
||||
wrapper.close
|
||||
wrapper.path
|
||||
end
|
||||
|
||||
def create_sudoers!(user, command)
|
||||
sudoers = Tempfile.new('vagrant-lxc-sudoers').tap do |file|
|
||||
file.puts "# Automatically created by vagrant-lxc"
|
||||
file.puts "#{user} ALL=(root) NOPASSWD: #{command}"
|
||||
end
|
||||
sudoers.close
|
||||
sudoers.path
|
||||
end
|
||||
|
||||
def su_copy(files)
|
||||
commands = files.map { |file|
|
||||
[
|
||||
"rm -f #{file[:target]}",
|
||||
"cp #{file[:source]} #{file[:target]}",
|
||||
"chown root:root #{file[:target]}",
|
||||
"chmod #{file[:mode]} #{file[:target]}"
|
||||
]
|
||||
}.flatten
|
||||
system "echo \"#{commands.join("; ")}\" | sudo sh"
|
||||
end
|
||||
|
||||
def build_cmd_paths_hash
|
||||
{}.tap do |hash|
|
||||
%w( which cat mkdir cp chown chmod rm tar chown ip ifconfig brctl ).each do |cmd|
|
||||
hash[cmd] = `sudo which #{cmd}`.strip
|
||||
end
|
||||
hash['lxc_bin'] = Pathname(`sudo which lxc-create`.strip).parent.to_s
|
||||
hash['ruby'] = Gem.ruby
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,13 +1,76 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
class Config < Vagrant.plugin("2", :config)
|
||||
# An array of options to be passed to lxc-start when booting the machine.
|
||||
# An array of container's configuration overrides to be provided to `lxc-start`.
|
||||
#
|
||||
# @return [Array]
|
||||
attr_reader :start_opts
|
||||
attr_reader :customizations
|
||||
|
||||
# A string that contains the backing store type used with lxc-create -B
|
||||
attr_accessor :backingstore
|
||||
|
||||
# Optional arguments for the backing store, such as --fssize, --fstype, ...
|
||||
#
|
||||
# @return [Array]
|
||||
attr_accessor :backingstore_options
|
||||
|
||||
# A string to explicitly set the container name. To use the vagrant
|
||||
# machine name, set this to :machine
|
||||
attr_accessor :container_name
|
||||
|
||||
# Size (as a string like '400M') of the tmpfs to mount at /tmp on boot.
|
||||
# Set to false or nil to disable the tmpfs mount altogether. Defaults to '2G'.
|
||||
attr_accessor :tmpfs_mount_size
|
||||
|
||||
attr_accessor :fetch_ip_tries
|
||||
|
||||
attr_accessor :ssh_ip_addr
|
||||
|
||||
# Whether the container needs to be privileged. Defaults to true (unprivileged containers
|
||||
# is a very new feature in vagrant-lxc). If false, will try creating an unprivileged
|
||||
# container. If it can't, will revert to the old "sudo wrapper" method to create a privileged
|
||||
# container.
|
||||
attr_accessor :privileged
|
||||
|
||||
def initialize
|
||||
@start_opts = []
|
||||
@customizations = []
|
||||
@backingstore = UNSET_VALUE
|
||||
@backingstore_options = []
|
||||
@container_name = UNSET_VALUE
|
||||
@tmpfs_mount_size = UNSET_VALUE
|
||||
@fetch_ip_tries = UNSET_VALUE
|
||||
@ssh_ip_addr = UNSET_VALUE
|
||||
@privileged = UNSET_VALUE
|
||||
end
|
||||
|
||||
# Customize the container by calling `lxc-start` with the given
|
||||
# configuration overrides.
|
||||
#
|
||||
# For example, if you want to set the memory limit, you can use it
|
||||
# like: config.customize 'cgroup.memory.limit_in_bytes', '400M'
|
||||
#
|
||||
# When `lxc-start`ing the container, vagrant-lxc will pass in
|
||||
# "-s lxc.cgroup.memory.limit_in_bytes=400M" to it.
|
||||
#
|
||||
# @param [String] key Configuration key to override
|
||||
# @param [String] value Configuration value to override
|
||||
def customize(key, value)
|
||||
@customizations << [key, value]
|
||||
end
|
||||
|
||||
# Stores options for backingstores like lvm, btrfs, etc
|
||||
def backingstore_option(key, value)
|
||||
@backingstore_options << [key, value]
|
||||
end
|
||||
|
||||
def finalize!
|
||||
@container_name = nil if @container_name == UNSET_VALUE
|
||||
@backingstore = nil if @backingstore == UNSET_VALUE
|
||||
@existing_container_name = nil if @existing_container_name == UNSET_VALUE
|
||||
@tmpfs_mount_size = '2G' if @tmpfs_mount_size == UNSET_VALUE
|
||||
@fetch_ip_tries = 10 if @fetch_ip_tries == UNSET_VALUE
|
||||
@ssh_ip_addr = nil if @ssh_ip_addr == UNSET_VALUE
|
||||
@privileged = true if @privileged == UNSET_VALUE
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,170 +0,0 @@
|
|||
# FIXME: Ruby 1.8 users dont have SecureRandom
|
||||
require 'securerandom'
|
||||
|
||||
require "vagrant-lxc/errors"
|
||||
require "vagrant-lxc/container/cli"
|
||||
|
||||
require "vagrant/util/retryable"
|
||||
require "vagrant/util/subprocess"
|
||||
|
||||
module Vagrant
|
||||
module LXC
|
||||
class Container
|
||||
# Root folder where containers are stored
|
||||
CONTAINERS_PATH = '/var/lib/lxc'
|
||||
|
||||
# Default LXC configs
|
||||
LXC_DEFAULTS_PATH = '/etc/default/lxc'
|
||||
|
||||
# Include this so we can use `Subprocess` more easily.
|
||||
include Vagrant::Util::Retryable
|
||||
|
||||
# This is raised if the container can't be found when initializing it with
|
||||
# a name.
|
||||
class NotFound < StandardError; end
|
||||
|
||||
attr_reader :name
|
||||
|
||||
def initialize(name, cli = CLI.new(name))
|
||||
@name = name
|
||||
@cli = cli
|
||||
@logger = Log4r::Logger.new("vagrant::provider::lxc::container")
|
||||
end
|
||||
|
||||
def validate!
|
||||
raise NotFound if @name && ! @cli.list.include?(@name)
|
||||
end
|
||||
|
||||
def base_path
|
||||
Pathname.new("#{CONTAINERS_PATH}/#{@name}")
|
||||
end
|
||||
|
||||
def rootfs_path
|
||||
Pathname.new("#{base_path}/rootfs")
|
||||
end
|
||||
|
||||
def create(metadata = {})
|
||||
@logger.debug('Creating container using lxc-create...')
|
||||
|
||||
@name = SecureRandom.hex(6)
|
||||
public_key = Vagrant.source_root.join('keys', 'vagrant.pub').expand_path.to_s
|
||||
meta_opts = metadata.fetch('template-opts', {}).merge(
|
||||
'--auth-key' => public_key,
|
||||
'--cache' => metadata.fetch('rootfs-cache-path')
|
||||
)
|
||||
|
||||
@cli.name = @name
|
||||
@cli.create(metadata.fetch('template-name'), meta_opts)
|
||||
|
||||
@name
|
||||
end
|
||||
|
||||
def share_folders(folders, config)
|
||||
folders.each do |folder|
|
||||
guestpath = rootfs_path.join(folder[:guestpath].gsub(/^\//, ''))
|
||||
unless guestpath.directory?
|
||||
begin
|
||||
system "sudo mkdir -p #{guestpath.to_s}"
|
||||
rescue Errno::EACCES
|
||||
raise Vagrant::Errors::SharedFolderCreateFailed,
|
||||
:path => guestpath.to_s
|
||||
end
|
||||
end
|
||||
|
||||
config.start_opts << "lxc.mount.entry=#{folder[:hostpath]} #{guestpath} none bind 0 0"
|
||||
end
|
||||
end
|
||||
|
||||
def start(config)
|
||||
@logger.info('Starting container...')
|
||||
|
||||
opts = config.start_opts.dup
|
||||
if ENV['LXC_START_LOG_FILE']
|
||||
extra = ['-o', ENV['LXC_START_LOG_FILE'], '-l', 'DEBUG']
|
||||
end
|
||||
|
||||
@cli.transition_to(:running) { |c| c.start(opts, (extra || nil)) }
|
||||
end
|
||||
|
||||
def halt
|
||||
@logger.info('Shutting down container...')
|
||||
|
||||
# TODO: issue an lxc-stop if a timeout gets reached
|
||||
@cli.transition_to(:stopped) { |c| c.shutdown }
|
||||
end
|
||||
|
||||
def destroy
|
||||
@cli.destroy
|
||||
end
|
||||
|
||||
def state
|
||||
if @name
|
||||
@cli.state
|
||||
end
|
||||
end
|
||||
|
||||
def assigned_ip
|
||||
unless File.read(base_path.join('config')) =~ /^lxc\.network\.hwaddr\s*=\s*([a-z0-9:]+)\s*$/
|
||||
raise 'Unknown Container MAC Address'
|
||||
end
|
||||
mac_addr = $1
|
||||
|
||||
ip = ''
|
||||
retryable(:on => LXC::Errors::ExecuteError, :tries => 10, :sleep => 3) do
|
||||
# See: http://programminglinuxblog.blogspot.com.br/2007/11/detecting-ip-address-from-mac-address.html
|
||||
unless ip = get_container_ip_from_arp(mac_addr)
|
||||
# Ping subnet and try to get ip again
|
||||
ping_subnet!
|
||||
end
|
||||
end
|
||||
ip
|
||||
end
|
||||
|
||||
def get_container_ip_from_arp(mac_addr)
|
||||
r = raw 'arp', '-n'
|
||||
|
||||
# If the command was a failure then raise an exception that is nicely
|
||||
# handled by Vagrant.
|
||||
if r.exit_code != 0
|
||||
if @interrupted
|
||||
@logger.info("Exit code != 0, but interrupted. Ignoring.")
|
||||
else
|
||||
raise LXC::Errors::ExecuteError, :command => ['arp', '-n'].inspect
|
||||
end
|
||||
end
|
||||
|
||||
if r.stdout.gsub("\r\n", "\n").strip =~ /^([0-9.]+).+#{Regexp.escape mac_addr}/
|
||||
return $1.to_s
|
||||
end
|
||||
end
|
||||
|
||||
# FIXME: Should output an error friendly message in case fping is not installed
|
||||
def ping_subnet!
|
||||
raise LXC::Errors::UnknownLxcConfigFile unless File.exists?(LXC_DEFAULTS_PATH)
|
||||
|
||||
raise LXC::Errors::UnknownLxcBridgeAddress unless
|
||||
File.read(LXC_DEFAULTS_PATH) =~ /^LXC_ADDR\="?([0-9.]+)"?.*$/
|
||||
|
||||
cmd = ['fping', '-c', '1', '-g', '-q', "#{$1}/24"]
|
||||
raw(*cmd)
|
||||
|
||||
raise LXC::Errors::ExecuteError, :command => cmd.inspect
|
||||
end
|
||||
|
||||
# TODO: Review code below this line, it was pretty much a copy and paste from VirtualBox base driver
|
||||
def raw(*command, &block)
|
||||
int_callback = lambda do
|
||||
@interrupted = true
|
||||
@logger.info("Interrupted.")
|
||||
end
|
||||
|
||||
# Append in the options for subprocess
|
||||
command << { :notify => [:stdout, :stderr] }
|
||||
|
||||
Vagrant::Util::Busy.busy(int_callback) do
|
||||
Vagrant::Util::Subprocess.execute(*command, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,124 +0,0 @@
|
|||
require "vagrant/util/retryable"
|
||||
require "vagrant/util/subprocess"
|
||||
|
||||
require "vagrant-lxc/errors"
|
||||
|
||||
module Vagrant
|
||||
module LXC
|
||||
class Container
|
||||
class CLI
|
||||
attr_accessor :name
|
||||
|
||||
class TransitionBlockNotProvided < RuntimeError; end
|
||||
|
||||
# Include this so we can use `Subprocess` more easily.
|
||||
include Vagrant::Util::Retryable
|
||||
|
||||
def initialize(name = nil)
|
||||
@name = name
|
||||
@logger = Log4r::Logger.new("vagrant::provider::lxc::container::cli")
|
||||
end
|
||||
|
||||
def list
|
||||
run(:ls).split(/\s+/).uniq
|
||||
end
|
||||
|
||||
def state
|
||||
if @name && run(:info, '--name', @name) =~ /^state:[^A-Z]+([A-Z]+)$/
|
||||
$1.downcase.to_sym
|
||||
elsif @name
|
||||
:unknown
|
||||
end
|
||||
end
|
||||
|
||||
def create(template, template_opts = {})
|
||||
extra = template_opts.to_a.flatten
|
||||
extra.unshift '--' unless extra.empty?
|
||||
|
||||
run :create,
|
||||
# lxc-create options
|
||||
'--template', template,
|
||||
'--name', @name,
|
||||
*extra
|
||||
end
|
||||
|
||||
def destroy
|
||||
run :destroy, '--name', @name
|
||||
end
|
||||
|
||||
def start(configs = [], extra_opts = [])
|
||||
configs = configs.map { |conf| ["-s", conf] }.flatten
|
||||
configs += extra_opts if extra_opts
|
||||
run :start, '-d', '--name', @name, *configs
|
||||
end
|
||||
|
||||
def shutdown
|
||||
run :shutdown, '--name', @name
|
||||
end
|
||||
|
||||
def transition_to(state, &block)
|
||||
raise TransitionBlockNotProvided unless block_given?
|
||||
|
||||
yield self
|
||||
|
||||
run :wait, '--name', @name, '--state', state.to_s.upcase
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def run(command, *args)
|
||||
execute('sudo', "lxc-#{command}", *args)
|
||||
end
|
||||
|
||||
# TODO: Review code below this line, it was pretty much a copy and
|
||||
# paste from VirtualBox base driver and has no tests
|
||||
def execute(*command, &block)
|
||||
# Get the options hash if it exists
|
||||
opts = {}
|
||||
opts = command.pop if command.last.is_a?(Hash)
|
||||
|
||||
tries = 0
|
||||
tries = 3 if opts[:retryable]
|
||||
|
||||
sleep = opts.fetch(:sleep, 1)
|
||||
|
||||
# Variable to store our execution result
|
||||
r = nil
|
||||
|
||||
retryable(:on => LXC::Errors::ExecuteError, :tries => tries, :sleep => sleep) do
|
||||
# Execute the command
|
||||
r = raw(*command, &block)
|
||||
|
||||
# If the command was a failure, then raise an exception that is
|
||||
# nicely handled by Vagrant.
|
||||
if r.exit_code != 0
|
||||
if @interrupted
|
||||
@logger.info("Exit code != 0, but interrupted. Ignoring.")
|
||||
else
|
||||
raise LXC::Errors::ExecuteError, :command => command.inspect
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Return the output, making sure to replace any Windows-style
|
||||
# newlines with Unix-style.
|
||||
r.stdout.gsub("\r\n", "\n")
|
||||
end
|
||||
|
||||
def raw(*command, &block)
|
||||
int_callback = lambda do
|
||||
@interrupted = true
|
||||
@logger.info("Interrupted.")
|
||||
end
|
||||
|
||||
# Append in the options for subprocess
|
||||
command << { :notify => [:stdout, :stderr] }
|
||||
|
||||
Vagrant::Util::Busy.busy(int_callback) do
|
||||
Vagrant::Util::Subprocess.execute(*command, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
290
lib/vagrant-lxc/driver.rb
Normal file
290
lib/vagrant-lxc/driver.rb
Normal file
|
@ -0,0 +1,290 @@
|
|||
require "vagrant/util/retryable"
|
||||
require "vagrant/util/subprocess"
|
||||
|
||||
require "vagrant-lxc/errors"
|
||||
require "vagrant-lxc/driver/cli"
|
||||
require "vagrant-lxc/sudo_wrapper"
|
||||
|
||||
require "etc"
|
||||
|
||||
require "tempfile"
|
||||
|
||||
module Vagrant
|
||||
module LXC
|
||||
class Driver
|
||||
# This is raised if the container can't be found when initializing it with
|
||||
# a name.
|
||||
class ContainerNotFound < StandardError; end
|
||||
|
||||
# Default root folder where container configs are stored
|
||||
attr_reader :container_name,
|
||||
:customizations
|
||||
|
||||
def initialize(container_name, sudo_wrapper = nil, cli = nil, privileged: true)
|
||||
@container_name = container_name
|
||||
@sudo_wrapper = sudo_wrapper || SudoWrapper.new(privileged: privileged)
|
||||
@cli = cli || CLI.new(@sudo_wrapper, container_name)
|
||||
@logger = Log4r::Logger.new("vagrant::provider::lxc::driver")
|
||||
@customizations = []
|
||||
end
|
||||
|
||||
def validate!
|
||||
raise ContainerNotFound if @container_name && ! @cli.list.include?(@container_name)
|
||||
end
|
||||
|
||||
# Root folder where container configs are stored
|
||||
def containers_path
|
||||
@containers_path ||= @cli.config('lxc.lxcpath')
|
||||
end
|
||||
|
||||
def all_containers
|
||||
@cli.list
|
||||
end
|
||||
|
||||
def base_path
|
||||
Pathname.new("#{containers_path}/#{@container_name}")
|
||||
end
|
||||
|
||||
def config_path
|
||||
base_path.join('config').to_s
|
||||
end
|
||||
|
||||
def rootfs_path
|
||||
pathtype, path = config_string.match(/^lxc\.rootfs(?:\.path)?\s+=\s+(.+:)?(.+)$/)[1..2]
|
||||
case pathtype
|
||||
when 'overlayfs:'
|
||||
# Split on colon (:), ignoring any colon escaped by an escape character ( \ )
|
||||
# Pays attention to when the escape character is itself escaped.
|
||||
_, overlay_path = config_entry.split(/(?<!\\)(?:\\\\)*:/)
|
||||
if overlay_path
|
||||
Pathname.new(overlay_path)
|
||||
else
|
||||
# Malformed: fall back to prior behaviour
|
||||
Pathname.new(path)
|
||||
end
|
||||
else
|
||||
Pathname.new(path)
|
||||
end
|
||||
end
|
||||
|
||||
def mac_address
|
||||
return @mac_address if @mac_address
|
||||
|
||||
if config_string =~ /^lxc\.network\.hwaddr\s*+=\s*+(.+)$/
|
||||
@mac_address = $1
|
||||
end
|
||||
end
|
||||
|
||||
def config_string
|
||||
@sudo_wrapper.run('cat', config_path)
|
||||
end
|
||||
|
||||
def create(name, backingstore, backingstore_options, template_path, config_file, template_options = {})
|
||||
@cli.name = @container_name = name
|
||||
|
||||
@logger.debug "Creating container..."
|
||||
|
||||
@cli.create template_path, backingstore, backingstore_options, config_file, template_options
|
||||
end
|
||||
|
||||
def share_folders(folders)
|
||||
folders.each do |f|
|
||||
share_folder(f[:hostpath], f[:guestpath], f.fetch(:mount_options, nil))
|
||||
end
|
||||
end
|
||||
|
||||
def share_folder(host_path, guest_path, mount_options = nil)
|
||||
guest_path = guest_path.gsub(/^\//, '').gsub(' ', '\\\040')
|
||||
mount_options = Array(mount_options || ['bind', 'create=dir'])
|
||||
host_path = host_path.to_s.gsub(' ', '\\\040')
|
||||
@customizations << ['mount.entry', "#{host_path} #{guest_path} none #{mount_options.join(',')} 0 0"]
|
||||
end
|
||||
|
||||
def start(customizations)
|
||||
@logger.info('Starting container...')
|
||||
|
||||
if ENV['LXC_START_LOG_FILE']
|
||||
extra = ['-o', ENV['LXC_START_LOG_FILE'], '-l', 'DEBUG']
|
||||
end
|
||||
|
||||
prune_customizations
|
||||
write_customizations(customizations + @customizations)
|
||||
|
||||
@cli.start(extra)
|
||||
end
|
||||
|
||||
def forced_halt
|
||||
@logger.info('Shutting down container...')
|
||||
@cli.transition_to(:stopped) { |c| c.stop }
|
||||
end
|
||||
|
||||
def destroy
|
||||
@cli.destroy
|
||||
end
|
||||
|
||||
def attach(*command)
|
||||
@cli.attach(*command)
|
||||
end
|
||||
|
||||
def info(*command)
|
||||
@cli.info(*command)
|
||||
end
|
||||
|
||||
def configure_private_network(bridge_name, bridge_ip, container_name, address_type, ip)
|
||||
@logger.info "Configuring network interface for #{container_name} using #{ip} and bridge #{bridge_name}"
|
||||
if ip
|
||||
ip += '/24'
|
||||
end
|
||||
|
||||
if ! bridge_exists?(bridge_name)
|
||||
if not bridge_ip
|
||||
raise "Bridge is missing and no IP was specified!"
|
||||
end
|
||||
|
||||
@logger.info "Creating the bridge #{bridge_name}"
|
||||
cmd = [
|
||||
'brctl',
|
||||
'addbr',
|
||||
bridge_name
|
||||
]
|
||||
@sudo_wrapper.run(*cmd)
|
||||
end
|
||||
|
||||
if ! bridge_has_an_ip?(bridge_name)
|
||||
if not bridge_ip
|
||||
raise "Bridge has no IP and none was specified!"
|
||||
end
|
||||
@logger.info "Adding #{bridge_ip} to the bridge #{bridge_name}"
|
||||
cmd = [
|
||||
'ip',
|
||||
'addr',
|
||||
'add',
|
||||
"#{bridge_ip}/24",
|
||||
'dev',
|
||||
bridge_name
|
||||
]
|
||||
@sudo_wrapper.run(*cmd)
|
||||
@sudo_wrapper.run('ip', 'link', 'set', bridge_name, 'up')
|
||||
end
|
||||
|
||||
cmd = [
|
||||
Vagrant::LXC.source_root.join('scripts/pipework').to_s,
|
||||
bridge_name,
|
||||
container_name,
|
||||
ip ||= "dhcp"
|
||||
]
|
||||
@sudo_wrapper.run(*cmd)
|
||||
end
|
||||
|
||||
def bridge_has_an_ip?(bridge_name)
|
||||
@logger.info "Checking whether the bridge #{bridge_name} has an IP"
|
||||
`ip -4 addr show scope global #{bridge_name}` =~ /^\s+inet ([0-9.]+)\/[0-9]+\s+/
|
||||
end
|
||||
|
||||
def bridge_exists?(bridge_name)
|
||||
@logger.info "Checking whether bridge #{bridge_name} exists"
|
||||
brctl_output = `ip link | egrep -q " #{bridge_name}:"`
|
||||
$?.to_i == 0
|
||||
end
|
||||
|
||||
def bridge_is_in_use?(bridge_name)
|
||||
# REFACTOR: This method is **VERY** hacky
|
||||
@logger.info "Checking if bridge #{bridge_name} is in use"
|
||||
brctl_output = `brctl show #{bridge_name} 2>/dev/null | tail -n +2 | grep -q veth`
|
||||
$?.to_i == 0
|
||||
end
|
||||
|
||||
def remove_bridge(bridge_name)
|
||||
if ['lxcbr0', 'virbr0'].include? bridge_name
|
||||
@logger.info "Skipping removal of system bridge #{bridge_name}"
|
||||
return
|
||||
end
|
||||
|
||||
return unless bridge_exists?(bridge_name)
|
||||
|
||||
@logger.info "Removing bridge #{bridge_name}"
|
||||
@sudo_wrapper.run('ip', 'link', 'set', bridge_name, 'down')
|
||||
@sudo_wrapper.run('brctl', 'delbr', bridge_name)
|
||||
end
|
||||
|
||||
def version
|
||||
@version ||= @cli.version
|
||||
end
|
||||
|
||||
def supports_new_config_format
|
||||
Gem::Version.new(version) >= Gem::Version.new('2.1.0')
|
||||
end
|
||||
|
||||
# TODO: This needs to be reviewed and specs needs to be written
|
||||
def compress_rootfs
|
||||
# TODO: Pass in tmpdir so we can clean up from outside
|
||||
target_path = "#{Dir.mktmpdir}/rootfs.tar.gz"
|
||||
|
||||
@logger.info "Compressing '#{rootfs_path}' rootfs to #{target_path}"
|
||||
@sudo_wrapper.run('tar', '--numeric-owner', '-cvzf', target_path, '-C',
|
||||
rootfs_path.parent.to_s, "./#{rootfs_path.basename.to_s}")
|
||||
|
||||
@logger.info "Changing rootfs tarball owner"
|
||||
user_details = Etc.getpwnam(Etc.getlogin)
|
||||
@sudo_wrapper.run('chown', "#{user_details.uid}:#{user_details.gid}", target_path)
|
||||
|
||||
target_path
|
||||
end
|
||||
|
||||
def state
|
||||
if @container_name
|
||||
@cli.state
|
||||
end
|
||||
end
|
||||
|
||||
def prune_customizations
|
||||
# Use sed to just strip out the block of code which was inserted by Vagrant
|
||||
@logger.debug 'Prunning vagrant-lxc customizations'
|
||||
contents = config_string
|
||||
contents.gsub! /^# VAGRANT-BEGIN(.|\s)*# VAGRANT-END\n/, ''
|
||||
write_config(contents)
|
||||
end
|
||||
|
||||
def update_config_keys(path = nil)
|
||||
path = path || config_path
|
||||
@cli.update_config(path)
|
||||
rescue Errors::ExecuteError
|
||||
# not on LXC 2.1+. Doesn't matter, ignore.
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def write_customizations(customizations)
|
||||
customizations = customizations.map do |key, value|
|
||||
"lxc.#{key}=#{value}"
|
||||
end
|
||||
customizations.unshift '# VAGRANT-BEGIN'
|
||||
customizations << "# VAGRANT-END\n"
|
||||
|
||||
contents = config_string
|
||||
contents << customizations.join("\n")
|
||||
|
||||
write_config(contents)
|
||||
end
|
||||
|
||||
def write_config(contents)
|
||||
confpath = base_path.join('config').to_s
|
||||
begin
|
||||
File.open(confpath, File::RDWR) do |file|
|
||||
file.write contents
|
||||
end
|
||||
rescue
|
||||
# We don't have permissions to write in the conf file. That's probably because it's a
|
||||
# privileged container. Work around that through sudo_wrapper.
|
||||
Tempfile.new('lxc-config').tap do |file|
|
||||
file.chmod 0644
|
||||
file.write contents
|
||||
file.close
|
||||
@sudo_wrapper.run 'cp', '-f', file.path, confpath
|
||||
@sudo_wrapper.run 'chown', 'root:root', confpath
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
152
lib/vagrant-lxc/driver/cli.rb
Normal file
152
lib/vagrant-lxc/driver/cli.rb
Normal file
|
@ -0,0 +1,152 @@
|
|||
require "vagrant/util/retryable"
|
||||
require "vagrant/util/subprocess"
|
||||
|
||||
require "vagrant-lxc/errors"
|
||||
|
||||
module Vagrant
|
||||
module LXC
|
||||
class Driver
|
||||
class CLI
|
||||
attr_accessor :name
|
||||
|
||||
class TransitionBlockNotProvided < RuntimeError; end
|
||||
class TargetStateNotReached < RuntimeError
|
||||
def initialize(target_state, state)
|
||||
msg = "Target state '#{target_state}' not reached, currently on '#{state}'"
|
||||
super(msg)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(sudo_wrapper, name = nil)
|
||||
@sudo_wrapper = sudo_wrapper
|
||||
@name = name
|
||||
@logger = Log4r::Logger.new("vagrant::provider::lxc::container::cli")
|
||||
end
|
||||
|
||||
def list
|
||||
run(:ls).split(/\s+/).uniq
|
||||
end
|
||||
|
||||
def version
|
||||
return @version if @version
|
||||
@version = run(:create, '--version')
|
||||
if @version =~ /(lxc version:\s+|)(.+)\s*$/
|
||||
@version = $2.downcase
|
||||
else
|
||||
# TODO: Raise an user friendly error
|
||||
raise 'Unable to parse lxc version!'
|
||||
end
|
||||
end
|
||||
|
||||
def config(param)
|
||||
run(:config, param).gsub("\n", '')
|
||||
end
|
||||
|
||||
def update_config(path)
|
||||
run('update-config', '-c', path)
|
||||
end
|
||||
|
||||
def state
|
||||
if @name && run(:info, '--name', @name, retryable: true) =~ /^state:[^A-Z]+([A-Z]+)$/i
|
||||
$1.downcase.to_sym
|
||||
elsif @name
|
||||
:unknown
|
||||
end
|
||||
end
|
||||
|
||||
def create(template, backingstore, backingstore_options, config_file, template_opts = {})
|
||||
if config_file
|
||||
config_opts = ['-f', config_file]
|
||||
end
|
||||
|
||||
extra = template_opts.to_a.flatten.reject { |elem| elem.empty? }
|
||||
extra.unshift '--' unless extra.empty?
|
||||
|
||||
run :create,
|
||||
'-B', backingstore,
|
||||
'--template', template,
|
||||
'--name', @name,
|
||||
*(backingstore_options.to_a.flatten),
|
||||
*(config_opts),
|
||||
*extra
|
||||
rescue Errors::ExecuteError => e
|
||||
if e.stderr =~ /already exists/i
|
||||
raise Errors::ContainerAlreadyExists, name: @name
|
||||
else
|
||||
raise
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
run :destroy, '--name', @name
|
||||
end
|
||||
|
||||
def start(options = [])
|
||||
run :start, '-d', '--name', @name, *Array(options)
|
||||
end
|
||||
|
||||
## lxc-stop will exit 2 if machine was already stopped
|
||||
# Man Page:
|
||||
# 2 The specified container exists but was not running.
|
||||
def stop
|
||||
begin
|
||||
run :stop, '--name', @name
|
||||
rescue LXC::Errors::ExecuteError => e
|
||||
if e.exitcode == 2
|
||||
@logger.debug "Machine already stopped, lxc-stop returned 2"
|
||||
else
|
||||
raise e
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def attach(*cmd)
|
||||
cmd = ['--'] + cmd
|
||||
|
||||
if cmd.last.is_a?(Hash)
|
||||
opts = cmd.pop
|
||||
namespaces = Array(opts[:namespaces]).map(&:upcase).join('|')
|
||||
|
||||
# HACK: The wrapper script should be able to handle this
|
||||
if @sudo_wrapper.wrapper_path
|
||||
namespaces = "'#{namespaces}'"
|
||||
end
|
||||
|
||||
if namespaces
|
||||
extra = ['--namespaces', namespaces]
|
||||
end
|
||||
end
|
||||
|
||||
run :attach, '--name', @name, *((extra || []) + cmd)
|
||||
end
|
||||
|
||||
def info(*cmd)
|
||||
run(:info, '--name', @name, *cmd)
|
||||
end
|
||||
|
||||
def transition_to(target_state, tries = 30, timeout = 1, &block)
|
||||
raise TransitionBlockNotProvided unless block_given?
|
||||
|
||||
yield self
|
||||
|
||||
while (last_state = self.state) != target_state && tries > 0
|
||||
@logger.debug "Target state '#{target_state}' not reached, currently on '#{last_state}'"
|
||||
sleep timeout
|
||||
tries -= 1
|
||||
end
|
||||
|
||||
unless last_state == target_state
|
||||
# TODO: Raise an user friendly message
|
||||
raise TargetStateNotReached.new target_state, last_state
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def run(command, *args)
|
||||
@sudo_wrapper.run("lxc-#{command}", *args)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,12 +1,62 @@
|
|||
require 'vagrant/errors'
|
||||
|
||||
module Vagrant
|
||||
module LXC
|
||||
module Errors
|
||||
class ExecuteError < Vagrant::Errors::VagrantError
|
||||
error_key(:lxc_execute_error)
|
||||
attr_reader :stderr, :stdout, :exitcode
|
||||
def initialize(message, *args)
|
||||
super
|
||||
if message.is_a?(Hash)
|
||||
@stderr = message[:stderr]
|
||||
@stdout = message[:stdout]
|
||||
@exitcode = message[:exitcode]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when user interrupts a subprocess
|
||||
class SubprocessInterruptError < Vagrant::Errors::VagrantError
|
||||
error_key(:lxc_interrupt_error)
|
||||
def initialize(message, *args)
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class LxcLinuxRequired < Vagrant::Errors::VagrantError
|
||||
error_key(:lxc_linux_required)
|
||||
end
|
||||
|
||||
class LxcNotInstalled < Vagrant::Errors::VagrantError
|
||||
error_key(:lxc_not_installed)
|
||||
end
|
||||
|
||||
class ContainerAlreadyExists < Vagrant::Errors::VagrantError
|
||||
error_key(:lxc_container_already_exists)
|
||||
end
|
||||
|
||||
class CommandNotSupported < Vagrant::Errors::VagrantError
|
||||
error_key(:lxc_command_not_supported)
|
||||
end
|
||||
|
||||
# Box related errors
|
||||
class TemplateFileMissing < Vagrant::Errors::VagrantError
|
||||
error_key(:lxc_template_file_missing)
|
||||
end
|
||||
class TemplatesDirMissing < Vagrant::Errors::VagrantError
|
||||
error_key(:lxc_templates_dir_missing)
|
||||
end
|
||||
class RootFSTarballMissing < Vagrant::Errors::VagrantError
|
||||
error_key(:lxc_invalid_box_version)
|
||||
end
|
||||
class IncompatibleBox < Vagrant::Errors::VagrantError
|
||||
error_key(:lxc_incompatible_box)
|
||||
end
|
||||
class RedirNotInstalled < Vagrant::Errors::VagrantError
|
||||
error_key(:lxc_redir_not_installed)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
class MachineState < Vagrant::MachineState
|
||||
CREATED_STATES = %w( running stopped ).map!(&:to_sym)
|
||||
|
||||
def initialize(state_id)
|
||||
short = state_id.to_s.gsub("_", " ")
|
||||
long = I18n.t("vagrant.commands.status.#{state_id}")
|
||||
super(state_id, short, long)
|
||||
end
|
||||
|
||||
def created?
|
||||
CREATED_STATES.include?(self.id)
|
||||
end
|
||||
|
||||
def off?
|
||||
self.id == :stopped
|
||||
end
|
||||
|
||||
def running?
|
||||
self.id == :running
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,23 +1,51 @@
|
|||
require "vagrant"
|
||||
require 'vagrant'
|
||||
|
||||
module Vagrant
|
||||
module LXC
|
||||
class Plugin < Vagrant.plugin("2")
|
||||
name "Linux Containers (LXC) provider"
|
||||
name "vagrant-lxc"
|
||||
description <<-EOF
|
||||
The LXC provider allows Vagrant to manage and control
|
||||
LXC-based virtual machines.
|
||||
EOF
|
||||
|
||||
provider(:lxc) do
|
||||
require File.expand_path("../provider", __FILE__)
|
||||
provider(:lxc, parallel: true, priority: 7) do
|
||||
require_relative 'provider'
|
||||
init!
|
||||
Provider
|
||||
end
|
||||
|
||||
command "lxc" do
|
||||
require_relative 'command/root'
|
||||
init!
|
||||
Command::Root
|
||||
end
|
||||
|
||||
config(:lxc, :provider) do
|
||||
require File.expand_path("../config", __FILE__)
|
||||
require_relative 'config'
|
||||
init!
|
||||
Config
|
||||
end
|
||||
|
||||
synced_folder(:lxc) do
|
||||
require_relative 'synced_folder'
|
||||
SyncedFolder
|
||||
end
|
||||
|
||||
provider_capability("lxc", "public_address") do
|
||||
require_relative "provider/cap/public_address"
|
||||
Provider::Cap::PublicAddress
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def self.init!
|
||||
return if defined?(@_init)
|
||||
I18n.load_path << File.expand_path(File.dirname(__FILE__) + '/../../locales/en.yml')
|
||||
I18n.reload!
|
||||
@_init = true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,21 +1,37 @@
|
|||
require "log4r"
|
||||
|
||||
require "vagrant-lxc/action"
|
||||
require "vagrant-lxc/container"
|
||||
require "vagrant-lxc/machine_state"
|
||||
require "vagrant-lxc/driver"
|
||||
|
||||
module Vagrant
|
||||
module LXC
|
||||
class Provider < Vagrant.plugin("2", :provider)
|
||||
attr_reader :container
|
||||
attr_reader :driver
|
||||
|
||||
def self.usable?(raise_error=false)
|
||||
if !Vagrant::Util::Platform.linux?
|
||||
raise Errors::LxcLinuxRequired
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def initialize(machine)
|
||||
@logger = Log4r::Logger.new("vagrant::provider::lxc")
|
||||
@machine = machine
|
||||
|
||||
ensure_lxc_installed!
|
||||
machine_id_changed
|
||||
end
|
||||
|
||||
def ensure_lxc_installed!
|
||||
begin
|
||||
SudoWrapper.new(privileged: @machine.provider_config.privileged).run("which", "lxc-create")
|
||||
rescue Vagrant::LXC::Errors::ExecuteError
|
||||
raise Errors::LxcNotInstalled
|
||||
end
|
||||
end
|
||||
|
||||
# If the machine ID changed, then we need to rebuild our underlying
|
||||
# container.
|
||||
def machine_id_changed
|
||||
|
@ -23,9 +39,9 @@ module Vagrant
|
|||
|
||||
begin
|
||||
@logger.debug("Instantiating the container for: #{id.inspect}")
|
||||
@container = Container.new(id)
|
||||
@container.validate!
|
||||
rescue Container::NotFound
|
||||
@driver = Driver.new(id, privileged: @machine.provider_config.privileged)
|
||||
@driver.validate!
|
||||
rescue Driver::ContainerNotFound
|
||||
# The container doesn't exist, so we probably have a stale
|
||||
# ID. Just clear the id out of the machine and reload it.
|
||||
@logger.debug("Container not found! Clearing saved machine ID and reloading.")
|
||||
|
@ -34,35 +50,46 @@ module Vagrant
|
|||
end
|
||||
end
|
||||
|
||||
# @see Vagrant::Plugin::V1::Provider#action
|
||||
# @see Vagrant::Plugin::V2::Provider#action
|
||||
def action(name)
|
||||
# Attempt to get the action method from the Action class if it
|
||||
# exists, otherwise return nil to show that we don't support the
|
||||
# given action.
|
||||
action_method = "action_#{name}"
|
||||
# TODO: Rename to singular
|
||||
return LXC::Action.send(action_method) if LXC::Action.respond_to?(action_method)
|
||||
nil
|
||||
end
|
||||
|
||||
# Returns the SSH info for accessing the Container.
|
||||
def ssh_info
|
||||
# If the Container is not created then we cannot possibly SSH into it, so
|
||||
# If the Container is not running then we cannot possibly SSH into it, so
|
||||
# we return nil.
|
||||
return nil if state == :not_created
|
||||
return nil if state.id != :running
|
||||
|
||||
# Run a custom action called "ssh_ip" which does what it says and puts
|
||||
# the IP found into the `:machine_ip` key in the environment.
|
||||
env = @machine.action("ssh_ip")
|
||||
|
||||
# If we were not able to identify the container's IP, we return nil
|
||||
# here and we let Vagrant core deal with it ;)
|
||||
return nil unless env[:machine_ip]
|
||||
|
||||
{
|
||||
:host => @container.assigned_ip,
|
||||
:port => 22 # @driver.ssh_port(@machine.config.ssh.guest_port)
|
||||
:host => env[:machine_ip],
|
||||
:port => @machine.config.ssh.guest_port
|
||||
}
|
||||
end
|
||||
|
||||
def state
|
||||
state_id = nil
|
||||
state_id = :not_created if !@container.name
|
||||
state_id = @container.state if !state_id
|
||||
state_id = :not_created if !@driver.container_name
|
||||
state_id = @driver.state if !state_id
|
||||
state_id = :unknown if !state_id
|
||||
LXC::MachineState.new(state_id)
|
||||
|
||||
short = state_id.to_s.gsub("_", " ")
|
||||
long = I18n.t("vagrant.commands.status.#{state_id}")
|
||||
|
||||
Vagrant::MachineState.new(state_id, short, long)
|
||||
end
|
||||
|
||||
def to_s
|
||||
|
|
17
lib/vagrant-lxc/provider/cap/public_address.rb
Normal file
17
lib/vagrant-lxc/provider/cap/public_address.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
class Provider
|
||||
module Cap
|
||||
module PublicAddress
|
||||
def self.public_address(machine)
|
||||
return nil if machine.state.id != :running
|
||||
|
||||
ssh_info = machine.ssh_info
|
||||
return nil if !ssh_info
|
||||
ssh_info[:host]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
104
lib/vagrant-lxc/sudo_wrapper.rb
Normal file
104
lib/vagrant-lxc/sudo_wrapper.rb
Normal file
|
@ -0,0 +1,104 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
class SudoWrapper
|
||||
# Include this so we can use `Subprocess` more easily.
|
||||
include Vagrant::Util::Retryable
|
||||
|
||||
attr_reader :wrapper_path
|
||||
|
||||
def self.dest_path
|
||||
"/usr/local/bin/vagrant-lxc-wrapper"
|
||||
end
|
||||
|
||||
def initialize(privileged: true)
|
||||
@wrapper_path = Pathname.new(SudoWrapper.dest_path).exist? && SudoWrapper.dest_path || nil
|
||||
@privileged = privileged
|
||||
@logger = Log4r::Logger.new("vagrant::lxc::sudo_wrapper")
|
||||
end
|
||||
|
||||
def run(*command)
|
||||
options = command.last.is_a?(Hash) ? command.last : {}
|
||||
|
||||
# Avoid running LXC commands with a restrictive umask.
|
||||
# Otherwise disasters occur, like the container root directory
|
||||
# having permissions `rwxr-x---` which prevents the `vagrant`
|
||||
# user from accessing its own home directory; among other
|
||||
# problems, SSH cannot then read `authorized_keys`!
|
||||
old_mask = File.umask
|
||||
File.umask(old_mask & 022) # allow all `r` and `x` bits
|
||||
|
||||
begin
|
||||
if @privileged
|
||||
if @wrapper_path && !options[:no_wrapper]
|
||||
command.unshift @wrapper_path
|
||||
execute *(['sudo'] + command)
|
||||
else
|
||||
execute *(['sudo', '/usr/bin/env'] + command)
|
||||
end
|
||||
else
|
||||
execute *(['/usr/bin/env'] + command)
|
||||
end
|
||||
ensure
|
||||
File.umask(old_mask)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# TODO: Review code below this line, it was pretty much a copy and
|
||||
# paste from VirtualBox base driver and has no tests
|
||||
def execute(*command, &block)
|
||||
# Get the options hash if it exists
|
||||
opts = {}
|
||||
opts = command.pop if command.last.is_a?(Hash)
|
||||
|
||||
tries = 0
|
||||
tries = 3 if opts[:retryable]
|
||||
|
||||
sleep = opts.fetch(:sleep, 1)
|
||||
|
||||
# Variable to store our execution result
|
||||
r = nil
|
||||
|
||||
retryable(:on => LXC::Errors::ExecuteError, :tries => tries, :sleep => sleep) do
|
||||
# Execute the command
|
||||
r = raw(*command, &block)
|
||||
|
||||
# If the command was a failure, then raise an exception that is
|
||||
# nicely handled by Vagrant.
|
||||
if r.exit_code != 0
|
||||
if @interrupted
|
||||
raise LXC::Errors::SubprocessInterruptError, command.inspect
|
||||
else
|
||||
raise LXC::Errors::ExecuteError,
|
||||
command: command.inspect, stderr: r.stderr, stdout: r.stdout, exitcode: r.exit_code
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Return the output, making sure to replace any Windows-style
|
||||
# newlines with Unix-style.
|
||||
stdout = r.stdout.gsub("\r\n", "\n")
|
||||
if opts[:show_stderr]
|
||||
{ :stdout => stdout, :stderr => r.stderr.gsub("\r\n", "\n") }
|
||||
else
|
||||
stdout
|
||||
end
|
||||
end
|
||||
|
||||
def raw(*command, &block)
|
||||
int_callback = lambda do
|
||||
@interrupted = true
|
||||
@logger.info("Interrupted.")
|
||||
end
|
||||
|
||||
# Append in the options for subprocess
|
||||
command << { :notify => [:stdout, :stderr] }
|
||||
|
||||
Vagrant::Util::Busy.busy(int_callback) do
|
||||
Vagrant::Util::Subprocess.execute(*command, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
72
lib/vagrant-lxc/synced_folder.rb
Normal file
72
lib/vagrant-lxc/synced_folder.rb
Normal file
|
@ -0,0 +1,72 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
class SyncedFolder < Vagrant.plugin("2", :synced_folder)
|
||||
def usable?(machine)
|
||||
# These synced folders only work if the provider is LXC
|
||||
machine.provider_name == :lxc
|
||||
end
|
||||
|
||||
def prepare(machine, folders, _opts)
|
||||
machine.ui.output(I18n.t("vagrant.actions.lxc.share_folders.preparing"))
|
||||
# short guestpaths first, so we don't step on ourselves
|
||||
folders = folders.sort_by do |id, data|
|
||||
if data[:guestpath]
|
||||
data[:guestpath].length
|
||||
else
|
||||
# A long enough path to just do this at the end.
|
||||
10000
|
||||
end
|
||||
end
|
||||
|
||||
folders.each do |id, data|
|
||||
host_path = Pathname.new(File.expand_path(data[:hostpath], machine.env.root_path))
|
||||
guest_path = data[:guestpath]
|
||||
|
||||
machine.env.ui.warn(I18n.t("vagrant_lxc.messages.warn_owner")) if data[:owner]
|
||||
machine.env.ui.warn(I18n.t("vagrant_lxc.messages.warn_group")) if data[:group]
|
||||
|
||||
if !host_path.directory? && data[:create]
|
||||
# Host path doesn't exist, so let's create it.
|
||||
@logger.info("Host path doesn't exist, creating: #{host_path}")
|
||||
|
||||
begin
|
||||
host_path.mkpath
|
||||
rescue Errno::EACCES
|
||||
raise Vagrant::Errors::SharedFolderCreateFailed,
|
||||
:path => hostpath.to_s
|
||||
end
|
||||
end
|
||||
|
||||
mount_opts = data[:mount_options]
|
||||
machine.provider.driver.share_folder(host_path, guest_path, mount_opts)
|
||||
# Guest path specified, so mount the folder to specified point
|
||||
machine.ui.detail(I18n.t("vagrant.actions.vm.share_folders.mounting_entry",
|
||||
guestpath: data[:guestpath],
|
||||
hostpath: data[:hostpath],
|
||||
guest_path: data[:guestpath]))
|
||||
end
|
||||
end
|
||||
|
||||
def enable(machine, folders, _opts)
|
||||
# Emit an upstart event if we can
|
||||
return unless machine.communicate.test("test -x /sbin/initctl")
|
||||
|
||||
# short guestpaths first, so we don't step on ourselves
|
||||
folders = folders.sort_by do |id, data|
|
||||
if data[:guestpath]
|
||||
data[:guestpath].length
|
||||
else
|
||||
# A long enough path to just do this at the end.
|
||||
10000
|
||||
end
|
||||
end
|
||||
|
||||
folders.each do |id, data|
|
||||
guest_path = data[:guestpath]
|
||||
machine.communicate.sudo(
|
||||
"/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=#{guest_path}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,5 +1,5 @@
|
|||
module Vagrant
|
||||
module LXC
|
||||
VERSION = "0.0.1"
|
||||
VERSION = "1.4.2"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
# Tks to: https://github.com/carlhuda/bundler/blob/master/lib/bundler/vendored_thor.rb
|
||||
|
||||
if defined?(Vagrant) && Vagrant.respond_to?(:in_installer?)
|
||||
puts "vagrant has already been required. This may cause vagrant-lxc to malfunction in unexpected ways."
|
||||
end
|
||||
vendor = File.expand_path('../../vendor/vagrant/lib', __FILE__)
|
||||
$:.unshift(vendor) unless $:.include?(vendor)
|
||||
|
||||
require 'vagrant'
|
|
@ -1,17 +1,82 @@
|
|||
en:
|
||||
vagrant_lxc:
|
||||
messages:
|
||||
not_created: |-
|
||||
The container hasn't been created yet.
|
||||
not_running: |-
|
||||
The container is not currently running.
|
||||
will_not_destroy: |-
|
||||
The container '%{name}' will not be destroyed, since the confirmation
|
||||
was declined.
|
||||
starting: |-
|
||||
Starting container...
|
||||
force_shutdown: |-
|
||||
Forcing shutdown of container...
|
||||
warn_networks: |-
|
||||
Warning! The LXC provider doesn't support public networks, the settings
|
||||
will be silently ignored.
|
||||
warn_group: |-
|
||||
Warning! The LXC provider doesn't support the :group parameter for synced
|
||||
folders. It will be silently ignored.
|
||||
warn_owner: |-
|
||||
Warning! The LXC provider doesn't support the :owner parameter for synced
|
||||
folders. It will be silently ignored.
|
||||
setup_private_network: |-
|
||||
Setting up private networks...
|
||||
remove_bridge: |-
|
||||
Removing bridge '%{name}'...
|
||||
|
||||
vagrant:
|
||||
commands:
|
||||
status:
|
||||
stopped: |-
|
||||
The container is currently stopped. Run `vagrant up` to bring it up again.
|
||||
|
||||
actions:
|
||||
lxc:
|
||||
compressing_rootfs: Compressing container's rootfs...
|
||||
|
||||
share_folders:
|
||||
preparing: Setting up mount entries for shared folders...
|
||||
|
||||
errors:
|
||||
lxc_interrupt_error: |-
|
||||
Interrupted
|
||||
|
||||
lxc_execute_error: |-
|
||||
There was an error executing %{command}
|
||||
|
||||
For more information on the failure, enable detailed logging by setting
|
||||
the environment variable VAGRANT_LOG to DEBUG.
|
||||
|
||||
lxc_incompatible_box: |-
|
||||
The base box you are trying to use is not compatible with the installed
|
||||
vagrant-lxc version. Supported box versions are %{supported} but %{found} was found.
|
||||
|
||||
lxc_template_file_missing: |-
|
||||
The template file used for creating the container was not found for %{name}
|
||||
box.
|
||||
|
||||
lxc_templates_dir_missing: |-
|
||||
Unable to identify lxc templates path.
|
||||
|
||||
Looked up under: %{paths}
|
||||
|
||||
lxc_linux_required: |-
|
||||
The LXC provider only works on Linux. Please try to use
|
||||
another provider.
|
||||
|
||||
lxc_not_installed: |-
|
||||
The `lxc` package does not seem to be installed or `lxc-create` is not accessible on the PATH.
|
||||
|
||||
lxc_redir_not_installed: |-
|
||||
`redir` is not installed or is not accessible on the PATH.
|
||||
|
||||
lxc_container_already_exists: |-
|
||||
There is container on your system with the same name you've specified
|
||||
on your Vagrantfile (%{name}), please choose a different one or
|
||||
run `lxc-destroy --name %{name}` and try again.
|
||||
|
||||
lxc_command_not_supported: |-
|
||||
Command (lxc-%{command}) not supported in version %{version}.
|
||||
This command is available with version %{available_version}.
|
||||
|
|
180
scripts/lxc-template
Executable file
180
scripts/lxc-template
Executable file
|
@ -0,0 +1,180 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# This is a modified version of /usr/share/lxc/templates/lxc-download
|
||||
# that comes with ubuntu-lxc 1.0.0 stable from ppa changed to suit vagrant-lxc needs
|
||||
#
|
||||
# Copyright © 2014 Stéphane Graber <stgraber@ubuntu.com>
|
||||
# Copyright © 2014 Fábio Rehm <fgrehm@gmail.com>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
# USA
|
||||
|
||||
set -eu
|
||||
|
||||
LXC_HOOK_DIR="/usr/share/lxc/hooks"
|
||||
LXC_TEMPLATE_CONFIG="/usr/share/lxc/config"
|
||||
|
||||
LXC_MAPPED_GID=
|
||||
LXC_MAPPED_UID=
|
||||
LXC_NAME=
|
||||
LXC_PATH=
|
||||
LXC_ROOTFS=
|
||||
LXC_TARBALL=
|
||||
LXC_CONFIG=
|
||||
LXC_USE_OLDCONFIG=
|
||||
LXC_STRIP_COMPONENTS=2
|
||||
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
vagrant-lxc default template
|
||||
|
||||
Required arguments:
|
||||
[ --tarball <path> ]: The full path of the rootfs tarball
|
||||
|
||||
Optional arguments:
|
||||
[ --config ]: Configuration file to be used when building the container
|
||||
[ --oldconfig ]: Use pre LXC 2.1 config format
|
||||
[ -h | --help ]: This help message
|
||||
|
||||
LXC internal arguments (do not pass manually!):
|
||||
[ --name <name> ]: The container name
|
||||
[ --path <path> ]: The path to the container
|
||||
[ --rootfs <rootfs> ]: The path to the container's rootfs
|
||||
[ --mapped-uid <map> ]: A uid map (user namespaces)
|
||||
[ --mapped-gid <map> ]: A gid map (user namespaces)
|
||||
[ --strip-components <num> ]: Number of path components to strip from tarball
|
||||
EOF
|
||||
return 0
|
||||
}
|
||||
|
||||
options=$(getopt -o h -l tarball:,config:,oldconfig,help:,name:,path:,rootfs:,mapped-uid:,mapped-gid:,strip-components: -- "$@")SS
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
usage $(basename $0)
|
||||
exit 1
|
||||
fi
|
||||
eval set -- "$options"
|
||||
|
||||
while true
|
||||
do
|
||||
case "$1" in
|
||||
-h|--help) usage $0 && exit 0;;
|
||||
--config) LXC_CONFIG=$2; shift 2;;
|
||||
--oldconfig) LXC_USE_OLDCONFIG=1; shift 1;;
|
||||
--tarball) LXC_TARBALL=$2; shift 2;;
|
||||
--name) LXC_NAME=$2; shift 2;;
|
||||
--path) LXC_PATH=$2; shift 2;;
|
||||
--rootfs) LXC_ROOTFS=$2; shift 2;;
|
||||
--mapped-uid) LXC_MAPPED_UID=$2; shift 2;;
|
||||
--mapped-gid) LXC_MAPPED_GID=$2; shift 2;;
|
||||
--strip-components) LXC_STRIP_COMPONENTS=$2; shift 2;;
|
||||
*) break;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "${LXC_NAME}" ]; then
|
||||
echo "'name' parameter is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${LXC_TARBALL}" ]; then
|
||||
echo "'tarball' parameter is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${LXC_PATH}" ]; then
|
||||
echo "'path' parameter is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# if $LXC_ROOTFS exists here, it was passed in with --rootfs
|
||||
if [ -z "${LXC_ROOTFS}" ]; then
|
||||
config=${LXC_PATH}/config
|
||||
if grep -q '^lxc.rootfs' $config 2>/dev/null ; then
|
||||
LXC_ROOTFS=`grep 'lxc.rootfs =' $config | awk -F= '{ print $2 }'`
|
||||
else
|
||||
LXC_ROOTFS=$LXC_PATH/rootfs
|
||||
echo "lxc.rootfs = ${LXC_ROOTFS}" >> $config
|
||||
fi
|
||||
fi
|
||||
|
||||
# Unpack the rootfs
|
||||
echo "Unpacking the rootfs"
|
||||
|
||||
(
|
||||
flock -x 200
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Cache repository is busy."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p ${LXC_ROOTFS}
|
||||
(cd ${LXC_ROOTFS} && tar xfz ${LXC_TARBALL} --strip-components=${LXC_STRIP_COMPONENTS} --xattrs --xattrs-include=* || true)
|
||||
if [ ! -f ${LXC_ROOTFS}/bin/true ]; then
|
||||
echo "Failed to extract rootfs"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
) 200>${LXC_PATH}/vagrant_lock
|
||||
rm ${LXC_PATH}/vagrant_lock
|
||||
|
||||
mkdir -p ${LXC_ROOTFS}/dev/pts/
|
||||
|
||||
## Extract all the network config entries
|
||||
sed -i -e "/lxc.network/{w ${LXC_PATH}/config-network" -e "d}" \
|
||||
${LXC_PATH}/config
|
||||
|
||||
## Extract any other config entry
|
||||
sed -i -e "/lxc./{w ${LXC_PATH}/config-auto" -e "d}" ${LXC_PATH}/config
|
||||
|
||||
## Add the container-specific config
|
||||
echo "" >> ${LXC_PATH}/config
|
||||
echo "##############################################" >> ${LXC_PATH}/config
|
||||
echo "# Container specific configuration (automatically set)" >> ${LXC_PATH}/config
|
||||
if [ -e "${LXC_PATH}/config-auto" ]; then
|
||||
cat ${LXC_PATH}/config-auto >> ${LXC_PATH}/config
|
||||
rm ${LXC_PATH}/config-auto
|
||||
fi
|
||||
|
||||
if [ $LXC_USE_OLDCONFIG ]; then
|
||||
echo "lxc.utsname = ${LXC_NAME}" >> ${LXC_PATH}/config
|
||||
else
|
||||
echo "lxc.uts.name = ${LXC_NAME}" >> ${LXC_PATH}/config
|
||||
fi
|
||||
|
||||
## Re-add the previously removed network config
|
||||
if [ -e "${LXC_PATH}/config-network" ]; then
|
||||
echo "" >> ${LXC_PATH}/config
|
||||
echo "##############################################" >> ${LXC_PATH}/config
|
||||
echo "# Network configuration (automatically set)" >> ${LXC_PATH}/config
|
||||
cat ${LXC_PATH}/config-network >> ${LXC_PATH}/config
|
||||
rm ${LXC_PATH}/config-network
|
||||
fi
|
||||
|
||||
if [ -n "${LXC_CONFIG}" ]; then
|
||||
## Append the defaults
|
||||
echo "" >> ${LXC_PATH}/config
|
||||
echo "##############################################" >> ${LXC_PATH}/config
|
||||
echo "# vagrant-lxc base box specific configuration" >> ${LXC_PATH}/config
|
||||
cat ${LXC_CONFIG} >> ${LXC_PATH}/config
|
||||
fi
|
||||
|
||||
# Empty section for lxc.customize calls from vagrantfile
|
||||
echo "" >> ${LXC_PATH}/config
|
||||
echo "##############################################" >> ${LXC_PATH}/config
|
||||
echo "# vagrant-lxc container specific configuration" >> ${LXC_PATH}/config
|
||||
|
||||
exit 0
|
422
scripts/pipework
Executable file
422
scripts/pipework
Executable file
|
@ -0,0 +1,422 @@
|
|||
#!/bin/sh
|
||||
# This code should (try to) follow Google's Shell Style Guide
|
||||
# (https://google-styleguide.googlecode.com/svn/trunk/shell.xml)
|
||||
set -e
|
||||
|
||||
case "$1" in
|
||||
--wait)
|
||||
WAIT=1
|
||||
;;
|
||||
esac
|
||||
|
||||
IFNAME=$1
|
||||
|
||||
# default value set further down if not set here
|
||||
CONTAINER_IFNAME=
|
||||
if [ "$2" = "-i" ]; then
|
||||
CONTAINER_IFNAME=$3
|
||||
shift 2
|
||||
fi
|
||||
|
||||
if [ "$2" = "-l" ]; then
|
||||
LOCAL_IFNAME=$3
|
||||
shift 2
|
||||
fi
|
||||
|
||||
GUESTNAME=$2
|
||||
IPADDR=$3
|
||||
MACADDR=$4
|
||||
|
||||
case "$MACADDR" in
|
||||
*@*)
|
||||
VLAN="${MACADDR#*@}"
|
||||
VLAN="${VLAN%%@*}"
|
||||
MACADDR="${MACADDR%%@*}"
|
||||
;;
|
||||
*)
|
||||
VLAN=
|
||||
;;
|
||||
esac
|
||||
|
||||
# did they ask to generate a custom MACADDR?
|
||||
# generate the unique string
|
||||
case "$MACADDR" in
|
||||
U:*)
|
||||
macunique="${MACADDR#*:}"
|
||||
# now generate a 48-bit hash string from $macunique
|
||||
MACADDR=$(echo $macunique|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
[ "$IPADDR" ] || [ "$WAIT" ] || {
|
||||
echo "Syntax:"
|
||||
echo "pipework <hostinterface> [-i containerinterface] [-l localinterfacename] <guest> <ipaddr>/<subnet>[@default_gateway] [macaddr][@vlan]"
|
||||
echo "pipework <hostinterface> [-i containerinterface] [-l localinterfacename] <guest> dhcp [macaddr][@vlan]"
|
||||
echo "pipework route <guest> <route_command>"
|
||||
echo "pipework --wait [-i containerinterface]"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Succeed if the given utility is installed. Fail otherwise.
|
||||
# For explanations about `which` vs `type` vs `command`, see:
|
||||
# http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script/677212#677212
|
||||
# (Thanks to @chenhanxiao for pointing this out!)
|
||||
installed () {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Google Styleguide says error messages should go to standard error.
|
||||
warn () {
|
||||
echo "$@" >&2
|
||||
}
|
||||
die () {
|
||||
status="$1"
|
||||
shift
|
||||
warn "$@"
|
||||
exit "$status"
|
||||
}
|
||||
|
||||
# First step: determine type of first argument (bridge, physical interface...),
|
||||
# Unless "--wait" is set (then skip the whole section)
|
||||
if [ -z "$WAIT" ]; then
|
||||
if [ -d "/sys/class/net/$IFNAME" ]
|
||||
then
|
||||
if [ -d "/sys/class/net/$IFNAME/bridge" ]; then
|
||||
IFTYPE=bridge
|
||||
BRTYPE=linux
|
||||
elif installed ovs-vsctl && ovs-vsctl list-br|grep -q "^${IFNAME}$"; then
|
||||
IFTYPE=bridge
|
||||
BRTYPE=openvswitch
|
||||
elif [ "$(cat "/sys/class/net/$IFNAME/type")" -eq 32 ]; then # InfiniBand IPoIB interface type 32
|
||||
IFTYPE=ipoib
|
||||
# The IPoIB kernel module is fussy, set device name to ib0 if not overridden
|
||||
CONTAINER_IFNAME=${CONTAINER_IFNAME:-ib0}
|
||||
PKEY=$VLAN
|
||||
else IFTYPE=phys
|
||||
fi
|
||||
else
|
||||
case "$IFNAME" in
|
||||
br*)
|
||||
IFTYPE=bridge
|
||||
BRTYPE=linux
|
||||
;;
|
||||
ovs*)
|
||||
if ! installed ovs-vsctl; then
|
||||
die 1 "Need OVS installed on the system to create an ovs bridge"
|
||||
fi
|
||||
IFTYPE=bridge
|
||||
BRTYPE=openvswitch
|
||||
;;
|
||||
route*)
|
||||
IFTYPE=route
|
||||
;;
|
||||
dummy*)
|
||||
IFTYPE=dummy
|
||||
;;
|
||||
*) die 1 "I do not know how to setup interface $IFNAME." ;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
# Set the default container interface name to eth1 if not already set
|
||||
CONTAINER_IFNAME=${CONTAINER_IFNAME:-eth1}
|
||||
|
||||
[ "$WAIT" ] && {
|
||||
while true; do
|
||||
# This first method works even without `ip` or `ifconfig` installed,
|
||||
# but doesn't work on older kernels (e.g. CentOS 6.X). See #128.
|
||||
grep -q '^1$' "/sys/class/net/$CONTAINER_IFNAME/carrier" && break
|
||||
# This method hopefully works on those older kernels.
|
||||
ip link ls dev "$CONTAINER_IFNAME" && break
|
||||
sleep 1
|
||||
done > /dev/null 2>&1
|
||||
exit 0
|
||||
}
|
||||
|
||||
[ "$IFTYPE" = bridge ] && [ "$BRTYPE" = linux ] && [ "$VLAN" ] && {
|
||||
die 1 "VLAN configuration currently unsupported for Linux bridge."
|
||||
}
|
||||
|
||||
[ "$IFTYPE" = ipoib ] && [ "$MACADDR" ] && {
|
||||
die 1 "MACADDR configuration unsupported for IPoIB interfaces."
|
||||
}
|
||||
|
||||
# Second step: find the guest (for now, we only support LXC containers)
|
||||
while read _ mnt fstype options _; do
|
||||
[ "$fstype" != "cgroup" ] && continue
|
||||
echo "$options" | grep -qw devices || continue
|
||||
CGROUPMNT=$mnt
|
||||
done < /proc/mounts
|
||||
|
||||
[ "$CGROUPMNT" ] || {
|
||||
die 1 "Could not locate cgroup mount point."
|
||||
}
|
||||
|
||||
# Try to find a cgroup matching exactly the provided name.
|
||||
N=$(find "$CGROUPMNT" -name "$GUESTNAME" | wc -l)
|
||||
case "$N" in
|
||||
0)
|
||||
# If we didn't find anything, try to lookup the container with Docker.
|
||||
if installed docker; then
|
||||
RETRIES=3
|
||||
while [ "$RETRIES" -gt 0 ]; do
|
||||
DOCKERPID=$(docker inspect --format='{{ .State.Pid }}' "$GUESTNAME")
|
||||
[ "$DOCKERPID" != 0 ] && break
|
||||
sleep 1
|
||||
RETRIES=$((RETRIES - 1))
|
||||
done
|
||||
|
||||
[ "$DOCKERPID" = 0 ] && {
|
||||
die 1 "Docker inspect returned invalid PID 0"
|
||||
}
|
||||
|
||||
[ "$DOCKERPID" = "<no value>" ] && {
|
||||
die 1 "Container $GUESTNAME not found, and unknown to Docker."
|
||||
}
|
||||
else
|
||||
die 1 "Container $GUESTNAME not found, and Docker not installed."
|
||||
fi
|
||||
;;
|
||||
1) true ;;
|
||||
*) die 1 "Found more than one container matching $GUESTNAME." ;;
|
||||
esac
|
||||
|
||||
# only check IPADDR if we are not in a route mode
|
||||
[ "$IFTYPE" != route ] && {
|
||||
case "$IPADDR" in
|
||||
# Let's check first if the user asked for DHCP allocation.
|
||||
dhcp|dhcp:*)
|
||||
# Use Docker-specific strategy to run the DHCP client
|
||||
# from the busybox image, in the network namespace of
|
||||
# the container.
|
||||
if ! [ "$DOCKERPID" ]; then
|
||||
warn "You asked for a Docker-specific DHCP method."
|
||||
warn "However, $GUESTNAME doesn't seem to be a Docker container."
|
||||
warn "Try to replace 'dhcp' with another option?"
|
||||
die 1 "Aborting."
|
||||
fi
|
||||
DHCP_CLIENT=${IPADDR%%:*}
|
||||
;;
|
||||
udhcpc|udhcpc:*|udhcpc-f|udhcpc-f:*|dhcpcd|dhcpcd:*|dhclient|dhclient:*|dhclient-f|dhclient-f:*)
|
||||
DHCP_CLIENT=${IPADDR%%:*}
|
||||
# did they ask for the client to remain?
|
||||
DHCP_FOREGROUND=
|
||||
[ "${DHCP_CLIENT: -2}" = '-f' ] && {
|
||||
DHCP_FOREGROUND=true
|
||||
}
|
||||
DHCP_CLIENT=${DHCP_CLIENT%-f}
|
||||
if ! installed "$DHCP_CLIENT"; then
|
||||
die 1 "You asked for DHCP client $DHCP_CLIENT, but I can't find it."
|
||||
fi
|
||||
;;
|
||||
# Alright, no DHCP? Then let's see if we have a subnet *and* gateway.
|
||||
*/*@*)
|
||||
GATEWAY="${IPADDR#*@}" GATEWAY="${GATEWAY%%@*}"
|
||||
IPADDR="${IPADDR%%@*}"
|
||||
;;
|
||||
# No gateway? We need at least a subnet, anyway!
|
||||
*/*) : ;;
|
||||
# ... No? Then stop right here.
|
||||
*)
|
||||
warn "The IP address should include a netmask."
|
||||
die 1 "Maybe you meant $IPADDR/24 ?"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# If a DHCP method was specified, extract the DHCP options.
|
||||
if [ "$DHCP_CLIENT" ]; then
|
||||
case "$IPADDR" in
|
||||
*:*) DHCP_OPTIONS="${IPADDR#*:}" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ "$DOCKERPID" ]; then
|
||||
NSPID=$DOCKERPID
|
||||
else
|
||||
NSPID=$(head -n 1 "$(find "$CGROUPMNT" -name "$GUESTNAME" | head -n 1)/tasks")
|
||||
[ "$NSPID" ] || {
|
||||
# it is an alternative way to get the pid
|
||||
NSPID=$(lxc-info -n "$GUESTNAME" | grep PID | grep -Eo '[0-9]+')
|
||||
[ "$NSPID" ] || {
|
||||
die 1 "Could not find a process inside container $GUESTNAME."
|
||||
}
|
||||
}
|
||||
fi
|
||||
|
||||
# Check if an incompatible VLAN device already exists
|
||||
[ "$IFTYPE" = phys ] && [ "$VLAN" ] && [ -d "/sys/class/net/$IFNAME.VLAN" ] && {
|
||||
ip -d link show "$IFNAME.$VLAN" | grep -q "vlan.*id $VLAN" || {
|
||||
die 1 "$IFNAME.VLAN already exists but is not a VLAN device for tag $VLAN"
|
||||
}
|
||||
}
|
||||
|
||||
[ ! -d /var/run/netns ] && mkdir -p /var/run/netns
|
||||
rm -f "/var/run/netns/$NSPID"
|
||||
ln -s "/proc/$NSPID/ns/net" "/var/run/netns/$NSPID"
|
||||
|
||||
# Check if we need to create a bridge.
|
||||
[ "$IFTYPE" = bridge ] && [ ! -d "/sys/class/net/$IFNAME" ] && {
|
||||
[ "$BRTYPE" = linux ] && {
|
||||
(ip link add dev "$IFNAME" type bridge > /dev/null 2>&1) || (brctl addbr "$IFNAME")
|
||||
ip link set "$IFNAME" up
|
||||
}
|
||||
[ "$BRTYPE" = openvswitch ] && {
|
||||
ovs-vsctl add-br "$IFNAME"
|
||||
}
|
||||
}
|
||||
|
||||
[ "$IFTYPE" != "route" ] && [ "$IFTYPE" != "dummy" ] && MTU=$(ip link show "$IFNAME" | awk '{print $5}')
|
||||
|
||||
# If it's a bridge, we need to create a veth pair
|
||||
[ "$IFTYPE" = bridge ] && {
|
||||
if [ -z "$LOCAL_IFNAME" ]; then
|
||||
LOCAL_IFNAME="v${CONTAINER_IFNAME}pl${NSPID}"
|
||||
fi
|
||||
GUEST_IFNAME="v${CONTAINER_IFNAME}pg${NSPID}"
|
||||
# Does the link already exist?
|
||||
if ip link show "$LOCAL_IFNAME" >/dev/null 2>&1; then
|
||||
# link exists, is it in use?
|
||||
if ip link show "$LOCAL_IFNAME" up | grep -q "UP"; then
|
||||
echo "Link $LOCAL_IFNAME exists and is up"
|
||||
exit 1
|
||||
fi
|
||||
# delete the link so we can re-add it afterwards
|
||||
ip link del "$LOCAL_IFNAME"
|
||||
fi
|
||||
ip link add name "$LOCAL_IFNAME" mtu "$MTU" type veth peer name "$GUEST_IFNAME" mtu "$MTU"
|
||||
case "$BRTYPE" in
|
||||
linux)
|
||||
(ip link set "$LOCAL_IFNAME" master "$IFNAME" > /dev/null 2>&1) || (brctl addif "$IFNAME" "$LOCAL_IFNAME")
|
||||
;;
|
||||
openvswitch)
|
||||
if ! ovs-vsctl list-ports "$IFNAME" | grep -q "^${LOCAL_IFNAME}$"; then
|
||||
ovs-vsctl add-port "$IFNAME" "$LOCAL_IFNAME" ${VLAN:+tag="$VLAN"}
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
ip link set "$LOCAL_IFNAME" up
|
||||
}
|
||||
|
||||
# If it's a physical interface, create a macvlan subinterface
|
||||
[ "$IFTYPE" = phys ] && {
|
||||
[ "$VLAN" ] && {
|
||||
[ ! -d "/sys/class/net/${IFNAME}.${VLAN}" ] && {
|
||||
ip link add link "$IFNAME" name "$IFNAME.$VLAN" mtu "$MTU" type vlan id "$VLAN"
|
||||
}
|
||||
ip link set "$IFNAME" up
|
||||
IFNAME=$IFNAME.$VLAN
|
||||
}
|
||||
GUEST_IFNAME=ph$NSPID$CONTAINER_IFNAME
|
||||
ip link add link "$IFNAME" dev "$GUEST_IFNAME" mtu "$MTU" type macvlan mode bridge
|
||||
ip link set "$IFNAME" up
|
||||
}
|
||||
|
||||
# If it's an IPoIB interface, create a virtual IPoIB interface (the IPoIB
|
||||
# equivalent of a macvlan device)
|
||||
#
|
||||
# Note: no macvlan subinterface nor Ethernet bridge can be created on top of an
|
||||
# IPoIB interface. InfiniBand is not Ethernet. IPoIB is an IP layer on top of
|
||||
# InfiniBand, without an intermediate Ethernet layer.
|
||||
[ "$IFTYPE" = ipoib ] && {
|
||||
GUEST_IFNAME="${IFNAME}.${NSPID}"
|
||||
|
||||
# If a partition key is provided, use it
|
||||
[ "$PKEY" ] && {
|
||||
GUEST_IFNAME="${IFNAME}.${PKEY}.${NSPID}"
|
||||
PKEY="pkey 0x$PKEY"
|
||||
}
|
||||
|
||||
ip link add link "$IFNAME" name "$GUEST_IFNAME" type ipoib $PKEY
|
||||
ip link set "$IFNAME" up
|
||||
}
|
||||
|
||||
# If its a dummy interface, create a dummy interface.
|
||||
[ "$IFTYPE" = dummy ] && {
|
||||
GUEST_IFNAME=du$NSPID$CONTAINER_IFNAME
|
||||
ip link add dev "$GUEST_IFNAME" type dummy
|
||||
}
|
||||
|
||||
# If the `route` command was specified ...
|
||||
if [ "$IFTYPE" = route ]; then
|
||||
# ... discard the first two arguments and pass the rest to the route command.
|
||||
shift 2
|
||||
ip netns exec "$NSPID" ip route "$@"
|
||||
else
|
||||
# Otherwise, run normally.
|
||||
ip link set "$GUEST_IFNAME" netns "$NSPID"
|
||||
ip netns exec "$NSPID" ip link set "$GUEST_IFNAME" name "$CONTAINER_IFNAME"
|
||||
[ "$MACADDR" ] && ip netns exec "$NSPID" ip link set dev "$CONTAINER_IFNAME" address "$MACADDR"
|
||||
|
||||
# When using any of the DHCP methods, we start a DHCP client in the
|
||||
# network namespace of the container. With the 'dhcp' method, the
|
||||
# client used is taken from the Docker busybox image (therefore
|
||||
# requiring no specific client installed on the host). Other methods
|
||||
# use a locally installed client.
|
||||
case "$DHCP_CLIENT" in
|
||||
dhcp)
|
||||
docker run -d --net container:$GUESTNAME --cap-add NET_ADMIN \
|
||||
busybox udhcpc -i "$CONTAINER_IFNAME" -x "hostname:$GUESTNAME" \
|
||||
$DHCP_OPTIONS \
|
||||
>/dev/null
|
||||
;;
|
||||
udhcpc)
|
||||
DHCP_Q="-q"
|
||||
[ "$DHCP_FOREGROUND" ] && {
|
||||
DHCP_OPTIONS="$DHCP_OPTIONS -f"
|
||||
}
|
||||
ip netns exec "$NSPID" "$DHCP_CLIENT" -qi "$CONTAINER_IFNAME" \
|
||||
-x "hostname:$GUESTNAME" \
|
||||
-p "/var/run/udhcpc.$GUESTNAME.pid" \
|
||||
$DHCP_OPTIONS
|
||||
[ ! "$DHCP_FOREGROUND" ] && {
|
||||
rm "/var/run/udhcpc.$GUESTNAME.pid"
|
||||
}
|
||||
;;
|
||||
dhclient)
|
||||
ip netns exec "$NSPID" "$DHCP_CLIENT" "$CONTAINER_IFNAME" \
|
||||
-pf "/var/run/dhclient.$GUESTNAME.pid" \
|
||||
-lf "/etc/dhclient/dhclient.$GUESTNAME.leases" \
|
||||
$DHCP_OPTIONS
|
||||
# kill dhclient after get ip address to prevent device be used after container close
|
||||
[ ! "$DHCP_FOREGROUND" ] && {
|
||||
kill "$(cat "/var/run/dhclient.$GUESTNAME.pid")"
|
||||
rm "/var/run/dhclient.$GUESTNAME.pid"
|
||||
}
|
||||
;;
|
||||
dhcpcd)
|
||||
ip netns exec "$NSPID" "$DHCP_CLIENT" -q "$CONTAINER_IFNAME" -h "$GUESTNAME"
|
||||
;;
|
||||
"")
|
||||
if installed ipcalc; then
|
||||
eval "$(ipcalc -b $IPADDR)"
|
||||
ip netns exec "$NSPID" ip addr add "$IPADDR" brd "$BROADCAST" dev "$CONTAINER_IFNAME"
|
||||
else
|
||||
ip netns exec "$NSPID" ip addr add "$IPADDR" dev "$CONTAINER_IFNAME"
|
||||
fi
|
||||
|
||||
[ "$GATEWAY" ] && {
|
||||
ip netns exec "$NSPID" ip route delete default >/dev/null 2>&1 && true
|
||||
}
|
||||
ip netns exec "$NSPID" ip link set "$CONTAINER_IFNAME" up
|
||||
[ "$GATEWAY" ] && {
|
||||
ip netns exec "$NSPID" ip route get "$GATEWAY" >/dev/null 2>&1 || \
|
||||
ip netns exec "$NSPID" ip route add "$GATEWAY/32" dev "$CONTAINER_IFNAME"
|
||||
ip netns exec "$NSPID" ip route replace default via "$GATEWAY"
|
||||
}
|
||||
;;
|
||||
esac
|
||||
|
||||
# Give our ARP neighbors a nudge about the new interface
|
||||
if installed arping; then
|
||||
IPADDR=$(echo "$IPADDR" | cut -d/ -f1)
|
||||
ip netns exec "$NSPID" arping -c 1 -A -I "$CONTAINER_IFNAME" "$IPADDR" > /dev/null 2>&1 || true
|
||||
else
|
||||
echo "Warning: arping not found; interface may not be immediately reachable"
|
||||
fi
|
||||
fi
|
||||
# Remove NSPID to avoid `ip netns` catch it.
|
||||
rm -f "/var/run/netns/$NSPID"
|
||||
|
||||
# vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab :
|
26
spec/Vagrantfile
vendored
Normal file
26
spec/Vagrantfile
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
Vagrant.require_plugin 'vagrant-lxc'
|
||||
Vagrant.require_plugin 'vagrant-cachier'
|
||||
|
||||
ENV['BOX_NAME'] ||= 'quantal64'
|
||||
puts "Running vagrant commands using #{ENV['BOX_NAME']} box"
|
||||
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = ENV['BOX_NAME']
|
||||
config.vm.hostname = 'lxc-test-box'
|
||||
config.vm.box_url = ENV['BOX_URL']
|
||||
config.vm.network :forwarded_port, guest: 80, host: 8080
|
||||
|
||||
config.cache.auto_detect = true
|
||||
|
||||
config.vm.provision :shell,
|
||||
inline: 'mkdir -p /vagrant/tmp && echo -n "Provisioned" > /vagrant/tmp/provisioning'
|
||||
|
||||
config.vm.provision :shell,
|
||||
inline: 'apt-get install apache2 -y'
|
||||
|
||||
config.vm.provision :shell, privileged: false,
|
||||
inline: "if ! [ -f $HOME/original-box ]; then echo '#{ENV['BOX_NAME']}' > $HOME/original-box; fi"
|
||||
end
|
4
spec/fixtures/sample-arp-output
vendored
4
spec/fixtures/sample-arp-output
vendored
|
@ -1,4 +0,0 @@
|
|||
Address HWtype HWaddress Flags Mask Iface
|
||||
120.0.3.30 ether 10:16:3e:c8:f9:b7 C lxcbr0
|
||||
10.0.3.30 ether 00:16:3e:64:d6:74 C lxcbr0
|
||||
192.168.25.1 ether 2c:e4:12:95:90:45 C wlan0
|
47
spec/fixtures/sample-config
vendored
47
spec/fixtures/sample-config
vendored
|
@ -1,47 +0,0 @@
|
|||
lxc.network.type=veth
|
||||
lxc.network.link=lxcbr0
|
||||
lxc.network.flags=up
|
||||
lxc.network.hwaddr = 00:16:3e:64:d6:74
|
||||
lxc.rootfs = /var/lib/lxc/a91df47bfc6e/rootfs
|
||||
lxc.utsname = a91df47bfc6e
|
||||
|
||||
lxc.devttydir = lxc
|
||||
lxc.tty = 4
|
||||
lxc.pts = 1024
|
||||
lxc.mount = /var/lib/lxc/a91df47bfc6e/fstab
|
||||
lxc.arch = amd64
|
||||
lxc.cap.drop = sys_module mac_admin mac_override
|
||||
lxc.pivotdir = lxc_putold
|
||||
|
||||
# uncomment the next line to run the container unconfined:
|
||||
#lxc.aa_profile = unconfined
|
||||
|
||||
lxc.cgroup.devices.deny = a
|
||||
# Allow any mknod (but not using the node)
|
||||
lxc.cgroup.devices.allow = c *:* m
|
||||
lxc.cgroup.devices.allow = b *:* m
|
||||
# /dev/null and zero
|
||||
lxc.cgroup.devices.allow = c 1:3 rwm
|
||||
lxc.cgroup.devices.allow = c 1:5 rwm
|
||||
# consoles
|
||||
lxc.cgroup.devices.allow = c 5:1 rwm
|
||||
lxc.cgroup.devices.allow = c 5:0 rwm
|
||||
#lxc.cgroup.devices.allow = c 4:0 rwm
|
||||
#lxc.cgroup.devices.allow = c 4:1 rwm
|
||||
# /dev/{,u}random
|
||||
lxc.cgroup.devices.allow = c 1:9 rwm
|
||||
lxc.cgroup.devices.allow = c 1:8 rwm
|
||||
lxc.cgroup.devices.allow = c 136:* rwm
|
||||
lxc.cgroup.devices.allow = c 5:2 rwm
|
||||
# rtc
|
||||
lxc.cgroup.devices.allow = c 254:0 rwm
|
||||
#fuse
|
||||
lxc.cgroup.devices.allow = c 10:229 rwm
|
||||
#tun
|
||||
lxc.cgroup.devices.allow = c 10:200 rwm
|
||||
#full
|
||||
lxc.cgroup.devices.allow = c 1:7 rwm
|
||||
#hpet
|
||||
lxc.cgroup.devices.allow = c 10:228 rwm
|
||||
#kvm
|
||||
lxc.cgroup.devices.allow = c 10:232 rwm
|
2
spec/fixtures/sample-ip-addr-output
vendored
Normal file
2
spec/fixtures/sample-ip-addr-output
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
49: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
|
||||
inet 10.0.254.137/24 brd 10.0.254.255 scope global eth0
|
|
@ -1,24 +1,19 @@
|
|||
if ENV['COVERAGE']
|
||||
require 'simplecov'
|
||||
SimpleCov.start do
|
||||
# This can probably go away once we stop using vagrant as submodule
|
||||
add_filter { |source_file| source_file.filename =~ /\/vagrant\/plugins\// }
|
||||
add_filter { |source_file| source_file.filename =~ /\/vagrant\/lib\/vagrant(\/|\.rb)/ }
|
||||
add_filter { |source_file| source_file.filename =~ /\/spec\/support/ }
|
||||
end
|
||||
require 'coveralls'
|
||||
|
||||
SimpleCov.start { add_filter '/spec/' }
|
||||
SimpleCov.merge_timeout 300
|
||||
end
|
||||
|
||||
require 'bundler'
|
||||
require 'bundler/setup'
|
||||
|
||||
require 'rspec-spies'
|
||||
require 'i18n'
|
||||
|
||||
require 'vagrant-lxc'
|
||||
|
||||
Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each { |f| require f }
|
||||
|
||||
require 'rspec/fire'
|
||||
RSpec::Fire.configure do |config|
|
||||
config.verify_constant_names = ENV['VERIFY_CONSTANT_NAMES'] == '1'
|
||||
end
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.treat_symbols_as_metadata_keys_with_true_values = true
|
||||
config.run_all_when_everything_filtered = true
|
||||
|
@ -29,4 +24,12 @@ RSpec.configure do |config|
|
|||
# the seed, which is printed after each run.
|
||||
# --seed 1234
|
||||
config.order = 'random'
|
||||
|
||||
config.mock_with :rspec do |c|
|
||||
c.yield_receiver_to_any_instance_implementation_blocks = true
|
||||
end
|
||||
config.expect_with :rspec do |c|
|
||||
c.syntax = :expect
|
||||
end
|
||||
config.raise_errors_for_deprecations!
|
||||
end
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
module UnitExampleGroup
|
||||
def self.included(base)
|
||||
base.metadata[:type] = :unit
|
||||
base.before do
|
||||
Object.any_instance.stub(:system) { |*args, &block|
|
||||
UnitExampleGroup.prevent_system_calls(*args, &block)
|
||||
}
|
||||
Object.any_instance.stub(:`) { |*args, &block|
|
||||
UnitExampleGroup.prevent_system_calls(*args, &block)
|
||||
}
|
||||
require 'vagrant/util/subprocess'
|
||||
Vagrant::Util::Subprocess.stub(:execute) { |*args, &block|
|
||||
UnitExampleGroup.prevent_system_calls(*args, &block)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def self.prevent_system_calls(*args, &block)
|
||||
args.pop if args.last.is_a?(Hash)
|
||||
|
||||
raise <<-MSG
|
||||
Somehow your code under test is trying to execute a command on your system,
|
||||
please stub it out or move your spec code to an acceptance spec.
|
||||
|
||||
Command: "#{args.join(' ')}"
|
||||
MSG
|
||||
end
|
||||
end
|
43
spec/unit/action/clear_forwarded_ports_spec.rb
Normal file
43
spec/unit/action/clear_forwarded_ports_spec.rb
Normal file
|
@ -0,0 +1,43 @@
|
|||
require 'unit_helper'
|
||||
|
||||
require 'tmpdir'
|
||||
require 'vagrant-lxc/action/clear_forwarded_ports'
|
||||
|
||||
describe Vagrant::LXC::Action::ClearForwardedPorts do
|
||||
let(:app) { double(:app, call: true) }
|
||||
let(:env) { {machine: machine, ui: double(info: true)} }
|
||||
let(:machine) { double(:machine, data_dir: data_dir) }
|
||||
let!(:data_dir) { Pathname.new(Dir.mktmpdir) }
|
||||
let(:pids_dir) { data_dir.join('pids') }
|
||||
let(:pid) { 'a-pid' }
|
||||
let(:pid_cmd) { 'redir' }
|
||||
|
||||
subject { described_class.new(app, env) }
|
||||
|
||||
before do
|
||||
pids_dir.mkdir
|
||||
pids_dir.join('redir_1234.pid').open('w') { |f| f.write(pid) }
|
||||
subject.stub(system: true, :` => pid_cmd)
|
||||
subject.call(env)
|
||||
end
|
||||
|
||||
after { FileUtils.rm_rf data_dir.to_s }
|
||||
|
||||
it 'removes all files under pid directory' do
|
||||
expect(Dir[pids_dir.to_s + "/redir_*.pid"]).to be_empty
|
||||
end
|
||||
|
||||
context 'with a valid redir pid' do
|
||||
it 'kills known processes' do
|
||||
expect(subject).to have_received(:system).with("pkill -TERM -P #{pid}")
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an invalid pid' do
|
||||
let(:pid_cmd) { 'sudo ls' }
|
||||
|
||||
it 'does not kill the process' do
|
||||
expect(subject).not_to have_received(:system).with("pkill -TERM -P #{pid}")
|
||||
end
|
||||
end
|
||||
end
|
29
spec/unit/action/compress_rootfs_spec.rb
Normal file
29
spec/unit/action/compress_rootfs_spec.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
require 'unit_helper'
|
||||
|
||||
require 'vagrant-lxc/plugin'
|
||||
require 'vagrant-lxc/provider'
|
||||
require 'vagrant-lxc/action/compress_rootfs'
|
||||
|
||||
describe Vagrant::LXC::Action::CompressRootFS do
|
||||
let(:app) { double(:app, call: true) }
|
||||
let(:env) { {machine: machine, ui: double(info: true)} }
|
||||
let(:machine) { double(Vagrant::Machine, provider: provider) }
|
||||
let(:provider) { double(Vagrant::LXC::Provider, driver: driver) }
|
||||
let(:driver) { double(Vagrant::LXC::Driver, compress_rootfs: compressed_rootfs_path) }
|
||||
let(:compressed_rootfs_path) { '/path/to/rootfs.tar.gz' }
|
||||
|
||||
subject { described_class.new(app, env) }
|
||||
|
||||
before do
|
||||
provider.stub_chain(:state, :id).and_return(:stopped)
|
||||
subject.call(env)
|
||||
end
|
||||
|
||||
it "asks the driver to compress container's rootfs" do
|
||||
expect(driver).to have_received(:compress_rootfs)
|
||||
end
|
||||
|
||||
it 'sets export.temp_dir on action env' do
|
||||
expect(env['package.rootfs']).to eq(compressed_rootfs_path)
|
||||
end
|
||||
end
|
117
spec/unit/action/forward_ports_spec.rb
Normal file
117
spec/unit/action/forward_ports_spec.rb
Normal file
|
@ -0,0 +1,117 @@
|
|||
require 'unit_helper'
|
||||
|
||||
require 'tmpdir'
|
||||
require 'vagrant-lxc/provider'
|
||||
require 'vagrant-lxc/action/forward_ports'
|
||||
|
||||
describe Vagrant::LXC::Action::ForwardPorts do
|
||||
let(:app) { double(:app, call: true) }
|
||||
let(:env) { {machine: machine, ui: double(info: true, warn: true)} }
|
||||
let(:machine) { double(:machine) }
|
||||
let!(:data_dir) { Pathname.new(Dir.mktmpdir) }
|
||||
let(:provider) { double(Vagrant::LXC::Provider, ssh_info: {host: container_ip}) }
|
||||
let(:host_ip) { '127.0.0.1' }
|
||||
let(:host_port) { 8080 }
|
||||
let(:guest_port) { 80 }
|
||||
let(:container_ip) { '10.0.1.234' }
|
||||
let(:pid) { 'a-pid' }
|
||||
let(:forward_conf) { {guest: guest_port, host: host_port, host_ip: host_ip} }
|
||||
let(:networks) { [[:other_config, {}], [:forwarded_port, forward_conf]] }
|
||||
|
||||
subject { described_class.new(app, env) }
|
||||
|
||||
before do
|
||||
machine.stub_chain(:config, :vm, :networks).and_return(networks)
|
||||
machine.stub(provider: provider, data_dir: data_dir)
|
||||
|
||||
subject.stub(redir_version: 3)
|
||||
subject.stub(exec: true)
|
||||
subject.stub(spawn: pid)
|
||||
end
|
||||
|
||||
after { FileUtils.rm_rf data_dir.to_s }
|
||||
|
||||
it 'forwards ports using redir' do
|
||||
subject.stub(system: true)
|
||||
subject.call(env)
|
||||
expect(subject).to have_received(:spawn).with(
|
||||
"redir -n #{host_ip}:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null"
|
||||
)
|
||||
end
|
||||
|
||||
it 'Uses 127.0.0.1 as default if host_ip is nil' do
|
||||
forward_conf.delete(:host_ip)
|
||||
subject.stub(system: true)
|
||||
subject.call(env)
|
||||
expect(subject).to have_received(:spawn).with(
|
||||
"redir -n 127.0.0.1:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null"
|
||||
)
|
||||
end
|
||||
|
||||
it 'Uses 127.0.0.1 by default if host_ip is a blank string' do
|
||||
forward_conf[:host_ip] = ' '
|
||||
subject.stub(system: true)
|
||||
subject.call(env)
|
||||
expect(subject).to have_received(:spawn).with(
|
||||
"redir -n 127.0.0.1:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null"
|
||||
)
|
||||
end
|
||||
|
||||
it "stores redir pids on machine's data dir" do
|
||||
subject.stub(system: true)
|
||||
subject.call(env)
|
||||
pid_file = data_dir.join('pids', "redir_#{host_port}.pid").read
|
||||
expect(pid_file).to eq(pid)
|
||||
end
|
||||
|
||||
it 'allows disabling a previously forwarded port' do
|
||||
forward_conf[:disabled] = true
|
||||
subject.stub(system: true)
|
||||
subject.call(env)
|
||||
expect(subject).not_to have_received(:spawn)
|
||||
end
|
||||
|
||||
it 'uses redir 2.x command line interface' do
|
||||
subject.stub(system: true)
|
||||
subject.stub(redir_version: 2)
|
||||
subject.call(env)
|
||||
expect(subject).to have_received(:spawn).with(
|
||||
"redir --laddr=#{host_ip} --lport=#{host_port} --caddr=#{container_ip} --cport=#{guest_port} 2>/dev/null"
|
||||
)
|
||||
end
|
||||
|
||||
it 'raises RedirNotInstalled error if `redir` is not installed' do
|
||||
subject.stub(system: false)
|
||||
expect { subject.call(env) }.to raise_error(Vagrant::LXC::Errors::RedirNotInstalled)
|
||||
end
|
||||
|
||||
context 'when a privileged port is used' do
|
||||
let(:host_port) { 80 }
|
||||
|
||||
it 'forwards ports using redir' do
|
||||
subject.stub(system: true)
|
||||
subject.call(env)
|
||||
expect(subject).to have_received(:spawn).with(
|
||||
"sudo redir -n #{host_ip}:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null"
|
||||
)
|
||||
end
|
||||
|
||||
it 'Uses 127.0.0.1 by default if host_ip is nil' do
|
||||
forward_conf.delete(:host_ip)
|
||||
subject.stub(system: true)
|
||||
subject.call(env)
|
||||
expect(subject).to have_received(:spawn).with(
|
||||
"sudo redir -n 127.0.0.1:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null"
|
||||
)
|
||||
end
|
||||
|
||||
it 'Uses 127.0.0.1 by default if host_ip is a blank string' do
|
||||
forward_conf[:host_ip] = ' '
|
||||
subject.stub(system: true)
|
||||
subject.call(env)
|
||||
expect(subject).to have_received(:spawn).with(
|
||||
"sudo redir -n 127.0.0.1:#{host_port} #{container_ip}:#{guest_port} 2>/dev/null"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,44 +1,126 @@
|
|||
require 'unit_helper'
|
||||
|
||||
require 'vagrant-lxc/action/base_action'
|
||||
require 'vagrant'
|
||||
require 'vagrant-lxc/errors'
|
||||
require 'vagrant-lxc/action/handle_box_metadata'
|
||||
|
||||
describe Vagrant::LXC::Action::HandleBoxMetadata do
|
||||
let(:metadata) { {'template-opts' => {'--foo' => 'bar'}} }
|
||||
let(:box) { mock(:box, name: 'box-name', metadata: metadata, directory: box_directory) }
|
||||
let(:app) { double(:app, call: true) }
|
||||
let(:env) { {machine: machine, ui: double(info: true, warn: true)} }
|
||||
let(:machine) { double(:machine, box: box) }
|
||||
let(:box) { double(:box, name: 'box-name', metadata: metadata, directory: box_directory) }
|
||||
let(:box_directory) { Pathname.new('/path/to/box') }
|
||||
let(:machine) { mock(:machine, box: box) }
|
||||
let(:app) { mock(:app, call: true) }
|
||||
let(:env) { {machine: machine, ui: stub(info: true)} }
|
||||
let(:tmpdir) { '/tmp/rootfs/dir' }
|
||||
let(:version) { '2' }
|
||||
let(:metadata) { {'template-opts' => {'--foo' => 'bar'}, 'version' => version} }
|
||||
let(:vagrant_key) { Vagrant.source_root.join('keys', 'vagrant.pub').expand_path.to_s }
|
||||
|
||||
subject { described_class.new(app, env) }
|
||||
|
||||
before do
|
||||
Dir.stub(mktmpdir: tmpdir)
|
||||
File.stub(exists?: true)
|
||||
subject.stub(:system)
|
||||
subject.call(env)
|
||||
context 'with 1.0.0 box' do
|
||||
let(:version) { '1.0.0' }
|
||||
|
||||
before do
|
||||
File.stub(exists?: true)
|
||||
# REFACTOR: This is pretty bad
|
||||
subject.stub_chain(:template_config_file, :exist?).and_return(true)
|
||||
subject.stub_chain(:template_config_file, :to_s).and_return(box_directory.join('lxc-config').to_s)
|
||||
subject.call(env)
|
||||
end
|
||||
|
||||
it 'sets the tarball argument for the template' do
|
||||
expect(env[:lxc_template_opts]).to include(
|
||||
'--tarball' => box_directory.join('rootfs.tar.gz').to_s
|
||||
)
|
||||
end
|
||||
|
||||
it 'sets the template --config parameter' do
|
||||
expect(env[:lxc_template_opts]).to include(
|
||||
'--config' => box_directory.join('lxc-config').to_s
|
||||
)
|
||||
end
|
||||
|
||||
it 'does not set the auth key argument for the template' do
|
||||
expect(env[:lxc_template_opts]).not_to include(
|
||||
'--auth-key' => vagrant_key
|
||||
)
|
||||
end
|
||||
|
||||
it 'sets the template options from metadata on env hash' do
|
||||
expect(env[:lxc_template_opts]).to include(metadata['template-opts'])
|
||||
end
|
||||
|
||||
xit 'sets the template source path on env hash' do
|
||||
expect(env[:lxc_template_src]).to eq(box_directory.join('lxc-template').to_s)
|
||||
end
|
||||
|
||||
it 'does not warn about deprecation' do
|
||||
expect(env[:ui]).not_to have_received(:warn)
|
||||
end
|
||||
end
|
||||
|
||||
it 'creates a tmp directory to store rootfs-cache-path' do
|
||||
metadata['rootfs-cache-path'].should == tmpdir
|
||||
context 'with valid pre 1.0.0 box' do
|
||||
before do
|
||||
File.stub(exists?: true)
|
||||
# REFACTOR: This is pretty bad
|
||||
subject.stub_chain(:old_template_config_file, :exist?).and_return(true)
|
||||
subject.stub_chain(:old_template_config_file, :to_s).and_return(box_directory.join('lxc.conf').to_s)
|
||||
subject.call(env)
|
||||
end
|
||||
|
||||
it 'sets the tarball argument for the template' do
|
||||
expect(env[:lxc_template_opts]).to include(
|
||||
'--tarball' => box_directory.join('rootfs.tar.gz').to_s
|
||||
)
|
||||
end
|
||||
|
||||
it 'sets the auth key argument for the template' do
|
||||
expect(env[:lxc_template_opts]).to include(
|
||||
'--auth-key' => vagrant_key
|
||||
)
|
||||
end
|
||||
|
||||
it 'sets the lxc config file parameter' do
|
||||
expect(env[:lxc_template_config]).to eq(box_directory.join('lxc.conf').to_s)
|
||||
end
|
||||
|
||||
it 'sets the template options from metadata on env hash' do
|
||||
expect(env[:lxc_template_opts]).to include(metadata['template-opts'])
|
||||
end
|
||||
|
||||
xit 'sets the template source path on env hash' do
|
||||
expect(env[:lxc_template_src]).to eq(box_directory.join('lxc-template').to_s)
|
||||
end
|
||||
|
||||
it 'warns about deprecation' do
|
||||
expect(env[:ui]).to have_received(:warn)
|
||||
end
|
||||
end
|
||||
|
||||
it 'prepends vagrant and box name to template-name' do
|
||||
metadata['template-name'].should == "vagrant-#{box.name}"
|
||||
end
|
||||
describe 'with invalid contents' do
|
||||
before { File.stub(exists?: true) }
|
||||
|
||||
it 'copies box template file to the right folder' do
|
||||
src = box_directory.join('lxc-template').to_s
|
||||
dest = "/usr/share/lxc/templates/lxc-#{metadata['template-name']}"
|
||||
it 'validates box versions' do
|
||||
%w( 2 3 1.0.0 ).each do |v|
|
||||
metadata['version'] = v
|
||||
expect { subject.call(env) }.to_not raise_error
|
||||
end
|
||||
|
||||
subject.should have_received(:system).
|
||||
with("sudo su root -c \"cp #{src} #{dest}\"")
|
||||
end
|
||||
metadata['version'] = '1'
|
||||
expect { subject.call(env) }.to raise_error
|
||||
end
|
||||
|
||||
it 'extracts rootfs into a tmp folder' do
|
||||
subject.should have_received(:system).
|
||||
with(%Q[sudo su root -c "cd #{box_directory} && tar xfz rootfs.tar.gz -C #{tmpdir}"])
|
||||
it 'raises an error if the rootfs tarball cant be found' do
|
||||
allow(File).to receive(:exists?).with(box_directory.join('rootfs.tar.gz').to_s).and_return(false)
|
||||
expect {
|
||||
subject.call(env)
|
||||
}.to raise_error(Vagrant::LXC::Errors::RootFSTarballMissing)
|
||||
end
|
||||
|
||||
it 'does not raise an error if the lxc-template script cant be found' do
|
||||
allow(File).to receive(:exists?).with(box_directory.join('lxc-template').to_s).and_return(false)
|
||||
expect {
|
||||
subject.call(env)
|
||||
}.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
83
spec/unit/action/setup_package_files_spec.rb
Normal file
83
spec/unit/action/setup_package_files_spec.rb
Normal file
|
@ -0,0 +1,83 @@
|
|||
require 'unit_helper'
|
||||
|
||||
require 'vagrant-lxc/action/setup_package_files'
|
||||
|
||||
describe Vagrant::LXC::Action::SetupPackageFiles do
|
||||
let(:app) { double(:app, call: true) }
|
||||
let(:env) { {machine: machine, tmp_path: tmp_path, ui: double(info: true), 'package.rootfs' => rootfs_path} }
|
||||
let(:machine) { double(Vagrant::Machine, box: box) }
|
||||
let!(:tmp_path) { Pathname.new(Dir.mktmpdir) }
|
||||
let(:box) { double(Vagrant::Box, directory: tmp_path.join('box')) }
|
||||
let(:rootfs_path) { tmp_path.join('rootfs-amd64.tar.gz') }
|
||||
|
||||
subject { described_class.new(app, env) }
|
||||
|
||||
before do
|
||||
box.directory.mkdir
|
||||
files = %w( lxc-template metadata.json lxc.conf lxc-config ).map { |f| box.directory.join(f) }
|
||||
(files + [rootfs_path]).each do |file|
|
||||
file.open('w') { |f| f.puts file.to_s }
|
||||
end
|
||||
|
||||
subject.stub(recover: true) # Prevents files from being removed on specs
|
||||
end
|
||||
|
||||
after do
|
||||
FileUtils.rm_rf(tmp_path.to_s)
|
||||
end
|
||||
|
||||
context 'when all files exist' do
|
||||
before { subject.call(env) }
|
||||
|
||||
it 'copies box lxc-template to package directory' do
|
||||
expect(env['package.directory'].join('lxc-template')).to be_file
|
||||
end
|
||||
|
||||
it 'copies metadata.json to package directory' do
|
||||
expect(env['package.directory'].join('metadata.json')).to be_file
|
||||
end
|
||||
|
||||
it 'copies box lxc.conf to package directory' do
|
||||
expect(env['package.directory'].join('lxc-template')).to be_file
|
||||
end
|
||||
|
||||
it 'copies box lxc-config to package directory' do
|
||||
expect(env['package.directory'].join('lxc-config')).to be_file
|
||||
end
|
||||
|
||||
it 'moves the compressed rootfs to package directory' do
|
||||
expect(env['package.directory'].join(rootfs_path.basename)).to be_file
|
||||
expect(env['package.rootfs']).not_to be_file
|
||||
end
|
||||
end
|
||||
|
||||
context 'when lxc-template file is not present' do
|
||||
before do
|
||||
box.directory.join('lxc-template').delete
|
||||
end
|
||||
|
||||
it 'does not blow up' do
|
||||
expect { subject.call(env) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'when lxc.conf file is not present' do
|
||||
before do
|
||||
box.directory.join('lxc.conf').delete
|
||||
end
|
||||
|
||||
it 'does not blow up' do
|
||||
expect { subject.call(env) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'when lxc-config file is not present' do
|
||||
before do
|
||||
box.directory.join('lxc-config').delete
|
||||
end
|
||||
|
||||
it 'does not blow up' do
|
||||
expect { subject.call(env) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,148 +0,0 @@
|
|||
require 'unit_helper'
|
||||
|
||||
require "vendored_vagrant"
|
||||
require 'vagrant-lxc/container/cli'
|
||||
|
||||
describe Vagrant::LXC::Container::CLI do
|
||||
describe 'list' do
|
||||
let(:lxc_ls_out) { "dup-container\na-container dup-container" }
|
||||
let(:exec_args) { @exec_args }
|
||||
let(:result) { @result }
|
||||
|
||||
before do
|
||||
subject.stub(:run).with(:ls).and_return(lxc_ls_out)
|
||||
@result = subject.list
|
||||
end
|
||||
|
||||
it 'grabs previously created containers from lxc-ls output' do
|
||||
result.should be_an Enumerable
|
||||
result.should include 'a-container'
|
||||
result.should include 'dup-container'
|
||||
end
|
||||
|
||||
it 'removes duplicates from lxc-ls output' do
|
||||
result.uniq.should == result
|
||||
end
|
||||
end
|
||||
|
||||
describe 'create' do
|
||||
let(:template) { 'quantal-64' }
|
||||
let(:name) { 'quantal-container' }
|
||||
let(:template_args) { { '--extra-param' => 'param', '--other' => 'value' } }
|
||||
|
||||
subject { described_class.new(name) }
|
||||
|
||||
before do
|
||||
subject.stub(:run)
|
||||
subject.create(template, template_args)
|
||||
end
|
||||
|
||||
it 'issues a lxc-create with provided template, container name and hash of arguments' do
|
||||
subject.should have_received(:run).with(
|
||||
:create,
|
||||
'--template', template,
|
||||
'--name', name,
|
||||
'--',
|
||||
'--extra-param', 'param',
|
||||
'--other', 'value'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'destroy' do
|
||||
let(:name) { 'a-container-for-destruction' }
|
||||
|
||||
subject { described_class.new(name) }
|
||||
|
||||
before do
|
||||
subject.stub(:run)
|
||||
subject.destroy
|
||||
end
|
||||
|
||||
it 'issues a lxc-destroy with container name' do
|
||||
subject.should have_received(:run).with(:destroy, '--name', name)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'start' do
|
||||
let(:name) { 'a-container' }
|
||||
subject { described_class.new(name) }
|
||||
|
||||
before do
|
||||
subject.stub(:run)
|
||||
end
|
||||
|
||||
it 'starts container on the background' do
|
||||
subject.start
|
||||
subject.should have_received(:run).with(
|
||||
:start,
|
||||
'-d',
|
||||
'--name', name
|
||||
)
|
||||
end
|
||||
|
||||
it 'uses provided hash to configure the container' do
|
||||
subject.start(['lxc.config=value', 'lxc.other=value'])
|
||||
subject.should have_received(:run).with(:start, '-d', '--name', name,
|
||||
'-s', 'lxc.config=value',
|
||||
'-s', 'lxc.other=value'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'shutdown' do
|
||||
let(:name) { 'a-running-container' }
|
||||
subject { described_class.new(name) }
|
||||
|
||||
before do
|
||||
subject.stub(:run)
|
||||
subject.shutdown
|
||||
end
|
||||
|
||||
it 'issues a lxc-shutdown with provided container name' do
|
||||
subject.should have_received(:run).with(:shutdown, '--name', name)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'state' do
|
||||
let(:name) { 'a-container' }
|
||||
subject { described_class.new(name) }
|
||||
|
||||
before do
|
||||
subject.stub(:run).and_return("state: STOPPED\npid: 2")
|
||||
end
|
||||
|
||||
it 'calls lxc-info with the right arguments' do
|
||||
subject.state
|
||||
subject.should have_received(:run).with(:info, '--name', name)
|
||||
end
|
||||
|
||||
it 'maps the output of lxc-info status out to a symbol' do
|
||||
subject.state.should == :stopped
|
||||
end
|
||||
end
|
||||
|
||||
describe 'transition block' do
|
||||
let(:name) { 'a-running-container' }
|
||||
subject { described_class.new(name) }
|
||||
|
||||
before { subject.stub(:run) }
|
||||
|
||||
it 'yields cli object' do
|
||||
subject.stub(:shutdown)
|
||||
subject.transition_to(:stopped) { |c| c.shutdown }
|
||||
subject.should have_received(:shutdown)
|
||||
end
|
||||
|
||||
it 'throws an exception if block is not provided' do
|
||||
expect {
|
||||
subject.transition_to(:running)
|
||||
}.to raise_error(described_class::TransitionBlockNotProvided)
|
||||
end
|
||||
|
||||
it 'waits for the expected container state using lxc-wait' do
|
||||
subject.transition_to(:running) { }
|
||||
subject.should have_received(:run).with(:wait, '--name', name, '--state', 'RUNNING')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,151 +0,0 @@
|
|||
require 'unit_helper'
|
||||
|
||||
require "vendored_vagrant"
|
||||
require 'vagrant-lxc/container'
|
||||
|
||||
describe Vagrant::LXC::Container do
|
||||
let(:name) { nil }
|
||||
subject { described_class.new(name) }
|
||||
|
||||
describe 'container name validation' do
|
||||
let(:unknown_container) { described_class.new('unknown', cli) }
|
||||
let(:valid_container) { described_class.new('valid', cli) }
|
||||
let(:new_container) { described_class.new(nil) }
|
||||
let(:cli) { fire_double('Vagrant::LXC::Container::CLI', list: ['valid']) }
|
||||
|
||||
it 'raises a NotFound error if an unknown container name gets provided' do
|
||||
expect {
|
||||
unknown_container.validate!
|
||||
}.to raise_error(Vagrant::LXC::Container::NotFound)
|
||||
end
|
||||
|
||||
it 'does not raise a NotFound error if a valid container name gets provided' do
|
||||
expect {
|
||||
valid_container.validate!
|
||||
}.to_not raise_error(Vagrant::LXC::Container::NotFound)
|
||||
end
|
||||
|
||||
it 'does not raise a NotFound error if nil is provider as name' do
|
||||
expect {
|
||||
new_container.validate!
|
||||
}.to_not raise_error(Vagrant::LXC::Container::NotFound)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'creation' do
|
||||
let(:name) { 'random-container-name' }
|
||||
let(:template_name) { 'template-name' }
|
||||
let(:rootfs_cache) { '/path/to/cache' }
|
||||
let(:public_key_path) { Vagrant.source_root.join('keys', 'vagrant.pub').expand_path.to_s }
|
||||
let(:cli) { fire_double('Vagrant::LXC::Container::CLI', :create => true, :name= => true) }
|
||||
|
||||
subject { described_class.new(name, cli) }
|
||||
|
||||
before do
|
||||
SecureRandom.stub(hex: name)
|
||||
subject.create 'template-name' => template_name, 'rootfs-cache-path' => rootfs_cache, 'template-opts' => { '--foo' => 'bar'}
|
||||
end
|
||||
|
||||
it 'creates container with the right arguments' do
|
||||
cli.should have_received(:create).with(
|
||||
template_name,
|
||||
'--auth-key' => public_key_path,
|
||||
'--cache' => rootfs_cache,
|
||||
'--foo' => 'bar'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'destruction' do
|
||||
let(:name) { 'container-name' }
|
||||
let(:cli) { fire_double('Vagrant::LXC::Container::CLI', destroy: true) }
|
||||
|
||||
subject { described_class.new(name, cli) }
|
||||
|
||||
before { subject.destroy }
|
||||
|
||||
it 'delegates to cli object' do
|
||||
cli.should have_received(:destroy)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'start' do
|
||||
let(:config) { mock(:config, start_opts: ['a=1', 'b=2']) }
|
||||
let(:name) { 'container-name' }
|
||||
let(:cli) { fire_double('Vagrant::LXC::Container::CLI', start: true) }
|
||||
|
||||
subject { described_class.new(name, cli) }
|
||||
|
||||
before do
|
||||
cli.stub(:transition_to).and_yield(cli)
|
||||
end
|
||||
|
||||
it 'starts container with configured lxc settings' do
|
||||
cli.should_receive(:start).with(['a=1', 'b=2'], nil)
|
||||
subject.start(config)
|
||||
end
|
||||
|
||||
it 'expects a transition to running state to take place' do
|
||||
cli.should_receive(:transition_to).with(:running)
|
||||
subject.start(config)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'halt' do
|
||||
let(:name) { 'container-name' }
|
||||
let(:cli) { fire_double('Vagrant::LXC::Container::CLI', shutdown: true) }
|
||||
|
||||
subject { described_class.new(name, cli) }
|
||||
|
||||
before do
|
||||
cli.stub(:transition_to).and_yield(cli)
|
||||
end
|
||||
|
||||
it 'delegates to cli shutdown' do
|
||||
cli.should_receive(:shutdown)
|
||||
subject.halt
|
||||
end
|
||||
|
||||
it 'expects a transition to running state to take place' do
|
||||
cli.should_receive(:transition_to).with(:stopped)
|
||||
subject.halt
|
||||
end
|
||||
end
|
||||
|
||||
describe 'state' do
|
||||
let(:name) { 'random-container-name' }
|
||||
let(:cli_state) { :something }
|
||||
let(:cli) { fire_double('Vagrant::LXC::Container::CLI', state: cli_state) }
|
||||
|
||||
subject { described_class.new(name, cli) }
|
||||
|
||||
it 'delegates to cli' do
|
||||
subject.state.should == cli_state
|
||||
end
|
||||
end
|
||||
|
||||
describe 'assigned ip' do
|
||||
# This ip is set on the sample-arp-output fixture based on mac address from
|
||||
# sample-config fixture
|
||||
let(:ip) { "10.0.3.30" }
|
||||
let(:conf_file_contents) { File.read('spec/fixtures/sample-config') }
|
||||
let(:name) { 'random-container-name' }
|
||||
|
||||
context 'when container mac address gets returned from the first `arp` call' do
|
||||
before do
|
||||
@arp_output = File.read('spec/fixtures/sample-arp-output')
|
||||
subject.stub(:raw) {
|
||||
mock(stdout: "#{@arp_output}\n", exit_code: 0)
|
||||
}
|
||||
File.stub(read: conf_file_contents)
|
||||
end
|
||||
|
||||
it 'gets parsed from `arp` based on lxc mac address' do
|
||||
subject.assigned_ip.should == ip
|
||||
subject.should have_received(:raw).with('arp', '-n')
|
||||
end
|
||||
end
|
||||
|
||||
pending 'when mac address is not returned from an `arp` call'
|
||||
end
|
||||
end
|
209
spec/unit/driver/cli_spec.rb
Normal file
209
spec/unit/driver/cli_spec.rb
Normal file
|
@ -0,0 +1,209 @@
|
|||
require 'unit_helper'
|
||||
|
||||
require 'vagrant-lxc/sudo_wrapper'
|
||||
require 'vagrant-lxc/driver/cli'
|
||||
|
||||
describe Vagrant::LXC::Driver::CLI do
|
||||
let(:sudo_wrapper) { double(Vagrant::LXC::SudoWrapper, run: true, wrapper_path: nil) }
|
||||
|
||||
subject { described_class.new(sudo_wrapper) }
|
||||
|
||||
describe 'list' do
|
||||
let(:lxc_ls_out) { "dup-container\na-container dup-container" }
|
||||
let(:result) { @result }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:run).with(:ls).and_return(lxc_ls_out)
|
||||
@result = subject.list
|
||||
end
|
||||
|
||||
it 'grabs previously created containers from lxc-ls output' do
|
||||
expect(result).to be_an Enumerable
|
||||
expect(result).to include 'a-container'
|
||||
expect(result).to include 'dup-container'
|
||||
end
|
||||
|
||||
it 'removes duplicates from lxc-ls output' do
|
||||
expect(result.uniq).to eq(result)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'version' do
|
||||
before do
|
||||
allow(subject).to receive(:run).with(:create, '--version').and_return(lxc_version_out)
|
||||
end
|
||||
|
||||
describe 'lxc version after 1.x.x' do
|
||||
let(:lxc_version_out) { "1.0.0\n" }
|
||||
|
||||
it 'parses the version from the output' do
|
||||
expect(subject.version).to eq('1.0.0')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'config' do
|
||||
before do
|
||||
allow(subject).to receive(:run).with(:config, 'lxc.lxcpath').and_return(lxc_config_out)
|
||||
allow(subject).to receive(:run).with(:create, '--version').and_return(lxc_version_out)
|
||||
end
|
||||
|
||||
describe 'lxc version after 1.x.x'do
|
||||
let(:lxc_config_out) { "/var/lib/lxc\n" }
|
||||
let(:lxc_version_out) { "1.0.0\n" }
|
||||
|
||||
it 'parser the lxc.lxcpath value' do
|
||||
expect(subject.config('lxc.lxcpath')).not_to end_with("\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'create' do
|
||||
let(:template) { 'quantal-64' }
|
||||
let(:name) { 'quantal-container' }
|
||||
let(:backingstore) { 'btrfs' }
|
||||
let(:backingstore_opts) { [['--dir', '/tmp/foo'], ['--foo', 'bar']] }
|
||||
let(:config_file) { 'config' }
|
||||
let(:template_args) { { '--extra-param' => 'param', '--other' => 'value' } }
|
||||
|
||||
subject { described_class.new(sudo_wrapper, name) }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:run) { |*args| @run_args = args }
|
||||
end
|
||||
|
||||
it 'issues a lxc-create with provided template, container name and hash of arguments' do
|
||||
subject.create(template, backingstore, backingstore_opts, config_file, template_args)
|
||||
expect(subject).to have_received(:run).with(
|
||||
:create,
|
||||
'-B', backingstore,
|
||||
'--template', template,
|
||||
'--name', name,
|
||||
*(backingstore_opts.flatten),
|
||||
'-f', config_file,
|
||||
'--',
|
||||
'--extra-param', 'param',
|
||||
'--other', 'value'
|
||||
)
|
||||
end
|
||||
|
||||
it 'wraps a low level error into something more meaningful in case the container already exists' do
|
||||
allow(subject).to receive(:run) { raise Vagrant::LXC::Errors::ExecuteError, stderr: 'alreAdy Exists' }
|
||||
expect {
|
||||
subject.create(template, backingstore, backingstore_opts, config_file, template_args)
|
||||
}.to raise_error(Vagrant::LXC::Errors::ContainerAlreadyExists)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'destroy' do
|
||||
let(:name) { 'a-container-for-destruction' }
|
||||
|
||||
subject { described_class.new(sudo_wrapper, name) }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:run)
|
||||
subject.destroy
|
||||
end
|
||||
|
||||
it 'issues a lxc-destroy with container name' do
|
||||
expect(subject).to have_received(:run).with(:destroy, '--name', name)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'start' do
|
||||
let(:name) { 'a-container' }
|
||||
subject { described_class.new(sudo_wrapper, name) }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:run)
|
||||
end
|
||||
|
||||
it 'starts container on the background' do
|
||||
subject.start
|
||||
expect(subject).to have_received(:run).with(
|
||||
:start,
|
||||
'-d',
|
||||
'--name', name
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'stop' do
|
||||
let(:name) { 'a-running-container' }
|
||||
subject { described_class.new(sudo_wrapper, name) }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:run)
|
||||
subject.stop
|
||||
end
|
||||
|
||||
it 'issues a lxc-stop with provided container name' do
|
||||
expect(subject).to have_received(:run).with(:stop, '--name', name)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'state' do
|
||||
let(:name) { 'a-container' }
|
||||
subject { described_class.new(sudo_wrapper, name) }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:run).and_return("state: STOPPED\npid: 2")
|
||||
end
|
||||
|
||||
it 'calls lxc-info with the right arguments' do
|
||||
subject.state
|
||||
expect(subject).to have_received(:run).with(:info, '--name', name, retryable: true)
|
||||
end
|
||||
|
||||
it 'maps the output of lxc-info status out to a symbol' do
|
||||
expect(subject.state).to eq(:stopped)
|
||||
end
|
||||
|
||||
it 'is not case sensitive' do
|
||||
allow(subject).to receive(:run).and_return("StatE: STarTED\npid: 2")
|
||||
expect(subject.state).to eq(:started)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'attach' do
|
||||
let(:name) { 'a-running-container' }
|
||||
let(:command) { ['ls', 'cat /tmp/file'] }
|
||||
let(:command_output) { 'folders list' }
|
||||
subject { described_class.new(sudo_wrapper, name) }
|
||||
|
||||
before do
|
||||
subject.stub(run: command_output)
|
||||
end
|
||||
|
||||
it 'calls lxc-attach with specified command' do
|
||||
subject.attach(*command)
|
||||
expect(subject).to have_received(:run).with(:attach, '--name', name, '--', *command)
|
||||
end
|
||||
|
||||
it 'supports a "namespaces" parameter' do
|
||||
allow(subject).to receive(:run).with(:attach, '-h', :show_stderr => true).and_return({:stdout => '', :stderr => '--namespaces'})
|
||||
subject.attach *(command + [{namespaces: ['network', 'mount']}])
|
||||
expect(subject).to have_received(:run).with(:attach, '--name', name, '--namespaces', 'NETWORK|MOUNT', '--', *command)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'transition block' do
|
||||
before do
|
||||
subject.stub(run: true, sleep: true, state: :stopped)
|
||||
end
|
||||
|
||||
it 'yields a cli object' do
|
||||
allow(subject).to receive(:shutdown)
|
||||
subject.transition_to(:stopped) { |c| c.shutdown }
|
||||
expect(subject).to have_received(:shutdown)
|
||||
end
|
||||
|
||||
it 'throws an exception if block is not provided' do
|
||||
expect {
|
||||
subject.transition_to(:running)
|
||||
}.to raise_error(described_class::TransitionBlockNotProvided)
|
||||
end
|
||||
|
||||
skip 'waits for the expected container state'
|
||||
end
|
||||
end
|
257
spec/unit/driver_spec.rb
Normal file
257
spec/unit/driver_spec.rb
Normal file
|
@ -0,0 +1,257 @@
|
|||
require 'unit_helper'
|
||||
|
||||
require 'vagrant-lxc/driver'
|
||||
require 'vagrant-lxc/driver/cli'
|
||||
require 'vagrant-lxc/sudo_wrapper'
|
||||
|
||||
describe Vagrant::LXC::Driver do
|
||||
describe 'container name validation' do
|
||||
let(:unknown_container) { described_class.new('unknown', nil, cli) }
|
||||
let(:valid_container) { described_class.new('valid', nil, cli) }
|
||||
let(:new_container) { described_class.new(nil, nil) }
|
||||
let(:cli) { double(Vagrant::LXC::Driver::CLI, list: ['valid']) }
|
||||
|
||||
it 'raises a ContainerNotFound error if an unknown container name gets provided' do
|
||||
expect {
|
||||
unknown_container.validate!
|
||||
}.to raise_error
|
||||
end
|
||||
|
||||
it 'does not raise a ContainerNotFound error if a valid container name gets provided' do
|
||||
expect {
|
||||
valid_container.validate!
|
||||
}.not_to raise_error
|
||||
end
|
||||
|
||||
it 'does not raise a ContainerNotFound error if nil is provider as name' do
|
||||
expect {
|
||||
new_container.validate!
|
||||
}.not_to raise_error
|
||||
end
|
||||
end
|
||||
|
||||
describe 'creation' do
|
||||
let(:name) { 'container-name' }
|
||||
let(:backingstore) { 'btrfs' }
|
||||
let(:backingstore_opts) { [['--dir', '/tmp/foo'], ['--foo', 'bar']] }
|
||||
let(:template_name) { 'auto-assigned-template-id' }
|
||||
let(:template_path) { '/path/to/lxc-template-from-box' }
|
||||
let(:template_opts) { {'--some' => 'random-option'} }
|
||||
let(:config_file) { '/path/to/lxc-config-from-box' }
|
||||
let(:rootfs_tarball) { '/path/to/cache/rootfs.tar.gz' }
|
||||
let(:cli) { double(Vagrant::LXC::Driver::CLI, :create => true, :name= => true) }
|
||||
|
||||
subject { described_class.new(nil, nil, cli) }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:import_template).and_yield(template_name)
|
||||
subject.create name, backingstore, backingstore_opts, template_path, config_file, template_opts
|
||||
end
|
||||
|
||||
it 'sets the cli object container name' do
|
||||
expect(cli).to have_received(:name=).with(name)
|
||||
end
|
||||
|
||||
it 'creates container with the right arguments' do
|
||||
expect(cli).to have_received(:create).with(
|
||||
template_path,
|
||||
backingstore,
|
||||
backingstore_opts,
|
||||
config_file,
|
||||
template_opts
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'destruction' do
|
||||
let(:cli) { double(Vagrant::LXC::Driver::CLI, destroy: true) }
|
||||
|
||||
subject { described_class.new('name', nil, cli) }
|
||||
|
||||
before { subject.destroy }
|
||||
|
||||
it 'delegates to cli object' do
|
||||
expect(cli).to have_received(:destroy)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'start' do
|
||||
let(:customizations) { [['a', '1'], ['b', '2']] }
|
||||
let(:internal_customization) { ['internal', 'customization'] }
|
||||
let(:cli) { double(Vagrant::LXC::Driver::CLI, start: true) }
|
||||
let(:sudo) { double(Vagrant::LXC::SudoWrapper) }
|
||||
|
||||
subject { described_class.new('name', sudo, cli) }
|
||||
|
||||
before do
|
||||
sudo.should_receive(:run).with('cat', '/var/lib/lxc/name/config').exactly(2).times.
|
||||
and_return('# CONFIGURATION')
|
||||
sudo.should_receive(:run).twice.with('cp', '-f', %r{/(run|tmp)/.*}, '/var/lib/lxc/name/config')
|
||||
sudo.should_receive(:run).twice.with('chown', 'root:root', '/var/lib/lxc/name/config')
|
||||
expect(cli).to receive(:config).with("lxc.lxcpath").and_return("/var/lib/lxc")
|
||||
|
||||
subject.customizations << internal_customization
|
||||
subject.start(customizations)
|
||||
end
|
||||
|
||||
it 'prunes previous customizations before writing'
|
||||
|
||||
it 'writes configurations to config file'
|
||||
|
||||
it 'starts container with configured customizations' do
|
||||
expect(cli).to have_received(:start)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'halt' do
|
||||
let(:cli) { double(Vagrant::LXC::Driver::CLI, stop: true) }
|
||||
|
||||
subject { described_class.new('name', nil, cli) }
|
||||
|
||||
before do
|
||||
allow(cli).to receive(:transition_to).and_yield(cli)
|
||||
end
|
||||
|
||||
it 'delegates to cli stop' do
|
||||
expect(cli).to receive(:stop)
|
||||
subject.forced_halt
|
||||
end
|
||||
|
||||
it 'expects a transition to running state to take place' do
|
||||
expect(cli).to receive(:transition_to).with(:stopped)
|
||||
subject.forced_halt
|
||||
end
|
||||
|
||||
it 'attempts to force the container to stop in case a shutdown doesnt work' do
|
||||
allow(cli).to receive(:shutdown).and_raise(Vagrant::LXC::Driver::CLI::TargetStateNotReached.new :target, :source)
|
||||
expect(cli).to receive(:transition_to).with(:stopped)
|
||||
expect(cli).to receive(:stop)
|
||||
subject.forced_halt
|
||||
end
|
||||
end
|
||||
|
||||
describe 'state' do
|
||||
let(:cli_state) { :something }
|
||||
let(:cli) { double(Vagrant::LXC::Driver::CLI, state: cli_state) }
|
||||
|
||||
subject { described_class.new('name', nil, cli) }
|
||||
|
||||
it 'delegates to cli' do
|
||||
expect(subject.state).to eq(cli_state)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'containers_path' do
|
||||
let(:cli) { double(Vagrant::LXC::Driver::CLI, config: cli_config_value) }
|
||||
|
||||
subject { described_class.new('name', nil, cli) }
|
||||
|
||||
describe 'lxc version after 1.x.x' do
|
||||
let(:cli_config_value) { '/etc/lxc' }
|
||||
|
||||
it 'delegates to cli' do
|
||||
expect(subject.containers_path).to eq(cli_config_value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'folder sharing' do
|
||||
let(:shared_folder) { {guestpath: '/vagrant', hostpath: '/path/to/host/dir'} }
|
||||
let(:ro_rw_folder) { {guestpath: '/vagrant/ro_rw', hostpath: '/path/to/host/dir', mount_options: ['ro', 'rw']} }
|
||||
let(:with_space_folder) { {guestpath: '/tmp/with space', hostpath: '/path/with space'} }
|
||||
let(:folders) { [shared_folder, ro_rw_folder, with_space_folder] }
|
||||
let(:expected_guest_path) { "vagrant" }
|
||||
let(:sudo_wrapper) { double(Vagrant::LXC::SudoWrapper, run: true) }
|
||||
let(:rootfs_path) { Pathname('/path/to/rootfs') }
|
||||
|
||||
subject { described_class.new('name', sudo_wrapper) }
|
||||
|
||||
describe "with fixed rootfs" do
|
||||
before do
|
||||
subject.stub(rootfs_path: Pathname('/path/to/rootfs'), system: true)
|
||||
subject.share_folders(folders)
|
||||
end
|
||||
|
||||
it 'adds a mount.entry to its local customizations' do
|
||||
expect(subject.customizations).to include [
|
||||
'mount.entry',
|
||||
"#{shared_folder[:hostpath]} #{expected_guest_path} none bind,create=dir 0 0"
|
||||
]
|
||||
end
|
||||
|
||||
it 'supports additional mount options' do
|
||||
expect(subject.customizations).to include [
|
||||
'mount.entry',
|
||||
"#{ro_rw_folder[:hostpath]} vagrant/ro_rw none ro,rw 0 0"
|
||||
]
|
||||
end
|
||||
|
||||
it 'supports directories with spaces' do
|
||||
expect(subject.customizations).to include [
|
||||
'mount.entry',
|
||||
"/path/with\\040space tmp/with\\040space none bind,create=dir 0 0"
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
describe "with directory-based LXC config" do
|
||||
let(:config_string) {
|
||||
<<-ENDCONFIG.gsub(/^\s+/, '')
|
||||
# Blah blah comment
|
||||
lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0
|
||||
lxc.mount.entry = sysfs sys sysfs defaults 0 0
|
||||
lxc.tty.max = 4
|
||||
lxc.pty.max = 1024
|
||||
lxc.rootfs.path = #{rootfs_path}
|
||||
# VAGRANT-BEGIN
|
||||
lxc.network.type=veth
|
||||
lxc.network.name=eth1
|
||||
# VAGRANT-END
|
||||
ENDCONFIG
|
||||
}
|
||||
|
||||
before do
|
||||
subject { described_class.new('name', sudo_wrapper) }
|
||||
subject.stub(config_string: config_string)
|
||||
subject.share_folders(folders)
|
||||
end
|
||||
|
||||
it 'adds a mount.entry to its local customizations' do
|
||||
expect(subject.customizations).to include [
|
||||
'mount.entry',
|
||||
"#{shared_folder[:hostpath]} #{expected_guest_path} none bind,create=dir 0 0"
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
describe "with overlayfs-based LXC config" do
|
||||
let(:config_string) {
|
||||
<<-ENDCONFIG.gsub(/^\s+/, '')
|
||||
# Blah blah comment
|
||||
lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0
|
||||
lxc.mount.entry = sysfs sys sysfs defaults 0 0
|
||||
lxc.tty.max = 4
|
||||
lxc.pty.max = 1024
|
||||
lxc.rootfs.path = overlayfs:/path/to/master/directory:#{rootfs_path}
|
||||
# VAGRANT-BEGIN
|
||||
lxc.network.type=veth
|
||||
lxc.network.name=eth1
|
||||
# VAGRANT-END
|
||||
ENDCONFIG
|
||||
}
|
||||
|
||||
before do
|
||||
subject { described_class.new('name', sudo_wrapper) }
|
||||
subject.stub(config_string: config_string)
|
||||
subject.share_folders(folders)
|
||||
end
|
||||
|
||||
it 'adds a mount.entry to its local customizations' do
|
||||
expect(subject.customizations).to include [
|
||||
'mount.entry',
|
||||
"#{shared_folder[:hostpath]} #{expected_guest_path} none bind,create=dir 0 0"
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,39 +0,0 @@
|
|||
require 'unit_helper'
|
||||
|
||||
require 'vagrant-lxc/machine_state'
|
||||
|
||||
describe Vagrant::LXC::MachineState do
|
||||
describe 'short description' do
|
||||
subject { described_class.new(:not_created) }
|
||||
|
||||
it 'is a humanized version of state id' do
|
||||
subject.short_description.should == 'not created'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'long description' do
|
||||
subject { described_class.new(:short_name) }
|
||||
before { I18n.stub(t: 'some really long description') }
|
||||
|
||||
it 'is a localized version of the state id' do
|
||||
subject.long_description.should == 'some really long description'
|
||||
I18n.should have_received(:t).with('vagrant.commands.status.short_name')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when state id is :running' do
|
||||
subject { described_class.new(:running) }
|
||||
|
||||
it { should be_created }
|
||||
it { should be_running }
|
||||
it { should_not be_off }
|
||||
end
|
||||
|
||||
context 'when state id is :stopped' do
|
||||
subject { described_class.new(:stopped) }
|
||||
|
||||
it { should be_created }
|
||||
it { should be_off }
|
||||
it { should_not be_running }
|
||||
end
|
||||
end
|
38
spec/unit/support/unit_example_group.rb
Normal file
38
spec/unit/support/unit_example_group.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
module UnitExampleGroup
|
||||
def self.included(base)
|
||||
base.metadata[:type] = :unit
|
||||
base.before do
|
||||
allow_any_instance_of(Object).to receive(:system) { |instance, *args, &block|
|
||||
UnitExampleGroup.prevent_system_calls(*args, &block)
|
||||
}
|
||||
allow_any_instance_of(Object).to receive(:`) { |instance, *args, &block|
|
||||
UnitExampleGroup.prevent_system_calls(*args, &block)
|
||||
}
|
||||
allow_any_instance_of(Object).to receive(:exec) { |instance, *args, &block|
|
||||
UnitExampleGroup.prevent_system_calls(*args, &block)
|
||||
}
|
||||
allow_any_instance_of(Object).to receive(:fork) { |instance, *args, &block|
|
||||
UnitExampleGroup.prevent_system_calls(*args, &block)
|
||||
}
|
||||
allow_any_instance_of(Object).to receive(:spawn) { |instance, *args, &block|
|
||||
UnitExampleGroup.prevent_system_calls(*args, &block)
|
||||
}
|
||||
require 'vagrant/util/subprocess'
|
||||
allow(Vagrant::Util::Subprocess).to receive(:execute) { |*args, &block|
|
||||
UnitExampleGroup.prevent_system_calls(*args, &block)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def self.prevent_system_calls(*args, &block)
|
||||
args.pop if args.last.is_a?(Hash)
|
||||
|
||||
raise <<-MSG
|
||||
Somehow your code under test is trying to execute a command on your system,
|
||||
please stub it out or move your spec code to an acceptance spec.
|
||||
|
||||
Block: #{block.inspect}
|
||||
Command: "#{args.join(' ')}"
|
||||
MSG
|
||||
end
|
||||
end
|
|
@ -1,9 +1,17 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.include RSpec::Fire
|
||||
Dir[File.dirname(__FILE__) + "/unit/support/**/*.rb"].each { |f| require f }
|
||||
|
||||
if defined? SimpleCov
|
||||
SimpleCov.command_name 'unit'
|
||||
end
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.include UnitExampleGroup, :type => :unit, :example_group => {
|
||||
:file_path => /\bspec\/unit\//
|
||||
}
|
||||
|
||||
config.mock_with :rspec do |c|
|
||||
c.yield_receiver_to_any_instance_implementation_blocks = true
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
namespace :boxes do
|
||||
namespace :quantal64 do
|
||||
desc 'Build Ubuntu Quantal 64 bits Vagrant LXC box'
|
||||
task :build do
|
||||
if File.exists?('./boxes/output/lxc-quantal64.box')
|
||||
puts 'Box has been built already!'
|
||||
exit 1
|
||||
end
|
||||
|
||||
sh 'mkdir -p boxes/output'
|
||||
sh 'cd boxes/quantal64 && sudo ./download-ubuntu'
|
||||
sh 'rm -f boxes/quantal64/rootfs.tar.gz'
|
||||
sh 'cd boxes/quantal64 && sudo tar --numeric-owner -czf rootfs.tar.gz ./rootfs-amd64/*'
|
||||
sh "cd boxes/quantal64 && sudo chown #{ENV['USER']}:#{ENV['USER']} rootfs.tar.gz && tar -czf ../output/lxc-quantal64.box ./* --exclude=rootfs-amd64 --exclude=download-ubuntu"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,12 +1,15 @@
|
|||
begin
|
||||
require 'rspec/core/rake_task'
|
||||
require 'coveralls/rake/task'
|
||||
|
||||
# TODO: add 'spec:acceptance' and 'spec:integration' then they are in place
|
||||
desc 'Run all specs'
|
||||
task :spec => ['spec:unit']
|
||||
task :spec => ['spec:set_coverage', 'spec:unit', 'spec:acceptance']
|
||||
|
||||
desc 'Default task which runs all specs with code coverage enabled'
|
||||
task :default => ['spec:set_coverage', 'spec']
|
||||
task :default => ['spec:set_coverage', 'spec:unit']
|
||||
|
||||
Coveralls::RakeTask.new
|
||||
task :ci => ['spec:set_coverage', 'spec:unit', 'coveralls:push']
|
||||
rescue LoadError; end
|
||||
|
||||
namespace :spec do
|
||||
|
@ -14,17 +17,24 @@ namespace :spec do
|
|||
ENV['COVERAGE'] = 'true'
|
||||
end
|
||||
|
||||
def types
|
||||
dirs = Dir['./spec/**/*_spec.rb'].map { |f| f.sub(/^\.\/(spec\/\w+)\/.*/, '\\1') }.uniq
|
||||
Hash[dirs.map { |d| [d.split('/').last, d] }]
|
||||
desc 'Run acceptance specs using vagrant-spec'
|
||||
task :acceptance do
|
||||
components = %w(
|
||||
basic
|
||||
network/forwarded_port
|
||||
synced_folder
|
||||
synced_folder/nfs
|
||||
synced_folder/rsync
|
||||
provisioner/shell
|
||||
provisioner/puppet
|
||||
provisioner/chef-solo
|
||||
package
|
||||
).map{|s| "provider/lxc/#{s}" }
|
||||
sh "export ACCEPTANCE=true && bundle exec vagrant-spec test --components=#{components.join(' ')}"
|
||||
end
|
||||
types.each do |type, dir|
|
||||
desc "Run the code examples in #{dir}"
|
||||
RSpec::Core::RakeTask.new(type) do |t|
|
||||
# Tells rspec-fire to verify if constants used really exist
|
||||
ENV['VERIFY_CONSTANT_NAMES'] = '1'
|
||||
|
||||
t.pattern = "./#{dir}/**/*_spec.rb"
|
||||
end
|
||||
desc "Run unit specs with rspec"
|
||||
RSpec::Core::RakeTask.new(:unit) do |t|
|
||||
t.pattern = "./unit/**/*_spec.rb"
|
||||
end
|
||||
end
|
||||
|
|
129
templates/sudoers.rb.erb
Normal file
129
templates/sudoers.rb.erb
Normal file
|
@ -0,0 +1,129 @@
|
|||
#!<%= cmd_paths['ruby'] %>
|
||||
# Automatically created by vagrant-lxc
|
||||
|
||||
class Whitelist
|
||||
class << self
|
||||
def add(command, *args)
|
||||
list[command] ||= []
|
||||
list[command] << args
|
||||
end
|
||||
|
||||
def add_regex(regex, *args)
|
||||
regex_list << [regex, [args]]
|
||||
end
|
||||
|
||||
def list
|
||||
@list ||= {}
|
||||
end
|
||||
|
||||
def regex_list
|
||||
@regex_list ||= []
|
||||
end
|
||||
|
||||
def allowed(command)
|
||||
list[command] || allowed_regex(command) || []
|
||||
end
|
||||
|
||||
def allowed_regex(command)
|
||||
found = regex_list.find { |r| r[0] =~ command }
|
||||
return found[1] if found
|
||||
end
|
||||
|
||||
def run!(argv)
|
||||
begin
|
||||
command, args = `which #{argv.shift}`.chomp, argv || []
|
||||
check!(command, args)
|
||||
system "#{command} #{args.join(" ")}"
|
||||
|
||||
exit_code = $?.to_i
|
||||
exit_code = 1 if exit_code == 256
|
||||
|
||||
exit exit_code
|
||||
rescue => e
|
||||
STDERR.puts e.message
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def check!(command, args)
|
||||
allowed(command).each do |checks|
|
||||
return if valid_args?(args, checks)
|
||||
end
|
||||
raise_invalid(command, args)
|
||||
end
|
||||
|
||||
def valid_args?(args, checks)
|
||||
return false unless valid_length?(args, checks)
|
||||
check = nil
|
||||
args.each_with_index do |provided, i|
|
||||
check = checks[i] unless check == '**'
|
||||
return false unless match?(provided, check)
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def valid_length?(args, checks)
|
||||
args.length == checks.length || checks.last == '**'
|
||||
end
|
||||
|
||||
def match?(arg, check)
|
||||
check == '**' || check.is_a?(Regexp) && !!check.match(arg) || arg == check
|
||||
end
|
||||
|
||||
def raise_invalid(command, args)
|
||||
raise "Invalid arguments for command #{command}, " <<
|
||||
"provided args: #{args.inspect}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
base = "<%= lxc_base_path %>"
|
||||
base_path = %r{\A#{base}/.*\z}
|
||||
|
||||
##
|
||||
# Commands from provider.rb
|
||||
# - Check lxc is installed
|
||||
Whitelist.add '<%= cmd_paths['which'] %>', /\Alxc-\w+\z/
|
||||
|
||||
##
|
||||
# Commands from driver.rb
|
||||
# - Container config file
|
||||
Whitelist.add '<%= cmd_paths['cat'] %>', base_path
|
||||
# - Shared folders
|
||||
Whitelist.add '<%= cmd_paths['mkdir'] %>', '-p', base_path
|
||||
# - Container config customizations and pruning
|
||||
Whitelist.add '<%= cmd_paths['cp'] %>', '-f', %r{/tmp/.*}, base_path
|
||||
Whitelist.add '<%= cmd_paths['chown'] %>', 'root:root', base_path
|
||||
# - Packaging
|
||||
Whitelist.add '<%= cmd_paths['tar'] %>', '--numeric-owner', '-cvzf', %r{/tmp/.*/rootfs.tar.gz}, '-C', base_path, './rootfs'
|
||||
Whitelist.add '<%= cmd_paths['chown'] %>', /\A\d+:\d+\z/, %r{\A/tmp/.*/rootfs\.tar\.gz\z}
|
||||
# - Private network script and commands
|
||||
Whitelist.add '<%= cmd_paths['ip'] %>', 'addr', 'add', /(\d+|\.)+\/24/, 'dev', /.+/
|
||||
Whitelist.add '<%= cmd_paths['ip'] %>', 'link', 'set', /.+/, /(up|down)/
|
||||
Whitelist.add '<%= cmd_paths['brctl'] %>', /(addbr|delbr)/, /.+/
|
||||
Whitelist.add_regex %r{<%= pipework_regex %>}, '**'
|
||||
|
||||
##
|
||||
# Commands from driver/cli.rb
|
||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-version'
|
||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-ls'
|
||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-info', '--name', /.*/
|
||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-info', '--name', /.*/, '-iH'
|
||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-create', '-B', /.*/, '--template', /.*/, '--name', /.*/, '**'
|
||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-create', '--version'
|
||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-destroy', '--name', /.*/
|
||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-start', '-d', '--name', /.*/, '**'
|
||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-stop', '--name', /.*/
|
||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-shutdown', '--name', /.*/
|
||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-attach', '--name', /.*/, '**'
|
||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-attach', '-h'
|
||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-config', 'lxc.lxcpath'
|
||||
Whitelist.add '<%= cmd_paths['lxc_bin'] %>/lxc-update-config', '-c', /.*/
|
||||
|
||||
##
|
||||
# Commands from driver/action/remove_temporary_files.rb
|
||||
Whitelist.add '<%= cmd_paths['rm'] %>', '-rf', %r{\A#{base}/.*/rootfs/tmp/.*}
|
||||
|
||||
# Watch out for stones
|
||||
Whitelist.run!(ARGV)
|
|
@ -10,23 +10,11 @@ Gem::Specification.new do |gem|
|
|||
gem.email = ["fgrehm@gmail.com"]
|
||||
gem.description = %q{Linux Containers provider for Vagrant}
|
||||
gem.summary = gem.description
|
||||
gem.license = 'MIT'
|
||||
gem.homepage = "https://github.com/fgrehm/vagrant-lxc"
|
||||
|
||||
gem.files = `git ls-files`.split($/)
|
||||
gem.files << `cd vendor/vagrant && git ls-files`.split($/).map{|file| "vendor/vagrant/#{file}"}
|
||||
|
||||
gem.files = `git ls-files`.split($/)
|
||||
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
||||
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
||||
gem.require_paths = ["lib"]
|
||||
|
||||
gem.add_development_dependency "rake"
|
||||
|
||||
# Vagrant's dependencies
|
||||
gem.add_dependency "childprocess", "~> 0.3.7"
|
||||
gem.add_dependency "erubis", "~> 2.7.0"
|
||||
gem.add_dependency "i18n", "~> 0.6.0"
|
||||
gem.add_dependency "json", ">= 1.5.1", "< 1.8.0"
|
||||
gem.add_dependency "log4r", "~> 1.1.9"
|
||||
gem.add_dependency "net-ssh", "~> 2.2.2"
|
||||
gem.add_dependency "net-scp", "~> 1.0.4"
|
||||
end
|
||||
|
|
24
vagrant-spec.config.rb
Normal file
24
vagrant-spec.config.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
# FIXME: Figure out why this doesn't work
|
||||
if ENV['COVERAGE'] == 'true'
|
||||
require 'simplecov'
|
||||
require 'coveralls'
|
||||
|
||||
SimpleCov.start { add_filter '/spec/' }
|
||||
SimpleCov.command_name 'acceptance'
|
||||
end
|
||||
|
||||
if ENV['BOX_PATH'] == nil
|
||||
latest = ENV.fetch('LATEST_BOXES','2014-03-21')
|
||||
release = ENV.fetch('RELEASE', 'acceptance')
|
||||
local_path ="#{File.expand_path("../", __FILE__)}/boxes/output/#{latest}/vagrant-lxc-#{release}-amd64.box"
|
||||
if File.exists?(local_path)
|
||||
ENV['BOX_PATH'] = local_path
|
||||
else
|
||||
raise 'Set $BOX_PATH to the latest released boxes'
|
||||
end
|
||||
end
|
||||
|
||||
Vagrant::Spec::Acceptance.configure do |c|
|
||||
c.component_paths << "spec/acceptance"
|
||||
c.provider 'lxc', box: ENV['BOX_PATH'], features: ['!suspend']
|
||||
end
|
1
vendor/vagrant
vendored
1
vendor/vagrant
vendored
|
@ -1 +0,0 @@
|
|||
Subproject commit fc95944631a9adeed1c2b01f5b35c34ed8b59ff5
|
Loading…
Add table
Reference in a new issue