diff --git a/Cargo.lock b/Cargo.lock index 9eb862e43..fed949756 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,126 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" +checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" + +[[package]] +name = "async-channel" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell", + "slab", +] + +[[package]] +name = "async-fs" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b3ca4f8ff117c37c278a2f7415ce9be55560b846b5bc4412aaa5d29c1c3dae2" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-io" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bbfd5cf2794b1e908ea8457e6c45f8f8f1f6ec5f74617bf4662623f47503c3b" +dependencies = [ + "concurrent-queue", + "fastrand", + "futures-lite", + "libc", + "log", + "once_cell", + "parking", + "polling", + "slab", + "socket2", + "waker-fn", + "winapi", +] + +[[package]] +name = "async-lock" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-net" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b0a74e7f70af3c8cf1aa539edbd044795706659ac52b78a71dc1a205ecefdf" +dependencies = [ + "async-io", + "blocking", + "fastrand", + "futures-lite", +] + +[[package]] +name = "async-process" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f38756dd9ac84671c428afbf7c9f7495feff9ec5b0710f17100098e5b354ac" +dependencies = [ + "async-io", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "libc", + "once_cell", + "signal-hook", + "winapi", +] + +[[package]] +name = "async-task" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" + +[[package]] +name = "async-trait" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b98e84bbb4cbcdd97da190ba0c58a1bb0de2c1fdf67d159e192ed766aeca722" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atomic-waker" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" [[package]] name = "atty" @@ -46,17 +163,37 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "blocking" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" +dependencies = [ + "async-channel", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", + "once_cell", +] + [[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "cache-padded" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" + [[package]] name = "caps" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d092fbb6657fb1f98a7da70c14335ac97e5a9477e1a8156d4bbf19a3a7aece51" +checksum = "c088f2dddef283f86b023ab1ebe2301c653326834996458b2f48d29b804e9540" dependencies = [ "errno", "libc", @@ -65,9 +202,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.66" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" +checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" [[package]] name = "cfg-if" @@ -120,6 +257,15 @@ dependencies = [ "syn", ] +[[package]] +name = "concurrent-queue" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +dependencies = [ + "cache-padded", +] + [[package]] name = "crc32fast" version = "1.2.1" @@ -150,6 +296,21 @@ dependencies = [ "libc", ] +[[package]] +name = "event-listener" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" + +[[package]] +name = "fastrand" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77b705829d1e87f762c2df6da140b26af5839e1033aa84aa5f56bb688e4e1bdb" +dependencies = [ + "instant", +] + [[package]] name = "flate2" version = "1.0.20" @@ -164,9 +325,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1" +checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27" dependencies = [ "futures-channel", "futures-core", @@ -179,9 +340,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939" +checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2" dependencies = [ "futures-core", "futures-sink", @@ -189,15 +350,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94" +checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1" [[package]] name = "futures-executor" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1" +checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79" dependencies = [ "futures-core", "futures-task", @@ -207,16 +368,32 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59" +checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1" + +[[package]] +name = "futures-lite" +version = "1.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4481d0cd0de1d204a4fa55e7d45f07b1d958abcb06714b3446438e2eff695fb" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] [[package]] name = "futures-macro" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea405816a5139fb39af82c2beb921d52143f556038378d6db21183a5c37fbfb7" +checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121" dependencies = [ + "autocfg", "proc-macro-hack", "proc-macro2", "quote", @@ -225,22 +402,23 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3" +checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282" [[package]] name = "futures-task" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80" +checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae" [[package]] name = "futures-util" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" +checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" dependencies = [ + "autocfg", "futures-channel", "futures-core", "futures-io", @@ -293,14 +471,23 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "indexmap" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" +checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" dependencies = [ "autocfg", "hashbrown", ] +[[package]] +name = "instant" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +dependencies = [ + "cfg-if", +] + [[package]] name = "itoa" version = "0.4.7" @@ -315,9 +502,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.84" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff" +checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" [[package]] name = "log" @@ -346,9 +533,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.7.7" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7" +checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956" dependencies = [ "libc", "log", @@ -359,11 +546,10 @@ dependencies = [ [[package]] name = "miow" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" dependencies = [ - "socket2", "winapi", ] @@ -379,6 +565,18 @@ dependencies = [ "libc", ] +[[package]] +name = "nix" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", +] + [[package]] name = "ntapi" version = "0.3.6" @@ -423,16 +621,16 @@ version = "0.1.0" dependencies = [ "anyhow", "caps", - "nix", + "nix 0.19.1", "serde", "serde_json", ] [[package]] name = "once_cell" -version = "1.6.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad167a2f54e832b82dbe003a046280dceffe5227b5f79e08e363a29638cfddd" +checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" [[package]] name = "os_str_bytes" @@ -440,6 +638,12 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85" +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + [[package]] name = "pin-project-lite" version = "0.2.6" @@ -452,6 +656,19 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "polling" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fc12d774e799ee9ebae13f4076ca003b40d18a11ac0f3641e6f899618580b7b" +dependencies = [ + "cfg-if", + "libc", + "log", + "wepoll-sys", + "winapi", +] + [[package]] name = "prctl" version = "1.0.0" @@ -459,7 +676,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "059a34f111a9dee2ce1ac2826a68b24601c4298cfeb1a587c3cb493d5ab46f52" dependencies = [ "libc", - "nix", + "nix 0.20.0", ] [[package]] @@ -500,9 +717,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" dependencies = [ "unicode-xid", ] @@ -524,9 +741,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] @@ -556,18 +773,18 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "serde" -version = "1.0.123" +version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" +checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.123" +version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" +checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" dependencies = [ "proc-macro2", "quote", @@ -576,28 +793,64 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "signal-hook" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef33d6d0cd06e0840fba9985aab098c147e67e05cee14d412d3345ed14ff30ac" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +dependencies = [ + "libc", +] + [[package]] name = "slab" -version = "0.4.2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" + +[[package]] +name = "smol" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +checksum = "85cf3b5351f3e783c1d79ab5fc604eeed8b8ae9abd36b166e8b87a089efd85e4" +dependencies = [ + "async-channel", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-net", + "async-process", + "blocking", + "futures-lite", + "once_cell", +] [[package]] name = "socket2" -version = "0.3.19" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2" dependencies = [ - "cfg-if", "libc", "winapi", ] @@ -610,9 +863,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.60" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" dependencies = [ "proc-macro2", "quote", @@ -639,18 +892,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d" dependencies = [ "proc-macro2", "quote", @@ -682,9 +935,9 @@ checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "vec_map" @@ -694,9 +947,15 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" [[package]] name = "wasi" @@ -704,6 +963,15 @@ version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +[[package]] +name = "wepoll-sys" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcb14dea929042224824779fbc82d9fab8d2e6d3cbc0ac404de8edf489e77ff" +dependencies = [ + "cc", +] + [[package]] name = "winapi" version = "0.3.9" @@ -740,6 +1008,7 @@ name = "youki" version = "0.0.1" dependencies = [ "anyhow", + "async-trait", "caps", "chrono", "clap", @@ -747,7 +1016,7 @@ dependencies = [ "libc", "log", "mio", - "nix", + "nix 0.19.1", "oci_spec", "once_cell", "prctl", @@ -755,4 +1024,5 @@ dependencies = [ "regex", "serde", "serde_json", + "smol", ] diff --git a/Cargo.toml b/Cargo.toml index 4cbe34dfe..07e643865 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,4 +21,6 @@ chrono = "0.4" once_cell = "1.6.0" futures = { version = "0.3", features = ["thread-pool"] } regex = "1.5" +smol = "1.2.5" +async-trait = "0.1.50" oci_spec = { version = "0.1.0", path = "./oci_spec" } diff --git a/src/cgroups/blkio.rs b/src/cgroups/blkio.rs index feb319ab3..34e13c890 100644 --- a/src/cgroups/blkio.rs +++ b/src/cgroups/blkio.rs @@ -1,8 +1,8 @@ -use std::{ - fs::{self, OpenOptions}, - io::Write, - path::Path, -}; +use std::path::Path; + + +use async_trait::async_trait; +use smol::{fs::{OpenOptions, create_dir_all}, io::AsyncWriteExt}; use crate::{ cgroups::Controller, @@ -16,8 +16,9 @@ const CGROUP_BLKIO_THROTTLE_WRITE_IOPS: &str = "blkio.throttle.write_iops_device pub struct Blkio {} +#[async_trait] impl Controller for Blkio { - fn apply( + async fn apply( linux_resources: &LinuxResources, cgroup_root: &Path, pid: nix::unistd::Pid, @@ -25,62 +26,66 @@ impl Controller for Blkio { match &linux_resources.block_io { None => return Ok(()), Some(block_io) => { - fs::create_dir_all(cgroup_root)?; - Self::apply(cgroup_root, block_io)?; + create_dir_all(cgroup_root).await?; + Self::apply(cgroup_root, block_io).await?; } } - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(cgroup_root.join("cgroup.procs"))? - .write_all(pid.to_string().as_bytes())?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; Ok(()) } } impl Blkio { - fn apply(root_path: &Path, blkio: &LinuxBlockIo) -> anyhow::Result<()> { + async fn apply(root_path: &Path, blkio: &LinuxBlockIo) -> anyhow::Result<()> { for trbd in &blkio.blkio_throttle_read_bps_device { Self::write_file( &root_path.join(CGROUP_BLKIO_THROTTLE_READ_BPS), &format!("{}:{} {}", trbd.major, trbd.minor, trbd.rate), - )?; + ).await?; } for twbd in &blkio.blkio_throttle_write_bps_device { Self::write_file( &root_path.join(CGROUP_BLKIO_THROTTLE_WRITE_BPS), &format!("{}:{} {}", twbd.major, twbd.minor, twbd.rate), - )?; + ).await?; } for trid in &blkio.blkio_throttle_read_iops_device { Self::write_file( &root_path.join(CGROUP_BLKIO_THROTTLE_READ_IOPS), &format!("{}:{} {}", trid.major, trid.minor, trid.rate), - )?; + ).await?; } for twid in &blkio.blkio_throttle_write_iops_device { Self::write_file( &root_path.join(CGROUP_BLKIO_THROTTLE_WRITE_IOPS), &format!("{}:{} {}", twid.major, twid.minor, twid.rate), - )?; + ).await?; } Ok(()) } - fn write_file(file_path: &Path, data: &str) -> anyhow::Result<()> { - fs::OpenOptions::new() + async fn write_file(file_path: &Path, data: &str) -> anyhow::Result<()> { + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(file_path)? - .write_all(data.as_bytes())?; + .open(file_path).await?; + + file.write_all(data.as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -92,6 +97,7 @@ mod tests { use super::*; use oci_spec::{LinuxBlockIo, LinuxThrottleDevice}; + use std::io::Write; struct BlockIoBuilder { block_io: LinuxBlockIo, @@ -152,12 +158,14 @@ mod tests { ) -> anyhow::Result { let full_path = temp_dir.join(filename); - std::fs::OpenOptions::new() + let mut file = std::fs::OpenOptions::new() .create(true) .write(true) .truncate(true) - .open(&full_path)? - .write_all(val.as_bytes())?; + .open(&full_path)?; + + file.write_all(val.as_bytes())?; + file.sync_data()?; Ok(full_path) } @@ -172,19 +180,21 @@ mod tests { let (test_root, throttle) = setup("test_set_blkio_read_bps", CGROUP_BLKIO_THROTTLE_READ_BPS); - let blkio = BlockIoBuilder::new() - .with_read_bps(vec![LinuxThrottleDevice { - major: 8, - minor: 0, - rate: 102400, - }]) - .build(); - - Blkio::apply(&test_root, &blkio).expect("apply blkio"); - let content = fs::read_to_string(throttle) - .unwrap_or_else(|_| panic!("read {} content", CGROUP_BLKIO_THROTTLE_READ_BPS)); - - assert_eq!("8:0 102400", content); + smol::block_on(async { + let blkio = BlockIoBuilder::new() + .with_read_bps(vec![LinuxThrottleDevice { + major: 8, + minor: 0, + rate: 102400, + }]) + .build(); + + Blkio::apply(&test_root, &blkio).await.expect("apply blkio"); + let content = std::fs::read_to_string(throttle) + .expect(&format!("read {} content", CGROUP_BLKIO_THROTTLE_READ_BPS)); + + assert_eq!("8:0 102400", content); + }); } #[test] @@ -192,19 +202,21 @@ mod tests { let (test_root, throttle) = setup("test_set_blkio_write_bps", CGROUP_BLKIO_THROTTLE_WRITE_BPS); - let blkio = BlockIoBuilder::new() - .with_write_bps(vec![LinuxThrottleDevice { - major: 8, - minor: 0, - rate: 102400, - }]) - .build(); - - Blkio::apply(&test_root, &blkio).expect("apply blkio"); - let content = fs::read_to_string(throttle) - .unwrap_or_else(|_| panic!("read {} content", CGROUP_BLKIO_THROTTLE_WRITE_BPS)); - - assert_eq!("8:0 102400", content); + smol::block_on(async { + let blkio = BlockIoBuilder::new() + .with_write_bps(vec![LinuxThrottleDevice { + major: 8, + minor: 0, + rate: 102400, + }]) + .build(); + + Blkio::apply(&test_root, &blkio).await.expect("apply blkio"); + let content = std::fs::read_to_string(throttle) + .expect(&format!("read {} content", CGROUP_BLKIO_THROTTLE_WRITE_BPS)); + + assert_eq!("8:0 102400", content); + }); } #[test] @@ -212,19 +224,21 @@ mod tests { let (test_root, throttle) = setup("test_set_blkio_read_iops", CGROUP_BLKIO_THROTTLE_READ_IOPS); - let blkio = BlockIoBuilder::new() - .with_read_iops(vec![LinuxThrottleDevice { - major: 8, - minor: 0, - rate: 102400, - }]) - .build(); - - Blkio::apply(&test_root, &blkio).expect("apply blkio"); - let content = fs::read_to_string(throttle) - .unwrap_or_else(|_| panic!("read {} content", CGROUP_BLKIO_THROTTLE_READ_IOPS)); - - assert_eq!("8:0 102400", content); + smol::block_on(async { + let blkio = BlockIoBuilder::new() + .with_read_iops(vec![LinuxThrottleDevice { + major: 8, + minor: 0, + rate: 102400, + }]) + .build(); + + Blkio::apply(&test_root, &blkio).await.expect("apply blkio"); + let content = std::fs::read_to_string(throttle) + .expect(&format!("read {} content", CGROUP_BLKIO_THROTTLE_READ_IOPS)); + + assert_eq!("8:0 102400", content); + }); } #[test] @@ -234,18 +248,22 @@ mod tests { CGROUP_BLKIO_THROTTLE_WRITE_IOPS, ); - let blkio = BlockIoBuilder::new() - .with_write_iops(vec![LinuxThrottleDevice { - major: 8, - minor: 0, - rate: 102400, - }]) - .build(); - - Blkio::apply(&test_root, &blkio).expect("apply blkio"); - let content = fs::read_to_string(throttle) - .unwrap_or_else(|_| panic!("read {} content", CGROUP_BLKIO_THROTTLE_WRITE_IOPS)); - - assert_eq!("8:0 102400", content); + smol::block_on(async { + let blkio = BlockIoBuilder::new() + .with_write_iops(vec![LinuxThrottleDevice { + major: 8, + minor: 0, + rate: 102400, + }]) + .build(); + + Blkio::apply(&test_root, &blkio).await.expect("apply blkio"); + let content = std::fs::read_to_string(throttle).expect(&format!( + "read {} content", + CGROUP_BLKIO_THROTTLE_WRITE_IOPS + )); + + assert_eq!("8:0 102400", content); + }); } } diff --git a/src/cgroups/controller.rs b/src/cgroups/controller.rs index 84e0b3cc2..ffe8bb73f 100644 --- a/src/cgroups/controller.rs +++ b/src/cgroups/controller.rs @@ -1,10 +1,12 @@ use std::path::Path; use anyhow::Result; +use async_trait::async_trait; use nix::unistd::Pid; use oci_spec::LinuxResources; +#[async_trait] pub trait Controller { - fn apply(linux_resources: &LinuxResources, cgroup_root: &Path, pid: Pid) -> Result<()>; + async fn apply(linux_resources: &LinuxResources, cgroup_root: &Path, pid: Pid) -> Result<()>; } diff --git a/src/cgroups/devices.rs b/src/cgroups/devices.rs index ff64afeda..d09016091 100644 --- a/src/cgroups/devices.rs +++ b/src/cgroups/devices.rs @@ -1,11 +1,11 @@ -use std::io::Write; use std::{ - fs::{create_dir_all, OpenOptions}, path::Path, }; use anyhow::Result; +use async_trait::async_trait; use nix::unistd::Pid; +use smol::{fs::{OpenOptions, create_dir_all}, io::AsyncWriteExt}; use crate::{ cgroups::Controller, @@ -15,13 +15,21 @@ use oci_spec::{LinuxDeviceCgroup, LinuxDeviceType, LinuxResources}; pub struct Devices {} +#[async_trait] impl Controller for Devices { - fn apply(linux_resources: &LinuxResources, cgroup_root: &Path, pid: Pid) -> Result<()> { + async fn apply(linux_resources: &LinuxResources, cgroup_root: &Path, pid: Pid) -> Result<()> { log::debug!("Apply Devices cgroup config"); - create_dir_all(&cgroup_root)?; + create_dir_all(&cgroup_root).await?; + + let mut allowed: Vec = Vec::new(); + let mut denied: Vec = Vec::new(); for d in &linux_resources.devices { - Self::apply_device(d, cgroup_root)?; + if d.allow { + allowed.push(d.to_string()) + } else { + denied.push(d.to_string()) + } } for d in [ @@ -30,33 +38,38 @@ impl Controller for Devices { ] .concat() { - Self::apply_device(&d, &cgroup_root)?; + if d.allow { + allowed.push(d.to_string()) + } else { + denied.push(d.to_string()) + } } - OpenOptions::new() + Self::write_file(&allowed.join("\n"), &cgroup_root.join("devices.allow")).await?; + Self::write_file(&denied.join("\n"), &cgroup_root.join("devices.deny")).await?; + + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(cgroup_root.join("cgroup.procs"))? - .write_all(pid.to_string().as_bytes())?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; Ok(()) } } impl Devices { - fn apply_device(device: &LinuxDeviceCgroup, cgroup_root: &Path) -> Result<()> { - let path = if device.allow { - cgroup_root.join("devices.allow") - } else { - cgroup_root.join("devices.deny") - }; - - OpenOptions::new() + async fn write_file(data: &str, path: &Path) -> Result<()> { + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(path)? - .write_all(device.to_string().as_bytes())?; + .open(path).await?; + + file.write_all(data.as_bytes()).await?; + file.sync_data().await?; Ok(()) } diff --git a/src/cgroups/hugetlb.rs b/src/cgroups/hugetlb.rs index 3e74cd216..26e5524fa 100644 --- a/src/cgroups/hugetlb.rs +++ b/src/cgroups/hugetlb.rs @@ -1,11 +1,9 @@ -use std::{ - fs::{self, OpenOptions}, - io::Write, - path::Path, -}; +use std::path::Path; use anyhow::anyhow; +use async_trait::async_trait; use regex::Regex; +use smol::{fs::{OpenOptions, create_dir_all}, io::AsyncWriteExt}; use crate::{ cgroups::Controller, @@ -14,31 +12,34 @@ use oci_spec::{LinuxHugepageLimit, LinuxResources}; pub struct Hugetlb {} +#[async_trait] impl Controller for Hugetlb { - fn apply( + async fn apply( linux_resources: &LinuxResources, cgroup_root: &std::path::Path, pid: nix::unistd::Pid, ) -> anyhow::Result<()> { log::debug!("Apply Hugetlb cgroup config"); - fs::create_dir_all(cgroup_root)?; + create_dir_all(cgroup_root).await?; for hugetlb in &linux_resources.hugepage_limits { - Self::apply(cgroup_root, hugetlb)? + Self::apply(cgroup_root, hugetlb).await? } - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(cgroup_root.join("cgroup.procs"))? - .write_all(pid.to_string().as_bytes())?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; Ok(()) } } impl Hugetlb { - fn apply(root_path: &Path, hugetlb: &LinuxHugepageLimit) -> anyhow::Result<()> { + async fn apply(root_path: &Path, hugetlb: &LinuxHugepageLimit) -> anyhow::Result<()> { let re = Regex::new(r"(?P[0-9]+)[KMG]B")?; let caps = re.captures(&hugetlb.page_size); match caps { @@ -54,17 +55,19 @@ impl Hugetlb { Self::write_file( &root_path.join(format!("hugetlb.{}.limit_in_bytes", hugetlb.page_size)), &hugetlb.limit.to_string(), - )?; + ).await?; Ok(()) } - fn write_file(file_path: &Path, data: &str) -> anyhow::Result<()> { - fs::OpenOptions::new() + async fn write_file(file_path: &Path, data: &str) -> anyhow::Result<()> { + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path)? - .write_all(data.as_bytes())?; + .open(file_path).await?; + + file.write_all(data.as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -80,14 +83,17 @@ mod tests { use super::*; use oci_spec::LinuxHugepageLimit; + use std::io::Write; fn set_fixture(temp_dir: &std::path::Path, filename: &str, val: &str) -> anyhow::Result<()> { - std::fs::OpenOptions::new() + let mut file = std::fs::OpenOptions::new() .create(true) .write(true) .truncate(true) - .open(temp_dir.join(filename))? - .write_all(val.as_bytes())?; + .open(temp_dir.join(filename))?; + + file.write_all(val.as_bytes())?; + file.sync_data()?; Ok(()) } @@ -103,14 +109,16 @@ mod tests { let tmp = create_temp_dir("test_set_hugetlb").expect("create temp directory for test"); set_fixture(&tmp, page_file_name, "0").expect("Set fixture for 2 MB page size"); - let hugetlb = LinuxHugepageLimit { - page_size: "2MB".to_owned(), - limit: 16384, - }; - Hugetlb::apply(&tmp, &hugetlb).expect("apply hugetlb"); - let content = - std::fs::read_to_string(tmp.join(page_file_name)).expect("Read hugetlb file content"); - assert_eq!(hugetlb.limit.to_string(), content); + smol::block_on(async { + let hugetlb = LinuxHugepageLimit { + page_size: "2MB".to_owned(), + limit: 16384, + }; + Hugetlb::apply(&tmp, &hugetlb).await.expect("apply hugetlb"); + let content = + std::fs::read_to_string(tmp.join(page_file_name)).expect("Read hugetlb file content"); + assert_eq!(hugetlb.limit.to_string(), content); + }); } #[test] @@ -118,15 +126,17 @@ mod tests { let tmp = create_temp_dir("test_set_hugetlb_with_invalid_page_size") .expect("create temp directory for test"); - let hugetlb = LinuxHugepageLimit { - page_size: "3MB".to_owned(), - limit: 16384, - }; - - let result = Hugetlb::apply(&tmp, &hugetlb); - assert!( - result.is_err(), - "page size that is not a power of two should be an error" - ); + smol::block_on(async { + let hugetlb = LinuxHugepageLimit { + page_size: "3MB".to_owned(), + limit: 16384, + }; + + let result = Hugetlb::apply(&tmp, &hugetlb).await; + assert!( + result.is_err(), + "page size that is not a power of two should be an error" + ); + }); } } diff --git a/src/cgroups/manager.rs b/src/cgroups/manager.rs index 8a74ef117..e2f27ce39 100644 --- a/src/cgroups/manager.rs +++ b/src/cgroups/manager.rs @@ -1,5 +1,6 @@ use std::{collections::HashMap, path::PathBuf}; use std::{fs::remove_dir, path::Path}; +use futures::future::try_join_all; use anyhow::Result; use nix::unistd::Pid; @@ -41,20 +42,26 @@ impl Manager { } pub fn apply(&self, linux_resources: &LinuxResources, pid: Pid) -> Result<()> { - for subsys in &self.subsystems { - match subsys.0.as_str() { - "devices" => Devices::apply(linux_resources, &subsys.1, pid)?, - "hugetlb" => Hugetlb::apply(linux_resources, &subsys.1, pid)?, - "memory" => Memory::apply(linux_resources, &subsys.1, pid)?, - "pids" => Pids::apply(linux_resources, &subsys.1, pid)?, - "blkio" => Blkio::apply(linux_resources, &subsys.1, pid)?, - "net_prio" => NetworkPriority::apply(linux_resources, &subsys.1, pid)?, - "net_cls" => NetworkClassifier::apply(linux_resources, &subsys.1, pid)?, - _ => continue, - } - } + smol::block_on(async { + try_join_all(self.subsystems.iter() + .filter_map(|entry| { + let key = entry.0.as_str(); + let value = entry.1; + match key { + "devices" => Some(Devices::apply(linux_resources, value, pid)), + "hugetlb" => Some(Hugetlb::apply(linux_resources, value, pid)), + "memory" => Some(Memory::apply(linux_resources, value, pid)), + "pids" => Some(Pids::apply(linux_resources, value, pid)), + "blkio" => Some(Blkio::apply(linux_resources, value, pid)), + "net_prio" => Some(NetworkPriority::apply(linux_resources, value, pid)), + "net_cls" => Some(NetworkClassifier::apply(linux_resources, value, pid)), + _ => None, + } + }).collect::>() + ).await?; - Ok(()) + Ok(()) + }) } pub fn remove(&self) -> Result<()> { @@ -78,14 +85,20 @@ impl Manager { // Some systems mount net_prio and net_cls in the same directory // other systems mount them in their own diretories. This // should handle both cases. - if subsystem == "net_cls" || subsystem == "net_prio" { + if subsystem == "net_cls" { + return m.mount_point.ends_with("net_cls,net_prio") + || m.mount_point.ends_with("net_prio,net_cls") + || m.mount_point.ends_with("net_cls"); + } else if subsystem == "net_prio" { return m.mount_point.ends_with("net_cls,net_prio") - || m.mount_point.ends_with("net_prio,net_cls"); + || m.mount_point.ends_with("net_prio,net_cls") + || m.mount_point.ends_with("net_prio"); } + return m.mount_point.ends_with(subsystem); } - m.mount_point.ends_with(subsystem) + return false; }) - .unwrap(); + .expect("Failed to find mount point for subsystem"); let cgroup = Process::myself()? .cgroups()? diff --git a/src/cgroups/memory.rs b/src/cgroups/memory.rs index 696f7455d..c4a66b442 100644 --- a/src/cgroups/memory.rs +++ b/src/cgroups/memory.rs @@ -1,11 +1,11 @@ -use std::io::{prelude::*, Write}; use std::{ - fs::{create_dir_all, OpenOptions}, path::Path, }; use anyhow::{Result, *}; +use async_trait::async_trait; use nix::{errno::Errno, unistd::Pid}; +use smol::{fs::{OpenOptions, create_dir_all}, io::{AsyncReadExt, AsyncWriteExt}}; use crate::{ cgroups::Controller, @@ -25,29 +25,30 @@ const CGROUP_KERNEL_TCP_MEMORY_LIMIT: &str = "memory.kmem.tcp.limit_in_bytes"; pub struct Memory {} +#[async_trait] impl Controller for Memory { - fn apply(linux_resources: &LinuxResources, cgroup_root: &Path, pid: Pid) -> Result<()> { + async fn apply(linux_resources: &LinuxResources, cgroup_root: &Path, pid: Pid) -> Result<()> { log::debug!("Apply Memory cgroup config"); - create_dir_all(&cgroup_root)?; + create_dir_all(&cgroup_root).await?; if let Some(memory) = &linux_resources.memory { let reservation = memory.reservation.unwrap_or(0); - Self::apply(&memory, cgroup_root)?; + Self::apply(&memory, cgroup_root).await?; if reservation != 0 { - Self::set(reservation, &cgroup_root.join(CGROUP_MEMORY_RESERVATION))?; + Self::set(reservation, &cgroup_root.join(CGROUP_MEMORY_RESERVATION)).await?; } if linux_resources.disable_oom_killer { - Self::set(0, &cgroup_root.join(CGROUP_MEMORY_OOM_CONTROL))?; + Self::set(0 as i64, &cgroup_root.join(CGROUP_MEMORY_OOM_CONTROL)).await?; } else { - Self::set(1, &cgroup_root.join(CGROUP_MEMORY_OOM_CONTROL))?; + Self::set(1 as i64, &cgroup_root.join(CGROUP_MEMORY_OOM_CONTROL)).await?; } if let Some(swappiness) = memory.swappiness { if swappiness <= 100 { - Self::set(swappiness, &cgroup_root.join(CGROUP_MEMORY_SWAPPINESS))?; + Self::set(swappiness, &cgroup_root.join(CGROUP_MEMORY_SWAPPINESS)).await?; } else { // invalid swappiness value return Err(anyhow!( @@ -61,32 +62,34 @@ impl Controller for Memory { // neither are implemented by runc. Tests pass without this, but // kept in per the spec. if let Some(kmem) = memory.kernel { - Self::set(kmem, &cgroup_root.join(CGROUP_KERNEL_MEMORY_LIMIT))?; + Self::set(kmem, &cgroup_root.join(CGROUP_KERNEL_MEMORY_LIMIT)).await?; } if let Some(tcp_mem) = memory.kernel_tcp { - Self::set(tcp_mem, &cgroup_root.join(CGROUP_KERNEL_TCP_MEMORY_LIMIT))?; + Self::set(tcp_mem, &cgroup_root.join(CGROUP_KERNEL_TCP_MEMORY_LIMIT)).await?; } - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(cgroup_root.join("cgroup.procs"))? - .write_all(pid.to_string().as_bytes())?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_all().await?; } Ok(()) } } impl Memory { - fn get_memory_usage(cgroup_root: &Path) -> Result { + async fn get_memory_usage(cgroup_root: &Path) -> Result { let path = cgroup_root.join(CGROUP_MEMORY_USAGE); let mut contents = String::new(); OpenOptions::new() .create(false) .read(true) - .open(path)? - .read_to_string(&mut contents)?; + .open(path).await? + .read_to_string(&mut contents).await?; contents = contents.trim().to_string(); @@ -98,14 +101,14 @@ impl Memory { Ok(val) } - fn get_memory_max_usage(cgroup_root: &Path) -> Result { + async fn get_memory_max_usage(cgroup_root: &Path) -> Result { let path = cgroup_root.join(CGROUP_MEMORY_MAX_USAGE); let mut contents = String::new(); OpenOptions::new() .create(false) .read(true) - .open(path)? - .read_to_string(&mut contents)?; + .open(path).await? + .read_to_string(&mut contents).await?; contents = contents.trim().to_string(); @@ -117,14 +120,14 @@ impl Memory { Ok(val) } - fn get_memory_limit(cgroup_root: &Path) -> Result { + async fn get_memory_limit(cgroup_root: &Path) -> Result { let path = cgroup_root.join(CGROUP_MEMORY_LIMIT); let mut contents = String::new(); OpenOptions::new() .create(false) .read(true) - .open(path)? - .read_to_string(&mut contents)?; + .open(path).await? + .read_to_string(&mut contents).await?; contents = contents.trim().to_string(); @@ -136,31 +139,29 @@ impl Memory { Ok(val) } - fn set(val: T, path: &Path) -> std::io::Result<()> { - OpenOptions::new() + async fn set(val: T, path: &Path) -> std::io::Result<()> { + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(path)? - .write_all(val.to_string().as_bytes())?; + .open(path).await.expect(&format!("Open: {}", path.to_str().unwrap())); + file.write_all(val.to_string().as_bytes()).await?; + file.sync_all().await?; Ok(()) } - fn set_memory(val: i64, cgroup_root: &Path) -> Result<()> { - if val == 0 { - return Ok(()); - } + async fn set_memory(val: i64, cgroup_root: &Path) -> Result<()> { let path = cgroup_root.join(CGROUP_MEMORY_LIMIT); - match Self::set(val, &path) { + match Self::set(val, &path).await { Ok(_) => Ok(()), Err(e) => { // we need to look into the raw OS error for an EBUSY status match e.raw_os_error() { Some(code) => match Errno::from_i32(code) { Errno::EBUSY => { - let usage = Self::get_memory_usage(cgroup_root)?; - let max_usage = Self::get_memory_max_usage(cgroup_root)?; + let usage = Self::get_memory_usage(cgroup_root).await?; + let max_usage = Self::get_memory_max_usage(cgroup_root).await?; bail!( "unable to set memory limit to {} (current usage: {}, peak usage: {})", val, @@ -176,19 +177,19 @@ impl Memory { } } - fn set_swap(val: i64, cgroup_root: &Path) -> Result<()> { + async fn set_swap(val: i64, cgroup_root: &Path) -> Result<()> { if val == 0 { return Ok(()); } let path = cgroup_root.join(CGROUP_MEMORY_SWAP_LIMIT); - Self::set(val, &path)?; + Self::set(val, &path).await?; Ok(()) } - fn set_memory_and_swap( + async fn set_memory_and_swap( limit: i64, swap: i64, is_updated: bool, @@ -200,36 +201,40 @@ impl Memory { // see: // https://github.com/opencontainers/runc/blob/3f6594675675d4e88901c782462f56497260b1d2/libcontainer/cgroups/fs/memory.go#L89 if is_updated { - Self::set_swap(swap, cgroup_root)?; - Self::set_memory(limit, cgroup_root)?; + Self::set_swap(swap, cgroup_root).await?; + Self::set_memory(limit, cgroup_root).await?; } - Self::set_memory(limit, cgroup_root)?; - Self::set_swap(swap, cgroup_root)?; + Self::set_memory(limit, cgroup_root).await?; + Self::set_swap(swap, cgroup_root).await?; Ok(()) } - fn apply(resource: &LinuxMemory, cgroup_root: &Path) -> Result<()> { + async fn apply(resource: &LinuxMemory, cgroup_root: &Path) -> Result<()> { match resource.limit { Some(limit) => { - let current_limit = Self::get_memory_limit(cgroup_root)?; + let current_limit = Self::get_memory_limit(cgroup_root).await?; match resource.swap { Some(swap) => { let is_updated = swap == -1 || current_limit < swap; - Self::set_memory_and_swap(limit, swap, is_updated, cgroup_root)?; + Self::set_memory_and_swap(limit, swap, is_updated, cgroup_root).await?; } None => { if limit == -1 { - Self::set_memory_and_swap(limit, -1, true, cgroup_root)?; + Self::set_memory_and_swap(limit, -1, true, cgroup_root).await?; } else { let is_updated = current_limit < 0; - Self::set_memory_and_swap(limit, 0, is_updated, cgroup_root)?; + Self::set_memory_and_swap(limit, 0, is_updated, cgroup_root).await?; } } } } None => match resource.swap { - Some(swap) => Self::set_memory_and_swap(0, swap, false, cgroup_root)?, - None => Self::set_memory_and_swap(0, 0, false, cgroup_root)?, + Some(swap) => { + Self::set_memory_and_swap(0, swap, false, cgroup_root).await?; + } + None => { + Self::set_memory_and_swap(0, 0, false, cgroup_root).await?; + } }, } Ok(()) @@ -239,15 +244,17 @@ impl Memory { #[cfg(test)] mod tests { use super::*; + use std::io::Write; use oci_spec::LinuxMemory; fn set_fixture(temp_dir: &std::path::Path, filename: &str, val: &str) -> Result<()> { - std::fs::OpenOptions::new() + let mut file = std::fs::OpenOptions::new() .create(true) .write(true) .truncate(true) - .open(temp_dir.join(filename))? - .write_all(val.as_bytes())?; + .open(temp_dir.join(filename))?; + file.write_all(val.as_bytes())?; + file.sync_all()?; Ok(()) } @@ -264,23 +271,13 @@ mod tests { set_fixture(&tmp, CGROUP_MEMORY_USAGE, "0").expect("Set fixure for memory usage"); set_fixture(&tmp, CGROUP_MEMORY_MAX_USAGE, "0").expect("Set fixure for max memory usage"); set_fixture(&tmp, CGROUP_MEMORY_LIMIT, "0").expect("Set fixure for memory limit"); - Memory::set_memory(limit, &tmp).expect("Set memory limit"); - let content = - std::fs::read_to_string(tmp.join(CGROUP_MEMORY_LIMIT)).expect("Read to string"); - assert_eq!(limit.to_string(), content) - } - #[test] - fn pass_set_memory_if_limit_is_zero() { - let sample_val = "1024"; - let limit = 0; - let tmp = create_temp_dir("pass_set_memory_if_limit_is_zero") - .expect("create temp directory for test"); - set_fixture(&tmp, CGROUP_MEMORY_LIMIT, sample_val).expect("Set fixure for memory limit"); - Memory::set_memory(limit, &tmp).expect("Set memory limit"); - let content = - std::fs::read_to_string(tmp.join(CGROUP_MEMORY_LIMIT)).expect("Read to string"); - assert_eq!(content, sample_val) + smol::block_on(async { + Memory::set_memory(limit, &tmp).await.expect("Set memory limit"); + let content = + std::fs::read_to_string(tmp.join(CGROUP_MEMORY_LIMIT)).expect("Read to string"); + assert_eq!(limit.to_string(), content) + }); } #[test] @@ -288,10 +285,13 @@ mod tests { let limit = 512; let tmp = create_temp_dir("test_set_swap").expect("create temp directory for test"); set_fixture(&tmp, CGROUP_MEMORY_SWAP_LIMIT, "0").expect("Set fixure for swap limit"); - Memory::set_swap(limit, &tmp).expect("Set swap limit"); - let content = - std::fs::read_to_string(tmp.join(CGROUP_MEMORY_SWAP_LIMIT)).expect("Read to string"); - assert_eq!(limit.to_string(), content) + + smol::block_on(async { + Memory::set_swap(limit, &tmp).await.expect("Set swap limit"); + let content = + std::fs::read_to_string(tmp.join(CGROUP_MEMORY_SWAP_LIMIT)).expect("Read to string"); + assert_eq!(limit.to_string(), content) + }); } #[test] @@ -304,30 +304,30 @@ mod tests { set_fixture(&tmp, CGROUP_MEMORY_SWAP_LIMIT, "0").expect("Set fixure for swap limit"); // test unlimited memory with no set swap - { - let limit = -1; - let linux_memory = &LinuxMemory { - limit: Some(limit), - swap: None, // Some(0) gives the same outcome - reservation: None, - kernel: None, - kernel_tcp: None, - swappiness: None, - }; - Memory::apply(linux_memory, &tmp).expect("Set memory and swap"); - - let limit_content = - std::fs::read_to_string(tmp.join(CGROUP_MEMORY_LIMIT)).expect("Read to string"); - assert_eq!(limit.to_string(), limit_content); - - let swap_content = std::fs::read_to_string(tmp.join(CGROUP_MEMORY_SWAP_LIMIT)) - .expect("Read to string"); - // swap should be set to -1 also - assert_eq!(limit.to_string(), swap_content); - } + smol::block_on(async { + let limit = -1; + let linux_memory = &LinuxMemory { + limit: Some(limit), + swap: None, // Some(0) gives the same outcome + reservation: None, + kernel: None, + kernel_tcp: None, + swappiness: None, + }; + Memory::apply(linux_memory, &tmp).await.expect("Set memory and swap"); + + let limit_content = + std::fs::read_to_string(tmp.join(CGROUP_MEMORY_LIMIT)).expect("Read to string"); + assert_eq!(limit.to_string(), limit_content); + + let swap_content = std::fs::read_to_string(tmp.join(CGROUP_MEMORY_SWAP_LIMIT)) + .expect("Read to string"); + // swap should be set to -1 also + assert_eq!(limit.to_string(), swap_content); + }); // test setting swap and memory to arbitrary values - { + smol::block_on(async { let limit = 1024 * 1024 * 1024; let swap = 1024; let linux_memory = &LinuxMemory { @@ -338,15 +338,17 @@ mod tests { kernel_tcp: None, swappiness: None, }; - Memory::apply(linux_memory, &tmp).expect("Set memory and swap"); - - let limit_content = - std::fs::read_to_string(tmp.join(CGROUP_MEMORY_LIMIT)).expect("Read to string"); - assert_eq!(limit.to_string(), limit_content); - - let swap_content = std::fs::read_to_string(tmp.join(CGROUP_MEMORY_SWAP_LIMIT)) - .expect("Read to string"); - assert_eq!(swap.to_string(), swap_content); - } + smol::block_on(async { + Memory::apply(linux_memory, &tmp).await.expect("Set memory and swap"); + + let limit_content = + std::fs::read_to_string(tmp.join(CGROUP_MEMORY_LIMIT)).expect("Read to string"); + assert_eq!(limit.to_string(), limit_content); + + let swap_content = std::fs::read_to_string(tmp.join(CGROUP_MEMORY_SWAP_LIMIT)) + .expect("Read to string"); + assert_eq!(swap.to_string(), swap_content); + }); + }); } } diff --git a/src/cgroups/network_classifier.rs b/src/cgroups/network_classifier.rs index c6df7448d..9ff012e71 100644 --- a/src/cgroups/network_classifier.rs +++ b/src/cgroups/network_classifier.rs @@ -1,11 +1,9 @@ -use std::io::Write; -use std::{ - fs::{create_dir_all, OpenOptions}, - path::Path, -}; +use std::path::Path; use anyhow::Result; +use async_trait::async_trait; use nix::unistd::Pid; +use smol::{fs::{OpenOptions, create_dir_all}, io::AsyncWriteExt}; use crate::{ cgroups::Controller, @@ -14,20 +12,23 @@ use oci_spec::{LinuxNetwork, LinuxResources}; pub struct NetworkClassifier {} +#[async_trait] impl Controller for NetworkClassifier { - fn apply(linux_resources: &LinuxResources, cgroup_root: &Path, pid: Pid) -> Result<()> { + async fn apply(linux_resources: &LinuxResources, cgroup_root: &Path, pid: Pid) -> Result<()> { log::debug!("Apply NetworkClassifier cgroup config"); - create_dir_all(&cgroup_root)?; + create_dir_all(&cgroup_root).await?; if let Some(network) = linux_resources.network.as_ref() { - Self::apply(cgroup_root, network)?; + Self::apply(cgroup_root, network).await?; - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(cgroup_root.join("cgroup.procs"))? - .write_all(pid.to_string().as_bytes())?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; } Ok(()) @@ -35,21 +36,23 @@ impl Controller for NetworkClassifier { } impl NetworkClassifier { - fn apply(root_path: &Path, network: &LinuxNetwork) -> Result<()> { + async fn apply(root_path: &Path, network: &LinuxNetwork) -> Result<()> { if let Some(class_id) = network.class_id { - Self::write_file(&root_path.join("net_cls.classid"), &class_id.to_string())?; + Self::write_file(&root_path.join("net_cls.classid"), &class_id.to_string()).await?; } Ok(()) } - fn write_file(file_path: &Path, data: &str) -> Result<()> { - OpenOptions::new() + async fn write_file(file_path: &Path, data: &str) -> Result<()> { + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path)? - .write_all(data.as_bytes())?; + .open(file_path).await?; + + file.write_all(data.as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -58,16 +61,19 @@ impl NetworkClassifier { #[cfg(test)] mod tests { use std::path::PathBuf; + use std::io::Write; use super::*; fn set_fixture(temp_dir: &std::path::Path, filename: &str, val: &str) -> Result<()> { - std::fs::OpenOptions::new() + let mut file = std::fs::OpenOptions::new() .create(true) .write(true) .truncate(true) - .open(temp_dir.join(filename))? - .write_all(val.as_bytes())?; + .open(temp_dir.join(filename))?; + + file.write_all(val.as_bytes())?; + file.sync_data()?; Ok(()) } @@ -83,16 +89,18 @@ mod tests { .expect("create temp directory for test"); set_fixture(&tmp, "net_cls.classid", "0").expect("set fixture for classID"); - let id = 0x100001; - let network = LinuxNetwork { - class_id: Some(id), - priorities: vec![], - }; + smol::block_on(async { + let id = 0x100001; + let network = LinuxNetwork { + class_id: Some(id), + priorities: vec![], + }; - NetworkClassifier::apply(&tmp, &network).expect("apply network classID"); + NetworkClassifier::apply(&tmp, &network).await.expect("apply network classID"); - let content = - std::fs::read_to_string(tmp.join("net_cls.classid")).expect("Read classID contents"); - assert_eq!(id.to_string(), content); + let content = + std::fs::read_to_string(tmp.join("net_cls.classid")).expect("Read classID contents"); + assert_eq!(id.to_string(), content); + }); } } diff --git a/src/cgroups/network_priority.rs b/src/cgroups/network_priority.rs index 291ca9df5..12b50a35c 100644 --- a/src/cgroups/network_priority.rs +++ b/src/cgroups/network_priority.rs @@ -1,31 +1,32 @@ -use std::io::Write; -use std::{ - fs::{create_dir_all, OpenOptions}, - path::Path, -}; +use std::path::Path; use anyhow::Result; +use async_trait::async_trait; use nix::unistd::Pid; +use smol::{fs::{OpenOptions, create_dir_all}, io::AsyncWriteExt}; use crate::cgroups::Controller; use oci_spec::{LinuxNetwork, LinuxResources}; pub struct NetworkPriority {} +#[async_trait] impl Controller for NetworkPriority { - fn apply(linux_resources: &LinuxResources, cgroup_root: &Path, pid: Pid) -> Result<()> { + async fn apply(linux_resources: &LinuxResources, cgroup_root: &Path, pid: Pid) -> Result<()> { log::debug!("Apply NetworkPriority cgroup config"); - create_dir_all(&cgroup_root)?; + create_dir_all(&cgroup_root).await?; if let Some(network) = linux_resources.network.as_ref() { - Self::apply(cgroup_root, network)?; + Self::apply(cgroup_root, network).await?; - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(cgroup_root.join("cgroup.procs"))? - .write_all(pid.to_string().as_bytes())?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; } Ok(()) @@ -33,20 +34,22 @@ impl Controller for NetworkPriority { } impl NetworkPriority { - fn apply(root_path: &Path, network: &LinuxNetwork) -> Result<()> { + async fn apply(root_path: &Path, network: &LinuxNetwork) -> Result<()> { let priorities: String = network.priorities.iter().map(|p| p.to_string()).collect(); - Self::write_file(&root_path.join("net_prio.ifpriomap"), &priorities.trim())?; + Self::write_file(&root_path.join("net_prio.ifpriomap"), &priorities.trim()).await?; Ok(()) } - fn write_file(file_path: &Path, data: &str) -> Result<()> { - OpenOptions::new() + async fn write_file(file_path: &Path, data: &str) -> Result<()> { + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path)? - .write_all(data.as_bytes())?; + .open(file_path).await?; + + file.write_all(data.as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -55,17 +58,20 @@ impl NetworkPriority { #[cfg(test)] mod tests { use std::path::PathBuf; + use std::io::Write; use super::*; use oci_spec::LinuxInterfacePriority; fn set_fixture(temp_dir: &std::path::Path, filename: &str, val: &str) -> Result<()> { - std::fs::OpenOptions::new() + let mut file = std::fs::OpenOptions::new() .create(true) .write(true) .truncate(true) - .open(temp_dir.join(filename))? - .write_all(val.as_bytes())?; + .open(temp_dir.join(filename))?; + + file.write_all(val.as_bytes())?; + file.sync_data()?; Ok(()) } @@ -80,26 +86,33 @@ mod tests { let tmp = create_temp_dir("test_apply_network_priorites") .expect("create temp directory for test"); set_fixture(&tmp, "net_prio.ifpriomap", "").expect("set fixture for priority map"); - let priorities = vec![ - LinuxInterfacePriority { - name: "a".to_owned(), - priority: 1, - }, - LinuxInterfacePriority { - name: "b".to_owned(), - priority: 2, - }, - ]; - let priorities_string = priorities.iter().map(|p| p.to_string()).collect::(); - let network = LinuxNetwork { - class_id: None, - priorities, - }; - - NetworkPriority::apply(&tmp, &network).expect("apply network priorities"); - - let content = - std::fs::read_to_string(tmp.join("net_prio.ifpriomap")).expect("Read classID contents"); - assert_eq!(priorities_string.trim(), content); + + smol::block_on(async { + let priorities = vec![ + LinuxInterfacePriority { + name: "a".to_owned(), + priority: 1, + }, + LinuxInterfacePriority { + name: "b".to_owned(), + priority: 2, + }, + ]; + let priorities_string = priorities + .clone() + .iter() + .map(|p| p.to_string()) + .collect::(); + let network = LinuxNetwork { + class_id: None, + priorities, + }; + + NetworkPriority::apply(&tmp, &network).await.expect("apply network priorities"); + + let content = + std::fs::read_to_string(tmp.join("net_prio.ifpriomap")).expect("Read classID contents"); + assert_eq!(priorities_string.trim(), content); + }); } } diff --git a/src/cgroups/pids.rs b/src/cgroups/pids.rs index df6d5b9c9..82bfc96cc 100644 --- a/src/cgroups/pids.rs +++ b/src/cgroups/pids.rs @@ -1,10 +1,8 @@ -use std::{ - fs::{self, OpenOptions}, - io::Write, - path::Path, -}; +use std::path::Path; use anyhow::Result; +use async_trait::async_trait; +use smol::{fs::{OpenOptions, create_dir_all}, io::AsyncWriteExt}; use crate::{ cgroups::Controller, @@ -13,47 +11,52 @@ use oci_spec::{LinuxPids, LinuxResources}; pub struct Pids {} +#[async_trait] impl Controller for Pids { - fn apply( + async fn apply( linux_resources: &LinuxResources, cgroup_root: &std::path::Path, pid: nix::unistd::Pid, ) -> anyhow::Result<()> { - fs::create_dir_all(cgroup_root)?; + create_dir_all(cgroup_root).await?; for pids in &linux_resources.pids { - Self::apply(cgroup_root, pids)? + Self::apply(cgroup_root, pids).await? } - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(cgroup_root.join("cgroup.procs"))? - .write_all(pid.to_string().as_bytes())?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; Ok(()) } } impl Pids { - fn apply(root_path: &Path, pids: &LinuxPids) -> Result<()> { + async fn apply(root_path: &Path, pids: &LinuxPids) -> Result<()> { let limit = if pids.limit > 0 { pids.limit.to_string() } else { "max".to_string() }; - Self::write_file(&root_path.join("pids.max"), &limit)?; + Self::write_file(&root_path.join("pids.max"), &limit).await?; Ok(()) } - fn write_file(file_path: &Path, data: &str) -> Result<()> { - fs::OpenOptions::new() + async fn write_file(file_path: &Path, data: &str) -> Result<()> { + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path)? - .write_all(data.as_bytes())?; + .open(file_path).await?; + + file.write_all(data.as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -63,14 +66,17 @@ impl Pids { mod tests { use super::*; use oci_spec::LinuxPids; + use std::io::Write; fn set_fixture(temp_dir: &std::path::Path, filename: &str, val: &str) -> Result<()> { - std::fs::OpenOptions::new() + let mut file = std::fs::OpenOptions::new() .create(true) .write(true) .truncate(true) - .open(temp_dir.join(filename))? - .write_all(val.as_bytes())?; + .open(temp_dir.join(filename))?; + + file.write_all(val.as_bytes())?; + file.sync_data()?; Ok(()) } @@ -86,12 +92,14 @@ mod tests { let tmp = create_temp_dir("test_set_pids").expect("create temp directory for test"); set_fixture(&tmp, pids_file_name, "1000").expect("Set fixture for 1000 pids"); - let pids = LinuxPids { limit: 1000 }; + smol::block_on(async { + let pids = LinuxPids { limit: 1000 }; - Pids::apply(&tmp, &pids).expect("apply pids"); - let content = - std::fs::read_to_string(tmp.join(pids_file_name)).expect("Read pids contents"); - assert_eq!(pids.limit.to_string(), content); + Pids::apply(&tmp, &pids).await.expect("apply pids"); + let content = + std::fs::read_to_string(tmp.join(pids_file_name)).expect("Read pids contents"); + assert_eq!(pids.limit.to_string(), content); + }); } #[test] @@ -100,12 +108,15 @@ mod tests { let tmp = create_temp_dir("test_set_pids_max").expect("create temp directory for test"); set_fixture(&tmp, pids_file_name, "0").expect("set fixture for 0 pids"); - let pids = LinuxPids { limit: 0 }; - Pids::apply(&tmp, &pids).expect("apply pids"); + smol::block_on(async { + let pids = LinuxPids { limit: 0 }; + + Pids::apply(&tmp, &pids).await.expect("apply pids"); - let content = - std::fs::read_to_string(tmp.join(pids_file_name)).expect("Read pids contents"); - assert_eq!("max".to_string(), content); + let content = + std::fs::read_to_string(tmp.join(pids_file_name)).expect("Read pids contents"); + assert_eq!("max".to_string(), content); + }); } }