diff --git a/Makefile b/Makefile index 6bb914271f..6f398c3236 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ TOOLS = TOOLS += agent-ctl TOOLS += trace-forwarder +TOOLS += runk STANDARD_TARGETS = build check clean install test vendor diff --git a/README.md b/README.md index 431d687de0..3cac624006 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ The table below lists the remaining parts of the project: | [osbuilder](tools/osbuilder) | infrastructure | Tool to create "mini O/S" rootfs and initrd images and kernel for the hypervisor. | | [`agent-ctl`](src/tools/agent-ctl) | utility | Tool that provides low-level access for testing the agent. | | [`trace-forwarder`](src/tools/trace-forwarder) | utility | Agent tracing helper. | +| [`runk`](src/tools/runk) | utility | Standard OCI container runtime based on the agent. | | [`ci`](https://github.com/kata-containers/ci) | CI | Continuous Integration configuration files and scripts. | | [`katacontainers.io`](https://github.com/kata-containers/www.katacontainers.io) | Source for the [`katacontainers.io`](https://www.katacontainers.io) site. | diff --git a/src/tools/runk/.gitignore b/src/tools/runk/.gitignore new file mode 100644 index 0000000000..57872d0f1e --- /dev/null +++ b/src/tools/runk/.gitignore @@ -0,0 +1 @@ +/vendor/ diff --git a/src/tools/runk/Cargo.lock b/src/tools/runk/Cargo.lock new file mode 100644 index 0000000000..f8628cbf7d --- /dev/null +++ b/src/tools/runk/Cargo.lock @@ -0,0 +1,1474 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" + +[[package]] +name = "arc-swap" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f" + +[[package]] +name = "async-trait" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +dependencies = [ + "byteorder", + "iovec", +] + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "capctl" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "526c6a8746a7cfb052c15d20259c4f5c021966affdc7c960c71ca640f824c801" +dependencies = [ + "bitflags", + "cfg-if 1.0.0", + "libc", +] + +[[package]] +name = "caps" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61bf7211aad104ce2769ec05efcdfabf85ee84ac92461d142f22cf8badd0e54c" +dependencies = [ + "errno", + "libc", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cgroups-rs" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdae996d9638ba03253ffa1c93345a585974a97abbdeab9176c77922f3efc1e8" +dependencies = [ + "libc", + "log", + "nix 0.23.1", + "regex", +] + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "serde", + "time 0.1.44", + "winapi", +] + +[[package]] +name = "clap" +version = "3.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c167e37342afc5f33fd87bbc870cedd020d2a6dffa05d45ccd9241fbdd146db" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "indexmap", + "lazy_static", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1" +dependencies = [ + "heck 0.4.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "189ddd3b5d32a70b35e7686054371742a937b0d99128e76dde6340210e966669" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +dependencies = [ + "cfg-if 1.0.0", + "lazy_static", +] + +[[package]] +name = "darling" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2c43f534ea4b0b049015d00269734195e6d3f0f6635cb692251aca6f9f8b3c" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e91455b86830a1c21799d94524df0845183fa55bafd9aa137b01c7d1065fa36" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29b5acf0dea37a7f66f7b25d2c5e93fd46f8f6968b1a5d7a3e02e97768afc95a" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "derive-new" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d13202debe11181040ae9063d739fa32cfcaaebe2275fe387703460ae2365b30" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66e616858f6187ed828df7c64a6d71720d83767a7f19740b2d1b6fe6327b36e5" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58a94ace95092c5acb1e97a7e846b310cfbd499652f72297da7493f618a98d73" +dependencies = [ + "derive_builder_core", + "syn", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "fixedbitset" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-executor" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-macro" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags", + "futures-core", + "inotify-sys", + "libc", + "tokio", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.124" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50" + +[[package]] +name = "libcontainer" +version = "0.0.1" +dependencies = [ + "anyhow", + "chrono", + "derive_builder", + "libc", + "logging", + "nix 0.23.1", + "oci", + "rustjail", + "serde", + "serde_json", + "slog", + "tempfile", +] + +[[package]] +name = "liboci-cli" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c25aa929b6575121059b01bfd7289dedf25a988534b6550d3472ccd5064be8ce" +dependencies = [ + "clap", +] + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "logging" +version = "0.1.0" +dependencies = [ + "serde_json", + "slog", + "slog-async", + "slog-json", + "slog-scope", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mio" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "wasi 0.11.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "nix" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0eaf8df8bab402257e0a5c17a254e4cc1f72a93588a1ddfb5d356c801aa7cb" +dependencies = [ + "bitflags", + "cc", + "cfg-if 0.1.10", + "libc", + "void", +] + +[[package]] +name = "nix" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", + "memoffset", +] + +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0" +dependencies = [ + "libc", +] + +[[package]] +name = "oci" +version = "0.1.0" +dependencies = [ + "libc", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "once_cell" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" + +[[package]] +name = "os_str_bytes" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "995f667a6c822200b0433ac218e05582f0e2efa1b922a3fd2fbaadc5f87bab37" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "path-absolutize" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceeedc827d9a758b4641457683ced2f02d4252cc1bd8794c415ed20256114290" +dependencies = [ + "path-dedot", + "slash-formatter", +] + +[[package]] +name = "path-dedot" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45c58ab1edb03f77d0bb3f08e4a179dd43ce9bc8eab9867ec53a78285ea3039b" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "petgraph" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "prost" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de5e2533f59d08fcf364fd374ebda0692a70bd6d7e66ef97f306f45c6c5d8020" +dependencies = [ + "bytes 1.1.0", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603" +dependencies = [ + "bytes 1.1.0", + "heck 0.3.3", + "itertools", + "log", + "multimap", + "petgraph", + "prost", + "prost-types", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "600d2f334aa05acb02a755e217ef1ab6dea4d51b58b7846588b747edec04efba" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "603bbd6394701d13f3f25aada59c7de9d35a6a5887cfc156181234a44002771b" +dependencies = [ + "bytes 1.1.0", + "prost", +] + +[[package]] +name = "protobuf" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e86d370532557ae7573551a1ec8235a0f8d6cb276c7c9e6aa490b511c447485" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "protobuf-codegen" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de113bba758ccf2c1ef816b127c958001b7831136c9bc3f8e9ec695ac4e82b0c" +dependencies = [ + "protobuf", +] + +[[package]] +name = "protobuf-codegen-pure" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d1a4febc73bf0cada1d77c459a0c8e5973179f1cfd5b0f1ab789d45b17b6440" +dependencies = [ + "protobuf", + "protobuf-codegen", +] + +[[package]] +name = "protocols" +version = "0.1.0" +dependencies = [ + "async-trait", + "protobuf", + "ttrpc", + "ttrpc-codegen", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "rlimit" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a9ed03edbed449d6897c2092c71ab5f7b5fb80f6f0b1a3ed6d40a6f9fc0720" +dependencies = [ + "libc", +] + +[[package]] +name = "runk" +version = "0.0.1" +dependencies = [ + "anyhow", + "chrono", + "clap", + "libc", + "libcontainer", + "liboci-cli", + "logging", + "nix 0.23.1", + "oci", + "rustjail", + "serde", + "serde_json", + "slog", + "slog-async", + "tokio", +] + +[[package]] +name = "rustjail" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "capctl", + "caps", + "cfg-if 0.1.10", + "cgroups-rs", + "futures", + "inotify", + "lazy_static", + "libc", + "nix 0.23.1", + "oci", + "path-absolutize", + "protobuf", + "protocols", + "regex", + "rlimit", + "scan_fmt", + "scopeguard", + "serde", + "serde_derive", + "serde_json", + "slog", + "slog-scope", + "tokio", +] + +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "scan_fmt" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b53b0a5db882a8e2fdaae0a43f7b39e7e9082389e978398bdf223a55b581248" +dependencies = [ + "regex", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "slash-formatter" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f7fb98e76e2022054673f3ebc43a4e12890ec6272530629df6237cafbb70569" + +[[package]] +name = "slog" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" + +[[package]] +name = "slog-async" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "766c59b252e62a34651412870ff55d8c4e6d04df19b43eecb2703e417b097ffe" +dependencies = [ + "crossbeam-channel", + "slog", + "take_mut", + "thread_local", +] + +[[package]] +name = "slog-json" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e1e53f61af1e3c8b852eef0a9dee29008f55d6dd63794f3f12cef786cf0f219" +dependencies = [ + "serde", + "serde_json", + "slog", + "time 0.3.9", +] + +[[package]] +name = "slog-scope" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f95a4b4c3274cd2869549da82b57ccc930859bdbf5bcea0424bc5f140b3c786" +dependencies = [ + "arc-swap", + "lazy_static", + "slog", +] + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if 1.0.0", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" + +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "time" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +dependencies = [ + "itoa", + "libc", + "num_threads", +] + +[[package]] +name = "tokio" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +dependencies = [ + "bytes 1.1.0", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-vsock" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e0723fc001950a3b018947b05eeb45014fd2b7c6e8f292502193ab74486bdb6" +dependencies = [ + "bytes 0.4.12", + "futures", + "libc", + "tokio", + "vsock", +] + +[[package]] +name = "ttrpc" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "004604e91de38bc16cb9c7898187343075388ea414ad24896a21fc4e91a7c861" +dependencies = [ + "async-trait", + "byteorder", + "futures", + "libc", + "log", + "nix 0.16.1", + "protobuf", + "protobuf-codegen-pure", + "thiserror", + "tokio", + "tokio-vsock", +] + +[[package]] +name = "ttrpc-codegen" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809eda4e459820237104e4b61d6b41bbe6c9e1ce6adf4057955e6e6722a90408" +dependencies = [ + "protobuf", + "protobuf-codegen", + "protobuf-codegen-pure", + "ttrpc-compiler", +] + +[[package]] +name = "ttrpc-compiler" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2978ed3fa047d8fd55cbeb4d4a61d461fb3021a90c9618519c73ce7e5bb66c15" +dependencies = [ + "derive-new", + "prost", + "prost-build", + "prost-types", + "protobuf", + "protobuf-codegen", + "tempfile", +] + +[[package]] +name = "unicode-segmentation" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "vsock" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e32675ee2b3ce5df274c0ab52d19b28789632406277ca26bffee79a8e27dc133" +dependencies = [ + "libc", + "nix 0.23.1", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "which" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" +dependencies = [ + "either", + "lazy_static", + "libc", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" + +[[package]] +name = "windows_i686_gnu" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" + +[[package]] +name = "windows_i686_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" diff --git a/src/tools/runk/Cargo.toml b/src/tools/runk/Cargo.toml new file mode 100644 index 0000000000..83aca82ca2 --- /dev/null +++ b/src/tools/runk/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "runk" +version = "0.0.1" +authors = ["The Kata Containers community "] +description = "runk: Kata OCI container runtime based on Kata agent" +license = "Apache-2.0" +edition = "2018" + +[dependencies] +libcontainer = { path = "./libcontainer" } +rustjail = { path = "../../agent/rustjail", features = ["standard-oci-runtime"] } +oci = { path = "../../libs/oci" } +logging = { path = "../../libs/logging" } +liboci-cli = "0.0.3" +clap = { version = "3.0.6", features = ["derive", "cargo"] } +libc = "0.2.108" +nix = "0.23.0" +anyhow = "1.0.52" +slog = "2.7.0" +chrono = { version = "0.4.19", features = ["serde"] } +slog-async = "2.7.0" +tokio = { version = "1.15.0", features = ["full"] } +serde = { version = "1.0.133", features = ["derive"] } +serde_json = "1.0.74" + +[workspace] +members = [ + "libcontainer" +] diff --git a/src/tools/runk/Makefile b/src/tools/runk/Makefile new file mode 100644 index 0000000000..cfd795fb6c --- /dev/null +++ b/src/tools/runk/Makefile @@ -0,0 +1,60 @@ +# Copyright 2021-2022 Sony Group Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +include ../../../utils.mk + +TARGET = runk +TARGET_PATH = target/$(TRIPLE)/$(BUILD_TYPE)/$(TARGET) + +AGENT_TARGET = oci-kata-agent +AGENT_TARGET_PATH = target/$(TRIPLE)/$(BUILD_TYPE)/$(AGENT_TARGET) +AGENT_SOURCE_PATH = ../../agent + +# BINDIR is a directory for installing executable programs +BINDIR := /usr/local/bin + +.DEFAULT_GOAL := default +default: build + +build: build-agent build-runk + +build-agent: + make -C $(AGENT_SOURCE_PATH) STANDARD_OCI_RUNTIME=yes + +build-runk: + @RUSTFLAGS="$(EXTRA_RUSTFLAGS) --deny warnings" cargo build --target $(TRIPLE) --$(BUILD_TYPE) + +install: install-agent install-runk + +install-agent: + install -D $(AGENT_SOURCE_PATH)/$(AGENT_TARGET_PATH) $(BINDIR)/$(AGENT_TARGET) + +install-runk: + install -D $(TARGET_PATH) $(BINDIR)/$(TARGET) + +clean: + cargo clean + +vendor: + cargo vendor + +test: + cargo test --all --target $(TRIPLE) -- --nocapture + +check: standard_rust_check + +.PHONY: \ + build \ + build-agent \ + build-runk \ + install \ + install-agent \ + install-runk \ + clean \ + clippy \ + format \ + vendor \ + test \ + check \ diff --git a/src/tools/runk/README.md b/src/tools/runk/README.md new file mode 100644 index 0000000000..81f02fc598 --- /dev/null +++ b/src/tools/runk/README.md @@ -0,0 +1,282 @@ +# runk + +## Overview + +> **Warnings:** +> `runk` is currently an experimental tool. +> Only continue if you are using a non-critical system. + +`runk` is a standard OCI container runtime written in Rust based on a modified version of +the [Kata Container agent](https://github.com/kata-containers/kata-containers/tree/main/src/agent), `kata-agent`. + +`runk` conforms to the [OCI Container Runtime specifications](https://github.com/opencontainers/runtime-spec). + +Unlike the [Kata Container runtime](https://github.com/kata-containers/kata-containers/tree/main/src/agent#features), +`kata-runtime`, `runk` spawns and runs containers on the host machine directly. +The user can run `runk` in the same way as the existing container runtimes such as `runc`, +the most used implementation of the OCI runtime specs. + +## Why does `runk` exist? + +The `kata-agent` is a process running inside a virtual machine (VM) as a supervisor for managing containers +and processes running within those containers. +In other words, the `kata-agent` is a kind of "low-level" container runtime inside VM because the agent +spawns and runs containers according to the OCI runtime specs. +However, the `kata-agent` does not have the OCI Command-Line Interface (CLI) that is defined in the +[runtime spec](https://github.com/opencontainers/runtime-spec/blob/master/runtime.md). +The `kata-runtime` provides the CLI part of the Kata Containers runtime component, +but the `kata-runtime` is a container runtime for creating hardware-virtualized containers running on the host. + +`runk` is a Rust-based standard OCI container runtime that manages normal containers, +not hardware-virtualized containers. +`runk` aims to become one of the alternatives to existing OCI compliant container runtimes. +The `kata-agent` has most of the [features](https://github.com/kata-containers/kata-containers/tree/main/src/agent#features) +needed for the container runtime and delivers high performance with a low memory footprint owing to the +implementation by Rust language. +Therefore, `runk` leverages the mechanism of the `kata-agent` to avoid reinventing the wheel. + +## Performance + +`runk` is faster than `runc` and has a lower memory footprint. + +This table shows the average of the elapsed time and the memory footprint (maximum resident set size) +for running sequentially 100 containers, the containers run `/bin/true` using `run` command with +[detached mode](https://github.com/opencontainers/runc/blob/master/docs/terminals.md#detached) +on 12 CPU cores (`3.8 GHz AMD Ryzen 9 3900X`) and 32 GiB of RAM. +`runk` always runs containers with detached mode currently. + +Evaluation Results: + +| | `runk` (v0.0.1) | `runc` (v1.0.3) | `crun` (v1.4.2) | +|-----------------------|---------------|---------------|---------------| +| time [ms] | 39.83 | 50.39 | 38.41 | +| memory footprint [MB] | 4.013 | 10.78 | 1.738 | + +## Status of `runk` + +We drafted the initial code here, and any contributions to `runk` and [`kata-agent`](https://github.com/kata-containers/kata-containers/tree/main/src/agent) +are welcome. + +Regarding features compared to `runc`, see the `Status of runk` section in the [issue](https://github.com/kata-containers/kata-containers/issues/2784). + +## Building + +`runk` uses the modified the `kata-agent` binary, `oci-kata-agent`, which is an agent to be called from `runk`. +Therefore, you also need to build the `oci-kata-agent` to run `runk`. + +You can build both `runk` and `oci-kata-agent` as follows. + +```bash +$ cd runk +$ make +``` + +To install `runk` and `oci-kata-agent` into default directory for install executable program (`/usr/local/bin`): + +```bash +$ sudo make install +``` + +## Using `runk` directly + +Please note that `runk` is a low level tool not developed with an end user in mind. +It is mostly employed by other higher-level container software like `containerd`. + +If you still want to use `runk` directly, here's how. + +### Prerequisites + +It is necessary to create an OCI bundle to use the tool. The simplest method is: + +``` bash +$ bundle_dir="bundle" +$ rootfs_dir="$bundle_dir/rootfs" +$ image="busybox" +$ mkdir -p "$rootfs_dir" && (cd "$bundle_dir" && runk spec) +$ sudo docker export $(sudo docker create "$image") | tar -C "$rootfs_dir" -xvf - +``` + +> **Note:** +> If you use the unmodified `runk spec` template, this should give a `sh` session inside the container. +> However, if you use `runk` directly and run a container with the unmodified template, +> `runk` cannot launch the `sh` session because `runk` does not support terminal handling yet. +> You need to edit the process field in the `config.json` should look like this below +> with `"terminal": false` and `"args": ["sleep", "10"]`. + +```json +"process": { + "terminal": false, + "user": { + "uid": 0, + "gid": 0 + }, + "args": [ + "sleep", + "10" + ], + "env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=xterm" + ], + "cwd": "/", + [...] +} +``` + +If you want to launch the `sh` session inside the container, you need to run `runk` from `containerd`. + +Please refer to the [Using `runk` from containerd](#using-runk-from-containerd) section + +### Running a container + +Now you can go through the [lifecycle operations](https://github.com/opencontainers/runtime-spec/blob/master/runtime.md) +in your shell. +You need to run `runk` as `root` because `runk` does not have the rootless feature which is the ability +to run containers without root privileges. + +```bash +$ cd $bundle_dir + +# Create a container +$ sudo runk create test + +# View the container is created and in the "created" state +$ sudo runk state test + +# Start the process inside the container +$ sudo runk start test + +# After 10 seconds view that the container has exited and is now in the "stopped" state +$ sudo runk state test + +# Now delete the container +$ sudo runk delete test +``` + +## Using `runk` from `containerd` + +`runk` can run containers with the containerd runtime handler support on `containerd`. + +### Prerequisites for `runk` with containerd + +* `containerd` v1.2.4 or above +* `cri-tool` + +> **Note:** +> [`cri-tools`](https://github.com/kubernetes-sigs/cri-tools) is a set of tools for CRI +> used for development and testing. + +Install `cri-tools` from source code: + +```bash +$ go get github.com/kubernetes-incubator/cri-tools +$ pushd $GOPATH/src/github.com/kubernetes-incubator/cri-tools +$ make +$ sudo -E make install +$ popd +``` + +Write the `crictl` configuration file: + +``` bash +$ cat <"] +description = "Library for runk container" +license = "Apache-2.0" +edition = "2018" + +[dependencies] +rustjail = { path = "../../../agent/rustjail", features = ["standard-oci-runtime"] } +oci = { path = "../../../libs/oci" } +logging = { path = "../../../libs/logging" } +derive_builder = "0.10.2" +libc = "0.2.108" +nix = "0.23.0" +anyhow = "1.0.52" +slog = "2.7.0" +chrono = { version = "0.4.19", features = ["serde"] } +serde = { version = "1.0.133", features = ["derive"] } +serde_json = "1.0.74" + +[dev-dependencies] +tempfile = "3.3.0" diff --git a/src/tools/runk/libcontainer/src/builder.rs b/src/tools/runk/libcontainer/src/builder.rs new file mode 100644 index 0000000000..738c639ae2 --- /dev/null +++ b/src/tools/runk/libcontainer/src/builder.rs @@ -0,0 +1,121 @@ +// Copyright 2021-2022 Sony Group Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +use crate::container::{get_config_path, ContainerContext}; +use anyhow::{anyhow, Result}; +use derive_builder::Builder; +use oci::Spec; +use std::path::{Path, PathBuf}; + +#[derive(Default, Builder, Debug)] +pub struct Container { + id: String, + bundle: PathBuf, + root: PathBuf, + console_socket: Option, +} + +impl Container { + pub fn create_ctx(self) -> Result { + let bundle_canon = self.bundle.canonicalize()?; + let config_path = get_config_path(&bundle_canon); + let mut spec = Spec::load( + config_path + .to_str() + .ok_or_else(|| anyhow!("invalid config path"))?, + )?; + + if spec.root.is_some() { + let mut spec_root = spec + .root + .as_mut() + .ok_or_else(|| anyhow!("root config was not present in the spec file"))?; + let rootfs_path = Path::new(&spec_root.path); + + // If the rootfs path in the spec file is a relative path, + // convert it into a canonical path to pass validation of rootfs in the agent. + if !&rootfs_path.is_absolute() { + let rootfs_name = rootfs_path + .file_name() + .ok_or_else(|| anyhow!("invalid rootfs name"))?; + spec_root.path = bundle_canon + .join(rootfs_name) + .to_str() + .map(|s| s.to_string()) + .ok_or_else(|| anyhow!("failed to convert bundle path"))?; + } + } + + Ok(ContainerContext { + id: self.id, + bundle: self.bundle, + state_root: self.root, + spec, + // TODO: liboci-cli does not support --no-pivot option for create and run command. + // After liboci-cli supports the option, we will change the following code. + // no_pivot_root: self.no_pivot, + no_pivot_root: false, + console_socket: self.console_socket, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::container::CONFIG_FILE_NAME; + use oci::Spec; + use std::{fs::File, path::PathBuf}; + use tempfile::tempdir; + + #[derive(Debug)] + struct TestData { + id: String, + bundle: PathBuf, + root: PathBuf, + console_socket: Option, + spec: Spec, + no_pivot_root: bool, + } + + #[test] + fn test_create_ctx() { + let bundle_dir = tempdir().unwrap(); + let config_file = bundle_dir.path().join(CONFIG_FILE_NAME); + let spec = Spec::default(); + let file = File::create(config_file).unwrap(); + serde_json::to_writer(&file, &spec).unwrap(); + + let test_data = TestData { + id: String::from("test"), + bundle: PathBuf::from(bundle_dir.into_path()), + root: PathBuf::from("test"), + console_socket: Some(PathBuf::from("test")), + spec: Spec::default(), + no_pivot_root: false, + }; + + let test_ctx = ContainerContext { + id: test_data.id.clone(), + bundle: test_data.bundle.clone(), + state_root: test_data.root.clone(), + spec: test_data.spec.clone(), + no_pivot_root: test_data.no_pivot_root, + console_socket: test_data.console_socket.clone(), + }; + + let ctx = ContainerBuilder::default() + .id(test_data.id.clone()) + .bundle(test_data.bundle.clone()) + .root(test_data.root.clone()) + .console_socket(test_data.console_socket.clone()) + .build() + .unwrap() + .create_ctx() + .unwrap(); + + assert_eq!(test_ctx, ctx); + } +} diff --git a/src/tools/runk/libcontainer/src/cgroup.rs b/src/tools/runk/libcontainer/src/cgroup.rs new file mode 100644 index 0000000000..9b53bb3689 --- /dev/null +++ b/src/tools/runk/libcontainer/src/cgroup.rs @@ -0,0 +1,40 @@ +// Copyright 2021-2022 Sony Group Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +use anyhow::{anyhow, Result}; +use rustjail::cgroups::fs::Manager as CgroupManager; +use std::{ + path::Path, + {fs, thread, time}, +}; + +pub fn destroy_cgroup(cgroup_mg: &CgroupManager) -> Result<()> { + for path in cgroup_mg.paths.values() { + remove_cgroup_dir(Path::new(path))?; + } + + Ok(()) +} + +// Try to remove the provided cgroups path five times with increasing delay between tries. +// If after all there are not removed cgroups, an appropriate error will be returned. +fn remove_cgroup_dir(path: &Path) -> Result<()> { + let mut retries = 5; + let mut delay = time::Duration::from_millis(10); + while retries != 0 { + if retries != 5 { + delay *= 2; + thread::sleep(delay); + } + + if !path.exists() || fs::remove_dir(path).is_ok() { + return Ok(()); + } + + retries -= 1; + } + + return Err(anyhow!("failed to remove cgroups paths: {:?}", path)); +} diff --git a/src/tools/runk/libcontainer/src/container.rs b/src/tools/runk/libcontainer/src/container.rs new file mode 100644 index 0000000000..d5464e9239 --- /dev/null +++ b/src/tools/runk/libcontainer/src/container.rs @@ -0,0 +1,151 @@ +// Copyright 2021-2022 Sony Group Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +use crate::status::Status; +use anyhow::{anyhow, Result}; +use nix::unistd::{chdir, unlink, Pid}; +use oci::Spec; +use rustjail::{ + container::{BaseContainer, LinuxContainer, EXEC_FIFO_FILENAME}, + process::Process, + specconv::CreateOpts, +}; +use slog::Logger; +use std::{ + env::current_dir, + path::{Path, PathBuf}, +}; + +pub const CONFIG_FILE_NAME: &str = "config.json"; + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum ContainerAction { + Create, + Run, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct ContainerContext { + pub id: String, + pub bundle: PathBuf, + pub state_root: PathBuf, + pub spec: Spec, + pub no_pivot_root: bool, + pub console_socket: Option, +} + +impl ContainerContext { + pub async fn launch(&self, action: ContainerAction, logger: &Logger) -> Result { + Status::create_dir(&self.state_root, &self.id)?; + + let current_dir = current_dir()?; + chdir(&self.bundle)?; + + let create_opts = CreateOpts { + cgroup_name: "".to_string(), + use_systemd_cgroup: false, + no_pivot_root: self.no_pivot_root, + no_new_keyring: false, + spec: Some(self.spec.clone()), + rootless_euid: false, + rootless_cgroup: false, + }; + + let mut ctr = LinuxContainer::new( + &self.id, + &self + .state_root + .to_str() + .map(|s| s.to_string()) + .ok_or_else(|| anyhow!("failed to convert bundle path"))?, + create_opts.clone(), + logger, + )?; + + let process = if self.spec.process.is_some() { + Process::new( + logger, + self.spec + .process + .as_ref() + .ok_or_else(|| anyhow!("process config was not present in the spec file"))?, + &self.id, + true, + 0, + )? + } else { + return Err(anyhow!("no process configuration")); + }; + + if let Some(ref csocket_path) = self.console_socket { + ctr.set_console_socket(csocket_path)?; + } + + match action { + ContainerAction::Create => { + ctr.start(process).await?; + } + ContainerAction::Run => { + ctr.run(process).await?; + } + } + + let oci_state = ctr.oci_state()?; + let status = Status::new( + &self.state_root, + oci_state, + ctr.init_process_start_time, + ctr.created, + ctr.cgroup_manager + .ok_or_else(|| anyhow!("cgroup manager was not present"))?, + create_opts, + )?; + + status.save()?; + + if action == ContainerAction::Run { + let fifo_path = get_fifo_path(&status); + if fifo_path.exists() { + unlink(&fifo_path)?; + } + } + + chdir(¤t_dir)?; + + Ok(Pid::from_raw(ctr.init_process_pid)) + } +} + +pub fn get_config_path>(bundle: P) -> PathBuf { + bundle.as_ref().join(CONFIG_FILE_NAME) +} + +pub fn get_fifo_path(status: &Status) -> PathBuf { + status.root.join(&status.id).join(EXEC_FIFO_FILENAME) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::utils::test_utils::*; + use rustjail::container::EXEC_FIFO_FILENAME; + use std::path::PathBuf; + + #[test] + fn test_get_config_path() { + let test_data = PathBuf::from(TEST_BUNDLE_PATH).join(CONFIG_FILE_NAME); + assert_eq!(get_config_path(TEST_BUNDLE_PATH), test_data); + } + + #[test] + fn test_get_fifo_path() { + let test_data = PathBuf::from(TEST_BUNDLE_PATH) + .join(TEST_CONTAINER_ID) + .join(EXEC_FIFO_FILENAME); + let status = create_dummy_status(); + + assert_eq!(get_fifo_path(&status), test_data); + } +} diff --git a/src/tools/runk/libcontainer/src/lib.rs b/src/tools/runk/libcontainer/src/lib.rs new file mode 100644 index 0000000000..49dae46944 --- /dev/null +++ b/src/tools/runk/libcontainer/src/lib.rs @@ -0,0 +1,10 @@ +// Copyright 2021-2022 Sony Group Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +pub mod builder; +pub mod cgroup; +pub mod container; +pub mod status; +pub mod utils; diff --git a/src/tools/runk/libcontainer/src/status.rs b/src/tools/runk/libcontainer/src/status.rs new file mode 100644 index 0000000000..21ba00cda4 --- /dev/null +++ b/src/tools/runk/libcontainer/src/status.rs @@ -0,0 +1,246 @@ +// Copyright 2021-2022 Sony Group Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +use crate::container::get_fifo_path; +use crate::utils::*; +use anyhow::{anyhow, Result}; +use chrono::{DateTime, Utc}; +use libc::pid_t; +use nix::{ + errno::Errno, + sys::{signal::kill, stat::Mode}, + unistd::Pid, +}; +use oci::{ContainerState, State as OCIState}; +use rustjail::{cgroups::fs::Manager as CgroupManager, specconv::CreateOpts}; +use serde::{Deserialize, Serialize}; +use std::{ + fs::{self, File, OpenOptions}, + path::{Path, PathBuf}, + time::SystemTime, +}; + +const STATUS_FILE: &str = "status.json"; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Status { + pub oci_version: String, + pub id: String, + pub pid: pid_t, + pub root: PathBuf, + pub bundle: PathBuf, + pub rootfs: String, + pub process_start_time: u64, + pub created: DateTime, + pub cgroup_manager: CgroupManager, + pub config: CreateOpts, +} + +impl Status { + pub fn new( + root: &Path, + oci_state: OCIState, + process_start_time: u64, + created_time: SystemTime, + cgroup_mg: CgroupManager, + config: CreateOpts, + ) -> Result { + let created = DateTime::from(created_time); + let rootfs = config + .clone() + .spec + .ok_or_else(|| anyhow!("spec config was not present"))? + .root + .as_ref() + .ok_or_else(|| anyhow!("root config was not present in the spec"))? + .path + .clone(); + + Ok(Self { + oci_version: oci_state.version, + id: oci_state.id, + pid: oci_state.pid, + root: root.to_path_buf(), + bundle: PathBuf::from(&oci_state.bundle), + rootfs, + process_start_time, + created, + cgroup_manager: cgroup_mg, + config, + }) + } + + pub fn save(&self) -> Result<()> { + let state_file_path = Self::get_file_path(&self.root, &self.id); + + if !&self.root.exists() { + create_dir_with_mode(&self.root, Mode::S_IRWXU, true)?; + } + + let file = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(state_file_path)?; + + serde_json::to_writer(&file, self)?; + + Ok(()) + } + + pub fn load(state_root: &Path, id: &str) -> Result { + let state_file_path = Self::get_file_path(state_root, id); + if !state_file_path.exists() { + return Err(anyhow!("container \"{}\" does not exist", id)); + } + + let file = File::open(&state_file_path)?; + let state: Self = serde_json::from_reader(&file)?; + + Ok(state) + } + + pub fn create_dir(state_root: &Path, id: &str) -> Result<()> { + let state_dir_path = Self::get_dir_path(state_root, id); + if !state_dir_path.exists() { + create_dir_with_mode(state_dir_path, Mode::S_IRWXU, true)?; + } else { + return Err(anyhow!("container with id exists: \"{}\"", id)); + } + + Ok(()) + } + + pub fn remove_dir(&self) -> Result<()> { + let state_dir_path = Self::get_dir_path(&self.root, &self.id); + fs::remove_dir_all(state_dir_path)?; + + Ok(()) + } + + pub fn get_dir_path(state_root: &Path, id: &str) -> PathBuf { + state_root.join(id) + } + + pub fn get_file_path(state_root: &Path, id: &str) -> PathBuf { + state_root.join(id).join(STATUS_FILE) + } +} + +pub fn is_process_running(pid: Pid) -> Result { + match kill(pid, None) { + Err(errno) => { + if errno != Errno::ESRCH { + return Err(anyhow!("no such process")); + } + Ok(false) + } + Ok(()) => Ok(true), + } +} + +pub fn get_current_container_state(status: &Status) -> Result { + let running = is_process_running(Pid::from_raw(status.pid))?; + let mut has_fifo = false; + + if running { + let fifo = get_fifo_path(status); + if fifo.exists() { + has_fifo = true + } + } + + if running && !has_fifo { + // TODO: Check paused status. + // runk does not support pause command currently. + } + + if !running { + Ok(ContainerState::Stopped) + } else if has_fifo { + Ok(ContainerState::Created) + } else { + Ok(ContainerState::Running) + } +} + +pub fn get_all_pid(cgm: &CgroupManager) -> Result> { + let cgroup_path = cgm.paths.get("devices"); + match cgroup_path { + Some(v) => { + let path = Path::new(v); + if !path.exists() { + return Err(anyhow!("cgroup devices file does not exist")); + } + + let procs_path = path.join("cgroup.procs"); + let pids: Vec = lines_from_file(&procs_path)? + .into_iter() + .map(|v| { + Pid::from_raw( + v.parse::() + .expect("failed to parse string into pid_t"), + ) + }) + .collect(); + Ok(pids) + } + None => Err(anyhow!("cgroup devices file dose not exist")), + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::utils::test_utils::*; + use chrono::{DateTime, Utc}; + use nix::unistd::getpid; + use oci::ContainerState; + use rustjail::cgroups::fs::Manager as CgroupManager; + use std::path::Path; + use std::time::SystemTime; + + #[test] + fn test_status() { + let cgm: CgroupManager = serde_json::from_str(TEST_CGM_DATA).unwrap(); + let oci_state = create_dummy_oci_state(); + let created = SystemTime::now(); + let status = Status::new( + Path::new(TEST_BUNDLE_PATH), + oci_state.clone(), + 1, + created, + cgm, + create_dummy_opts(), + ) + .unwrap(); + + assert_eq!(status.id, oci_state.id); + assert_eq!(status.pid, oci_state.pid); + assert_eq!(status.process_start_time, 1); + assert_eq!(status.created, DateTime::::from(created)); + } + + #[test] + fn test_is_process_running() { + let pid = getpid(); + let ret = is_process_running(pid).unwrap(); + assert!(ret); + } + + #[test] + fn test_get_current_container_state() { + let status = create_dummy_status(); + let state = get_current_container_state(&status).unwrap(); + assert_eq!(state, ContainerState::Running); + } + + #[test] + fn test_get_all_pid() { + let cgm: CgroupManager = serde_json::from_str(TEST_CGM_DATA).unwrap(); + assert!(get_all_pid(&cgm).is_ok()); + } +} diff --git a/src/tools/runk/libcontainer/src/utils.rs b/src/tools/runk/libcontainer/src/utils.rs new file mode 100644 index 0000000000..5a356d7c2d --- /dev/null +++ b/src/tools/runk/libcontainer/src/utils.rs @@ -0,0 +1,106 @@ +// Copyright 2021-2022 Sony Group Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +use anyhow::{anyhow, Result}; +use nix::sys::stat::Mode; +use std::{ + fs::{DirBuilder, File}, + io::{prelude::*, BufReader}, + os::unix::fs::DirBuilderExt, + path::Path, +}; + +pub fn lines_from_file>(path: P) -> Result> { + let file = File::open(&path)?; + let buf = BufReader::new(file); + Ok(buf + .lines() + .map(|v| v.expect("could not parse line")) + .collect()) +} + +pub fn create_dir_with_mode>(path: P, mode: Mode, recursive: bool) -> Result<()> { + let path = path.as_ref(); + if path.exists() { + return Err(anyhow!("{} already exists", path.display())); + } + + Ok(DirBuilder::new() + .recursive(recursive) + .mode(mode.bits()) + .create(path)?) +} + +#[cfg(test)] +pub(crate) mod test_utils { + use crate::status::Status; + use nix::unistd::getpid; + use oci::State as OCIState; + use oci::{ContainerState, Root, Spec}; + use rustjail::cgroups::fs::Manager as CgroupManager; + use rustjail::specconv::CreateOpts; + use std::path::Path; + use std::time::SystemTime; + + pub const TEST_CONTAINER_ID: &str = "test"; + pub const TEST_BUNDLE_PATH: &str = "/test"; + pub const TEST_ANNOTATION: &str = "test"; + pub const TEST_CGM_DATA: &str = r#"{ + "paths": { + "devices": "/sys/fs/cgroup/devices" + }, + "mounts": { + "devices": "/sys/fs/cgroup/devices" + }, + "cpath": "test" + }"#; + + pub fn create_dummy_opts() -> CreateOpts { + let spec = Spec { + root: Some(Root::default()), + ..Default::default() + }; + CreateOpts { + cgroup_name: "".to_string(), + use_systemd_cgroup: false, + no_pivot_root: false, + no_new_keyring: false, + spec: Some(spec), + rootless_euid: false, + rootless_cgroup: false, + } + } + + pub fn create_dummy_oci_state() -> OCIState { + OCIState { + version: "1.0.0".to_string(), + id: TEST_CONTAINER_ID.to_string(), + status: ContainerState::Running, + pid: getpid().as_raw(), + bundle: TEST_BUNDLE_PATH.to_string(), + annotations: [(TEST_ANNOTATION.to_string(), TEST_ANNOTATION.to_string())] + .iter() + .cloned() + .collect(), + } + } + + pub fn create_dummy_status() -> Status { + let cgm: CgroupManager = serde_json::from_str(TEST_CGM_DATA).unwrap(); + let oci_state = create_dummy_oci_state(); + let created = SystemTime::now(); + let status = Status::new( + Path::new(TEST_BUNDLE_PATH), + oci_state.clone(), + 1, + created, + cgm, + create_dummy_opts(), + ) + .unwrap(); + + status + } +} diff --git a/src/tools/runk/src/commands/create.rs b/src/tools/runk/src/commands/create.rs new file mode 100644 index 0000000000..b29d5b9141 --- /dev/null +++ b/src/tools/runk/src/commands/create.rs @@ -0,0 +1,37 @@ +// Copyright 2021-2022 Sony Group Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +use anyhow::Result; +use libcontainer::{builder::ContainerBuilder, container::ContainerAction}; +use liboci_cli::Create; +use nix::unistd::Pid; +use slog::{info, Logger}; +use std::{fs, path::Path}; + +pub async fn run(opts: Create, root: &Path, logger: &Logger) -> Result<()> { + let ctx = ContainerBuilder::default() + .id(opts.container_id) + .bundle(opts.bundle) + .root(root.to_path_buf()) + .console_socket(opts.console_socket) + .build()? + .create_ctx()?; + + let pid = ctx.launch(ContainerAction::Create, logger).await?; + + if let Some(ref pid_file) = opts.pid_file { + create_pid_file(pid_file, pid)?; + } + + info!(&logger, "create command finished successfully"); + + Ok(()) +} + +fn create_pid_file>(pid_file: P, pid: Pid) -> Result<()> { + fs::write(pid_file.as_ref(), format!("{}", pid))?; + + Ok(()) +} diff --git a/src/tools/runk/src/commands/delete.rs b/src/tools/runk/src/commands/delete.rs new file mode 100644 index 0000000000..f84c79d08a --- /dev/null +++ b/src/tools/runk/src/commands/delete.rs @@ -0,0 +1,103 @@ +// Copyright 2021-2022 Sony Group Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +use anyhow::{anyhow, Result}; +use libcontainer::{ + cgroup, + status::{get_current_container_state, Status}, +}; +use liboci_cli::Delete; +use nix::{ + errno::Errno, + sys::signal::{kill, Signal}, + unistd::Pid, +}; +use oci::{ContainerState, State as OCIState}; +use rustjail::container; +use slog::{info, Logger}; +use std::{fs, path::Path}; + +pub async fn run(opts: Delete, root: &Path, logger: &Logger) -> Result<()> { + let container_id = &opts.container_id; + let status_dir = Status::get_dir_path(root, container_id); + if !status_dir.exists() { + return Err(anyhow!("container {} does not exist", container_id)); + } + + let status = if let Ok(value) = Status::load(root, container_id) { + value + } else { + fs::remove_dir_all(status_dir)?; + return Ok(()); + }; + + let spec = status + .config + .spec + .as_ref() + .ok_or_else(|| anyhow!("spec config was not present in the status"))?; + + let oci_state = OCIState { + version: status.oci_version.clone(), + id: status.id.clone(), + status: get_current_container_state(&status)?, + pid: status.pid, + bundle: status + .bundle + .to_str() + .ok_or_else(|| anyhow!("invalid bundle path"))? + .to_string(), + annotations: spec.annotations.clone(), + }; + + if spec.hooks.is_some() { + let hooks = spec + .hooks + .as_ref() + .ok_or_else(|| anyhow!("hooks config was not present"))?; + for h in hooks.poststop.iter() { + container::execute_hook(logger, h, &oci_state).await?; + } + } + + match oci_state.status { + ContainerState::Stopped => { + destroy_container(&status)?; + } + ContainerState::Created => { + kill(Pid::from_raw(status.pid), Some(Signal::SIGKILL))?; + destroy_container(&status)?; + } + _ => { + if opts.force { + match kill(Pid::from_raw(status.pid), Some(Signal::SIGKILL)) { + Err(errno) => { + if errno != Errno::ESRCH { + return Err(anyhow!("{}", errno)); + } + } + Ok(()) => {} + } + destroy_container(&status)?; + } else { + return Err(anyhow!( + "cannot delete container {} that is not stopped", + container_id + )); + } + } + } + + info!(&logger, "delete command finished successfully"); + + Ok(()) +} + +fn destroy_container(status: &Status) -> Result<()> { + cgroup::destroy_cgroup(&status.cgroup_manager)?; + status.remove_dir()?; + + Ok(()) +} diff --git a/src/tools/runk/src/commands/kill.rs b/src/tools/runk/src/commands/kill.rs new file mode 100644 index 0000000000..e9de813596 --- /dev/null +++ b/src/tools/runk/src/commands/kill.rs @@ -0,0 +1,82 @@ +// Copyright 2021-2022 Sony Group Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +use anyhow::{anyhow, Result}; +use libcontainer::status::{self, get_current_container_state, Status}; +use liboci_cli::Kill; +use nix::{ + sys::signal::{kill, Signal}, + unistd::Pid, +}; +use oci::ContainerState; +use slog::{info, Logger}; +use std::{convert::TryFrom, path::Path, str::FromStr}; + +pub fn run(opts: Kill, state_root: &Path, logger: &Logger) -> Result<()> { + let container_id = &opts.container_id; + let status = Status::load(state_root, container_id)?; + let current_state = get_current_container_state(&status)?; + let sig = parse_signal(&opts.signal)?; + + // TODO: liboci-cli does not support --all option for kill command. + // After liboci-cli supports the option, we will change the following code. + let all = false; + if all { + let pids = status::get_all_pid(&status.cgroup_manager)?; + for pid in pids { + if !status::is_process_running(pid)? { + continue; + } + kill(pid, sig)?; + } + } else { + if current_state == ContainerState::Stopped { + return Err(anyhow!("container {} not running", container_id)); + } + + let p = Pid::from_raw(status.pid); + if status::is_process_running(p)? { + kill(p, sig)?; + } + } + + info!(&logger, "kill command finished successfully"); + + Ok(()) +} + +fn parse_signal(signal: &str) -> Result { + if let Ok(num) = signal.parse::() { + return Ok(Signal::try_from(num)?); + } + + let mut signal_upper = signal.to_uppercase(); + if !signal_upper.starts_with("SIG") { + signal_upper = "SIG".to_string() + &signal_upper; + } + + Ok(Signal::from_str(&signal_upper)?) +} + +#[cfg(test)] +mod tests { + use super::*; + use nix::sys::signal::Signal; + + #[test] + fn test_parse_signal() { + assert_eq!(Signal::SIGHUP, parse_signal("1").unwrap()); + assert_eq!(Signal::SIGHUP, parse_signal("sighup").unwrap()); + assert_eq!(Signal::SIGHUP, parse_signal("hup").unwrap()); + assert_eq!(Signal::SIGHUP, parse_signal("SIGHUP").unwrap()); + assert_eq!(Signal::SIGHUP, parse_signal("HUP").unwrap()); + + assert_eq!(Signal::SIGKILL, parse_signal("9").unwrap()); + assert_eq!(Signal::SIGKILL, parse_signal("sigkill").unwrap()); + assert_eq!(Signal::SIGKILL, parse_signal("kill").unwrap()); + assert_eq!(Signal::SIGKILL, parse_signal("SIGKILL").unwrap()); + assert_eq!(Signal::SIGKILL, parse_signal("KILL").unwrap()); + } +} diff --git a/src/tools/runk/src/commands/mod.rs b/src/tools/runk/src/commands/mod.rs new file mode 100644 index 0000000000..12017263db --- /dev/null +++ b/src/tools/runk/src/commands/mod.rs @@ -0,0 +1,12 @@ +// Copyright 2021-2022 Sony Group Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +pub mod create; +pub mod delete; +pub mod kill; +pub mod run; +pub mod spec; +pub mod start; +pub mod state; diff --git a/src/tools/runk/src/commands/run.rs b/src/tools/runk/src/commands/run.rs new file mode 100644 index 0000000000..bdf2e91d9b --- /dev/null +++ b/src/tools/runk/src/commands/run.rs @@ -0,0 +1,26 @@ +// Copyright 2021-2022 Sony Group Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +use anyhow::Result; +use libcontainer::{builder::ContainerBuilder, container::ContainerAction}; +use liboci_cli::Run; +use slog::{info, Logger}; +use std::path::Path; + +pub async fn run(opts: Run, root: &Path, logger: &Logger) -> Result<()> { + let ctx = ContainerBuilder::default() + .id(opts.container_id) + .bundle(opts.bundle) + .root(root.to_path_buf()) + .console_socket(opts.console_socket) + .build()? + .create_ctx()?; + + ctx.launch(ContainerAction::Run, logger).await?; + + info!(&logger, "run command finished successfully"); + + Ok(()) +} diff --git a/src/tools/runk/src/commands/spec.rs b/src/tools/runk/src/commands/spec.rs new file mode 100644 index 0000000000..4dcf4d9ebf --- /dev/null +++ b/src/tools/runk/src/commands/spec.rs @@ -0,0 +1,207 @@ +// Copyright 2021-2022 Sony Group Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +//use crate::container::get_config_path; +use anyhow::Result; +use libcontainer::container::CONFIG_FILE_NAME; +use liboci_cli::Spec; +use slog::{info, Logger}; +use std::{fs::File, io::Write, path::Path}; + +pub const DEFAULT_SPEC: &str = r#"{ + "ociVersion": "1.0.2-dev", + "process": { + "terminal": true, + "user": { + "uid": 0, + "gid": 0 + }, + "args": [ + "sh" + ], + "env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=xterm" + ], + "cwd": "/", + "capabilities": { + "bounding": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "effective": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "inheritable": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "permitted": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "ambient": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ] + }, + "rlimits": [ + { + "type": "RLIMIT_NOFILE", + "hard": 1024, + "soft": 1024 + } + ], + "noNewPrivileges": true + }, + "root": { + "path": "rootfs", + "readonly": true + }, + "hostname": "runk", + "mounts": [ + { + "destination": "/proc", + "type": "proc", + "source": "proc" + }, + { + "destination": "/dev", + "type": "tmpfs", + "source": "tmpfs", + "options": [ + "nosuid", + "strictatime", + "mode=755", + "size=65536k" + ] + }, + { + "destination": "/dev/pts", + "type": "devpts", + "source": "devpts", + "options": [ + "nosuid", + "noexec", + "newinstance", + "ptmxmode=0666", + "mode=0620", + "gid=5" + ] + }, + { + "destination": "/dev/shm", + "type": "tmpfs", + "source": "shm", + "options": [ + "nosuid", + "noexec", + "nodev", + "mode=1777", + "size=65536k" + ] + }, + { + "destination": "/dev/mqueue", + "type": "mqueue", + "source": "mqueue", + "options": [ + "nosuid", + "noexec", + "nodev" + ] + }, + { + "destination": "/sys", + "type": "sysfs", + "source": "sysfs", + "options": [ + "nosuid", + "noexec", + "nodev", + "ro" + ] + }, + { + "destination": "/sys/fs/cgroup", + "type": "cgroup", + "source": "cgroup", + "options": [ + "nosuid", + "noexec", + "nodev", + "relatime", + "ro" + ] + } + ], + "linux": { + "resources": { + "devices": [ + { + "allow": false, + "access": "rwm" + } + ] + }, + "namespaces": [ + { + "type": "pid" + }, + { + "type": "network" + }, + { + "type": "ipc" + }, + { + "type": "uts" + }, + { + "type": "mount" + } + ], + "maskedPaths": [ + "/proc/acpi", + "/proc/asound", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/sys/firmware", + "/proc/scsi" + ], + "readonlyPaths": [ + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger" + ] + } +}"#; + +pub fn run(_opts: Spec, logger: &Logger) -> Result<()> { + // TODO: liboci-cli does not support --bundle option for spec command. + // After liboci-cli supports the option, we will change the following code. + // let config_path = get_config_path(&opts.bundle); + let config_path = Path::new(".").join(CONFIG_FILE_NAME); + let config_data = DEFAULT_SPEC; + + let mut file = File::create(config_path)?; + file.write_all(config_data.as_bytes())?; + + info!(&logger, "spec command finished successfully"); + + Ok(()) +} diff --git a/src/tools/runk/src/commands/start.rs b/src/tools/runk/src/commands/start.rs new file mode 100644 index 0000000000..7504936887 --- /dev/null +++ b/src/tools/runk/src/commands/start.rs @@ -0,0 +1,48 @@ +// Copyright 2021-2022 Sony Group Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +use crate::commands::state::get_container_state_name; +use anyhow::{anyhow, Result}; +use libcontainer::{ + container::get_fifo_path, + status::{get_current_container_state, Status}, +}; +use liboci_cli::Start; +use nix::unistd::unlink; +use oci::ContainerState; +use slog::{info, Logger}; +use std::{fs::OpenOptions, io::prelude::*, path::Path, time::SystemTime}; + +pub fn run(opts: Start, state_root: &Path, logger: &Logger) -> Result<()> { + let mut status = Status::load(state_root, &opts.container_id)?; + let state = get_current_container_state(&status)?; + if state != ContainerState::Created { + return Err(anyhow!( + "cannot start a container in the {} state", + get_container_state_name(state) + )); + }; + + let fifo_path = get_fifo_path(&status); + let mut file = OpenOptions::new().write(true).open(&fifo_path)?; + + file.write_all("0".as_bytes())?; + + info!(&logger, "container started"); + + status.process_start_time = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH)? + .as_secs(); + + status.save()?; + + if fifo_path.exists() { + unlink(&fifo_path)?; + } + + info!(&logger, "start command finished successfully"); + + Ok(()) +} diff --git a/src/tools/runk/src/commands/state.rs b/src/tools/runk/src/commands/state.rs new file mode 100644 index 0000000000..eb6b87d492 --- /dev/null +++ b/src/tools/runk/src/commands/state.rs @@ -0,0 +1,79 @@ +// Copyright 2021-2022 Sony Group Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +use anyhow::Result; +use chrono::{DateTime, Utc}; +use libcontainer::status::{get_current_container_state, Status}; +use liboci_cli::State; +use oci::ContainerState; +use serde::{Deserialize, Serialize}; +use slog::{info, Logger}; +use std::path::{Path, PathBuf}; + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct RuntimeState { + pub oci_version: String, + pub id: String, + pub pid: i32, + pub status: String, + pub bundle: PathBuf, + pub created: DateTime, +} + +impl RuntimeState { + pub fn new(status: Status, state: ContainerState) -> Self { + Self { + oci_version: status.oci_version, + id: status.id, + pid: status.pid, + status: get_container_state_name(state), + bundle: status.bundle, + created: status.created, + } + } +} + +pub fn run(opts: State, state_root: &Path, logger: &Logger) -> Result<()> { + let status = Status::load(state_root, &opts.container_id)?; + let state = get_current_container_state(&status)?; + let oci_state = RuntimeState::new(status, state); + let json_state = &serde_json::to_string_pretty(&oci_state)?; + + println!("{}", json_state); + + info!(&logger, "state command finished successfully"); + + Ok(()) +} + +pub fn get_container_state_name(state: ContainerState) -> String { + match state { + ContainerState::Creating => "creating", + ContainerState::Created => "created", + ContainerState::Running => "running", + ContainerState::Stopped => "stopped", + ContainerState::Paused => "paused", + } + .into() +} + +#[cfg(test)] +mod tests { + use super::*; + use oci::ContainerState; + + #[test] + fn test_get_container_state_name() { + assert_eq!( + "creating", + get_container_state_name(ContainerState::Creating) + ); + assert_eq!("created", get_container_state_name(ContainerState::Created)); + assert_eq!("running", get_container_state_name(ContainerState::Running)); + assert_eq!("stopped", get_container_state_name(ContainerState::Stopped)); + assert_eq!("paused", get_container_state_name(ContainerState::Paused)); + } +} diff --git a/src/tools/runk/src/main.rs b/src/tools/runk/src/main.rs new file mode 100644 index 0000000000..865a642589 --- /dev/null +++ b/src/tools/runk/src/main.rs @@ -0,0 +1,111 @@ +// Copyright 2021-2022 Sony Group Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +use anyhow::{anyhow, Result}; +use clap::{crate_description, crate_name, Parser}; +use liboci_cli::{CommonCmd, GlobalOpts, StandardCmd}; +use slog::{o, Logger}; +use slog_async::AsyncGuard; +use std::{ + fs::OpenOptions, + path::{Path, PathBuf}, + process::exit, +}; + +const DEFAULT_ROOT_DIR: &str = "/run/runk"; +const DEFAULT_LOG_LEVEL: slog::Level = slog::Level::Info; + +mod commands; + +#[derive(Parser, Debug)] +enum SubCommand { + #[clap(flatten)] + Standard(StandardCmd), + #[clap(flatten)] + Common(CommonCmd), +} + +#[derive(Parser, Debug)] +#[clap(version, author, about = crate_description!())] +struct Cli { + #[clap(flatten)] + global: GlobalOpts, + #[clap(subcommand)] + subcmd: SubCommand, +} + +async fn cmd_run(subcmd: SubCommand, root_path: &Path, logger: &Logger) -> Result<()> { + match subcmd { + SubCommand::Standard(cmd) => match cmd { + StandardCmd::Create(create) => commands::create::run(create, root_path, logger).await, + StandardCmd::Start(start) => commands::start::run(start, root_path, logger), + StandardCmd::Kill(kill) => commands::kill::run(kill, root_path, logger), + StandardCmd::Delete(delete) => commands::delete::run(delete, root_path, logger).await, + StandardCmd::State(state) => commands::state::run(state, root_path, logger), + }, + SubCommand::Common(cmd) => match cmd { + CommonCmd::Run(run) => commands::run::run(run, root_path, logger).await, + CommonCmd::Spec(spec) => commands::spec::run(spec, logger), + _ => { + return Err(anyhow!("command is not implemented yet")); + } + }, + } +} + +fn setup_logger( + log_file: Option, + log_level: slog::Level, +) -> Result<(Logger, Option)> { + if let Some(ref file) = log_file { + let log_writer = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .truncate(true) + .open(&file)?; + + // TODO: Support 'text' log format. + let (logger_local, logger_async_guard_local) = + logging::create_logger(crate_name!(), crate_name!(), log_level, log_writer); + + Ok((logger_local, Some(logger_async_guard_local))) + } else { + let logger = slog::Logger::root(slog::Discard, o!()); + Ok((logger, None)) + } +} + +async fn real_main() -> Result<()> { + let cli = Cli::parse(); + + let root_path = if let Some(path) = cli.global.root { + path + } else { + PathBuf::from(DEFAULT_ROOT_DIR) + }; + + let log_level = if cli.global.debug { + slog::Level::Debug + } else { + DEFAULT_LOG_LEVEL + }; + + let (logger, _async_guard) = setup_logger(cli.global.log, log_level)?; + + cmd_run(cli.subcmd, &root_path, &logger).await?; + + Ok(()) +} + +#[tokio::main] +async fn main() { + if let Err(e) = real_main().await { + eprintln!("ERROR: {}", e); + exit(1); + } + + exit(0); +}