From f8f35e8d39cba6dcb37b2d5a5a47e855418fd810 Mon Sep 17 00:00:00 2001 From: tsturzl Date: Tue, 25 May 2021 15:04:21 -0600 Subject: [PATCH 01/14] time to write tests --- Cargo.lock | 396 +++++++++++++++++++++++++----- Cargo.toml | 2 + src/cgroups/blkio.rs | 39 +-- src/cgroups/controller.rs | 4 +- src/cgroups/devices.rs | 23 +- src/cgroups/hugetlb.rs | 32 +-- src/cgroups/manager.rs | 30 ++- src/cgroups/memory.rs | 85 +++---- src/cgroups/network_classifier.rs | 25 +- src/cgroups/network_priority.rs | 29 ++- src/cgroups/pids.rs | 32 +-- 11 files changed, 491 insertions(+), 206 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ef201813..55716e223 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "adler" version = "1.0.2" @@ -17,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 = "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 = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" +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" @@ -44,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", @@ -63,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" @@ -118,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" @@ -148,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" @@ -162,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", @@ -177,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", @@ -187,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", @@ -205,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", @@ -223,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", @@ -291,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" @@ -313,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" @@ -344,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", @@ -357,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", ] @@ -377,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" @@ -417,9 +617,9 @@ dependencies = [ [[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" @@ -427,6 +627,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" @@ -439,6 +645,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" @@ -446,7 +665,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "059a34f111a9dee2ce1ac2826a68b24601c4298cfeb1a587c3cb493d5ab46f52" dependencies = [ "libc", - "nix", + "nix 0.20.0", ] [[package]] @@ -487,9 +706,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", ] @@ -511,9 +730,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", ] @@ -543,18 +762,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", @@ -563,28 +782,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", ] @@ -597,9 +852,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", @@ -626,18 +881,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", @@ -669,9 +924,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" @@ -681,9 +936,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" @@ -691,6 +952,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" @@ -727,6 +997,7 @@ name = "youki" version = "0.0.1" dependencies = [ "anyhow", + "async-trait", "caps", "chrono", "clap", @@ -734,11 +1005,12 @@ dependencies = [ "libc", "log", "mio", - "nix", + "nix 0.19.1", "once_cell", "prctl", "procfs", "regex", "serde", "serde_json", + "smol", ] diff --git a/Cargo.toml b/Cargo.toml index eb8f2e502..7f809ebe0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,5 @@ 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" diff --git a/src/cgroups/blkio.rs b/src/cgroups/blkio.rs index c1e34a4ff..802767e9c 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,8 +26,8 @@ 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?; } } @@ -34,53 +35,53 @@ impl Controller for Blkio { .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? + .write_all(pid.to_string().as_bytes()).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<()> { + OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(file_path)? - .write_all(data.as_bytes())?; + .open(file_path).await? + .write_all(data.as_bytes()).await?; Ok(()) } diff --git a/src/cgroups/controller.rs b/src/cgroups/controller.rs index a82bcb8a5..ea362ef1c 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 crate::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 eb5d4b40b..9a9fe0762 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, @@ -35,13 +35,14 @@ impl ToString for LinuxDeviceCgroup { 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?; for d in &linux_resources.devices { - Self::apply_device(d, cgroup_root)?; + Self::apply_device(d, cgroup_root).await?; } for d in [ @@ -50,21 +51,21 @@ impl Controller for Devices { ] .concat() { - Self::apply_device(&d, &cgroup_root)?; + Self::apply_device(&d, &cgroup_root).await?; } 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? + .write_all(pid.to_string().as_bytes()).await?; Ok(()) } } impl Devices { - fn apply_device(device: &LinuxDeviceCgroup, cgroup_root: &Path) -> Result<()> { + async fn apply_device(device: &LinuxDeviceCgroup, cgroup_root: &Path) -> Result<()> { let path = if device.allow { cgroup_root.join("devices.allow") } else { @@ -75,8 +76,8 @@ impl Devices { .create(false) .write(true) .truncate(false) - .open(path)? - .write_all(device.to_string().as_bytes())?; + .open(path).await? + .write_all(device.to_string().as_bytes()).await?; Ok(()) } diff --git a/src/cgroups/hugetlb.rs b/src/cgroups/hugetlb.rs index 0f9f60c8a..50a79cd0e 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,32 @@ use crate::{ 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() .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? + .write_all(pid.to_string().as_bytes()).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 +53,17 @@ 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<()> { + OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path)? - .write_all(data.as_bytes())?; + .open(file_path).await? + .write_all(data.as_bytes()).await?; Ok(()) } @@ -80,6 +79,7 @@ mod tests { use super::*; use crate::spec::LinuxHugepageLimit; + use std::io::Write; fn set_fixture(temp_dir: &std::path::Path, filename: &str, val: &str) -> anyhow::Result<()> { std::fs::OpenOptions::new() diff --git a/src/cgroups/manager.rs b/src/cgroups/manager.rs index b6d59523c..59b02018a 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::join_all; use anyhow::Result; use nix::unistd::Pid; @@ -41,20 +42,25 @@ 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 { + let futures = Vec::with_capacity(7); + for subsys in &self.subsystems { + futures.push(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, + }); } - } - Ok(()) + join_all(futures); + + Ok(()) + }) } pub fn remove(&self) -> Result<()> { diff --git a/src/cgroups/memory.rs b/src/cgroups/memory.rs index 3490f4fef..85f854ff0 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,32 @@ 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() .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? + .write_all(pid.to_string().as_bytes()).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 +99,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 +118,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,17 +137,17 @@ impl Memory { Ok(val) } - fn set(val: T, path: &Path) -> std::io::Result<()> { + async fn set(val: T, path: &Path) -> std::io::Result<()> { OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(path)? - .write_all(val.to_string().as_bytes())?; + .open(path).await? + .write_all(val.to_string().as_bytes()).await?; Ok(()) } - fn set_memory(val: i64, cgroup_root: &Path) -> Result<()> { + async fn set_memory(val: i64, cgroup_root: &Path) -> Result<()> { let path = cgroup_root.join(CGROUP_MEMORY_LIMIT); match Self::set(val, &path) { @@ -156,8 +157,8 @@ impl Memory { 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?; Err(anyhow!( "unable to set memory limit to {} (current usage: {}, peak usage: {})", val, @@ -173,19 +174,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, @@ -197,39 +198,39 @@ 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)?; + Self::set_memory_and_swap(0, swap, false, cgroup_root).await?; } None => { - Self::set_memory_and_swap(0, 0, false, cgroup_root)?; + Self::set_memory_and_swap(0, 0, false, cgroup_root).await?; } }, } diff --git a/src/cgroups/network_classifier.rs b/src/cgroups/network_classifier.rs index 6b9e1fa37..f3d918c93 100644 --- a/src/cgroups/network_classifier.rs +++ b/src/cgroups/network_classifier.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, @@ -14,20 +14,21 @@ use crate::{ 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() .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? + .write_all(pid.to_string().as_bytes()).await?; } Ok(()) @@ -35,21 +36,21 @@ 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<()> { + async fn write_file(file_path: &Path, data: &str) -> Result<()> { OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path)? - .write_all(data.as_bytes())?; + .open(file_path).await? + .write_all(data.as_bytes()).await?; Ok(()) } diff --git a/src/cgroups/network_priority.rs b/src/cgroups/network_priority.rs index a895e379c..c5e07ce14 100644 --- a/src/cgroups/network_priority.rs +++ b/src/cgroups/network_priority.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, @@ -20,20 +18,21 @@ impl ToString for LinuxInterfacePriority { 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() .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? + .write_all(pid.to_string().as_bytes()).await?; } Ok(()) @@ -41,20 +40,20 @@ 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<()> { + async fn write_file(file_path: &Path, data: &str) -> Result<()> { OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path)? - .write_all(data.as_bytes())?; + .open(file_path).await? + .write_all(data.as_bytes()).await?; Ok(()) } diff --git a/src/cgroups/pids.rs b/src/cgroups/pids.rs index f86709641..0c995b5e0 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,48 @@ use crate::{ 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() .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? + .write_all(pid.to_string().as_bytes()).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<()> { + OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path)? - .write_all(data.as_bytes())?; + .open(file_path).await? + .write_all(data.as_bytes()).await?; Ok(()) } @@ -63,6 +62,7 @@ impl Pids { mod tests { use super::*; use crate::spec::LinuxPids; + use std::io::Write; fn set_fixture(temp_dir: &std::path::Path, filename: &str, val: &str) -> Result<()> { std::fs::OpenOptions::new() From 7579fcfdb777adfa7f02ab18d7be98500124fb1c Mon Sep 17 00:00:00 2001 From: Travis Sturzl Date: Wed, 26 May 2021 12:17:49 -0600 Subject: [PATCH 02/14] actively testing --- src/cgroups/blkio.rs | 117 ++++++++++++++++-------------- src/cgroups/hugetlb.rs | 40 +++++----- src/cgroups/manager.rs | 61 +++++++++++----- src/cgroups/memory.rs | 63 +++++++++------- src/cgroups/network_classifier.rs | 21 +++--- src/cgroups/network_priority.rs | 54 +++++++------- src/cgroups/pids.rs | 27 ++++--- 7 files changed, 222 insertions(+), 161 deletions(-) diff --git a/src/cgroups/blkio.rs b/src/cgroups/blkio.rs index 802767e9c..c5745f11e 100644 --- a/src/cgroups/blkio.rs +++ b/src/cgroups/blkio.rs @@ -93,6 +93,7 @@ mod tests { use super::*; use crate::spec::{LinuxBlockIo, LinuxThrottleDevice}; + use std::io::Write; struct BlockIoBuilder { block_io: LinuxBlockIo, @@ -173,19 +174,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) - .expect(&format!("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] @@ -193,19 +196,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) - .expect(&format!("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] @@ -213,19 +218,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) - .expect(&format!("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] @@ -235,20 +242,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).expect(&format!( - "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/hugetlb.rs b/src/cgroups/hugetlb.rs index 50a79cd0e..d3d8dc4f3 100644 --- a/src/cgroups/hugetlb.rs +++ b/src/cgroups/hugetlb.rs @@ -103,14 +103,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 +120,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 59b02018a..8c761e651 100644 --- a/src/cgroups/manager.rs +++ b/src/cgroups/manager.rs @@ -43,21 +43,40 @@ impl Manager { pub fn apply(&self, linux_resources: &LinuxResources, pid: Pid) -> Result<()> { smol::block_on(async { - let futures = Vec::with_capacity(7); - for subsys in &self.subsystems { - futures.push(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, - }); - } + // let futures = Vec::with_capacity(7); + // for subsys in &self.subsystems { + // futures.push(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, + // }); + // } + + let futures = 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::>(); - join_all(futures); + join_all(futures).await.iter() + .for_each(|result| { + result.as_ref().expect("Cgroup controller future returned a failure"); + }); Ok(()) }) @@ -84,14 +103,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 85f854ff0..642b040d0 100644 --- a/src/cgroups/memory.rs +++ b/src/cgroups/memory.rs @@ -150,7 +150,7 @@ impl Memory { 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 @@ -241,6 +241,7 @@ impl Memory { #[cfg(test)] mod tests { use super::*; + use std::io::Write; use crate::spec::LinuxMemory; fn set_fixture(temp_dir: &std::path::Path, filename: &str, val: &str) -> Result<()> { @@ -266,10 +267,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) + + 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] @@ -277,10 +281,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] @@ -303,16 +310,18 @@ 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"); - // swap should be set to -1 also - assert_eq!(limit.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"); + // swap should be set to -1 also + assert_eq!(limit.to_string(), swap_content); + }); } // test setting swap and memory to arbitrary values @@ -327,15 +336,17 @@ mod tests { kernel_tcp: None, swappiness: None, }; - Memory::apply(linux_memory, &tmp).expect("Set memory and swap"); + 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 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); + 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 f3d918c93..0d38b0351 100644 --- a/src/cgroups/network_classifier.rs +++ b/src/cgroups/network_classifier.rs @@ -59,6 +59,7 @@ impl NetworkClassifier { #[cfg(test)] mod tests { use std::path::PathBuf; + use std::io::Write; use super::*; @@ -84,16 +85,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 c5e07ce14..eadf924a0 100644 --- a/src/cgroups/network_priority.rs +++ b/src/cgroups/network_priority.rs @@ -62,6 +62,7 @@ impl NetworkPriority { #[cfg(test)] mod tests { use std::path::PathBuf; + use std::io::Write; use super::*; @@ -86,30 +87,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 - .clone() - .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 0c995b5e0..fa005ed8c 100644 --- a/src/cgroups/pids.rs +++ b/src/cgroups/pids.rs @@ -86,12 +86,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 }; - - 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); + smol::block_on(async { + let pids = LinuxPids { limit: 1000 }; + + 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 +102,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); + }); } } From 77a0eea1e7428af919ba1e6c9e804afa5cabe278 Mon Sep 17 00:00:00 2001 From: Travis Sturzl Date: Wed, 26 May 2021 15:34:00 -0600 Subject: [PATCH 03/14] unit tests passing, some integration tests still fail --- src/cgroups/blkio.rs | 24 ++++++++++------ src/cgroups/devices.rs | 16 +++++++---- src/cgroups/hugetlb.rs | 24 ++++++++++------ src/cgroups/manager.rs | 14 ---------- src/cgroups/memory.rs | 46 ++++++++++++++++--------------- src/cgroups/network_classifier.rs | 28 +++++++++++-------- src/cgroups/network_priority.rs | 24 ++++++++++------ src/cgroups/pids.rs | 24 ++++++++++------ 8 files changed, 110 insertions(+), 90 deletions(-) diff --git a/src/cgroups/blkio.rs b/src/cgroups/blkio.rs index c5745f11e..3d4b59cde 100644 --- a/src/cgroups/blkio.rs +++ b/src/cgroups/blkio.rs @@ -31,12 +31,14 @@ impl Controller for Blkio { } } - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(cgroup_root.join("cgroup.procs")).await? - .write_all(pid.to_string().as_bytes()).await?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -76,12 +78,14 @@ impl Blkio { } async fn write_file(file_path: &Path, data: &str) -> anyhow::Result<()> { - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(file_path).await? - .write_all(data.as_bytes()).await?; + .open(file_path).await?; + + file.write_all(data.as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -154,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) } diff --git a/src/cgroups/devices.rs b/src/cgroups/devices.rs index 9a9fe0762..319178404 100644 --- a/src/cgroups/devices.rs +++ b/src/cgroups/devices.rs @@ -54,12 +54,14 @@ impl Controller for Devices { Self::apply_device(&d, &cgroup_root).await?; } - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(cgroup_root.join("cgroup.procs")).await? - .write_all(pid.to_string().as_bytes()).await?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; Ok(()) } } @@ -72,12 +74,14 @@ impl Devices { cgroup_root.join("devices.deny") }; - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(path).await? - .write_all(device.to_string().as_bytes()).await?; + .open(path).await?; + + file.write_all(device.to_string().as_bytes()).await?; + file.sync_data().await?; Ok(()) } diff --git a/src/cgroups/hugetlb.rs b/src/cgroups/hugetlb.rs index d3d8dc4f3..eb049b10d 100644 --- a/src/cgroups/hugetlb.rs +++ b/src/cgroups/hugetlb.rs @@ -26,12 +26,14 @@ impl Controller for 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")).await? - .write_all(pid.to_string().as_bytes()).await?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; Ok(()) } } @@ -58,12 +60,14 @@ impl Hugetlb { } async fn write_file(file_path: &Path, data: &str) -> anyhow::Result<()> { - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path).await? - .write_all(data.as_bytes()).await?; + .open(file_path).await?; + + file.write_all(data.as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -82,12 +86,14 @@ mod tests { 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(()) } diff --git a/src/cgroups/manager.rs b/src/cgroups/manager.rs index 8c761e651..3c85244ce 100644 --- a/src/cgroups/manager.rs +++ b/src/cgroups/manager.rs @@ -43,20 +43,6 @@ impl Manager { pub fn apply(&self, linux_resources: &LinuxResources, pid: Pid) -> Result<()> { smol::block_on(async { - // let futures = Vec::with_capacity(7); - // for subsys in &self.subsystems { - // futures.push(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, - // }); - // } - let futures = self.subsystems.iter() .filter_map(|entry| { let key = entry.0.as_str(); diff --git a/src/cgroups/memory.rs b/src/cgroups/memory.rs index 642b040d0..837beb956 100644 --- a/src/cgroups/memory.rs +++ b/src/cgroups/memory.rs @@ -68,12 +68,14 @@ impl Controller for Memory { 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")).await? - .write_all(pid.to_string().as_bytes()).await?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_all().await?; } Ok(()) } @@ -138,12 +140,13 @@ impl Memory { } async fn set(val: T, path: &Path) -> std::io::Result<()> { - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(path).await? - .write_all(val.to_string().as_bytes()).await?; + .open(path).await?; + file.write_all(val.to_string().as_bytes()).await?; + file.sync_all().await?; Ok(()) } @@ -245,12 +248,13 @@ mod tests { use crate::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(()) } @@ -300,17 +304,16 @@ 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, - }; 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 = @@ -322,10 +325,9 @@ mod tests { // 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 { @@ -347,6 +349,6 @@ mod tests { .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 0d38b0351..d25f36da1 100644 --- a/src/cgroups/network_classifier.rs +++ b/src/cgroups/network_classifier.rs @@ -1,6 +1,4 @@ -use std::{ - path::Path, -}; +use std::path::Path; use anyhow::Result; use async_trait::async_trait; @@ -23,12 +21,14 @@ impl Controller for NetworkClassifier { if let Some(network) = linux_resources.network.as_ref() { 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")).await? - .write_all(pid.to_string().as_bytes()).await?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; } Ok(()) @@ -45,12 +45,14 @@ impl NetworkClassifier { } async fn write_file(file_path: &Path, data: &str) -> Result<()> { - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path).await? - .write_all(data.as_bytes()).await?; + .open(file_path).await?; + + file.write_all(data.as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -64,12 +66,14 @@ mod tests { 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(()) } diff --git a/src/cgroups/network_priority.rs b/src/cgroups/network_priority.rs index eadf924a0..25ec1398c 100644 --- a/src/cgroups/network_priority.rs +++ b/src/cgroups/network_priority.rs @@ -27,12 +27,14 @@ impl Controller for NetworkPriority { if let Some(network) = linux_resources.network.as_ref() { 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")).await? - .write_all(pid.to_string().as_bytes()).await?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; } Ok(()) @@ -48,12 +50,14 @@ impl NetworkPriority { } async fn write_file(file_path: &Path, data: &str) -> Result<()> { - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path).await? - .write_all(data.as_bytes()).await?; + .open(file_path).await?; + + file.write_all(data.as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -67,12 +71,14 @@ mod tests { 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(()) } diff --git a/src/cgroups/pids.rs b/src/cgroups/pids.rs index fa005ed8c..b9273df7d 100644 --- a/src/cgroups/pids.rs +++ b/src/cgroups/pids.rs @@ -24,12 +24,14 @@ impl Controller for 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")).await? - .write_all(pid.to_string().as_bytes()).await?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; Ok(()) } } @@ -47,12 +49,14 @@ impl Pids { } async fn write_file(file_path: &Path, data: &str) -> Result<()> { - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path).await? - .write_all(data.as_bytes()).await?; + .open(file_path).await?; + + file.write_all(data.as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -65,12 +69,14 @@ mod tests { 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(()) } From 61f895b767b67270005b427006150797a7b28d6c Mon Sep 17 00:00:00 2001 From: Travis Sturzl Date: Thu, 27 May 2021 21:19:19 -0600 Subject: [PATCH 04/14] try_join_all is cleaner --- src/cgroups/manager.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/cgroups/manager.rs b/src/cgroups/manager.rs index 3c85244ce..a8f51172a 100644 --- a/src/cgroups/manager.rs +++ b/src/cgroups/manager.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, path::PathBuf}; use std::{fs::remove_dir, path::Path}; -use futures::future::join_all; +use futures::future::try_join_all; use anyhow::Result; use nix::unistd::Pid; @@ -43,7 +43,7 @@ impl Manager { pub fn apply(&self, linux_resources: &LinuxResources, pid: Pid) -> Result<()> { smol::block_on(async { - let futures = self.subsystems.iter() + try_join_all(self.subsystems.iter() .filter_map(|entry| { let key = entry.0.as_str(); let value = entry.1; @@ -57,12 +57,8 @@ impl Manager { "net_cls" => Some(NetworkClassifier::apply(linux_resources, value, pid)), _ => None, } - }).collect::>(); - - join_all(futures).await.iter() - .for_each(|result| { - result.as_ref().expect("Cgroup controller future returned a failure"); - }); + }).collect::>() + ).await?; Ok(()) }) From 990a189a702ac42d72c4140be0807310acd5dd96 Mon Sep 17 00:00:00 2001 From: tsturzl Date: Tue, 25 May 2021 15:04:21 -0600 Subject: [PATCH 05/14] time to write tests --- Cargo.lock | 396 +++++++++++++++++++++++++----- Cargo.toml | 2 + src/cgroups/blkio.rs | 39 +-- src/cgroups/controller.rs | 4 +- src/cgroups/devices.rs | 23 +- src/cgroups/hugetlb.rs | 32 +-- src/cgroups/manager.rs | 30 ++- src/cgroups/network_classifier.rs | 25 +- src/cgroups/network_priority.rs | 29 ++- src/cgroups/pids.rs | 32 +-- 10 files changed, 447 insertions(+), 165 deletions(-) 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..80e9b6cd8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,3 +22,5 @@ once_cell = "1.6.0" futures = { version = "0.3", features = ["thread-pool"] } regex = "1.5" oci_spec = { version = "0.1.0", path = "./oci_spec" } +smol = "1.2.5" +async-trait = "0.1.50" diff --git a/src/cgroups/blkio.rs b/src/cgroups/blkio.rs index feb319ab3..6592ded09 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,8 +26,8 @@ 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?; } } @@ -34,53 +35,53 @@ impl Controller for Blkio { .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? + .write_all(pid.to_string().as_bytes()).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<()> { + OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(file_path)? - .write_all(data.as_bytes())?; + .open(file_path).await? + .write_all(data.as_bytes()).await?; Ok(()) } 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..472d7c96e 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,14 @@ 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?; for d in &linux_resources.devices { - Self::apply_device(d, cgroup_root)?; + Self::apply_device(d, cgroup_root).await?; } for d in [ @@ -30,21 +31,21 @@ impl Controller for Devices { ] .concat() { - Self::apply_device(&d, &cgroup_root)?; + Self::apply_device(&d, &cgroup_root).await?; } 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? + .write_all(pid.to_string().as_bytes()).await?; Ok(()) } } impl Devices { - fn apply_device(device: &LinuxDeviceCgroup, cgroup_root: &Path) -> Result<()> { + async fn apply_device(device: &LinuxDeviceCgroup, cgroup_root: &Path) -> Result<()> { let path = if device.allow { cgroup_root.join("devices.allow") } else { @@ -55,8 +56,8 @@ impl Devices { .create(false) .write(true) .truncate(false) - .open(path)? - .write_all(device.to_string().as_bytes())?; + .open(path).await? + .write_all(device.to_string().as_bytes()).await?; Ok(()) } diff --git a/src/cgroups/hugetlb.rs b/src/cgroups/hugetlb.rs index 3e74cd216..c7aa9c39a 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,32 @@ 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() .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? + .write_all(pid.to_string().as_bytes()).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 +53,17 @@ 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<()> { + OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path)? - .write_all(data.as_bytes())?; + .open(file_path).await? + .write_all(data.as_bytes()).await?; Ok(()) } @@ -80,6 +79,7 @@ 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() diff --git a/src/cgroups/manager.rs b/src/cgroups/manager.rs index 8a74ef117..4e382be76 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::join_all; use anyhow::Result; use nix::unistd::Pid; @@ -41,20 +42,25 @@ 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 { + let futures = Vec::with_capacity(7); + for subsys in &self.subsystems { + futures.push(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, + }); } - } - Ok(()) + join_all(futures); + + Ok(()) + }) } pub fn remove(&self) -> Result<()> { diff --git a/src/cgroups/network_classifier.rs b/src/cgroups/network_classifier.rs index c6df7448d..83295ac20 100644 --- a/src/cgroups/network_classifier.rs +++ b/src/cgroups/network_classifier.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, @@ -14,20 +14,21 @@ 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() .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? + .write_all(pid.to_string().as_bytes()).await?; } Ok(()) @@ -35,21 +36,21 @@ 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<()> { + async fn write_file(file_path: &Path, data: &str) -> Result<()> { OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path)? - .write_all(data.as_bytes())?; + .open(file_path).await? + .write_all(data.as_bytes()).await?; Ok(()) } diff --git a/src/cgroups/network_priority.rs b/src/cgroups/network_priority.rs index 291ca9df5..647bf6958 100644 --- a/src/cgroups/network_priority.rs +++ b/src/cgroups/network_priority.rs @@ -1,31 +1,30 @@ -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() .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? + .write_all(pid.to_string().as_bytes()).await?; } Ok(()) @@ -33,20 +32,20 @@ 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<()> { + async fn write_file(file_path: &Path, data: &str) -> Result<()> { OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path)? - .write_all(data.as_bytes())?; + .open(file_path).await? + .write_all(data.as_bytes()).await?; Ok(()) } diff --git a/src/cgroups/pids.rs b/src/cgroups/pids.rs index df6d5b9c9..a69a618f0 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,48 @@ 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() .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? + .write_all(pid.to_string().as_bytes()).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<()> { + OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path)? - .write_all(data.as_bytes())?; + .open(file_path).await? + .write_all(data.as_bytes()).await?; Ok(()) } @@ -63,6 +62,7 @@ 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() From a783698088fe8e63b9c91da186bb6baeb65de830 Mon Sep 17 00:00:00 2001 From: Travis Sturzl Date: Wed, 26 May 2021 12:17:49 -0600 Subject: [PATCH 06/14] actively testing --- src/cgroups/blkio.rs | 115 ++++++++++++++++-------------- src/cgroups/hugetlb.rs | 40 ++++++----- src/cgroups/manager.rs | 61 +++++++++++----- src/cgroups/memory.rs | 63 +++++++++------- src/cgroups/network_classifier.rs | 21 +++--- src/cgroups/network_priority.rs | 50 +++++++------ src/cgroups/pids.rs | 27 ++++--- 7 files changed, 222 insertions(+), 155 deletions(-) diff --git a/src/cgroups/blkio.rs b/src/cgroups/blkio.rs index 6592ded09..8b86737d1 100644 --- a/src/cgroups/blkio.rs +++ b/src/cgroups/blkio.rs @@ -93,6 +93,7 @@ mod tests { use super::*; use oci_spec::{LinuxBlockIo, LinuxThrottleDevice}; + use std::io::Write; struct BlockIoBuilder { block_io: LinuxBlockIo, @@ -173,19 +174,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] @@ -193,19 +196,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] @@ -213,19 +218,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] @@ -235,18 +242,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/hugetlb.rs b/src/cgroups/hugetlb.rs index c7aa9c39a..c4223fada 100644 --- a/src/cgroups/hugetlb.rs +++ b/src/cgroups/hugetlb.rs @@ -103,14 +103,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 +120,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 4e382be76..0c024ea3c 100644 --- a/src/cgroups/manager.rs +++ b/src/cgroups/manager.rs @@ -43,21 +43,40 @@ impl Manager { pub fn apply(&self, linux_resources: &LinuxResources, pid: Pid) -> Result<()> { smol::block_on(async { - let futures = Vec::with_capacity(7); - for subsys in &self.subsystems { - futures.push(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, - }); - } + // let futures = Vec::with_capacity(7); + // for subsys in &self.subsystems { + // futures.push(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, + // }); + // } - join_all(futures); + let futures = 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::>(); + + join_all(futures).await.iter() + .for_each(|result| { + result.as_ref().expect("Cgroup controller future returned a failure"); + }); Ok(()) }) @@ -84,14 +103,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..a27e99f88 100644 --- a/src/cgroups/memory.rs +++ b/src/cgroups/memory.rs @@ -152,7 +152,7 @@ impl Memory { } 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 @@ -240,6 +240,7 @@ impl Memory { mod tests { use super::*; use oci_spec::LinuxMemory; + use std::io::Write; fn set_fixture(temp_dir: &std::path::Path, filename: &str, val: &str) -> Result<()> { std::fs::OpenOptions::new() @@ -264,10 +265,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) + + 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 +292,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] @@ -314,16 +321,18 @@ 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"); - // swap should be set to -1 also - assert_eq!(limit.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"); + // swap should be set to -1 also + assert_eq!(limit.to_string(), swap_content); + }); } // test setting swap and memory to arbitrary values @@ -338,15 +347,17 @@ mod tests { kernel_tcp: None, swappiness: None, }; - Memory::apply(linux_memory, &tmp).expect("Set memory and swap"); + 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 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); + 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 83295ac20..bc868ace6 100644 --- a/src/cgroups/network_classifier.rs +++ b/src/cgroups/network_classifier.rs @@ -59,6 +59,7 @@ impl NetworkClassifier { #[cfg(test)] mod tests { use std::path::PathBuf; + use std::io::Write; use super::*; @@ -84,16 +85,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 647bf6958..7bbbba32b 100644 --- a/src/cgroups/network_priority.rs +++ b/src/cgroups/network_priority.rs @@ -54,6 +54,7 @@ impl NetworkPriority { #[cfg(test)] mod tests { use std::path::PathBuf; + use std::io::Write; use super::*; use oci_spec::LinuxInterfacePriority; @@ -79,26 +80,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 a69a618f0..bf19eda19 100644 --- a/src/cgroups/pids.rs +++ b/src/cgroups/pids.rs @@ -86,12 +86,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 }; - - 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); + smol::block_on(async { + let pids = LinuxPids { limit: 1000 }; + + 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 +102,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); + }); } } From db2b13980e1d924e848dd27e3bb1ea256c615518 Mon Sep 17 00:00:00 2001 From: Travis Sturzl Date: Wed, 26 May 2021 15:34:00 -0600 Subject: [PATCH 07/14] unit tests passing, some integration tests still fail --- src/cgroups/blkio.rs | 24 ++++++++++------ src/cgroups/devices.rs | 16 +++++++---- src/cgroups/hugetlb.rs | 24 ++++++++++------ src/cgroups/manager.rs | 14 --------- src/cgroups/memory.rs | 48 ++++++++++++++++--------------- src/cgroups/network_classifier.rs | 28 ++++++++++-------- src/cgroups/network_priority.rs | 24 ++++++++++------ src/cgroups/pids.rs | 24 ++++++++++------ 8 files changed, 111 insertions(+), 91 deletions(-) diff --git a/src/cgroups/blkio.rs b/src/cgroups/blkio.rs index 8b86737d1..34e13c890 100644 --- a/src/cgroups/blkio.rs +++ b/src/cgroups/blkio.rs @@ -31,12 +31,14 @@ impl Controller for Blkio { } } - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(cgroup_root.join("cgroup.procs")).await? - .write_all(pid.to_string().as_bytes()).await?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -76,12 +78,14 @@ impl Blkio { } async fn write_file(file_path: &Path, data: &str) -> anyhow::Result<()> { - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(file_path).await? - .write_all(data.as_bytes()).await?; + .open(file_path).await?; + + file.write_all(data.as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -154,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) } diff --git a/src/cgroups/devices.rs b/src/cgroups/devices.rs index 472d7c96e..9317b2178 100644 --- a/src/cgroups/devices.rs +++ b/src/cgroups/devices.rs @@ -34,12 +34,14 @@ impl Controller for Devices { Self::apply_device(&d, &cgroup_root).await?; } - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(cgroup_root.join("cgroup.procs")).await? - .write_all(pid.to_string().as_bytes()).await?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; Ok(()) } } @@ -52,12 +54,14 @@ impl Devices { cgroup_root.join("devices.deny") }; - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(false) - .open(path).await? - .write_all(device.to_string().as_bytes()).await?; + .open(path).await?; + + file.write_all(device.to_string().as_bytes()).await?; + file.sync_data().await?; Ok(()) } diff --git a/src/cgroups/hugetlb.rs b/src/cgroups/hugetlb.rs index c4223fada..26e5524fa 100644 --- a/src/cgroups/hugetlb.rs +++ b/src/cgroups/hugetlb.rs @@ -26,12 +26,14 @@ impl Controller for 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")).await? - .write_all(pid.to_string().as_bytes()).await?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; Ok(()) } } @@ -58,12 +60,14 @@ impl Hugetlb { } async fn write_file(file_path: &Path, data: &str) -> anyhow::Result<()> { - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path).await? - .write_all(data.as_bytes()).await?; + .open(file_path).await?; + + file.write_all(data.as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -82,12 +86,14 @@ mod tests { 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(()) } diff --git a/src/cgroups/manager.rs b/src/cgroups/manager.rs index 0c024ea3c..6daec8ec9 100644 --- a/src/cgroups/manager.rs +++ b/src/cgroups/manager.rs @@ -43,20 +43,6 @@ impl Manager { pub fn apply(&self, linux_resources: &LinuxResources, pid: Pid) -> Result<()> { smol::block_on(async { - // let futures = Vec::with_capacity(7); - // for subsys in &self.subsystems { - // futures.push(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, - // }); - // } - let futures = self.subsystems.iter() .filter_map(|entry| { let key = entry.0.as_str(); diff --git a/src/cgroups/memory.rs b/src/cgroups/memory.rs index a27e99f88..00ede7b6d 100644 --- a/src/cgroups/memory.rs +++ b/src/cgroups/memory.rs @@ -67,12 +67,14 @@ impl Controller for Memory { Self::set(tcp_mem, &cgroup_root.join(CGROUP_KERNEL_TCP_MEMORY_LIMIT))?; } - 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(()) } @@ -136,13 +138,14 @@ 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?; + file.write_all(val.to_string().as_bytes()).await?; + file.sync_all().await?; Ok(()) } @@ -243,12 +246,13 @@ mod tests { 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_all()?; Ok(()) } @@ -311,17 +315,16 @@ 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, - }; 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 = @@ -333,10 +336,9 @@ mod tests { // 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 { @@ -358,6 +360,6 @@ mod tests { .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 bc868ace6..9ff012e71 100644 --- a/src/cgroups/network_classifier.rs +++ b/src/cgroups/network_classifier.rs @@ -1,6 +1,4 @@ -use std::{ - path::Path, -}; +use std::path::Path; use anyhow::Result; use async_trait::async_trait; @@ -23,12 +21,14 @@ impl Controller for NetworkClassifier { if let Some(network) = linux_resources.network.as_ref() { 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")).await? - .write_all(pid.to_string().as_bytes()).await?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; } Ok(()) @@ -45,12 +45,14 @@ impl NetworkClassifier { } async fn write_file(file_path: &Path, data: &str) -> Result<()> { - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path).await? - .write_all(data.as_bytes()).await?; + .open(file_path).await?; + + file.write_all(data.as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -64,12 +66,14 @@ mod tests { 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(()) } diff --git a/src/cgroups/network_priority.rs b/src/cgroups/network_priority.rs index 7bbbba32b..12b50a35c 100644 --- a/src/cgroups/network_priority.rs +++ b/src/cgroups/network_priority.rs @@ -19,12 +19,14 @@ impl Controller for NetworkPriority { if let Some(network) = linux_resources.network.as_ref() { 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")).await? - .write_all(pid.to_string().as_bytes()).await?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; } Ok(()) @@ -40,12 +42,14 @@ impl NetworkPriority { } async fn write_file(file_path: &Path, data: &str) -> Result<()> { - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path).await? - .write_all(data.as_bytes()).await?; + .open(file_path).await?; + + file.write_all(data.as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -60,12 +64,14 @@ mod tests { 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(()) } diff --git a/src/cgroups/pids.rs b/src/cgroups/pids.rs index bf19eda19..82bfc96cc 100644 --- a/src/cgroups/pids.rs +++ b/src/cgroups/pids.rs @@ -24,12 +24,14 @@ impl Controller for 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")).await? - .write_all(pid.to_string().as_bytes()).await?; + .open(cgroup_root.join("cgroup.procs")).await?; + + file.write_all(pid.to_string().as_bytes()).await?; + file.sync_data().await?; Ok(()) } } @@ -47,12 +49,14 @@ impl Pids { } async fn write_file(file_path: &Path, data: &str) -> Result<()> { - OpenOptions::new() + let mut file = OpenOptions::new() .create(false) .write(true) .truncate(true) - .open(file_path).await? - .write_all(data.as_bytes()).await?; + .open(file_path).await?; + + file.write_all(data.as_bytes()).await?; + file.sync_data().await?; Ok(()) } @@ -65,12 +69,14 @@ mod tests { 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(()) } From 62b543c6b80146fa73b2998b0ee6523434b937aa Mon Sep 17 00:00:00 2001 From: Travis Sturzl Date: Thu, 27 May 2021 21:19:19 -0600 Subject: [PATCH 08/14] try_join_all is cleaner --- src/cgroups/manager.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/cgroups/manager.rs b/src/cgroups/manager.rs index 6daec8ec9..e2f27ce39 100644 --- a/src/cgroups/manager.rs +++ b/src/cgroups/manager.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, path::PathBuf}; use std::{fs::remove_dir, path::Path}; -use futures::future::join_all; +use futures::future::try_join_all; use anyhow::Result; use nix::unistd::Pid; @@ -43,7 +43,7 @@ impl Manager { pub fn apply(&self, linux_resources: &LinuxResources, pid: Pid) -> Result<()> { smol::block_on(async { - let futures = self.subsystems.iter() + try_join_all(self.subsystems.iter() .filter_map(|entry| { let key = entry.0.as_str(); let value = entry.1; @@ -57,12 +57,8 @@ impl Manager { "net_cls" => Some(NetworkClassifier::apply(linux_resources, value, pid)), _ => None, } - }).collect::>(); - - join_all(futures).await.iter() - .for_each(|result| { - result.as_ref().expect("Cgroup controller future returned a failure"); - }); + }).collect::>() + ).await?; Ok(()) }) From a0448a32d5078a750d717f0618a3af54df70694b Mon Sep 17 00:00:00 2001 From: Travis Sturzl Date: Thu, 27 May 2021 21:44:32 -0600 Subject: [PATCH 09/14] rough rebase --- Cargo.lock | 1 + Cargo.toml | 1 + src/cgroups/memory.rs | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 75b4a185b..fed949756 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1017,6 +1017,7 @@ dependencies = [ "log", "mio", "nix 0.19.1", + "oci_spec", "once_cell", "prctl", "procfs", diff --git a/Cargo.toml b/Cargo.toml index 5734551ce..07e643865 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,3 +23,4 @@ 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/memory.rs b/src/cgroups/memory.rs index 5939644cb..b36489c38 100644 --- a/src/cgroups/memory.rs +++ b/src/cgroups/memory.rs @@ -162,7 +162,7 @@ impl Memory { Errno::EBUSY => { let usage = Self::get_memory_usage(cgroup_root).await?; let max_usage = Self::get_memory_max_usage(cgroup_root).await?; - Err(anyhow!( + bail!( "unable to set memory limit to {} (current usage: {}, peak usage: {})", val, usage, @@ -245,7 +245,7 @@ impl Memory { mod tests { use super::*; use std::io::Write; - use crate::spec::LinuxMemory; + use oci_spec::LinuxMemory; fn set_fixture(temp_dir: &std::path::Path, filename: &str, val: &str) -> Result<()> { let mut file = std::fs::OpenOptions::new() From d1d9558367e8b47406685175c87272ddfda86ca7 Mon Sep 17 00:00:00 2001 From: Travis Sturzl Date: Thu, 27 May 2021 21:49:51 -0600 Subject: [PATCH 10/14] missed in rebase --- src/cgroups/blkio.rs | 2 +- src/cgroups/hugetlb.rs | 2 +- src/cgroups/pids.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cgroups/blkio.rs b/src/cgroups/blkio.rs index 32499f037..34e13c890 100644 --- a/src/cgroups/blkio.rs +++ b/src/cgroups/blkio.rs @@ -96,7 +96,7 @@ mod tests { use std::path::PathBuf; use super::*; - use crate::spec::{LinuxBlockIo, LinuxThrottleDevice}; + use oci_spec::{LinuxBlockIo, LinuxThrottleDevice}; use std::io::Write; struct BlockIoBuilder { diff --git a/src/cgroups/hugetlb.rs b/src/cgroups/hugetlb.rs index 42d30756c..26e5524fa 100644 --- a/src/cgroups/hugetlb.rs +++ b/src/cgroups/hugetlb.rs @@ -82,7 +82,7 @@ mod tests { use std::path::PathBuf; use super::*; - use crate::spec::LinuxHugepageLimit; + use oci_spec::LinuxHugepageLimit; use std::io::Write; fn set_fixture(temp_dir: &std::path::Path, filename: &str, val: &str) -> anyhow::Result<()> { diff --git a/src/cgroups/pids.rs b/src/cgroups/pids.rs index 13777a2c6..82bfc96cc 100644 --- a/src/cgroups/pids.rs +++ b/src/cgroups/pids.rs @@ -65,7 +65,7 @@ impl Pids { #[cfg(test)] mod tests { use super::*; - use crate::spec::LinuxPids; + use oci_spec::LinuxPids; use std::io::Write; fn set_fixture(temp_dir: &std::path::Path, filename: &str, val: &str) -> Result<()> { From 769978457308e1678a63cf4f6e0f52ff2ffa8af1 Mon Sep 17 00:00:00 2001 From: Travis Sturzl Date: Tue, 1 Jun 2021 20:17:18 -0600 Subject: [PATCH 11/14] try old manager --- src/cgroups/manager.rs | 12 +++--------- src/cgroups/memory.rs | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/cgroups/manager.rs b/src/cgroups/manager.rs index e2f27ce39..6e84529e1 100644 --- a/src/cgroups/manager.rs +++ b/src/cgroups/manager.rs @@ -85,18 +85,12 @@ 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" { + if subsystem == "net_cls" || 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_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"); + || m.mount_point.ends_with("net_prio,net_cls"); } - return m.mount_point.ends_with(subsystem); } - return false; + m.mount_point.ends_with(subsystem) }) .expect("Failed to find mount point for subsystem"); diff --git a/src/cgroups/memory.rs b/src/cgroups/memory.rs index b36489c38..c4a66b442 100644 --- a/src/cgroups/memory.rs +++ b/src/cgroups/memory.rs @@ -144,7 +144,7 @@ impl Memory { .create(false) .write(true) .truncate(true) - .open(path).await?; + .open(path).await.expect(&format!("Open: {}", path.to_str().unwrap())); file.write_all(val.to_string().as_bytes()).await?; file.sync_all().await?; Ok(()) From 9cfb1d4f6d50cbfa344f07c2c7d3509b18a941cf Mon Sep 17 00:00:00 2001 From: Travis Sturzl Date: Tue, 1 Jun 2021 21:17:36 -0600 Subject: [PATCH 12/14] revert, didn't affect the CI tests --- src/cgroups/manager.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/cgroups/manager.rs b/src/cgroups/manager.rs index 6e84529e1..e2f27ce39 100644 --- a/src/cgroups/manager.rs +++ b/src/cgroups/manager.rs @@ -85,12 +85,18 @@ 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_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"); } + return m.mount_point.ends_with(subsystem); } - m.mount_point.ends_with(subsystem) + return false; }) .expect("Failed to find mount point for subsystem"); From 428694ebe892a64438ae22d39d2709e6ced70d8c Mon Sep 17 00:00:00 2001 From: Travis Sturzl Date: Tue, 1 Jun 2021 21:57:48 -0600 Subject: [PATCH 13/14] reuse file --- src/cgroups/devices.rs | 43 ++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/cgroups/devices.rs b/src/cgroups/devices.rs index 9317b2178..1acdfc0b5 100644 --- a/src/cgroups/devices.rs +++ b/src/cgroups/devices.rs @@ -5,7 +5,7 @@ use std::{ use anyhow::Result; use async_trait::async_trait; use nix::unistd::Pid; -use smol::{fs::{OpenOptions, create_dir_all}, io::AsyncWriteExt}; +use smol::{fs::{File, OpenOptions, create_dir_all}, io::AsyncWriteExt}; use crate::{ cgroups::Controller, @@ -20,9 +20,25 @@ impl Controller for Devices { async fn apply(linux_resources: &LinuxResources, cgroup_root: &Path, pid: Pid) -> Result<()> { log::debug!("Apply Devices cgroup config"); create_dir_all(&cgroup_root).await?; + + let mut allowed = OpenOptions::new() + .create(false) + .write(true) + .truncate(false) + .open(cgroup_root.join("devices.allow")).await?; + + let mut denied = OpenOptions::new() + .create(false) + .write(true) + .truncate(false) + .open(cgroup_root.join("devices.deny")).await?; for d in &linux_resources.devices { - Self::apply_device(d, cgroup_root).await?; + if d.allow { + Self::apply_device(d, &mut allowed).await?; + } else { + Self::apply_device(d, &mut denied).await?; + } } for d in [ @@ -31,9 +47,16 @@ impl Controller for Devices { ] .concat() { - Self::apply_device(&d, &cgroup_root).await?; + if d.allow { + Self::apply_device(&d, &mut allowed).await?; + } else { + Self::apply_device(&d, &mut denied).await?; + } } + allowed.sync_data().await?; + denied.sync_data().await?; + let mut file = OpenOptions::new() .create(false) .write(true) @@ -47,19 +70,7 @@ impl Controller for Devices { } impl Devices { - async 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") - }; - - let mut file = OpenOptions::new() - .create(false) - .write(true) - .truncate(false) - .open(path).await?; - + async fn apply_device(device: &LinuxDeviceCgroup, file: &mut File) -> Result<()> { file.write_all(device.to_string().as_bytes()).await?; file.sync_data().await?; Ok(()) From 5a5d659ccca361b640ab5adc5c7c6f8c4baaa10b Mon Sep 17 00:00:00 2001 From: Travis Sturzl Date: Tue, 1 Jun 2021 22:08:07 -0600 Subject: [PATCH 14/14] batch write devices --- src/cgroups/devices.rs | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/cgroups/devices.rs b/src/cgroups/devices.rs index 1acdfc0b5..d09016091 100644 --- a/src/cgroups/devices.rs +++ b/src/cgroups/devices.rs @@ -5,7 +5,7 @@ use std::{ use anyhow::Result; use async_trait::async_trait; use nix::unistd::Pid; -use smol::{fs::{File, OpenOptions, create_dir_all}, io::AsyncWriteExt}; +use smol::{fs::{OpenOptions, create_dir_all}, io::AsyncWriteExt}; use crate::{ cgroups::Controller, @@ -21,23 +21,14 @@ impl Controller for Devices { log::debug!("Apply Devices cgroup config"); create_dir_all(&cgroup_root).await?; - let mut allowed = OpenOptions::new() - .create(false) - .write(true) - .truncate(false) - .open(cgroup_root.join("devices.allow")).await?; - - let mut denied = OpenOptions::new() - .create(false) - .write(true) - .truncate(false) - .open(cgroup_root.join("devices.deny")).await?; + let mut allowed: Vec = Vec::new(); + let mut denied: Vec = Vec::new(); for d in &linux_resources.devices { if d.allow { - Self::apply_device(d, &mut allowed).await?; + allowed.push(d.to_string()) } else { - Self::apply_device(d, &mut denied).await?; + denied.push(d.to_string()) } } @@ -48,14 +39,14 @@ impl Controller for Devices { .concat() { if d.allow { - Self::apply_device(&d, &mut allowed).await?; + allowed.push(d.to_string()) } else { - Self::apply_device(&d, &mut denied).await?; + denied.push(d.to_string()) } } - allowed.sync_data().await?; - denied.sync_data().await?; + 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) @@ -70,8 +61,14 @@ impl Controller for Devices { } impl Devices { - async fn apply_device(device: &LinuxDeviceCgroup, file: &mut File) -> Result<()> { - file.write_all(device.to_string().as_bytes()).await?; + async fn write_file(data: &str, path: &Path) -> Result<()> { + let mut file = OpenOptions::new() + .create(false) + .write(true) + .truncate(false) + .open(path).await?; + + file.write_all(data.as_bytes()).await?; file.sync_data().await?; Ok(()) }