├── .dockerignore ├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── automerge.yml │ ├── ci.yml │ └── rustfmt.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── README.md ├── Tiltfile ├── charts └── doc-controller │ ├── .helmignore │ ├── Chart.yaml │ ├── templates │ ├── _helpers.tpl │ ├── deployment.yaml │ ├── networkpolicy.yaml │ ├── rbac.yaml │ ├── service.yaml │ └── servicemonitor.yaml │ ├── test.yaml │ └── values.yaml ├── docker-compose.yaml ├── justfile ├── release.toml ├── rustfmt.toml ├── src ├── controller.rs ├── crdgen.rs ├── fixtures.rs ├── lib.rs ├── main.rs ├── metrics.rs └── telemetry.rs └── yaml ├── crd.yaml ├── deployment.yaml ├── instance-illegal.yaml ├── instance-lorem.yaml └── instance-samuel.yaml /.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | Cargo.lock linguist-generated 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | labels: 8 | - "dependencies" 9 | groups: 10 | artifact-io: 11 | patterns: 12 | - actions/upload-artifact 13 | - actions/download-artifact 14 | 15 | - package-ecosystem: "cargo" 16 | directory: "/" 17 | labels: 18 | - "dependencies" 19 | schedule: 20 | interval: "weekly" 21 | groups: 22 | kube: 23 | patterns: 24 | - kube 25 | - k8s-openapi 26 | otel: 27 | patterns: 28 | - tracing-opentelemetry 29 | - opentelemetry-otlp 30 | - opentelemetry_sdk 31 | - opentelemetry 32 | - tonic 33 | -------------------------------------------------------------------------------- /.github/workflows/automerge.yml: -------------------------------------------------------------------------------- 1 | name: Automerge 2 | on: pull_request 3 | 4 | permissions: 5 | contents: write 6 | pull-requests: write 7 | 8 | jobs: 9 | automerge: 10 | runs-on: ubuntu-latest 11 | if: ${{ github.actor == 'sszynrae' || github.actor == 'dependabot[bot]' }} 12 | steps: 13 | - name: Dependabot metadata 14 | id: metadata 15 | uses: dependabot/fetch-metadata@v2 16 | if: ${{ github.actor == 'dependabot[bot]' }} 17 | with: 18 | github-token: "${{ secrets.GITHUB_TOKEN }}" 19 | - name: Approve a PR 20 | run: gh pr review --approve "$PR_URL" 21 | env: 22 | PR_URL: ${{github.event.pull_request.html_url}} 23 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 24 | - name: Enable auto-merge for Dependency/Renovate PRs 25 | run: gh pr merge --auto --squash "$PR_URL" 26 | env: 27 | PR_URL: ${{github.event.pull_request.html_url}} 28 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 29 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | tags: 9 | - '*' 10 | 11 | permissions: 12 | contents: read 13 | packages: write 14 | 15 | jobs: 16 | docker-base: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | # Build and push with docker buildx 22 | - name: Setup docker buildx 23 | uses: docker/setup-buildx-action@v3 24 | 25 | - name: Configure tags based on git tags + latest 26 | uses: docker/metadata-action@v5 27 | id: meta 28 | with: 29 | images: ghcr.io/${{ github.repository_owner }}/controller 30 | tags: | 31 | type=pep440,pattern={{version}} 32 | type=raw,value=latest,enable={{is_default_branch}} 33 | type=ref,event=pr 34 | type=raw,value=test,enable=${{ !endsWith(github.ref, '/main')}} 35 | 36 | - name: Docker login on main origin 37 | uses: docker/login-action@v3 38 | if: github.event_name != 'pull_request' 39 | with: 40 | registry: ghcr.io 41 | username: ${{ github.repository_owner }} 42 | password: ${{ secrets.GITHUB_TOKEN }} 43 | 44 | - uses: actions/cache@v4 45 | with: 46 | path: | 47 | ~/.cargo/registry/index/ 48 | ~/.cargo/registry/cache/ 49 | ~/.cargo/git/db/ 50 | target/ 51 | key: musl-cargo-${{ hashFiles('**/Cargo.lock') }} 52 | 53 | - name: Compile base features 54 | run: | 55 | mkdir -p ~/.cargo/{git,registry} 56 | docker run --rm -t \ 57 | --mount type=bind,source=${{ github.workspace }},target=/volume \ 58 | --mount type=bind,source=$HOME/.cargo/registry,target=/root/.cargo/registry \ 59 | --mount type=bind,source=$HOME/.cargo/git,target=/root/.cargo/git \ 60 | clux/muslrust:stable \ 61 | cargo build --release --bin controller 62 | cp target/x86_64-unknown-linux-musl/release/controller . 63 | 64 | - name: Docker buildx and push with base features 65 | uses: docker/build-push-action@v6 66 | with: 67 | context: . 68 | cache-from: type=gha,scope=base 69 | cache-to: type=gha,scope=base,mode=max 70 | push: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags') }} 71 | tags: ${{ steps.meta.outputs.tags }} 72 | labels: ${{ steps.meta.outputs.labels }} 73 | platforms: linux/amd64 74 | 75 | - name: Persist base image build to a tarball 76 | uses: docker/build-push-action@v6 77 | with: 78 | context: . 79 | platforms: linux/amd64 80 | tags: ${{ steps.meta.outputs.tags }} 81 | cache-from: type=gha,scope=base 82 | outputs: type=docker,dest=/tmp/image.tar 83 | 84 | - name: Upload base docker image as artifact for e2e tests 85 | uses: actions/upload-artifact@v4 86 | with: 87 | name: controller-image 88 | path: /tmp/image.tar 89 | 90 | docker-otel: 91 | runs-on: ubuntu-latest 92 | steps: 93 | - uses: actions/checkout@v4 94 | 95 | # Build and push with docker buildx 96 | - name: Setup docker buildx 97 | uses: docker/setup-buildx-action@v3 98 | 99 | - name: Configure tags based on git tags for otel 100 | uses: docker/metadata-action@v5 101 | id: meta 102 | with: 103 | images: ghcr.io/${{ github.repository_owner }}/controller 104 | tags: | 105 | type=pep440,pattern={{version}},prefix=otel- 106 | type=raw,value=otel,enable={{is_default_branch}} 107 | type=ref,event=pr,prefix=otel- 108 | 109 | - uses: actions/cache@v4 110 | with: 111 | path: | 112 | ~/.cargo/registry/index/ 113 | ~/.cargo/registry/cache/ 114 | ~/.cargo/git/db/ 115 | target/ 116 | key: musl-cargo-otel-${{ hashFiles('**/Cargo.lock') }} 117 | 118 | - name: Compile with telemetry 119 | run: | 120 | mkdir -p ~/.cargo/{git,registry} 121 | docker run --rm -t \ 122 | --mount type=bind,source=${{ github.workspace }},target=/volume \ 123 | --mount type=bind,source=$HOME/.cargo/registry,target=/root/.cargo/registry \ 124 | --mount type=bind,source=$HOME/.cargo/git,target=/root/.cargo/git \ 125 | clux/muslrust:stable \ 126 | cargo build --features=telemetry --release --bin controller 127 | cp target/x86_64-unknown-linux-musl/release/controller . 128 | 129 | - name: Docker login on main origin 130 | uses: docker/login-action@v3 131 | if: github.event_name != 'pull_request' 132 | with: 133 | registry: ghcr.io 134 | username: ${{ github.repository_owner }} 135 | password: ${{ secrets.GITHUB_TOKEN }} 136 | 137 | - name: Docker buildx and push with telemetry 138 | uses: docker/build-push-action@v6 139 | with: 140 | context: . 141 | cache-from: type=gha,scope=otel 142 | cache-to: type=gha,scope=otel,mode=max 143 | push: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags') }} 144 | tags: ${{ steps.meta.outputs.tags }} 145 | labels: ${{ steps.meta.outputs.labels }} 146 | platforms: linux/amd64 147 | 148 | e2e: 149 | runs-on: ubuntu-latest 150 | needs: [docker-base] 151 | # No need to e2e on main, we know it worked at the branch level 152 | # (also the e2e test assumes tag :test which is not available elsewhere) 153 | if: github.ref != 'refs/heads/main' 154 | steps: 155 | - uses: actions/checkout@v4 156 | - uses: nolar/setup-k3d-k3s@v1 157 | with: 158 | version: v1.31 159 | k3d-name: kube 160 | k3d-args: "--no-lb --no-rollback --registry-create reg --k3s-arg --disable=traefik,servicelb,metrics-server@server:*" 161 | - run: kubectl apply -f yaml/crd.yaml 162 | - name: Set up Docker Buildx 163 | uses: docker/setup-buildx-action@v3 164 | - name: Download docker image artifact from docker job 165 | uses: actions/download-artifact@v4 166 | with: 167 | name: controller-image 168 | path: /tmp 169 | - name: Load image into k3d registry 170 | run: k3d image import /tmp/image.tar --cluster kube 171 | - name: helm template | kubctl apply 172 | run: | 173 | apiserver="$(kubectl get endpoints kubernetes -ojson | jq '.subsets[0].addresses[0].ip' -r)" 174 | helm template charts/doc-controller \ 175 | --set version=test \ 176 | --set networkPolicy.enabled=true \ 177 | --set networkPolicy.apiserver.0=${apiserver}/32 \ 178 | | kubectl apply -f - 179 | - run: kubectl wait --for=condition=available deploy/doc-controller --timeout=30s 180 | - run: kubectl apply -f yaml/instance-samuel.yaml 181 | - run: sleep 2 # TODO: add condition on status and wait for it instead 182 | # verify reconcile actions have happened 183 | - run: kubectl get netpol doc-controller -oyaml 184 | - run: kubectl logs deploy/doc-controller 185 | - run: kubectl get event --field-selector "involvedObject.kind=Document,involvedObject.name=samuel" | grep "HideRequested" 186 | - run: kubectl get doc -oyaml | grep -A1 finalizers | grep documents.kube.rs 187 | 188 | lint: 189 | runs-on: ubuntu-latest 190 | steps: 191 | - uses: actions/checkout@v4 192 | - name: Install protoc 193 | run: sudo apt-get install -y protobuf-compiler 194 | - uses: dtolnay/rust-toolchain@stable 195 | with: 196 | toolchain: nightly 197 | components: rustfmt,clippy 198 | - run: cargo +nightly fmt -- --check 199 | 200 | - uses: giraffate/clippy-action@v1 201 | with: 202 | reporter: 'github-pr-review' 203 | github_token: ${{ secrets.GITHUB_TOKEN }} 204 | clippy_flags: --all-features 205 | 206 | integration: 207 | runs-on: ubuntu-latest 208 | steps: 209 | - uses: actions/checkout@v4 210 | - uses: dtolnay/rust-toolchain@stable 211 | - uses: Swatinem/rust-cache@v2 212 | - uses: nolar/setup-k3d-k3s@v1 213 | with: 214 | version: v1.31 215 | k3d-name: kube 216 | k3d-args: "--no-lb --no-rollback --k3s-arg --disable=traefik,servicelb,metrics-server@server:*" 217 | 218 | - name: Build workspace 219 | run: cargo build 220 | - name: Install crd 221 | run: cargo run --bin crdgen | kubectl apply -f - 222 | - name: Run all default features integration library tests 223 | run: cargo test --lib --all -- --ignored 224 | 225 | unit: 226 | runs-on: ubuntu-latest 227 | steps: 228 | - uses: actions/checkout@v4 229 | with: 230 | fetch-depth: 2 231 | - uses: dtolnay/rust-toolchain@stable 232 | - uses: Swatinem/rust-cache@v2 233 | 234 | # Real CI work starts here 235 | - name: Build workspace 236 | run: cargo build 237 | - name: Run workspace unit tests 238 | run: cargo test 239 | - name: Generate crd.yaml 240 | run: cargo run --bin crdgen > yaml/crd.yaml 241 | - name: Generate deployment.yaml 242 | run: helm template charts/doc-controller > yaml/deployment.yaml 243 | - name: Ensure generated output is committed 244 | run: | 245 | if ! git diff --exit-code yaml/; then 246 | echo "Uncommitted changes in yaml directory" 247 | echo "Please run 'just generate' and commit the results" 248 | exit 1 249 | fi 250 | -------------------------------------------------------------------------------- /.github/workflows/rustfmt.yml: -------------------------------------------------------------------------------- 1 | # When pushed to master, run `cargo +nightly fmt --all` and open a PR. 2 | name: rustfmt 3 | on: 4 | push: 5 | # Limit to `master` because this action creates a PR 6 | branches: 7 | - master 8 | jobs: 9 | rustfmt_nightly: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout sources 13 | uses: actions/checkout@v4 14 | - uses: dtolnay/rust-toolchain@stable 15 | with: 16 | toolchain: nightly 17 | components: rustfmt 18 | - run: cargo +nightly fmt 19 | 20 | - name: Create Pull Request 21 | uses: peter-evans/create-pull-request@v7 22 | with: 23 | commit-message: rustfmt 24 | signoff: true 25 | title: rustfmt 26 | body: Changes from `cargo +nightly fmt`. 27 | branch: rustfmt 28 | # Delete branch when merged 29 | delete-branch: true 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | controller 4 | audit 5 | audit.yaml 6 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "actix-codec" 7 | version = "0.5.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" 10 | dependencies = [ 11 | "bitflags", 12 | "bytes", 13 | "futures-core", 14 | "futures-sink", 15 | "memchr", 16 | "pin-project-lite", 17 | "tokio", 18 | "tokio-util", 19 | "tracing", 20 | ] 21 | 22 | [[package]] 23 | name = "actix-http" 24 | version = "3.11.0" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | checksum = "44dfe5c9e0004c623edc65391dfd51daa201e7e30ebd9c9bedf873048ec32bc2" 27 | dependencies = [ 28 | "actix-codec", 29 | "actix-rt", 30 | "actix-service", 31 | "actix-utils", 32 | "base64 0.22.1", 33 | "bitflags", 34 | "brotli", 35 | "bytes", 36 | "bytestring", 37 | "derive_more", 38 | "encoding_rs", 39 | "flate2", 40 | "foldhash", 41 | "futures-core", 42 | "h2 0.3.26", 43 | "http 0.2.12", 44 | "httparse", 45 | "httpdate", 46 | "itoa", 47 | "language-tags", 48 | "local-channel", 49 | "mime", 50 | "percent-encoding", 51 | "pin-project-lite", 52 | "rand 0.9.0", 53 | "sha1", 54 | "smallvec", 55 | "tokio", 56 | "tokio-util", 57 | "tracing", 58 | "zstd", 59 | ] 60 | 61 | [[package]] 62 | name = "actix-macros" 63 | version = "0.2.4" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" 66 | dependencies = [ 67 | "quote", 68 | "syn", 69 | ] 70 | 71 | [[package]] 72 | name = "actix-router" 73 | version = "0.5.3" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" 76 | dependencies = [ 77 | "bytestring", 78 | "cfg-if", 79 | "http 0.2.12", 80 | "regex", 81 | "regex-lite", 82 | "serde", 83 | "tracing", 84 | ] 85 | 86 | [[package]] 87 | name = "actix-rt" 88 | version = "2.10.0" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208" 91 | dependencies = [ 92 | "futures-core", 93 | "tokio", 94 | ] 95 | 96 | [[package]] 97 | name = "actix-server" 98 | version = "2.6.0" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "a65064ea4a457eaf07f2fba30b4c695bf43b721790e9530d26cb6f9019ff7502" 101 | dependencies = [ 102 | "actix-rt", 103 | "actix-service", 104 | "actix-utils", 105 | "futures-core", 106 | "futures-util", 107 | "mio", 108 | "socket2", 109 | "tokio", 110 | "tracing", 111 | ] 112 | 113 | [[package]] 114 | name = "actix-service" 115 | version = "2.0.2" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" 118 | dependencies = [ 119 | "futures-core", 120 | "paste", 121 | "pin-project-lite", 122 | ] 123 | 124 | [[package]] 125 | name = "actix-utils" 126 | version = "3.0.1" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" 129 | dependencies = [ 130 | "local-waker", 131 | "pin-project-lite", 132 | ] 133 | 134 | [[package]] 135 | name = "actix-web" 136 | version = "4.11.0" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "a597b77b5c6d6a1e1097fddde329a83665e25c5437c696a3a9a4aa514a614dea" 139 | dependencies = [ 140 | "actix-codec", 141 | "actix-http", 142 | "actix-macros", 143 | "actix-router", 144 | "actix-rt", 145 | "actix-server", 146 | "actix-service", 147 | "actix-utils", 148 | "actix-web-codegen", 149 | "bytes", 150 | "bytestring", 151 | "cfg-if", 152 | "cookie", 153 | "derive_more", 154 | "encoding_rs", 155 | "foldhash", 156 | "futures-core", 157 | "futures-util", 158 | "impl-more", 159 | "itoa", 160 | "language-tags", 161 | "log", 162 | "mime", 163 | "once_cell", 164 | "pin-project-lite", 165 | "regex", 166 | "regex-lite", 167 | "serde", 168 | "serde_json", 169 | "serde_urlencoded", 170 | "smallvec", 171 | "socket2", 172 | "time", 173 | "tracing", 174 | "url", 175 | ] 176 | 177 | [[package]] 178 | name = "actix-web-codegen" 179 | version = "4.3.0" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "f591380e2e68490b5dfaf1dd1aa0ebe78d84ba7067078512b4ea6e4492d622b8" 182 | dependencies = [ 183 | "actix-router", 184 | "proc-macro2", 185 | "quote", 186 | "syn", 187 | ] 188 | 189 | [[package]] 190 | name = "addr2line" 191 | version = "0.24.2" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 194 | dependencies = [ 195 | "gimli", 196 | ] 197 | 198 | [[package]] 199 | name = "adler2" 200 | version = "2.0.0" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 203 | 204 | [[package]] 205 | name = "ahash" 206 | version = "0.8.11" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 209 | dependencies = [ 210 | "cfg-if", 211 | "getrandom 0.2.15", 212 | "once_cell", 213 | "version_check", 214 | "zerocopy 0.7.35", 215 | ] 216 | 217 | [[package]] 218 | name = "aho-corasick" 219 | version = "1.1.3" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 222 | dependencies = [ 223 | "memchr", 224 | ] 225 | 226 | [[package]] 227 | name = "alloc-no-stdlib" 228 | version = "2.0.4" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" 231 | 232 | [[package]] 233 | name = "alloc-stdlib" 234 | version = "0.2.2" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" 237 | dependencies = [ 238 | "alloc-no-stdlib", 239 | ] 240 | 241 | [[package]] 242 | name = "allocator-api2" 243 | version = "0.2.21" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" 246 | 247 | [[package]] 248 | name = "android-tzdata" 249 | version = "0.1.1" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 252 | 253 | [[package]] 254 | name = "android_system_properties" 255 | version = "0.1.5" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 258 | dependencies = [ 259 | "libc", 260 | ] 261 | 262 | [[package]] 263 | name = "anyhow" 264 | version = "1.0.98" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" 267 | 268 | [[package]] 269 | name = "assert-json-diff" 270 | version = "2.0.2" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" 273 | dependencies = [ 274 | "serde", 275 | "serde_json", 276 | ] 277 | 278 | [[package]] 279 | name = "async-broadcast" 280 | version = "0.7.1" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e" 283 | dependencies = [ 284 | "event-listener", 285 | "event-listener-strategy", 286 | "futures-core", 287 | "pin-project-lite", 288 | ] 289 | 290 | [[package]] 291 | name = "async-stream" 292 | version = "0.3.6" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" 295 | dependencies = [ 296 | "async-stream-impl", 297 | "futures-core", 298 | "pin-project-lite", 299 | ] 300 | 301 | [[package]] 302 | name = "async-stream-impl" 303 | version = "0.3.6" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" 306 | dependencies = [ 307 | "proc-macro2", 308 | "quote", 309 | "syn", 310 | ] 311 | 312 | [[package]] 313 | name = "async-trait" 314 | version = "0.1.83" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" 317 | dependencies = [ 318 | "proc-macro2", 319 | "quote", 320 | "syn", 321 | ] 322 | 323 | [[package]] 324 | name = "atomic-waker" 325 | version = "1.1.2" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 328 | 329 | [[package]] 330 | name = "autocfg" 331 | version = "1.4.0" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 334 | 335 | [[package]] 336 | name = "axum" 337 | version = "0.7.9" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" 340 | dependencies = [ 341 | "async-trait", 342 | "axum-core", 343 | "bytes", 344 | "futures-util", 345 | "http 1.3.1", 346 | "http-body", 347 | "http-body-util", 348 | "itoa", 349 | "matchit", 350 | "memchr", 351 | "mime", 352 | "percent-encoding", 353 | "pin-project-lite", 354 | "rustversion", 355 | "serde", 356 | "sync_wrapper 1.0.2", 357 | "tower 0.5.1", 358 | "tower-layer", 359 | "tower-service", 360 | ] 361 | 362 | [[package]] 363 | name = "axum-core" 364 | version = "0.4.5" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" 367 | dependencies = [ 368 | "async-trait", 369 | "bytes", 370 | "futures-util", 371 | "http 1.3.1", 372 | "http-body", 373 | "http-body-util", 374 | "mime", 375 | "pin-project-lite", 376 | "rustversion", 377 | "sync_wrapper 1.0.2", 378 | "tower-layer", 379 | "tower-service", 380 | ] 381 | 382 | [[package]] 383 | name = "backon" 384 | version = "1.4.0" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "49fef586913a57ff189f25c9b3d034356a5bf6b3fa9a7f067588fe1698ba1f5d" 387 | dependencies = [ 388 | "fastrand", 389 | "gloo-timers", 390 | "tokio", 391 | ] 392 | 393 | [[package]] 394 | name = "backtrace" 395 | version = "0.3.74" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 398 | dependencies = [ 399 | "addr2line", 400 | "cfg-if", 401 | "libc", 402 | "miniz_oxide", 403 | "object", 404 | "rustc-demangle", 405 | "windows-targets", 406 | ] 407 | 408 | [[package]] 409 | name = "base64" 410 | version = "0.21.7" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 413 | 414 | [[package]] 415 | name = "base64" 416 | version = "0.22.1" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 419 | 420 | [[package]] 421 | name = "bitflags" 422 | version = "2.7.0" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" 425 | 426 | [[package]] 427 | name = "block-buffer" 428 | version = "0.10.4" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 431 | dependencies = [ 432 | "generic-array", 433 | ] 434 | 435 | [[package]] 436 | name = "brotli" 437 | version = "8.0.1" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" 440 | dependencies = [ 441 | "alloc-no-stdlib", 442 | "alloc-stdlib", 443 | "brotli-decompressor", 444 | ] 445 | 446 | [[package]] 447 | name = "brotli-decompressor" 448 | version = "5.0.0" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" 451 | dependencies = [ 452 | "alloc-no-stdlib", 453 | "alloc-stdlib", 454 | ] 455 | 456 | [[package]] 457 | name = "bumpalo" 458 | version = "3.16.0" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 461 | 462 | [[package]] 463 | name = "byteorder" 464 | version = "1.5.0" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 467 | 468 | [[package]] 469 | name = "bytes" 470 | version = "1.9.0" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" 473 | 474 | [[package]] 475 | name = "bytestring" 476 | version = "1.4.0" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f" 479 | dependencies = [ 480 | "bytes", 481 | ] 482 | 483 | [[package]] 484 | name = "cc" 485 | version = "1.2.2" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" 488 | dependencies = [ 489 | "jobserver", 490 | "libc", 491 | "shlex", 492 | ] 493 | 494 | [[package]] 495 | name = "cfg-if" 496 | version = "1.0.0" 497 | source = "registry+https://github.com/rust-lang/crates.io-index" 498 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 499 | 500 | [[package]] 501 | name = "chrono" 502 | version = "0.4.41" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" 505 | dependencies = [ 506 | "android-tzdata", 507 | "iana-time-zone", 508 | "js-sys", 509 | "num-traits", 510 | "serde", 511 | "wasm-bindgen", 512 | "windows-link", 513 | ] 514 | 515 | [[package]] 516 | name = "concurrent-queue" 517 | version = "2.5.0" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" 520 | dependencies = [ 521 | "crossbeam-utils", 522 | ] 523 | 524 | [[package]] 525 | name = "controller" 526 | version = "0.16.0" 527 | dependencies = [ 528 | "actix-web", 529 | "anyhow", 530 | "assert-json-diff", 531 | "chrono", 532 | "futures", 533 | "http 1.3.1", 534 | "hyper", 535 | "k8s-openapi", 536 | "kube", 537 | "opentelemetry", 538 | "opentelemetry-otlp", 539 | "opentelemetry_sdk", 540 | "prometheus-client", 541 | "schemars", 542 | "serde", 543 | "serde_json", 544 | "serde_yaml", 545 | "thiserror 2.0.12", 546 | "tokio", 547 | "tower-test", 548 | "tracing", 549 | "tracing-opentelemetry", 550 | "tracing-subscriber", 551 | ] 552 | 553 | [[package]] 554 | name = "cookie" 555 | version = "0.16.2" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" 558 | dependencies = [ 559 | "percent-encoding", 560 | "time", 561 | "version_check", 562 | ] 563 | 564 | [[package]] 565 | name = "core-foundation" 566 | version = "0.9.4" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 569 | dependencies = [ 570 | "core-foundation-sys", 571 | "libc", 572 | ] 573 | 574 | [[package]] 575 | name = "core-foundation" 576 | version = "0.10.0" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" 579 | dependencies = [ 580 | "core-foundation-sys", 581 | "libc", 582 | ] 583 | 584 | [[package]] 585 | name = "core-foundation-sys" 586 | version = "0.8.7" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 589 | 590 | [[package]] 591 | name = "cpufeatures" 592 | version = "0.2.16" 593 | source = "registry+https://github.com/rust-lang/crates.io-index" 594 | checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" 595 | dependencies = [ 596 | "libc", 597 | ] 598 | 599 | [[package]] 600 | name = "crc32fast" 601 | version = "1.4.2" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 604 | dependencies = [ 605 | "cfg-if", 606 | ] 607 | 608 | [[package]] 609 | name = "crossbeam-utils" 610 | version = "0.8.20" 611 | source = "registry+https://github.com/rust-lang/crates.io-index" 612 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 613 | 614 | [[package]] 615 | name = "crypto-common" 616 | version = "0.1.6" 617 | source = "registry+https://github.com/rust-lang/crates.io-index" 618 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 619 | dependencies = [ 620 | "generic-array", 621 | "typenum", 622 | ] 623 | 624 | [[package]] 625 | name = "darling" 626 | version = "0.20.10" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" 629 | dependencies = [ 630 | "darling_core", 631 | "darling_macro", 632 | ] 633 | 634 | [[package]] 635 | name = "darling_core" 636 | version = "0.20.10" 637 | source = "registry+https://github.com/rust-lang/crates.io-index" 638 | checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" 639 | dependencies = [ 640 | "fnv", 641 | "ident_case", 642 | "proc-macro2", 643 | "quote", 644 | "strsim", 645 | "syn", 646 | ] 647 | 648 | [[package]] 649 | name = "darling_macro" 650 | version = "0.20.10" 651 | source = "registry+https://github.com/rust-lang/crates.io-index" 652 | checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" 653 | dependencies = [ 654 | "darling_core", 655 | "quote", 656 | "syn", 657 | ] 658 | 659 | [[package]] 660 | name = "deranged" 661 | version = "0.3.11" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" 664 | dependencies = [ 665 | "powerfmt", 666 | ] 667 | 668 | [[package]] 669 | name = "derive_more" 670 | version = "2.0.1" 671 | source = "registry+https://github.com/rust-lang/crates.io-index" 672 | checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" 673 | dependencies = [ 674 | "derive_more-impl", 675 | ] 676 | 677 | [[package]] 678 | name = "derive_more-impl" 679 | version = "2.0.1" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" 682 | dependencies = [ 683 | "proc-macro2", 684 | "quote", 685 | "syn", 686 | "unicode-xid", 687 | ] 688 | 689 | [[package]] 690 | name = "digest" 691 | version = "0.10.7" 692 | source = "registry+https://github.com/rust-lang/crates.io-index" 693 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 694 | dependencies = [ 695 | "block-buffer", 696 | "crypto-common", 697 | ] 698 | 699 | [[package]] 700 | name = "displaydoc" 701 | version = "0.2.5" 702 | source = "registry+https://github.com/rust-lang/crates.io-index" 703 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 704 | dependencies = [ 705 | "proc-macro2", 706 | "quote", 707 | "syn", 708 | ] 709 | 710 | [[package]] 711 | name = "dtoa" 712 | version = "1.0.9" 713 | source = "registry+https://github.com/rust-lang/crates.io-index" 714 | checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" 715 | 716 | [[package]] 717 | name = "dyn-clone" 718 | version = "1.0.17" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" 721 | 722 | [[package]] 723 | name = "educe" 724 | version = "0.6.0" 725 | source = "registry+https://github.com/rust-lang/crates.io-index" 726 | checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" 727 | dependencies = [ 728 | "enum-ordinalize", 729 | "proc-macro2", 730 | "quote", 731 | "syn", 732 | ] 733 | 734 | [[package]] 735 | name = "either" 736 | version = "1.13.0" 737 | source = "registry+https://github.com/rust-lang/crates.io-index" 738 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 739 | 740 | [[package]] 741 | name = "encoding_rs" 742 | version = "0.8.35" 743 | source = "registry+https://github.com/rust-lang/crates.io-index" 744 | checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 745 | dependencies = [ 746 | "cfg-if", 747 | ] 748 | 749 | [[package]] 750 | name = "enum-ordinalize" 751 | version = "4.3.0" 752 | source = "registry+https://github.com/rust-lang/crates.io-index" 753 | checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" 754 | dependencies = [ 755 | "enum-ordinalize-derive", 756 | ] 757 | 758 | [[package]] 759 | name = "enum-ordinalize-derive" 760 | version = "4.3.1" 761 | source = "registry+https://github.com/rust-lang/crates.io-index" 762 | checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" 763 | dependencies = [ 764 | "proc-macro2", 765 | "quote", 766 | "syn", 767 | ] 768 | 769 | [[package]] 770 | name = "equivalent" 771 | version = "1.0.1" 772 | source = "registry+https://github.com/rust-lang/crates.io-index" 773 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 774 | 775 | [[package]] 776 | name = "event-listener" 777 | version = "5.3.1" 778 | source = "registry+https://github.com/rust-lang/crates.io-index" 779 | checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" 780 | dependencies = [ 781 | "concurrent-queue", 782 | "parking", 783 | "pin-project-lite", 784 | ] 785 | 786 | [[package]] 787 | name = "event-listener-strategy" 788 | version = "0.5.3" 789 | source = "registry+https://github.com/rust-lang/crates.io-index" 790 | checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" 791 | dependencies = [ 792 | "event-listener", 793 | "pin-project-lite", 794 | ] 795 | 796 | [[package]] 797 | name = "fastrand" 798 | version = "2.3.0" 799 | source = "registry+https://github.com/rust-lang/crates.io-index" 800 | checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 801 | 802 | [[package]] 803 | name = "flate2" 804 | version = "1.0.35" 805 | source = "registry+https://github.com/rust-lang/crates.io-index" 806 | checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" 807 | dependencies = [ 808 | "crc32fast", 809 | "miniz_oxide", 810 | ] 811 | 812 | [[package]] 813 | name = "fnv" 814 | version = "1.0.7" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 817 | 818 | [[package]] 819 | name = "foldhash" 820 | version = "0.1.3" 821 | source = "registry+https://github.com/rust-lang/crates.io-index" 822 | checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" 823 | 824 | [[package]] 825 | name = "form_urlencoded" 826 | version = "1.2.1" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 829 | dependencies = [ 830 | "percent-encoding", 831 | ] 832 | 833 | [[package]] 834 | name = "futures" 835 | version = "0.3.31" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 838 | dependencies = [ 839 | "futures-channel", 840 | "futures-core", 841 | "futures-executor", 842 | "futures-io", 843 | "futures-sink", 844 | "futures-task", 845 | "futures-util", 846 | ] 847 | 848 | [[package]] 849 | name = "futures-channel" 850 | version = "0.3.31" 851 | source = "registry+https://github.com/rust-lang/crates.io-index" 852 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 853 | dependencies = [ 854 | "futures-core", 855 | "futures-sink", 856 | ] 857 | 858 | [[package]] 859 | name = "futures-core" 860 | version = "0.3.31" 861 | source = "registry+https://github.com/rust-lang/crates.io-index" 862 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 863 | 864 | [[package]] 865 | name = "futures-executor" 866 | version = "0.3.31" 867 | source = "registry+https://github.com/rust-lang/crates.io-index" 868 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 869 | dependencies = [ 870 | "futures-core", 871 | "futures-task", 872 | "futures-util", 873 | ] 874 | 875 | [[package]] 876 | name = "futures-io" 877 | version = "0.3.31" 878 | source = "registry+https://github.com/rust-lang/crates.io-index" 879 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 880 | 881 | [[package]] 882 | name = "futures-macro" 883 | version = "0.3.31" 884 | source = "registry+https://github.com/rust-lang/crates.io-index" 885 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 886 | dependencies = [ 887 | "proc-macro2", 888 | "quote", 889 | "syn", 890 | ] 891 | 892 | [[package]] 893 | name = "futures-sink" 894 | version = "0.3.31" 895 | source = "registry+https://github.com/rust-lang/crates.io-index" 896 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 897 | 898 | [[package]] 899 | name = "futures-task" 900 | version = "0.3.31" 901 | source = "registry+https://github.com/rust-lang/crates.io-index" 902 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 903 | 904 | [[package]] 905 | name = "futures-util" 906 | version = "0.3.31" 907 | source = "registry+https://github.com/rust-lang/crates.io-index" 908 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 909 | dependencies = [ 910 | "futures-channel", 911 | "futures-core", 912 | "futures-io", 913 | "futures-macro", 914 | "futures-sink", 915 | "futures-task", 916 | "memchr", 917 | "pin-project-lite", 918 | "pin-utils", 919 | "slab", 920 | ] 921 | 922 | [[package]] 923 | name = "generic-array" 924 | version = "0.14.7" 925 | source = "registry+https://github.com/rust-lang/crates.io-index" 926 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 927 | dependencies = [ 928 | "typenum", 929 | "version_check", 930 | ] 931 | 932 | [[package]] 933 | name = "getrandom" 934 | version = "0.2.15" 935 | source = "registry+https://github.com/rust-lang/crates.io-index" 936 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 937 | dependencies = [ 938 | "cfg-if", 939 | "libc", 940 | "wasi 0.11.0+wasi-snapshot-preview1", 941 | ] 942 | 943 | [[package]] 944 | name = "getrandom" 945 | version = "0.3.1" 946 | source = "registry+https://github.com/rust-lang/crates.io-index" 947 | checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" 948 | dependencies = [ 949 | "cfg-if", 950 | "libc", 951 | "wasi 0.13.3+wasi-0.2.2", 952 | "windows-targets", 953 | ] 954 | 955 | [[package]] 956 | name = "gimli" 957 | version = "0.31.1" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 960 | 961 | [[package]] 962 | name = "glob" 963 | version = "0.3.1" 964 | source = "registry+https://github.com/rust-lang/crates.io-index" 965 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 966 | 967 | [[package]] 968 | name = "gloo-timers" 969 | version = "0.3.0" 970 | source = "registry+https://github.com/rust-lang/crates.io-index" 971 | checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" 972 | dependencies = [ 973 | "futures-channel", 974 | "futures-core", 975 | "js-sys", 976 | "wasm-bindgen", 977 | ] 978 | 979 | [[package]] 980 | name = "h2" 981 | version = "0.3.26" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" 984 | dependencies = [ 985 | "bytes", 986 | "fnv", 987 | "futures-core", 988 | "futures-sink", 989 | "futures-util", 990 | "http 0.2.12", 991 | "indexmap 2.7.0", 992 | "slab", 993 | "tokio", 994 | "tokio-util", 995 | "tracing", 996 | ] 997 | 998 | [[package]] 999 | name = "h2" 1000 | version = "0.4.7" 1001 | source = "registry+https://github.com/rust-lang/crates.io-index" 1002 | checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" 1003 | dependencies = [ 1004 | "atomic-waker", 1005 | "bytes", 1006 | "fnv", 1007 | "futures-core", 1008 | "futures-sink", 1009 | "http 1.3.1", 1010 | "indexmap 2.7.0", 1011 | "slab", 1012 | "tokio", 1013 | "tokio-util", 1014 | "tracing", 1015 | ] 1016 | 1017 | [[package]] 1018 | name = "hashbrown" 1019 | version = "0.12.3" 1020 | source = "registry+https://github.com/rust-lang/crates.io-index" 1021 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 1022 | 1023 | [[package]] 1024 | name = "hashbrown" 1025 | version = "0.15.2" 1026 | source = "registry+https://github.com/rust-lang/crates.io-index" 1027 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 1028 | dependencies = [ 1029 | "allocator-api2", 1030 | "equivalent", 1031 | "foldhash", 1032 | ] 1033 | 1034 | [[package]] 1035 | name = "headers" 1036 | version = "0.4.0" 1037 | source = "registry+https://github.com/rust-lang/crates.io-index" 1038 | checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" 1039 | dependencies = [ 1040 | "base64 0.21.7", 1041 | "bytes", 1042 | "headers-core", 1043 | "http 1.3.1", 1044 | "httpdate", 1045 | "mime", 1046 | "sha1", 1047 | ] 1048 | 1049 | [[package]] 1050 | name = "headers-core" 1051 | version = "0.3.0" 1052 | source = "registry+https://github.com/rust-lang/crates.io-index" 1053 | checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" 1054 | dependencies = [ 1055 | "http 1.3.1", 1056 | ] 1057 | 1058 | [[package]] 1059 | name = "home" 1060 | version = "0.5.9" 1061 | source = "registry+https://github.com/rust-lang/crates.io-index" 1062 | checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" 1063 | dependencies = [ 1064 | "windows-sys 0.52.0", 1065 | ] 1066 | 1067 | [[package]] 1068 | name = "hostname" 1069 | version = "0.4.0" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba" 1072 | dependencies = [ 1073 | "cfg-if", 1074 | "libc", 1075 | "windows", 1076 | ] 1077 | 1078 | [[package]] 1079 | name = "http" 1080 | version = "0.2.12" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" 1083 | dependencies = [ 1084 | "bytes", 1085 | "fnv", 1086 | "itoa", 1087 | ] 1088 | 1089 | [[package]] 1090 | name = "http" 1091 | version = "1.3.1" 1092 | source = "registry+https://github.com/rust-lang/crates.io-index" 1093 | checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" 1094 | dependencies = [ 1095 | "bytes", 1096 | "fnv", 1097 | "itoa", 1098 | ] 1099 | 1100 | [[package]] 1101 | name = "http-body" 1102 | version = "1.0.1" 1103 | source = "registry+https://github.com/rust-lang/crates.io-index" 1104 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 1105 | dependencies = [ 1106 | "bytes", 1107 | "http 1.3.1", 1108 | ] 1109 | 1110 | [[package]] 1111 | name = "http-body-util" 1112 | version = "0.1.2" 1113 | source = "registry+https://github.com/rust-lang/crates.io-index" 1114 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 1115 | dependencies = [ 1116 | "bytes", 1117 | "futures-util", 1118 | "http 1.3.1", 1119 | "http-body", 1120 | "pin-project-lite", 1121 | ] 1122 | 1123 | [[package]] 1124 | name = "httparse" 1125 | version = "1.9.5" 1126 | source = "registry+https://github.com/rust-lang/crates.io-index" 1127 | checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" 1128 | 1129 | [[package]] 1130 | name = "httpdate" 1131 | version = "1.0.3" 1132 | source = "registry+https://github.com/rust-lang/crates.io-index" 1133 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 1134 | 1135 | [[package]] 1136 | name = "hyper" 1137 | version = "1.6.0" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" 1140 | dependencies = [ 1141 | "bytes", 1142 | "futures-channel", 1143 | "futures-util", 1144 | "h2 0.4.7", 1145 | "http 1.3.1", 1146 | "http-body", 1147 | "httparse", 1148 | "httpdate", 1149 | "itoa", 1150 | "pin-project-lite", 1151 | "smallvec", 1152 | "tokio", 1153 | "want", 1154 | ] 1155 | 1156 | [[package]] 1157 | name = "hyper-http-proxy" 1158 | version = "1.1.0" 1159 | source = "registry+https://github.com/rust-lang/crates.io-index" 1160 | checksum = "7ad4b0a1e37510028bc4ba81d0e38d239c39671b0f0ce9e02dfa93a8133f7c08" 1161 | dependencies = [ 1162 | "bytes", 1163 | "futures-util", 1164 | "headers", 1165 | "http 1.3.1", 1166 | "hyper", 1167 | "hyper-rustls", 1168 | "hyper-util", 1169 | "pin-project-lite", 1170 | "rustls-native-certs 0.7.3", 1171 | "tokio", 1172 | "tokio-rustls", 1173 | "tower-service", 1174 | ] 1175 | 1176 | [[package]] 1177 | name = "hyper-rustls" 1178 | version = "0.27.5" 1179 | source = "registry+https://github.com/rust-lang/crates.io-index" 1180 | checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" 1181 | dependencies = [ 1182 | "futures-util", 1183 | "http 1.3.1", 1184 | "hyper", 1185 | "hyper-util", 1186 | "log", 1187 | "rustls", 1188 | "rustls-native-certs 0.8.1", 1189 | "rustls-pki-types", 1190 | "tokio", 1191 | "tokio-rustls", 1192 | "tower-service", 1193 | ] 1194 | 1195 | [[package]] 1196 | name = "hyper-timeout" 1197 | version = "0.5.2" 1198 | source = "registry+https://github.com/rust-lang/crates.io-index" 1199 | checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" 1200 | dependencies = [ 1201 | "hyper", 1202 | "hyper-util", 1203 | "pin-project-lite", 1204 | "tokio", 1205 | "tower-service", 1206 | ] 1207 | 1208 | [[package]] 1209 | name = "hyper-util" 1210 | version = "0.1.11" 1211 | source = "registry+https://github.com/rust-lang/crates.io-index" 1212 | checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" 1213 | dependencies = [ 1214 | "bytes", 1215 | "futures-channel", 1216 | "futures-util", 1217 | "http 1.3.1", 1218 | "http-body", 1219 | "hyper", 1220 | "libc", 1221 | "pin-project-lite", 1222 | "socket2", 1223 | "tokio", 1224 | "tower-service", 1225 | "tracing", 1226 | ] 1227 | 1228 | [[package]] 1229 | name = "iana-time-zone" 1230 | version = "0.1.61" 1231 | source = "registry+https://github.com/rust-lang/crates.io-index" 1232 | checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" 1233 | dependencies = [ 1234 | "android_system_properties", 1235 | "core-foundation-sys", 1236 | "iana-time-zone-haiku", 1237 | "js-sys", 1238 | "wasm-bindgen", 1239 | "windows-core", 1240 | ] 1241 | 1242 | [[package]] 1243 | name = "iana-time-zone-haiku" 1244 | version = "0.1.2" 1245 | source = "registry+https://github.com/rust-lang/crates.io-index" 1246 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 1247 | dependencies = [ 1248 | "cc", 1249 | ] 1250 | 1251 | [[package]] 1252 | name = "icu_collections" 1253 | version = "1.5.0" 1254 | source = "registry+https://github.com/rust-lang/crates.io-index" 1255 | checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 1256 | dependencies = [ 1257 | "displaydoc", 1258 | "yoke", 1259 | "zerofrom", 1260 | "zerovec", 1261 | ] 1262 | 1263 | [[package]] 1264 | name = "icu_locid" 1265 | version = "1.5.0" 1266 | source = "registry+https://github.com/rust-lang/crates.io-index" 1267 | checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 1268 | dependencies = [ 1269 | "displaydoc", 1270 | "litemap", 1271 | "tinystr", 1272 | "writeable", 1273 | "zerovec", 1274 | ] 1275 | 1276 | [[package]] 1277 | name = "icu_locid_transform" 1278 | version = "1.5.0" 1279 | source = "registry+https://github.com/rust-lang/crates.io-index" 1280 | checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 1281 | dependencies = [ 1282 | "displaydoc", 1283 | "icu_locid", 1284 | "icu_locid_transform_data", 1285 | "icu_provider", 1286 | "tinystr", 1287 | "zerovec", 1288 | ] 1289 | 1290 | [[package]] 1291 | name = "icu_locid_transform_data" 1292 | version = "1.5.0" 1293 | source = "registry+https://github.com/rust-lang/crates.io-index" 1294 | checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" 1295 | 1296 | [[package]] 1297 | name = "icu_normalizer" 1298 | version = "1.5.0" 1299 | source = "registry+https://github.com/rust-lang/crates.io-index" 1300 | checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 1301 | dependencies = [ 1302 | "displaydoc", 1303 | "icu_collections", 1304 | "icu_normalizer_data", 1305 | "icu_properties", 1306 | "icu_provider", 1307 | "smallvec", 1308 | "utf16_iter", 1309 | "utf8_iter", 1310 | "write16", 1311 | "zerovec", 1312 | ] 1313 | 1314 | [[package]] 1315 | name = "icu_normalizer_data" 1316 | version = "1.5.0" 1317 | source = "registry+https://github.com/rust-lang/crates.io-index" 1318 | checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" 1319 | 1320 | [[package]] 1321 | name = "icu_properties" 1322 | version = "1.5.1" 1323 | source = "registry+https://github.com/rust-lang/crates.io-index" 1324 | checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 1325 | dependencies = [ 1326 | "displaydoc", 1327 | "icu_collections", 1328 | "icu_locid_transform", 1329 | "icu_properties_data", 1330 | "icu_provider", 1331 | "tinystr", 1332 | "zerovec", 1333 | ] 1334 | 1335 | [[package]] 1336 | name = "icu_properties_data" 1337 | version = "1.5.0" 1338 | source = "registry+https://github.com/rust-lang/crates.io-index" 1339 | checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" 1340 | 1341 | [[package]] 1342 | name = "icu_provider" 1343 | version = "1.5.0" 1344 | source = "registry+https://github.com/rust-lang/crates.io-index" 1345 | checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 1346 | dependencies = [ 1347 | "displaydoc", 1348 | "icu_locid", 1349 | "icu_provider_macros", 1350 | "stable_deref_trait", 1351 | "tinystr", 1352 | "writeable", 1353 | "yoke", 1354 | "zerofrom", 1355 | "zerovec", 1356 | ] 1357 | 1358 | [[package]] 1359 | name = "icu_provider_macros" 1360 | version = "1.5.0" 1361 | source = "registry+https://github.com/rust-lang/crates.io-index" 1362 | checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 1363 | dependencies = [ 1364 | "proc-macro2", 1365 | "quote", 1366 | "syn", 1367 | ] 1368 | 1369 | [[package]] 1370 | name = "ident_case" 1371 | version = "1.0.1" 1372 | source = "registry+https://github.com/rust-lang/crates.io-index" 1373 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 1374 | 1375 | [[package]] 1376 | name = "idna" 1377 | version = "1.0.3" 1378 | source = "registry+https://github.com/rust-lang/crates.io-index" 1379 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 1380 | dependencies = [ 1381 | "idna_adapter", 1382 | "smallvec", 1383 | "utf8_iter", 1384 | ] 1385 | 1386 | [[package]] 1387 | name = "idna_adapter" 1388 | version = "1.2.0" 1389 | source = "registry+https://github.com/rust-lang/crates.io-index" 1390 | checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 1391 | dependencies = [ 1392 | "icu_normalizer", 1393 | "icu_properties", 1394 | ] 1395 | 1396 | [[package]] 1397 | name = "impl-more" 1398 | version = "0.1.8" 1399 | source = "registry+https://github.com/rust-lang/crates.io-index" 1400 | checksum = "aae21c3177a27788957044151cc2800043d127acaa460a47ebb9b84dfa2c6aa0" 1401 | 1402 | [[package]] 1403 | name = "indexmap" 1404 | version = "1.9.3" 1405 | source = "registry+https://github.com/rust-lang/crates.io-index" 1406 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 1407 | dependencies = [ 1408 | "autocfg", 1409 | "hashbrown 0.12.3", 1410 | ] 1411 | 1412 | [[package]] 1413 | name = "indexmap" 1414 | version = "2.7.0" 1415 | source = "registry+https://github.com/rust-lang/crates.io-index" 1416 | checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" 1417 | dependencies = [ 1418 | "equivalent", 1419 | "hashbrown 0.15.2", 1420 | ] 1421 | 1422 | [[package]] 1423 | name = "itertools" 1424 | version = "0.13.0" 1425 | source = "registry+https://github.com/rust-lang/crates.io-index" 1426 | checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" 1427 | dependencies = [ 1428 | "either", 1429 | ] 1430 | 1431 | [[package]] 1432 | name = "itoa" 1433 | version = "1.0.14" 1434 | source = "registry+https://github.com/rust-lang/crates.io-index" 1435 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 1436 | 1437 | [[package]] 1438 | name = "jobserver" 1439 | version = "0.1.32" 1440 | source = "registry+https://github.com/rust-lang/crates.io-index" 1441 | checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" 1442 | dependencies = [ 1443 | "libc", 1444 | ] 1445 | 1446 | [[package]] 1447 | name = "js-sys" 1448 | version = "0.3.74" 1449 | source = "registry+https://github.com/rust-lang/crates.io-index" 1450 | checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" 1451 | dependencies = [ 1452 | "once_cell", 1453 | "wasm-bindgen", 1454 | ] 1455 | 1456 | [[package]] 1457 | name = "json-patch" 1458 | version = "4.0.0" 1459 | source = "registry+https://github.com/rust-lang/crates.io-index" 1460 | checksum = "159294d661a039f7644cea7e4d844e6b25aaf71c1ffe9d73a96d768c24b0faf4" 1461 | dependencies = [ 1462 | "jsonptr", 1463 | "serde", 1464 | "serde_json", 1465 | "thiserror 1.0.69", 1466 | ] 1467 | 1468 | [[package]] 1469 | name = "jsonpath-rust" 1470 | version = "0.7.3" 1471 | source = "registry+https://github.com/rust-lang/crates.io-index" 1472 | checksum = "69a61b87f6a55cc6c28fed5739dd36b9642321ce63e4a5e4a4715d69106f4a10" 1473 | dependencies = [ 1474 | "pest", 1475 | "pest_derive", 1476 | "regex", 1477 | "serde_json", 1478 | "thiserror 1.0.69", 1479 | ] 1480 | 1481 | [[package]] 1482 | name = "jsonptr" 1483 | version = "0.7.1" 1484 | source = "registry+https://github.com/rust-lang/crates.io-index" 1485 | checksum = "a5a3cc660ba5d72bce0b3bb295bf20847ccbb40fd423f3f05b61273672e561fe" 1486 | dependencies = [ 1487 | "serde", 1488 | "serde_json", 1489 | ] 1490 | 1491 | [[package]] 1492 | name = "k8s-openapi" 1493 | version = "0.25.0" 1494 | source = "registry+https://github.com/rust-lang/crates.io-index" 1495 | checksum = "aa60a41b57ae1a0a071af77dbcf89fc9819cfe66edaf2beeb204c34459dcf0b2" 1496 | dependencies = [ 1497 | "base64 0.22.1", 1498 | "chrono", 1499 | "serde", 1500 | "serde_json", 1501 | ] 1502 | 1503 | [[package]] 1504 | name = "kube" 1505 | version = "1.1.0" 1506 | source = "registry+https://github.com/rust-lang/crates.io-index" 1507 | checksum = "778f98664beaf4c3c11372721e14310d1ae00f5e2d9aabcf8906c881aa4e9f51" 1508 | dependencies = [ 1509 | "k8s-openapi", 1510 | "kube-client", 1511 | "kube-core", 1512 | "kube-derive", 1513 | "kube-runtime", 1514 | ] 1515 | 1516 | [[package]] 1517 | name = "kube-client" 1518 | version = "1.1.0" 1519 | source = "registry+https://github.com/rust-lang/crates.io-index" 1520 | checksum = "7cb276b85b6e94ded00ac8ea2c68fcf4697ea0553cb25fddc35d4a0ab718db8d" 1521 | dependencies = [ 1522 | "base64 0.22.1", 1523 | "bytes", 1524 | "chrono", 1525 | "either", 1526 | "futures", 1527 | "home", 1528 | "http 1.3.1", 1529 | "http-body", 1530 | "http-body-util", 1531 | "hyper", 1532 | "hyper-http-proxy", 1533 | "hyper-rustls", 1534 | "hyper-timeout", 1535 | "hyper-util", 1536 | "jsonpath-rust", 1537 | "k8s-openapi", 1538 | "kube-core", 1539 | "pem", 1540 | "rustls", 1541 | "secrecy", 1542 | "serde", 1543 | "serde_json", 1544 | "serde_yaml", 1545 | "thiserror 2.0.12", 1546 | "tokio", 1547 | "tokio-util", 1548 | "tower 0.5.1", 1549 | "tower-http", 1550 | "tracing", 1551 | ] 1552 | 1553 | [[package]] 1554 | name = "kube-core" 1555 | version = "1.1.0" 1556 | source = "registry+https://github.com/rust-lang/crates.io-index" 1557 | checksum = "e3c56ff45deb0031f2a476017eed60c06872251f271b8387ad8020b8fef60960" 1558 | dependencies = [ 1559 | "chrono", 1560 | "derive_more", 1561 | "form_urlencoded", 1562 | "http 1.3.1", 1563 | "json-patch", 1564 | "k8s-openapi", 1565 | "schemars", 1566 | "serde", 1567 | "serde-value", 1568 | "serde_json", 1569 | "thiserror 2.0.12", 1570 | ] 1571 | 1572 | [[package]] 1573 | name = "kube-derive" 1574 | version = "1.1.0" 1575 | source = "registry+https://github.com/rust-lang/crates.io-index" 1576 | checksum = "079fc8c1c397538628309cfdee20696ebdcc26745f9fb17f89b78782205bd995" 1577 | dependencies = [ 1578 | "darling", 1579 | "proc-macro2", 1580 | "quote", 1581 | "serde", 1582 | "serde_json", 1583 | "syn", 1584 | ] 1585 | 1586 | [[package]] 1587 | name = "kube-runtime" 1588 | version = "1.1.0" 1589 | source = "registry+https://github.com/rust-lang/crates.io-index" 1590 | checksum = "2f1326e946fadf6248febdf8a1c001809c3899ccf48cb9768cbc536b741040dc" 1591 | dependencies = [ 1592 | "ahash", 1593 | "async-broadcast", 1594 | "async-stream", 1595 | "backon", 1596 | "educe", 1597 | "futures", 1598 | "hashbrown 0.15.2", 1599 | "hostname", 1600 | "json-patch", 1601 | "k8s-openapi", 1602 | "kube-client", 1603 | "parking_lot", 1604 | "pin-project", 1605 | "serde", 1606 | "serde_json", 1607 | "thiserror 2.0.12", 1608 | "tokio", 1609 | "tokio-util", 1610 | "tracing", 1611 | ] 1612 | 1613 | [[package]] 1614 | name = "language-tags" 1615 | version = "0.3.2" 1616 | source = "registry+https://github.com/rust-lang/crates.io-index" 1617 | checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" 1618 | 1619 | [[package]] 1620 | name = "lazy_static" 1621 | version = "1.5.0" 1622 | source = "registry+https://github.com/rust-lang/crates.io-index" 1623 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 1624 | 1625 | [[package]] 1626 | name = "libc" 1627 | version = "0.2.172" 1628 | source = "registry+https://github.com/rust-lang/crates.io-index" 1629 | checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" 1630 | 1631 | [[package]] 1632 | name = "litemap" 1633 | version = "0.7.4" 1634 | source = "registry+https://github.com/rust-lang/crates.io-index" 1635 | checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" 1636 | 1637 | [[package]] 1638 | name = "local-channel" 1639 | version = "0.1.5" 1640 | source = "registry+https://github.com/rust-lang/crates.io-index" 1641 | checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" 1642 | dependencies = [ 1643 | "futures-core", 1644 | "futures-sink", 1645 | "local-waker", 1646 | ] 1647 | 1648 | [[package]] 1649 | name = "local-waker" 1650 | version = "0.1.4" 1651 | source = "registry+https://github.com/rust-lang/crates.io-index" 1652 | checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" 1653 | 1654 | [[package]] 1655 | name = "lock_api" 1656 | version = "0.4.12" 1657 | source = "registry+https://github.com/rust-lang/crates.io-index" 1658 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 1659 | dependencies = [ 1660 | "autocfg", 1661 | "scopeguard", 1662 | ] 1663 | 1664 | [[package]] 1665 | name = "log" 1666 | version = "0.4.22" 1667 | source = "registry+https://github.com/rust-lang/crates.io-index" 1668 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 1669 | 1670 | [[package]] 1671 | name = "matchers" 1672 | version = "0.1.0" 1673 | source = "registry+https://github.com/rust-lang/crates.io-index" 1674 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 1675 | dependencies = [ 1676 | "regex-automata 0.1.10", 1677 | ] 1678 | 1679 | [[package]] 1680 | name = "matchit" 1681 | version = "0.7.3" 1682 | source = "registry+https://github.com/rust-lang/crates.io-index" 1683 | checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" 1684 | 1685 | [[package]] 1686 | name = "memchr" 1687 | version = "2.7.4" 1688 | source = "registry+https://github.com/rust-lang/crates.io-index" 1689 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 1690 | 1691 | [[package]] 1692 | name = "mime" 1693 | version = "0.3.17" 1694 | source = "registry+https://github.com/rust-lang/crates.io-index" 1695 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 1696 | 1697 | [[package]] 1698 | name = "miniz_oxide" 1699 | version = "0.8.0" 1700 | source = "registry+https://github.com/rust-lang/crates.io-index" 1701 | checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" 1702 | dependencies = [ 1703 | "adler2", 1704 | ] 1705 | 1706 | [[package]] 1707 | name = "mio" 1708 | version = "1.0.3" 1709 | source = "registry+https://github.com/rust-lang/crates.io-index" 1710 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 1711 | dependencies = [ 1712 | "libc", 1713 | "log", 1714 | "wasi 0.11.0+wasi-snapshot-preview1", 1715 | "windows-sys 0.52.0", 1716 | ] 1717 | 1718 | [[package]] 1719 | name = "nu-ansi-term" 1720 | version = "0.46.0" 1721 | source = "registry+https://github.com/rust-lang/crates.io-index" 1722 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 1723 | dependencies = [ 1724 | "overload", 1725 | "winapi", 1726 | ] 1727 | 1728 | [[package]] 1729 | name = "num-conv" 1730 | version = "0.1.0" 1731 | source = "registry+https://github.com/rust-lang/crates.io-index" 1732 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 1733 | 1734 | [[package]] 1735 | name = "num-traits" 1736 | version = "0.2.19" 1737 | source = "registry+https://github.com/rust-lang/crates.io-index" 1738 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1739 | dependencies = [ 1740 | "autocfg", 1741 | ] 1742 | 1743 | [[package]] 1744 | name = "object" 1745 | version = "0.36.5" 1746 | source = "registry+https://github.com/rust-lang/crates.io-index" 1747 | checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" 1748 | dependencies = [ 1749 | "memchr", 1750 | ] 1751 | 1752 | [[package]] 1753 | name = "once_cell" 1754 | version = "1.21.3" 1755 | source = "registry+https://github.com/rust-lang/crates.io-index" 1756 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 1757 | 1758 | [[package]] 1759 | name = "openssl-probe" 1760 | version = "0.1.6" 1761 | source = "registry+https://github.com/rust-lang/crates.io-index" 1762 | checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" 1763 | 1764 | [[package]] 1765 | name = "opentelemetry" 1766 | version = "0.27.1" 1767 | source = "registry+https://github.com/rust-lang/crates.io-index" 1768 | checksum = "ab70038c28ed37b97d8ed414b6429d343a8bbf44c9f79ec854f3a643029ba6d7" 1769 | dependencies = [ 1770 | "futures-core", 1771 | "futures-sink", 1772 | "js-sys", 1773 | "pin-project-lite", 1774 | "thiserror 1.0.69", 1775 | "tracing", 1776 | ] 1777 | 1778 | [[package]] 1779 | name = "opentelemetry-otlp" 1780 | version = "0.27.0" 1781 | source = "registry+https://github.com/rust-lang/crates.io-index" 1782 | checksum = "91cf61a1868dacc576bf2b2a1c3e9ab150af7272909e80085c3173384fe11f76" 1783 | dependencies = [ 1784 | "async-trait", 1785 | "futures-core", 1786 | "http 1.3.1", 1787 | "opentelemetry", 1788 | "opentelemetry-proto", 1789 | "opentelemetry_sdk", 1790 | "prost", 1791 | "thiserror 1.0.69", 1792 | "tokio", 1793 | "tonic", 1794 | "tracing", 1795 | ] 1796 | 1797 | [[package]] 1798 | name = "opentelemetry-proto" 1799 | version = "0.27.0" 1800 | source = "registry+https://github.com/rust-lang/crates.io-index" 1801 | checksum = "a6e05acbfada5ec79023c85368af14abd0b307c015e9064d249b2a950ef459a6" 1802 | dependencies = [ 1803 | "opentelemetry", 1804 | "opentelemetry_sdk", 1805 | "prost", 1806 | "tonic", 1807 | ] 1808 | 1809 | [[package]] 1810 | name = "opentelemetry_sdk" 1811 | version = "0.27.1" 1812 | source = "registry+https://github.com/rust-lang/crates.io-index" 1813 | checksum = "231e9d6ceef9b0b2546ddf52335785ce41252bc7474ee8ba05bfad277be13ab8" 1814 | dependencies = [ 1815 | "async-trait", 1816 | "futures-channel", 1817 | "futures-executor", 1818 | "futures-util", 1819 | "glob", 1820 | "opentelemetry", 1821 | "percent-encoding", 1822 | "rand 0.8.5", 1823 | "serde_json", 1824 | "thiserror 1.0.69", 1825 | "tokio", 1826 | "tokio-stream", 1827 | "tracing", 1828 | ] 1829 | 1830 | [[package]] 1831 | name = "ordered-float" 1832 | version = "2.10.1" 1833 | source = "registry+https://github.com/rust-lang/crates.io-index" 1834 | checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" 1835 | dependencies = [ 1836 | "num-traits", 1837 | ] 1838 | 1839 | [[package]] 1840 | name = "overload" 1841 | version = "0.1.1" 1842 | source = "registry+https://github.com/rust-lang/crates.io-index" 1843 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 1844 | 1845 | [[package]] 1846 | name = "parking" 1847 | version = "2.2.1" 1848 | source = "registry+https://github.com/rust-lang/crates.io-index" 1849 | checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" 1850 | 1851 | [[package]] 1852 | name = "parking_lot" 1853 | version = "0.12.3" 1854 | source = "registry+https://github.com/rust-lang/crates.io-index" 1855 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 1856 | dependencies = [ 1857 | "lock_api", 1858 | "parking_lot_core", 1859 | ] 1860 | 1861 | [[package]] 1862 | name = "parking_lot_core" 1863 | version = "0.9.10" 1864 | source = "registry+https://github.com/rust-lang/crates.io-index" 1865 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 1866 | dependencies = [ 1867 | "cfg-if", 1868 | "libc", 1869 | "redox_syscall", 1870 | "smallvec", 1871 | "windows-targets", 1872 | ] 1873 | 1874 | [[package]] 1875 | name = "paste" 1876 | version = "1.0.15" 1877 | source = "registry+https://github.com/rust-lang/crates.io-index" 1878 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 1879 | 1880 | [[package]] 1881 | name = "pem" 1882 | version = "3.0.4" 1883 | source = "registry+https://github.com/rust-lang/crates.io-index" 1884 | checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" 1885 | dependencies = [ 1886 | "base64 0.22.1", 1887 | "serde", 1888 | ] 1889 | 1890 | [[package]] 1891 | name = "percent-encoding" 1892 | version = "2.3.1" 1893 | source = "registry+https://github.com/rust-lang/crates.io-index" 1894 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1895 | 1896 | [[package]] 1897 | name = "pest" 1898 | version = "2.7.14" 1899 | source = "registry+https://github.com/rust-lang/crates.io-index" 1900 | checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" 1901 | dependencies = [ 1902 | "memchr", 1903 | "thiserror 1.0.69", 1904 | "ucd-trie", 1905 | ] 1906 | 1907 | [[package]] 1908 | name = "pest_derive" 1909 | version = "2.7.14" 1910 | source = "registry+https://github.com/rust-lang/crates.io-index" 1911 | checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" 1912 | dependencies = [ 1913 | "pest", 1914 | "pest_generator", 1915 | ] 1916 | 1917 | [[package]] 1918 | name = "pest_generator" 1919 | version = "2.7.14" 1920 | source = "registry+https://github.com/rust-lang/crates.io-index" 1921 | checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" 1922 | dependencies = [ 1923 | "pest", 1924 | "pest_meta", 1925 | "proc-macro2", 1926 | "quote", 1927 | "syn", 1928 | ] 1929 | 1930 | [[package]] 1931 | name = "pest_meta" 1932 | version = "2.7.14" 1933 | source = "registry+https://github.com/rust-lang/crates.io-index" 1934 | checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" 1935 | dependencies = [ 1936 | "once_cell", 1937 | "pest", 1938 | "sha2", 1939 | ] 1940 | 1941 | [[package]] 1942 | name = "pin-project" 1943 | version = "1.1.7" 1944 | source = "registry+https://github.com/rust-lang/crates.io-index" 1945 | checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" 1946 | dependencies = [ 1947 | "pin-project-internal", 1948 | ] 1949 | 1950 | [[package]] 1951 | name = "pin-project-internal" 1952 | version = "1.1.7" 1953 | source = "registry+https://github.com/rust-lang/crates.io-index" 1954 | checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" 1955 | dependencies = [ 1956 | "proc-macro2", 1957 | "quote", 1958 | "syn", 1959 | ] 1960 | 1961 | [[package]] 1962 | name = "pin-project-lite" 1963 | version = "0.2.15" 1964 | source = "registry+https://github.com/rust-lang/crates.io-index" 1965 | checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" 1966 | 1967 | [[package]] 1968 | name = "pin-utils" 1969 | version = "0.1.0" 1970 | source = "registry+https://github.com/rust-lang/crates.io-index" 1971 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1972 | 1973 | [[package]] 1974 | name = "pkg-config" 1975 | version = "0.3.31" 1976 | source = "registry+https://github.com/rust-lang/crates.io-index" 1977 | checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" 1978 | 1979 | [[package]] 1980 | name = "powerfmt" 1981 | version = "0.2.0" 1982 | source = "registry+https://github.com/rust-lang/crates.io-index" 1983 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1984 | 1985 | [[package]] 1986 | name = "ppv-lite86" 1987 | version = "0.2.20" 1988 | source = "registry+https://github.com/rust-lang/crates.io-index" 1989 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 1990 | dependencies = [ 1991 | "zerocopy 0.7.35", 1992 | ] 1993 | 1994 | [[package]] 1995 | name = "proc-macro2" 1996 | version = "1.0.93" 1997 | source = "registry+https://github.com/rust-lang/crates.io-index" 1998 | checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" 1999 | dependencies = [ 2000 | "unicode-ident", 2001 | ] 2002 | 2003 | [[package]] 2004 | name = "prometheus-client" 2005 | version = "0.23.1" 2006 | source = "registry+https://github.com/rust-lang/crates.io-index" 2007 | checksum = "cf41c1a7c32ed72abe5082fb19505b969095c12da9f5732a4bc9878757fd087c" 2008 | dependencies = [ 2009 | "dtoa", 2010 | "itoa", 2011 | "parking_lot", 2012 | "prometheus-client-derive-encode", 2013 | ] 2014 | 2015 | [[package]] 2016 | name = "prometheus-client-derive-encode" 2017 | version = "0.4.2" 2018 | source = "registry+https://github.com/rust-lang/crates.io-index" 2019 | checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" 2020 | dependencies = [ 2021 | "proc-macro2", 2022 | "quote", 2023 | "syn", 2024 | ] 2025 | 2026 | [[package]] 2027 | name = "prost" 2028 | version = "0.13.3" 2029 | source = "registry+https://github.com/rust-lang/crates.io-index" 2030 | checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" 2031 | dependencies = [ 2032 | "bytes", 2033 | "prost-derive", 2034 | ] 2035 | 2036 | [[package]] 2037 | name = "prost-derive" 2038 | version = "0.13.3" 2039 | source = "registry+https://github.com/rust-lang/crates.io-index" 2040 | checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" 2041 | dependencies = [ 2042 | "anyhow", 2043 | "itertools", 2044 | "proc-macro2", 2045 | "quote", 2046 | "syn", 2047 | ] 2048 | 2049 | [[package]] 2050 | name = "quote" 2051 | version = "1.0.38" 2052 | source = "registry+https://github.com/rust-lang/crates.io-index" 2053 | checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" 2054 | dependencies = [ 2055 | "proc-macro2", 2056 | ] 2057 | 2058 | [[package]] 2059 | name = "rand" 2060 | version = "0.8.5" 2061 | source = "registry+https://github.com/rust-lang/crates.io-index" 2062 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 2063 | dependencies = [ 2064 | "libc", 2065 | "rand_chacha 0.3.1", 2066 | "rand_core 0.6.4", 2067 | ] 2068 | 2069 | [[package]] 2070 | name = "rand" 2071 | version = "0.9.0" 2072 | source = "registry+https://github.com/rust-lang/crates.io-index" 2073 | checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" 2074 | dependencies = [ 2075 | "rand_chacha 0.9.0", 2076 | "rand_core 0.9.3", 2077 | "zerocopy 0.8.23", 2078 | ] 2079 | 2080 | [[package]] 2081 | name = "rand_chacha" 2082 | version = "0.3.1" 2083 | source = "registry+https://github.com/rust-lang/crates.io-index" 2084 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 2085 | dependencies = [ 2086 | "ppv-lite86", 2087 | "rand_core 0.6.4", 2088 | ] 2089 | 2090 | [[package]] 2091 | name = "rand_chacha" 2092 | version = "0.9.0" 2093 | source = "registry+https://github.com/rust-lang/crates.io-index" 2094 | checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 2095 | dependencies = [ 2096 | "ppv-lite86", 2097 | "rand_core 0.9.3", 2098 | ] 2099 | 2100 | [[package]] 2101 | name = "rand_core" 2102 | version = "0.6.4" 2103 | source = "registry+https://github.com/rust-lang/crates.io-index" 2104 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 2105 | dependencies = [ 2106 | "getrandom 0.2.15", 2107 | ] 2108 | 2109 | [[package]] 2110 | name = "rand_core" 2111 | version = "0.9.3" 2112 | source = "registry+https://github.com/rust-lang/crates.io-index" 2113 | checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" 2114 | dependencies = [ 2115 | "getrandom 0.3.1", 2116 | ] 2117 | 2118 | [[package]] 2119 | name = "redox_syscall" 2120 | version = "0.5.7" 2121 | source = "registry+https://github.com/rust-lang/crates.io-index" 2122 | checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" 2123 | dependencies = [ 2124 | "bitflags", 2125 | ] 2126 | 2127 | [[package]] 2128 | name = "regex" 2129 | version = "1.11.1" 2130 | source = "registry+https://github.com/rust-lang/crates.io-index" 2131 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 2132 | dependencies = [ 2133 | "aho-corasick", 2134 | "memchr", 2135 | "regex-automata 0.4.9", 2136 | "regex-syntax 0.8.5", 2137 | ] 2138 | 2139 | [[package]] 2140 | name = "regex-automata" 2141 | version = "0.1.10" 2142 | source = "registry+https://github.com/rust-lang/crates.io-index" 2143 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 2144 | dependencies = [ 2145 | "regex-syntax 0.6.29", 2146 | ] 2147 | 2148 | [[package]] 2149 | name = "regex-automata" 2150 | version = "0.4.9" 2151 | source = "registry+https://github.com/rust-lang/crates.io-index" 2152 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 2153 | dependencies = [ 2154 | "aho-corasick", 2155 | "memchr", 2156 | "regex-syntax 0.8.5", 2157 | ] 2158 | 2159 | [[package]] 2160 | name = "regex-lite" 2161 | version = "0.1.6" 2162 | source = "registry+https://github.com/rust-lang/crates.io-index" 2163 | checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" 2164 | 2165 | [[package]] 2166 | name = "regex-syntax" 2167 | version = "0.6.29" 2168 | source = "registry+https://github.com/rust-lang/crates.io-index" 2169 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 2170 | 2171 | [[package]] 2172 | name = "regex-syntax" 2173 | version = "0.8.5" 2174 | source = "registry+https://github.com/rust-lang/crates.io-index" 2175 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 2176 | 2177 | [[package]] 2178 | name = "ring" 2179 | version = "0.17.9" 2180 | source = "registry+https://github.com/rust-lang/crates.io-index" 2181 | checksum = "e75ec5e92c4d8aede845126adc388046234541629e76029599ed35a003c7ed24" 2182 | dependencies = [ 2183 | "cc", 2184 | "cfg-if", 2185 | "getrandom 0.2.15", 2186 | "libc", 2187 | "untrusted", 2188 | "windows-sys 0.52.0", 2189 | ] 2190 | 2191 | [[package]] 2192 | name = "rustc-demangle" 2193 | version = "0.1.24" 2194 | source = "registry+https://github.com/rust-lang/crates.io-index" 2195 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 2196 | 2197 | [[package]] 2198 | name = "rustls" 2199 | version = "0.23.27" 2200 | source = "registry+https://github.com/rust-lang/crates.io-index" 2201 | checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" 2202 | dependencies = [ 2203 | "log", 2204 | "once_cell", 2205 | "ring", 2206 | "rustls-pki-types", 2207 | "rustls-webpki", 2208 | "subtle", 2209 | "zeroize", 2210 | ] 2211 | 2212 | [[package]] 2213 | name = "rustls-native-certs" 2214 | version = "0.7.3" 2215 | source = "registry+https://github.com/rust-lang/crates.io-index" 2216 | checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" 2217 | dependencies = [ 2218 | "openssl-probe", 2219 | "rustls-pemfile", 2220 | "rustls-pki-types", 2221 | "schannel", 2222 | "security-framework 2.11.1", 2223 | ] 2224 | 2225 | [[package]] 2226 | name = "rustls-native-certs" 2227 | version = "0.8.1" 2228 | source = "registry+https://github.com/rust-lang/crates.io-index" 2229 | checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" 2230 | dependencies = [ 2231 | "openssl-probe", 2232 | "rustls-pki-types", 2233 | "schannel", 2234 | "security-framework 3.2.0", 2235 | ] 2236 | 2237 | [[package]] 2238 | name = "rustls-pemfile" 2239 | version = "2.2.0" 2240 | source = "registry+https://github.com/rust-lang/crates.io-index" 2241 | checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" 2242 | dependencies = [ 2243 | "rustls-pki-types", 2244 | ] 2245 | 2246 | [[package]] 2247 | name = "rustls-pki-types" 2248 | version = "1.12.0" 2249 | source = "registry+https://github.com/rust-lang/crates.io-index" 2250 | checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" 2251 | dependencies = [ 2252 | "zeroize", 2253 | ] 2254 | 2255 | [[package]] 2256 | name = "rustls-webpki" 2257 | version = "0.103.3" 2258 | source = "registry+https://github.com/rust-lang/crates.io-index" 2259 | checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" 2260 | dependencies = [ 2261 | "ring", 2262 | "rustls-pki-types", 2263 | "untrusted", 2264 | ] 2265 | 2266 | [[package]] 2267 | name = "rustversion" 2268 | version = "1.0.18" 2269 | source = "registry+https://github.com/rust-lang/crates.io-index" 2270 | checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" 2271 | 2272 | [[package]] 2273 | name = "ryu" 2274 | version = "1.0.18" 2275 | source = "registry+https://github.com/rust-lang/crates.io-index" 2276 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 2277 | 2278 | [[package]] 2279 | name = "schannel" 2280 | version = "0.1.27" 2281 | source = "registry+https://github.com/rust-lang/crates.io-index" 2282 | checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" 2283 | dependencies = [ 2284 | "windows-sys 0.59.0", 2285 | ] 2286 | 2287 | [[package]] 2288 | name = "schemars" 2289 | version = "0.8.22" 2290 | source = "registry+https://github.com/rust-lang/crates.io-index" 2291 | checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" 2292 | dependencies = [ 2293 | "chrono", 2294 | "dyn-clone", 2295 | "schemars_derive", 2296 | "serde", 2297 | "serde_json", 2298 | ] 2299 | 2300 | [[package]] 2301 | name = "schemars_derive" 2302 | version = "0.8.22" 2303 | source = "registry+https://github.com/rust-lang/crates.io-index" 2304 | checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" 2305 | dependencies = [ 2306 | "proc-macro2", 2307 | "quote", 2308 | "serde_derive_internals", 2309 | "syn", 2310 | ] 2311 | 2312 | [[package]] 2313 | name = "scopeguard" 2314 | version = "1.2.0" 2315 | source = "registry+https://github.com/rust-lang/crates.io-index" 2316 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 2317 | 2318 | [[package]] 2319 | name = "secrecy" 2320 | version = "0.10.3" 2321 | source = "registry+https://github.com/rust-lang/crates.io-index" 2322 | checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" 2323 | dependencies = [ 2324 | "zeroize", 2325 | ] 2326 | 2327 | [[package]] 2328 | name = "security-framework" 2329 | version = "2.11.1" 2330 | source = "registry+https://github.com/rust-lang/crates.io-index" 2331 | checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 2332 | dependencies = [ 2333 | "bitflags", 2334 | "core-foundation 0.9.4", 2335 | "core-foundation-sys", 2336 | "libc", 2337 | "security-framework-sys", 2338 | ] 2339 | 2340 | [[package]] 2341 | name = "security-framework" 2342 | version = "3.2.0" 2343 | source = "registry+https://github.com/rust-lang/crates.io-index" 2344 | checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" 2345 | dependencies = [ 2346 | "bitflags", 2347 | "core-foundation 0.10.0", 2348 | "core-foundation-sys", 2349 | "libc", 2350 | "security-framework-sys", 2351 | ] 2352 | 2353 | [[package]] 2354 | name = "security-framework-sys" 2355 | version = "2.14.0" 2356 | source = "registry+https://github.com/rust-lang/crates.io-index" 2357 | checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" 2358 | dependencies = [ 2359 | "core-foundation-sys", 2360 | "libc", 2361 | ] 2362 | 2363 | [[package]] 2364 | name = "serde" 2365 | version = "1.0.219" 2366 | source = "registry+https://github.com/rust-lang/crates.io-index" 2367 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 2368 | dependencies = [ 2369 | "serde_derive", 2370 | ] 2371 | 2372 | [[package]] 2373 | name = "serde-value" 2374 | version = "0.7.0" 2375 | source = "registry+https://github.com/rust-lang/crates.io-index" 2376 | checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" 2377 | dependencies = [ 2378 | "ordered-float", 2379 | "serde", 2380 | ] 2381 | 2382 | [[package]] 2383 | name = "serde_derive" 2384 | version = "1.0.219" 2385 | source = "registry+https://github.com/rust-lang/crates.io-index" 2386 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 2387 | dependencies = [ 2388 | "proc-macro2", 2389 | "quote", 2390 | "syn", 2391 | ] 2392 | 2393 | [[package]] 2394 | name = "serde_derive_internals" 2395 | version = "0.29.1" 2396 | source = "registry+https://github.com/rust-lang/crates.io-index" 2397 | checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" 2398 | dependencies = [ 2399 | "proc-macro2", 2400 | "quote", 2401 | "syn", 2402 | ] 2403 | 2404 | [[package]] 2405 | name = "serde_json" 2406 | version = "1.0.140" 2407 | source = "registry+https://github.com/rust-lang/crates.io-index" 2408 | checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 2409 | dependencies = [ 2410 | "itoa", 2411 | "memchr", 2412 | "ryu", 2413 | "serde", 2414 | ] 2415 | 2416 | [[package]] 2417 | name = "serde_urlencoded" 2418 | version = "0.7.1" 2419 | source = "registry+https://github.com/rust-lang/crates.io-index" 2420 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 2421 | dependencies = [ 2422 | "form_urlencoded", 2423 | "itoa", 2424 | "ryu", 2425 | "serde", 2426 | ] 2427 | 2428 | [[package]] 2429 | name = "serde_yaml" 2430 | version = "0.9.34+deprecated" 2431 | source = "registry+https://github.com/rust-lang/crates.io-index" 2432 | checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" 2433 | dependencies = [ 2434 | "indexmap 2.7.0", 2435 | "itoa", 2436 | "ryu", 2437 | "serde", 2438 | "unsafe-libyaml", 2439 | ] 2440 | 2441 | [[package]] 2442 | name = "sha1" 2443 | version = "0.10.6" 2444 | source = "registry+https://github.com/rust-lang/crates.io-index" 2445 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 2446 | dependencies = [ 2447 | "cfg-if", 2448 | "cpufeatures", 2449 | "digest", 2450 | ] 2451 | 2452 | [[package]] 2453 | name = "sha2" 2454 | version = "0.10.8" 2455 | source = "registry+https://github.com/rust-lang/crates.io-index" 2456 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 2457 | dependencies = [ 2458 | "cfg-if", 2459 | "cpufeatures", 2460 | "digest", 2461 | ] 2462 | 2463 | [[package]] 2464 | name = "sharded-slab" 2465 | version = "0.1.7" 2466 | source = "registry+https://github.com/rust-lang/crates.io-index" 2467 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 2468 | dependencies = [ 2469 | "lazy_static", 2470 | ] 2471 | 2472 | [[package]] 2473 | name = "shlex" 2474 | version = "1.3.0" 2475 | source = "registry+https://github.com/rust-lang/crates.io-index" 2476 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 2477 | 2478 | [[package]] 2479 | name = "signal-hook-registry" 2480 | version = "1.4.2" 2481 | source = "registry+https://github.com/rust-lang/crates.io-index" 2482 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 2483 | dependencies = [ 2484 | "libc", 2485 | ] 2486 | 2487 | [[package]] 2488 | name = "slab" 2489 | version = "0.4.9" 2490 | source = "registry+https://github.com/rust-lang/crates.io-index" 2491 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 2492 | dependencies = [ 2493 | "autocfg", 2494 | ] 2495 | 2496 | [[package]] 2497 | name = "smallvec" 2498 | version = "1.13.2" 2499 | source = "registry+https://github.com/rust-lang/crates.io-index" 2500 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 2501 | 2502 | [[package]] 2503 | name = "socket2" 2504 | version = "0.5.9" 2505 | source = "registry+https://github.com/rust-lang/crates.io-index" 2506 | checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" 2507 | dependencies = [ 2508 | "libc", 2509 | "windows-sys 0.52.0", 2510 | ] 2511 | 2512 | [[package]] 2513 | name = "stable_deref_trait" 2514 | version = "1.2.0" 2515 | source = "registry+https://github.com/rust-lang/crates.io-index" 2516 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 2517 | 2518 | [[package]] 2519 | name = "strsim" 2520 | version = "0.11.1" 2521 | source = "registry+https://github.com/rust-lang/crates.io-index" 2522 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 2523 | 2524 | [[package]] 2525 | name = "subtle" 2526 | version = "2.6.1" 2527 | source = "registry+https://github.com/rust-lang/crates.io-index" 2528 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 2529 | 2530 | [[package]] 2531 | name = "syn" 2532 | version = "2.0.96" 2533 | source = "registry+https://github.com/rust-lang/crates.io-index" 2534 | checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" 2535 | dependencies = [ 2536 | "proc-macro2", 2537 | "quote", 2538 | "unicode-ident", 2539 | ] 2540 | 2541 | [[package]] 2542 | name = "sync_wrapper" 2543 | version = "0.1.2" 2544 | source = "registry+https://github.com/rust-lang/crates.io-index" 2545 | checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" 2546 | 2547 | [[package]] 2548 | name = "sync_wrapper" 2549 | version = "1.0.2" 2550 | source = "registry+https://github.com/rust-lang/crates.io-index" 2551 | checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 2552 | 2553 | [[package]] 2554 | name = "synstructure" 2555 | version = "0.13.1" 2556 | source = "registry+https://github.com/rust-lang/crates.io-index" 2557 | checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 2558 | dependencies = [ 2559 | "proc-macro2", 2560 | "quote", 2561 | "syn", 2562 | ] 2563 | 2564 | [[package]] 2565 | name = "thiserror" 2566 | version = "1.0.69" 2567 | source = "registry+https://github.com/rust-lang/crates.io-index" 2568 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 2569 | dependencies = [ 2570 | "thiserror-impl 1.0.69", 2571 | ] 2572 | 2573 | [[package]] 2574 | name = "thiserror" 2575 | version = "2.0.12" 2576 | source = "registry+https://github.com/rust-lang/crates.io-index" 2577 | checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" 2578 | dependencies = [ 2579 | "thiserror-impl 2.0.12", 2580 | ] 2581 | 2582 | [[package]] 2583 | name = "thiserror-impl" 2584 | version = "1.0.69" 2585 | source = "registry+https://github.com/rust-lang/crates.io-index" 2586 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 2587 | dependencies = [ 2588 | "proc-macro2", 2589 | "quote", 2590 | "syn", 2591 | ] 2592 | 2593 | [[package]] 2594 | name = "thiserror-impl" 2595 | version = "2.0.12" 2596 | source = "registry+https://github.com/rust-lang/crates.io-index" 2597 | checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" 2598 | dependencies = [ 2599 | "proc-macro2", 2600 | "quote", 2601 | "syn", 2602 | ] 2603 | 2604 | [[package]] 2605 | name = "thread_local" 2606 | version = "1.1.8" 2607 | source = "registry+https://github.com/rust-lang/crates.io-index" 2608 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 2609 | dependencies = [ 2610 | "cfg-if", 2611 | "once_cell", 2612 | ] 2613 | 2614 | [[package]] 2615 | name = "time" 2616 | version = "0.3.37" 2617 | source = "registry+https://github.com/rust-lang/crates.io-index" 2618 | checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" 2619 | dependencies = [ 2620 | "deranged", 2621 | "itoa", 2622 | "num-conv", 2623 | "powerfmt", 2624 | "serde", 2625 | "time-core", 2626 | "time-macros", 2627 | ] 2628 | 2629 | [[package]] 2630 | name = "time-core" 2631 | version = "0.1.2" 2632 | source = "registry+https://github.com/rust-lang/crates.io-index" 2633 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 2634 | 2635 | [[package]] 2636 | name = "time-macros" 2637 | version = "0.2.19" 2638 | source = "registry+https://github.com/rust-lang/crates.io-index" 2639 | checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" 2640 | dependencies = [ 2641 | "num-conv", 2642 | "time-core", 2643 | ] 2644 | 2645 | [[package]] 2646 | name = "tinystr" 2647 | version = "0.7.6" 2648 | source = "registry+https://github.com/rust-lang/crates.io-index" 2649 | checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 2650 | dependencies = [ 2651 | "displaydoc", 2652 | "zerovec", 2653 | ] 2654 | 2655 | [[package]] 2656 | name = "tokio" 2657 | version = "1.45.1" 2658 | source = "registry+https://github.com/rust-lang/crates.io-index" 2659 | checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" 2660 | dependencies = [ 2661 | "backtrace", 2662 | "bytes", 2663 | "libc", 2664 | "mio", 2665 | "parking_lot", 2666 | "pin-project-lite", 2667 | "signal-hook-registry", 2668 | "socket2", 2669 | "tokio-macros", 2670 | "windows-sys 0.52.0", 2671 | ] 2672 | 2673 | [[package]] 2674 | name = "tokio-macros" 2675 | version = "2.5.0" 2676 | source = "registry+https://github.com/rust-lang/crates.io-index" 2677 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 2678 | dependencies = [ 2679 | "proc-macro2", 2680 | "quote", 2681 | "syn", 2682 | ] 2683 | 2684 | [[package]] 2685 | name = "tokio-rustls" 2686 | version = "0.26.2" 2687 | source = "registry+https://github.com/rust-lang/crates.io-index" 2688 | checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" 2689 | dependencies = [ 2690 | "rustls", 2691 | "tokio", 2692 | ] 2693 | 2694 | [[package]] 2695 | name = "tokio-stream" 2696 | version = "0.1.16" 2697 | source = "registry+https://github.com/rust-lang/crates.io-index" 2698 | checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" 2699 | dependencies = [ 2700 | "futures-core", 2701 | "pin-project-lite", 2702 | "tokio", 2703 | ] 2704 | 2705 | [[package]] 2706 | name = "tokio-test" 2707 | version = "0.4.4" 2708 | source = "registry+https://github.com/rust-lang/crates.io-index" 2709 | checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" 2710 | dependencies = [ 2711 | "async-stream", 2712 | "bytes", 2713 | "futures-core", 2714 | "tokio", 2715 | "tokio-stream", 2716 | ] 2717 | 2718 | [[package]] 2719 | name = "tokio-util" 2720 | version = "0.7.13" 2721 | source = "registry+https://github.com/rust-lang/crates.io-index" 2722 | checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" 2723 | dependencies = [ 2724 | "bytes", 2725 | "futures-core", 2726 | "futures-sink", 2727 | "pin-project-lite", 2728 | "slab", 2729 | "tokio", 2730 | ] 2731 | 2732 | [[package]] 2733 | name = "tonic" 2734 | version = "0.12.3" 2735 | source = "registry+https://github.com/rust-lang/crates.io-index" 2736 | checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" 2737 | dependencies = [ 2738 | "async-stream", 2739 | "async-trait", 2740 | "axum", 2741 | "base64 0.22.1", 2742 | "bytes", 2743 | "h2 0.4.7", 2744 | "http 1.3.1", 2745 | "http-body", 2746 | "http-body-util", 2747 | "hyper", 2748 | "hyper-timeout", 2749 | "hyper-util", 2750 | "percent-encoding", 2751 | "pin-project", 2752 | "prost", 2753 | "socket2", 2754 | "tokio", 2755 | "tokio-stream", 2756 | "tower 0.4.13", 2757 | "tower-layer", 2758 | "tower-service", 2759 | "tracing", 2760 | ] 2761 | 2762 | [[package]] 2763 | name = "tower" 2764 | version = "0.4.13" 2765 | source = "registry+https://github.com/rust-lang/crates.io-index" 2766 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 2767 | dependencies = [ 2768 | "futures-core", 2769 | "futures-util", 2770 | "indexmap 1.9.3", 2771 | "pin-project", 2772 | "pin-project-lite", 2773 | "rand 0.8.5", 2774 | "slab", 2775 | "tokio", 2776 | "tokio-util", 2777 | "tower-layer", 2778 | "tower-service", 2779 | "tracing", 2780 | ] 2781 | 2782 | [[package]] 2783 | name = "tower" 2784 | version = "0.5.1" 2785 | source = "registry+https://github.com/rust-lang/crates.io-index" 2786 | checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" 2787 | dependencies = [ 2788 | "futures-core", 2789 | "futures-util", 2790 | "pin-project-lite", 2791 | "sync_wrapper 0.1.2", 2792 | "tokio", 2793 | "tokio-util", 2794 | "tower-layer", 2795 | "tower-service", 2796 | "tracing", 2797 | ] 2798 | 2799 | [[package]] 2800 | name = "tower-http" 2801 | version = "0.6.2" 2802 | source = "registry+https://github.com/rust-lang/crates.io-index" 2803 | checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" 2804 | dependencies = [ 2805 | "base64 0.22.1", 2806 | "bitflags", 2807 | "bytes", 2808 | "http 1.3.1", 2809 | "http-body", 2810 | "mime", 2811 | "pin-project-lite", 2812 | "tower-layer", 2813 | "tower-service", 2814 | "tracing", 2815 | ] 2816 | 2817 | [[package]] 2818 | name = "tower-layer" 2819 | version = "0.3.3" 2820 | source = "registry+https://github.com/rust-lang/crates.io-index" 2821 | checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 2822 | 2823 | [[package]] 2824 | name = "tower-service" 2825 | version = "0.3.3" 2826 | source = "registry+https://github.com/rust-lang/crates.io-index" 2827 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 2828 | 2829 | [[package]] 2830 | name = "tower-test" 2831 | version = "0.4.0" 2832 | source = "registry+https://github.com/rust-lang/crates.io-index" 2833 | checksum = "a4546773ffeab9e4ea02b8872faa49bb616a80a7da66afc2f32688943f97efa7" 2834 | dependencies = [ 2835 | "futures-util", 2836 | "pin-project", 2837 | "tokio", 2838 | "tokio-test", 2839 | "tower-layer", 2840 | "tower-service", 2841 | ] 2842 | 2843 | [[package]] 2844 | name = "tracing" 2845 | version = "0.1.41" 2846 | source = "registry+https://github.com/rust-lang/crates.io-index" 2847 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 2848 | dependencies = [ 2849 | "log", 2850 | "pin-project-lite", 2851 | "tracing-attributes", 2852 | "tracing-core", 2853 | ] 2854 | 2855 | [[package]] 2856 | name = "tracing-attributes" 2857 | version = "0.1.28" 2858 | source = "registry+https://github.com/rust-lang/crates.io-index" 2859 | checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" 2860 | dependencies = [ 2861 | "proc-macro2", 2862 | "quote", 2863 | "syn", 2864 | ] 2865 | 2866 | [[package]] 2867 | name = "tracing-core" 2868 | version = "0.1.33" 2869 | source = "registry+https://github.com/rust-lang/crates.io-index" 2870 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 2871 | dependencies = [ 2872 | "once_cell", 2873 | "valuable", 2874 | ] 2875 | 2876 | [[package]] 2877 | name = "tracing-log" 2878 | version = "0.2.0" 2879 | source = "registry+https://github.com/rust-lang/crates.io-index" 2880 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 2881 | dependencies = [ 2882 | "log", 2883 | "once_cell", 2884 | "tracing-core", 2885 | ] 2886 | 2887 | [[package]] 2888 | name = "tracing-opentelemetry" 2889 | version = "0.28.0" 2890 | source = "registry+https://github.com/rust-lang/crates.io-index" 2891 | checksum = "97a971f6058498b5c0f1affa23e7ea202057a7301dbff68e968b2d578bcbd053" 2892 | dependencies = [ 2893 | "js-sys", 2894 | "once_cell", 2895 | "opentelemetry", 2896 | "opentelemetry_sdk", 2897 | "smallvec", 2898 | "tracing", 2899 | "tracing-core", 2900 | "tracing-log", 2901 | "tracing-subscriber", 2902 | "web-time", 2903 | ] 2904 | 2905 | [[package]] 2906 | name = "tracing-serde" 2907 | version = "0.2.0" 2908 | source = "registry+https://github.com/rust-lang/crates.io-index" 2909 | checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" 2910 | dependencies = [ 2911 | "serde", 2912 | "tracing-core", 2913 | ] 2914 | 2915 | [[package]] 2916 | name = "tracing-subscriber" 2917 | version = "0.3.19" 2918 | source = "registry+https://github.com/rust-lang/crates.io-index" 2919 | checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" 2920 | dependencies = [ 2921 | "matchers", 2922 | "nu-ansi-term", 2923 | "once_cell", 2924 | "regex", 2925 | "serde", 2926 | "serde_json", 2927 | "sharded-slab", 2928 | "smallvec", 2929 | "thread_local", 2930 | "tracing", 2931 | "tracing-core", 2932 | "tracing-log", 2933 | "tracing-serde", 2934 | ] 2935 | 2936 | [[package]] 2937 | name = "try-lock" 2938 | version = "0.2.5" 2939 | source = "registry+https://github.com/rust-lang/crates.io-index" 2940 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 2941 | 2942 | [[package]] 2943 | name = "typenum" 2944 | version = "1.17.0" 2945 | source = "registry+https://github.com/rust-lang/crates.io-index" 2946 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 2947 | 2948 | [[package]] 2949 | name = "ucd-trie" 2950 | version = "0.1.7" 2951 | source = "registry+https://github.com/rust-lang/crates.io-index" 2952 | checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" 2953 | 2954 | [[package]] 2955 | name = "unicode-ident" 2956 | version = "1.0.14" 2957 | source = "registry+https://github.com/rust-lang/crates.io-index" 2958 | checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" 2959 | 2960 | [[package]] 2961 | name = "unicode-xid" 2962 | version = "0.2.6" 2963 | source = "registry+https://github.com/rust-lang/crates.io-index" 2964 | checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 2965 | 2966 | [[package]] 2967 | name = "unsafe-libyaml" 2968 | version = "0.2.11" 2969 | source = "registry+https://github.com/rust-lang/crates.io-index" 2970 | checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" 2971 | 2972 | [[package]] 2973 | name = "untrusted" 2974 | version = "0.9.0" 2975 | source = "registry+https://github.com/rust-lang/crates.io-index" 2976 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 2977 | 2978 | [[package]] 2979 | name = "url" 2980 | version = "2.5.4" 2981 | source = "registry+https://github.com/rust-lang/crates.io-index" 2982 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 2983 | dependencies = [ 2984 | "form_urlencoded", 2985 | "idna", 2986 | "percent-encoding", 2987 | ] 2988 | 2989 | [[package]] 2990 | name = "utf16_iter" 2991 | version = "1.0.5" 2992 | source = "registry+https://github.com/rust-lang/crates.io-index" 2993 | checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 2994 | 2995 | [[package]] 2996 | name = "utf8_iter" 2997 | version = "1.0.4" 2998 | source = "registry+https://github.com/rust-lang/crates.io-index" 2999 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 3000 | 3001 | [[package]] 3002 | name = "valuable" 3003 | version = "0.1.0" 3004 | source = "registry+https://github.com/rust-lang/crates.io-index" 3005 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 3006 | 3007 | [[package]] 3008 | name = "version_check" 3009 | version = "0.9.5" 3010 | source = "registry+https://github.com/rust-lang/crates.io-index" 3011 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 3012 | 3013 | [[package]] 3014 | name = "want" 3015 | version = "0.3.1" 3016 | source = "registry+https://github.com/rust-lang/crates.io-index" 3017 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 3018 | dependencies = [ 3019 | "try-lock", 3020 | ] 3021 | 3022 | [[package]] 3023 | name = "wasi" 3024 | version = "0.11.0+wasi-snapshot-preview1" 3025 | source = "registry+https://github.com/rust-lang/crates.io-index" 3026 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 3027 | 3028 | [[package]] 3029 | name = "wasi" 3030 | version = "0.13.3+wasi-0.2.2" 3031 | source = "registry+https://github.com/rust-lang/crates.io-index" 3032 | checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" 3033 | dependencies = [ 3034 | "wit-bindgen-rt", 3035 | ] 3036 | 3037 | [[package]] 3038 | name = "wasm-bindgen" 3039 | version = "0.2.97" 3040 | source = "registry+https://github.com/rust-lang/crates.io-index" 3041 | checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" 3042 | dependencies = [ 3043 | "cfg-if", 3044 | "once_cell", 3045 | "wasm-bindgen-macro", 3046 | ] 3047 | 3048 | [[package]] 3049 | name = "wasm-bindgen-backend" 3050 | version = "0.2.97" 3051 | source = "registry+https://github.com/rust-lang/crates.io-index" 3052 | checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" 3053 | dependencies = [ 3054 | "bumpalo", 3055 | "log", 3056 | "once_cell", 3057 | "proc-macro2", 3058 | "quote", 3059 | "syn", 3060 | "wasm-bindgen-shared", 3061 | ] 3062 | 3063 | [[package]] 3064 | name = "wasm-bindgen-macro" 3065 | version = "0.2.97" 3066 | source = "registry+https://github.com/rust-lang/crates.io-index" 3067 | checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" 3068 | dependencies = [ 3069 | "quote", 3070 | "wasm-bindgen-macro-support", 3071 | ] 3072 | 3073 | [[package]] 3074 | name = "wasm-bindgen-macro-support" 3075 | version = "0.2.97" 3076 | source = "registry+https://github.com/rust-lang/crates.io-index" 3077 | checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" 3078 | dependencies = [ 3079 | "proc-macro2", 3080 | "quote", 3081 | "syn", 3082 | "wasm-bindgen-backend", 3083 | "wasm-bindgen-shared", 3084 | ] 3085 | 3086 | [[package]] 3087 | name = "wasm-bindgen-shared" 3088 | version = "0.2.97" 3089 | source = "registry+https://github.com/rust-lang/crates.io-index" 3090 | checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" 3091 | 3092 | [[package]] 3093 | name = "web-time" 3094 | version = "1.1.0" 3095 | source = "registry+https://github.com/rust-lang/crates.io-index" 3096 | checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" 3097 | dependencies = [ 3098 | "js-sys", 3099 | "wasm-bindgen", 3100 | ] 3101 | 3102 | [[package]] 3103 | name = "winapi" 3104 | version = "0.3.9" 3105 | source = "registry+https://github.com/rust-lang/crates.io-index" 3106 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 3107 | dependencies = [ 3108 | "winapi-i686-pc-windows-gnu", 3109 | "winapi-x86_64-pc-windows-gnu", 3110 | ] 3111 | 3112 | [[package]] 3113 | name = "winapi-i686-pc-windows-gnu" 3114 | version = "0.4.0" 3115 | source = "registry+https://github.com/rust-lang/crates.io-index" 3116 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 3117 | 3118 | [[package]] 3119 | name = "winapi-x86_64-pc-windows-gnu" 3120 | version = "0.4.0" 3121 | source = "registry+https://github.com/rust-lang/crates.io-index" 3122 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 3123 | 3124 | [[package]] 3125 | name = "windows" 3126 | version = "0.52.0" 3127 | source = "registry+https://github.com/rust-lang/crates.io-index" 3128 | checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" 3129 | dependencies = [ 3130 | "windows-core", 3131 | "windows-targets", 3132 | ] 3133 | 3134 | [[package]] 3135 | name = "windows-core" 3136 | version = "0.52.0" 3137 | source = "registry+https://github.com/rust-lang/crates.io-index" 3138 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 3139 | dependencies = [ 3140 | "windows-targets", 3141 | ] 3142 | 3143 | [[package]] 3144 | name = "windows-link" 3145 | version = "0.1.0" 3146 | source = "registry+https://github.com/rust-lang/crates.io-index" 3147 | checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" 3148 | 3149 | [[package]] 3150 | name = "windows-sys" 3151 | version = "0.52.0" 3152 | source = "registry+https://github.com/rust-lang/crates.io-index" 3153 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 3154 | dependencies = [ 3155 | "windows-targets", 3156 | ] 3157 | 3158 | [[package]] 3159 | name = "windows-sys" 3160 | version = "0.59.0" 3161 | source = "registry+https://github.com/rust-lang/crates.io-index" 3162 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 3163 | dependencies = [ 3164 | "windows-targets", 3165 | ] 3166 | 3167 | [[package]] 3168 | name = "windows-targets" 3169 | version = "0.52.6" 3170 | source = "registry+https://github.com/rust-lang/crates.io-index" 3171 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 3172 | dependencies = [ 3173 | "windows_aarch64_gnullvm", 3174 | "windows_aarch64_msvc", 3175 | "windows_i686_gnu", 3176 | "windows_i686_gnullvm", 3177 | "windows_i686_msvc", 3178 | "windows_x86_64_gnu", 3179 | "windows_x86_64_gnullvm", 3180 | "windows_x86_64_msvc", 3181 | ] 3182 | 3183 | [[package]] 3184 | name = "windows_aarch64_gnullvm" 3185 | version = "0.52.6" 3186 | source = "registry+https://github.com/rust-lang/crates.io-index" 3187 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 3188 | 3189 | [[package]] 3190 | name = "windows_aarch64_msvc" 3191 | version = "0.52.6" 3192 | source = "registry+https://github.com/rust-lang/crates.io-index" 3193 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 3194 | 3195 | [[package]] 3196 | name = "windows_i686_gnu" 3197 | version = "0.52.6" 3198 | source = "registry+https://github.com/rust-lang/crates.io-index" 3199 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 3200 | 3201 | [[package]] 3202 | name = "windows_i686_gnullvm" 3203 | version = "0.52.6" 3204 | source = "registry+https://github.com/rust-lang/crates.io-index" 3205 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 3206 | 3207 | [[package]] 3208 | name = "windows_i686_msvc" 3209 | version = "0.52.6" 3210 | source = "registry+https://github.com/rust-lang/crates.io-index" 3211 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 3212 | 3213 | [[package]] 3214 | name = "windows_x86_64_gnu" 3215 | version = "0.52.6" 3216 | source = "registry+https://github.com/rust-lang/crates.io-index" 3217 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 3218 | 3219 | [[package]] 3220 | name = "windows_x86_64_gnullvm" 3221 | version = "0.52.6" 3222 | source = "registry+https://github.com/rust-lang/crates.io-index" 3223 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 3224 | 3225 | [[package]] 3226 | name = "windows_x86_64_msvc" 3227 | version = "0.52.6" 3228 | source = "registry+https://github.com/rust-lang/crates.io-index" 3229 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 3230 | 3231 | [[package]] 3232 | name = "wit-bindgen-rt" 3233 | version = "0.33.0" 3234 | source = "registry+https://github.com/rust-lang/crates.io-index" 3235 | checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" 3236 | dependencies = [ 3237 | "bitflags", 3238 | ] 3239 | 3240 | [[package]] 3241 | name = "write16" 3242 | version = "1.0.0" 3243 | source = "registry+https://github.com/rust-lang/crates.io-index" 3244 | checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 3245 | 3246 | [[package]] 3247 | name = "writeable" 3248 | version = "0.5.5" 3249 | source = "registry+https://github.com/rust-lang/crates.io-index" 3250 | checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 3251 | 3252 | [[package]] 3253 | name = "yoke" 3254 | version = "0.7.5" 3255 | source = "registry+https://github.com/rust-lang/crates.io-index" 3256 | checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" 3257 | dependencies = [ 3258 | "serde", 3259 | "stable_deref_trait", 3260 | "yoke-derive", 3261 | "zerofrom", 3262 | ] 3263 | 3264 | [[package]] 3265 | name = "yoke-derive" 3266 | version = "0.7.5" 3267 | source = "registry+https://github.com/rust-lang/crates.io-index" 3268 | checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" 3269 | dependencies = [ 3270 | "proc-macro2", 3271 | "quote", 3272 | "syn", 3273 | "synstructure", 3274 | ] 3275 | 3276 | [[package]] 3277 | name = "zerocopy" 3278 | version = "0.7.35" 3279 | source = "registry+https://github.com/rust-lang/crates.io-index" 3280 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 3281 | dependencies = [ 3282 | "byteorder", 3283 | "zerocopy-derive 0.7.35", 3284 | ] 3285 | 3286 | [[package]] 3287 | name = "zerocopy" 3288 | version = "0.8.23" 3289 | source = "registry+https://github.com/rust-lang/crates.io-index" 3290 | checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" 3291 | dependencies = [ 3292 | "zerocopy-derive 0.8.23", 3293 | ] 3294 | 3295 | [[package]] 3296 | name = "zerocopy-derive" 3297 | version = "0.7.35" 3298 | source = "registry+https://github.com/rust-lang/crates.io-index" 3299 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 3300 | dependencies = [ 3301 | "proc-macro2", 3302 | "quote", 3303 | "syn", 3304 | ] 3305 | 3306 | [[package]] 3307 | name = "zerocopy-derive" 3308 | version = "0.8.23" 3309 | source = "registry+https://github.com/rust-lang/crates.io-index" 3310 | checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" 3311 | dependencies = [ 3312 | "proc-macro2", 3313 | "quote", 3314 | "syn", 3315 | ] 3316 | 3317 | [[package]] 3318 | name = "zerofrom" 3319 | version = "0.1.5" 3320 | source = "registry+https://github.com/rust-lang/crates.io-index" 3321 | checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" 3322 | dependencies = [ 3323 | "zerofrom-derive", 3324 | ] 3325 | 3326 | [[package]] 3327 | name = "zerofrom-derive" 3328 | version = "0.1.5" 3329 | source = "registry+https://github.com/rust-lang/crates.io-index" 3330 | checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" 3331 | dependencies = [ 3332 | "proc-macro2", 3333 | "quote", 3334 | "syn", 3335 | "synstructure", 3336 | ] 3337 | 3338 | [[package]] 3339 | name = "zeroize" 3340 | version = "1.8.1" 3341 | source = "registry+https://github.com/rust-lang/crates.io-index" 3342 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 3343 | 3344 | [[package]] 3345 | name = "zerovec" 3346 | version = "0.10.4" 3347 | source = "registry+https://github.com/rust-lang/crates.io-index" 3348 | checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 3349 | dependencies = [ 3350 | "yoke", 3351 | "zerofrom", 3352 | "zerovec-derive", 3353 | ] 3354 | 3355 | [[package]] 3356 | name = "zerovec-derive" 3357 | version = "0.10.3" 3358 | source = "registry+https://github.com/rust-lang/crates.io-index" 3359 | checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 3360 | dependencies = [ 3361 | "proc-macro2", 3362 | "quote", 3363 | "syn", 3364 | ] 3365 | 3366 | [[package]] 3367 | name = "zstd" 3368 | version = "0.13.2" 3369 | source = "registry+https://github.com/rust-lang/crates.io-index" 3370 | checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" 3371 | dependencies = [ 3372 | "zstd-safe", 3373 | ] 3374 | 3375 | [[package]] 3376 | name = "zstd-safe" 3377 | version = "7.2.1" 3378 | source = "registry+https://github.com/rust-lang/crates.io-index" 3379 | checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" 3380 | dependencies = [ 3381 | "zstd-sys", 3382 | ] 3383 | 3384 | [[package]] 3385 | name = "zstd-sys" 3386 | version = "2.0.13+zstd.1.5.6" 3387 | source = "registry+https://github.com/rust-lang/crates.io-index" 3388 | checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" 3389 | dependencies = [ 3390 | "cc", 3391 | "pkg-config", 3392 | ] 3393 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "controller" 3 | version = "0.16.0" 4 | authors = ["clux "] 5 | edition = "2021" 6 | default-run = "controller" 7 | license = "Apache-2.0" 8 | publish = false 9 | 10 | [[bin]] 11 | doc = false 12 | name = "controller" 13 | path = "src/main.rs" 14 | 15 | [[bin]] 16 | doc = false 17 | name = "crdgen" 18 | path = "src/crdgen.rs" 19 | 20 | [lib] 21 | name = "controller" 22 | path = "src/lib.rs" 23 | 24 | [features] 25 | default = [] 26 | telemetry = ["opentelemetry-otlp"] 27 | 28 | [dependencies] 29 | actix-web = "4.11.0" 30 | futures = "0.3.31" 31 | tokio = { version = "1.45.1", features = ["macros", "rt-multi-thread"] } 32 | k8s-openapi = { version = "0.25.0", features = ["latest"] } 33 | schemars = { version = "0.8.22", features = ["chrono"] } 34 | serde = { version = "1.0.219", features = ["derive"] } 35 | serde_json = "1.0.140" 36 | serde_yaml = "0.9.25" 37 | chrono = { version = "0.4.41", features = ["serde"] } 38 | tracing = "0.1.41" 39 | tracing-subscriber = { version = "0.3.19", features = ["json", "env-filter"] } 40 | tracing-opentelemetry = "0.28.0" 41 | opentelemetry = { version = "0.27.1", features = ["trace"] } 42 | opentelemetry-otlp = { version = "0.27.0", optional = true } 43 | opentelemetry_sdk = { version = "0.27.1", features = ["rt-tokio"] } 44 | thiserror = "2.0.12" 45 | anyhow = "1.0.98" 46 | prometheus-client = "0.23.1" 47 | 48 | [dev-dependencies] 49 | assert-json-diff = "2.0.2" 50 | http = "1" 51 | hyper = "1" 52 | tower-test = "0.4.0" 53 | 54 | [dependencies.kube] 55 | features = ["runtime", "client", "derive"] 56 | version = "1.1.0" 57 | 58 | # testing new releases - ignore 59 | # git = "https://github.com/kube-rs/kube.git" 60 | # branch = "main" 61 | #rev = "19b90ad3a4dbc83e1dd742847c7707333259b1bb" 62 | #path = "../kube/kube" 63 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM cgr.dev/chainguard/static 2 | COPY --chown=nonroot:nonroot ./controller /app/ 3 | EXPOSE 8080 4 | ENTRYPOINT ["/app/controller"] 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2021 The Kube-rs Authors. 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## controller-rs 2 | [![ci](https://github.com/kube-rs/controller-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/kube-rs/controller-rs/actions/workflows/ci.yml) 3 | 4 | A rust kubernetes reference controller for a [`Document` resource](https://github.com/kube-rs/controller-rs/blob/main/yaml/crd.yaml) using [kube](https://github.com/kube-rs/kube/), with observability instrumentation. 5 | 6 | The `Controller` object reconciles `Document` instances when changes to it are detected, writes to its `.status` object, creates associated events, and uses finalizers for guaranteed delete handling. 7 | 8 | ## Installation 9 | 10 | ### CRD 11 | Apply the CRD from [cached file](yaml/crd.yaml), or pipe it from `crdgen` to pickup schema changes: 12 | 13 | ```sh 14 | cargo run --bin crdgen | kubectl apply -f - 15 | ``` 16 | 17 | ### Controller 18 | 19 | Install the controller via `helm` by setting your preferred settings. For defaults: 20 | 21 | ```sh 22 | helm template charts/doc-controller | kubectl apply -f - 23 | kubectl wait --for=condition=available deploy/doc-controller --timeout=30s 24 | kubectl port-forward service/doc-controller 8080:80 25 | ``` 26 | 27 | The helm chart sets up the [container](https://github.com/kube-rs/controller-rs/pkgs/container/controller) built from this repository. 28 | 29 | ### Opentelemetry 30 | 31 | Build and run with `telemetry` feature, or configure it via `helm`: 32 | 33 | ```sh 34 | helm template charts/doc-controller --set tracing.enabled=true | kubectl apply -f - 35 | ``` 36 | 37 | This requires an opentelemetry collector in your cluster. [Tempo](https://github.com/grafana/helm-charts/tree/main/charts/tempo) / [opentelemetry-operator](https://github.com/open-telemetry/opentelemetry-helm-charts/tree/main/charts/opentelemetry-operator) / [grafana agent](https://github.com/grafana/helm-charts/tree/main/charts/agent-operator) should all work out of the box. If your collector does not support grpc otlp you need to change the exporter in [`telemetry.rs`](./src/telemetry.rs). 38 | 39 | Note that the [images are pushed either with or without the telemetry feature](https://hub.docker.com/r/clux/controller/tags/) depending on whether the tag includes `otel`. 40 | 41 | ### Metrics 42 | 43 | Metrics is available on `/metrics` and a `ServiceMonitor` is configurable from the chart: 44 | 45 | ```sh 46 | helm template charts/doc-controller --set serviceMonitor.enabled=true | kubectl apply -f - 47 | ``` 48 | 49 | ## Running 50 | 51 | ### Locally 52 | 53 | ```sh 54 | cargo run 55 | ``` 56 | 57 | or, with optional telemetry: 58 | 59 | ```sh 60 | OPENTELEMETRY_ENDPOINT_URL=https://0.0.0.0:4317 RUST_LOG=info,kube=trace,controller=debug cargo run --features=telemetry 61 | ``` 62 | 63 | ### In-cluster 64 | For prebuilt, edit the [chart values](./charts/doc-controller/values.yaml) or [snapshotted yaml](./yaml/deployment.yaml) and apply as you see fit (like above). 65 | 66 | To develop by building/reloading the deployment in k3d quickly, you can use [`tilt up`](https://tilt.dev/). 67 | 68 | ## Usage 69 | In either of the run scenarios, your app is listening on port `8080`, and it will observe `Document` events. 70 | 71 | Try some of: 72 | 73 | ```sh 74 | kubectl apply -f yaml/instance-lorem.yaml 75 | kubectl delete doc lorem 76 | kubectl edit doc lorem # change hidden 77 | ``` 78 | 79 | The reconciler will run and write the status object on every change. You should see results in the logs of the pod, or on the `.status` object outputs of `kubectl get doc -oyaml`. 80 | 81 | ### Webapp output 82 | The sample web server exposes some example metrics and debug information you can inspect with `curl`. 83 | 84 | ```sh 85 | $ kubectl apply -f yaml/instance-lorem.yaml 86 | $ curl 0.0.0.0:8080/metrics 87 | # HELP doc_controller_reconcile_duration_seconds The duration of reconcile to complete in seconds 88 | # TYPE doc_controller_reconcile_duration_seconds histogram 89 | doc_controller_reconcile_duration_seconds_bucket{le="0.01"} 1 90 | doc_controller_reconcile_duration_seconds_bucket{le="0.1"} 1 91 | doc_controller_reconcile_duration_seconds_bucket{le="0.25"} 1 92 | doc_controller_reconcile_duration_seconds_bucket{le="0.5"} 1 93 | doc_controller_reconcile_duration_seconds_bucket{le="1"} 1 94 | doc_controller_reconcile_duration_seconds_bucket{le="5"} 1 95 | doc_controller_reconcile_duration_seconds_bucket{le="15"} 1 96 | doc_controller_reconcile_duration_seconds_bucket{le="60"} 1 97 | doc_controller_reconcile_duration_seconds_bucket{le="+Inf"} 1 98 | doc_controller_reconcile_duration_seconds_sum 0.013 99 | doc_controller_reconcile_duration_seconds_count 1 100 | # HELP doc_controller_reconciliation_errors_total reconciliation errors 101 | # TYPE doc_controller_reconciliation_errors_total counter 102 | doc_controller_reconciliation_errors_total 0 103 | # HELP doc_controller_reconciliations_total reconciliations 104 | # TYPE doc_controller_reconciliations_total counter 105 | doc_controller_reconciliations_total 1 106 | $ curl 0.0.0.0:8080/ 107 | {"last_event":"2019-07-17T22:31:37.591320068Z"} 108 | ``` 109 | 110 | The metrics will be scraped by prometheus if you setup a`ServiceMonitor` for it. 111 | 112 | ### Events 113 | The example `reconciler` only checks the `.spec.hidden` bool. If it does, it updates the `.status` object to reflect whether or not the instance `is_hidden`. It also sends a Kubernetes event associated with the controller. It is visible at the bottom of `kubectl describe doc samuel`. 114 | 115 | To extend this controller for a real-world setting. Consider looking at the [kube.rs controller guide](https://kube.rs/controllers/intro/). 116 | -------------------------------------------------------------------------------- /Tiltfile: -------------------------------------------------------------------------------- 1 | # Usage default features: 2 | # tilt up 3 | # 4 | # Usage with features: 5 | # tilt up telemetry 6 | config.define_string("features", args=True) 7 | cfg = config.parse() 8 | features = cfg.get('features', "") 9 | print("compiling with features: {}".format(features)) 10 | 11 | IMG = 'kube-rs/controller' 12 | local_resource('compile', 'just compile %s' % features) 13 | docker_build(IMG, '.') 14 | # NB: for the image to be pullable by kubernetes via k3d 15 | k8s_yaml('yaml/crd.yaml') 16 | k8s_yaml(helm('./charts/doc-controller', set=['image.repository=' + IMG])) 17 | k8s_resource('doc-controller', port_forwards=8080) 18 | -------------------------------------------------------------------------------- /charts/doc-controller/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/doc-controller/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: doc-controller 3 | description: document controller sample chart 4 | type: application 5 | version: 0.1.0 6 | appVersion: 0.16.0 7 | -------------------------------------------------------------------------------- /charts/doc-controller/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{- define "controller.name" -}} 2 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 3 | {{- end }} 4 | 5 | {{- define "controller.fullname" -}} 6 | {{- $name := default .Chart.Name .Values.nameOverride }} 7 | {{- $name | trunc 63 | trimSuffix "-" }} 8 | {{- end }} 9 | 10 | {{- define "controller.labels" -}} 11 | {{- include "controller.selectorLabels" . }} 12 | app.kubernetes.io/name: {{ include "controller.name" . }} 13 | app.kubernetes.io/version: {{ .Values.image.tag | default .Chart.AppVersion | quote }} 14 | {{- end }} 15 | 16 | {{- define "controller.selectorLabels" -}} 17 | app: {{ include "controller.name" . }} 18 | {{- end }} 19 | 20 | {{- define "controller.tag" -}} 21 | {{- if .Values.image.tag }} 22 | {{- .Values.image.tag }} 23 | {{- else if .Values.tracing.enabled }} 24 | {{- "otel-" }}{{ .Values.version | default .Chart.AppVersion }} 25 | {{- else }} 26 | {{- .Values.version | default .Chart.AppVersion }} 27 | {{- end }} 28 | {{- end }} 29 | -------------------------------------------------------------------------------- /charts/doc-controller/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: {{ include "controller.fullname" . }} 6 | namespace: {{ required "namespace is required" .Values.namespace }} 7 | labels: 8 | {{- include "controller.labels" . | nindent 4 }} 9 | spec: 10 | replicas: {{ .Values.replicaCount }} 11 | selector: 12 | matchLabels: 13 | {{- include "controller.selectorLabels" . | nindent 6 }} 14 | template: 15 | metadata: 16 | labels: 17 | {{- include "controller.selectorLabels" . | nindent 8 }} 18 | annotations: 19 | kubectl.kubernetes.io/default-container: {{ .Chart.Name }} 20 | {{- if .Values.podAnnotations }} 21 | {{- toYaml .Values.podAnnotations | nindent 8 }} 22 | {{- end }} 23 | spec: 24 | serviceAccountName: {{ include "controller.fullname" . }} 25 | {{- with .Values.imagePullSecrets }} 26 | imagePullSecrets: 27 | {{- toYaml . | nindent 8 }} 28 | {{- end }} 29 | securityContext: 30 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 31 | containers: 32 | - name: {{ .Chart.Name }} 33 | image: {{ .Values.image.repository }}:{{ include "controller.tag" . }} 34 | imagePullPolicy: {{ .Values.image.pullPolicy }} 35 | securityContext: 36 | {{- toYaml .Values.securityContext | nindent 10 }} 37 | resources: 38 | {{- toYaml .Values.resources | nindent 10 }} 39 | ports: 40 | - name: http 41 | containerPort: 8080 42 | protocol: TCP 43 | env: 44 | - name: RUST_LOG 45 | value: {{ .Values.logging.env_filter }} 46 | {{- if .Values.tracing.enabled }} 47 | - name: OPENTELEMETRY_ENDPOINT_URL 48 | value: http://{{ .Values.tracing.service }}.{{ .Values.tracing.namespace }}.svc:{{ .Values.tracing.port }} 49 | {{- end }} 50 | {{- with .Values.env }} 51 | {{- toYaml . | nindent 8 }} 52 | {{- end }} 53 | readinessProbe: 54 | httpGet: 55 | path: /health 56 | port: http 57 | initialDelaySeconds: 5 58 | periodSeconds: 5 59 | -------------------------------------------------------------------------------- /charts/doc-controller/templates/networkpolicy.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.networkPolicy.enabled }} 2 | --- 3 | apiVersion: networking.k8s.io/v1 4 | kind: NetworkPolicy 5 | metadata: 6 | name: {{ include "controller.fullname" . }} 7 | namespace: {{ .Values.namespace }} 8 | labels: 9 | {{- include "controller.labels" . | nindent 4 }} 10 | spec: 11 | podSelector: 12 | matchLabels: 13 | {{- include "controller.selectorLabels" . | nindent 6 }} 14 | policyTypes: 15 | - Ingress 16 | - Egress 17 | egress: 18 | {{- if .Values.tracing.enabled }} 19 | # pushing tracing spans to a collector 20 | - to: 21 | - namespaceSelector: 22 | matchLabels: 23 | name: {{.Values.tracing.namespace }} 24 | ports: 25 | - port: {{ .Values.tracing.port }} 26 | protocol: TCP 27 | {{- end }} 28 | 29 | # Kubernetes apiserver access 30 | - to: 31 | - ipBlock: 32 | {{- range .Values.networkPolicy.apiserver }} 33 | cidr: {{ . }} 34 | {{- end }} 35 | ports: 36 | - port: 443 37 | protocol: TCP 38 | - port: 6443 39 | protocol: TCP 40 | 41 | {{- if .Values.networkPolicy.dns }} 42 | # DNS egress 43 | - to: 44 | - podSelector: 45 | matchLabels: 46 | k8s-app: kube-dns 47 | ports: 48 | - port: 53 49 | protocol: UDP 50 | {{- end }} 51 | 52 | ingress: 53 | {{- with .Values.networkPolicy.prometheus }} 54 | {{- if .enabled }} 55 | # prometheus metrics scraping support 56 | - from: 57 | - namespaceSelector: 58 | matchLabels: 59 | name: {{ .namespace }} 60 | podSelector: 61 | matchLabels: 62 | app: {{ .app }} 63 | ports: 64 | - port: {{ .port }} 65 | protocol: TCP 66 | {{- end }} 67 | {{- end }} 68 | 69 | {{- end }} 70 | -------------------------------------------------------------------------------- /charts/doc-controller/templates/rbac.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create }} 2 | --- 3 | # Scoped service account 4 | apiVersion: v1 5 | kind: ServiceAccount 6 | metadata: 7 | name: {{ include "controller.fullname" . }} 8 | labels: 9 | {{- include "controller.labels" . | nindent 4 }} 10 | {{- with .Values.serviceAccount.annotations }} 11 | annotations: 12 | {{- toYaml . | nindent 4 }} 13 | {{- end }} 14 | namespace: {{ .Values.namespace }} 15 | automountServiceAccountToken: true 16 | {{- end }} 17 | 18 | --- 19 | # Access for the service account 20 | kind: ClusterRole 21 | apiVersion: rbac.authorization.k8s.io/v1 22 | metadata: 23 | name: {{ include "controller.fullname" . }} 24 | rules: 25 | - apiGroups: ["kube.rs"] 26 | resources: ["documents", "documents/status", "documents/finalizers"] 27 | verbs: ["get", "list", "watch", "patch", "update"] 28 | - apiGroups: ["events.k8s.io"] 29 | resources: ["events"] 30 | verbs: ["create"] 31 | 32 | --- 33 | # Binding the role to the account 34 | kind: ClusterRoleBinding 35 | apiVersion: rbac.authorization.k8s.io/v1 36 | metadata: 37 | name: {{ include "controller.fullname" . }} 38 | subjects: 39 | - kind: ServiceAccount 40 | namespace: {{ .Values.namespace }} 41 | name: {{ include "controller.fullname" . }} 42 | roleRef: 43 | kind: ClusterRole 44 | name: {{ include "controller.fullname" . }} 45 | apiGroup: rbac.authorization.k8s.io 46 | -------------------------------------------------------------------------------- /charts/doc-controller/templates/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Expose the http port of the service 3 | apiVersion: v1 4 | kind: Service 5 | metadata: 6 | name: {{ include "controller.fullname" . }} 7 | namespace: {{ .Values.namespace }} 8 | labels: 9 | {{- include "controller.labels" . | nindent 4 }} 10 | {{- with .Values.service.annotations }} 11 | annotations: 12 | {{- toYaml . | nindent 4 }} 13 | {{- end }} 14 | spec: 15 | type: {{ .Values.service.type }} 16 | ports: 17 | - port: {{ .Values.service.port }} 18 | targetPort: 8080 19 | protocol: TCP 20 | name: http 21 | selector: 22 | app: {{ include "controller.fullname" . }} 23 | -------------------------------------------------------------------------------- /charts/doc-controller/templates/servicemonitor.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceMonitor.enabled }} 2 | --- 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: ServiceMonitor 5 | metadata: 6 | name: {{ include "controller.fullname" . }} 7 | namespace: {{ .Values.namespace }} 8 | labels: 9 | {{- include "controller.labels" . | nindent 4 }} 10 | {{- with .Values.service.annotations }} 11 | annotations: 12 | {{- toYaml . | nindent 4 }} 13 | {{- end }} 14 | spec: 15 | endpoints: 16 | - port: http 17 | {{- with .Values.serviceMonitor.interval }} 18 | interval: {{ . }} 19 | {{- end }} 20 | {{- with .Values.serviceMonitor.scrapeTimeout }} 21 | scrapeTimeout: {{ . }} 22 | {{- end }} 23 | honorLabels: true 24 | path: {{ .Values.serviceMonitor.path }} 25 | scheme: {{ .Values.serviceMonitor.scheme }} 26 | {{- with .Values.serviceMonitor.relabelings }} 27 | relabelings: 28 | {{- toYaml . | nindent 6 }} 29 | {{- end }} 30 | {{- with .Values.serviceMonitor.metricRelabelings }} 31 | metricRelabelings: 32 | {{- toYaml . | nindent 6 }} 33 | {{- end }} 34 | jobLabel: {{ include "controller.fullname" . }} 35 | selector: 36 | matchLabels: 37 | {{- include "controller.selectorLabels" . | nindent 6 }} 38 | namespaceSelector: 39 | matchNames: 40 | - {{ .Values.namespace }} 41 | {{- with .Values.serviceMonitor.targetLabels }} 42 | targetLabels: 43 | {{- toYaml . | nindent 4 }} 44 | {{- end }} 45 | {{- end }} 46 | -------------------------------------------------------------------------------- /charts/doc-controller/test.yaml: -------------------------------------------------------------------------------- 1 | image: 2 | repository: clux/controller 3 | pullPolicy: Always 4 | tag: "latest" 5 | namespace: default 6 | -------------------------------------------------------------------------------- /charts/doc-controller/values.yaml: -------------------------------------------------------------------------------- 1 | replicaCount: 1 2 | nameOverride: "" 3 | namespace: "default" 4 | version: "" # pin a specific version 5 | 6 | image: 7 | repository: ghcr.io/kube-rs/controller 8 | pullPolicy: IfNotPresent 9 | 10 | imagePullSecrets: [] 11 | 12 | serviceAccount: 13 | create: true 14 | annotations: {} 15 | podAnnotations: {} 16 | 17 | podSecurityContext: {} 18 | # fsGroup: 2000 19 | securityContext: {} 20 | # capabilities: 21 | # drop: 22 | # - ALL 23 | # readOnlyRootFilesystem: true 24 | # runAsNonRoot: true 25 | # runAsUser: 1000 26 | 27 | # Configure the gRPC opentelemetry push url 28 | tracing: 29 | # Use the telemetry built image and inject OPENTELEMETRY_ENDPOINT_URL 30 | enabled: false 31 | # namespace of the collector 32 | namespace: monitoring 33 | # collector service name 34 | service: promstack-tempo 35 | # collector port for OTLP gRPC 36 | port: 4317 37 | 38 | networkPolicy: 39 | enabled: true 40 | dns: true 41 | # apiserver access: please scope; take addresses from "kubectl get endpoints kubernetes -n default" 42 | apiserver: 43 | - "0.0.0.0/0" # extremely wide-open egress on ports 443 + 6443 44 | prometheus: 45 | enabled: true 46 | namespace: monitoring 47 | app: prometheus 48 | port: http 49 | 50 | logging: 51 | env_filter: info,kube=debug,controller=debug 52 | 53 | env: [] 54 | 55 | service: 56 | type: ClusterIP 57 | port: 80 58 | 59 | resources: 60 | limits: 61 | cpu: 200m 62 | memory: 256Mi 63 | requests: 64 | cpu: 50m 65 | memory: 100Mi 66 | 67 | serviceMonitor: 68 | enabled: false 69 | path: /metrics 70 | scheme: http 71 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | zipkin: 4 | image: openzipkin/zipkin:latest 5 | environment: 6 | - JAVA_OPTS=-Xms512m -Xmx512m -XX:+ExitOnOutOfMemoryError 7 | restart: always 8 | ports: 9 | - "9411:9411" 10 | 11 | otel-collector: 12 | image: otel/opentelemetry-collector:latest 13 | restart: always 14 | command: > 15 | --set=receivers.otlp.protocols.grpc.endpoint=0.0.0.0:4317 16 | --set=exporters.zipkin.endpoint=http://zipkin:9411/api/v2/spans 17 | --set=service.pipelines.traces.receivers=[otlp] 18 | --set=service.pipelines.traces.exporters=[zipkin] 19 | ports: 20 | - "4317:4317" 21 | depends_on: 22 | - zipkin 23 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | [private] 2 | default: 3 | @just --list --unsorted 4 | 5 | # install crd into the cluster 6 | install-crd: generate 7 | kubectl apply -f yaml/crd.yaml 8 | 9 | generate: 10 | cargo run --bin crdgen > yaml/crd.yaml 11 | helm template charts/doc-controller > yaml/deployment.yaml 12 | 13 | # run with opentelemetry 14 | run-telemetry: 15 | docker-compose up -d 16 | OPENTELEMETRY_ENDPOINT_URL=http://127.0.0.1:4317 RUST_LOG=info,kube=debug,controller=debug cargo run --features=telemetry 17 | 18 | # run without opentelemetry 19 | run: 20 | RUST_LOG=info,kube=debug,controller=debug cargo run 21 | 22 | # format with nightly rustfmt 23 | fmt: 24 | cargo +nightly fmt 25 | 26 | # run unit tests 27 | test-unit: 28 | cargo test 29 | # run integration tests 30 | test-integration: install-crd 31 | cargo test -- --ignored 32 | # run telemetry tests 33 | test-telemetry: 34 | OPENTELEMETRY_ENDPOINT_URL=http://127.0.0.1:4317 cargo test --lib --all-features -- get_trace_id_returns_valid_traces --ignored 35 | 36 | # compile for musl (for docker image) 37 | compile features="": 38 | #!/usr/bin/env bash 39 | docker run --rm \ 40 | -v cargo-cache:/root/.cargo \ 41 | -v $PWD:/volume \ 42 | -w /volume \ 43 | -t clux/muslrust:stable \ 44 | cargo build --release --features={{features}} --bin controller 45 | cp target/x86_64-unknown-linux-musl/release/controller . 46 | 47 | [private] 48 | _build features="": 49 | just compile {{features}} 50 | docker build -t clux/controller:local . 51 | 52 | # docker build base 53 | build-base: (_build "") 54 | # docker build with telemetry 55 | build-otel: (_build "telemetry") 56 | 57 | 58 | # local helper for test-telemetry and run-telemetry 59 | # forward grpc otel port from svc/promstack-tempo in monitoring 60 | forward-tempo: 61 | kubectl port-forward -n monitoring svc/promstack-tempo 55680:4317 62 | -------------------------------------------------------------------------------- /release.toml: -------------------------------------------------------------------------------- 1 | # Release process 2 | # 3 | # Versions are bumped in both Cargo.toml and Chart.yaml simultaneously through cargo-release 4 | # 5 | # cargo release patch --execute 6 | 7 | # Reference 8 | # https://github.com/crate-ci/cargo-release/blob/master/docs/reference.md 9 | 10 | pre-release-replacements = [ 11 | {file="charts/doc-controller/Chart.yaml", search="appVersion: .*", replace="appVersion: {{version}}"}, 12 | ] 13 | pre-release-hook = ["just", "generate"] 14 | pre-release-commit-message = "release {{version}}" 15 | push = false 16 | tag = true 17 | tag-name = "{{version}}" 18 | sign-tag = true 19 | sign-commit = true 20 | enable-all-features = true 21 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | overflow_delimited_expr = true 2 | newline_style = "Unix" 3 | imports_granularity = "Crate" 4 | reorder_impl_items = true 5 | fn_single_line = false 6 | blank_lines_upper_bound = 2 7 | ignore = [ 8 | ] 9 | comment_width = 110 10 | max_width = 110 11 | inline_attribute_width = 80 12 | -------------------------------------------------------------------------------- /src/controller.rs: -------------------------------------------------------------------------------- 1 | use crate::{telemetry, Error, Metrics, Result}; 2 | use chrono::{DateTime, Utc}; 3 | use futures::StreamExt; 4 | use kube::{ 5 | api::{Api, ListParams, Patch, PatchParams, ResourceExt}, 6 | client::Client, 7 | runtime::{ 8 | controller::{Action, Controller}, 9 | events::{Event, EventType, Recorder, Reporter}, 10 | finalizer::{finalizer, Event as Finalizer}, 11 | watcher::Config, 12 | }, 13 | CustomResource, Resource, 14 | }; 15 | use schemars::JsonSchema; 16 | use serde::{Deserialize, Serialize}; 17 | use serde_json::json; 18 | use std::sync::Arc; 19 | use tokio::{sync::RwLock, time::Duration}; 20 | use tracing::*; 21 | 22 | pub static DOCUMENT_FINALIZER: &str = "documents.kube.rs"; 23 | 24 | /// Generate the Kubernetes wrapper struct `Document` from our Spec and Status struct 25 | /// 26 | /// This provides a hook for generating the CRD yaml (in crdgen.rs) 27 | /// NB: CustomResource generates a pub struct Document here 28 | /// To query for documents.kube.rs with kube, use Api. 29 | #[derive(CustomResource, Deserialize, Serialize, Clone, Debug, JsonSchema)] 30 | #[cfg_attr(test, derive(Default))] 31 | #[kube(kind = "Document", group = "kube.rs", version = "v1", namespaced)] 32 | #[kube(status = "DocumentStatus", shortname = "doc")] 33 | pub struct DocumentSpec { 34 | pub title: String, 35 | pub hide: bool, 36 | pub content: String, 37 | } 38 | /// The status object of `Document` 39 | #[derive(Deserialize, Serialize, Clone, Default, Debug, JsonSchema)] 40 | pub struct DocumentStatus { 41 | pub hidden: bool, 42 | } 43 | 44 | impl Document { 45 | fn was_hidden(&self) -> bool { 46 | self.status.as_ref().map(|s| s.hidden).unwrap_or(false) 47 | } 48 | } 49 | 50 | // Context for our reconciler 51 | #[derive(Clone)] 52 | pub struct Context { 53 | /// Kubernetes client 54 | pub client: Client, 55 | /// Event recorder 56 | pub recorder: Recorder, 57 | /// Diagnostics read by the web server 58 | pub diagnostics: Arc>, 59 | /// Prometheus metrics 60 | pub metrics: Arc, 61 | } 62 | 63 | #[instrument(skip(ctx, doc), fields(trace_id))] 64 | async fn reconcile(doc: Arc, ctx: Arc) -> Result { 65 | let trace_id = telemetry::get_trace_id(); 66 | if trace_id != opentelemetry::trace::TraceId::INVALID { 67 | Span::current().record("trace_id", field::display(&trace_id)); 68 | } 69 | let _timer = ctx.metrics.reconcile.count_and_measure(&trace_id); 70 | ctx.diagnostics.write().await.last_event = Utc::now(); 71 | let ns = doc.namespace().unwrap(); // doc is namespace scoped 72 | let docs: Api = Api::namespaced(ctx.client.clone(), &ns); 73 | 74 | info!("Reconciling Document \"{}\" in {}", doc.name_any(), ns); 75 | finalizer(&docs, DOCUMENT_FINALIZER, doc, |event| async { 76 | match event { 77 | Finalizer::Apply(doc) => doc.reconcile(ctx.clone()).await, 78 | Finalizer::Cleanup(doc) => doc.cleanup(ctx.clone()).await, 79 | } 80 | }) 81 | .await 82 | .map_err(|e| Error::FinalizerError(Box::new(e))) 83 | } 84 | 85 | fn error_policy(doc: Arc, error: &Error, ctx: Arc) -> Action { 86 | warn!("reconcile failed: {:?}", error); 87 | ctx.metrics.reconcile.set_failure(&doc, error); 88 | Action::requeue(Duration::from_secs(5 * 60)) 89 | } 90 | 91 | impl Document { 92 | // Reconcile (for non-finalizer related changes) 93 | async fn reconcile(&self, ctx: Arc) -> Result { 94 | let client = ctx.client.clone(); 95 | let oref = self.object_ref(&()); 96 | let ns = self.namespace().unwrap(); 97 | let name = self.name_any(); 98 | let docs: Api = Api::namespaced(client, &ns); 99 | 100 | let should_hide = self.spec.hide; 101 | if !self.was_hidden() && should_hide { 102 | // send an event once per hide 103 | ctx.recorder 104 | .publish( 105 | &Event { 106 | type_: EventType::Normal, 107 | reason: "HideRequested".into(), 108 | note: Some(format!("Hiding `{name}`")), 109 | action: "Hiding".into(), 110 | secondary: None, 111 | }, 112 | &oref, 113 | ) 114 | .await 115 | .map_err(Error::KubeError)?; 116 | } 117 | if name == "illegal" { 118 | return Err(Error::IllegalDocument); // error names show up in metrics 119 | } 120 | // always overwrite status object with what we saw 121 | let new_status = Patch::Apply(json!({ 122 | "apiVersion": "kube.rs/v1", 123 | "kind": "Document", 124 | "status": DocumentStatus { 125 | hidden: should_hide, 126 | } 127 | })); 128 | let ps = PatchParams::apply("cntrlr").force(); 129 | let _o = docs 130 | .patch_status(&name, &ps, &new_status) 131 | .await 132 | .map_err(Error::KubeError)?; 133 | 134 | // If no events were received, check back every 5 minutes 135 | Ok(Action::requeue(Duration::from_secs(5 * 60))) 136 | } 137 | 138 | // Finalizer cleanup (the object was deleted, ensure nothing is orphaned) 139 | async fn cleanup(&self, ctx: Arc) -> Result { 140 | let oref = self.object_ref(&()); 141 | // Document doesn't have any real cleanup, so we just publish an event 142 | ctx.recorder 143 | .publish( 144 | &Event { 145 | type_: EventType::Normal, 146 | reason: "DeleteRequested".into(), 147 | note: Some(format!("Delete `{}`", self.name_any())), 148 | action: "Deleting".into(), 149 | secondary: None, 150 | }, 151 | &oref, 152 | ) 153 | .await 154 | .map_err(Error::KubeError)?; 155 | Ok(Action::await_change()) 156 | } 157 | } 158 | 159 | /// Diagnostics to be exposed by the web server 160 | #[derive(Clone, Serialize)] 161 | pub struct Diagnostics { 162 | #[serde(deserialize_with = "from_ts")] 163 | pub last_event: DateTime, 164 | #[serde(skip)] 165 | pub reporter: Reporter, 166 | } 167 | impl Default for Diagnostics { 168 | fn default() -> Self { 169 | Self { 170 | last_event: Utc::now(), 171 | reporter: "doc-controller".into(), 172 | } 173 | } 174 | } 175 | impl Diagnostics { 176 | fn recorder(&self, client: Client) -> Recorder { 177 | Recorder::new(client, self.reporter.clone()) 178 | } 179 | } 180 | 181 | /// State shared between the controller and the web server 182 | #[derive(Clone, Default)] 183 | pub struct State { 184 | /// Diagnostics populated by the reconciler 185 | diagnostics: Arc>, 186 | /// Metrics 187 | metrics: Arc, 188 | } 189 | 190 | /// State wrapper around the controller outputs for the web server 191 | impl State { 192 | /// Metrics getter 193 | pub fn metrics(&self) -> String { 194 | let mut buffer = String::new(); 195 | let registry = &*self.metrics.registry; 196 | prometheus_client::encoding::text::encode(&mut buffer, registry).unwrap(); 197 | buffer 198 | } 199 | 200 | /// State getter 201 | pub async fn diagnostics(&self) -> Diagnostics { 202 | self.diagnostics.read().await.clone() 203 | } 204 | 205 | // Create a Controller Context that can update State 206 | pub async fn to_context(&self, client: Client) -> Arc { 207 | Arc::new(Context { 208 | client: client.clone(), 209 | recorder: self.diagnostics.read().await.recorder(client), 210 | metrics: self.metrics.clone(), 211 | diagnostics: self.diagnostics.clone(), 212 | }) 213 | } 214 | } 215 | 216 | /// Initialize the controller and shared state (given the crd is installed) 217 | pub async fn run(state: State) { 218 | let client = Client::try_default().await.expect("failed to create kube Client"); 219 | let docs = Api::::all(client.clone()); 220 | if let Err(e) = docs.list(&ListParams::default().limit(1)).await { 221 | error!("CRD is not queryable; {e:?}. Is the CRD installed?"); 222 | info!("Installation: cargo run --bin crdgen | kubectl apply -f -"); 223 | std::process::exit(1); 224 | } 225 | Controller::new(docs, Config::default().any_semantic()) 226 | .shutdown_on_signal() 227 | .run(reconcile, error_policy, state.to_context(client).await) 228 | .filter_map(|x| async move { std::result::Result::ok(x) }) 229 | .for_each(|_| futures::future::ready(())) 230 | .await; 231 | } 232 | 233 | // Mock tests relying on fixtures.rs and its primitive apiserver mocks 234 | #[cfg(test)] 235 | mod test { 236 | use super::{error_policy, reconcile, Context, Document}; 237 | use crate::{ 238 | fixtures::{timeout_after_1s, Scenario}, 239 | metrics::ErrorLabels, 240 | }; 241 | use std::sync::Arc; 242 | 243 | #[tokio::test] 244 | async fn documents_without_finalizer_gets_a_finalizer() { 245 | let (testctx, fakeserver) = Context::test(); 246 | let doc = Document::test(); 247 | let mocksrv = fakeserver.run(Scenario::FinalizerCreation(doc.clone())); 248 | reconcile(Arc::new(doc), testctx).await.expect("reconciler"); 249 | timeout_after_1s(mocksrv).await; 250 | } 251 | 252 | #[tokio::test] 253 | async fn finalized_doc_causes_status_patch() { 254 | let (testctx, fakeserver) = Context::test(); 255 | let doc = Document::test().finalized(); 256 | let mocksrv = fakeserver.run(Scenario::StatusPatch(doc.clone())); 257 | reconcile(Arc::new(doc), testctx).await.expect("reconciler"); 258 | timeout_after_1s(mocksrv).await; 259 | } 260 | 261 | #[tokio::test] 262 | async fn finalized_doc_with_hide_causes_event_and_hide_patch() { 263 | let (testctx, fakeserver) = Context::test(); 264 | let doc = Document::test().finalized().needs_hide(); 265 | let scenario = Scenario::EventPublishThenStatusPatch("HideRequested".into(), doc.clone()); 266 | let mocksrv = fakeserver.run(scenario); 267 | reconcile(Arc::new(doc), testctx).await.expect("reconciler"); 268 | timeout_after_1s(mocksrv).await; 269 | } 270 | 271 | #[tokio::test] 272 | async fn finalized_doc_with_delete_timestamp_causes_delete() { 273 | let (testctx, fakeserver) = Context::test(); 274 | let doc = Document::test().finalized().needs_delete(); 275 | let mocksrv = fakeserver.run(Scenario::Cleanup("DeleteRequested".into(), doc.clone())); 276 | reconcile(Arc::new(doc), testctx).await.expect("reconciler"); 277 | timeout_after_1s(mocksrv).await; 278 | } 279 | 280 | #[tokio::test] 281 | async fn illegal_doc_reconcile_errors_which_bumps_failure_metric() { 282 | let (testctx, fakeserver) = Context::test(); 283 | let doc = Arc::new(Document::illegal().finalized()); 284 | let mocksrv = fakeserver.run(Scenario::RadioSilence); 285 | let res = reconcile(doc.clone(), testctx.clone()).await; 286 | timeout_after_1s(mocksrv).await; 287 | assert!(res.is_err(), "apply reconciler fails on illegal doc"); 288 | let err = res.unwrap_err(); 289 | assert!(err.to_string().contains("IllegalDocument")); 290 | // calling error policy with the reconciler error should cause the correct metric to be set 291 | error_policy(doc.clone(), &err, testctx.clone()); 292 | let err_labels = ErrorLabels { 293 | instance: "illegal".into(), 294 | error: "finalizererror(applyfailed(illegaldocument))".into(), 295 | }; 296 | let metrics = &testctx.metrics.reconcile; 297 | let failures = metrics.failures.get_or_create(&err_labels).get(); 298 | assert_eq!(failures, 1); 299 | } 300 | 301 | // Integration test without mocks 302 | use kube::api::{Api, ListParams, Patch, PatchParams}; 303 | #[tokio::test] 304 | #[ignore = "uses k8s current-context"] 305 | async fn integration_reconcile_should_set_status_and_send_event() { 306 | let client = kube::Client::try_default().await.unwrap(); 307 | let ctx = super::State::default().to_context(client.clone()).await; 308 | 309 | // create a test doc 310 | let doc = Document::test().finalized().needs_hide(); 311 | let docs: Api = Api::namespaced(client.clone(), "default"); 312 | let ssapply = PatchParams::apply("ctrltest"); 313 | let patch = Patch::Apply(doc.clone()); 314 | docs.patch("test", &ssapply, &patch).await.unwrap(); 315 | 316 | // reconcile it (as if it was just applied to the cluster like this) 317 | reconcile(Arc::new(doc), ctx).await.unwrap(); 318 | 319 | // verify side-effects happened 320 | let output = docs.get_status("test").await.unwrap(); 321 | assert!(output.status.is_some()); 322 | // verify hide event was found 323 | let events: Api = Api::all(client.clone()); 324 | let opts = ListParams::default().fields("involvedObject.kind=Document,involvedObject.name=test"); 325 | let event = events 326 | .list(&opts) 327 | .await 328 | .unwrap() 329 | .into_iter() 330 | .filter(|e| e.reason.as_deref() == Some("HideRequested")) 331 | .last() 332 | .unwrap(); 333 | dbg!("got ev: {:?}", &event); 334 | assert_eq!(event.action.as_deref(), Some("Hiding")); 335 | } 336 | } 337 | -------------------------------------------------------------------------------- /src/crdgen.rs: -------------------------------------------------------------------------------- 1 | use kube::CustomResourceExt; 2 | fn main() { 3 | print!("{}", serde_yaml::to_string(&controller::Document::crd()).unwrap()) 4 | } 5 | -------------------------------------------------------------------------------- /src/fixtures.rs: -------------------------------------------------------------------------------- 1 | //! Helper methods only available for tests 2 | use crate::{Context, Document, DocumentSpec, DocumentStatus, Result, DOCUMENT_FINALIZER}; 3 | use assert_json_diff::assert_json_include; 4 | use http::{Request, Response}; 5 | use kube::{client::Body, runtime::events::Recorder, Client, Resource, ResourceExt}; 6 | use std::sync::Arc; 7 | 8 | impl Document { 9 | /// A document that will cause the reconciler to fail 10 | pub fn illegal() -> Self { 11 | let mut d = Document::new("illegal", DocumentSpec::default()); 12 | d.meta_mut().namespace = Some("default".into()); 13 | d 14 | } 15 | 16 | /// A normal test document 17 | pub fn test() -> Self { 18 | let mut d = Document::new("test", DocumentSpec::default()); 19 | d.meta_mut().namespace = Some("default".into()); 20 | d 21 | } 22 | 23 | /// Modify document to be set to hide 24 | pub fn needs_hide(mut self) -> Self { 25 | self.spec.hide = true; 26 | self 27 | } 28 | 29 | /// Modify document to set a deletion timestamp 30 | pub fn needs_delete(mut self) -> Self { 31 | use chrono::prelude::{DateTime, TimeZone, Utc}; 32 | let now: DateTime = Utc.with_ymd_and_hms(2017, 04, 02, 12, 50, 32).unwrap(); 33 | use k8s_openapi::apimachinery::pkg::apis::meta::v1::Time; 34 | self.meta_mut().deletion_timestamp = Some(Time(now)); 35 | self 36 | } 37 | 38 | /// Modify a document to have the expected finalizer 39 | pub fn finalized(mut self) -> Self { 40 | self.finalizers_mut().push(DOCUMENT_FINALIZER.to_string()); 41 | self 42 | } 43 | 44 | /// Modify a document to have an expected status 45 | pub fn with_status(mut self, status: DocumentStatus) -> Self { 46 | self.status = Some(status); 47 | self 48 | } 49 | } 50 | 51 | // We wrap tower_test::mock::Handle 52 | type ApiServerHandle = tower_test::mock::Handle, Response>; 53 | pub struct ApiServerVerifier(ApiServerHandle); 54 | 55 | /// Scenarios we test for in ApiServerVerifier 56 | pub enum Scenario { 57 | /// objects without finalizers will get a finalizer applied (and not call the apply loop) 58 | FinalizerCreation(Document), 59 | /// objects that do not fail and do not cause publishes will only patch 60 | StatusPatch(Document), 61 | /// finalized objects with hide set causes both an event and then a hide patch 62 | EventPublishThenStatusPatch(String, Document), 63 | /// finalized objects "with errors" (i.e. the "illegal" object) will short circuit the apply loop 64 | RadioSilence, 65 | /// objects with a deletion timestamp will run the cleanup loop sending event and removing the finalizer 66 | Cleanup(String, Document), 67 | } 68 | 69 | pub async fn timeout_after_1s(handle: tokio::task::JoinHandle<()>) { 70 | tokio::time::timeout(std::time::Duration::from_secs(1), handle) 71 | .await 72 | .expect("timeout on mock apiserver") 73 | .expect("scenario succeeded") 74 | } 75 | 76 | impl ApiServerVerifier { 77 | /// Tests only get to run specific scenarios that has matching handlers 78 | /// 79 | /// This setup makes it easy to handle multiple requests by chaining handlers together. 80 | /// 81 | /// NB: If the controller is making more calls than we are handling in the scenario, 82 | /// you then typically see a `KubeError(Service(Closed(())))` from the reconciler. 83 | /// 84 | /// You should await the `JoinHandle` (with a timeout) from this function to ensure that the 85 | /// scenario runs to completion (i.e. all expected calls were responded to), 86 | /// using the timeout to catch missing api calls to Kubernetes. 87 | pub fn run(self, scenario: Scenario) -> tokio::task::JoinHandle<()> { 88 | tokio::spawn(async move { 89 | // moving self => one scenario per test 90 | match scenario { 91 | Scenario::FinalizerCreation(doc) => self.handle_finalizer_creation(doc).await, 92 | Scenario::StatusPatch(doc) => self.handle_status_patch(doc).await, 93 | Scenario::EventPublishThenStatusPatch(reason, doc) => { 94 | self.handle_event_create(reason) 95 | .await 96 | .unwrap() 97 | .handle_status_patch(doc) 98 | .await 99 | } 100 | Scenario::RadioSilence => Ok(self), 101 | Scenario::Cleanup(reason, doc) => { 102 | self.handle_event_create(reason) 103 | .await 104 | .unwrap() 105 | .handle_finalizer_removal(doc) 106 | .await 107 | } 108 | } 109 | .expect("scenario completed without errors"); 110 | }) 111 | } 112 | 113 | // chainable scenario handlers 114 | 115 | async fn handle_finalizer_creation(mut self, doc: Document) -> Result { 116 | let (request, send) = self.0.next_request().await.expect("service not called"); 117 | // We expect a json patch to the specified document adding our finalizer 118 | assert_eq!(request.method(), http::Method::PATCH); 119 | assert_eq!( 120 | request.uri().to_string(), 121 | format!( 122 | "/apis/kube.rs/v1/namespaces/default/documents/{}?", 123 | doc.name_any() 124 | ) 125 | ); 126 | let expected_patch = serde_json::json!([ 127 | { "op": "test", "path": "/metadata/finalizers", "value": null }, 128 | { "op": "add", "path": "/metadata/finalizers", "value": vec![DOCUMENT_FINALIZER] } 129 | ]); 130 | let req_body = request.into_body().collect_bytes().await.unwrap(); 131 | let runtime_patch: serde_json::Value = 132 | serde_json::from_slice(&req_body).expect("valid document from runtime"); 133 | assert_json_include!(actual: runtime_patch, expected: expected_patch); 134 | 135 | let response = serde_json::to_vec(&doc.finalized()).unwrap(); // respond as the apiserver would have 136 | send.send_response(Response::builder().body(Body::from(response)).unwrap()); 137 | Ok(self) 138 | } 139 | 140 | async fn handle_finalizer_removal(mut self, doc: Document) -> Result { 141 | let (request, send) = self.0.next_request().await.expect("service not called"); 142 | // We expect a json patch to the specified document removing our finalizer (at index 0) 143 | assert_eq!(request.method(), http::Method::PATCH); 144 | assert_eq!( 145 | request.uri().to_string(), 146 | format!( 147 | "/apis/kube.rs/v1/namespaces/default/documents/{}?", 148 | doc.name_any() 149 | ) 150 | ); 151 | let expected_patch = serde_json::json!([ 152 | { "op": "test", "path": "/metadata/finalizers/0", "value": DOCUMENT_FINALIZER }, 153 | { "op": "remove", "path": "/metadata/finalizers/0", "path": "/metadata/finalizers/0" } 154 | ]); 155 | let req_body = request.into_body().collect_bytes().await.unwrap(); 156 | let runtime_patch: serde_json::Value = 157 | serde_json::from_slice(&req_body).expect("valid document from runtime"); 158 | assert_json_include!(actual: runtime_patch, expected: expected_patch); 159 | 160 | let response = serde_json::to_vec(&doc).unwrap(); // respond as the apiserver would have 161 | send.send_response(Response::builder().body(Body::from(response)).unwrap()); 162 | Ok(self) 163 | } 164 | 165 | async fn handle_event_create(mut self, reason: String) -> Result { 166 | let (request, send) = self.0.next_request().await.expect("service not called"); 167 | assert_eq!(request.method(), http::Method::POST); 168 | assert_eq!( 169 | request.uri().to_string(), 170 | format!("/apis/events.k8s.io/v1/namespaces/default/events?") 171 | ); 172 | // verify the event reason matches the expected 173 | let req_body = request.into_body().collect_bytes().await.unwrap(); 174 | let postdata: serde_json::Value = 175 | serde_json::from_slice(&req_body).expect("valid event from runtime"); 176 | dbg!("postdata for event: {}", postdata.clone()); 177 | assert_eq!( 178 | postdata.get("reason").unwrap().as_str().map(String::from), 179 | Some(reason) 180 | ); 181 | // then pass through the body 182 | send.send_response(Response::builder().body(Body::from(req_body)).unwrap()); 183 | Ok(self) 184 | } 185 | 186 | async fn handle_status_patch(mut self, doc: Document) -> Result { 187 | let (request, send) = self.0.next_request().await.expect("service not called"); 188 | assert_eq!(request.method(), http::Method::PATCH); 189 | assert_eq!( 190 | request.uri().to_string(), 191 | format!( 192 | "/apis/kube.rs/v1/namespaces/default/documents/{}/status?&force=true&fieldManager=cntrlr", 193 | doc.name_any() 194 | ) 195 | ); 196 | let req_body = request.into_body().collect_bytes().await.unwrap(); 197 | let json: serde_json::Value = serde_json::from_slice(&req_body).expect("patch_status object is json"); 198 | let status_json = json.get("status").expect("status object").clone(); 199 | let status: DocumentStatus = serde_json::from_value(status_json).expect("valid status"); 200 | assert_eq!(status.hidden, doc.spec.hide, "status.hidden iff doc.spec.hide"); 201 | let response = serde_json::to_vec(&doc.with_status(status)).unwrap(); 202 | // pass through document "patch accepted" 203 | send.send_response(Response::builder().body(Body::from(response)).unwrap()); 204 | Ok(self) 205 | } 206 | } 207 | 208 | impl Context { 209 | // Create a test context with a mocked kube client, locally registered metrics and default diagnostics 210 | pub fn test() -> (Arc, ApiServerVerifier) { 211 | let (mock_service, handle) = tower_test::mock::pair::, Response>(); 212 | let mock_client = Client::new(mock_service, "default"); 213 | let mock_recorder = Recorder::new(mock_client.clone(), "doc-ctrl-test".into()); 214 | let ctx = Self { 215 | client: mock_client, 216 | metrics: Arc::default(), 217 | diagnostics: Arc::default(), 218 | recorder: mock_recorder, 219 | }; 220 | (Arc::new(ctx), ApiServerVerifier(handle)) 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Error, Debug)] 4 | pub enum Error { 5 | #[error("SerializationError: {0}")] 6 | SerializationError(#[source] serde_json::Error), 7 | 8 | #[error("Kube Error: {0}")] 9 | KubeError(#[source] kube::Error), 10 | 11 | #[error("Finalizer Error: {0}")] 12 | // NB: awkward type because finalizer::Error embeds the reconciler error (which is this) 13 | // so boxing this error to break cycles 14 | FinalizerError(#[source] Box>), 15 | 16 | #[error("IllegalDocument")] 17 | IllegalDocument, 18 | } 19 | pub type Result = std::result::Result; 20 | 21 | impl Error { 22 | pub fn metric_label(&self) -> String { 23 | format!("{self:?}").to_lowercase() 24 | } 25 | } 26 | 27 | /// Expose all controller components used by main 28 | pub mod controller; 29 | pub use crate::controller::*; 30 | 31 | /// Log and trace integrations 32 | pub mod telemetry; 33 | 34 | /// Metrics 35 | mod metrics; 36 | pub use metrics::Metrics; 37 | 38 | #[cfg(test)] pub mod fixtures; 39 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports, unused_variables)] 2 | use actix_web::{get, middleware, web::Data, App, HttpRequest, HttpResponse, HttpServer, Responder}; 3 | pub use controller::{self, telemetry, State}; 4 | 5 | #[get("/metrics")] 6 | async fn metrics(c: Data, _req: HttpRequest) -> impl Responder { 7 | let metrics = c.metrics(); 8 | HttpResponse::Ok() 9 | .content_type("application/openmetrics-text; version=1.0.0; charset=utf-8") 10 | .body(metrics) 11 | } 12 | 13 | #[get("/health")] 14 | async fn health(_: HttpRequest) -> impl Responder { 15 | HttpResponse::Ok().json("healthy") 16 | } 17 | 18 | #[get("/")] 19 | async fn index(c: Data, _req: HttpRequest) -> impl Responder { 20 | let d = c.diagnostics().await; 21 | HttpResponse::Ok().json(&d) 22 | } 23 | 24 | #[tokio::main] 25 | async fn main() -> anyhow::Result<()> { 26 | telemetry::init().await; 27 | 28 | // Initiatilize Kubernetes controller state 29 | let state = State::default(); 30 | let controller = controller::run(state.clone()); 31 | 32 | // Start web server 33 | let server = HttpServer::new(move || { 34 | App::new() 35 | .app_data(Data::new(state.clone())) 36 | .wrap(middleware::Logger::default().exclude("/health")) 37 | .service(index) 38 | .service(health) 39 | .service(metrics) 40 | }) 41 | .bind("0.0.0.0:8080")? 42 | .shutdown_timeout(5); 43 | 44 | // Both runtimes implements graceful shutdown, so poll until both are done 45 | tokio::join!(controller, server.run()).1?; 46 | Ok(()) 47 | } 48 | -------------------------------------------------------------------------------- /src/metrics.rs: -------------------------------------------------------------------------------- 1 | use crate::{Document, Error}; 2 | use kube::ResourceExt; 3 | use opentelemetry::trace::TraceId; 4 | use prometheus_client::{ 5 | encoding::EncodeLabelSet, 6 | metrics::{counter::Counter, exemplar::HistogramWithExemplars, family::Family}, 7 | registry::{Registry, Unit}, 8 | }; 9 | use std::sync::Arc; 10 | use tokio::time::Instant; 11 | 12 | #[derive(Clone)] 13 | pub struct Metrics { 14 | pub reconcile: ReconcileMetrics, 15 | pub registry: Arc, 16 | } 17 | 18 | impl Default for Metrics { 19 | fn default() -> Self { 20 | let mut registry = Registry::with_prefix("doc_ctrl_reconcile"); 21 | let reconcile = ReconcileMetrics::default().register(&mut registry); 22 | Self { 23 | registry: Arc::new(registry), 24 | reconcile, 25 | } 26 | } 27 | } 28 | 29 | #[derive(Clone, Hash, PartialEq, Eq, EncodeLabelSet, Debug, Default)] 30 | pub struct TraceLabel { 31 | pub trace_id: String, 32 | } 33 | impl TryFrom<&TraceId> for TraceLabel { 34 | type Error = anyhow::Error; 35 | 36 | fn try_from(id: &TraceId) -> Result { 37 | if std::matches!(id, &TraceId::INVALID) { 38 | anyhow::bail!("invalid trace id") 39 | } else { 40 | let trace_id = id.to_string(); 41 | Ok(Self { trace_id }) 42 | } 43 | } 44 | } 45 | 46 | #[derive(Clone)] 47 | pub struct ReconcileMetrics { 48 | pub runs: Counter, 49 | pub failures: Family, 50 | pub duration: HistogramWithExemplars, 51 | } 52 | 53 | impl Default for ReconcileMetrics { 54 | fn default() -> Self { 55 | Self { 56 | runs: Counter::default(), 57 | failures: Family::::default(), 58 | duration: HistogramWithExemplars::new([0.01, 0.1, 0.25, 0.5, 1., 5., 15., 60.].into_iter()), 59 | } 60 | } 61 | } 62 | 63 | #[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)] 64 | pub struct ErrorLabels { 65 | pub instance: String, 66 | pub error: String, 67 | } 68 | 69 | impl ReconcileMetrics { 70 | /// Register API metrics to start tracking them. 71 | pub fn register(self, r: &mut Registry) -> Self { 72 | r.register_with_unit( 73 | "duration", 74 | "reconcile duration", 75 | Unit::Seconds, 76 | self.duration.clone(), 77 | ); 78 | r.register("failures", "reconciliation errors", self.failures.clone()); 79 | r.register("runs", "reconciliations", self.runs.clone()); 80 | self 81 | } 82 | 83 | pub fn set_failure(&self, doc: &Document, e: &Error) { 84 | self.failures 85 | .get_or_create(&ErrorLabels { 86 | instance: doc.name_any(), 87 | error: e.metric_label(), 88 | }) 89 | .inc(); 90 | } 91 | 92 | pub fn count_and_measure(&self, trace_id: &TraceId) -> ReconcileMeasurer { 93 | self.runs.inc(); 94 | ReconcileMeasurer { 95 | start: Instant::now(), 96 | labels: trace_id.try_into().ok(), 97 | metric: self.duration.clone(), 98 | } 99 | } 100 | } 101 | 102 | /// Smart function duration measurer 103 | /// 104 | /// Relies on Drop to calculate duration and register the observation in the histogram 105 | pub struct ReconcileMeasurer { 106 | start: Instant, 107 | labels: Option, 108 | metric: HistogramWithExemplars, 109 | } 110 | 111 | impl Drop for ReconcileMeasurer { 112 | fn drop(&mut self) { 113 | #[allow(clippy::cast_precision_loss)] 114 | let duration = self.start.elapsed().as_millis() as f64 / 1000.0; 115 | let labels = self.labels.take(); 116 | self.metric.observe(duration, labels); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/telemetry.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] // some used only for telemetry feature 2 | use opentelemetry::trace::{TraceId, TracerProvider}; 3 | use opentelemetry_sdk::{runtime, trace as sdktrace, trace::Config, Resource}; 4 | use tracing_subscriber::{prelude::*, EnvFilter, Registry}; 5 | 6 | /// Fetch an opentelemetry::trace::TraceId as hex through the full tracing stack 7 | pub fn get_trace_id() -> TraceId { 8 | use opentelemetry::trace::TraceContextExt as _; // opentelemetry::Context -> opentelemetry::trace::Span 9 | use tracing_opentelemetry::OpenTelemetrySpanExt as _; // tracing::Span to opentelemetry::Context 10 | tracing::Span::current() 11 | .context() 12 | .span() 13 | .span_context() 14 | .trace_id() 15 | } 16 | 17 | #[cfg(feature = "telemetry")] 18 | fn resource() -> Resource { 19 | use opentelemetry::KeyValue; 20 | Resource::new([ 21 | KeyValue::new("service.name", env!("CARGO_PKG_NAME")), 22 | KeyValue::new("service.version", env!("CARGO_PKG_VERSION")), 23 | ]) 24 | } 25 | 26 | #[cfg(feature = "telemetry")] 27 | fn init_tracer() -> sdktrace::Tracer { 28 | use opentelemetry_otlp::{SpanExporter, WithExportConfig}; 29 | let endpoint = std::env::var("OPENTELEMETRY_ENDPOINT_URL").expect("Needs an otel collector"); 30 | let exporter = SpanExporter::builder() 31 | .with_tonic() 32 | .with_endpoint(endpoint) 33 | .build() 34 | .unwrap(); 35 | 36 | let provider = sdktrace::TracerProvider::builder() 37 | .with_batch_exporter(exporter, runtime::Tokio) 38 | .with_resource(resource()) 39 | .build(); 40 | 41 | opentelemetry::global::set_tracer_provider(provider.clone()); 42 | provider.tracer("tracing-otel-subscriber") 43 | } 44 | 45 | /// Initialize tracing 46 | pub async fn init() { 47 | // Setup tracing layers 48 | #[cfg(feature = "telemetry")] 49 | let otel = tracing_opentelemetry::OpenTelemetryLayer::new(init_tracer()); 50 | 51 | let logger = tracing_subscriber::fmt::layer().compact(); 52 | let env_filter = EnvFilter::try_from_default_env() 53 | .or(EnvFilter::try_new("info")) 54 | .unwrap(); 55 | 56 | // Decide on layers 57 | let reg = Registry::default(); 58 | #[cfg(feature = "telemetry")] 59 | reg.with(env_filter).with(logger).with(otel).init(); 60 | #[cfg(not(feature = "telemetry"))] 61 | reg.with(env_filter).with(logger).init(); 62 | } 63 | 64 | #[cfg(test)] 65 | mod test { 66 | // This test only works when telemetry is initialized fully 67 | // and requires OPENTELEMETRY_ENDPOINT_URL pointing to a valid server 68 | #[cfg(feature = "telemetry")] 69 | #[tokio::test] 70 | #[ignore = "requires a trace exporter"] 71 | async fn get_trace_id_returns_valid_traces() { 72 | use super::*; 73 | super::init().await; 74 | #[tracing::instrument(name = "test_span")] // need to be in an instrumented fn 75 | fn test_trace_id() -> TraceId { 76 | get_trace_id() 77 | } 78 | assert_ne!(test_trace_id(), TraceId::INVALID, "valid trace"); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /yaml/crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: documents.kube.rs 5 | spec: 6 | group: kube.rs 7 | names: 8 | categories: [] 9 | kind: Document 10 | plural: documents 11 | shortNames: 12 | - doc 13 | singular: document 14 | scope: Namespaced 15 | versions: 16 | - additionalPrinterColumns: [] 17 | name: v1 18 | schema: 19 | openAPIV3Schema: 20 | description: Auto-generated derived type for DocumentSpec via `CustomResource` 21 | properties: 22 | spec: 23 | description: |- 24 | Generate the Kubernetes wrapper struct `Document` from our Spec and Status struct 25 | 26 | This provides a hook for generating the CRD yaml (in crdgen.rs) NB: CustomResource generates a pub struct Document here To query for documents.kube.rs with kube, use Api. 27 | properties: 28 | content: 29 | type: string 30 | hide: 31 | type: boolean 32 | title: 33 | type: string 34 | required: 35 | - content 36 | - hide 37 | - title 38 | type: object 39 | status: 40 | description: The status object of `Document` 41 | nullable: true 42 | properties: 43 | hidden: 44 | type: boolean 45 | required: 46 | - hidden 47 | type: object 48 | required: 49 | - spec 50 | title: Document 51 | type: object 52 | served: true 53 | storage: true 54 | subresources: 55 | status: {} 56 | -------------------------------------------------------------------------------- /yaml/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Source: doc-controller/templates/networkpolicy.yaml 3 | apiVersion: networking.k8s.io/v1 4 | kind: NetworkPolicy 5 | metadata: 6 | name: doc-controller 7 | namespace: default 8 | labels: 9 | app: doc-controller 10 | app.kubernetes.io/name: doc-controller 11 | app.kubernetes.io/version: "0.16.0" 12 | spec: 13 | podSelector: 14 | matchLabels: 15 | app: doc-controller 16 | policyTypes: 17 | - Ingress 18 | - Egress 19 | egress: 20 | 21 | # Kubernetes apiserver access 22 | - to: 23 | - ipBlock: 24 | cidr: 0.0.0.0/0 25 | ports: 26 | - port: 443 27 | protocol: TCP 28 | - port: 6443 29 | protocol: TCP 30 | # DNS egress 31 | - to: 32 | - podSelector: 33 | matchLabels: 34 | k8s-app: kube-dns 35 | ports: 36 | - port: 53 37 | protocol: UDP 38 | 39 | ingress: 40 | # prometheus metrics scraping support 41 | - from: 42 | - namespaceSelector: 43 | matchLabels: 44 | name: monitoring 45 | podSelector: 46 | matchLabels: 47 | app: prometheus 48 | ports: 49 | - port: http 50 | protocol: TCP 51 | --- 52 | # Source: doc-controller/templates/rbac.yaml 53 | # Scoped service account 54 | apiVersion: v1 55 | kind: ServiceAccount 56 | metadata: 57 | name: doc-controller 58 | labels: 59 | app: doc-controller 60 | app.kubernetes.io/name: doc-controller 61 | app.kubernetes.io/version: "0.16.0" 62 | namespace: default 63 | automountServiceAccountToken: true 64 | --- 65 | # Source: doc-controller/templates/rbac.yaml 66 | # Access for the service account 67 | kind: ClusterRole 68 | apiVersion: rbac.authorization.k8s.io/v1 69 | metadata: 70 | name: doc-controller 71 | rules: 72 | - apiGroups: ["kube.rs"] 73 | resources: ["documents", "documents/status", "documents/finalizers"] 74 | verbs: ["get", "list", "watch", "patch", "update"] 75 | - apiGroups: ["events.k8s.io"] 76 | resources: ["events"] 77 | verbs: ["create"] 78 | --- 79 | # Source: doc-controller/templates/rbac.yaml 80 | # Binding the role to the account 81 | kind: ClusterRoleBinding 82 | apiVersion: rbac.authorization.k8s.io/v1 83 | metadata: 84 | name: doc-controller 85 | subjects: 86 | - kind: ServiceAccount 87 | namespace: default 88 | name: doc-controller 89 | roleRef: 90 | kind: ClusterRole 91 | name: doc-controller 92 | apiGroup: rbac.authorization.k8s.io 93 | --- 94 | # Source: doc-controller/templates/service.yaml 95 | # Expose the http port of the service 96 | apiVersion: v1 97 | kind: Service 98 | metadata: 99 | name: doc-controller 100 | namespace: default 101 | labels: 102 | app: doc-controller 103 | app.kubernetes.io/name: doc-controller 104 | app.kubernetes.io/version: "0.16.0" 105 | spec: 106 | type: ClusterIP 107 | ports: 108 | - port: 80 109 | targetPort: 8080 110 | protocol: TCP 111 | name: http 112 | selector: 113 | app: doc-controller 114 | --- 115 | # Source: doc-controller/templates/deployment.yaml 116 | apiVersion: apps/v1 117 | kind: Deployment 118 | metadata: 119 | name: doc-controller 120 | namespace: default 121 | labels: 122 | app: doc-controller 123 | app.kubernetes.io/name: doc-controller 124 | app.kubernetes.io/version: "0.16.0" 125 | spec: 126 | replicas: 1 127 | selector: 128 | matchLabels: 129 | app: doc-controller 130 | template: 131 | metadata: 132 | labels: 133 | app: doc-controller 134 | annotations: 135 | kubectl.kubernetes.io/default-container: doc-controller 136 | spec: 137 | serviceAccountName: doc-controller 138 | securityContext: 139 | {} 140 | containers: 141 | - name: doc-controller 142 | image: ghcr.io/kube-rs/controller:0.16.0 143 | imagePullPolicy: IfNotPresent 144 | securityContext: 145 | {} 146 | resources: 147 | limits: 148 | cpu: 200m 149 | memory: 256Mi 150 | requests: 151 | cpu: 50m 152 | memory: 100Mi 153 | ports: 154 | - name: http 155 | containerPort: 8080 156 | protocol: TCP 157 | env: 158 | - name: RUST_LOG 159 | value: info,kube=debug,controller=debug 160 | readinessProbe: 161 | httpGet: 162 | path: /health 163 | port: http 164 | initialDelaySeconds: 5 165 | periodSeconds: 5 166 | -------------------------------------------------------------------------------- /yaml/instance-illegal.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kube.rs/v1 2 | kind: Document 3 | metadata: 4 | name: illegal 5 | spec: 6 | title: Breaking the law 7 | hide: false 8 | content: | 9 | This document will cause the reconcile fn to return an Err which will be visible in the metrics of the controller. 10 | -------------------------------------------------------------------------------- /yaml/instance-lorem.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kube.rs/v1 2 | kind: Document 3 | metadata: 4 | name: lorem 5 | spec: 6 | title: Lorem Ipsum 7 | hide: false 8 | content: | 9 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 10 | Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 11 | Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. 12 | Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 13 | -------------------------------------------------------------------------------- /yaml/instance-samuel.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kube.rs/v1 2 | kind: Document 3 | metadata: 4 | name: samuel 5 | spec: 6 | title: Samuel Ipsum 7 | hide: true 8 | content: | 9 | You think water moves fast? You should see ice. It moves like it has a mind. Like it knows it killed the world once and got a taste for murder. 10 | After the avalanche, it took us a week to climb out. 11 | Now, I don't know exactly when we turned on each other, but I know that seven of us survived the slide... and only five made it out. 12 | Now we took an oath, that I'm breaking now. We said we'd say it was the snow that killed the other two, but it wasn't. 13 | Nature is lethal but it doesn't hold a candle to man. 14 | --------------------------------------------------------------------------------