diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..bb75eb4 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,17 @@ + + +**What this PR does / why we need it**: + +**Special notes for your reviewer**: + +**If applicable**: +- [ ] this PR has an associated PR with documentation in [akri-docs](https://github.com/project-akri/akri-docs) +- [ ] this PR contains unit tests +- [ ] added code adheres to standard Rust formatting (`cargo fmt`) +- [ ] code builds properly (`cargo build`) +- [ ] code is free of common mistakes (`cargo clippy`) +- [ ] all tests succeed (`cargo test`) +- [ ] inline documentation builds (`cargo doc`) +- [ ] all commits pass the [DCO bot check](https://probot.github.io/apps/dco/) by being signed off -- see the failing DCO check for instructions on how to retroactively sign commits \ No newline at end of file diff --git a/.github/workflows/build-container.yml b/.github/workflows/build-container.yml new file mode 100644 index 0000000..f84139a --- /dev/null +++ b/.github/workflows/build-container.yml @@ -0,0 +1,64 @@ +name: Build and Push Production Udev Discovery Handler Container + +on: + push: + branches: [ main ] + paths: + - .github/workflows/build-rust-code.yml + - build/Dockerfile.rust + - '**.rs' + - '**/Cargo.toml' + - '**/Cargo.lock' + - version.txt + release: + types: + - published + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 50 + env: + AKRI_COMPONENT: "udev-discovery-handler" + + steps: + - name: Checkout the head commit of the branch + uses: actions/checkout@v3 + with: + persist-credentials: false + + - name: Get discovery handler version + id: version-string + run: | + echo "version=$(cat version.txt)" >> $GITHUB_OUTPUT + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Docker meta + uses: docker/metadata-action@v5 + id: meta + with: + images: ghcr.io/project-akri/akri/${{ env.AKRI_COMPONENT }} + labels: | + org.opencontainers.image.title=akri-${{env.AKRI_COMPONENT}} + tags: | + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=${{steps.version-string.outputs.version}},enable=${{github.event_name != 'release'}} + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + build-args: | + AKRI_COMPONENT=${{env.AKRI_COMPONENT}} + EXTRA_CARGO_ARGS=--release + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + file: build/Dockerfile.rust + platforms: linux/amd64,linux/arm64,linux/arm/v7 diff --git a/.github/workflows/check-rust.yml b/.github/workflows/check-rust.yml new file mode 100644 index 0000000..a71b133 --- /dev/null +++ b/.github/workflows/check-rust.yml @@ -0,0 +1,55 @@ +name: Check Rust + +on: + push: + branches: [ main ] + paths: + - .github/workflows/check-rust.yml + - '**.rs' + - '**/Cargo.toml' + - '**/Cargo.lock' + pull_request: + branches: [ main ] + paths: + - .github/workflows/check-rust.yml + - '**.rs' + - '**/Cargo.toml' + - '**/Cargo.lock' + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Checkout the head commit of the branch + uses: actions/checkout@v3 + with: + persist-credentials: false + + - name: Rust install + uses: dtolnay/rust-toolchain@master + with: + toolchain: 1.68.1 + components: clippy, rustfmt + - name: Install Linux requirements + run: | + apt_dependencies="git curl libssl-dev pkg-config libudev-dev" + echo "Run apt update and apt install the following dependencies: $apt_dependencies" + sudo apt update + sudo apt install -y $apt_dependencies + - name: Check rust format + run: cargo fmt --all -- --check + - name: Check clippy + run: cargo clippy --all + - name: Check clippy for tests + run: cargo clippy --all-targets --all-features -- -D warnings -A clippy::derive_partial_eq_without_eq + - name: Run check + run: cargo check + - name: Run tests + run: cargo test --workspace + - name: Run doc + run: export RUSTDOCFLAGS="-Dwarnings" && cargo doc --no-deps diff --git a/.github/workflows/run-tarpaulin.yml b/.github/workflows/run-tarpaulin.yml new file mode 100644 index 0000000..8dd2ffd --- /dev/null +++ b/.github/workflows/run-tarpaulin.yml @@ -0,0 +1,66 @@ +name: Tarpaulin Code Coverage + +on: + push: + branches: [ main ] + paths: + - .github/workflows/run-tarpaulin.yml + - '**.rs' + - '**/Cargo.toml' + pull_request: + branches: [ main ] + paths: + - .github/workflows/run-tarpaulin.yml + - '**.rs' + - '**/Cargo.toml' + +env: + CARGO_TERM_COLOR: always + CARGO_VERSION: 1.68.1 + +jobs: + build: + runs-on: ubuntu-latest + # There is a second, hidden timeout in this workflow. When the tarpaulin container is created, + # it is created with a CMD that sleeps for 600 minutes. A more reasonable value could be selected, + # but it seems easier to make it SOOOO big that timeout-minutes is likely to never be impacted by + # it. + # + # But, if this workflow is mysteriously timing out after 600 minutes, make changes to the docker + # create command in the Create tarpaulin instance step. + timeout-minutes: 30 + + steps: + - name: Checkout the head commit of the branch + uses: actions/checkout@v3 + with: + persist-credentials: false + + - name: Create tarpaulin instance + run: docker create --network host --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.25.1 bash -c "echo 'sleep 600m; echo bye' > /tmp/keep_alive.sh; chmod 777 /tmp/keep_alive.sh; /tmp/keep_alive.sh" > container_id.txt + - name: Start tarpaulin instance + run: docker start $(cat container_id.txt) + - name: Install linux requirement in tarpaulin instance + run: docker exec $(cat container_id.txt) sh -c "echo Run apt update and apt install the following dependencies - git curl libssl-dev pkg-config libudev-dev ; apt update ; apt install -y git curl libssl-dev pkg-config libudev-dev" + - name: Install desired rust version + run: docker exec $(cat container_id.txt) sh -c "rustup install $CARGO_VERSION" + - name: Tell cargo to use desired rust version + run: docker exec $(cat container_id.txt) sh -c "rustup override set $CARGO_VERSION" + - name: Install rust requirements in tarpaulin instance + run: docker exec $(cat container_id.txt) sh -c "rustup component add rustfmt" + - name: Run tarpaulin + run: docker exec $(cat container_id.txt) sh -c "RUST_LOG=trace cargo tarpaulin -v --all-features --out Xml" + + - name: Upload report to codecov for push + if: (!(startsWith(github.event_name, 'pull_request'))) + uses: codecov/codecov-action@v3 + with: + token: ${{secrets.CODECOV_TOKEN}} + fail_ci_if_error: true + verbose: true + + - name: Archive code coverage results + uses: actions/upload-artifact@v3 + with: + name: code-coverage-report + path: cobertura.xml diff --git a/.github/workflows/run-test-cases.yml b/.github/workflows/run-test-cases.yml new file mode 100644 index 0000000..48271bf --- /dev/null +++ b/.github/workflows/run-test-cases.yml @@ -0,0 +1,239 @@ +name: Test K3s, Kubernetes, and MicroK8s + +on: + pull_request: + branches: [main] + paths: + - e2e/** + - .github/workflows/run-test-cases.yml + - build/Dockerfile.rust + - version.txt + - Makefile + push: + branches: [main] + paths: + - e2e/** + - .github/workflows/run-test-cases.yml + - build/Dockerfile.rust + - version.txt + - Makefile + release: + types: + - published + +jobs: + build-containers: + runs-on: ubuntu-latest + timeout-minutes: 60 + + steps: + - name: Checkout the head commit of the branch + uses: actions/checkout@v3 + with: + persist-credentials: false + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build local containers for PR tests + if: startsWith(github.event_name, 'pull_request') + env: + PREFIX: ghcr.io/project-akri/akri + LABEL_PREFIX: pr + run: | + make LOAD=1 + docker save ${PREFIX}/udev-discovery:${LABEL_PREFIX} > udev-discovery.tar + + - name: Upload UDEV discovery container as artifact + if: startsWith(github.event_name, 'pull_request') + uses: actions/upload-artifact@v3 + with: + name: udev-discovery.tar + path: udev-discovery.tar + + test-cases: + needs: build-containers + runs-on: ubuntu-latest + timeout-minutes: 95 + + strategy: + fail-fast: false + matrix: + kube: + - runtime: microk8s + version: 1.25/stable + - runtime: microk8s + version: 1.26/stable + - runtime: microk8s + version: 1.27/stable + - runtime: microk8s + version: 1.28/stable + - runtime: k3s + version: v1.25.13+k3s1 + - runtime: k3s + version: v1.26.8+k3s1 + - runtime: k3s + version: v1.27.5+k3s1 + - runtime: k3s + version: v1.28.1+k3s1 + - runtime: k8s + version: 1.25.13 + - runtime: k8s + version: 1.26.8 + - runtime: k8s + version: 1.27.5 + - runtime: k8s + version: 1.28.1 + + steps: + - name: Checkout the head commit of the branch + uses: actions/checkout@v3 + with: + persist-credentials: false + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + - name: Install Poetry and dependencies + working-directory: ./e2e + run: | + POETRY_HOME=/opt/poetry + python3 -m venv $POETRY_HOME + $POETRY_HOME/bin/pip install poetry==1.5.1 + $POETRY_HOME/bin/poetry --version + $POETRY_HOME/bin/poetry install --no-root + + - name: Download container artifacts + if: startsWith(github.event_name, 'pull_request') + uses: actions/download-artifact@v3 + with: + path: /tmp/images + + - if: startsWith(matrix.kube.runtime, 'k3s') + name: Install K3s + env: + INSTALL_K3S_VERSION: ${{ matrix.kube.version }} + run: | + sudo curl -sfL https://get.k3s.io -o install.sh + sudo chmod +x install.sh + ./install.sh server --kubelet-arg=eviction-hard="imagefs.available<1%,nodefs.available<1%" --kubelet-arg=eviction-minimum-reclaim="imagefs.available=1%,nodefs.available=1%" + mkdir -p $HOME/.kube + sudo cp -i /etc/rancher/k3s/k3s.yaml $HOME/.kube/config + sudo chown $(id -u):$(id -g) $HOME/.kube/config + until kubectl get node ${HOSTNAME,,} -o jsonpath='{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status}' | grep 'Ready=True'; do echo "waiting for k3s to become ready"; sleep 10; done + + - if: (startsWith(github.event_name, 'pull_request')) && (startsWith(matrix.kube.runtime, 'K3s')) + name: Import local agent and controller to K3s + working-directory: /tmp/images + run: | + sudo find -name "*.tar" -type f -exec k3s ctr image import {} \; + + - if: startsWith(matrix.kube.runtime, 'k8s') + name: Install Kubernetes + run: | + SHORTVERSION=$(cut -d '.' -f 1,2 <<< "${{ matrix.kube.version }}") + sudo apt-get update -y + sudo apt-get install -y apt-transport-https ca-certificates curl + curl -fsSL https://pkgs.k8s.io/core:/stable:/v${SHORTVERSION}/deb/Release.key | sudo gpg --yes --batch --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg + echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v${SHORTVERSION}/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --yes --batch --dearmor -o /usr/share/keyrings/docker.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list + sudo apt-get update + sudo apt-get install -o Dpkg::Options::="--force-overwrite" -y --allow-downgrades kubelet=${{ matrix.kube.version }}-* kubeadm=${{ matrix.kube.version }}-* kubectl=${{ matrix.kube.version }}-* containerd.io + kubectl version && echo "kubectl return code: $?" || echo "kubectl return code: $?" + kubeadm version && echo "kubeadm return code: $?" || echo "kubeadm return code: $?" + kubelet --version && echo "kubelet return code: $?" || echo "kubelet return code: $?" + cat < $HOME/.kube/config + sudo chown $(id -u):$(id -g) $HOME/.kube/config + sudo microk8s.enable rbac dns + sudo sed -i 's/memory.available<100Mi,nodefs.available<1Gi,imagefs.available<1Gi/memory.available<25Mi,nodefs.available<50Mi,imagefs.available<50Mi/' /var/snap/microk8s/current/args/kubelet + sudo systemctl restart snap.microk8s.daemon-kubelite + until sudo microk8s.status --wait-ready; do sleep 5s; echo "Try again"; done + + - name: Add Akri Helm Chart + run: helm repo add akri-helm-charts https://project-akri.github.io/akri/ + + # For push and release, we need to wait for the Helm chart and + # associated containers to build. + - if: github.event_name == 'push' || github.event_name == 'release' + name: sleep before running script for 80 minutes + run: sleep 4800 + + - name: Execute test script + working-directory: ./e2e + run: | + case "${{ github.event_name }}" in "push");; "release") extra_param="--release";; *) extra_param="--use-local";; esac + /opt/poetry/bin/poetry run pytest -v --distribution ${{ matrix.kube.runtime}} --test-version $(cat ../version.txt) $extra_param + + - name: Sanitize logs artifact name + id: sanitize-artifact-name + if: always() + run: echo "name=${{ matrix.kube.runtime }}-${{ matrix.kube.version }}-logs" | tr "/:" "_" >> $GITHUB_OUTPUT + + - name: Upload logs as artifact + if: always() + uses: actions/upload-artifact@v3 + with: + name: ${{ steps.sanitize-artifact-name.outputs.name }} + path: /tmp/logs/ \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f4ceea7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +**/target/ diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..c71d830 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,2639 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "akri-discovery-utils" +version = "0.12.9" +source = "git+https://github.com/project-akri/akri/?tag=v0.12.9#911cdc1e9f5aeed76f7e09339db35de4d871478a" +dependencies = [ + "akri-shared", + "anyhow", + "async-stream", + "futures", + "log", + "prost", + "serde", + "serde_derive", + "serde_yaml", + "tokio", + "tokio-stream", + "tonic", + "tonic-build", + "tower", +] + +[[package]] +name = "akri-shared" +version = "0.12.9" +source = "git+https://github.com/project-akri/akri/?tag=v0.12.9#911cdc1e9f5aeed76f7e09339db35de4d871478a" +dependencies = [ + "anyhow", + "async-trait", + "either", + "k8s-openapi", + "kube", + "log", + "mockall", + "prometheus", + "rand", + "schemars", + "serde", + "serde_derive", + "serde_json", + "serde_yaml", + "tokio", + "tonic", + "tower", + "warp", +] + +[[package]] +name = "akri-udev" +version = "0.12.16" +dependencies = [ + "akri-discovery-utils", + "anyhow", + "async-trait", + "env_logger", + "log", + "mockall", + "pest", + "pest_derive", + "regex", + "serde", + "serde_derive", + "serde_json", + "tokio", + "tokio-stream", + "tonic", + "udev", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "async-trait" +version = "0.1.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "data-encoding" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" + +[[package]] +name = "difference" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "downcast" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d" + +[[package]] +name = "dyn-clone" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "env_logger" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fixedbitset" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float-cmp" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fragile" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7464c5c4a3f014d9b2ec4073650e5c06596f385060af740fc45ad5a19f959e8" +dependencies = [ + "fragile 2.0.0", +] + +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + +[[package]] +name = "futures" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-executor" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" + +[[package]] +name = "futures-macro" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "futures-sink" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" + +[[package]] +name = "futures-task" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-util" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + +[[package]] +name = "h2" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util 0.7.10", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" + +[[package]] +name = "headers" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +dependencies = [ + "base64 0.21.5", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.4.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-openssl" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ee5d7a8f718585d1c3c61dfde28ef5b0bb14734b4db13f5ada856cdc6c612b" +dependencies = [ + "http", + "hyper", + "linked_hash_set", + "once_cell", + "openssl", + "openssl-sys", + "parking_lot 0.12.1", + "tokio", + "tokio-openssl", + "tower-layer", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.2", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "js-sys" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonpath_lib" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaa63191d68230cccb81c5aa23abd53ed64d83337cacbb25a7b8c7979523774f" +dependencies = [ + "log", + "serde", + "serde_json", +] + +[[package]] +name = "k8s-openapi" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1985030683a2bac402cbda61222195de80d3f66b4c87ab56e5fea379bd98c3" +dependencies = [ + "base64 0.20.0", + "bytes", + "chrono", + "schemars", + "serde", + "serde-value", + "serde_json", +] + +[[package]] +name = "kube" +version = "0.80.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414d80c69906a91e8ecf4ae16d0fb504e19aa6b099135d35d85298b4e4be3ed3" +dependencies = [ + "k8s-openapi", + "kube-client", + "kube-core", + "kube-derive", +] + +[[package]] +name = "kube-client" +version = "0.80.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dc5ae0b9148b4e2ebb0dabda06a0cd65b1eed2f41d792d49787841a68050283" +dependencies = [ + "base64 0.20.0", + "bytes", + "chrono", + "dirs-next", + "either", + "futures", + "http", + "http-body", + "hyper", + "hyper-openssl", + "hyper-timeout", + "jsonpath_lib", + "k8s-openapi", + "kube-core", + "openssl", + "pem", + "pin-project", + "secrecy", + "serde", + "serde_json", + "serde_yaml", + "thiserror", + "tokio", + "tokio-util 0.7.10", + "tower", + "tower-http", + "tracing", +] + +[[package]] +name = "kube-core" +version = "0.80.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98331c6f1354893f7c50da069e43a3fd1c84e55bbedc7765d9db22ec3291d07d" +dependencies = [ + "chrono", + "form_urlencoded", + "http", + "k8s-openapi", + "once_cell", + "schemars", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "kube-derive" +version = "0.80.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4be6ff26b9a34ce831d341e8b33bc78986a33c1be88f5bf9ca84e92e98b1dfb" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "serde_json", + "syn 1.0.109", +] + +[[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.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] + +[[package]] +name = "libudev-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linked_hash_set" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "mockall" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab571328afa78ae322493cacca3efac6a0f2e0a67305b4df31fd439ef129ac0" +dependencies = [ + "cfg-if", + "downcast", + "fragile 1.2.2", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e25b214433f669161f414959594216d8e6ba83b6679d3db96899c0b4639033" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "multer" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "log", + "memchr", + "mime", + "spin 0.9.8", + "version_check", +] + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "openssl" +version = "0.10.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "openssl-sys" +version = "0.9.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.9", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "smallvec", + "windows-targets", +] + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "pest" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "pest_meta" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "petgraph" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +dependencies = [ + "fixedbitset", + "indexmap 1.9.3", +] + +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "predicates" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49cfaf7fdaa3bfacc6fa3e7054e65148878354a5cfddcf661df4c851f8021df" +dependencies = [ + "difference", + "float-cmp", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" + +[[package]] +name = "predicates-tree" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "procfs" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8809e0c18450a2db0f236d2a44ec0b4c1412d0eb936233579f0990faa5d5cd" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "flate2", + "hex", + "lazy_static", + "libc", +] + +[[package]] +name = "prometheus" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5986aa8d62380092d2f50f8b1cdba9cb9b6731ffd4b25b51fd126b6c3e05b99c" +dependencies = [ + "cfg-if", + "fnv", + "lazy_static", + "libc", + "memchr", + "parking_lot 0.11.2", + "procfs", + "protobuf", + "thiserror", +] + +[[package]] +name = "prost" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de5e2533f59d08fcf364fd374ebda0692a70bd6d7e66ef97f306f45c6c5d8020" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603" +dependencies = [ + "bytes", + "heck", + "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 1.0.109", +] + +[[package]] +name = "prost-types" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "603bbd6394701d13f3f25aada59c7de9d35a6a5887cfc156181234a44002771b" +dependencies = [ + "bytes", + "prost", +] + +[[package]] +name = "protobuf" +version = "2.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustix" +version = "0.38.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ad981d6c340a49cdc40a1028d9c6084ec7e9fa33fcb839cab656a267071e234" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustls" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64 0.13.1", + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.5", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "schemars" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "serde", + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.192" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.192" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "indexmap 2.1.0", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" +dependencies = [ + "indexmap 1.9.3", + "ryu", + "serde", + "yaml-rust", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[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.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.4.1", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot 0.12.1", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.5", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "tokio-openssl" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08f9ffb7809f1b20c1b398d92acf4cc719874b3b2b2d9ea2f09b4a80350878a" +dependencies = [ + "futures-util", + "openssl", + "openssl-sys", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tonic" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "796c5e1cd49905e65dd8e700d4cb1dffcbfdb4fc9d017de08c1a537afd83627c" +dependencies = [ + "async-stream", + "async-trait", + "base64 0.13.1", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "prost-derive", + "tokio", + "tokio-rustls", + "tokio-stream", + "tokio-util 0.6.10", + "tower", + "tower-layer", + "tower-service", + "tracing", + "tracing-futures", +] + +[[package]] +name = "tonic-build" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12b52d07035516c2b74337d2ac7746075e7dcae7643816c1b12c5ff8a7484c08" +dependencies = [ + "proc-macro2", + "prost-build", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand", + "slab", + "tokio", + "tokio-util 0.7.10", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" +dependencies = [ + "base64 0.13.1", + "bitflags 1.3.2", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "udev" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "048df778e99eea028c08cca7853b9b521df6948b59bb29ab8bb737c057f58e6d" +dependencies = [ + "libc", + "libudev-sys", +] + +[[package]] +name = "udev-discovery-handler" +version = "0.12.16" +dependencies = [ + "akri-discovery-utils", + "akri-udev", + "env_logger", + "log", + "tokio", +] + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "warp" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1e92e22e03ff1230c03a1a8ee37d2f89cd489e2e541b7550d6afad96faed169" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "headers", + "http", + "hyper", + "log", + "mime", + "mime_guess", + "multer", + "percent-encoding", + "pin-project", + "rustls-pemfile", + "scoped-tls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tokio-util 0.7.10", + "tower-service", + "tracing", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" + +[[package]] +name = "web-sys" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +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-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "zeroize" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12a3946ecfc929b583800f4629b6c25b88ac6e92a40ea5670f77112a85d40a8b" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..cdd95d5 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "udev-discovery-handler" +version = { workspace = true } +license = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } + +[workspace.package] +version = "0.12.16" +license = "Apache-2.0" +authors = ["Akri Maintainers "] +edition = "2018" +rust-version = "1.68.1" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +akri-discovery-utils = { git = "https://github.com/project-akri/akri/", tag = "v0.12.9" } +akri-udev = { path = "crates/udev" } +env_logger = "0.10.0" +log = "0.4" +tokio = { version = "1.0.1" } diff --git a/LICENSE b/LICENSE index 261eeb9..ae0df2b 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2021 Akri Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0abee1a --- /dev/null +++ b/Makefile @@ -0,0 +1,51 @@ +BUILDX_ARGS = +EXTRA_CARGO_ARGS = + +PUSH ?= +LOAD ?= +LOCAL_ARCH = $(shell uname -m) +ifeq ($(LOAD), 1) +PLATFORMS ?= $(LOCAL_ARCH) +ifneq (1, $(words $(PLATFORMS))) +$(error Cannot load for more than one platform: [$(PLATFORMS)]) +endif +else +PLATFORMS ?= amd64 arm64 arm/v7 +endif + +null := +space := $(null) # +comma := , + +DOCKER_PLATFORMS = $(subst $(space),$(comma),$(strip $(addprefix linux/, $(PLATFORMS)))) + +# Specify flag to build optimized release version of rust components. +# Set to be empty to use debug builds. +BUILD_RELEASE_FLAG ?= 1 + +REGISTRY ?= devcaptest.azurecr.io +UNIQUE_ID ?= $(USER) +DOCKERFILE_DIR ?= build +PREFIX ?= $(REGISTRY)/$(UNIQUE_ID) + +# Evaluate VERSION and TIMESTAMP immediately to avoid +# any lazy evaluation change in the values +VERSION=$(shell cat version.txt) +TIMESTAMP := $(shell date +"%Y%m%d_%H%M%S") + +VERSION_LABEL=v$(VERSION)-$(TIMESTAMP) +LABEL_PREFIX ?= $(VERSION_LABEL) + +CACHE_OPTION ?= + +ENABLE_DOCKER_MANIFEST = DOCKER_CLI_EXPERIMENTAL=enabled + +AMD64_SUFFIX = amd64 +ARM32V7_SUFFIX = arm32v7 +ARM64V8_SUFFIX = arm64v8 + +COMMON_DOCKER_BUILD_ARGS = $(if $(LOAD), --load) $(if $(PUSH), --push) --platform=$(DOCKER_PLATFORMS) + +.PHONY: akri-udev-discovery-handler +akri-udev-discovery-handler: + docker buildx build $(COMMON_DOCKER_BUILD_ARGS) --build-arg AKRI_COMPONENT=udev-discovery-handler --tag "$(PREFIX)/udev-discovery:$(LABEL_PREFIX)" --build-arg EXTRA_CARGO_ARGS="$(if $(BUILD_RELEASE_FLAG), --release)" --file $(DOCKERFILE_DIR)/Dockerfile.rust . diff --git a/README.md b/README.md index 2f977c0..85a0d08 100644 --- a/README.md +++ b/README.md @@ -1 +1,22 @@ -# udev-discovery-handler \ No newline at end of file +

Akri Logo

+ +[![Slack channel #akri](https://img.shields.io/badge/slack-akri-blueviolet.svg?logo=slack)](https://kubernetes.slack.com/messages/akri) +[![Rust Version](https://img.shields.io/badge/rustc-1.68.1-blue.svg)](https://blog.rust-lang.org/2023/03/31/Rust-1.68.1.html) +[![codecov](https://codecov.io/gh/project-akri/akri/branch/main/graph/badge.svg?token=V468HO7CDE)](https://codecov.io/gh/project-akri/udev-discovery-handler) + +---- + +# Akri Udev Discovery Handler + +An [Akri](https://docs.akri.sh/) Discovery Handler for discovery Udev devices. + +## Documentation +See Akri's [documentation site](https://docs.akri.sh/discovery-handlers/udev) and the [docs repository](https://github.com/project-akri/akri-docs) to contribute new docs. + +## Community, Contributing, and Support +You can reach the Akri community via the [#akri](https://kubernetes.slack.com/messages/akri) channel in [Kubernetes Slack](https://kubernetes.slack.com) or join our [community calls](https://hackmd.io/@akri/S1GKJidJd) on the first Tuesday of the month at 9:00 AM PT. + +Akri welcomes contributions, whether by [creating new issues](https://github.com/project-akri/udev-discovery-handler/issues/) or pull requests. See our [contributing document](https://docs.akri.sh/community/contributing) on how to get started! + +## Licensing +This project is released under the [Apache 2.0 license](./LICENSE). diff --git a/build/Dockerfile.rust b/build/Dockerfile.rust new file mode 100644 index 0000000..00dd56c --- /dev/null +++ b/build/Dockerfile.rust @@ -0,0 +1,34 @@ +FROM --platform=$BUILDPLATFORM tonistiigi/xx:master AS xx + +FROM --platform=$BUILDPLATFORM rust:1.72-slim-bookworm AS build +RUN rustup component add rustfmt +RUN apt-get update && apt-get install -y clang lld protobuf-compiler pkg-config mmdebstrap wget +COPY --from=xx / / +ARG TARGETPLATFORM + +# See https://github.com/tonistiigi/xx/issues/108 +RUN sed -i -E 's/xx-clang --setup-target-triple/XX_VENDOR=\$vendor ARM_TARGET_ARCH="" xx-clang --setup-target-triple/' $(which xx-cargo) && \ + sed -i -E 's/\$\(xx-info\)-/\$\(XX_VENDOR=\$vendor ARM_TARGET_ARCH="" xx-info\)-/g' $(which xx-cargo) + +# Generate minimal runtime environment +RUN mmdebstrap --architectures=$(xx-info debian-arch) --include=libc6,libssl3,libudev1,busybox --variant=extract bookworm /installroot +RUN mkdir -p /installroot/usr/local/bin /build/bin && for tool in sh uniq tail sort grep cut; do ln -s /bin/busybox /installroot/bin/$tool; done + + +RUN xx-apt-get install -y xx-c-essentials libssl-dev libudev-dev pkg-config +COPY . /app +WORKDIR /app +ARG EXTRA_CARGO_ARGS +RUN XX_DEBUG_CARGO=1 xx-cargo build ${EXTRA_CARGO_ARGS} +ARG AKRI_COMPONENT +RUN PROFILE=$(echo "${EXTRA_CARGO_ARGS}" | grep -q -- --release && echo "release" || echo "debug"); \ + xx-verify ./target/$(xx-cargo --print-target-triple)/${PROFILE}/${AKRI_COMPONENT}\ + && cp ./target/$(xx-cargo --print-target-triple)/${PROFILE}/${AKRI_COMPONENT} /build/bin/akri + +FROM scratch +COPY --from=build /installroot / +COPY --from=build /build/bin /usr/local/bin +ENV RUST_LOG akri_discovery_utils,akri_udev,udev_discovery_handler +# Using a fixed value here as we can't use any variable in entrypoint +ENTRYPOINT [ "/usr/local/bin/akri" ] + diff --git a/build/setup.sh b/build/setup.sh new file mode 100755 index 0000000..97a64a6 --- /dev/null +++ b/build/setup.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# exit on failures +set -ex + +echo "User: $(whoami)" + +apt_dependencies="git curl libssl-dev pkg-config" +echo "Install dependencies: $apt_dependencies" +if [ -x "$(command -v sudo)" ]; +then + echo "Run sudo apt install ..." + sudo apt update + sudo apt install -y $apt_dependencies +else + echo "Run apt update and apt install without sudo" + apt update + apt install -y $apt_dependencies +fi + +if ! [ -x "$(command -v rustup)" ]; +then + if [ -x "$(command -v sudo)" ]; + then + echo "Install rustup" + sudo curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=1.68.1 + else + echo "Install rustup" + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain=1.68.1 + fi +else + echo "Found rustup" +fi + +echo "Install rustfmt" +rustup component add rustfmt +echo "Dependencies successfully installed!" +echo -e "\033[33mNote: to build full agent with embedded udev discovery, also install libudev-dev\033[0m" +exit 0 \ No newline at end of file diff --git a/crates/udev/Cargo.lock b/crates/udev/Cargo.lock new file mode 100644 index 0000000..87725f1 --- /dev/null +++ b/crates/udev/Cargo.lock @@ -0,0 +1,2628 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "akri-discovery-utils" +version = "0.12.9" +source = "git+https://github.com/project-akri/akri/?tag=v0.12.9#911cdc1e9f5aeed76f7e09339db35de4d871478a" +dependencies = [ + "akri-shared", + "anyhow", + "async-stream", + "futures", + "log", + "prost", + "serde", + "serde_derive", + "serde_yaml", + "tokio", + "tokio-stream", + "tonic", + "tonic-build", + "tower", +] + +[[package]] +name = "akri-shared" +version = "0.12.9" +source = "git+https://github.com/project-akri/akri/?tag=v0.12.9#911cdc1e9f5aeed76f7e09339db35de4d871478a" +dependencies = [ + "anyhow", + "async-trait", + "either", + "k8s-openapi", + "kube", + "log", + "mockall", + "prometheus", + "rand", + "schemars", + "serde", + "serde_derive", + "serde_json", + "serde_yaml", + "tokio", + "tonic", + "tower", + "warp", +] + +[[package]] +name = "akri-udev" +version = "0.12.16" +dependencies = [ + "akri-discovery-utils", + "anyhow", + "async-trait", + "env_logger", + "log", + "mockall", + "pest", + "pest_derive", + "regex", + "serde", + "serde_derive", + "serde_json", + "tokio", + "tokio-stream", + "tonic", + "udev", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "async-trait" +version = "0.1.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "data-encoding" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" + +[[package]] +name = "difference" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "downcast" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d" + +[[package]] +name = "dyn-clone" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "env_logger" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fixedbitset" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float-cmp" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fragile" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7464c5c4a3f014d9b2ec4073650e5c06596f385060af740fc45ad5a19f959e8" +dependencies = [ + "fragile 2.0.0", +] + +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + +[[package]] +name = "futures" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-executor" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" + +[[package]] +name = "futures-macro" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "futures-sink" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" + +[[package]] +name = "futures-task" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-util" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + +[[package]] +name = "h2" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util 0.7.10", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" + +[[package]] +name = "headers" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +dependencies = [ + "base64 0.21.5", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.4.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-openssl" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ee5d7a8f718585d1c3c61dfde28ef5b0bb14734b4db13f5ada856cdc6c612b" +dependencies = [ + "http", + "hyper", + "linked_hash_set", + "once_cell", + "openssl", + "openssl-sys", + "parking_lot 0.12.1", + "tokio", + "tokio-openssl", + "tower-layer", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.2", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "js-sys" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonpath_lib" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaa63191d68230cccb81c5aa23abd53ed64d83337cacbb25a7b8c7979523774f" +dependencies = [ + "log", + "serde", + "serde_json", +] + +[[package]] +name = "k8s-openapi" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1985030683a2bac402cbda61222195de80d3f66b4c87ab56e5fea379bd98c3" +dependencies = [ + "base64 0.20.0", + "bytes", + "chrono", + "schemars", + "serde", + "serde-value", + "serde_json", +] + +[[package]] +name = "kube" +version = "0.80.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414d80c69906a91e8ecf4ae16d0fb504e19aa6b099135d35d85298b4e4be3ed3" +dependencies = [ + "k8s-openapi", + "kube-client", + "kube-core", + "kube-derive", +] + +[[package]] +name = "kube-client" +version = "0.80.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dc5ae0b9148b4e2ebb0dabda06a0cd65b1eed2f41d792d49787841a68050283" +dependencies = [ + "base64 0.20.0", + "bytes", + "chrono", + "dirs-next", + "either", + "futures", + "http", + "http-body", + "hyper", + "hyper-openssl", + "hyper-timeout", + "jsonpath_lib", + "k8s-openapi", + "kube-core", + "openssl", + "pem", + "pin-project", + "secrecy", + "serde", + "serde_json", + "serde_yaml", + "thiserror", + "tokio", + "tokio-util 0.7.10", + "tower", + "tower-http", + "tracing", +] + +[[package]] +name = "kube-core" +version = "0.80.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98331c6f1354893f7c50da069e43a3fd1c84e55bbedc7765d9db22ec3291d07d" +dependencies = [ + "chrono", + "form_urlencoded", + "http", + "k8s-openapi", + "once_cell", + "schemars", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "kube-derive" +version = "0.80.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4be6ff26b9a34ce831d341e8b33bc78986a33c1be88f5bf9ca84e92e98b1dfb" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "serde_json", + "syn 1.0.109", +] + +[[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.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] + +[[package]] +name = "libudev-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linked_hash_set" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "mockall" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab571328afa78ae322493cacca3efac6a0f2e0a67305b4df31fd439ef129ac0" +dependencies = [ + "cfg-if", + "downcast", + "fragile 1.2.2", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e25b214433f669161f414959594216d8e6ba83b6679d3db96899c0b4639033" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "multer" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "log", + "memchr", + "mime", + "spin 0.9.8", + "version_check", +] + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "openssl" +version = "0.10.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "openssl-sys" +version = "0.9.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.9", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "smallvec", + "windows-targets", +] + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "pest" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "pest_meta" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "petgraph" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +dependencies = [ + "fixedbitset", + "indexmap 1.9.3", +] + +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "predicates" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49cfaf7fdaa3bfacc6fa3e7054e65148878354a5cfddcf661df4c851f8021df" +dependencies = [ + "difference", + "float-cmp", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" + +[[package]] +name = "predicates-tree" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "procfs" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8809e0c18450a2db0f236d2a44ec0b4c1412d0eb936233579f0990faa5d5cd" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "flate2", + "hex", + "lazy_static", + "libc", +] + +[[package]] +name = "prometheus" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5986aa8d62380092d2f50f8b1cdba9cb9b6731ffd4b25b51fd126b6c3e05b99c" +dependencies = [ + "cfg-if", + "fnv", + "lazy_static", + "libc", + "memchr", + "parking_lot 0.11.2", + "procfs", + "protobuf", + "thiserror", +] + +[[package]] +name = "prost" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de5e2533f59d08fcf364fd374ebda0692a70bd6d7e66ef97f306f45c6c5d8020" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603" +dependencies = [ + "bytes", + "heck", + "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 1.0.109", +] + +[[package]] +name = "prost-types" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "603bbd6394701d13f3f25aada59c7de9d35a6a5887cfc156181234a44002771b" +dependencies = [ + "bytes", + "prost", +] + +[[package]] +name = "protobuf" +version = "2.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustix" +version = "0.38.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ad981d6c340a49cdc40a1028d9c6084ec7e9fa33fcb839cab656a267071e234" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustls" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64 0.13.1", + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.5", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "schemars" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "serde", + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.192" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.192" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "indexmap 2.1.0", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" +dependencies = [ + "indexmap 1.9.3", + "ryu", + "serde", + "yaml-rust", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[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.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.4.1", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot 0.12.1", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.5", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "tokio-openssl" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08f9ffb7809f1b20c1b398d92acf4cc719874b3b2b2d9ea2f09b4a80350878a" +dependencies = [ + "futures-util", + "openssl", + "openssl-sys", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tonic" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "796c5e1cd49905e65dd8e700d4cb1dffcbfdb4fc9d017de08c1a537afd83627c" +dependencies = [ + "async-stream", + "async-trait", + "base64 0.13.1", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "prost-derive", + "tokio", + "tokio-rustls", + "tokio-stream", + "tokio-util 0.6.10", + "tower", + "tower-layer", + "tower-service", + "tracing", + "tracing-futures", +] + +[[package]] +name = "tonic-build" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12b52d07035516c2b74337d2ac7746075e7dcae7643816c1b12c5ff8a7484c08" +dependencies = [ + "proc-macro2", + "prost-build", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand", + "slab", + "tokio", + "tokio-util 0.7.10", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" +dependencies = [ + "base64 0.13.1", + "bitflags 1.3.2", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "udev" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "048df778e99eea028c08cca7853b9b521df6948b59bb29ab8bb737c057f58e6d" +dependencies = [ + "libc", + "libudev-sys", +] + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "warp" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1e92e22e03ff1230c03a1a8ee37d2f89cd489e2e541b7550d6afad96faed169" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "headers", + "http", + "hyper", + "log", + "mime", + "mime_guess", + "multer", + "percent-encoding", + "pin-project", + "rustls-pemfile", + "scoped-tls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tokio-util 0.7.10", + "tower-service", + "tracing", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" + +[[package]] +name = "web-sys" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +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-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "zeroize" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12a3946ecfc929b583800f4629b6c25b88ac6e92a40ea5670f77112a85d40a8b" diff --git a/crates/udev/Cargo.toml b/crates/udev/Cargo.toml new file mode 100644 index 0000000..f1225b2 --- /dev/null +++ b/crates/udev/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "akri-udev" +version = { workspace = true } +license = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +akri-discovery-utils = { git = "https://github.com/project-akri/akri/", tag = "v0.12.9" } +anyhow = "1.0.38" +async-trait = "0.1.0" +log = "0.4" +pest = "2.0" +pest_derive = "2.0" +regex = "1" +serde = "1.0.104" +serde_derive = "1.0.104" +tokio = { version = "1.0", features = ["time", "net", "sync"] } +tokio-stream = { version = "0.1", features = ["net"] } +tonic = { version = "0.5.2", features = ["tls"] } +udev = "0.5" + +[dev-dependencies] +env_logger = "0.10.0" +mockall = "0.10.2" +serde_json = "1.0.45" diff --git a/crates/udev/src/discovery_handler.rs b/crates/udev/src/discovery_handler.rs new file mode 100644 index 0000000..037ff5d --- /dev/null +++ b/crates/udev/src/discovery_handler.rs @@ -0,0 +1,195 @@ +use super::{ + discovery_impl::{do_parse_and_find, insert_device_with_relatives, DeviceProperties}, + wrappers::udev_enumerator, +}; +use akri_discovery_utils::discovery::{ + discovery_handler::{deserialize_discovery_details, DISCOVERED_DEVICES_CHANNEL_CAPACITY}, + v0::{ + discovery_handler_server::DiscoveryHandler, Device, DeviceSpec, DiscoverRequest, + DiscoverResponse, + }, + DiscoverStream, +}; +use async_trait::async_trait; +use log::{error, info, trace}; +use std::collections::{HashMap, HashSet}; +use std::time::Duration; +use tokio::sync::mpsc; +use tokio::time::sleep; +use tonic::{Response, Status}; + +// TODO: make this configurable +pub const DISCOVERY_INTERVAL_SECS: u64 = 10; + +/// This defines the udev data stored in the Configuration +/// CRD DiscoveryDetails +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct UdevDiscoveryDetails { + pub udev_rules: Vec, + + #[serde(default)] + pub group_recursive: bool, +} + +/// `DiscoveryHandlerImpl` discovers udev instances by parsing the udev rules in `discovery_handler_config.udev_rules`. +pub struct DiscoveryHandlerImpl { + register_sender: Option>, +} + +impl DiscoveryHandlerImpl { + pub fn new(register_sender: Option>) -> Self { + DiscoveryHandlerImpl { register_sender } + } +} + +#[async_trait] +impl DiscoveryHandler for DiscoveryHandlerImpl { + type DiscoverStream = DiscoverStream; + async fn discover( + &self, + request: tonic::Request, + ) -> Result, Status> { + info!("discover - called for udev protocol"); + let register_sender = self.register_sender.clone(); + let discover_request = request.get_ref(); + let (discovered_devices_sender, discovered_devices_receiver) = + mpsc::channel(DISCOVERED_DEVICES_CHANNEL_CAPACITY); + let discovery_handler_config: UdevDiscoveryDetails = + deserialize_discovery_details(&discover_request.discovery_details) + .map_err(|e| tonic::Status::new(tonic::Code::InvalidArgument, format!("{}", e)))?; + let mut previously_discovered_devices: Vec = Vec::new(); + tokio::spawn(async move { + let udev_rules = discovery_handler_config.udev_rules.clone(); + loop { + trace!("discover - for udev rules {:?}", udev_rules); + // Before each iteration, check if receiver has dropped + if discovered_devices_sender.is_closed() { + error!("discover - channel closed ... attempting to re-register with Agent"); + if let Some(sender) = register_sender { + sender.send(()).await.unwrap(); + } + break; + } + let mut devpaths: HashMap> = HashMap::new(); + udev_rules.iter().for_each(|rule| { + let enumerator = udev_enumerator::create_enumerator(); + let paths = do_parse_and_find(enumerator, rule).unwrap(); + for path in paths.into_iter() { + if !discovery_handler_config.group_recursive { + devpaths.insert(path.0.clone(), HashSet::from([path])); + } else { + insert_device_with_relatives(&mut devpaths, path); + } + } + }); + trace!( + "discover - mapping and returning devices at devpaths {:?}", + devpaths + ); + let discovered_devices = devpaths + .into_iter() + .map(|(id, paths)| { + let mut properties = HashMap::new(); + let mut device_specs = Vec::new(); + for (i, (_, node)) in paths.into_iter().enumerate() { + let property_suffix = discovery_handler_config + .group_recursive + .then(|| format!("_{}", i)) + .unwrap_or_default(); + if let Some(devnode) = node { + properties.insert( + super::UDEV_DEVNODE_LABEL_ID.to_string() + &property_suffix, + devnode.clone(), + ); + device_specs.push(DeviceSpec { + container_path: devnode.clone(), + host_path: devnode, + permissions: "rwm".to_string(), + }) + } + } + + //id is the sysfs path of the most top level device so we only need this one + properties.insert(super::UDEV_DEVPATH_LABEL_ID.to_string(), id.clone()); + + // TODO: use device spec + Device { + id, + properties, + mounts: Vec::default(), + device_specs, + } + }) + .collect::>(); + let mut changed_device_list = false; + let mut matching_device_count = 0; + discovered_devices.iter().for_each(|device| { + if !previously_discovered_devices.contains(device) { + changed_device_list = true; + } else { + matching_device_count += 1; + } + }); + if changed_device_list + || matching_device_count != previously_discovered_devices.len() + { + info!("discover - sending updated device list"); + previously_discovered_devices = discovered_devices.clone(); + if let Err(e) = discovered_devices_sender + .send(Ok(DiscoverResponse { + devices: discovered_devices, + })) + .await + { + error!( + "discover - for udev failed to send discovery response with error {}", + e + ); + if let Some(sender) = register_sender { + sender.send(()).await.unwrap(); + } + break; + } + } + sleep(Duration::from_secs(DISCOVERY_INTERVAL_SECS)).await; + } + }); + Ok(Response::new(tokio_stream::wrappers::ReceiverStream::new( + discovered_devices_receiver, + ))) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_deserialize_discovery_details_empty() { + // Check that udev errors if no udev rules passed in + let udev_dh_config: Result = + deserialize_discovery_details(""); + assert!(udev_dh_config.is_err()); + + let yaml = r#" + udevRules: [] + "#; + let udev_dh_config: UdevDiscoveryDetails = deserialize_discovery_details(yaml).unwrap(); + assert!(udev_dh_config.udev_rules.is_empty()); + let serialized = serde_json::to_string(&udev_dh_config).unwrap(); + let expected_deserialized = r#"{"udevRules":[],"groupRecursive":false}"#; + assert_eq!(expected_deserialized, serialized); + } + + #[test] + fn test_deserialize_discovery_details_detailed() { + let yaml = r#" + udevRules: + - 'KERNEL=="video[0-9]*"' + "#; + let udev_dh_config: UdevDiscoveryDetails = deserialize_discovery_details(yaml).unwrap(); + assert_eq!(udev_dh_config.udev_rules.len(), 1); + assert_eq!(&udev_dh_config.udev_rules[0], "KERNEL==\"video[0-9]*\""); + } +} diff --git a/crates/udev/src/discovery_impl.rs b/crates/udev/src/discovery_impl.rs new file mode 100644 index 0000000..307908c --- /dev/null +++ b/crates/udev/src/discovery_impl.rs @@ -0,0 +1,1453 @@ +use std::collections::HashSet; + +use super::wrappers::{ + udev_device::{ + get_attribute_value, get_devnode, get_devpath, get_driver, get_parent, get_property_value, + get_subsystem, get_sysname, DeviceExt, + }, + udev_enumerator::Enumerator, +}; +use log::{error, info, trace}; +use pest::iterators::Pair; +use pest::Parser; +use regex::Regex; + +const TAGS: &str = "TAGS"; + +#[derive(Parser)] +#[grammar = "udev_rule_grammar.pest"] +pub struct UdevRuleParser; + +#[derive(Debug, PartialEq)] +pub struct UdevFilter<'a> { + field: Pair<'a, Rule>, + operation: Rule, + value: String, +} + +/// A udev device is defined by its devpath and devnode (if exists) +pub(crate) type DeviceProperties = (String, Option); + +/// This parses the udev rule into UdevFilters and finds all devices that match those filters +pub fn do_parse_and_find( + enumerator: impl Enumerator, + udev_rule_string: &str, +) -> Result, anyhow::Error> { + let udev_filters = parse_udev_rule(udev_rule_string)?; + let devices = find_devices(enumerator, udev_filters)?; + trace!( + "do_parse_and_find - returning discovered devices with devpaths: {:?}", + devices + ); + Ok(devices) +} + +/// This parses a udev rule and returns a list of UdevFilter objects that specify which devices to search for. +/// This returns an error if the udev rule parameter does not fit the format specified in udev +/// man pages/wiki and therefore does not match the grammar specified in udev_rule_grammar.pest +/// A udev rule is made of a list of field-value pairs which have format field"value" +/// This function will only create UdevFilter objects for field-value pairs with supported fields and operations. +/// Udev discovery is only interested in match operations ("==", "!="), so all action ("=" , "+=" , "-=" , ":=") operations +/// will be ignored. +/// Udev discovery is only interested in match fields, so all action fields, such as TEST, are ignored +fn parse_udev_rule(udev_rule_string: &str) -> Result, anyhow::Error> { + info!( + "parse_udev_rule - enter for udev rule string {}", + udev_rule_string + ); + let mut udev_filters: Vec = Vec::new(); + + // So long as parse succeeds, subsequent unwraps will not fails, since they are following the + // format specified in the grammar + let udev_rule = UdevRuleParser::parse(Rule::udev_rule, udev_rule_string)? + .next() // move to first rule within udev_rule aka inner_rule + .unwrap() // does not panic because udev_rule always has inner_rule + .into_inner() // go into inner_rule which has format { udev_filter ~ ("," ~ udev_filter)* } + .next() // move to first rule in inner_rule aka udev_filter + .unwrap(); // does not panic because inner_rule always has udev_filter + + trace!( + "parse_udev_rule - parsing udev_rule {:?}", + udev_rule.as_str() + ); + for udev_filter in udev_rule.into_inner() { + let mut inner_rules = udev_filter.into_inner(); + let field_pair = inner_rules.next().unwrap(); + let inner_field = field_pair.into_inner().next().unwrap(); + if inner_field.as_rule() == Rule::unsupported_field { + return Err(anyhow::format_err!( + "parse_udev_rule - unsupported field {}", + inner_field.into_inner().next().unwrap().as_str() + )); + } + + let operation_rule = inner_rules + .next() + .unwrap() + .into_inner() + .next() + .unwrap() + .as_rule(); + let mut quoted_value = inner_rules.next().unwrap().into_inner(); + let value = quoted_value.next().unwrap().as_str(); + if operation_rule != Rule::action_operation { + udev_filters.push(UdevFilter { + field: inner_field, + operation: operation_rule, + value: value.to_string(), + }); + } else { + return Err(anyhow::format_err!("parse_udev_rule - unsupported action operation for rule with field [{}], operation [{:?}], and value[{}]", + inner_field.into_inner().as_str(), operation_rule, value)); + } + } + Ok(udev_filters) +} + +/// This searches for devices that match the UdevFilters and returns their devpaths +fn find_devices( + enumerator: impl Enumerator, + udev_filters: Vec, +) -> std::io::Result> { + let mut enumerator = enumerator; + trace!("find_devices - enter with udev_filters {:?}", udev_filters); + + // Enumerator scans sys devices for its filters. Only certain filters can be applied to it. + // Divide device fields by type of filter than can be applied to Enumerator, if any + // (1) Enumerator can filter for field by equality/match + // (2) Enumerator can filter for field by inequality/nomatch + // (3) Enumerator cannot filter for field. Must manually filter by looking at each Device the filtered Enumerator returns. + let match_fields = vec![ + Rule::devpath, + Rule::kernel, + Rule::tag, + Rule::subsystem, + Rule::attribute, + Rule::property, + ]; + let nomatch_fields = vec![Rule::attribute, Rule::subsystem]; + + let mut match_udev_filters: Vec<&UdevFilter> = Vec::new(); + let mut nomatch_udev_filters: Vec<&UdevFilter> = Vec::new(); + let mut remaining_udev_filters: Vec<&UdevFilter> = Vec::new(); + + // Sort UdevFilters based off of which group they belong to + udev_filters.iter().for_each(|udev_filter| { + if udev_filter.operation == Rule::equality + && match_fields.contains(&udev_filter.field.as_rule()) + { + match_udev_filters.push(udev_filter); + } else if udev_filter.operation == Rule::inequality + && nomatch_fields.contains(&udev_filter.field.as_rule()) + { + nomatch_udev_filters.push(udev_filter); + } else { + remaining_udev_filters.push(udev_filter); + } + }); + + // Apply UdevFilters of groups in 1,2,3 order + filter_by_match_udev_filters(&mut enumerator, match_udev_filters); + filter_by_nomatch_udev_filters(&mut enumerator, nomatch_udev_filters); + let devices: Vec = enumerator.scan_devices()?.collect(); + let final_devices = filter_by_remaining_udev_filters(devices, remaining_udev_filters); + + let device_devpaths: Vec = final_devices + .into_iter() + .map(|device| { + ( + get_devpath(&device).to_str().unwrap().to_string(), + get_devnode(&device).map(|devnode| devnode.to_str().unwrap().to_string()), + ) + }) + .collect(); + + Ok(device_devpaths) +} + +/// This adds equality filters to the Enumerator +fn filter_by_match_udev_filters(enumerator: &mut impl Enumerator, udev_filters: Vec<&UdevFilter>) { + trace!( + "enumerator_match_udev_filters - enter with udev_filters {:?}", + udev_filters + ); + for udev_filter in udev_filters { + match udev_filter.field.as_rule() { + Rule::devpath => { + let mut syspath: String = "/sys".to_owned(); + syspath.push_str(&udev_filter.value); + enumerator.add_syspath(&syspath).unwrap(); + } + Rule::kernel => { + enumerator.match_sysname(&udev_filter.value).unwrap(); + } + Rule::tag => { + enumerator.match_tag(&udev_filter.value).unwrap(); + } + Rule::subsystem => { + enumerator.match_subsystem(&udev_filter.value).unwrap(); + } + Rule::attribute => { + let key = udev_filter + .field + .clone() + .into_inner() + .next() + .unwrap() + .into_inner() + .next() + .unwrap() + .as_str(); + enumerator.match_attribute(key, &udev_filter.value).unwrap(); + } + Rule::property => { + let key = udev_filter + .field + .clone() + .into_inner() + .next() + .unwrap() + .into_inner() + .next() + .unwrap() + .as_str(); + enumerator.match_property(key, &udev_filter.value).unwrap(); + } + _ => { + error!("enumerator_match_udev_filters - encountered unsupported field"); + } + } + } +} + +/// This adds inequality filters to the Enumerator +fn filter_by_nomatch_udev_filters( + enumerator: &mut impl Enumerator, + udev_filters: Vec<&UdevFilter>, +) { + trace!( + "enumerator_nomatch_udev_filters - enter with udev_filters {:?}", + udev_filters + ); + for udev_filter in udev_filters { + match udev_filter.field.as_rule() { + Rule::attribute => { + let key = udev_filter + .field + .clone() + .into_inner() + .next() + .unwrap() + .into_inner() + .next() + .unwrap() + .as_str(); + enumerator + .nomatch_attribute(key, &udev_filter.value) + .unwrap(); + } + Rule::subsystem => { + enumerator.nomatch_subsystem(&udev_filter.value).unwrap(); + } + _ => { + error!("enumerator_nomatch_udev_filters - encountered unsupported field"); + } + } + } +} + +/// This iterates over devices returned by filtered Enumerator and inspects the device's fields to see if they match/don't match +/// the fields in the remaining UdevFilters that could not be applied to Enumerator. +fn filter_by_remaining_udev_filters( + devices: Vec, + udev_filters: Vec<&UdevFilter>, +) -> Vec { + trace!( + "filter_by_remaining_udev_filters - enter with udev_filters {:?}", + udev_filters + ); + let mut mutable_devices = devices; + for udev_filter in udev_filters { + let value_regex = Regex::new(&udev_filter.value).unwrap(); + let is_equality = udev_filter.operation == Rule::equality; + match udev_filter.field.as_rule() { + Rule::devpath => { + // Filter for inequality. Equality already accounted for in filter_by_match_udev_filters + mutable_devices.retain(|device| { + let devpath = get_devpath(device).to_str().unwrap(); + !is_regex_match(devpath, &value_regex) + }); + } + Rule::kernel => { + // Filter for inequality. Equality already accounted for in filter_by_match_udev_filters + mutable_devices.retain(|device| { + let sysname = get_sysname(device).to_str().unwrap(); + !is_regex_match(sysname, &value_regex) + }); + } + Rule::tag => { + mutable_devices.retain(|device| { + if let Some(tags) = get_property_value(device, TAGS) { + let tags = tags.to_str().unwrap().split(':'); + // Filter for inequality. Equality already accounted for in filter_by_match_udev_filters + // Return false if discover a tag that should be excluded + let mut include = true; + for tag in tags { + if is_regex_match(tag, &value_regex) { + include = false; + break; + } + } + include + } else { + true + } + }); + } + Rule::property => { + let key = udev_filter + .field + .clone() + .into_inner() + .next() + .unwrap() + .into_inner() + .next() + .unwrap() + .as_str(); + // Filter for inequality. Equality already accounted for in filter_by_match_udev_filters + mutable_devices.retain(|device| { + if let Some(property_value) = get_property_value(device, key) { + let property_value_str = property_value.to_str().unwrap(); + !is_regex_match(property_value_str, &value_regex) + } else { + true + } + }); + } + Rule::driver => { + mutable_devices.retain(|device| match get_driver(device) { + Some(driver) => { + let driver = driver.to_str().unwrap(); + filter_equality_check(is_equality, is_regex_match(driver, &value_regex)) + } + None => !is_equality, + }); + } + Rule::subsystems => { + mutable_devices.retain(|device| { + filter_equality_check( + is_equality, + device_or_parents_have_subsystem(device, &value_regex), + ) + }); + } + Rule::attributes => { + let key = udev_filter + .field + .clone() + .into_inner() + .next() + .unwrap() + .into_inner() + .next() + .unwrap() + .as_str(); + mutable_devices.retain(|device| { + filter_equality_check( + is_equality, + device_or_parents_have_attribute(device, key, &value_regex), + ) + }); + } + Rule::drivers => { + mutable_devices.retain(|device| { + filter_equality_check( + is_equality, + device_or_parents_have_driver(device, &value_regex), + ) + }); + } + Rule::kernels => { + mutable_devices.retain(|device| { + filter_equality_check( + is_equality, + device_or_parents_have_sysname(device, &value_regex), + ) + }); + } + Rule::tags => { + mutable_devices.retain(|device| { + filter_equality_check( + is_equality, + device_or_parents_have_tag(device, &value_regex), + ) + }); + } + _ => { + error!("filter_by_remaining_udev_filters - encountered unsupported field"); + } + } + } + mutable_devices +} + +/// Check whether the device should be selected based on equality and field matching +fn filter_equality_check(is_equality: bool, is_match: bool) -> bool { + (is_equality && is_match) || (!is_equality && !is_match) +} + +/// Check to see if the current value is a regex match of the requested value. +/// Ensure that the match is exclusively on the value to be tested. For example, for the regex `video[0-9]*`, +/// the values `video0` and `video10` should match; however, `blahvideo0blah` should not be accepted as a match. +fn is_regex_match(test_value: &str, value_regex: &Regex) -> bool { + if let Some(value_containing_match) = value_regex.find(test_value) { + value_containing_match.start() == 0 && value_containing_match.end() == test_value.len() + } else { + false + } +} + +/// Recursively look up a device's hierarchy to see if it or one of its ancestors has a specified subsystem. +fn device_or_parents_have_subsystem(device: &impl DeviceExt, value_regex: &Regex) -> bool { + match get_subsystem(device) { + Some(subsystem) => { + let subsystem_str = subsystem.to_str().unwrap(); + if is_regex_match(subsystem_str, value_regex) { + true + } else { + match get_parent(device) { + Some(parent) => device_or_parents_have_subsystem(&parent, value_regex), + None => false, + } + } + } + None => match get_parent(device) { + Some(parent) => device_or_parents_have_subsystem(&parent, value_regex), + None => false, + }, + } +} + +/// Recursively look up a device's hierarchy to see if it or one of its ancestors has a specified attribute. +fn device_or_parents_have_attribute( + device: &impl DeviceExt, + key: &str, + value_regex: &Regex, +) -> bool { + match get_attribute_value(device, key) { + Some(attribute_value) => { + let attribute_value_str = attribute_value.to_str().unwrap(); + if is_regex_match(attribute_value_str, value_regex) { + true + } else { + match get_parent(device) { + Some(parent) => device_or_parents_have_attribute(&parent, key, value_regex), + None => false, + } + } + } + None => match get_parent(device) { + Some(parent) => device_or_parents_have_attribute(&parent, key, value_regex), + None => false, + }, + } +} + +/// Recursively look up a device's hierarchy to see if it or one of its ancestors has a specified driver. +fn device_or_parents_have_driver(device: &impl DeviceExt, value_regex: &Regex) -> bool { + match get_driver(device) { + Some(driver) => { + let driver_str = driver.to_str().unwrap(); + if is_regex_match(driver_str, value_regex) { + true + } else { + match get_parent(device) { + Some(parent) => device_or_parents_have_driver(&parent, value_regex), + None => false, + } + } + } + None => match get_parent(device) { + Some(parent) => device_or_parents_have_driver(&parent, value_regex), + None => false, + }, + } +} + +/// Recursively look up a device's hierarchy to see if it or one of its ancestors has a specified sysname aka kernel. +fn device_or_parents_have_sysname(device: &impl DeviceExt, value_regex: &Regex) -> bool { + let sysname = get_sysname(device).to_str().unwrap(); + if is_regex_match(sysname, value_regex) { + true + } else { + match get_parent(device) { + Some(parent) => device_or_parents_have_sysname(&parent, value_regex), + None => false, + } + } +} + +/// Recursively look up a device's hierarchy to see if or one of its ancestors has a specified tag. +fn device_or_parents_have_tag(device: &impl DeviceExt, value_regex: &Regex) -> bool { + if let Some(tags) = get_property_value(device, TAGS) { + let tags = tags.to_str().unwrap().split(':'); + let mut has_tag = false; + for tag in tags { + if is_regex_match(tag, value_regex) { + has_tag = true; + break; + } + } + if has_tag { + true + } else { + match get_parent(device) { + Some(parent) => device_or_parents_have_tag(&parent, value_regex), + None => false, + } + } + } else { + match get_parent(device) { + Some(parent) => device_or_parents_have_tag(&parent, value_regex), + None => false, + } + } +} + +/// Retrieve Parent or Children of a device using their sysfs path. +fn get_device_relatives<'a>( + device_path: &str, + possible_relatives: impl Iterator, +) -> (Option, Vec) { + let mut childrens = Vec::new(); + for relative in possible_relatives { + match relative { + parent if device_path.starts_with(relative.as_str()) => { + return (Some(parent.clone()), vec![]) + } + child if relative.starts_with(device_path) => childrens.push(child.clone()), + _ => (), + } + } + (None, childrens) +} + +pub fn insert_device_with_relatives( + devpaths: &mut std::collections::HashMap>, + path: DeviceProperties, +) { + match get_device_relatives(&path.0, devpaths.keys()) { + (Some(parent), _) => { + let _ = devpaths.get_mut(&parent).unwrap().insert(path); + } + (None, children) => { + let id = path.0.clone(); + let mut children_devices: HashSet = children + .into_iter() + .flat_map(|child| devpaths.remove(&child).unwrap().into_iter()) + .collect(); + children_devices.insert(path); + let _ = devpaths.insert(id, children_devices); + } + } +} + +#[cfg(test)] +mod discovery_tests { + use super::super::wrappers::udev_enumerator::{create_enumerator, MockEnumerator}; + use super::*; + use std::{ + collections::HashMap, + ffi::OsStr, + fs::File, + io::{prelude::*, BufReader}, + path::Path, + }; + #[derive(Clone)] + pub struct MockDevice<'a> { + pub devpath: String, + pub devnode: String, + pub sysname: String, + pub properties: std::collections::HashMap, + pub driver: Option<&'a OsStr>, + pub subsystem: Option<&'a OsStr>, + pub attributes: std::collections::HashMap, + pub parent: Box>>, + } + + impl<'a> DeviceExt for MockDevice<'a> { + fn mockable_devpath(&self) -> &OsStr { + OsStr::new(&self.devpath) + } + fn mockable_devnode(&self) -> Option<&Path> { + Some(Path::new(&self.devnode)) + } + fn mockable_sysname(&self) -> &OsStr { + OsStr::new(&self.sysname) + } + fn mockable_property_value(&self, property: &str) -> Option<&OsStr> { + if let Some(value) = self.properties.get(property) { + Some(OsStr::new(value)) + } else { + None + } + } + fn mockable_attribute_value(&self, property: &str) -> Option<&OsStr> { + if let Some(value) = self.attributes.get(property) { + Some(OsStr::new(value)) + } else { + None + } + } + fn mockable_driver(&self) -> Option<&OsStr> { + self.driver + } + fn mockable_subsystem(&self) -> Option<&OsStr> { + self.subsystem + } + fn mockable_parent(&self) -> Option { + *self.parent.clone() + } + } + + #[allow(clippy::too_many_arguments)] + fn create_mock_device<'a>( + devpath: &str, + devnode: &str, + sysname: &str, + properties: HashMap, + attributes: HashMap, + driver: Option<&'a OsStr>, + subsystem: Option<&'a OsStr>, + parent: Option>, + ) -> MockDevice<'a> { + MockDevice { + devpath: devpath.to_string(), + devnode: devnode.to_string(), + sysname: sysname.to_string(), + properties, + attributes, + driver, + subsystem, + parent: Box::new(parent), + } + } + + #[test] + fn test_parse_udev_rule_detailed() { + let _ = env_logger::builder().is_test(true).try_init(); + let rule = "KERNEL==\"video[0-9]*\",SUBSYSTEM==\"video4linux\", ATTR{idVendor}==\"05a9\""; + let udev_filters = parse_udev_rule(rule).unwrap(); + assert_eq!(udev_filters.len(), 3); + assert_eq!(udev_filters[0].field.as_str(), "KERNEL"); + assert_eq!(udev_filters[0].operation, Rule::equality); + assert_eq!(&udev_filters[0].value, "video[0-9]*"); + + assert_eq!(udev_filters[1].field.as_str(), "SUBSYSTEM"); + assert_eq!(udev_filters[1].operation, Rule::equality); + assert_eq!(&udev_filters[1].value, "video4linux"); + + assert_eq!(udev_filters[2].field.as_str(), "ATTR{idVendor}"); + assert_eq!(udev_filters[2].operation, Rule::equality); + assert_eq!(&udev_filters[2].value, "05a9"); + } + + #[test] + fn test_parse_udev_rule_error() { + // Throws error if unknown field (TYPO) + let rule = "KERNEL==\"video[0-9]*\", TYPO==\"blah\", ATTR{idVendor}==\"05a9\", ATTRS{idProduct}==\"4519\""; + assert!(parse_udev_rule(rule).is_err()); + + // Throws error if leading space + let rule = " KERNEL==\"video[0-9]*\", TYPO==\"blah\", ATTR{idVendor}==\"05a9\", ATTRS{idProduct}==\"4519\""; + assert!(parse_udev_rule(rule).is_err()); + } + + #[test] + fn test_parse_udev_rule_empty() { + // Assert that doesn't throw error on empty rules + let rule = ""; + let result = parse_udev_rule(rule); + assert!(result.is_ok()); + let udev_filters = result.unwrap(); + assert_eq!(udev_filters.len(), 0); + } + + #[test] + fn test_parse_udev_rule_from_file() { + let _ = env_logger::builder().is_test(true).try_init(); + let file_path = "test/example.rules"; + let file = File::open(file_path).expect("no such file"); + let buf = BufReader::new(file); + let mut num_udev_filters: Vec = Vec::new(); + let lines: Vec = buf + .lines() + .map(|l| { + let unwrapped = l.expect("Could not parse line"); + num_udev_filters.push(unwrapped[0..1].parse::().unwrap()); + unwrapped[2..].to_string() + }) + .collect(); + for x in 0..lines.len() { + let line = &lines[x]; + let udev_filters = parse_udev_rule(line).unwrap(); + assert_eq!(udev_filters.len(), num_udev_filters[x]); + } + } + + #[test] + fn test_parse_unsupported_udev_rule_from_file() { + let _ = env_logger::builder().is_test(true).try_init(); + let file_path = "test/example-unsupported.rules"; + let file = File::open(file_path).expect("no such file"); + let buf = BufReader::new(file); + buf.lines().for_each(|line| { + let unwrapped = line.expect("Could not parse line"); + assert!(parse_udev_rule(&unwrapped).is_err()); + }); + } + + #[test] + fn test_filter_by_match_udev_filters() { + let rule = "SUBSYSTEM==\"video4linux\", ATTR{someKey}==\"1000\", KERNEL==\"video0\", ENV{ID}==\"1\", TAG==\"some_tag\", DEVPATH==\"/devices/path\""; + let mut mock = MockEnumerator::new(); + mock.expect_match_subsystem() + .times(1) + .withf(move |value: &str| value == "video4linux") + .returning(|_| Ok(())); + mock.expect_match_attribute() + .times(1) + .withf(move |key: &str, value: &str| key == "someKey" && value == "1000") + .returning(|_, _| Ok(())); + mock.expect_match_sysname() + .times(1) + .withf(move |value: &str| value == "video0") + .returning(|_| Ok(())); + mock.expect_match_property() + .times(1) + .withf(move |key: &str, value: &str| key == "ID" && value == "1") + .returning(|_, _| Ok(())); + mock.expect_match_tag() + .times(1) + .withf(move |value: &str| value == "some_tag") + .returning(|_| Ok(())); + mock.expect_add_syspath() + .times(1) + .withf(move |value: &str| value == "/sys/devices/path") + .returning(|_| Ok(())); + let udev_filters = parse_udev_rule(rule).unwrap(); + let udev_filters: Vec<&UdevFilter> = udev_filters.iter().collect(); + filter_by_match_udev_filters(&mut mock, udev_filters); + } + + #[test] + fn test_filter_by_nomatch_udev_filters() { + let rule = "SUBSYSTEM!=\"usb\", ATTR{someKey}!=\"1000\""; + let mut mock = MockEnumerator::new(); + mock.expect_nomatch_subsystem() + .times(1) + .withf(move |value: &str| value == "usb") + .returning(|_| Ok(())); + mock.expect_nomatch_attribute() + .times(1) + .withf(move |key: &str, value: &str| key == "someKey" && value == "1000") + .returning(|_, _| Ok(())); + let udev_filters = parse_udev_rule(rule).unwrap(); + let udev_filters: Vec<&UdevFilter> = udev_filters.iter().collect(); + filter_by_nomatch_udev_filters(&mut mock, udev_filters); + } + + #[test] + fn test_filter_by_remaining_udev_filters() { + let rule = "KERNEL!=\"video0\", TAG!=\"tag_exclude\", ENV{ID}!=\"id_num\", TAG!=\"tag[3-9]\", DEVPATH!=\"/devices/path/exclude\", DRIVER!=\"exclude\""; + let mut include_properties = std::collections::HashMap::new(); + include_properties.insert("TAGS".to_string(), "tag0:tag_excluded:tag2".to_string()); + let mut tag_exclude_properties = std::collections::HashMap::new(); + tag_exclude_properties.insert("TAGS".to_string(), "tag3:other:tag2".to_string()); + let mut id_exclude_properties = std::collections::HashMap::new(); + id_exclude_properties.insert("ID".to_string(), "id_num".to_string()); + let mock_device_to_exclude0 = create_mock_device( + "/devices/path/exclude", + "/dev/exclude", + "mock0", + HashMap::new(), + HashMap::new(), + Some(OsStr::new("include")), + None, + None, + ); + let mock_device_to_exclude1 = create_mock_device( + "/devices/path/include", + "/dev/exclude", + "mock1", + HashMap::new(), + HashMap::new(), + Some(OsStr::new("exclude")), + None, + None, + ); + let mock_device_to_include1 = create_mock_device( + "/devices/path/include", + "/dev/include", + "mock2", + HashMap::new(), + HashMap::new(), + Some(OsStr::new("include")), + None, + None, + ); + let mock_device_to_exclude3 = create_mock_device( + "/devices/path/include", + "/dev/include", + "mock3", + tag_exclude_properties, + HashMap::new(), + Some(OsStr::new("include")), + None, + None, + ); + let mock_device_to_include2 = create_mock_device( + "/devices/path/include", + "/dev/include", + "mock4", + HashMap::new(), + HashMap::new(), + Some(OsStr::new("include")), + None, + None, + ); + let mock_device_to_exclude4 = create_mock_device( + "/devices/path/include", + "/dev/include", + "mock5", + id_exclude_properties, + HashMap::new(), + Some(OsStr::new("include")), + None, + None, + ); + let devices = vec![ + mock_device_to_exclude0, + mock_device_to_exclude1, + mock_device_to_include1, + mock_device_to_exclude3, + mock_device_to_include2, + mock_device_to_exclude4, + ]; + let udev_filters = parse_udev_rule(rule).unwrap(); + let udev_filters: Vec<&UdevFilter> = udev_filters.iter().collect(); + let filtered_devices = filter_by_remaining_udev_filters(devices, udev_filters); + + assert_eq!(filtered_devices.len(), 2); + assert_eq!(get_sysname(&filtered_devices[0]).to_str().unwrap(), "mock2"); + assert_eq!(get_sysname(&filtered_devices[1]).to_str().unwrap(), "mock4"); + } + + #[test] + fn test_filter_by_driver() { + let match_rule = "DRIVER==\"some driver\""; + let mock_device = create_mock_device( + "/devices/path/include", + "/dev/include", + "mock", + HashMap::new(), + HashMap::new(), + Some(OsStr::new("another driver")), + None, + None, + ); + let udev_filters = parse_udev_rule(match_rule).unwrap(); + let udev_filters_ref: Vec<&UdevFilter> = udev_filters.iter().collect(); + let filtered_devices = + filter_by_remaining_udev_filters(vec![mock_device.clone()], udev_filters_ref); + assert_eq!(filtered_devices.len(), 0); + + let nomatch_rule = "DRIVER!=\"some driver\""; + let udev_filters = parse_udev_rule(nomatch_rule).unwrap(); + let udev_filters_ref: Vec<&UdevFilter> = udev_filters.iter().collect(); + let filtered_devices = + filter_by_remaining_udev_filters(vec![mock_device], udev_filters_ref); + assert_eq!(filtered_devices.len(), 1); + } + + // Test that hierarchy fields also check for match with device OR parent device + #[test] + fn test_filter_by_hierarchy_field() { + let rule = "SUBSYSTEMS==\"usb\", ATTRS{someKey}==\"value\", TAGS==\"tag[0-9]*\", KERNELS==\"usb[0-9]*\", DRIVERS==\"some driver\""; + let mut attributes = std::collections::HashMap::new(); + attributes.insert("someKey".to_string(), "value".to_string()); + let mut properties = std::collections::HashMap::new(); + properties.insert("TAGS".to_string(), "tag0:middle_tag:tag".to_string()); + let mock_device = create_mock_device( + "/devices/path/usb", + "/dev/node", + "usb1", + properties, + attributes, + Some(OsStr::new("some driver")), + Some(OsStr::new("usb")), + None, + ); + let udev_filters = parse_udev_rule(rule).unwrap(); + let udev_filters: Vec<&UdevFilter> = udev_filters.iter().collect(); + let filtered_devices = + filter_by_remaining_udev_filters(vec![mock_device.clone()], udev_filters); + + assert_eq!(filtered_devices.len(), 1); + assert_eq!(get_sysname(&filtered_devices[0]).to_str().unwrap(), "usb1"); + + let rule = "SUBSYSTEMS==\"usb\", ATTRS{someKey}==\"value\", TAGS==\"tag[0-9]*\", KERNELS==\"usb[0-9]*\", DRIVERS!=\"some driver\""; + let udev_filters = parse_udev_rule(rule).unwrap(); + let udev_filters: Vec<&UdevFilter> = udev_filters.iter().collect(); + let filtered_devices = filter_by_remaining_udev_filters(vec![mock_device], udev_filters); + assert_eq!(filtered_devices.len(), 0); + } + + #[test] + fn test_filter_by_subsystems() { + let rule = "SUBSYSTEMS==\"usb\""; + let mock_usb_grandparent = create_mock_device( + "/devices/path/usb", + "/dev/node", + "usb-grandparent", + HashMap::new(), + HashMap::new(), + None, + Some(OsStr::new("usb")), + None, + ); + + let mock_usb_parent = create_mock_device( + "/devices/path/usb", + "/dev/node", + "usb-parent", + HashMap::new(), + HashMap::new(), + None, + None, + Some(mock_usb_grandparent.clone()), + ); + let mock_pci_parent = create_mock_device( + "/devices/path", + "/dev/node", + "pci-parent", + HashMap::new(), + HashMap::new(), + None, + Some(OsStr::new("pci")), + None, + ); + let mock_device_pci_child = create_mock_device( + "/devices/path", + "/dev/node", + "pci-child", + HashMap::new(), + HashMap::new(), + None, + Some(OsStr::new("random")), + Some(mock_pci_parent), + ); + let mock_device_usb_child = create_mock_device( + "/devices/path", + "/dev/node", + "usb-child", + HashMap::new(), + HashMap::new(), + Some(OsStr::new("driver")), + Some(OsStr::new("random")), + Some(mock_usb_parent.clone()), + ); + let devices = vec![mock_device_pci_child, mock_device_usb_child]; + let udev_filters = parse_udev_rule(rule).unwrap(); + let udev_filters: Vec<&UdevFilter> = udev_filters.iter().collect(); + let filtered_devices = filter_by_remaining_udev_filters(devices.clone(), udev_filters); + + assert_eq!(filtered_devices.len(), 1); + assert_eq!( + get_sysname(&filtered_devices[0]).to_str().unwrap(), + "usb-child" + ); + + let rule = "SUBSYSTEMS==\"pci\""; + let udev_filters = parse_udev_rule(rule).unwrap(); + let udev_filters: Vec<&UdevFilter> = udev_filters.iter().collect(); + let filtered_devices = filter_by_remaining_udev_filters(devices.clone(), udev_filters); + assert_eq!(filtered_devices.len(), 1); + assert_eq!( + get_sysname(&filtered_devices[0]).to_str().unwrap(), + "pci-child" + ); + + let rule = "SUBSYSTEMS!=\"pci\""; + let udev_filters = parse_udev_rule(rule).unwrap(); + let udev_filters: Vec<&UdevFilter> = udev_filters.iter().collect(); + let filtered_devices = filter_by_remaining_udev_filters(devices.clone(), udev_filters); + assert_eq!(filtered_devices.len(), 1); + assert_eq!( + get_sysname(&filtered_devices[0]).to_str().unwrap(), + "usb-child" + ); + } + + #[test] + fn test_filter_by_attrs() { + let rule = "ATTRS{someKey}==\"value\""; + let mut attributes = std::collections::HashMap::new(); + attributes.insert("someKey".to_string(), "value".to_string()); + let mut attributes2 = std::collections::HashMap::new(); + attributes2.insert("someKey".to_string(), "value2".to_string()); + let mock_usb_grandparent = create_mock_device( + "/devices/path", + "/dev/node", + "usb-grandparent", + HashMap::new(), + attributes, + None, + None, + None, + ); + let mock_usb_parent = create_mock_device( + "/devices/path", + "/dev/node", + "usb-parent", + HashMap::new(), + HashMap::new(), + None, + Some(OsStr::new("usb")), + Some(mock_usb_grandparent), + ); + let mock_pci_parent = create_mock_device( + "/devices/path", + "/dev/node", + "pci-parent", + HashMap::new(), + attributes2, + None, + Some(OsStr::new("pci")), + None, + ); + let mock_device_pci_child = create_mock_device( + "/devices/path", + "/dev/node", + "pci-child", + HashMap::new(), + HashMap::new(), + None, + Some(OsStr::new("random")), + Some(mock_pci_parent), + ); + let mock_device_usb_child = create_mock_device( + "/devices/path", + "/dev/node", + "usb-child", + HashMap::new(), + HashMap::new(), + Some(OsStr::new("driver")), + Some(OsStr::new("random")), + Some(mock_usb_parent), + ); + let devices = vec![mock_device_pci_child, mock_device_usb_child]; + let udev_filters = parse_udev_rule(rule).unwrap(); + let udev_filters: Vec<&UdevFilter> = udev_filters.iter().collect(); + let filtered_devices = filter_by_remaining_udev_filters(devices.clone(), udev_filters); + + assert_eq!(filtered_devices.len(), 1); + assert_eq!( + get_sysname(&filtered_devices[0]).to_str().unwrap(), + "usb-child" + ); + + let rule = "ATTRS{someKey}!=\"value\""; + let udev_filters = parse_udev_rule(rule).unwrap(); + let udev_filters: Vec<&UdevFilter> = udev_filters.iter().collect(); + let filtered_devices = filter_by_remaining_udev_filters(devices, udev_filters); + assert_eq!(filtered_devices.len(), 1); + assert_eq!( + get_sysname(&filtered_devices[0]).to_str().unwrap(), + "pci-child" + ); + } + + #[test] + fn test_filter_by_drivers() { + let rule = "DRIVERS==\"some driver\""; + let mock_usb_grandparent = create_mock_device( + "/devices/path", + "/dev/node", + "usb1", + HashMap::new(), + HashMap::new(), + Some(OsStr::new("some driver")), + Some(OsStr::new("usb")), + None, + ); + let mock_parent = create_mock_device( + "/devices/path", + "/dev/node", + "random", + HashMap::new(), + HashMap::new(), + None, + None, + Some(mock_usb_grandparent), + ); + let mock_pci_parent = create_mock_device( + "/devices/path", + "/dev/node", + "pci1", + HashMap::new(), + HashMap::new(), + None, + Some(OsStr::new("pci")), + None, + ); + let mock_device_pci_child = create_mock_device( + "/devices/path", + "/dev/node", + "pci-child", + HashMap::new(), + HashMap::new(), + None, + Some(OsStr::new("random")), + Some(mock_pci_parent), + ); + let mock_device_usb_child = create_mock_device( + "/devices/path", + "/dev/node", + "usb-child", + HashMap::new(), + HashMap::new(), + Some(OsStr::new("driver")), + Some(OsStr::new("random")), + Some(mock_parent), + ); + let devices = vec![mock_device_pci_child, mock_device_usb_child]; + let udev_filters = parse_udev_rule(rule).unwrap(); + let udev_filters: Vec<&UdevFilter> = udev_filters.iter().collect(); + let filtered_devices = filter_by_remaining_udev_filters(devices.clone(), udev_filters); + + assert_eq!(filtered_devices.len(), 1); + assert_eq!( + get_sysname(&filtered_devices[0]).to_str().unwrap(), + "usb-child" + ); + + let rule = "DRIVERS!=\"some driver\""; + let udev_filters = parse_udev_rule(rule).unwrap(); + let udev_filters: Vec<&UdevFilter> = udev_filters.iter().collect(); + let filtered_devices = filter_by_remaining_udev_filters(devices, udev_filters); + assert_eq!(filtered_devices.len(), 1); + assert_eq!( + get_sysname(&filtered_devices[0]).to_str().unwrap(), + "pci-child" + ); + } + + #[test] + fn test_filter_by_tags() { + let rule = "TAGS==\"tag[0-9]*\""; + let mut properties = std::collections::HashMap::new(); + properties.insert("TAGS".to_string(), "tag0:middle_tag:tag".to_string()); + let mock_usb_grandparent = create_mock_device( + "/devices/path", + "/dev/node", + "usb1", + properties, + HashMap::new(), + Some(OsStr::new("some driver")), + Some(OsStr::new("usb")), + None, + ); + let mock_parent = create_mock_device( + "/devices/path", + "/dev/node", + "random", + HashMap::new(), + HashMap::new(), + None, + None, + Some(mock_usb_grandparent), + ); + let mock_pci_parent = create_mock_device( + "/devices/path", + "/dev/node", + "pci1", + HashMap::new(), + HashMap::new(), + None, + Some(OsStr::new("pci")), + None, + ); + let mock_device_pci_child = create_mock_device( + "/devices/path", + "/dev/node", + "pci-child", + HashMap::new(), + HashMap::new(), + None, + Some(OsStr::new("random")), + Some(mock_pci_parent), + ); + let mock_device_usb_child = create_mock_device( + "/devices/path", + "/dev/node", + "usb-child", + HashMap::new(), + HashMap::new(), + Some(OsStr::new("driver")), + Some(OsStr::new("random")), + Some(mock_parent), + ); + let devices = vec![mock_device_pci_child, mock_device_usb_child]; + let udev_filters = parse_udev_rule(rule).unwrap(); + let udev_filters: Vec<&UdevFilter> = udev_filters.iter().collect(); + let filtered_devices = filter_by_remaining_udev_filters(devices.clone(), udev_filters); + + assert_eq!(filtered_devices.len(), 1); + assert_eq!( + get_sysname(&filtered_devices[0]).to_str().unwrap(), + "usb-child" + ); + + let rule = "TAGS!=\"tag0\""; + let udev_filters = parse_udev_rule(rule).unwrap(); + let udev_filters: Vec<&UdevFilter> = udev_filters.iter().collect(); + let filtered_devices = filter_by_remaining_udev_filters(devices, udev_filters); + assert_eq!(filtered_devices.len(), 1); + assert_eq!( + get_sysname(&filtered_devices[0]).to_str().unwrap(), + "pci-child" + ); + } + + #[test] + fn test_filter_by_kernels() { + let rule = "KERNELS==\"usb[0-9]*\""; + let mock_usb_grandparent = create_mock_device( + "/devices/path", + "/dev/node", + "usb1", + HashMap::new(), + HashMap::new(), + None, + Some(OsStr::new("usb")), + None, + ); + let mock_parent = create_mock_device( + "/devices/path", + "/dev/node", + "random", + HashMap::new(), + HashMap::new(), + None, + None, + Some(mock_usb_grandparent), + ); + let mock_pci_parent = create_mock_device( + "/devices/path", + "/dev/node", + "pci1", + HashMap::new(), + HashMap::new(), + None, + Some(OsStr::new("pci")), + None, + ); + let mock_device_pci_child = create_mock_device( + "/devices/path", + "/dev/node", + "pci-child", + HashMap::new(), + HashMap::new(), + None, + Some(OsStr::new("random")), + Some(mock_pci_parent), + ); + let mock_device_usb_child = create_mock_device( + "/devices/path", + "/dev/node", + "usb-child", + HashMap::new(), + HashMap::new(), + Some(OsStr::new("driver")), + Some(OsStr::new("random")), + Some(mock_parent), + ); + let devices = vec![mock_device_pci_child, mock_device_usb_child]; + let udev_filters = parse_udev_rule(rule).unwrap(); + let udev_filters: Vec<&UdevFilter> = udev_filters.iter().collect(); + let filtered_devices = filter_by_remaining_udev_filters(devices.clone(), udev_filters); + + assert_eq!(filtered_devices.len(), 1); + assert_eq!( + get_sysname(&filtered_devices[0]).to_str().unwrap(), + "usb-child" + ); + + let rule = "KERNELS!=\"usb[0-9]*\""; + let udev_filters = parse_udev_rule(rule).unwrap(); + let udev_filters: Vec<&UdevFilter> = udev_filters.iter().collect(); + let filtered_devices = filter_by_remaining_udev_filters(devices, udev_filters); + assert_eq!(filtered_devices.len(), 1); + assert_eq!( + get_sysname(&filtered_devices[0]).to_str().unwrap(), + "pci-child" + ); + } + + // Only tests that proper match calls were made + #[test] + fn test_do_parse_and_find() { + let rule = "KERNEL==\"video[0-9]*\",ATTR{someKey}!=\"1000\", SUBSYSTEM==\"video4linux\""; + let mut mock = MockEnumerator::new(); + mock.expect_match_subsystem() + .times(1) + .withf(move |value: &str| value == "video4linux") + .returning(|_| Ok(())); + mock.expect_nomatch_attribute() + .times(1) + .withf(move |key: &str, value: &str| key == "someKey" && value == "1000") + .returning(|_, _| Ok(())); + mock.expect_match_sysname() + .times(1) + .withf(move |value: &str| value == "video[0-9]*") + .returning(|_| Ok(())); + mock.expect_scan_devices().times(1).returning(|| { + let mut enumerator = create_enumerator(); + enumerator + .match_attribute("random", "attribute_that_should_not_be_found") + .unwrap(); + enumerator.scan_devices() + }); + assert_eq!(do_parse_and_find(mock, rule).unwrap().len(), 0); + } + + #[test] + fn test_get_device_relatives() { + let device_path = "/devices/pci0/usb0/0-1/0-1.1"; + let children_paths = vec![ + "/devices/pci0/usb0/0-1/0-1.1/0-1.1:1.0/video4linux/video0".to_string(), + "/devices/pci0/usb0/0-1/0-1.1/0-1.1:1.0/video4linux/video1".to_string(), + "/devices/pci0/usb0/0-1/0-1.1/0-1.1:1.1".to_string(), + ]; + let unrelated_paths = vec![ + "/devices/pci0/usb0/0-1/0-1.2/0-1.2:1.1".to_string(), + "/devices/pci0/usb1/0-1/0-1.2/0-1.2:1.1".to_string(), + ]; + let parent_path = vec!["/devices/pci0/usb0".to_string()]; + let empty: Vec = Vec::new(); + + // Test with children devices + let (parent_0, childrens_0) = get_device_relatives( + device_path, + unrelated_paths.iter().chain(children_paths.iter()), + ); + assert!(parent_0.is_none()); + assert_eq!(childrens_0, children_paths); + + // Test with no possible relative devices + let (parent_1, childrens_1) = get_device_relatives(device_path, empty.iter()); + assert!(parent_1.is_none()); + assert_eq!(childrens_1, empty); + + // Test with no related devices + let (parent_2, childrens_2) = get_device_relatives(device_path, unrelated_paths.iter()); + assert!(parent_2.is_none()); + assert_eq!(childrens_2, empty); + + // Test with a parent device + let (parent_4, childrens_4) = + get_device_relatives(device_path, children_paths.iter().chain(parent_path.iter())); + assert_eq!(parent_4, Some(parent_path[0].clone())); + assert_eq!(childrens_4, empty); + } + + #[test] + fn test_insert_device_with_relatives() { + let mut devpaths: HashMap> = HashMap::default(); + let related_devices = vec![ + ("/sys/device/parent".to_string(), None), + ( + "/sys/device/parent/child1".to_string(), + Some("/dev/dev1".to_string()), + ), + ( + "/sys/device/parent/child1/child2".to_string(), + Some("/dev/dev2".to_string()), + ), + ]; + let unrelated_device = ( + "/sys/device/other".to_string(), + Some("/dev/other".to_string()), + ); + + // Add first device + insert_device_with_relatives(&mut devpaths, related_devices[1].clone()); + assert_eq!( + devpaths, + HashMap::from([( + related_devices[1].0.clone(), + HashSet::from([related_devices[1].clone()]) + )]) + ); + + // Add its child + insert_device_with_relatives(&mut devpaths, related_devices[2].clone()); + assert_eq!( + devpaths, + HashMap::from([( + related_devices[1].0.clone(), + HashSet::from([related_devices[1].clone(), related_devices[2].clone()]) + )]) + ); + + // Add its parent + insert_device_with_relatives(&mut devpaths, related_devices[0].clone()); + assert_eq!( + devpaths, + HashMap::from([( + related_devices[0].0.clone(), + HashSet::from([ + related_devices[1].clone(), + related_devices[2].clone(), + related_devices[0].clone() + ]) + )]) + ); + + // Add it again + insert_device_with_relatives(&mut devpaths, related_devices[0].clone()); + assert_eq!( + devpaths, + HashMap::from([( + related_devices[0].0.clone(), + HashSet::from([ + related_devices[1].clone(), + related_devices[2].clone(), + related_devices[0].clone() + ]) + )]) + ); + + // Add a completely unrelated device + insert_device_with_relatives(&mut devpaths, unrelated_device.clone()); + assert_eq!( + devpaths, + HashMap::from([ + ( + related_devices[0].0.clone(), + HashSet::from([ + related_devices[1].clone(), + related_devices[2].clone(), + related_devices[0].clone() + ]) + ), + ( + unrelated_device.0.clone(), + HashSet::from([unrelated_device]) + ), + ]) + ); + } +} diff --git a/crates/udev/src/lib.rs b/crates/udev/src/lib.rs new file mode 100644 index 0000000..433ca4f --- /dev/null +++ b/crates/udev/src/lib.rs @@ -0,0 +1,21 @@ +extern crate pest; +#[macro_use] +extern crate pest_derive; +extern crate udev; +#[macro_use] +extern crate serde_derive; + +pub mod discovery_handler; +mod discovery_impl; +mod wrappers; + +/// Name of environment variable that is set in udev brokers. Contains devnode for udev device +/// the broker should use. +pub const UDEV_DEVNODE_LABEL_ID: &str = "UDEV_DEVNODE"; +/// Name of environment variable that is set in udev brokers. Contains devpath for udev device +/// the broker should connect to. +pub const UDEV_DEVPATH_LABEL_ID: &str = "UDEV_DEVPATH"; +/// Name that udev discovery handlers use when registering with the Agent +pub const DISCOVERY_HANDLER_NAME: &str = "udev"; +/// Defines whether this discovery handler discovers local devices on nodes rather than ones visible to multiple nodes +pub const SHARED: bool = false; diff --git a/crates/udev/src/udev_rule_grammar.pest b/crates/udev/src/udev_rule_grammar.pest new file mode 100644 index 0000000..37f3e09 --- /dev/null +++ b/crates/udev/src/udev_rule_grammar.pest @@ -0,0 +1,66 @@ +/// Grammar for parsing udev rules +WHITESPACE = _{ " " } +// if remove *, will throw error when empty string +udev_rule = { SOI ~ (inner_rule)* ~ EOI } +inner_rule = { udev_filter ~ ("," ~ udev_filter)* } +udev_filter = ${ field ~ operation ~ quoted_value } +field = { unsupported_field | attributes | attribute | devpath | drivers | driver | kernels | kernel | property | subsystems | subsystem | tags | tag } +action_field = { label | goto | group | import | options | owner | mode | run | wait_for } +unsupported_field = { action | action_field | constant | name | program | result | seclabel | symlink | sysctl | test } +bounded_key = {"{" ~ key ~ "}"} +// remove ! on key and value rules if want to allow spaces between ""/{} and key/value (ie: { DEVPATH } vs {DEVPATH}) +key = !{ (ASCII_ALPHANUMERIC | SPACE_SEPARATOR | "$" | "." | "_" | "*" | "?" | "[" | "]" | "-" | "|" | "\\" | "/" )* } +value = !{ (ASCII_ALPHANUMERIC | SPACE_SEPARATOR | "$" | "." | "_" | "*" | ":" | "?" | "[" | "]" | "-" | "|" | "\\" | "/" | "%" | "{"| "}")* } +allowed_value_characters = { ASCII_DIGIT | ASCII_ALPHA | MARK | PUNCTUATION | SYMBOL | SPACE_SEPARATOR } +quoted_value = {"\"" ~ value ~ "\""} +operation = { equality | inequality | action_operation } +action_operation = { addition | removal | final_assignment | assignment } +equality = { "==" } +inequality = { "!=" } +assignment = { "=" } +addition = { "+=" } +removal = { "-=" } +final_assignment = { ":=" } + +// Supported fields +attributes = { "ATTRS" ~ bounded_key } +attribute = { "ATTR" ~ bounded_key } // {key} +devpath = { "DEVPATH" } +drivers = { "DRIVERS" } +driver = { "DRIVER" } +kernels = { "KERNELS" } +kernel = { "KERNEL" } +property = { "ENV" ~ bounded_key } // {key} +subsystems = { "SUBSYSTEMS" } +subsystem = { "SUBSYSTEM" } +tags = { "TAGS" } +tag = { "TAG" } + + +// +// Unsupported fields +// +// Unsupported action only fields +goto = { "GOTO" } +group = { "GROUP" } +label = { "LABEL" } +import = { "IMPORT" ~ bounded_key } // {type} where type = program | builtin | file | db | cmdline | parent +mode = { "MODE" } +options = { "OPTIONS" } +owner = { "OWNER" } +run = { "RUN" ~ bounded_key } // {type} where type = program | builtin +wait_for = { "WAIT_FOR" } + +// Other unsupported match (and action) fields +action = { "ACTION" } +constant = { "CONST" ~ bounded_key } // {key} where key = "arch" | "virt" +name = { "NAME" } +program = { "PROGRAM" } +result = { "RESULT" } +seclabel = { "SECLABEL" ~ bounded_key } // {module} +symlink = { "SYMLINK" } +sysctl = { "SYSCTL" ~ bounded_key } // {kernel key} +test = { "TEST" ~ bounded_key } // {octal mode mask} + + + diff --git a/crates/udev/src/wrappers.rs b/crates/udev/src/wrappers.rs new file mode 100644 index 0000000..ea3e450 --- /dev/null +++ b/crates/udev/src/wrappers.rs @@ -0,0 +1,146 @@ +pub mod udev_device { + extern crate udev; + use std::{ffi::OsStr, path::Path}; + + /// Extension Trait for udev::Device. Enables creation of MockDevice for testing. + pub trait DeviceExt: Sized { + fn mockable_devpath(&self) -> &OsStr; + fn mockable_devnode(&self) -> Option<&Path>; + fn mockable_sysname(&self) -> &OsStr; + fn mockable_property_value(&self, property: &str) -> Option<&OsStr>; + fn mockable_attribute_value(&self, attribute: &str) -> Option<&OsStr>; + fn mockable_driver(&self) -> Option<&OsStr>; + fn mockable_subsystem(&self) -> Option<&OsStr>; + fn mockable_parent(&self) -> Option + where + Self: Sized; + } + + impl DeviceExt for udev::Device { + fn mockable_devpath(&self) -> &OsStr { + self.devpath() + } + fn mockable_devnode(&self) -> Option<&Path> { + self.devnode() + } + fn mockable_sysname(&self) -> &OsStr { + self.sysname() + } + fn mockable_property_value(&self, property: &str) -> Option<&OsStr> { + self.property_value(property) + } + fn mockable_attribute_value(&self, attribute: &str) -> Option<&OsStr> { + self.attribute_value(attribute) + } + fn mockable_driver(&self) -> Option<&OsStr> { + self.driver() + } + fn mockable_subsystem(&self) -> Option<&OsStr> { + self.subsystem() + } + fn mockable_parent(&self) -> Option { + self.parent() + } + } + + pub fn get_devpath(device: &impl DeviceExt) -> &OsStr { + device.mockable_devpath() + } + + pub fn get_devnode(device: &impl DeviceExt) -> Option<&Path> { + device.mockable_devnode() + } + + pub fn get_sysname(device: &impl DeviceExt) -> &OsStr { + device.mockable_sysname() + } + + pub fn get_property_value<'a>(device: &'a impl DeviceExt, property: &str) -> Option<&'a OsStr> { + device.mockable_property_value(property) + } + + pub fn get_attribute_value<'a>( + device: &'a impl DeviceExt, + attribute: &str, + ) -> Option<&'a OsStr> { + device.mockable_attribute_value(attribute) + } + + pub fn get_driver(device: &impl DeviceExt) -> Option<&OsStr> { + device.mockable_driver() + } + + pub fn get_subsystem(device: &impl DeviceExt) -> Option<&OsStr> { + device.mockable_subsystem() + } + + pub fn get_parent(device: &impl DeviceExt) -> Option { + device.mockable_parent() + } +} + +pub mod udev_enumerator { + extern crate udev; + #[cfg(test)] + use mockall::{automock, predicate::*}; + + /// Wrap udev::Enumerator functions in a trait to enable mocking for testing. + #[cfg_attr(test, automock)] + pub trait Enumerator { + fn match_subsystem(&mut self, value: &str) -> std::io::Result<()>; + fn nomatch_subsystem(&mut self, value: &str) -> std::io::Result<()>; + fn match_attribute(&mut self, key: &str, value: &str) -> std::io::Result<()>; + fn nomatch_attribute(&mut self, key: &str, value: &str) -> std::io::Result<()>; + fn match_sysname(&mut self, value: &str) -> std::io::Result<()>; + fn match_property(&mut self, key: &str, value: &str) -> std::io::Result<()>; + fn match_tag(&mut self, value: &str) -> std::io::Result<()>; + fn add_syspath(&mut self, value: &str) -> std::io::Result<()>; + fn scan_devices(&mut self) -> std::io::Result; + } + + pub fn create_enumerator() -> impl Enumerator { + EnumeratorImpl::new() + } + + pub struct EnumeratorImpl { + inner_enumerator: udev::Enumerator, + } + + impl EnumeratorImpl { + fn new() -> Self { + EnumeratorImpl { + inner_enumerator: udev::Enumerator::new().unwrap(), + } + } + } + + impl Enumerator for EnumeratorImpl { + fn match_subsystem(&mut self, value: &str) -> std::io::Result<()> { + self.inner_enumerator.match_subsystem(value) + } + fn nomatch_subsystem(&mut self, value: &str) -> std::io::Result<()> { + self.inner_enumerator.nomatch_subsystem(value) + } + fn match_attribute(&mut self, key: &str, value: &str) -> std::io::Result<()> { + self.inner_enumerator.match_attribute(key, value) + } + fn nomatch_attribute(&mut self, key: &str, value: &str) -> std::io::Result<()> { + self.inner_enumerator.nomatch_attribute(key, value) + } + fn match_sysname(&mut self, value: &str) -> std::io::Result<()> { + self.inner_enumerator.match_sysname(value) + } + fn match_property(&mut self, key: &str, value: &str) -> std::io::Result<()> { + self.inner_enumerator.match_property(key, value) + } + fn match_tag(&mut self, value: &str) -> std::io::Result<()> { + self.inner_enumerator.match_tag(value) + } + fn add_syspath(&mut self, value: &str) -> std::io::Result<()> { + self.inner_enumerator.add_syspath(value) + } + fn scan_devices(&mut self) -> std::io::Result { + self.inner_enumerator.scan_devices() + } + } +} diff --git a/crates/udev/test/example-unsupported.rules b/crates/udev/test/example-unsupported.rules new file mode 100644 index 0000000..1a16c2a --- /dev/null +++ b/crates/udev/test/example-unsupported.rules @@ -0,0 +1,22 @@ +RUN{builtin}+="uaccess" +LABEL="some label" +GOTO="end" +IMPORT{program}="v4l_id $devnode" +OPTIONS="some options" +OWNER="owner" +GROUP="group" +MODE="mode" +WAIT_FOR="queue/read_q" +ACTION=="this action" +NAME=="another_disk" +SYMLINK+="v4l/by-id/$env{ID_BUS}-$env{ID_SERIAL}-video-index$attr{index}" +TEST{key}=="value +PROGRAM=="some program" +RESULT=="some result" +CONST{key}=="value" +SECLABEL{key}=="value +SYSCTL{key}=="value" +TAG-="uaccess" +TAG+="uaccess" +TAG="uaccess" +TAG:="uaccess" \ No newline at end of file diff --git a/crates/udev/test/example.rules b/crates/udev/test/example.rules new file mode 100644 index 0000000..1488817 --- /dev/null +++ b/crates/udev/test/example.rules @@ -0,0 +1,12 @@ +1 SUBSYSTEM=="video4linux" +2 KERNEL=="video*", ENV{ID_SERIAL}=="?*" +3 ENV{ID_PATH}=="?*", KERNEL=="video*|vbi*", DRIVER=="some driver" +2 TAG=="uaccess",ENV{MAJOR}!="" +2 KERNEL=="video[0-9]", DEVPATH!="/sys/path/to/device" +2 ATTR{idProduct}=="1900", ENV{ID_MM_ERICSSON_MBM}=="1" +2 ATTR{idVendor}=="0bdd", ENV{a name}=="Keyboard that has a mouse" +2 KERNEL=="video[0-9]*", ENV{ID_V4L_CAPABILITIES}==":capture:" +1 SUBSYSTEMS=="pci" +2 ATTRS{idVendor}=="0bdd", DRIVERS!="a driver" +1 TAGS=="uaccess" +1 KERNELS=="card[0-9]*" diff --git a/e2e/.gitignore b/e2e/.gitignore new file mode 100644 index 0000000..f071240 --- /dev/null +++ b/e2e/.gitignore @@ -0,0 +1,2 @@ +__pycache__ +.pytest_cache \ No newline at end of file diff --git a/e2e/conftest.py b/e2e/conftest.py new file mode 100644 index 0000000..faa74cd --- /dev/null +++ b/e2e/conftest.py @@ -0,0 +1,104 @@ +from dataclasses import dataclass +import subprocess +import pytest +import kubernetes +from pathlib import Path + +from helpers import save_akri_logs + + +def pytest_addoption(parser): + parser.addoption( + "--distribution", action="store", help="Specify distribution to use" + ) + parser.addoption("--test-version", action="store", help="version to test") + parser.addoption( + "--local-tag", action="store", default="pr", help="tag for local images" + ) + parser.addoption("--use-local", action="store_true", help="use local images if set") + parser.addoption("--release", action="store_true", help="use released helm chart") + + +@dataclass +class Distribution: + name: str + kubeconfig: Path + kubectl: str + + +@pytest.fixture(scope="session") +def distribution_config(pytestconfig): + distribution = pytestconfig.getoption("--distribution", None) + if distribution == "k3s": + yield Distribution("k3s", Path.home() / ".kube/config", "kubectl") + elif distribution == "k8s": + yield Distribution("k8s", Path.home() / ".kube/config", "kubectl") + elif distribution == "microk8s": + yield Distribution("microk8s", Path.home() / ".kube/config", "kubectl") + elif distribution is None: + pytest.exit( + "Please provide a kubernetes distribution via '--distribution' flag" + ) + else: + pytest.exit( + "Wrong distribution provided, valid values are 'k3s', 'k8s' or 'microk8s'" + ) + + +@pytest.fixture(scope="session", autouse=True) +def kube_client(distribution_config): + kubernetes.config.load_kube_config(str(distribution_config.kubeconfig)) + return kubernetes.client.ApiClient() + + +@pytest.fixture(scope="session") +def akri_version(pytestconfig): + local_version = (Path(__file__).parent / "../version.txt").read_text().strip() + version = pytestconfig.getoption("--test-version") + if version is None: + version = local_version + return version + + +@pytest.fixture(scope="module", autouse=True) +def install_akri(request, distribution_config, pytestconfig, akri_version): + discovery_handlers = getattr(request.module, "discovery_handlers", []) + + release = pytestconfig.getoption("--release", False) + subprocess.run(["helm", "repo", "update"], check=True) + helm_install_command = ["helm", "install", "akri"] + + chart_name = "akri" + helm_install_command.extend( + [ + f"akri-helm-charts/{chart_name}" + ] + ) + + for discovery_handler in discovery_handlers: + if pytestconfig.getoption("--use-local"): + local_tag = pytestconfig.getoption("--local-tag", "pr") + helm_install_command.extend( + [ + "--set", + f"{discovery_handler}.discovery.image.pullPolicy=Never," + f"{discovery_handler}.discovery.image.tag={local_tag}" + ]) + helm_install_command.extend( + [ + "--set", + f"{discovery_handler}.discovery.enabled=true", + ] + ) + helm_install_command.extend( + [ + "--set", + f"kubernetesDistro={distribution_config.name}", + "--debug", + "--atomic", + ] + ) + subprocess.run(helm_install_command, check=True) + yield + save_akri_logs(getattr(request.module, "__name__")) + subprocess.run(["helm", "delete", "akri", "--wait"]) diff --git a/e2e/helpers.py b/e2e/helpers.py new file mode 100644 index 0000000..998493c --- /dev/null +++ b/e2e/helpers.py @@ -0,0 +1,165 @@ +import time + +import kubernetes +from pathlib import Path + + +def get_pods_logs(label_selector, since=None): + v1_core = kubernetes.client.CoreV1Api() + pods = v1_core.list_namespaced_pod("default", label_selector=label_selector).items + return { + pod.metadata.name: v1_core.read_namespaced_pod_log( + pod.metadata.name, "default", since_seconds=since + ) + for pod in pods + } + + +def get_agent_logs(since=None): + return get_pods_logs("app.kubernetes.io/name=akri-agent", since=since) + + +def save_akri_logs(prefix): + directory = Path("/tmp/logs") + directory.mkdir(parents=True, exist_ok=True) + logs = get_pods_logs("app.kubernetes.io/part-of=akri") + for pod, content in logs.items(): + with open(directory / f"{prefix}-{pod}.log", "a") as f: + f.write(content) + + +def check_akri_is_healthy(handlers): + v1_core = kubernetes.client.CoreV1Api() + for component in [f"{h}-discovery" for h in handlers] + ["agent", "controller"]: + if component == "debugEcho-discovery": + component = "debug-echo-discovery" + pods = v1_core.list_namespaced_pod( + "default", + label_selector=f"app.kubernetes.io/name=akri-{component}", + field_selector="status.phase=Running", + ) + assert len(pods.items) > 0, f"{component} is not running" + + +def assert_broker_pods_running(config_name, count, timeout_seconds=400): + v1_core = kubernetes.client.CoreV1Api() + field_selector = ( + "status.phase=Running" if count > 0 else "status.phase!=Terminating" + ) + pods = v1_core.list_namespaced_pod( + "default", + label_selector=f"akri.sh/configuration={config_name}", + field_selector=field_selector, + ) + version = pods.metadata.resource_version + pods_set = {pod.metadata.name for pod in pods.items} + if len(pods_set) == count: + return + w = kubernetes.watch.Watch() + for e in w.stream( + v1_core.list_namespaced_pod, + "default", + label_selector=f"akri.sh/configuration={config_name}", + field_selector=field_selector, + resource_version=version, + timeout_seconds=timeout_seconds, + ): + if e["type"] == "DELETED": + pods_set.discard(e["object"].metadata.name) + else: + pods_set.add(e["object"].metadata.name) + if len(pods_set) == count: + w.stop() + return + raise AssertionError(f"{count} != {len(pods_set)}") + + +def assert_svc_present(config_name, instance_level, count, timeout_seconds=400): + v1_core = kubernetes.client.CoreV1Api() + label_selector = ( + "akri.sh/instance" if instance_level else f"akri.sh/configuration={config_name}" + ) + svcs = v1_core.list_namespaced_service("default", label_selector=label_selector) + version = svcs.metadata.resource_version + if instance_level: + svcs_set = { + svc.metadata.name + for svc in svcs.items + if svc.metadata.labels["akri.sh/instance"].startswith(f"{config_name}-") + } + else: + svcs_set = {svc.metadata.name for svc in svcs.items} + + if count == len(svcs_set): + return + w = kubernetes.watch.Watch() + for e in w.stream( + v1_core.list_namespaced_service, + "default", + label_selector=label_selector, + resource_version=version, + timeout_seconds=timeout_seconds, + ): + if instance_level and not e["object"].metadata.labels[ + "akri.sh/instance" + ].startswith(f"{config_name}-"): + continue + if e["type"] == "DELETED": + svcs_set.discard(e["object"].metadata.name) + else: + svcs_set.add(e["object"].metadata.name) + if len(svcs_set) == count: + w.stop() + return + raise AssertionError(f"{len(svcs_set)} != {count}") + + +def assert_akri_instances_present( + akri_version, config_name, count, timeout_seconds=400 +): + version = f'v{akri_version.split(".")[0]}' + v1_custom = kubernetes.client.CustomObjectsApi() + + def get_instances(): + instances = v1_custom.list_namespaced_custom_object( + "akri.sh", version, "default", "instances" + ) + resource_version = instances["metadata"]["resourceVersion"] + instances = { + instance["metadata"]["name"] + for instance in instances["items"] + if instance["spec"]["configurationName"] == config_name + } + return instances, resource_version + + instances, resource_version = get_instances() + if len(instances) == count: + # Check it is not a transient state + time.sleep(1) + instances, resource_version = get_instances() + if len(instances) == count: + return + w = kubernetes.watch.Watch() + for e in w.stream( + v1_custom.list_namespaced_custom_object, + "akri.sh", + version, + "default", + "instances", + timeout_seconds=timeout_seconds, + resource_version=resource_version, + ): + if e["raw_object"]["spec"]["configurationName"] != config_name: + continue + if e["type"] == "DELETED": + instances.discard(e["raw_object"]["metadata"]["name"]) + else: + instances.add(e["raw_object"]["metadata"]["name"]) + if len(instances) == count: + # Check it is not a transient state + time.sleep(1) + instances, _ = get_instances() + if len(instances) == count: + w.stop() + return + raise AssertionError(f"{count} != {len(instances)}") diff --git a/e2e/poetry.lock b/e2e/poetry.lock new file mode 100644 index 0000000..03514b9 --- /dev/null +++ b/e2e/poetry.lock @@ -0,0 +1,499 @@ +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. + +[[package]] +name = "cachetools" +version = "5.3.1" +description = "Extensible memoizing collections and decorators" +optional = false +python-versions = ">=3.7" +files = [ + {file = "cachetools-5.3.1-py3-none-any.whl", hash = "sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590"}, + {file = "cachetools-5.3.1.tar.gz", hash = "sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b"}, +] + +[[package]] +name = "certifi" +version = "2023.5.7" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, + {file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.1.0" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"}, + {file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.1.1" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"}, + {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "faker" +version = "18.10.1" +description = "Faker is a Python package that generates fake data for you." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Faker-18.10.1-py3-none-any.whl", hash = "sha256:633b278caa3ec239463f9139c74da2607c8da5710e56d5d7d30fc8a7440104c4"}, + {file = "Faker-18.10.1.tar.gz", hash = "sha256:d9f363720c4a6cf9884c6c3e26e2ce26266ffe5d741a9bc7cb9256779bc62190"}, +] + +[package.dependencies] +python-dateutil = ">=2.4" + +[[package]] +name = "google-auth" +version = "2.17.3" +description = "Google Authentication Library" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" +files = [ + {file = "google-auth-2.17.3.tar.gz", hash = "sha256:ce311e2bc58b130fddf316df57c9b3943c2a7b4f6ec31de9663a9333e4064efc"}, + {file = "google_auth-2.17.3-py2.py3-none-any.whl", hash = "sha256:f586b274d3eb7bd932ea424b1c702a30e0393a2e2bc4ca3eae8263ffd8be229f"}, +] + +[package.dependencies] +cachetools = ">=2.0.0,<6.0" +pyasn1-modules = ">=0.2.1" +rsa = {version = ">=3.1.4,<5", markers = "python_version >= \"3.6\""} +six = ">=1.9.0" + +[package.extras] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)", "requests (>=2.20.0,<3.0.0dev)"] +enterprise-cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"] +pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] +reauth = ["pyu2f (>=0.1.5)"] +requests = ["requests (>=2.20.0,<3.0.0dev)"] + +[[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "kubernetes" +version = "26.1.0" +description = "Kubernetes python client" +optional = false +python-versions = ">=3.6" +files = [ + {file = "kubernetes-26.1.0-py2.py3-none-any.whl", hash = "sha256:e3db6800abf7e36c38d2629b5cb6b74d10988ee0cba6fba45595a7cbe60c0042"}, + {file = "kubernetes-26.1.0.tar.gz", hash = "sha256:5854b0c508e8d217ca205591384ab58389abdae608576f9c9afc35a3c76a366c"}, +] + +[package.dependencies] +certifi = ">=14.05.14" +google-auth = ">=1.0.1" +python-dateutil = ">=2.5.3" +pyyaml = ">=5.4.1" +requests = "*" +requests-oauthlib = "*" +setuptools = ">=21.0.0" +six = ">=1.9.0" +urllib3 = ">=1.24.2" +websocket-client = ">=0.32.0,<0.40.0 || >0.40.0,<0.41.dev0 || >=0.43.dev0" + +[package.extras] +adal = ["adal (>=1.0.2)"] + +[[package]] +name = "oauthlib" +version = "3.2.2" +description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" +optional = false +python-versions = ">=3.6" +files = [ + {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"}, + {file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"}, +] + +[package.extras] +rsa = ["cryptography (>=3.0.0)"] +signals = ["blinker (>=1.4.0)"] +signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] + +[[package]] +name = "packaging" +version = "23.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, +] + +[[package]] +name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pyasn1" +version = "0.5.0" +description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ + {file = "pyasn1-0.5.0-py2.py3-none-any.whl", hash = "sha256:87a2121042a1ac9358cabcaf1d07680ff97ee6404333bacca15f76aa8ad01a57"}, + {file = "pyasn1-0.5.0.tar.gz", hash = "sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde"}, +] + +[[package]] +name = "pyasn1-modules" +version = "0.3.0" +description = "A collection of ASN.1-based protocols modules" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ + {file = "pyasn1_modules-0.3.0-py2.py3-none-any.whl", hash = "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"}, + {file = "pyasn1_modules-0.3.0.tar.gz", hash = "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c"}, +] + +[package.dependencies] +pyasn1 = ">=0.4.6,<0.6.0" + +[[package]] +name = "pytest" +version = "7.3.1" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, + {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pyyaml" +version = "6.0" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, + {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, + {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, + {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "requests-oauthlib" +version = "1.3.1" +description = "OAuthlib authentication support for Requests." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "requests-oauthlib-1.3.1.tar.gz", hash = "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a"}, + {file = "requests_oauthlib-1.3.1-py2.py3-none-any.whl", hash = "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5"}, +] + +[package.dependencies] +oauthlib = ">=3.0.0" +requests = ">=2.0.0" + +[package.extras] +rsa = ["oauthlib[signedtoken] (>=3.0.0)"] + +[[package]] +name = "rsa" +version = "4.9" +description = "Pure-Python RSA implementation" +optional = false +python-versions = ">=3.6,<4" +files = [ + {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, + {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, +] + +[package.dependencies] +pyasn1 = ">=0.1.3" + +[[package]] +name = "setuptools" +version = "67.8.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, + {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "urllib3" +version = "2.0.3" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.7" +files = [ + {file = "urllib3-2.0.3-py3-none-any.whl", hash = "sha256:48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1"}, + {file = "urllib3-2.0.3.tar.gz", hash = "sha256:bee28b5e56addb8226c96f7f13ac28cb4c301dd5ea8a6ca179c0b9835e032825"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "websocket-client" +version = "1.5.2" +description = "WebSocket client for Python with low level API options" +optional = false +python-versions = ">=3.7" +files = [ + {file = "websocket-client-1.5.2.tar.gz", hash = "sha256:c7d67c13b928645f259d9b847ab5b57fd2d127213ca41ebd880de1f553b7c23b"}, + {file = "websocket_client-1.5.2-py3-none-any.whl", hash = "sha256:f8c64e28cd700e7ba1f04350d66422b6833b82a796b525a51e740b8cc8dab4b1"}, +] + +[package.extras] +docs = ["Sphinx (>=3.4)", "sphinx-rtd-theme (>=0.5)"] +optional = ["python-socks", "wsaccel"] +test = ["websockets"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.10" +content-hash = "d82f67b975ee77ff34728b6829aa4231627424598842d7c18e9b804246d9da75" diff --git a/e2e/pyproject.toml b/e2e/pyproject.toml new file mode 100644 index 0000000..e0fc3a1 --- /dev/null +++ b/e2e/pyproject.toml @@ -0,0 +1,20 @@ +[tool.poetry] +name = "akri-e2e" +version = "0.10.10" +description = "Akri end to end test framework" +authors = ["Nicolas Belouin "] +license = "Apache 2.0" +readme = "README.md" +packages = [{include = "akri_e2e"}] + +[tool.poetry.dependencies] +python = "^3.10" +pytest = "^7.3.1" +kubernetes = "^26.1.0" +pyyaml = "^6.0" +faker = "^18.10.1" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/e2e/test_udev.py b/e2e/test_udev.py new file mode 100644 index 0000000..1e9a900 --- /dev/null +++ b/e2e/test_udev.py @@ -0,0 +1,86 @@ +from pathlib import Path +import time + +import yaml +import pytest +import kubernetes +from helpers import assert_akri_instances_present, check_akri_is_healthy + + +discovery_handlers = ["udev"] + + +@pytest.fixture +def dev_null_config(akri_version): + with open(Path(__file__).parent / "yaml/udevDevNullConfiguration.yaml") as f: + body = yaml.safe_load(f) + client = kubernetes.client.CustomObjectsApi() + version = f'v{akri_version.split(".")[0]}' + client.create_namespaced_custom_object( + "akri.sh", version, "default", "configurations", body + ) + + yield body["metadata"]["name"] + + client.delete_namespaced_custom_object( + "akri.sh", version, "default", "configurations", body["metadata"]["name"] + ) + + +def test_dev_null_config(akri_version, dev_null_config): + check_akri_is_healthy(discovery_handlers) + assert_akri_instances_present(akri_version, dev_null_config, 1) + + +@pytest.fixture +def grouped_config(akri_version): + v1_core = kubernetes.client.CoreV1Api() + pods = v1_core.list_namespaced_pod( + "default", + label_selector=f"app.kubernetes.io/name=akri-udev-discovery", + field_selector="status.phase=Running", + ).items + base_command = ["/bin/sh", "-c"] + # This command will get the ID_PATH to use to get a device with many "subdevices" + command = "grep -hr ID_PATH= /run/udev/data | sort | uniq -cd | sort -n | tail -1 | cut -d '=' -f 2" + paths = set() + # Get the ID_PATH we can use + for pod in pods: + resp = kubernetes.stream.stream( + v1_core.connect_get_namespaced_pod_exec, + pod.metadata.name, + "default", + command=base_command + [command], + stdout=True, + stdin=False, + stderr=True, + tty=False, + _preload_content=False, + ) + try: + paths.add(resp.readline_stdout(timeout=3).strip()) + except: + pytest.skip(f"No udev ?") + if len(paths) == 0: + pytest.skip("No groupable devices found") + path = paths.pop() + + with open(Path(__file__).parent / "yaml/udevGroupedConfiguration.yaml") as f: + body = yaml.safe_load(f) + body["spec"]["discoveryHandler"]["discoveryDetails"] = body["spec"][ + "discoveryHandler" + ]["discoveryDetails"].format(path) + client = kubernetes.client.CustomObjectsApi() + version = f'v{akri_version.split(".")[0]}' + client.create_namespaced_custom_object( + "akri.sh", version, "default", "configurations", body + ) + yield body["metadata"]["name"] + client.delete_namespaced_custom_object( + "akri.sh", version, "default", "configurations", body["metadata"]["name"] + ) + + +def test_grouped_config(akri_version, grouped_config): + check_akri_is_healthy(discovery_handlers) + assert_akri_instances_present(akri_version, grouped_config, 1) diff --git a/e2e/yaml/udevDevNullConfiguration.yaml b/e2e/yaml/udevDevNullConfiguration.yaml new file mode 100644 index 0000000..bda7fba --- /dev/null +++ b/e2e/yaml/udevDevNullConfiguration.yaml @@ -0,0 +1,10 @@ +apiVersion: akri.sh/v0 +kind: Configuration +metadata: + name: akri-udev-dev-null +spec: + discoveryHandler: + name: udev + discoveryDetails: |+ + udevRules: + - KERNEL=="null" \ No newline at end of file diff --git a/e2e/yaml/udevGroupedConfiguration.yaml b/e2e/yaml/udevGroupedConfiguration.yaml new file mode 100644 index 0000000..1c218d9 --- /dev/null +++ b/e2e/yaml/udevGroupedConfiguration.yaml @@ -0,0 +1,11 @@ +apiVersion: akri.sh/v0 +kind: Configuration +metadata: + name: akri-udev-grouped +spec: + discoveryHandler: + name: udev + discoveryDetails: |+ + groupRecursive: true + udevRules: + - ENV{{ID_PATH}}=="{}" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ccd4b9a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,22 @@ +use akri_discovery_utils::discovery::discovery_handler::{ + run_discovery_handler, REGISTER_AGAIN_CHANNEL_CAPACITY, +}; +use akri_udev::{discovery_handler::DiscoveryHandlerImpl, DISCOVERY_HANDLER_NAME, SHARED}; +use log::info; +#[tokio::main] +async fn main() -> Result<(), Box> { + env_logger::try_init()?; + info!("main - udev discovery handler started"); + let (register_sender, register_receiver) = + tokio::sync::mpsc::channel(REGISTER_AGAIN_CHANNEL_CAPACITY); + let discovery_handler = DiscoveryHandlerImpl::new(Some(register_sender)); + run_discovery_handler( + discovery_handler, + register_receiver, + DISCOVERY_HANDLER_NAME, + SHARED, + ) + .await?; + info!("main - udev discovery handler ended"); + Ok(()) +} diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..1592299 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +0.12.16 \ No newline at end of file