mirror of https://github.com/chaos-mesh/toda.git
Compare commits
20 Commits
Author | SHA1 | Date |
---|---|---|
|
523c67dbd5 | |
|
4bc8404382 | |
|
04ba4edc20 | |
|
67b43ee417 | |
|
7eb184edd0 | |
|
f9c784ceac | |
|
65071a4a6e | |
|
7ea57ef5f3 | |
|
ac795a08cf | |
|
7ca342b0b0 | |
|
8734addae3 | |
|
a866988506 | |
|
62043db60a | |
|
4a991b5fbb | |
|
fe18e46efa | |
|
5aee355f82 | |
|
fbf1cb7215 | |
|
ab6be766d3 | |
|
c6248aa5c1 | |
|
a2ec5f7947 |
|
@ -23,7 +23,7 @@ jobs:
|
|||
- name: Add user_allow_other to /etc/fuse.conf
|
||||
run: echo "user_allow_other" | sudo tee -a /etc/fuse.conf
|
||||
- name: Run tests
|
||||
run: cargo test --verbose
|
||||
run: cargo test --verbose -- --test-threads=1
|
||||
clippy_check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler32"
|
||||
version = "1.2.0"
|
||||
|
@ -21,7 +23,7 @@ version = "0.11.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -30,7 +32,7 @@ version = "0.12.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -58,7 +60,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
|||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -85,6 +87,12 @@ version = "0.5.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.66"
|
||||
|
@ -113,7 +121,7 @@ dependencies = [
|
|||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -202,6 +210,22 @@ version = "1.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fuchsia-zircon-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
|
||||
[[package]]
|
||||
name = "fuser"
|
||||
version = "0.6.0"
|
||||
|
@ -214,6 +238,12 @@ dependencies = [
|
|||
"users",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.1.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.12"
|
||||
|
@ -254,6 +284,7 @@ dependencies = [
|
|||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -295,6 +326,7 @@ version = "0.3.12"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b"
|
||||
dependencies = [
|
||||
"futures 0.1.31",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
|
@ -366,6 +398,35 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
|
||||
dependencies = [
|
||||
"matches",
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
|
||||
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.9.0"
|
||||
|
@ -381,6 +442,95 @@ version = "0.4.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||
|
||||
[[package]]
|
||||
name = "jsonrpc-client-transports"
|
||||
version = "17.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15b6c6ad01c7354d60de493148c30ac8a82b759e22ae678c8705e9b8e0c566a4"
|
||||
dependencies = [
|
||||
"derive_more",
|
||||
"futures 0.3.12",
|
||||
"jsonrpc-core",
|
||||
"jsonrpc-pubsub",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonrpc-core"
|
||||
version = "17.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07569945133257ff557eb37b015497104cea61a2c9edaf126c1cbd6e8332397f"
|
||||
dependencies = [
|
||||
"futures 0.3.12",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonrpc-core-client"
|
||||
version = "17.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ac9d56dc729912796637c30f475bbf834594607b27740dfea6e5fa7ba40d1f1"
|
||||
dependencies = [
|
||||
"futures 0.3.12",
|
||||
"jsonrpc-client-transports",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonrpc-derive"
|
||||
version = "17.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b68ba7e76e5c7796cfa4d2a30e83986550c34404c6d40551c902ca6f7bd4a137"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonrpc-pubsub"
|
||||
version = "17.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c48dbebce7a9c88ab272a4db7d6478aa4c6d9596e6c086366e89efc4e9ed89e"
|
||||
dependencies = [
|
||||
"futures 0.3.12",
|
||||
"jsonrpc-core",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"rand",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonrpc-stdio-server"
|
||||
version = "17.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "369ec805537bd431d6d9a2df7297c73e214da68efc90c1b8c325d63e55aec5a7"
|
||||
dependencies = [
|
||||
"futures 0.3.12",
|
||||
"jsonrpc-core",
|
||||
"log",
|
||||
"tokio 0.2.24",
|
||||
"tokio-util 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -411,6 +561,15 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3286f09f7d4926fc486334f28d8d2e6ebe4f7f9994494b6dab27ddfad2c9b11b"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.13"
|
||||
|
@ -429,6 +588,12 @@ dependencies = [
|
|||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.4"
|
||||
|
@ -444,6 +609,81 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"fuchsia-zircon",
|
||||
"fuchsia-zircon-sys",
|
||||
"iovec",
|
||||
"kernel32-sys",
|
||||
"libc",
|
||||
"log",
|
||||
"miow 0.2.2",
|
||||
"net2",
|
||||
"slab",
|
||||
"winapi 0.2.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-named-pipes"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656"
|
||||
dependencies = [
|
||||
"log",
|
||||
"mio",
|
||||
"miow 0.3.6",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-uds"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
|
||||
dependencies = [
|
||||
"iovec",
|
||||
"libc",
|
||||
"mio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d"
|
||||
dependencies = [
|
||||
"kernel32-sys",
|
||||
"net2",
|
||||
"winapi 0.2.8",
|
||||
"ws2_32-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897"
|
||||
dependencies = [
|
||||
"socket2",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"libc",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.18.0"
|
||||
|
@ -491,6 +731,37 @@ version = "1.5.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "0.4.27"
|
||||
|
@ -541,6 +812,15 @@ version = "0.2.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
|
||||
dependencies = [
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
|
@ -651,6 +931,15 @@ dependencies = [
|
|||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.4.3"
|
||||
|
@ -700,6 +989,12 @@ version = "1.0.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[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.120"
|
||||
|
@ -740,6 +1035,15 @@ dependencies = [
|
|||
"lazy_static",
|
||||
]
|
||||
|
||||
[[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"
|
||||
|
@ -752,6 +1056,17 @@ version = "1.6.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
|
@ -848,12 +1163,27 @@ checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "toda"
|
||||
version = "0.1.18"
|
||||
version = "0.2.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -862,10 +1192,14 @@ dependencies = [
|
|||
"dynasmrt",
|
||||
"env_logger",
|
||||
"fuser",
|
||||
"futures",
|
||||
"futures 0.3.12",
|
||||
"glob",
|
||||
"humantime-serde",
|
||||
"itertools",
|
||||
"jsonrpc-core",
|
||||
"jsonrpc-core-client",
|
||||
"jsonrpc-derive",
|
||||
"jsonrpc-stdio-server",
|
||||
"libc",
|
||||
"nix",
|
||||
"once_cell",
|
||||
|
@ -878,7 +1212,8 @@ dependencies = [
|
|||
"structopt",
|
||||
"thiserror",
|
||||
"time",
|
||||
"tokio",
|
||||
"tokio 0.2.24",
|
||||
"tokio-util 0.6.9",
|
||||
"tracing",
|
||||
"tracing-futures",
|
||||
"tracing-subscriber",
|
||||
|
@ -890,12 +1225,79 @@ version = "0.2.24"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "099837d3464c16a808060bb3f02263b412f6fafcb5d01c533d309985fbeebe48"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"bytes 0.5.6",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"iovec",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"memchr",
|
||||
"mio",
|
||||
"mio-named-pipes",
|
||||
"mio-uds",
|
||||
"num_cpus",
|
||||
"pin-project-lite 0.1.11",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"tokio-macros",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838"
|
||||
dependencies = [
|
||||
"pin-project-lite 0.2.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e44da00bfc73a25f814cd8d7e57a68a5c31b74b3152a0a1d1f590c97ed06265a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499"
|
||||
dependencies = [
|
||||
"bytes 0.5.6",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"log",
|
||||
"pin-project-lite 0.1.11",
|
||||
"tokio 0.2.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"log",
|
||||
"pin-project-lite 0.2.4",
|
||||
"tokio 1.15.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -983,6 +1385,24 @@ dependencies = [
|
|||
"tracing-serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||
dependencies = [
|
||||
"matches",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.7.1"
|
||||
|
@ -1001,6 +1421,17 @@ version = "0.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "1.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
|
||||
dependencies = [
|
||||
"idna",
|
||||
"matches",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "users"
|
||||
version = "0.11.0"
|
||||
|
@ -1035,6 +1466,12 @@ version = "0.10.0+wasi-snapshot-preview1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
@ -1045,6 +1482,12 @@ dependencies = [
|
|||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
@ -1057,7 +1500,7 @@ version = "0.1.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1065,3 +1508,13 @@ 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 = "ws2_32-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "toda"
|
||||
version = "0.1.18"
|
||||
version = "0.2.4"
|
||||
authors = ["Yang Keao <keao.yang@yahoo.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
@ -10,11 +10,12 @@ edition = "2018"
|
|||
structopt = "0.3"
|
||||
nix = "0.18"
|
||||
anyhow = "1.0"
|
||||
fuser = {version = "0.6", features = ["abi-7-31"]}
|
||||
fuser = {version = "0.6", features = ["abi-7-19"]}
|
||||
time = "0.1"
|
||||
libc = "0.2"
|
||||
async-trait = "0.1"
|
||||
tokio = {version = "0.2", features = ["rt-core", "rt-threaded", "sync", "fs", "time", "blocking"]}
|
||||
tokio = {version = "0.2", features = ["rt-core", "rt-threaded", "sync", "fs", "time", "blocking", "macros", "full"]}
|
||||
tokio-util = "0.6"
|
||||
thiserror = "1.0"
|
||||
futures = "0.3"
|
||||
derive_more = "0.99.9"
|
||||
|
@ -34,6 +35,10 @@ retry = "1.2.0"
|
|||
tracing = "0.1"
|
||||
tracing-futures = "0.2"
|
||||
tracing-subscriber = "0.2"
|
||||
jsonrpc-stdio-server = "17.0.0"
|
||||
jsonrpc-derive = "17.0.0"
|
||||
jsonrpc-core = "17.0.0"
|
||||
jsonrpc-core-client = "17.0.0"
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
|
@ -12,7 +12,7 @@ ENV https_proxy $HTTPS_PROXY
|
|||
|
||||
RUN apt-get update && apt-get install build-essential curl git pkg-config libfuse-dev fuse -y && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain nightly-2020-07-01 -y
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain nightly-2021-12-23 -y
|
||||
ENV PATH "/root/.cargo/bin:${PATH}"
|
||||
|
||||
RUN if [ -n "$HTTP_PROXY" ]; then echo "[http]\n\
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
[
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "update",
|
||||
"params": [
|
||||
[
|
||||
{
|
||||
"type": "latency",
|
||||
"path": "/var/run/test/**/*",
|
||||
"path": "/var/lib/postgresql/data/**/*",
|
||||
"percent": 100,
|
||||
"latency": "10ms"
|
||||
"latency": "10s"
|
||||
}
|
||||
]
|
||||
]
|
||||
],
|
||||
"id": 1
|
||||
}
|
|
@ -1,22 +1,23 @@
|
|||
[
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "update",
|
||||
"params": [
|
||||
[
|
||||
{
|
||||
"type": "mistake",
|
||||
"path": "/tmp/test/test.txt",
|
||||
"methods":["READ","WRITE"],
|
||||
"mistakes":[
|
||||
{
|
||||
"filling":"zero",
|
||||
"percent":100,
|
||||
"maxOccurrences":1,
|
||||
"maxLength":10
|
||||
},
|
||||
{
|
||||
"filling": "random",
|
||||
"percent": 100,
|
||||
"maxOccurrences": 1,
|
||||
"maxLength": 10
|
||||
}
|
||||
"path": "/var/test/**/*",
|
||||
"methods": [
|
||||
"READ",
|
||||
"WRITE"
|
||||
],
|
||||
"percent":100
|
||||
"mistake": {
|
||||
"filling": "zero",
|
||||
"maxOccurrences": 1,
|
||||
"maxLength": 10000
|
||||
},
|
||||
"percent": 100
|
||||
}
|
||||
]
|
||||
]
|
||||
],
|
||||
"id": 1
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
[]
|
|
@ -1 +1 @@
|
|||
nightly-2020-07-01
|
||||
nightly-2021-12-23
|
|
@ -0,0 +1,4 @@
|
|||
reorder_imports = true
|
||||
imports_granularity = "Module"
|
||||
group_imports = "StdExternalCrate"
|
||||
unstable_features = true
|
|
@ -1,21 +1,18 @@
|
|||
use std::ffi::OsString;
|
||||
use std::fmt::Debug;
|
||||
use std::future::Future;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use fuser::*;
|
||||
use tracing::trace_span;
|
||||
use tracing_futures::Instrument;
|
||||
|
||||
use super::errors::Result;
|
||||
use super::reply::*;
|
||||
use super::runtime::spawn;
|
||||
|
||||
use std::ffi::OsString;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
future::Future,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use tracing::trace_span;
|
||||
|
||||
pub fn spawn_reply<F, R, V>(id: u64, reply: R, f: F)
|
||||
where
|
||||
F: Future<Output = Result<V>> + Send + 'static,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use nix::errno::Errno;
|
||||
use nix::Error;
|
||||
use thiserror::Error;
|
||||
|
||||
use tracing::error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
|
@ -69,11 +68,11 @@ impl From<tokio::task::JoinError> for HookFsError {
|
|||
}
|
||||
}
|
||||
|
||||
impl Into<libc::c_int> for HookFsError {
|
||||
fn into(self) -> libc::c_int {
|
||||
impl From<HookFsError> for libc::c_int {
|
||||
fn from(err: HookFsError) -> libc::c_int {
|
||||
use HookFsError::*;
|
||||
|
||||
match self {
|
||||
match err {
|
||||
Sys(errno) => errno as i32,
|
||||
InodeNotFound { inode: _ } => libc::EFAULT,
|
||||
FhNotFound { fh: _ } => libc::EFAULT,
|
||||
|
|
|
@ -4,32 +4,7 @@ mod reply;
|
|||
pub mod runtime;
|
||||
mod utils;
|
||||
|
||||
use crate::injector::Injector;
|
||||
use crate::injector::Method;
|
||||
use crate::injector::MultiInjector;
|
||||
|
||||
use utils::*;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use derive_more::{Deref, DerefMut, From};
|
||||
use fuser::*;
|
||||
use slab::Slab;
|
||||
|
||||
use libc::{c_void, lgetxattr, llistxattr, lremovexattr, lsetxattr};
|
||||
|
||||
use nix::dir;
|
||||
use nix::errno::Errno;
|
||||
use nix::fcntl::{open, readlink, renameat, OFlag};
|
||||
use nix::sys::stat;
|
||||
use nix::sys::statfs;
|
||||
use nix::unistd::{
|
||||
fchownat, fsync, linkat, mkdir, symlinkat, truncate, unlink, AccessFlags, FchownatFlags, Gid,
|
||||
LinkatFlags, Uid,
|
||||
};
|
||||
|
||||
use tracing::{debug, error, instrument, trace};
|
||||
|
||||
use std::{collections::{HashMap, LinkedList}};
|
||||
use std::collections::{HashMap, LinkedList};
|
||||
use std::ffi::{CString, OsStr, OsString};
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::os::unix::io::RawFd;
|
||||
|
@ -37,12 +12,28 @@ use std::path::{Path, PathBuf};
|
|||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
pub use async_fs::{AsyncFileSystem, AsyncFileSystemImpl};
|
||||
use async_trait::async_trait;
|
||||
use derive_more::{Deref, DerefMut, From};
|
||||
pub use errors::{HookFsError as Error, Result};
|
||||
use fuser::*;
|
||||
use libc::{c_void, lgetxattr, llistxattr, lremovexattr, lsetxattr};
|
||||
use nix::dir;
|
||||
use nix::errno::Errno;
|
||||
use nix::fcntl::{open, readlink, renameat, OFlag};
|
||||
use nix::sys::{stat, statfs};
|
||||
use nix::unistd::{
|
||||
close, fchownat, fsync, linkat, mkdir, symlinkat, truncate, unlink, AccessFlags, FchownatFlags,
|
||||
Gid, LinkatFlags, Uid,
|
||||
};
|
||||
pub use reply::Reply;
|
||||
use reply::*;
|
||||
use runtime::spawn_blocking;
|
||||
|
||||
use slab::Slab;
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::{debug, error, instrument, trace};
|
||||
use utils::*;
|
||||
|
||||
use crate::injector::{Injector, Method, MultiInjector};
|
||||
|
||||
// use fuse::consts::FOPEN_DIRECT_IO;
|
||||
|
||||
|
@ -51,6 +42,8 @@ macro_rules! inject {
|
|||
if $self.enable_injection.load(Ordering::SeqCst) {
|
||||
$self
|
||||
.injector
|
||||
.read()
|
||||
.await
|
||||
.inject(&Method::$method, $self.rebuild_path($path)?.as_path())
|
||||
.await?;
|
||||
}
|
||||
|
@ -81,19 +74,19 @@ macro_rules! inject_with_fh {
|
|||
}
|
||||
|
||||
macro_rules! inject_write_data {
|
||||
($self:ident, $fh:ident, $data:ident) => {
|
||||
{
|
||||
($self:ident, $fh:ident, $data:ident) => {{
|
||||
let opened_files = $self.opened_files.read().await;
|
||||
if let Ok(file) = opened_files.get($fh as usize) {
|
||||
let path = file.original_path().to_owned();
|
||||
trace!("Write data before inject {:?}", $data);
|
||||
$self
|
||||
.injector
|
||||
.read()
|
||||
.await
|
||||
.inject_write_data($self.rebuild_path(path)?.as_path(), &mut $data)?;
|
||||
trace!("Write data after inject {:?}", $data);
|
||||
}
|
||||
}
|
||||
};
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! inject_with_dir_fh {
|
||||
|
@ -124,6 +117,8 @@ macro_rules! inject_attr {
|
|||
if $self.enable_injection.load(Ordering::SeqCst) {
|
||||
$self
|
||||
.injector
|
||||
.read()
|
||||
.await
|
||||
.inject_attr(&mut $attr, $self.rebuild_path($path)?.as_path());
|
||||
}
|
||||
};
|
||||
|
@ -133,7 +128,7 @@ macro_rules! inject_reply {
|
|||
($self:ident, $method:ident, $path:expr, $reply:ident, $reply_typ:ident) => {
|
||||
if $self.enable_injection.load(Ordering::SeqCst) {
|
||||
trace!("before inject {:?}", $reply);
|
||||
$self.injector.inject_reply(
|
||||
$self.injector.read().await.inject_reply(
|
||||
&Method::$method,
|
||||
$self.rebuild_path($path)?.as_path(),
|
||||
&mut Reply::$reply_typ(&mut $reply),
|
||||
|
@ -154,7 +149,7 @@ pub struct HookFs {
|
|||
|
||||
opened_dirs: RwLock<FhMap<Dir>>,
|
||||
|
||||
injector: MultiInjector,
|
||||
pub injector: RwLock<MultiInjector>,
|
||||
|
||||
// map from inode to real path
|
||||
inode_map: RwLock<InodeMap>,
|
||||
|
@ -305,7 +300,7 @@ impl HookFs {
|
|||
injector: MultiInjector,
|
||||
) -> HookFs {
|
||||
let mut inode_map = InodeMap::from(HashMap::new());
|
||||
inode_map.insert_path(1, original_path.as_ref().to_owned());
|
||||
inode_map.insert_path(1, original_path.as_ref());
|
||||
|
||||
let inode_map = RwLock::new(inode_map);
|
||||
|
||||
|
@ -314,7 +309,7 @@ impl HookFs {
|
|||
original_path: original_path.as_ref().to_owned(),
|
||||
opened_files: RwLock::new(FhMap::from(Slab::new())),
|
||||
opened_dirs: RwLock::new(FhMap::from(Slab::new())),
|
||||
injector,
|
||||
injector: RwLock::new(injector),
|
||||
inode_map,
|
||||
enable_injection: AtomicBool::from(false),
|
||||
}
|
||||
|
@ -326,6 +321,14 @@ impl HookFs {
|
|||
|
||||
pub fn disable_injection(&self) {
|
||||
self.enable_injection.store(false, Ordering::SeqCst);
|
||||
|
||||
// TODO: create a standalone runtime only for interrupt is too ugly.
|
||||
// this RWLock is actually redundant, and the injector is rarely written.
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let injector = self.injector.read().await;
|
||||
injector.interrupt();
|
||||
});
|
||||
}
|
||||
|
||||
pub fn rebuild_path<P: AsRef<Path>>(&self, path: P) -> Result<PathBuf> {
|
||||
|
@ -338,7 +341,7 @@ impl HookFs {
|
|||
|
||||
impl HookFs {
|
||||
async fn get_file_attr(&self, path: &Path) -> Result<FileAttr> {
|
||||
let mut attr = async_stat(&path)
|
||||
let mut attr = async_stat(path)
|
||||
.await
|
||||
.map(convert_libc_stat_to_fuse_stat)??;
|
||||
|
||||
|
@ -406,7 +409,7 @@ impl AsyncFileSystemImpl for HookFs {
|
|||
let inode_map = self.inode_map.read().await;
|
||||
let path = inode_map.get_path(ino)?;
|
||||
trace!("getting attr from path {}", path.display());
|
||||
let stat = self.get_file_attr(&path).await?;
|
||||
let stat = self.get_file_attr(path).await?;
|
||||
|
||||
trace!("return with {:?}", stat);
|
||||
|
||||
|
@ -441,21 +444,21 @@ impl AsyncFileSystemImpl for HookFs {
|
|||
let inode_map = self.inode_map.read().await;
|
||||
let path = inode_map.get_path(ino)?;
|
||||
|
||||
async_lchown(&path, uid, gid).await?;
|
||||
async_lchown(path, uid, gid).await?;
|
||||
|
||||
if let Some(mode) = mode {
|
||||
async_fchmodat(&path, mode).await?;
|
||||
async_fchmodat(path, mode).await?;
|
||||
}
|
||||
|
||||
if let Some(size) = size {
|
||||
async_truncate(&path, size as i64).await?;
|
||||
async_truncate(path, size as i64).await?;
|
||||
}
|
||||
|
||||
let times = [convert_time(atime), convert_time(mtime)];
|
||||
let cpath = CString::new(path.as_os_str().as_bytes())?;
|
||||
async_utimensat(cpath, times).await?;
|
||||
|
||||
let stat = self.get_file_attr(&path).await?;
|
||||
let stat = self.get_file_attr(path).await?;
|
||||
trace!("return with {:?}", stat);
|
||||
let mut reply = Attr::new(stat);
|
||||
inject_reply!(self, GETATTR, path, reply, Attr);
|
||||
|
@ -471,7 +474,7 @@ impl AsyncFileSystemImpl for HookFs {
|
|||
let inode_map = self.inode_map.read().await;
|
||||
let link_path = inode_map.get_path(ino)?;
|
||||
|
||||
let path = async_readlink(&link_path).await?;
|
||||
let path = async_readlink(link_path).await?;
|
||||
|
||||
let path = CString::new(path.as_os_str().as_bytes())?;
|
||||
|
||||
|
@ -732,7 +735,7 @@ impl AsyncFileSystemImpl for HookFs {
|
|||
|
||||
trace!("open with flags: {:?}", filtered_flags);
|
||||
|
||||
let fd = async_open(&path, filtered_flags, stat::Mode::S_IRWXU).await?;
|
||||
let fd = async_open(path, filtered_flags, stat::Mode::S_IRWXU).await?;
|
||||
let fh = self.opened_files.write().await.insert(File::new(fd, path)) as u64;
|
||||
|
||||
trace!("return with fh: {}, flags: {}", fh, 0);
|
||||
|
@ -765,7 +768,7 @@ impl AsyncFileSystemImpl for HookFs {
|
|||
Ok(reply)
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
#[instrument(skip(self, data))]
|
||||
async fn write(
|
||||
&self,
|
||||
_ino: u64,
|
||||
|
@ -815,6 +818,9 @@ impl AsyncFileSystemImpl for HookFs {
|
|||
trace!("release");
|
||||
|
||||
let mut opened_files = self.opened_files.write().await;
|
||||
if let Ok(file) = opened_files.get(fh as usize) {
|
||||
async_close(file.fd).await?;
|
||||
}
|
||||
opened_files.remove(fh as usize);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1330,3 +1336,7 @@ async fn async_open(path: &Path, filtered_flags: OFlag, mode: stat::Mode) -> Res
|
|||
let fd = spawn_blocking(move || open(&path_clone, filtered_flags, mode)).await??;
|
||||
Ok(fd)
|
||||
}
|
||||
|
||||
async fn async_close(fd: RawFd) -> Result<()> {
|
||||
Ok(spawn_blocking(move || close(fd)).await??)
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use fuser::*;
|
||||
use std::fmt::Debug;
|
||||
use std::time::Duration;
|
||||
|
||||
use fuser::*;
|
||||
use tracing::{debug, error, trace};
|
||||
|
||||
use super::errors::Result;
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
const TTL: Duration = Duration::from_secs(0);
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
use once_cell::sync::Lazy;
|
||||
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
use std::future::Future;
|
||||
use std::sync::RwLock;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::task::JoinHandle;
|
||||
use tracing::trace;
|
||||
|
||||
pub static RUNTIME: Lazy<RwLock<Option<Runtime>>> = Lazy::new(|| {
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
use super::filter;
|
||||
use super::Injector;
|
||||
|
||||
use super::injector_config::{AttrOverrideConfig, FileType as ConfigFileType, FilterConfig};
|
||||
use crate::hookfs::Result;
|
||||
use std::path::Path;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use fuser::{FileAttr, FileType};
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use std::path::Path;
|
||||
use super::injector_config::{AttrOverrideConfig, FileType as ConfigFileType, FilterConfig};
|
||||
use super::{filter, Injector};
|
||||
use crate::hookfs::Result;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AttrOverrideInjector {
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
use super::filter;
|
||||
use super::Injector;
|
||||
|
||||
use super::injector_config::FaultsConfig;
|
||||
use crate::hookfs::{Error, Result};
|
||||
use std::path::Path;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use nix::errno::Errno;
|
||||
use rand::Rng;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use std::path::Path;
|
||||
use super::injector_config::FaultsConfig;
|
||||
use super::{filter, Injector};
|
||||
use crate::hookfs::{Error, Result};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FaultInjector {
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::path::Path;
|
||||
|
||||
use super::injector_config::FilterConfig;
|
||||
|
||||
use anyhow::{anyhow, Error, Result};
|
||||
use bitflags::bitflags;
|
||||
use glob::{MatchOptions, Pattern};
|
||||
use rand::Rng;
|
||||
|
||||
use tracing::{info, trace};
|
||||
|
||||
use super::injector_config::FilterConfig;
|
||||
|
||||
bitflags! {
|
||||
pub struct Method: u32 {
|
||||
const LOOKUP = 1;
|
||||
|
@ -110,15 +109,13 @@ impl Filter {
|
|||
.unwrap_or(Method::all());
|
||||
|
||||
let path_filter = conf
|
||||
.path
|
||||
.map(|path| -> Option<Pattern> {
|
||||
.path.and_then(|path| -> Option<Pattern> {
|
||||
if !path.is_empty() {
|
||||
Pattern::new(&path).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.flatten();
|
||||
});
|
||||
Ok(Self {
|
||||
path_filter,
|
||||
methods,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
@ -88,7 +88,7 @@ pub struct Timespec {
|
|||
#[serde(rename_all = "camelCase")]
|
||||
pub enum MistakeType {
|
||||
Zero,
|
||||
Random
|
||||
Random,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
|
@ -97,13 +97,12 @@ pub struct MistakeConfig {
|
|||
pub filling: MistakeType,
|
||||
pub max_length: usize,
|
||||
pub max_occurrences: usize,
|
||||
pub percent: usize
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MistakesConfig {
|
||||
pub mistakes: Vec<MistakeConfig>,
|
||||
pub mistake: MistakeConfig,
|
||||
#[serde(flatten)]
|
||||
pub filter: FilterConfig,
|
||||
}
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use std::path::Path;
|
||||
use std::time::Duration;
|
||||
|
||||
use super::filter;
|
||||
use super::injector_config::LatencyConfig;
|
||||
use super::Injector;
|
||||
use crate::hookfs::Result;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use tokio::time::delay_for;
|
||||
use tokio::select;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use super::injector_config::LatencyConfig;
|
||||
use super::{filter, Injector};
|
||||
use crate::hookfs::Result;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LatencyInjector {
|
||||
latency: Duration,
|
||||
filter: filter::Filter,
|
||||
cancel_token: CancellationToken,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
@ -22,13 +23,27 @@ impl Injector for LatencyInjector {
|
|||
async fn inject(&self, method: &filter::Method, path: &Path) -> Result<()> {
|
||||
trace!("test for filter");
|
||||
if self.filter.filter(method, path) {
|
||||
debug!("inject io delay {:?}", self.latency);
|
||||
delay_for(self.latency).await;
|
||||
let token = self.cancel_token.clone();
|
||||
let latency = self.latency;
|
||||
debug!("inject io delay {:?}", latency);
|
||||
|
||||
select! {
|
||||
_ = delay_for(latency) => {}
|
||||
_ = token.cancelled() => {
|
||||
debug!("cancelled");
|
||||
}
|
||||
}
|
||||
|
||||
debug!("latency finished");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn interrupt(&self) {
|
||||
debug!("interrupt latency");
|
||||
self.cancel_token.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
impl LatencyInjector {
|
||||
|
@ -38,6 +53,7 @@ impl LatencyInjector {
|
|||
Ok(Self {
|
||||
latency: conf.latency,
|
||||
filter: filter::Filter::build(conf.filter)?,
|
||||
cancel_token: CancellationToken::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
use std::cmp::{max, min};
|
||||
use std::path::Path;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use rand::Rng;
|
||||
|
||||
use std::{cmp::{max, min}, path::Path};
|
||||
|
||||
use super::filter;
|
||||
use super::injector_config::MistakeConfig;
|
||||
use super::injector_config::MistakeType;
|
||||
use super::injector_config::MistakesConfig;
|
||||
use super::Injector;
|
||||
use crate::hookfs::Reply;
|
||||
use crate::hookfs::Result;
|
||||
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use super::injector_config::{MistakeConfig, MistakeType, MistakesConfig};
|
||||
use super::{filter, Injector};
|
||||
use crate::hookfs::{Reply, Result};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MistakeInjector {
|
||||
mistakes: Vec<MistakeConfig>,
|
||||
mistake: MistakeConfig,
|
||||
filter: filter::Filter,
|
||||
}
|
||||
|
||||
|
@ -31,17 +27,16 @@ impl Injector for MistakeInjector {
|
|||
debug!("MI:Injecting reply");
|
||||
if let Reply::Data(data) = reply {
|
||||
let data = &mut data.data;
|
||||
self.handle(data);
|
||||
self.handle(data)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn inject_write_data(&self, path: &Path, data: &mut Vec<u8>) -> Result<()> {
|
||||
debug!("MI:Injecting write data???");
|
||||
if self.filter.filter(&super::Method::WRITE, path) {
|
||||
debug!("MI:Injecting write data");
|
||||
self.handle(data);
|
||||
self.handle(data)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -51,38 +46,40 @@ impl MistakeInjector {
|
|||
pub fn build(conf: MistakesConfig) -> anyhow::Result<Self> {
|
||||
trace!("build mistake injector");
|
||||
Ok(Self {
|
||||
mistakes: conf.mistakes,
|
||||
mistake: conf.mistake,
|
||||
filter: filter::Filter::build(conf.filter)?,
|
||||
})
|
||||
}
|
||||
pub fn handle(&self, data: &mut Vec<u8>) {
|
||||
pub fn handle(&self, data: &mut Vec<u8>) -> Result<()> {
|
||||
trace!("sabotage data");
|
||||
let mut rng = rand::thread_rng();
|
||||
let data_length = data.len();
|
||||
for mistake in self.mistakes.iter() {
|
||||
if rng.gen_range(0, 100) >= mistake.percent {
|
||||
continue;
|
||||
}
|
||||
let mistake = &self.mistake;
|
||||
let occurrence = match mistake.max_occurrences {
|
||||
0 => 0,
|
||||
mo => rng.gen_range(1, mo + 1),
|
||||
};
|
||||
for _ in 0..occurrence {
|
||||
let pos = rng.gen_range(0, max(data_length,1));
|
||||
let length = match min(mistake.max_length, data_length-pos) {
|
||||
let pos = rng.gen_range(0, max(data_length, 1));
|
||||
let length = match min(mistake.max_length, data_length - pos) {
|
||||
0 => 0,
|
||||
l => rng.gen_range(1, l + 1),
|
||||
};
|
||||
debug!("Setting index [{},{}) to {:?}",pos,pos+length,mistake.filling);
|
||||
debug!(
|
||||
"Setting index [{},{}) to {:?}",
|
||||
pos,
|
||||
pos + length,
|
||||
mistake.filling
|
||||
);
|
||||
match mistake.filling {
|
||||
MistakeType::Zero => {
|
||||
for i in pos..pos + length {
|
||||
data[i] = 0;
|
||||
for item in data.iter_mut().skip(pos).take(length) {
|
||||
*item = 0;
|
||||
}
|
||||
}
|
||||
MistakeType::Random => rng.fill(&mut data[pos..pos + length]),
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,15 +6,15 @@ mod latency_injector;
|
|||
mod mistake_injector;
|
||||
mod multi_injector;
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use async_trait::async_trait;
|
||||
pub use filter::Method;
|
||||
use fuser::FileAttr;
|
||||
pub use injector_config::InjectorConfig;
|
||||
pub use multi_injector::MultiInjector;
|
||||
|
||||
use crate::hookfs::{Reply, Result};
|
||||
use async_trait::async_trait;
|
||||
use fuser::FileAttr;
|
||||
|
||||
use std::{path::Path};
|
||||
|
||||
#[async_trait]
|
||||
pub trait Injector: Send + Sync + std::fmt::Debug {
|
||||
|
@ -28,13 +28,11 @@ pub trait Injector: Send + Sync + std::fmt::Debug {
|
|||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn inject_write_data(
|
||||
&self,
|
||||
_path: &Path,
|
||||
_data: &mut Vec<u8>,
|
||||
) -> Result<()> {
|
||||
fn inject_write_data(&self, _path: &Path, _data: &mut Vec<u8>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn inject_attr(&self, _attr: &mut FileAttr, _path: &Path) {}
|
||||
|
||||
fn interrupt(&self) {}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
use super::attr_override_injector::AttrOverrideInjector;
|
||||
use super::fault_injector::FaultInjector;
|
||||
use super::filter;
|
||||
use super::injector_config::InjectorConfig;
|
||||
use super::latency_injector::LatencyInjector;
|
||||
use super::mistake_injector::MistakeInjector;
|
||||
use super::Injector;
|
||||
use crate::hookfs::{Reply, Result};
|
||||
use std::path::Path;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use fuser::FileAttr;
|
||||
use tracing::trace;
|
||||
|
||||
use std::path::Path;
|
||||
use super::attr_override_injector::AttrOverrideInjector;
|
||||
use super::fault_injector::FaultInjector;
|
||||
use super::injector_config::InjectorConfig;
|
||||
use super::latency_injector::LatencyInjector;
|
||||
use super::mistake_injector::MistakeInjector;
|
||||
use super::{filter, Injector};
|
||||
use crate::hookfs::{Reply, Result};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MultiInjector {
|
||||
|
@ -69,14 +68,16 @@ impl Injector for MultiInjector {
|
|||
}
|
||||
}
|
||||
|
||||
fn inject_write_data(
|
||||
&self,
|
||||
path: &Path,
|
||||
data: &mut Vec<u8>,
|
||||
) -> Result<()> {
|
||||
fn inject_write_data(&self, path: &Path, data: &mut Vec<u8>) -> Result<()> {
|
||||
for injector in self.injectors.iter() {
|
||||
injector.inject_write_data(path, data)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn interrupt(&self) {
|
||||
for injector in self.injectors.iter() {
|
||||
injector.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
use std::sync::{mpsc, Arc, Mutex};
|
||||
|
||||
use jsonrpc_derive::rpc;
|
||||
use jsonrpc_stdio_server::jsonrpc_core::*;
|
||||
use jsonrpc_stdio_server::ServerBuilder;
|
||||
use tracing::{info, trace};
|
||||
|
||||
use crate::hookfs::HookFs;
|
||||
use crate::injector::{InjectorConfig, MultiInjector};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Comm {
|
||||
Shutdown = 0,
|
||||
}
|
||||
|
||||
pub async fn start_server(config: RpcImpl) {
|
||||
info!("Starting jsonrpc server");
|
||||
let server = new_server(config);
|
||||
let server = server.build();
|
||||
server.await;
|
||||
}
|
||||
|
||||
pub fn new_server(config: RpcImpl) -> ServerBuilder {
|
||||
info!("Creating jsonrpc server");
|
||||
let io = new_handler(config);
|
||||
ServerBuilder::new(io)
|
||||
}
|
||||
|
||||
pub fn new_handler(config: RpcImpl) -> IoHandler {
|
||||
info!("Creating jsonrpc handler");
|
||||
let mut io = IoHandler::new();
|
||||
io.extend_with(config.to_delegate());
|
||||
io
|
||||
}
|
||||
|
||||
#[rpc]
|
||||
pub trait Rpc {
|
||||
#[rpc(name = "get_status")]
|
||||
fn get_status(&self, inst: String) -> Result<String>;
|
||||
#[rpc(name = "update")]
|
||||
fn update(&self, config: Vec<InjectorConfig>) -> Result<String>;
|
||||
}
|
||||
|
||||
pub struct RpcImpl {
|
||||
status: Mutex<anyhow::Result<()>>,
|
||||
tx: Mutex<mpsc::Sender<Comm>>,
|
||||
hookfs: Option<Arc<HookFs>>,
|
||||
}
|
||||
|
||||
impl RpcImpl {
|
||||
pub fn new(
|
||||
status: Mutex<anyhow::Result<()>>,
|
||||
tx: Mutex<mpsc::Sender<Comm>>,
|
||||
hookfs: Option<Arc<HookFs>>,
|
||||
) -> Self {
|
||||
Self { status, tx, hookfs }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RpcImpl {
|
||||
fn drop(&mut self) {
|
||||
trace!("Dropping jrpc handler");
|
||||
}
|
||||
}
|
||||
|
||||
impl Rpc for RpcImpl {
|
||||
fn get_status(&self, _inst: String) -> Result<String> {
|
||||
info!("rpc get_status called");
|
||||
match &*self.status.lock().unwrap() {
|
||||
Ok(_) => Ok("ok".to_string()),
|
||||
Err(e) => {
|
||||
let tx = &self.tx.lock().unwrap();
|
||||
tx.send(Comm::Shutdown)
|
||||
.expect("Send through channel failed");
|
||||
Ok(e.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
fn update(&self, config: Vec<InjectorConfig>) -> Result<String> {
|
||||
info!("rpc update called");
|
||||
if let Err(e) = &*self.status.lock().unwrap() {
|
||||
return Ok(e.to_string());
|
||||
}
|
||||
let injectors = MultiInjector::build(config);
|
||||
if let Err(e) = &injectors {
|
||||
return Ok(e.to_string());
|
||||
}
|
||||
futures::executor::block_on(async {
|
||||
let hookfs = self.hookfs.as_ref().unwrap();
|
||||
let mut current_injectors = hookfs.injector.write().await;
|
||||
*current_injectors = injectors.unwrap();
|
||||
});
|
||||
Ok("ok".to_string())
|
||||
}
|
||||
}
|
11
src/lib.rs
11
src/lib.rs
|
@ -19,6 +19,13 @@
|
|||
#![allow(clippy::or_fun_call)]
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
pub mod injector;
|
||||
|
||||
pub mod fuse_device;
|
||||
pub mod hookfs;
|
||||
pub mod injector;
|
||||
pub mod jsonrpc;
|
||||
pub mod mount;
|
||||
pub mod mount_injector;
|
||||
pub mod ptrace;
|
||||
pub mod replacer;
|
||||
pub mod stop;
|
||||
pub mod utils;
|
||||
|
|
74
src/main.rs
74
src/main.rs
|
@ -24,6 +24,7 @@ extern crate derive_more;
|
|||
mod fuse_device;
|
||||
mod hookfs;
|
||||
mod injector;
|
||||
mod jsonrpc;
|
||||
mod mount;
|
||||
mod mount_injector;
|
||||
mod ptrace;
|
||||
|
@ -31,21 +32,24 @@ mod replacer;
|
|||
mod stop;
|
||||
mod utils;
|
||||
|
||||
use injector::InjectorConfig;
|
||||
use mount_injector::{MountInjectionGuard, MountInjector};
|
||||
use replacer::{Replacer, UnionReplacer};
|
||||
use utils::encode_path;
|
||||
use std::convert::TryFrom;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{mpsc, Mutex};
|
||||
use std::{io, thread};
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use injector::InjectorConfig;
|
||||
use jsonrpc::start_server;
|
||||
use mount_injector::{MountInjectionGuard, MountInjector};
|
||||
use nix::sys::signal::{signal, SigHandler, Signal};
|
||||
use nix::unistd::{pipe, read, write};
|
||||
use replacer::{Replacer, UnionReplacer};
|
||||
use structopt::StructOpt;
|
||||
use tracing::{info, instrument, trace};
|
||||
use tokio::runtime::Runtime;
|
||||
use tracing::{info, instrument};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::{convert::TryFrom, os::unix::io::RawFd};
|
||||
use utils::encode_path;
|
||||
|
||||
#[derive(StructOpt, Debug, Clone)]
|
||||
#[structopt(name = "basic")]
|
||||
|
@ -61,9 +65,7 @@ struct Options {
|
|||
}
|
||||
|
||||
#[instrument(skip(option))]
|
||||
fn inject(option: Options) -> Result<MountInjectionGuard> {
|
||||
trace!("parse injector configs");
|
||||
let injector_config: Vec<InjectorConfig> = serde_json::from_reader(std::io::stdin())?;
|
||||
fn inject(option: Options, injector_config: Vec<InjectorConfig>) -> Result<MountInjectionGuard> {
|
||||
info!("inject with config {:?}", injector_config);
|
||||
|
||||
let path = option.path.clone();
|
||||
|
@ -72,7 +74,7 @@ fn inject(option: Options) -> Result<MountInjectionGuard> {
|
|||
let path = path.canonicalize()?;
|
||||
|
||||
let replacer = if !option.mount_only {
|
||||
let mut replacer = UnionReplacer::new();
|
||||
let mut replacer = UnionReplacer::default();
|
||||
replacer.prepare(&path, &path)?;
|
||||
|
||||
Some(replacer)
|
||||
|
@ -114,7 +116,7 @@ fn resume(option: Options, mount_guard: MountInjectionGuard) -> Result<()> {
|
|||
let (_, new_path) = encode_path(&path)?;
|
||||
|
||||
let replacer = if !option.mount_only {
|
||||
let mut replacer = UnionReplacer::new();
|
||||
let mut replacer = UnionReplacer::default();
|
||||
replacer.prepare(&path, &new_path)?;
|
||||
info!("running replacer");
|
||||
let result = replacer.run();
|
||||
|
@ -145,6 +147,12 @@ extern "C" fn signal_handler(_: libc::c_int) {
|
|||
}
|
||||
}
|
||||
|
||||
fn wait_for_signal(chan: RawFd) -> Result<()> {
|
||||
let mut buf = vec![0u8; 6];
|
||||
read(chan, buf.as_mut_slice())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let (reader, writer) = pipe()?;
|
||||
unsafe {
|
||||
|
@ -155,21 +163,43 @@ fn main() -> Result<()> {
|
|||
unsafe { signal(Signal::SIGTERM, SigHandler::Handler(signal_handler))? };
|
||||
|
||||
let option = Options::from_args();
|
||||
info!("start with option: {:?}", option);
|
||||
let env_filter = EnvFilter::try_from_default_env()
|
||||
.or_else(|_| EnvFilter::try_from(&option.verbose))
|
||||
.or_else(|_| EnvFilter::try_new("trace"))
|
||||
.unwrap();
|
||||
tracing_subscriber::fmt().with_env_filter(env_filter).init();
|
||||
tracing_subscriber::fmt()
|
||||
.with_writer(io::stderr)
|
||||
.with_env_filter(env_filter)
|
||||
.init();
|
||||
info!("start with option: {:?}", option);
|
||||
let mount_injector = inject(option.clone(), vec![]);
|
||||
|
||||
let mount_injector = inject(option.clone())?;
|
||||
let status = match &mount_injector {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(anyhow::Error::msg(e.to_string())),
|
||||
};
|
||||
|
||||
let (tx, _) = mpsc::channel();
|
||||
{
|
||||
let hookfs = match &mount_injector {
|
||||
Ok(e) => Some(e.hookfs.clone()),
|
||||
Err(_) => None,
|
||||
};
|
||||
thread::spawn(|| {
|
||||
Runtime::new()
|
||||
.expect("Failed to create Tokio runtime")
|
||||
.block_on(start_server(jsonrpc::RpcImpl::new(
|
||||
Mutex::new(status),
|
||||
Mutex::new(tx),
|
||||
hookfs,
|
||||
)));
|
||||
});
|
||||
}
|
||||
info!("waiting for signal to exit");
|
||||
let mut buf = vec![0u8; 6];
|
||||
read(reader, buf.as_mut_slice())?;
|
||||
wait_for_signal(reader)?;
|
||||
info!("start to recover and exit");
|
||||
|
||||
resume(option, mount_injector)?;
|
||||
|
||||
if let Ok(v) = mount_injector {
|
||||
resume(option, v)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -2,9 +2,7 @@ use std::fs::create_dir_all;
|
|||
use std::path::Path;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
use nix::mount::{mount, MsFlags};
|
||||
|
||||
use procfs::process::{self, Process};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -1,21 +1,16 @@
|
|||
use crate::hookfs;
|
||||
use crate::injector::MultiInjector;
|
||||
use crate::mount;
|
||||
use crate::stop;
|
||||
use crate::InjectorConfig;
|
||||
|
||||
use std::ffi::OsStr;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use std::thread::JoinHandle;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
|
||||
use nix::mount::umount;
|
||||
|
||||
use retry::delay::Fixed;
|
||||
use retry::{retry, OperationResult};
|
||||
use tracing::info;
|
||||
|
||||
use retry::{delay::Fixed, retry, OperationResult};
|
||||
use crate::injector::{InjectorConfig, MultiInjector};
|
||||
use crate::{hookfs, mount, stop};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MountInjector {
|
||||
|
@ -27,7 +22,7 @@ pub struct MountInjector {
|
|||
pub struct MountInjectionGuard {
|
||||
original_path: PathBuf,
|
||||
new_path: PathBuf,
|
||||
hookfs: Arc<hookfs::HookFs>,
|
||||
pub hookfs: Arc<hookfs::HookFs>,
|
||||
handler: Option<JoinHandle<Result<()>>>,
|
||||
}
|
||||
|
||||
|
@ -135,7 +130,7 @@ impl MountInjector {
|
|||
|
||||
std::fs::create_dir_all(new_path.as_path())?;
|
||||
|
||||
let args = ["allow_other", "fsname=toda", "default_permissions"];
|
||||
let args = ["allow_other", "fsname=toda", "default_permissions", "nonempty"];
|
||||
let flags: Vec<_> = args
|
||||
.iter()
|
||||
.flat_map(|item| vec![OsStr::new("-o"), OsStr::new(item)])
|
||||
|
|
|
@ -1,26 +1,25 @@
|
|||
use Error::Internal;
|
||||
use anyhow::{anyhow, Result};
|
||||
use nix::sys::ptrace;
|
||||
use nix::sys::signal::Signal;
|
||||
use nix::sys::uio::{process_vm_writev, IoVec, RemoteIoVec};
|
||||
use nix::sys::wait;
|
||||
use nix::unistd::Pid;
|
||||
use nix::{
|
||||
errno::Errno,
|
||||
sys::mman::{MapFlags, ProtFlags},
|
||||
Error::Sys,
|
||||
};
|
||||
|
||||
use procfs::{ProcError, process::Task};
|
||||
use retry::{Error::{self, Operation}, OperationResult, delay::Fixed};
|
||||
use tracing::{error, info, instrument, trace, warn};
|
||||
|
||||
use std::{cell::RefCell, collections::HashSet};
|
||||
use std::collections::HashMap;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ffi::CString;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use nix::errno::Errno;
|
||||
use nix::sys::mman::{MapFlags, ProtFlags};
|
||||
use nix::sys::signal::Signal;
|
||||
use nix::sys::uio::{process_vm_writev, IoVec, RemoteIoVec};
|
||||
use nix::sys::{ptrace, wait};
|
||||
use nix::unistd::Pid;
|
||||
use nix::Error::Sys;
|
||||
use procfs::process::Task;
|
||||
use procfs::ProcError;
|
||||
use retry::delay::Fixed;
|
||||
use retry::Error::{self, Operation};
|
||||
use retry::OperationResult;
|
||||
use tracing::{error, info, instrument, trace, warn};
|
||||
use Error::Internal;
|
||||
|
||||
// There should be only one PtraceManager in one thread. But as we don't implement TLS
|
||||
// , we cannot use thread-local variables safely.
|
||||
#[derive(Debug, Default)]
|
||||
|
@ -56,8 +55,8 @@ fn attach_task(task: &Task) -> Result<()> {
|
|||
}
|
||||
Err(err) => {
|
||||
warn!("attach error: {:?}", err);
|
||||
return Err(err.into())
|
||||
},
|
||||
return Err(err.into());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
info!("attach task: {} successfully", task.tid);
|
||||
|
@ -91,10 +90,9 @@ impl PtraceManager {
|
|||
while iterations > 0 {
|
||||
let mut new_threads_found = false;
|
||||
let process = procfs::process::Process::new(raw_pid)?;
|
||||
for task in process.tasks()? {
|
||||
if let Ok(task) = task {
|
||||
for task in process.tasks()?.flatten() {
|
||||
if traced_tasks.contains(&task.tid) {
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Ok(()) = attach_task(&task) {
|
||||
|
@ -103,7 +101,6 @@ impl PtraceManager {
|
|||
traced_tasks.insert(task.tid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !new_threads_found {
|
||||
iterations -= 1;
|
||||
|
@ -129,8 +126,9 @@ impl PtraceManager {
|
|||
counter_ref.remove(&pid);
|
||||
|
||||
info!("detach process: {}", pid);
|
||||
if let Err(err) = retry::retry::<_, _, _, anyhow::Error, _>(Fixed::from_millis(500).take(20), || {
|
||||
match procfs::process::Process::new(pid) {
|
||||
if let Err(err) = retry::retry::<_, _, _, anyhow::Error, _>(
|
||||
Fixed::from_millis(500).take(20),
|
||||
|| match procfs::process::Process::new(pid) {
|
||||
Err(ProcError::NotFound(_)) => {
|
||||
info!("process {} not found", pid);
|
||||
OperationResult::Ok(())
|
||||
|
@ -139,14 +137,10 @@ impl PtraceManager {
|
|||
warn!("fail to detach task: {}, retry", pid);
|
||||
OperationResult::Retry(err.into())
|
||||
}
|
||||
Ok(process) => {
|
||||
match process.tasks() {
|
||||
Err(err) => {
|
||||
OperationResult::Retry(err.into())
|
||||
}
|
||||
Ok(process) => match process.tasks() {
|
||||
Err(err) => OperationResult::Retry(err.into()),
|
||||
Ok(tasks) => {
|
||||
for task in tasks {
|
||||
if let Ok(task) = task {
|
||||
for task in tasks.flatten() {
|
||||
match ptrace::detach(Pid::from_raw(task.tid), None) {
|
||||
Ok(()) => {
|
||||
info!("successfully detached task: {}", task.tid);
|
||||
|
@ -161,23 +155,20 @@ impl PtraceManager {
|
|||
}
|
||||
trace!("detach task: {} successfully", task.tid);
|
||||
}
|
||||
}
|
||||
info!("detach process: {} successfully", pid);
|
||||
OperationResult::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}) {
|
||||
},
|
||||
},
|
||||
) {
|
||||
warn!("fail to detach: {:?}", err);
|
||||
match err {
|
||||
Operation {error: e, total_delay:_, tries:_, } => {
|
||||
return Err(e)
|
||||
},
|
||||
Internal(err) => {
|
||||
error!("internal error: {:?}", err)
|
||||
}
|
||||
Operation {
|
||||
error: e,
|
||||
total_delay: _,
|
||||
tries: _,
|
||||
} => return Err(e),
|
||||
Internal(err) => error!("internal error: {:?}", err),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
use super::ptrace;
|
||||
use super::utils::all_processes;
|
||||
use super::Replacer;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use tracing::{error, info, trace};
|
||||
|
||||
use super::utils::all_processes;
|
||||
use super::{ptrace, Replacer};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CwdReplacer {
|
||||
processes: Vec<ptrace::TracedProcess>,
|
||||
new_path: PathBuf,
|
||||
processes: Vec<(ptrace::TracedProcess, PathBuf)>,
|
||||
}
|
||||
|
||||
impl CwdReplacer {
|
||||
|
@ -36,8 +33,13 @@ impl CwdReplacer {
|
|||
}
|
||||
})
|
||||
.filter(|(_, path)| path.starts_with(detect_path.as_ref()))
|
||||
.filter_map(|(pid, _)| match ptrace::trace(pid) {
|
||||
Ok(process) => Some(process),
|
||||
.filter_map(|(pid, path)| match ptrace::trace(pid) {
|
||||
Ok(process) => {
|
||||
let mut new_path = new_path.as_ref().to_path_buf();
|
||||
|
||||
new_path.push(path.strip_prefix(detect_path.as_ref()).unwrap());
|
||||
Some((process, new_path))
|
||||
}
|
||||
Err(err) => {
|
||||
error!("fail to ptrace process: pid({}) with error: {:?}", pid, err);
|
||||
None
|
||||
|
@ -45,18 +47,16 @@ impl CwdReplacer {
|
|||
})
|
||||
.collect();
|
||||
|
||||
Ok(CwdReplacer {
|
||||
processes,
|
||||
new_path: new_path.as_ref().to_owned(),
|
||||
})
|
||||
Ok(CwdReplacer { processes })
|
||||
}
|
||||
}
|
||||
|
||||
impl Replacer for CwdReplacer {
|
||||
fn run(&mut self) -> Result<()> {
|
||||
info!("running cwd replacer");
|
||||
for process in self.processes.iter() {
|
||||
process.chdir(&self.new_path)?;
|
||||
for (process, new_path) in self.processes.iter() {
|
||||
trace!("replacing cwd: {} to {:?}", process.pid, new_path);
|
||||
process.chdir(new_path)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
use super::ptrace;
|
||||
use super::utils::all_processes;
|
||||
use super::Replacer;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use std::io::{Cursor, Read, Write};
|
||||
use std::iter::FromIterator;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
|
||||
use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi};
|
||||
|
||||
use itertools::Itertools;
|
||||
use procfs::process::FDTarget;
|
||||
use tracing::{error, info, trace};
|
||||
|
||||
use procfs::process::FDTarget;
|
||||
|
||||
use itertools::Itertools;
|
||||
use super::utils::all_processes;
|
||||
use super::{ptrace, Replacer};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(packed)]
|
||||
|
|
|
@ -1,24 +1,18 @@
|
|||
use super::ptrace;
|
||||
use super::utils::all_processes;
|
||||
use super::Replacer;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use std::io::{Cursor, Read, Write};
|
||||
use std::iter::FromIterator;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi};
|
||||
use itertools::Itertools;
|
||||
use nix::sys::mman::{MapFlags, ProtFlags};
|
||||
use procfs::process::MMapPath;
|
||||
use tracing::{error, info, trace};
|
||||
|
||||
use procfs::process::MMapPath;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
|
||||
use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi};
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use nix::sys::mman::{MapFlags, ProtFlags};
|
||||
use super::utils::all_processes;
|
||||
use super::{ptrace, Replacer};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct ReplaceCase {
|
||||
|
@ -194,6 +188,7 @@ impl ProcessAccessor {
|
|||
; mov rdi, QWORD [r14+r15] // addr
|
||||
; mov rsi, QWORD [r14+r15+8] // length
|
||||
; mov rdx, 0x0
|
||||
; push rdi
|
||||
; syscall
|
||||
// open
|
||||
; mov rax, 0x2
|
||||
|
@ -206,6 +201,7 @@ impl ProcessAccessor {
|
|||
; mov rsi, libc::O_RDWR
|
||||
; mov rdx, 0x0
|
||||
; syscall
|
||||
; pop rdi // addr
|
||||
; push rax
|
||||
; mov r8, rax // fd
|
||||
// mmap
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::ptrace;
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::ptrace;
|
||||
|
||||
mod cwd_replacer;
|
||||
mod fd_replacer;
|
||||
mod mmap_replacer;
|
||||
|
@ -15,17 +15,12 @@ pub trait Replacer {
|
|||
fn run(&mut self) -> Result<()>;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct UnionReplacer<'a> {
|
||||
replacers: Vec<Box<dyn Replacer + 'a>>,
|
||||
}
|
||||
|
||||
impl<'a> UnionReplacer<'a> {
|
||||
pub fn new() -> UnionReplacer<'a> {
|
||||
UnionReplacer {
|
||||
replacers: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepare<P1: AsRef<Path>, P2: AsRef<Path>>(
|
||||
&mut self,
|
||||
detect_path: P1,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use anyhow::Result;
|
||||
|
||||
use procfs::process::{self, Process};
|
||||
|
||||
pub fn all_processes() -> Result<impl Iterator<Item = Process>> {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use std::sync::Arc;
|
||||
use std::sync::{Condvar, Mutex};
|
||||
use std::sync::{Arc, Condvar, Mutex};
|
||||
|
||||
struct Stop {
|
||||
inner: Mutex<bool>,
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
use std::sync::mpsc::channel;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use toda::jsonrpc::{self, new_handler, Comm};
|
||||
#[test]
|
||||
fn test_status_good() {
|
||||
let (tx, _rx) = channel();
|
||||
let io = new_handler(jsonrpc::RpcImpl::new(
|
||||
Mutex::new(Ok(())),
|
||||
Mutex::new(tx),
|
||||
None,
|
||||
));
|
||||
let request = r#"{"jsonrpc": "2.0","method":"get_status","params":[""],"id":1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":"ok","id":1}"#;
|
||||
assert_eq!(io.handle_request_sync(request), Some(response.to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_status_bad() {
|
||||
let (tx, rx) = channel();
|
||||
let io = new_handler(jsonrpc::RpcImpl::new(
|
||||
Mutex::new(Err(anyhow!("Not good"))),
|
||||
Mutex::new(tx),
|
||||
None,
|
||||
));
|
||||
let request = r#"{"jsonrpc": "2.0","method":"get_status","params":[""],"id":1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":"Not good","id":1}"#;
|
||||
assert_eq!(io.handle_request_sync(request), Some(response.to_string()));
|
||||
assert_eq!(rx.recv().unwrap(), Comm::Shutdown);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_should_not_update_config_if_status_is_failed() {
|
||||
let (tx, _rx) = channel();
|
||||
let request = r#"{"jsonrpc": "2.0","method":"update","params":[[]],"id":1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":"Not good","id":1}"#;
|
||||
let io = new_handler(jsonrpc::RpcImpl::new(
|
||||
Mutex::new(Err(anyhow!("Not good"))),
|
||||
Mutex::new(tx),
|
||||
None,
|
||||
));
|
||||
assert_eq!(io.handle_request_sync(request), Some(response.to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_should_fail_if_config_is_bad() {
|
||||
let (tx, _rx) = channel();
|
||||
let request = r#"{"jsonrpc": "2.0","method":"update","params":[["blah"]],"id":1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid params: invalid type: string \"blah\", expected internally tagged enum."},"id":1}"#;
|
||||
let io = new_handler(jsonrpc::RpcImpl::new(
|
||||
Mutex::new(Ok(())),
|
||||
Mutex::new(tx),
|
||||
None,
|
||||
));
|
||||
assert_eq!(io.handle_request_sync(request), Some(response.to_string()));
|
||||
}
|
|
@ -11,20 +11,17 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use toda::hookfs;
|
||||
use toda::injector::MultiInjector;
|
||||
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::{read_link, read_to_string, write, File, OpenOptions};
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::fs::symlink;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Once;
|
||||
use std::sync::{Arc, Once};
|
||||
|
||||
use nix::fcntl;
|
||||
use nix::sys::stat;
|
||||
use nix::unistd;
|
||||
use nix::{fcntl, unistd};
|
||||
use toda::hookfs;
|
||||
use toda::injector::MultiInjector;
|
||||
|
||||
// These tests are port from go-fuse test
|
||||
|
||||
|
|
Loading…
Reference in New Issue