Compare commits

...

427 Commits

Author SHA1 Message Date
katelyn martin e8cc4ec47b
nit(app): remove frivolous code (#4094)
this commit removes a piece of code that has been commented out.

it additionally removes a variable binding that is not needed. `dst` is
not moved, so we do not need to bind the address of the destination
service to a variable, nor do we need to clone it.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-08-20 11:31:09 -04:00
dependabot[bot] b951a6c374
build(deps): bump tempfile from 3.20.0 to 3.21.0 (#4093)
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.20.0 to 3.21.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/commits)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-version: 3.21.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-20 10:13:45 -04:00
dependabot[bot] 7f6ac15f13
build(deps): bump cfg-if from 1.0.1 to 1.0.3 (#4092)
Bumps [cfg-if](https://github.com/rust-lang/cfg-if) from 1.0.1 to 1.0.3.
- [Release notes](https://github.com/rust-lang/cfg-if/releases)
- [Changelog](https://github.com/rust-lang/cfg-if/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cfg-if/compare/v1.0.1...v1.0.3)

---
updated-dependencies:
- dependency-name: cfg-if
  dependency-version: 1.0.3
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-20 10:13:04 -04:00
dependabot[bot] 75e9caaeae
build(deps): bump thiserror from 2.0.15 to 2.0.16 (#4091)
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 2.0.15 to 2.0.16.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/2.0.15...2.0.16)

---
updated-dependencies:
- dependency-name: thiserror
  dependency-version: 2.0.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-20 10:12:43 -04:00
dependabot[bot] 02bbb3d617
build(deps): bump prettyplease from 0.2.36 to 0.2.37 (#4090)
Bumps [prettyplease](https://github.com/dtolnay/prettyplease) from 0.2.36 to 0.2.37.
- [Release notes](https://github.com/dtolnay/prettyplease/releases)
- [Commits](https://github.com/dtolnay/prettyplease/compare/0.2.36...0.2.37)

---
updated-dependencies:
- dependency-name: prettyplease
  dependency-version: 0.2.37
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-19 15:40:53 -04:00
dependabot[bot] 103c69ca75
build(deps): bump serde_json from 1.0.142 to 1.0.143 (#4088)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.142 to 1.0.143.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.142...v1.0.143)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-version: 1.0.143
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-19 15:40:39 -04:00
dependabot[bot] 4663cc4eb6
build(deps): bump tinyvec from 1.9.0 to 1.10.0 (#4087)
Bumps [tinyvec](https://github.com/Lokathor/tinyvec) from 1.9.0 to 1.10.0.
- [Changelog](https://github.com/Lokathor/tinyvec/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Lokathor/tinyvec/compare/v1.9.0...v1.10.0)

---
updated-dependencies:
- dependency-name: tinyvec
  dependency-version: 1.10.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-19 15:40:31 -04:00
dependabot[bot] 03374b9543
build(deps): bump hyper from 1.6.0 to 1.7.0 (#4089)
Bumps [hyper](https://github.com/hyperium/hyper) from 1.6.0 to 1.7.0.
- [Release notes](https://github.com/hyperium/hyper/releases)
- [Changelog](https://github.com/hyperium/hyper/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/hyper/compare/v1.6.0...v1.7.0)

---
updated-dependencies:
- dependency-name: hyper
  dependency-version: 1.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-19 15:40:03 -04:00
Scott Fleener 4c9ae74450 chore(metrics): Use `linkerd-rustls` for crypto provider metrics
Now that the `rustls` initialization/configuration has been decoupled from `linkerd-meshtls`, we can get the provider directly from there. This handles the uninitialized case better, which should be less of a problem now that we always directly initialize the provider in main.

Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-08-19 14:06:32 -04:00
katelyn martin 94572d174d
refactor(http/classify): remove unused classification middleware (#4085)
`NewBroadcastClassification<C, X, N>` is not used.

`BroadcastClassification<C, S>` is only used by the `gate` submodule in
this crate.

this commit removes `NewBroadcastClassification`, since it is unused.
this commit demotes `channel` to an internal submodule, since it has no
external users.

the reëxport of `BroadcastClassification` is unused, though it is left
intact because it _is_ exposed by `NewClassifyGateSet`'s implementation
of `NewService<T>`.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-08-19 09:33:29 -04:00
katelyn martin 897c7e85bc
refactor(app/core): remove unused `gate` reëxport (#4084)
`linkerd_app_core::classify` reëxports symbols from
`linkerd_proxy_http::classify::gate`.

nothing makes use of this, and these symbols are already reëxported from
`linkerd_proxy_http::classify`. existing callsites in the outbound proxy
import this middleware directly, or though the reëxport in
`linkerd_proxy_http`.

this commit removes this `pub use` directive, since it does nothing.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-08-18 20:58:18 +00:00
Scott Fleener 036ca75c00
chore(tls): Install default rustls provider in main (#4083)
* chore(tls): Move rustls into dedicated crate

Signed-off-by: Scott Fleener <scott@buoyant.io>

* chore(tls): Remove extraneous provider installs from tests

Signed-off-by: Scott Fleener <scott@buoyant.io>

* chore(tls): Install default rustls provider in main

Signed-off-by: Scott Fleener <scott@buoyant.io>

---------

Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-08-18 19:55:09 +00:00
Scott Fleener 98e731d841
chore(tls): Move `rustls` configuration into dedicated crate (#4082)
* chore(tls): Move rustls into dedicated crate

Signed-off-by: Scott Fleener <scott@buoyant.io>

* chore(tls): Remove extraneous provider installs from tests

Signed-off-by: Scott Fleener <scott@buoyant.io>

---------

Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-08-18 12:48:28 -07:00
Scott Fleener d5b12ea5e2 chore(tls): Hoist rustls directly into linkerd-meshtls
Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-08-18 15:37:05 -04:00
Scott Fleener a64170bd61
chore(tls): Refactor `rustls` shims out of `linkerd-meshtls` (#4080)
* chore(tls): Refactor shims out of meshtls

Meshtls previously assumed that mutliple TLS implementations could be used. Now that we've consolidated on rustls as the TLS implementation, we can remove these shims.

Signed-off-by: Scott Fleener <scott@buoyant.io>

* chore(tls): Refactor mode out of meshtls

Signed-off-by: Scott Fleener <scott@buoyant.io>

---------

Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-08-18 12:27:09 -07:00
katelyn martin 973dfa6f4d
refactor(app/inbound): remove unused `proxy_metrics()` method (#4079)
this commit removes `linkerd_app_inbound::Inbound::proxy_metrics()`.

this accessor is not used anywhere.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-08-18 14:36:31 -04:00
Scott Fleener 17bff6144a
feat(tls): Explicitly include post-quantum key exchange algorithms (#4070)
* feat(tls): Explicitly include post-quantum key exchange algorithms

This explicitly sets the key exchange algorithms the proxy uses. It adds `X25519MLKEM768` as the most preferred algorithm in non-FIPS mode, and `SECP256R1MLKEM768` in FIPS mode.

Note that `X25519MLKEM768` is still probably appropriate for FIPS environments according to [NIST's special publication 800-56Cr2](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Cr2.pdf) as it performs a FIPS-approved key-establishment first (`MLKEM768`), but we should evaluate this position more before committing to it.

Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-08-18 14:09:34 -04:00
katelyn martin d385094caa
nit(app/inbound): fix `InboundMetrics` doc comment (#4078)
this comment changes this comment in two ways:

1. fix a copy-paste typo. this should say "inbound", not "outbound".
2. add note that this is a "legacy" structure.

the equivalent structure in the outbound proxy was labeled as such
in https://github.com/linkerd/linkerd2-proxy/pull/2887.

see:

```rust
 /// Holds LEGACY outbound proxy metrics.
 #[derive(Clone, Debug)]
 pub struct OutboundMetrics {
     pub(crate) http_errors: error::Http,
     pub(crate) tcp_errors: error::Tcp,

     // pub(crate) http_route_backends: RouteBackendMetrics,
     // pub(crate) grpc_route_backends: RouteBackendMetrics,
     /// Holds metrics that are common to both inbound and outbound proxies. These metrics are
     /// reported separately
     pub(crate) proxy: Proxy,

     pub(crate) prom: PromMetrics,
 }
```

\- <dce6b61191/linkerd/app/outbound/src/metrics.rs (L22-L35)>

`authz::HttpAuthzMetrics`, `error::HttpErrorMetrics`,
`authz::TcpAuthzMetrics`, and `error::TcpErrorMetrics` all make use of
the "legacy" metrics implementation defined in `linkerd_metrics`.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-08-18 14:01:37 -04:00
dependabot[bot] dce6b61191
build(deps): bump syn from 2.0.105 to 2.0.106 (#4077)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.105 to 2.0.106.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.105...2.0.106)

---
updated-dependencies:
- dependency-name: syn
  dependency-version: 2.0.106
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 12:12:30 -04:00
dependabot[bot] 28ebc47a6b
build(deps): bump cc from 1.2.32 to 1.2.33 (#4076)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.32 to 1.2.33.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.32...cc-v1.2.33)

---
updated-dependencies:
- dependency-name: cc
  dependency-version: 1.2.33
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 11:38:09 -04:00
dependabot[bot] 4bae7e98f2
build(deps): bump proc-macro2 from 1.0.97 to 1.0.101 (#4075)
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.97 to 1.0.101.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.97...1.0.101)

---
updated-dependencies:
- dependency-name: proc-macro2
  dependency-version: 1.0.101
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 11:37:49 -04:00
dependabot[bot] b89c4902c6
build(deps): bump thiserror from 2.0.14 to 2.0.15 (#4074)
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 2.0.14 to 2.0.15.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/2.0.14...2.0.15)

---
updated-dependencies:
- dependency-name: thiserror
  dependency-version: 2.0.15
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 11:26:07 -04:00
dependabot[bot] 8a80f1ce95
build(deps): bump async-trait from 0.1.88 to 0.1.89 (#4073)
Bumps [async-trait](https://github.com/dtolnay/async-trait) from 0.1.88 to 0.1.89.
- [Release notes](https://github.com/dtolnay/async-trait/releases)
- [Commits](https://github.com/dtolnay/async-trait/compare/0.1.88...0.1.89)

---
updated-dependencies:
- dependency-name: async-trait
  dependency-version: 0.1.89
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 10:47:36 -04:00
dependabot[bot] edc35d6e18
build(deps): bump derive_arbitrary from 1.4.1 to 1.4.2 (#4072)
Bumps [derive_arbitrary](https://github.com/rust-fuzz/arbitrary) from 1.4.1 to 1.4.2.
- [Changelog](https://github.com/rust-fuzz/arbitrary/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-fuzz/arbitrary/compare/v1.4.1...v1.4.2)

---
updated-dependencies:
- dependency-name: derive_arbitrary
  dependency-version: 1.4.2
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 10:44:51 -04:00
dependabot[bot] 99f322a9a0
build(deps): bump arbitrary from 1.4.1 to 1.4.2 (#4071)
Bumps [arbitrary](https://github.com/rust-fuzz/arbitrary) from 1.4.1 to 1.4.2.
- [Changelog](https://github.com/rust-fuzz/arbitrary/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-fuzz/arbitrary/compare/v1.4.1...v1.4.2)

---
updated-dependencies:
- dependency-name: arbitrary
  dependency-version: 1.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 07:26:46 -07:00
Scott Fleener 627a5aad21
feat(tls): Remove boring as a TLS implementation (#4038)
* chore(tls): Remove ring as crypto backend

The broader ecosystem has mostly moved to aws-lc-rs as the primary rustls backend, and we should follow suit. This will also simplify the maintenance of the proxy's TLS implementation in the long term.

There will need to be some refactoring to clean up the rustls provider interfaces, but that will come in follow-ups.

Signed-off-by: Scott Fleener <scott@buoyant.io>

* feat(tls): Remove boring as a TLS implementation

BoringSSL, as we use it today, doesn't integrate well with the broader rustls ecosystem, so this removes it. This will also simplify the maintenance of the proxy's TLS implementation in the long term.

There will need to be some refactoring to clean up the rustls provider interfaces, but that will come in follow-ups.

Signed-off-by: Scott Fleener <scott@buoyant.io>

* chore(tls): Restore existing aws-lc feature names for compatibility

Signed-off-by: Scott Fleener <scott@buoyant.io>

* fix(tls): Use correct feature name for fips conditionals

Signed-off-by: Scott Fleener <scott@buoyant.io>

---------

Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-08-14 23:27:58 -04:00
Scott Fleener 356f80b786
chore(tls): Improve `aws-lc` usage (#4069)
This adds a few small improvements to how we handle the `aws-lc` usage in the proxy:

- Pull provider customization to the `aws-lc` backend, reducing the amount that the module exposes
- Validate that the provider is actually FIPS compatible when fips is enabled
- Use the same signature verification algorithms in the `rustls` provider as we do in the cert verifier. Previously, the provider also included RSA_PSS_2048_8192_SHA256, which is marked as legacy and we don't have a strong reason to support.
- Add change detector tests for the cipher suites, key exchange groups, and signature algorithms. These should ideally never change unless `rustls` changes, at which point we can re-evaluate which algorithms are in use by the proxy.

Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-08-14 18:56:35 +00:00
dependabot[bot] 0b3bc61263
build(deps): bump hashbrown from 0.15.2 to 0.15.5 (#4068)
Bumps [hashbrown](https://github.com/rust-lang/hashbrown) from 0.15.2 to 0.15.5.
- [Release notes](https://github.com/rust-lang/hashbrown/releases)
- [Changelog](https://github.com/rust-lang/hashbrown/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/hashbrown/commits/v0.15.5)

---
updated-dependencies:
- dependency-name: hashbrown
  dependency-version: 0.15.5
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-14 11:30:16 -04:00
Scott Fleener 2b0e723027
chore(deps): Update tonic deps to 0.13 (#4066)
* chore(deps): Update tonic deps to 0.13

Signed-off-by: Scott Fleener <scott@buoyant.io>

* chore(deps): Update linkerd2-proxy-api to 0.17.0

Signed-off-by: Scott Fleener <scott@buoyant.io>

---------

Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-08-13 10:45:42 -07:00
Scott Fleener 2156c3d5e3
chore(tls): Remove `ring` as `rustls` crypto backend (#4029)
* chore(tls): Remove ring as crypto backend

The broader ecosystem has mostly moved to aws-lc-rs as the primary rustls backend, and we should follow suit. This will also simplify the maintenance of the proxy's TLS implementation in the long term.

There will need to be some refactoring to clean up the rustls provider interfaces, but that will come in follow-ups.

Signed-off-by: Scott Fleener <scott@buoyant.io>

* chore(tls): Restore existing aws-lc feature names for compatibility

Signed-off-by: Scott Fleener <scott@buoyant.io>

* fix(tls): Use correct feature name for fips conditionals

Signed-off-by: Scott Fleener <scott@buoyant.io>

---------

Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-08-13 13:13:57 -04:00
dependabot[bot] c4cae21e11
build(deps): bump syn from 2.0.104 to 2.0.105 (#4067)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.104 to 2.0.105.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.104...2.0.105)

---
updated-dependencies:
- dependency-name: syn
  dependency-version: 2.0.105
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-13 10:09:16 -07:00
Scott Fleener 89c88caf5c
chore(deps): Manually remove unused dependencies (#4065)
Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-08-13 10:44:43 -04:00
dependabot[bot] bb612d3aac
build(deps): bump the symbolic group with 2 updates (#4063)
Bumps the symbolic group with 2 updates: [symbolic-common](https://github.com/getsentry/symbolic) and [symbolic-demangle](https://github.com/getsentry/symbolic).


Updates `symbolic-common` from 12.16.1 to 12.16.2
- [Release notes](https://github.com/getsentry/symbolic/releases)
- [Changelog](https://github.com/getsentry/symbolic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/symbolic/compare/12.16.1...12.16.2)

Updates `symbolic-demangle` from 12.16.1 to 12.16.2
- [Release notes](https://github.com/getsentry/symbolic/releases)
- [Changelog](https://github.com/getsentry/symbolic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/symbolic/compare/12.16.1...12.16.2)

---
updated-dependencies:
- dependency-name: symbolic-common
  dependency-version: 12.16.2
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: symbolic
- dependency-name: symbolic-demangle
  dependency-version: 12.16.2
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: symbolic
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 17:18:00 -07:00
dependabot[bot] 7030cc51ed
build(deps): bump anyhow from 1.0.98 to 1.0.99 (#4062)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.98 to 1.0.99.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.98...1.0.99)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-version: 1.0.99
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 18:39:04 +00:00
dependabot[bot] af520dfd12
build(deps): bump proc-macro2 from 1.0.96 to 1.0.97 (#4061)
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.96 to 1.0.97.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.96...1.0.97)

---
updated-dependencies:
- dependency-name: proc-macro2
  dependency-version: 1.0.97
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 12:33:58 -04:00
dependabot[bot] ccf91dfb3e
build(deps): bump actions/checkout from 4.3.0 to 5.0.0 (#4060)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.3.0 to 5.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](08eba0b27e...08c6903cd8)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 16:18:00 +00:00
dependabot[bot] 69cd164da1
build(deps): bump thiserror from 2.0.12 to 2.0.14 (#4059)
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 2.0.12 to 2.0.14.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/2.0.12...2.0.14)

---
updated-dependencies:
- dependency-name: thiserror
  dependency-version: 2.0.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 15:56:38 +00:00
dependabot[bot] feb5f87713
build(deps): bump libc from 0.2.174 to 0.2.175 (#4057)
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.174 to 0.2.175.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.175/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.174...0.2.175)

---
updated-dependencies:
- dependency-name: libc
  dependency-version: 0.2.175
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-11 12:14:04 -04:00
dependabot[bot] fdd7f218a3
build(deps): bump actions/checkout from 4.2.2 to 4.3.0 (#4053)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.2 to 4.3.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](11bd71901b...08eba0b27e)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 4.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-11 11:06:10 -04:00
dependabot[bot] b4e2b7e24f
build(deps): bump glob from 0.3.2 to 0.3.3 (#4055)
Bumps [glob](https://github.com/rust-lang/glob) from 0.3.2 to 0.3.3.
- [Release notes](https://github.com/rust-lang/glob/releases)
- [Changelog](https://github.com/rust-lang/glob/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/glob/compare/v0.3.2...v0.3.3)

---
updated-dependencies:
- dependency-name: glob
  dependency-version: 0.3.3
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-11 11:05:55 -04:00
dependabot[bot] 1b07f277d7
build(deps): bump rustversion from 1.0.21 to 1.0.22 (#4056)
Bumps [rustversion](https://github.com/dtolnay/rustversion) from 1.0.21 to 1.0.22.
- [Release notes](https://github.com/dtolnay/rustversion/releases)
- [Commits](https://github.com/dtolnay/rustversion/compare/1.0.21...1.0.22)

---
updated-dependencies:
- dependency-name: rustversion
  dependency-version: 1.0.22
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-11 11:05:34 -04:00
dependabot[bot] 25cf0c7f11
build(deps): bump proc-macro2 from 1.0.95 to 1.0.96 (#4054)
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.95 to 1.0.96.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.95...1.0.96)

---
updated-dependencies:
- dependency-name: proc-macro2
  dependency-version: 1.0.96
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-11 14:52:05 +00:00
dependabot[bot] d46e7c0c82
build(deps): bump cc from 1.2.31 to 1.2.32 (#4051)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.31 to 1.2.32.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.31...cc-v1.2.32)

---
updated-dependencies:
- dependency-name: cc
  dependency-version: 1.2.32
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-08 13:28:21 -04:00
dependabot[bot] 3305a890b0
build(deps): bump slab from 0.4.10 to 0.4.11 (#4052)
Bumps [slab](https://github.com/tokio-rs/slab) from 0.4.10 to 0.4.11.
- [Release notes](https://github.com/tokio-rs/slab/releases)
- [Changelog](https://github.com/tokio-rs/slab/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/slab/compare/v0.4.10...v0.4.11)

---
updated-dependencies:
- dependency-name: slab
  dependency-version: 0.4.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-08 13:28:01 -04:00
katelyn martin d850fa6f73
refactor(metrics): introduce a `legacy` namespace (#4050)
`linkerd-metrics` contains a suite of facilities for defining,
registering, and serving Prometheus metrics. these predate the
[`prometheus-client`](https://crates.io/crates/prometheus-client/)
crate, which should now be used for our metrics.

`linkerd-metrics` defines a `prom` namespace, which reëxports symbols
from the `prometheus-client` library. as the documentation comment for
this submodule notes, this should be used for all new metrics.

6b323d8457/linkerd/metrics/src/lib.rs (L30-L60)

`linkerd-metrics` still provides its legacy types in the public surface
of this library today, which can make it difficult to differentiate
between our two metrics implementations.

this branch introduces a new `legacy` namespace, to help clarify the
distinction between these two Prometheus implementations, and to smooth
the road to further adoption of `prometheus-client` interfaces across
the proxy.

---

* refactor(metrics): introduce empty `legacy` namespace

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor: move `Counter` into `legacy` namespace

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor: move `Gauge` into `legacy` namespace

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor: move `Histogram` into `legacy` namespace

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor: move `Metric` into `legacy` namespace

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor: move `FmtMetric` into `legacy` namespace

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor: move `FmtMetrics` into `legacy` namespace

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor: move `FmtLabels` into `legacy` namespace

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor: move `LastUpdate` into `legacy` namespace

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor: move `Store` into `legacy` namespace

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor: move `SharedStore` into `legacy` namespace

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor: move `Serve` into `legacy` namespace

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor: move `NewMetrics` into `legacy` namespace

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor: move `Factor` into `legacy` namespace

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-08-07 15:33:17 -04:00
dependabot[bot] 6b323d8457
build(deps): bump governor from 0.10.0 to 0.10.1 (#4049)
Bumps [governor](https://github.com/boinkor-net/governor) from 0.10.0 to 0.10.1.
- [Release notes](https://github.com/boinkor-net/governor/releases)
- [Changelog](https://github.com/boinkor-net/governor/blob/master/release.toml)
- [Commits](https://github.com/boinkor-net/governor/compare/v0.10.0...v0.10.1)

---
updated-dependencies:
- dependency-name: governor
  dependency-version: 0.10.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-07 10:37:18 -04:00
dependabot[bot] 7f58cd56ed
build(deps): bump tokio-metrics from 0.4.3 to 0.4.4 (#4048)
Bumps [tokio-metrics](https://github.com/tokio-rs/tokio-metrics) from 0.4.3 to 0.4.4.
- [Release notes](https://github.com/tokio-rs/tokio-metrics/releases)
- [Changelog](https://github.com/tokio-rs/tokio-metrics/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/tokio-metrics/commits)

---
updated-dependencies:
- dependency-name: tokio-metrics
  dependency-version: 0.4.4
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-07 10:37:00 -04:00
Scott Fleener 43e3f630ec feat(tls): Include rustls crypto provider metrics
This includes a small set of metrics about the currently installed rustls crypto provider and the algorithms it is configured to use.

We don't have 100% assurance that a default crypto provider has been installed before registering the metric, but in local testing it never appeared to be a problem. When we refactor the rustls initialization we can add an extra guarantee that we've initialized it by this point.

Example metric:
```
# HELP rustls_info Proxy TLS info.
# TYPE rustls_info gauge
rustls_info{tls_suites="TLS13_AES_128_GCM_SHA256,TLS13_AES_256_GCM_SHA384,TLS13_CHACHA20_POLY1305_SHA256,",tls_kx_groups="X25519,secp256r1,secp384r1,X25519MLKEM768,",tls_rand="AwsLcRs",tls_key_provider="AwsLcRs",tls_fips="false"} 1
```

Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-08-07 10:01:07 -04:00
Oliver Gould 7758436831
chore(ci): exercise all release platforms on workflow change (#4047)
We only build linux/amd64 during typical release CI runs. This means that the platform-
specific builds are not exercised. This change updates the release workflow so that
all platforms are built whenever the workflow itself is changed.
2025-08-06 14:29:05 +00:00
dependabot[bot] c0f921af33
build(deps): bump zerovec from 0.11.3 to 0.11.4 (#4046)
Bumps [zerovec](https://github.com/unicode-org/icu4x) from 0.11.3 to 0.11.4.
- [Release notes](https://github.com/unicode-org/icu4x/releases)
- [Changelog](https://github.com/unicode-org/icu4x/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unicode-org/icu4x/compare/ind/zerovec@0.11.3...ind/zerovec@0.11.4)

---
updated-dependencies:
- dependency-name: zerovec
  dependency-version: 0.11.4
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-06 09:48:31 -04:00
Scott Fleener b558ce5320
chore(meshtls-rustls): use aws-lc as the default crypto backend (#4043)
The broader ecosystem has mostly moved to `aws-lc-rs` as the primary `rustls` backend, and we should follow suit. This will also simplify the maintenance of the proxy's TLS implementation in the long term.

This requires some extra configuration for successful cross-compilation, ideally we can remove this extra configuration once linkerd/dev v48 is available.

This doesn't remove `ring` as a crypto backend, that can come in a follow-up at https://github.com/linkerd/linkerd2-proxy/pull/4029
2025-08-05 13:22:26 -07:00
dependabot[bot] 894d3506df
build(deps): bump socket2 from 0.5.10 to 0.6.0 (#4003)
* build(deps): bump socket2 from 0.5.10 to 0.6.0

Bumps [socket2](https://github.com/rust-lang/socket2) from 0.5.10 to 0.6.0.
- [Release notes](https://github.com/rust-lang/socket2/releases)
- [Changelog](https://github.com/rust-lang/socket2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/socket2/commits)

---
updated-dependencies:
- dependency-name: socket2
  dependency-version: 0.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(proxy/transport): use `original_dst_v*` methods

these have been renamed.

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: katelyn martin <kate@buoyant.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: katelyn martin <kate@buoyant.io>
2025-08-05 13:09:56 -07:00
dependabot[bot] 01e7ec0820
build(deps): bump zerovec from 0.11.2 to 0.11.3 (#4044)
Bumps [zerovec](https://github.com/unicode-org/icu4x) from 0.11.2 to 0.11.3.
- [Release notes](https://github.com/unicode-org/icu4x/releases)
- [Changelog](https://github.com/unicode-org/icu4x/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unicode-org/icu4x/commits/ind/zerovec@0.11.3)

---
updated-dependencies:
- dependency-name: zerovec
  dependency-version: 0.11.3
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-05 13:00:54 -07:00
dependabot[bot] 4f563fab68
build(deps): bump tokio-metrics from 0.4.2 to 0.4.3 (#3995)
Bumps [tokio-metrics](https://github.com/tokio-rs/tokio-metrics) from 0.4.2 to 0.4.3.
- [Release notes](https://github.com/tokio-rs/tokio-metrics/releases)
- [Changelog](https://github.com/tokio-rs/tokio-metrics/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/tokio-metrics/compare/v0.4.2...v0.4.3)

---
updated-dependencies:
- dependency-name: tokio-metrics
  dependency-version: 0.4.3
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-05 07:50:44 -07:00
dependabot[bot] 168c4bff7d
build(deps): bump tokio from 1.45.0 to 1.47.1 (#4040)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.45.0 to 1.47.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.45.0...tokio-1.47.1)

---
updated-dependencies:
- dependency-name: tokio
  dependency-version: 1.47.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-05 09:44:53 -04:00
dependabot[bot] 0df8cdbedb
build(deps): bump cc from 1.2.30 to 1.2.31 (#4042)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.30 to 1.2.31.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.30...cc-v1.2.31)

---
updated-dependencies:
- dependency-name: cc
  dependency-version: 1.2.31
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-04 14:59:55 -07:00
dependabot[bot] 1b837b7f91
build(deps): bump tokio-util from 0.7.15 to 0.7.16 (#4041)
Bumps [tokio-util](https://github.com/tokio-rs/tokio) from 0.7.15 to 0.7.16.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-util-0.7.15...tokio-util-0.7.16)

---
updated-dependencies:
- dependency-name: tokio-util
  dependency-version: 0.7.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-04 14:59:00 -07:00
katelyn martin 40078c96ca
chore(deps): update from tokio 1.45 to 1.47 (#4032)
* build(deps): bump tokio from 1.45.0 to 1.47.0

Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.45.0 to 1.47.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.45.0...tokio-1.47.0)

---
updated-dependencies:
- dependency-name: tokio
  dependency-version: 1.47.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

---

chore(deny): ignore socket2@v0.5

there is now a v0.6 used by the latest tokio.

while we wait for this new version to propagate through the ecosystem,
allow for two socket2 dependencies.

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(app/integration): remove inbound_io_err test

> @cratelyn I think it would be appropriate to remove these tests, given
> that they can no longer behave properly. I don't think that this test
> case is particularly meaningful or load bearing, it's best just to
> unblock the dependency updates.

\- <https://github.com/BuoyantIO/enterprise-linkerd/issues/1645#issuecomment-3046905516>

Co-authored-by: Oliver Gould <ver@buoyant.io>
Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(app/integration): remove inbound_multi test

this test exercises the same thing that the previous two tests do, as
the comment at the top of it points out.

this test is redundant, and we have removed the i/o error coverage that
this was redunant with. let's remove it.

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
Co-authored-by: Oliver Gould <ver@buoyant.io>
2025-08-04 09:04:02 -07:00
dependabot[bot] 9eaf1425a7
build(deps): bump signal-hook-registry from 1.4.5 to 1.4.6 (#4039)
Bumps [signal-hook-registry](https://github.com/vorner/signal-hook) from 1.4.5 to 1.4.6.
- [Changelog](https://github.com/vorner/signal-hook/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vorner/signal-hook/compare/registry-v1.4.5...registry-v1.4.6)

---
updated-dependencies:
- dependency-name: signal-hook-registry
  dependency-version: 1.4.6
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-04 08:08:41 -07:00
dependabot[bot] 842452368c
build(deps): bump rustc-demangle from 0.1.25 to 0.1.26 (#4026)
Bumps [rustc-demangle](https://github.com/rust-lang/rustc-demangle) from 0.1.25 to 0.1.26.
- [Release notes](https://github.com/rust-lang/rustc-demangle/releases)
- [Changelog](https://github.com/rust-lang/rustc-demangle/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/rustc-demangle/commits/rustc-demangle-v0.1.26)

---
updated-dependencies:
- dependency-name: rustc-demangle
  dependency-version: 0.1.26
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-04 11:07:17 -04:00
dependabot[bot] 09333dc2b2
build(deps): bump the symbolic group with 2 updates (#4035)
Bumps the symbolic group with 2 updates: [symbolic-common](https://github.com/getsentry/symbolic) and [symbolic-demangle](https://github.com/getsentry/symbolic).


Updates `symbolic-common` from 12.16.0 to 12.16.1
- [Release notes](https://github.com/getsentry/symbolic/releases)
- [Changelog](https://github.com/getsentry/symbolic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/symbolic/compare/12.16.0...12.16.1)

Updates `symbolic-demangle` from 12.16.0 to 12.16.1
- [Release notes](https://github.com/getsentry/symbolic/releases)
- [Changelog](https://github.com/getsentry/symbolic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/symbolic/compare/12.16.0...12.16.1)

---
updated-dependencies:
- dependency-name: symbolic-common
  dependency-version: 12.16.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: symbolic
- dependency-name: symbolic-demangle
  dependency-version: 12.16.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: symbolic
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Oliver Gould <ver@buoyant.io>
2025-08-01 18:28:55 +00:00
dependabot[bot] ddc847ccc4
build(deps): bump serde_json from 1.0.141 to 1.0.142 (#4036)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.141 to 1.0.142.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.141...v1.0.142)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-version: 1.0.142
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-01 11:23:49 -07:00
Scott Fleener 8d56746c1f
feat!(ci): Remove arm/v7 support (#4037)
This architecture has become too significant of a maintenance burden, and isn't used often enough to justify the associated maintenance cost.

This removes arm/v7 from all the build infrastructure/dockerfiles/etc. Note that arm64 targets are still widely used and well supported.

Related: https://github.com/linkerd/linkerd2/pull/14308

Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-08-01 13:26:12 -04:00
dependabot[bot] db0ed46978
build(deps): bump rustls from 0.23.29 to 0.23.31 in the rustls group (#4034)
Bumps the rustls group with 1 update: [rustls](https://github.com/rustls/rustls).


Updates `rustls` from 0.23.29 to 0.23.31
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.23.29...v/0.23.31)

---
updated-dependencies:
- dependency-name: rustls
  dependency-version: 0.23.31
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: rustls
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-31 05:53:48 -07:00
katelyn martin 1d94082d4b
chore(deps): downgrade deranged from 0.4.1 to 0.4.0 (#4031)
- https://crates.io/crates/deranged/versions
- https://crates.io/crates/deranged/0.4.1

this version has been yanked. this commit addresses this cargo deny
warning:

```
warning[yanked]: detected yanked crate (try `cargo update -p deranged`)
   ┌─ /home/katie/linkerd/linkerd2-proxy/Cargo.lock:41:1
   │
41 │ deranged 0.4.1 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ yanked version
   │
```

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-07-29 18:14:11 +00:00
dependabot[bot] 744e29e0bd
build(deps): bump rangemap from 1.5.1 to 1.6.0 (#4028)
Bumps [rangemap](https://github.com/jeffparsons/rangemap) from 1.5.1 to 1.6.0.
- [Changelog](https://github.com/jeffparsons/rangemap/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jeffparsons/rangemap/commits)

---
updated-dependencies:
- dependency-name: rangemap
  dependency-version: 1.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-29 10:59:35 -04:00
katelyn martin 83373d6b89
chore(deps): bump h2 from 0.4.8 to 0.4.11 (#4024)
- https://github.com/hyperium/h2/compare/v0.4.8...v0.4.11

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-07-28 21:23:25 +00:00
Scott Fleener 1dcb7a7d1a
fix(rustls): Make `ring` and `aws-lc-rs` exclusive features (#4009)
Currently, disabling the `ring` feature does not actually disable the dependency across the tree. Doing so requires a couple of tightly coupled steps:

- Making `ring` and `aws-lc` exclusive features, raising a compile error if they are both enabled.
- Removing a direct dependency on some `ring` types, and instead going through `rustls` for equivalent functionality.
- Removing a direct dependency on the `ring` crypto provider for integration tests, and instead using the provider from `linkerd-meshtls`.
- Installing the default crypto provider globally for the process and re-using it when requested, mostly to make the tests pass.

This was tested using a temporary `cargo deny` config that forbid `ring` when `aws-lc-rs` was used, and vice-versa. Note that it doesn't completely remove ring for dev dependencies, but that can be done as a follow-up.

Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-07-28 15:28:47 -04:00
Scott Fleener 68a6b6d1e8
fix(tls): Update preferred cipher suite order (#4015)
This makes two changes to the preferred cipher suite order.
- Prefer AES algorithms over ChaCha20. AES is significantly faster when AES hardware is present, and AES hardware is on all x86 CPUs since ~2010, and all ARM server CPUs for a similar amount of time. For these reasons it's reasonable to default to AES for modern deployments, and it's the same default that `aws-lc-rs` makes anyway.
- Remove ChaCha20 when FIPS is enabled. It's no longer a supported algorithm, so we shouldn't have it as an option.

Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-07-28 15:05:05 -04:00
Oliver Gould cdbb55fd53
build(linkerd2-proxy): make release artifacts auditable (#4023)
Auditing tools like Syft cannot inspect proxy dependencies, which makes it difficult to inspect the state of a binary. This change updates the release process to use cargo-auditable, which documents the proxy's crate dependencies in its release binary.
2025-07-28 17:00:06 +00:00
Oliver Gould 5997453393
build(deps): update linkerd/dev to v47 (#4022) 2025-07-28 11:49:06 -05:00
Joe 10643b9525
updating metrics descriptions (#4020)
Signed-off-by: Joe F <joe@buoyant.io>
2025-07-25 20:08:56 +00:00
dependabot[bot] fd0ea24b87
build(deps): bump serde_json from 1.0.140 to 1.0.141 (#4021)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.140 to 1.0.141.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.140...v1.0.141)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-version: 1.0.141
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-25 16:07:16 -04:00
dependabot[bot] 3a159be91a
build(deps): bump prettyplease from 0.2.35 to 0.2.36 (#4018)
Bumps [prettyplease](https://github.com/dtolnay/prettyplease) from 0.2.35 to 0.2.36.
- [Release notes](https://github.com/dtolnay/prettyplease/releases)
- [Commits](https://github.com/dtolnay/prettyplease/compare/0.2.35...0.2.36)

---
updated-dependencies:
- dependency-name: prettyplease
  dependency-version: 0.2.36
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-24 10:03:57 -04:00
dependabot[bot] b3bc6fe8cd
build(deps): bump hyper-util from 0.1.15 to 0.1.16 (#4019)
Bumps [hyper-util](https://github.com/hyperium/hyper-util) from 0.1.15 to 0.1.16.
- [Release notes](https://github.com/hyperium/hyper-util/releases)
- [Changelog](https://github.com/hyperium/hyper-util/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/hyper-util/compare/v0.1.15...v0.1.16)

---
updated-dependencies:
- dependency-name: hyper-util
  dependency-version: 0.1.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-24 10:02:38 -04:00
dependabot[bot] 5a00b70d11
build(deps): bump aws-lc-rs from 1.13.2 to 1.13.3 (#4016)
Bumps [aws-lc-rs](https://github.com/aws/aws-lc-rs) from 1.13.2 to 1.13.3.
- [Release notes](https://github.com/aws/aws-lc-rs/releases)
- [Commits](https://github.com/aws/aws-lc-rs/compare/v1.13.2...v1.13.3)

---
updated-dependencies:
- dependency-name: aws-lc-rs
  dependency-version: 1.13.3
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-23 07:02:52 -07:00
dependabot[bot] b91dd3e7af
build(deps): bump rcgen from 0.14.2 to 0.14.3 (#4017)
Bumps [rcgen](https://github.com/rustls/rcgen) from 0.14.2 to 0.14.3.
- [Release notes](https://github.com/rustls/rcgen/releases)
- [Commits](https://github.com/rustls/rcgen/compare/v0.14.2...v0.14.3)

---
updated-dependencies:
- dependency-name: rcgen
  dependency-version: 0.14.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-23 07:02:25 -07:00
dependabot[bot] a699b1cf58
build(deps): bump cc from 1.2.29 to 1.2.30 (#4014)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.29 to 1.2.30.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.29...cc-v1.2.30)

---
updated-dependencies:
- dependency-name: cc
  dependency-version: 1.2.30
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-22 09:35:32 -04:00
dependabot[bot] 9f3c45874e
build(deps): bump rand from 0.9.1 to 0.9.2 (#4013)
Bumps [rand](https://github.com/rust-random/rand) from 0.9.1 to 0.9.2.
- [Release notes](https://github.com/rust-random/rand/releases)
- [Changelog](https://github.com/rust-random/rand/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-random/rand/compare/rand_core-0.9.1...rand_core-0.9.2)

---
updated-dependencies:
- dependency-name: rand
  dependency-version: 0.9.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-22 09:35:19 -04:00
Oliver Gould 1de179e178
chore(deps): update jemallocator 0.5 to tikv-jemallocator 0.6 (#4012)
tikv-jemallocator supersedes jemallocator. To enable jemalloc profiling, this change updates the dependency and adds a `jemalloc-profiling` feature so that profiling can be enabled at build time.
2025-07-18 17:42:41 -04:00
dependabot[bot] f9d7e08242
build(deps): bump the rustls group with 2 updates (#4010)
---
updated-dependencies:
- dependency-name: rustls-webpki
  dependency-version: 0.103.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rustls
- dependency-name: rustls
  dependency-version: 0.23.29
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: rustls
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-18 07:48:31 -07:00
dependabot[bot] bd454b4be8
build(deps): bump the symbolic group with 2 updates (#4011)
---
updated-dependencies:
- dependency-name: symbolic-common
  dependency-version: 12.16.0
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: symbolic
- dependency-name: symbolic-demangle
  dependency-version: 12.16.0
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: symbolic
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-18 07:48:06 -07:00
Oliver Gould b1f8fa5419
chore(ci): enable overriding the runner in workflows (#4008)
We use the ubuntu-24.04 runner by default, but in forks this may not be appropriate. This change updates the runners to support overriding via the LINKERD2_PROXY_RUNNER variable.
2025-07-17 17:22:42 -07:00
dependabot[bot] e04947610a
build(deps): bump aws-lc-rs from 1.13.1 to 1.13.2 (#4006)
---
updated-dependencies:
- dependency-name: aws-lc-rs
  dependency-version: 1.13.2
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-17 11:05:10 -07:00
Oliver Gould 9c48e2471e
fix(app/env): limit default inbound connection pool size (#4007)
The inbound connection pool is effectively unlimited. This change configures a
default limit of 10K.
2025-07-17 16:47:32 +00:00
dependabot[bot] df38a5a2c9
build(deps): bump the rustls group across 1 directory with 3 updates (#3908)
* build(deps): bump the rustls group across 1 directory with 3 updates

Bumps the rustls group with 3 updates in the / directory: [rustls-webpki](https://github.com/rustls/webpki), [rustls](https://github.com/rustls/rustls) and [rustls-pki-types](https://github.com/rustls/pki-types).


Updates `rustls-webpki` from 0.103.1 to 0.103.2
- [Release notes](https://github.com/rustls/webpki/releases)
- [Commits](https://github.com/rustls/webpki/compare/v/0.103.1...v/0.103.2)

Updates `rustls` from 0.23.26 to 0.23.27
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.23.26...v/0.23.27)

Updates `rustls-pki-types` from 1.11.0 to 1.12.0
- [Release notes](https://github.com/rustls/pki-types/releases)
- [Commits](https://github.com/rustls/pki-types/compare/v/1.11.0...v/1.12.0)

---
updated-dependencies:
- dependency-name: rustls-webpki
  dependency-version: 0.103.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rustls
- dependency-name: rustls
  dependency-version: 0.23.27
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: rustls
- dependency-name: rustls-pki-types
  dependency-version: 1.12.0
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: rustls
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(rustls): Remove dependency on most rustls internal types

We only used these types for generating a ClientHello message for testing. Instead, we can manually encode a sample message based on the TLS spec.

Signed-off-by: Scott Fleener <scott@buoyant.io>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Scott Fleener <scott@buoyant.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Scott Fleener <scott@buoyant.io>
2025-07-17 16:20:37 +00:00
dependabot[bot] 7c6882bb35
build(deps): bump rcgen from 0.13.2 to 0.14.2 (#4000)
* build(deps): bump rcgen from 0.13.2 to 0.14.2

Bumps [rcgen](https://github.com/rustls/rcgen) from 0.13.2 to 0.14.2.
- [Release notes](https://github.com/rustls/rcgen/releases)
- [Commits](https://github.com/rustls/rcgen/compare/v0.13.2...v0.14.2)

---
updated-dependencies:
- dependency-name: rcgen
  dependency-version: 0.14.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(test): Fix breaking changes from rcgen 0.14

Signed-off-by: Scott Fleener <scott@buoyant.io>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Scott Fleener <scott@buoyant.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Scott Fleener <scott@buoyant.io>
2025-07-16 19:34:47 -04:00
katelyn martin a6e47d7e03
fix(app/env): a lower default maximum per-host connection limit (#4005)
* chore(app/env): fix typo

Signed-off-by: katelyn martin <kate@buoyant.io>

* fix(app/env): a lower default maximum per-host connection limit

see also:
* #4004
* linkerd/linkerd2#14204

in #4004 we fixed an issue related to our HTTP/1.1 client's connection
pool.

this further hedges against future issues related to our HTTP client
exhausting resources available to its container. today, the limit by
default is `usize::MAX`, which is dramatically higher than the practical
limit.

this commit changes the limit for outbound idle connections per-host to
10,000.

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-07-15 13:01:54 -04:00
Oliver Gould 2cc8c7d80e
fix(proxy/http): fix HTTP/1 client idle timeouts (#4004)
When constructing the HTTP/1 client, we configure connection pooling, but
notably do not provide a timer implementation to Hyper. This causes hyper's
connection pool to be configured without idle timeouts, which may lead to
resource leaks, especially for clients that communicate with many virtual hosts.

This change updates the HTTP/1 client builder to use a Tokio timer, which allows
Hyper to manage idle timeouts correctly.
2025-07-14 14:56:35 -07:00
dependabot[bot] 21f3ffc6c1
build(deps): bump crc32fast from 1.4.2 to 1.5.0 (#4002)
Bumps [crc32fast](https://github.com/srijs/rust-crc32fast) from 1.4.2 to 1.5.0.
- [Commits](https://github.com/srijs/rust-crc32fast/compare/v1.4.2...v1.5.0)

---
updated-dependencies:
- dependency-name: crc32fast
  dependency-version: 1.5.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-14 11:49:32 -04:00
dependabot[bot] 1b85cf93a4
build(deps): bump memmap2 from 0.9.5 to 0.9.7 (#4001)
Bumps [memmap2](https://github.com/RazrFalcon/memmap2-rs) from 0.9.5 to 0.9.7.
- [Changelog](https://github.com/RazrFalcon/memmap2-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/RazrFalcon/memmap2-rs/commits)

---
updated-dependencies:
- dependency-name: memmap2
  dependency-version: 0.9.7
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-14 07:02:56 -07:00
dependabot[bot] ce5df7d026
build(deps): bump cc from 1.2.27 to 1.2.29 (#3999)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.27 to 1.2.29.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.27...cc-v1.2.29)

---
updated-dependencies:
- dependency-name: cc
  dependency-version: 1.2.29
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-11 15:17:08 -04:00
Scott Fleener 79e612c2f9
feat(meshtls): Include AES_256_GCM as a supported ciphersuite (#3991)
This is a strong ciphersuite that's reasonable to include as a supported option. We still prefer CHACHA20_POLY1305 in non-FIPS modes for its speed, as well as keeping CHACHA20_POLY1305 as a backup for older proxies that only support it.

Signed-off-by: Scott Fleener <scott@buoyant.io>
Co-authored-by: Oliver Gould <ver@buoyant.io>
2025-07-10 15:23:47 -04:00
Oliver Gould 62ed64ea05
chore(build): bump linkerd/dev to v46 (#3984)
* Rust 1.88
2025-07-10 14:15:24 -04:00
dependabot[bot] e8de6359a5
build(deps): bump hyper-util from 0.1.14 to 0.1.15 (#3997)
Bumps [hyper-util](https://github.com/hyperium/hyper-util) from 0.1.14 to 0.1.15.
- [Release notes](https://github.com/hyperium/hyper-util/releases)
- [Changelog](https://github.com/hyperium/hyper-util/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/hyper-util/compare/v0.1.14...v0.1.15)

---
updated-dependencies:
- dependency-name: hyper-util
  dependency-version: 0.1.15
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-10 12:50:50 -04:00
dependabot[bot] 53a17808a7
build(deps): bump libfuzzer-sys from 0.4.9 to 0.4.10 (#3994)
Bumps [libfuzzer-sys](https://github.com/rust-fuzz/libfuzzer) from 0.4.9 to 0.4.10.
- [Changelog](https://github.com/rust-fuzz/libfuzzer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-fuzz/libfuzzer/compare/0.4.9...0.4.10)

---
updated-dependencies:
- dependency-name: libfuzzer-sys
  dependency-version: 0.4.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-08 09:17:27 -04:00
katelyn martin 34b46ab6cd
refactor: `FmtLabels` impls use exhaustive bindings (#3988)
this is based on #3987.

in #3987 (_see https://github.com/linkerd/linkerd2/issues/13821_) we discovered that some of the types that implement [`FmtLabels`](085be9978d/linkerd/metrics/src/fmt.rs (L5)) could collide when used in registry keys; i.e., they might emit identical label sets, but distinct `Hash` values.

#3987 solves two bugs. this pull request proposes a follow-on change, introducing _exhaustive_ bindings to implementations of `FmtLabels`, to prevent this category of bug from reoccurring again in the future.

this change means that the introduction of an additional field to any of these label structures, e.g. `OutboundEndpointLabels` or `HTTPLocalRateLimitLabels`, will cause a compilation error unless said new field is handled in the corresponding `FmtLabels` implementation.

### 🔖 a note

in writing this pull request, i noticed one label that i believe is unintentionally being elided. i've refrained from changing behavior in this pull request. i do note it though, as an example of this syntax identifying the category of bug i hope to hedge against here.

---

* fix: do not key transport metrics registry on `ClientTls`

Signed-off-by: katelyn martin <kate@buoyant.io>

* fix: do not key transport metrics registry on `ServerTls`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(transport-metrics): exhaustive `Eos: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/core): exhaustive `ServerLabels: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/core): exhaustive `TlsAccept: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/core): exhaustive `TargetAddr: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(metrics): exhaustive `Label: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(http/metrics): exhaustive `Status: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/core): exhaustive `ControlLabels: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/core): exhaustive `ProfileRouteLabels: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/core): exhaustive `InboundEndpointLabels: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/core): exhaustive `ServerLabel: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/core): exhaustive `ServerAuthzLabels: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/core): exhaustive `RouteLabels: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/core): exhaustive `RouteAuthzLabels: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/core): exhaustive `OutboundEndpointLabels: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/core): exhaustive `Authority: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/core): exhaustive `StackLabels: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/inbound): exhaustive `HTTPLocalRateLimitLabels: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/inbound): exhaustive `Key<L>: FmtLabels`

Signed-off-by: katelyn martin <kate@buoyant.io>

* nit(metrics): remove redundant banner comment

these impl blocks are all `FmtLabels`, following another series of the
same, above. we don't need another one of these comments.

Signed-off-by: katelyn martin <kate@buoyant.io>

* nit(metrics): exhaustive `AndThen: FmtMetrics`

Signed-off-by: katelyn martin <kate@buoyant.io>

* nit(app/core): note unused label

see #3262 (618838ec7), which introduced this label.

to preserve behavior, this label remains unused.

X-Ref: #3262
Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-07-03 11:56:14 -04:00
Oliver Gould 288fc74800
chore(app): increase default max backoff durations (#3992)
The inbound and outbound connect backoffs are now set at 500ms. This is very aggressive in practice, especially when an endpoint remains unavailable.

This change increases the maximum backoff durations:

* inbound: 10s
* outbound: 60s

The default minimum backoff durations remain unchanged at 100ms so that failed
connections are retried quickly. This change only increases the default _maximum_ backoff so that the timeout increases substantially when an endpoint is unavailable for a longer period of time.
2025-07-02 18:52:53 -07:00
katelyn martin 030fa28d55
fix: remove ambiguous metrics registry keys (#3987)
### 🖼️ background

the linkerd2 proxy implements, registers, and exports Prometheus metrics using a variety of systems, for historical reasons. new metrics broadly rely upon the official [`prometheus-client`](https://github.com/prometheus/client_rust/) library, whose interfaces are reexported for internal consumption in the [`linkerd_metrics::prom`](https://github.com/linkerd/linkerd2-proxy/blob/main/linkerd/metrics/src/lib.rs#L30-L60) namespace.

other metrics predate this library however, and rely on the metrics registry implemented in the workspace's [`linkerd-metrics`](https://github.com/linkerd/linkerd2-proxy/tree/main/linkerd/metrics) library.

### 🐛 bug report

* https://github.com/linkerd/linkerd2/issues/13821

linkerd/linkerd2#13821 reported a bug in which duplicate metrics could be observed and subsequently dropped by Prometheus when upgrading the control plane via helm with an existing workload running.

### 🦋 reproduction example

for posterity, i'll note the reproduction steps here.

i used these steps to identify the `2025.3.2` edge release as the affected release. upgrading from `2025.2.3` to `2025.3.1` did not exhibit this behavior. see below for more discussion about the cause.

generate certificates via <https://linkerd.io/2.18/tasks/generate-certificates/>

using these two deployments, courtesy of @GTRekter:

<details>
<summary>**💾 click to expand: app deployment**</summary>

```yaml
apiVersion: v1 
kind: Namespace 
metadata: 
  name: simple-app 
  annotations: 
    linkerd.io/inject: enabled 
---
apiVersion: v1 
kind: Service 
metadata: 
  name: simple-app-v1 
  namespace: simple-app 
spec: 
  selector: 
    app: simple-app-v1 
    version: v1 
  ports: 
    - port: 80 
      targetPort: 5678
---
apiVersion: apps/v1 
kind: Deployment 
metadata: 
  name: simple-app-v1 
  namespace: simple-app 
spec: 
  replicas: 1 
  selector: 
    matchLabels: 
      app: simple-app-v1 
      version: v1 
  template: 
    metadata: 
      labels: 
        app: simple-app-v1 
        version: v1 
    spec: 
      containers: 
        - name: http-app 
          image: hashicorp/http-echo:latest 
          args: 
            - "-text=Simple App v1" 
          ports: 
            - containerPort: 5678 
```
</details>

<details>
<summary>**🤠 click to expand: client deployment**</summary>

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: traffic
  namespace: simple-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: traffic
  template:
    metadata:
      labels:
        app: traffic
    spec:
      containers:
      - name: traffic
        image: curlimages/curl:latest
        command:
          - /bin/sh
          - -c
          - |
            while true; do
              TIMESTAMP_SEND=$(date '+%Y-%m-%d %H:%M:%S')
              PAYLOAD="{\"timestamp\":\"$TIMESTAMP_SEND\",\"test_id\":\"sniff_me\",\"message\":\"hello-world\"}"
              echo "$TIMESTAMP_SEND - Sending payload: $PAYLOAD"
              RESPONSE=$(curl -s -X POST \
                -H "Content-Type: application/json" \
                -d "$PAYLOAD" \
                http://simple-app-v1.simple-app.svc.cluster.local:80)
              TIMESTAMP_RESPONSE=$(date '+%Y-%m-%d %H:%M:%S')
              echo "$TIMESTAMP_RESPONSE - RESPONSE: $RESPONSE"
              sleep 1
            done
```
</details>

and this prometheus configuration:

<details>
<summary>**🔥 click to expand: prometheus configuration**</summary>

```yaml
global:
  scrape_interval: 10s

scrape_configs:
  - job_name: 'pod'
    scrape_interval: 10s
    static_configs:
    - targets: ['localhost:4191']
      labels:
        group: 'traffic'
```
</details>

we will perform the following steps:

```sh
# install the edge release

# specify the versions we'll migrate between.
export FROM="2025.3.1"
export TO="2025.3.2"

# create a cluster, and add the helm charts.
kind create cluster
helm repo add linkerd-edge https://helm.linkerd.io/edge

# install linkerd's crd's and control plane.
helm install linkerd-crds linkerd-edge/linkerd-crds \
  -n linkerd --create-namespace --version $FROM

helm install linkerd-control-plane \
  -n linkerd \
  --set-file identityTrustAnchorsPEM=cert/ca.crt \
  --set-file identity.issuer.tls.crtPEM=cert/issuer.crt \
  --set-file identity.issuer.tls.keyPEM=cert/issuer.key \
  --version $FROM \
  linkerd-edge/linkerd-control-plane

# install a simple app and a client to drive traffic.
kubectl apply -f duplicate-metrics-simple-app.yml
kubectl apply -f duplicate-metrics-traffic.yml

# bind the traffic pod's metrics port to the host.
kubectl port-forward -n simple-app deploy/traffic 4191

# start prometheus, begin scraping metrics
prometheus --config.file=prometheus.yml
```

now, open a browser and query `irate(request_total[1m])`.

next, upgrade the control plane:

```
helm upgrade linkerd-crds linkerd-edge/linkerd-crds \
  -n linkerd --create-namespace --version $TO
helm upgrade linkerd-control-plane \
  -n linkerd \
  --set-file identityTrustAnchorsPEM=cert/ca.crt \
  --set-file identity.issuer.tls.crtPEM=cert/issuer.crt \
  --set-file identity.issuer.tls.keyPEM=cert/issuer.key \
  --version $TO \
  linkerd-edge/linkerd-control-plane
```

prometheus will begin emitting warnings regarding 34 time series being dropped.

in your browser, querying `irate(request_total[1m])` once more will show that
the rate of requests has stopped, due to the new time series being dropped.

next, restart the workloads...

```
kubectl rollout restart deployment -n simple-app simple-app-v1 traffic
```

prometheus warnings will go away, as reported in linkerd/linkerd2#13821.

### 🔍 related changes

* https://github.com/linkerd/linkerd2/pull/13699
* https://github.com/linkerd/linkerd2/pull/13715

in linkerd/linkerd2#13715 and linkerd/linkerd2##13699, we made some changes to the destination controller. from the "Cautions" section of the `2025.3.2` edge release:

> Additionally, this release changes the default for `outbound-transport-mode`
> to `transport-header`, which will result in all traffic between meshed
> proxies flowing on port 4143, rather than using the original destination
> port.

linkerd/linkerd2#13699 (_included in `edge-25.3.1`_) introduced this outbound transport-protocol configuration surface, but maintained the default behavior, while linkerd/linkerd2#13715 (_included in `edge-25.3.2`_) altered the default behavior to route meshed traffic via port 4143.

this is a visible change in behavior that can be observed when upgrading from a version that preceded this change to the mesh. this means that when upgrading across `edge-25.3.2`, such as from the `2025.2.1` to `2025.3.2` versions of the helm charts, or from the `2025.2.3` to the `2025.3.4` versions of the helm charts (_reported upstream in linkerd/linkerd2#13821_), the freshly upgraded destination controller pods will begin routing meshed traffic differently.

i'll state explicitly, _that_ is not a bug! it is, however, an important clue to bear in mind: data plane pods that were started with the previous control plane version, and continue running after the control plane upgrade, will have seen both routing patterns. reporting a duplicate time series for affected metrics indicates that there is a hashing collision in our metrics system.

### 🐛 the bug(s)

we define a collection to structures to model labels for inbound and outbound endpoints'
metrics:

```rust
// linkerd/app/core/src/metrics.rs

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum EndpointLabels {
    Inbound(InboundEndpointLabels),
    Outbound(OutboundEndpointLabels),
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct InboundEndpointLabels {
    pub tls: tls::ConditionalServerTls,
    pub authority: Option<http::uri::Authority>,
    pub target_addr: SocketAddr,
    pub policy: RouteAuthzLabels,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct OutboundEndpointLabels {
    pub server_id: tls::ConditionalClientTls,
    pub authority: Option<http::uri::Authority>,
    pub labels: Option<String>,
    pub zone_locality: OutboundZoneLocality,
    pub target_addr: SocketAddr,
}
```

\- <https://github.com/linkerd/linkerd2-proxy/blob/main/linkerd/app/core/src/metrics.rs>

bear particular attention to the derived `Hash` implementation. note the `tls::ConditionalClientTls` and `tls::ConditionalServerTls` types used in each of these labels. these are used by some of our types like `TlsConnect` to emit prometheus labels, using our legacy system's `FmtLabels` trait:

```rust
// linkerd/app/core/src/transport/labels.rs

impl FmtLabels for TlsConnect<'_> {
    fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.0 {
            Conditional::None(tls::NoClientTls::Disabled) => {
                write!(f, "tls=\"disabled\"")
            }
            Conditional::None(why) => {
                write!(f, "tls=\"no_identity\",no_tls_reason=\"{}\"", why)
            }
            Conditional::Some(tls::ClientTls { server_id, .. }) => {
                write!(f, "tls=\"true\",server_id=\"{}\"", server_id)
            }
        }
    }
}
```

\- <99316f7898/linkerd/app/core/src/transport/labels.rs (L151-L165)>

note the `ClientTls` case, which ignores fields in the client tls information:

```rust
// linkerd/tls/src/client.rs

/// A stack parameter that configures a `Client` to establish a TLS connection.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct ClientTls {
    pub server_name: ServerName,
    pub server_id: ServerId,
    pub alpn: Option<AlpnProtocols>,
}
```

\- <99316f7898/linkerd/tls/src/client.rs (L20-L26)>

this means that there is potential for an identical set of labels to be emitted given two `ClientTls` structures with distinct server names or ALPN protocols. for brevity, i'll elide the equivalent issue with `ServerTls`, and its corresponding `TlsAccept<'_>` label implementation, though it exhibits the same issue.

### 🔨 the fix

this pull request introduces two new types: `ClientTlsLabels` and `ServerTlsLabels`. these continue to implement `Hash`, for use as a key in our metrics registry, and for use in formatting labels.

`ClientTlsLabels` and `ServerTlsLabels` each resemble `ClientTls` and `ServerTls`, respectively, but do not contain any fields that are elided in label formatting, to prevent duplicate metrics from being emitted.

relatedly, #3988 audits our existing `FmtLabels` implementations and makes use of exhaustive bindings, to prevent this category of problem in the short-term future. ideally, we might eventually consider replacing the metrics interfaces in `linkerd-metrics`, but that is strictly kept out-of-scope for the purposes of this particular fix.

---

* fix: do not key transport metrics registry on `ClientTls`

Signed-off-by: katelyn martin <kate@buoyant.io>

* fix: do not key transport metrics registry on `ServerTls`

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-07-02 12:38:04 -04:00
dependabot[bot] 085be9978d
build(deps): bump indexmap from 2.9.0 to 2.10.0 (#3986)
Bumps [indexmap](https://github.com/indexmap-rs/indexmap) from 2.9.0 to 2.10.0.
- [Changelog](https://github.com/indexmap-rs/indexmap/blob/main/RELEASES.md)
- [Commits](https://github.com/indexmap-rs/indexmap/compare/2.9.0...2.10.0)

---
updated-dependencies:
- dependency-name: indexmap
  dependency-version: 2.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-27 11:19:12 -04:00
dependabot[bot] 682421c98a
build(deps): bump Swatinem/rust-cache from 2.7.8 to 2.8.0 (#3983)
Bumps [Swatinem/rust-cache](https://github.com/swatinem/rust-cache) from 2.7.8 to 2.8.0.
- [Release notes](https://github.com/swatinem/rust-cache/releases)
- [Changelog](https://github.com/Swatinem/rust-cache/blob/master/CHANGELOG.md)
- [Commits](9d47c6ad4b...98c8021b55)

---
updated-dependencies:
- dependency-name: Swatinem/rust-cache
  dependency-version: 2.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-26 12:25:06 -04:00
katelyn martin 2b1e3925d5
fix(proxy/http): remove http/1 header read timeout (#3985)
this fixes #14131. this relates to #14147, though it does not introduce
a configurable option for this timeout.

 ###  background

in hyper 0.14, http/1.1 connections had no default header read timeout.
per the documentation for
[`hyper::server::Builder::http1_header_read_timeout()`][read-timeout-previous]:

> Set a timeout for reading client request headers. If a client does not
transmit the entire header within this time, the connection is closed.
>
> Default is None.

compare this with the latest hyper release, which enforces a
30 second timeout for http/1.1 connections. per the documentation for
[`hyper::server::conn::http1::Builder::header_read_timeout`][read-timeout-current]:

> Set a timeout for reading client request headers. If a client does not
> transmit the entire header within this time, the connection is closed.
>
> Requires a
> [Timer](https://docs.rs/hyper/latest/hyper/rt/trait.Timer.html) set by
> [Builder::timer](https://docs.rs/hyper/latest/hyper/server/conn/http1/struct.Builder.html#method.timer)
> to take effect. Panics if header_read_timeout is configured without a
> [Timer](https://docs.rs/hyper/latest/hyper/rt/trait.Timer.html).
>
> Pass None to disable.
>
> Default is 30 seconds.

this was changed in hyperium/hyper#3395, which was included in [the v1.0
release][v1-changelog].

[read-timeout-previous]: https://docs.rs/hyper/0.14.31/hyper/server/struct.Builder.html#method.http1_header_read_timeout
[read-timeout-current]: https://docs.rs/hyper/latest/hyper/server/conn/http1/struct.Builder.html#method.header_read_timeout
[v1-changelog]: https://github.com/hyperium/hyper/blob/master/CHANGELOG.md#v100-2023-11-15

 ### 🔨 changes

this commit passes `None` to the `linkerd-proxy-http::server::ServeHttp`
type's http/1 server-side connection builder, to remove the header read
timeout.

this restores the behavior that existed prior to linkerd/linkerd2#8733,
which upgraded our hyper dependency from 0.14 to 1.0.

X-Ref: https://github.com/linkerd/linkerd2/issues/14147
X-Ref: https://github.com/linkerd/linkerd2/issues/14131
X-Ref: https://github.com/linkerd/linkerd2/issues/8733
X-Ref: https://github.com/hyperium/hyper/issues/3395

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-06-26 12:08:38 -04:00
dependabot[bot] 504581e1d7
build(deps): bump bumpalo from 3.18.1 to 3.19.0 (#3982)
Bumps [bumpalo](https://github.com/fitzgen/bumpalo) from 3.18.1 to 3.19.0.
- [Changelog](https://github.com/fitzgen/bumpalo/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fitzgen/bumpalo/commits)

---
updated-dependencies:
- dependency-name: bumpalo
  dependency-version: 3.19.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-25 08:32:25 -04:00
Zahari Dichev 2869076d58
identity(spire): provide named pipe support for spire (#3970)
This change does two things: 
- adds support for `NamedPipes` to our SPIRE client. This will allow the client to connect to spire agents running on Windows hosts
- renames the `LINKERD2_PROXY_IDENTITY_SPIRE_SOCKET` to `LINKERD2_PROXY_IDENTITY_SPIRE_WORKLOAD_API_ADDRESS` and deprecates the former.

Signed-off-by: Zahari Dichev <zaharidichev@gmail.com>
2025-06-25 11:01:45 +03:00
dependabot[bot] 99316f7898
build(deps): bump prettyplease from 0.2.34 to 0.2.35 (#3981)
Bumps [prettyplease](https://github.com/dtolnay/prettyplease) from 0.2.34 to 0.2.35.
- [Release notes](https://github.com/dtolnay/prettyplease/releases)
- [Commits](https://github.com/dtolnay/prettyplease/compare/0.2.34...0.2.35)

---
updated-dependencies:
- dependency-name: prettyplease
  dependency-version: 0.2.35
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-24 09:17:31 -04:00
dependabot[bot] 7255530037
build(deps): bump syn from 2.0.103 to 2.0.104 (#3980)
---
updated-dependencies:
- dependency-name: syn
  dependency-version: 2.0.104
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-23 08:04:23 -04:00
Oliver Gould 3fe2dee32e
fix(errno): comment typo (#3949) 2025-06-20 15:00:10 +00:00
dependabot[bot] 3590892686
build(deps): bump errno from 0.3.12 to 0.3.13 (#3979)
Bumps [errno](https://github.com/lambda-fairy/rust-errno) from 0.3.12 to 0.3.13.
- [Release notes](https://github.com/lambda-fairy/rust-errno/releases)
- [Changelog](https://github.com/lambda-fairy/rust-errno/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lambda-fairy/rust-errno/compare/v0.3.12...v0.3.13)

---
updated-dependencies:
- dependency-name: errno
  dependency-version: 0.3.13
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-20 10:09:16 -04:00
dependabot[bot] 80a216892d
build(deps): bump syn from 2.0.102 to 2.0.103 (#3978)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.102 to 2.0.103.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.102...2.0.103)

---
updated-dependencies:
- dependency-name: syn
  dependency-version: 2.0.103
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-20 10:09:07 -04:00
dependabot[bot] 4dc6353d0c
build(deps): bump autocfg from 1.4.0 to 1.5.0 (#3977)
Bumps [autocfg](https://github.com/cuviper/autocfg) from 1.4.0 to 1.5.0.
- [Commits](https://github.com/cuviper/autocfg/compare/1.4.0...1.5.0)

---
updated-dependencies:
- dependency-name: autocfg
  dependency-version: 1.5.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-20 09:58:37 -04:00
dependabot[bot] c325f526af
build(deps): bump slab from 0.4.9 to 0.4.10 (#3976)
Bumps [slab](https://github.com/tokio-rs/slab) from 0.4.9 to 0.4.10.
- [Release notes](https://github.com/tokio-rs/slab/releases)
- [Changelog](https://github.com/tokio-rs/slab/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/slab/compare/v0.4.9...v0.4.10)

---
updated-dependencies:
- dependency-name: slab
  dependency-version: 0.4.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-18 07:52:57 -04:00
dependabot[bot] 9b3d93ddf6
build(deps): bump libc from 0.2.173 to 0.2.174 (#3975)
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.173 to 0.2.174.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.174/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.173...0.2.174)

---
updated-dependencies:
- dependency-name: libc
  dependency-version: 0.2.174
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-18 07:51:52 -04:00
dependabot[bot] dcd34222a9
build(deps): bump tracing-attributes in the tracing group (#3974)
Bumps the tracing group with 1 update: [tracing-attributes](https://github.com/tokio-rs/tracing).


Updates `tracing-attributes` from 0.1.29 to 0.1.30
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-attributes-0.1.29...tracing-attributes-0.1.30)

---
updated-dependencies:
- dependency-name: tracing-attributes
  dependency-version: 0.1.30
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: tracing
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-18 07:51:26 -04:00
dependabot[bot] 8203cd2e96
build(deps): bump jiff from 0.2.14 to 0.2.15 (#3973)
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.14 to 0.2.15.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.14...jiff-static-0.2.15)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.15
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-17 12:12:22 -04:00
dependabot[bot] 19235e0841
build(deps): bump libc from 0.2.172 to 0.2.173 (#3972)
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.172 to 0.2.173.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.173/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.172...0.2.173)

---
updated-dependencies:
- dependency-name: libc
  dependency-version: 0.2.173
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-17 12:12:08 -04:00
dependabot[bot] 6f51389717
build(deps): bump thread_local from 1.1.8 to 1.1.9 (#3971)
Bumps [thread_local](https://github.com/Amanieu/thread_local-rs) from 1.1.8 to 1.1.9.
- [Release notes](https://github.com/Amanieu/thread_local-rs/releases)
- [Changelog](https://github.com/Amanieu/thread_local-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Amanieu/thread_local-rs/compare/1.1.8...v1.1.9)

---
updated-dependencies:
- dependency-name: thread_local
  dependency-version: 1.1.9
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-17 12:11:57 -04:00
dependabot[bot] 3c2854beb1
build(deps): bump aws-lc-fips-sys from 0.13.6 to 0.13.7 (#3968)
Bumps [aws-lc-fips-sys](https://github.com/aws/aws-lc-rs) from 0.13.6 to 0.13.7.
- [Release notes](https://github.com/aws/aws-lc-rs/releases)
- [Commits](https://github.com/aws/aws-lc-rs/compare/aws-lc-fips-sys/v0.13.6...aws-lc-fips-sys/v0.13.7)

---
updated-dependencies:
- dependency-name: aws-lc-fips-sys
  dependency-version: 0.13.7
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-16 12:26:15 -04:00
dependabot[bot] 35ef9b3c8b
build(deps): bump cc from 1.2.26 to 1.2.27 (#3969)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.26 to 1.2.27.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.26...cc-v1.2.27)

---
updated-dependencies:
- dependency-name: cc
  dependency-version: 1.2.27
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-16 12:26:07 -04:00
dependabot[bot] 4922138b3e
build(deps): bump prettyplease from 0.2.33 to 0.2.34 (#3967)
Bumps [prettyplease](https://github.com/dtolnay/prettyplease) from 0.2.33 to 0.2.34.
- [Release notes](https://github.com/dtolnay/prettyplease/releases)
- [Commits](https://github.com/dtolnay/prettyplease/compare/0.2.33...0.2.34)

---
updated-dependencies:
- dependency-name: prettyplease
  dependency-version: 0.2.34
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-16 12:22:48 -04:00
dependabot[bot] 47f3817dea
build(deps): bump memchr from 2.7.4 to 2.7.5 (#3966)
Bumps [memchr](https://github.com/BurntSushi/memchr) from 2.7.4 to 2.7.5.
- [Commits](https://github.com/BurntSushi/memchr/compare/2.7.4...2.7.5)

---
updated-dependencies:
- dependency-name: memchr
  dependency-version: 2.7.5
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-12 16:04:26 -04:00
dependabot[bot] 15bcb9a056
build(deps): bump cfg-if from 1.0.0 to 1.0.1 (#3965)
Bumps [cfg-if](https://github.com/rust-lang/cfg-if) from 1.0.0 to 1.0.1.
- [Release notes](https://github.com/rust-lang/cfg-if/releases)
- [Changelog](https://github.com/rust-lang/cfg-if/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cfg-if/compare/1.0.0...v1.0.1)

---
updated-dependencies:
- dependency-name: cfg-if
  dependency-version: 1.0.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-12 16:03:01 -04:00
dependabot[bot] 25212a4423
build(deps): bump softprops/action-gh-release from 2.3.0 to 2.3.2 (#3964)
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.3.0 to 2.3.2.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](d5382d3e6f...72f2c25fcb)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.3.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-12 08:45:20 -07:00
dependabot[bot] 4cd1fbf69a
build(deps): bump wasi (#3963)
Bumps [wasi](https://github.com/bytecodealliance/wasi) from 0.11.0+wasi-snapshot-preview1 to 0.11.1+wasi-snapshot-preview1.
- [Commits](https://github.com/bytecodealliance/wasi/compare/0.11.0...0.11.1)

---
updated-dependencies:
- dependency-name: wasi
  dependency-version: 0.11.1+wasi-snapshot-preview1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-11 11:30:55 -04:00
dependabot[bot] f2c68aa010
build(deps): bump smallvec from 1.15.0 to 1.15.1 (#3962)
Bumps [smallvec](https://github.com/servo/rust-smallvec) from 1.15.0 to 1.15.1.
- [Release notes](https://github.com/servo/rust-smallvec/releases)
- [Commits](https://github.com/servo/rust-smallvec/compare/v1.15.0...v1.15.1)

---
updated-dependencies:
- dependency-name: smallvec
  dependency-version: 1.15.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-11 11:30:31 -04:00
dependabot[bot] 14c3716fcd
build(deps): bump miniz_oxide from 0.8.8 to 0.8.9 (#3961)
Bumps [miniz_oxide](https://github.com/Frommi/miniz_oxide) from 0.8.8 to 0.8.9.
- [Changelog](https://github.com/Frommi/miniz_oxide/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Frommi/miniz_oxide/commits)

---
updated-dependencies:
- dependency-name: miniz_oxide
  dependency-version: 0.8.9
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-11 11:30:20 -04:00
dependabot[bot] 6118756991
build(deps): bump adler2 from 2.0.0 to 2.0.1 (#3960)
Bumps [adler2](https://github.com/oyvindln/adler2) from 2.0.0 to 2.0.1.
- [Changelog](https://github.com/oyvindln/adler2/blob/main/CHANGELOG.md)
- [Commits](https://github.com/oyvindln/adler2/commits)

---
updated-dependencies:
- dependency-name: adler2
  dependency-version: 2.0.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-10 10:11:16 -04:00
dependabot[bot] f508e7998c
build(deps): bump syn from 2.0.101 to 2.0.102 (#3959)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.101 to 2.0.102.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.101...2.0.102)

---
updated-dependencies:
- dependency-name: syn
  dependency-version: 2.0.102
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-10 10:10:40 -04:00
dependabot[bot] 9ed7f8cf7d
build(deps): bump rustc-demangle from 0.1.24 to 0.1.25 (#3958)
Bumps [rustc-demangle](https://github.com/rust-lang/rustc-demangle) from 0.1.24 to 0.1.25.
- [Commits](https://github.com/rust-lang/rustc-demangle/commits)

---
updated-dependencies:
- dependency-name: rustc-demangle
  dependency-version: 0.1.25
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-10 10:10:15 -04:00
dependabot[bot] 3da6013871
build(deps): bump softprops/action-gh-release from 2.2.2 to 2.3.0 (#3957)
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.2.2 to 2.3.0.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](da05d55257...d5382d3e6f)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-10 10:09:51 -04:00
dependabot[bot] 66d558b8b2
build(deps): bump cc from 1.2.25 to 1.2.26 (#3956)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.25 to 1.2.26.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.25...cc-v1.2.26)

---
updated-dependencies:
- dependency-name: cc
  dependency-version: 1.2.26
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-09 11:35:37 -04:00
dependabot[bot] ede8a97d25
build(deps): bump tracing-attributes in the tracing group (#3955)
Bumps the tracing group with 1 update: [tracing-attributes](https://github.com/tokio-rs/tracing).


Updates `tracing-attributes` from 0.1.28 to 0.1.29
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-attributes-0.1.28...tracing-attributes-0.1.29)

---
updated-dependencies:
- dependency-name: tracing-attributes
  dependency-version: 0.1.29
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: tracing
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-09 11:35:23 -04:00
dependabot[bot] 44cfdfd7fe
build(deps): bump flate2 from 1.1.1 to 1.1.2 (#3954)
Bumps [flate2](https://github.com/rust-lang/flate2-rs) from 1.1.1 to 1.1.2.
- [Release notes](https://github.com/rust-lang/flate2-rs/releases)
- [Commits](https://github.com/rust-lang/flate2-rs/compare/1.1.1...1.1.2)

---
updated-dependencies:
- dependency-name: flate2
  dependency-version: 1.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-09 11:35:07 -04:00
dependabot[bot] 8a515a3cc0
build(deps): bump portable-atomic from 1.11.0 to 1.11.1 (#3952)
Bumps [portable-atomic](https://github.com/taiki-e/portable-atomic) from 1.11.0 to 1.11.1.
- [Release notes](https://github.com/taiki-e/portable-atomic/releases)
- [Changelog](https://github.com/taiki-e/portable-atomic/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/portable-atomic/compare/v1.11.0...v1.11.1)

---
updated-dependencies:
- dependency-name: portable-atomic
  dependency-version: 1.11.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-06 10:53:05 -04:00
dependabot[bot] d1ecb03c9f
build(deps): bump bumpalo from 3.17.0 to 3.18.1 (#3951)
Bumps [bumpalo](https://github.com/fitzgen/bumpalo) from 3.17.0 to 3.18.1.
- [Changelog](https://github.com/fitzgen/bumpalo/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fitzgen/bumpalo/compare/3.17.0...v3.18.1)

---
updated-dependencies:
- dependency-name: bumpalo
  dependency-version: 3.18.1
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-06 10:52:47 -04:00
dependabot[bot] f4ae038d79
build(deps): bump tracing-core in the tracing group (#3950)
Bumps the tracing group with 1 update: [tracing-core](https://github.com/tokio-rs/tracing).


Updates `tracing-core` from 0.1.33 to 0.1.34
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-core-0.1.33...tracing-core-0.1.34)

---
updated-dependencies:
- dependency-name: tracing-core
  dependency-version: 0.1.34
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: tracing
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-06 10:52:38 -04:00
dependabot[bot] 3aa53596f7
build(deps): bump hyper-util from 0.1.13 to 0.1.14 (#3948)
Bumps [hyper-util](https://github.com/hyperium/hyper-util) from 0.1.13 to 0.1.14.
- [Release notes](https://github.com/hyperium/hyper-util/releases)
- [Changelog](https://github.com/hyperium/hyper-util/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/hyper-util/compare/v0.1.13...v0.1.14)

---
updated-dependencies:
- dependency-name: hyper-util
  dependency-version: 0.1.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-05 06:51:50 -07:00
katelyn martin 67dc85a367
chore(app/test): remove unused dependencies (#3932)
`linkerd-app-test` relies on some dependencies that are unused.

this commit removes these dependencies from the crate's manifest.

see #3928 and #3929.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-06-02 15:10:53 -07:00
katelyn martin ea6f407c57
fix(http/retry): `PeekTrailersBody<B>` retains first frame (#3947)
see linkerd/linkerd2#14050.

this change fixes a logical bug with
`linkerd_http_retry::peek_trailers::PeekTrailersBody::<B>::read_body(..)`.

`read_body(..)` constructs a `PeekTrailersBody<B>`, by polling the inner
body to see whether or not it can reach the end of the stream by only
yielding to the asynchronous runtime once.

in linkerd/linkerd2-proxy#3559, we restructured this middleware's
internal modeling to reflect the `Frame<T>`-oriented signatures of the
`http_body::Body` trait's 1.0 interface.

unfortunately, this included a bug which could cause the first frame in
a stream to be discarded if the second `Body::poll_frame()` call
(_invoked via `now_or_never()`_) returns `Pending`. this could cause
non-deterministic errors for users when sending traffic to HTTPRoutes
and GRPCRoutes with retry annotations applied.

this change rectifies this problem, ensuring that the first frame is not
discarded when attempting to peek a body's trailers.

to confirm that this works as expected, additional test coverage is
introduced that confirms that the data and trailers of the inner body
are passed through faithfully.

---

* feat(http/retry): additional `PeekTrailersBody<B>` test coverage

this commit introduces additional test coverage to
`linker_http_retry::peek_trailers::PeekTrailersBody<B>`.

this body middleware is used to facilitate transparent http retries, and
allows callers to possibly inspect the trailers for a response, by
polling an `http_body::Body`.

this commit introduces additional unit test coverage that confirms that
the data and trailers of the inner body are passed through faithfully.

Signed-off-by: katelyn martin <kate@buoyant.io>

* feat(http/retry): another `PeekTrailersBody<B>` test case

this commit introduces some additional coverage for bodies that return
`Pending` when polled a second time.

Signed-off-by: katelyn martin <kate@buoyant.io>

* fix(http/retry): `PeekTrailersBody<B>` retains first frame

this commit fixes a logical bug with
`linkerd_http_retry::peek_trailers::PeekTrailersBody::<B>::read_body(..)`.

`read_body(..)` constructs a `PeekTrailersBody<B>`, by polling the inner
body to see whether or not it can reach the end of the stream by only
yielding to the asynchronous runtime once.

in linkerd/linkerd2-proxy#3559, we restructured this middleware's
internal modeling to reflect the `Frame<T>`-oriented signatures of the
`http_body::Body` trait's 1.0 interface.

unfortunately, this included a bug which could cause the first frame in
a stream to be discarded if the second `Body::poll_frame()` call
(_invoked via `now_or_never()`_) returns `Pending`. this could cause
non-deterministic errors for users when sending traffic to HTTPRoutes
and GRPCRoutes with retry annotations applied.

this commit rectifies this problem, ensuring that the first frame is not
discarded when attempting to peek a body's trailers.

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-06-02 09:53:24 -07:00
dependabot[bot] c36bef6b47
build(deps): bump num_cpus from 1.16.0 to 1.17.0 (#3946)
Bumps [num_cpus](https://github.com/seanmonstar/num_cpus) from 1.16.0 to 1.17.0.
- [Release notes](https://github.com/seanmonstar/num_cpus/releases)
- [Changelog](https://github.com/seanmonstar/num_cpus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/num_cpus/compare/v1.16.0...v1.17.0)

---
updated-dependencies:
- dependency-name: num_cpus
  dependency-version: 1.17.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-02 08:51:23 -04:00
dependabot[bot] 12822d1848
build(deps): bump cc from 1.2.24 to 1.2.25 (#3945)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.24 to 1.2.25.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.24...cc-v1.2.25)

---
updated-dependencies:
- dependency-name: cc
  dependency-version: 1.2.25
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-02 08:51:10 -04:00
dependabot[bot] 66b5f330c3
build(deps): bump prettyplease from 0.2.32 to 0.2.33 (#3944)
Bumps [prettyplease](https://github.com/dtolnay/prettyplease) from 0.2.32 to 0.2.33.
- [Release notes](https://github.com/dtolnay/prettyplease/releases)
- [Commits](https://github.com/dtolnay/prettyplease/compare/0.2.32...0.2.33)

---
updated-dependencies:
- dependency-name: prettyplease
  dependency-version: 0.2.33
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-02 08:50:58 -04:00
dependabot[bot] 423b5c07e6
build(deps): bump parking_lot from 0.12.3 to 0.12.4 (#3943)
Bumps [parking_lot](https://github.com/Amanieu/parking_lot) from 0.12.3 to 0.12.4.
- [Release notes](https://github.com/Amanieu/parking_lot/releases)
- [Changelog](https://github.com/Amanieu/parking_lot/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Amanieu/parking_lot/compare/0.12.3...parking_lot-v0.12.4)

---
updated-dependencies:
- dependency-name: parking_lot
  dependency-version: 0.12.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-30 08:18:04 -04:00
dependabot[bot] 0a17238d10
build(deps): bump parking_lot_core from 0.9.10 to 0.9.11 (#3942)
Bumps [parking_lot_core](https://github.com/Amanieu/parking_lot) from 0.9.10 to 0.9.11.
- [Release notes](https://github.com/Amanieu/parking_lot/releases)
- [Changelog](https://github.com/Amanieu/parking_lot/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Amanieu/parking_lot/compare/core-0.9.10...parking_lot_core-v0.9.11)

---
updated-dependencies:
- dependency-name: parking_lot_core
  dependency-version: 0.9.11
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-30 08:17:37 -04:00
dependabot[bot] cbfef553ce
build(deps): bump lock_api from 0.4.12 to 0.4.13 (#3941)
Bumps [lock_api](https://github.com/Amanieu/parking_lot) from 0.4.12 to 0.4.13.
- [Release notes](https://github.com/Amanieu/parking_lot/releases)
- [Changelog](https://github.com/Amanieu/parking_lot/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Amanieu/parking_lot/compare/lock_api-0.4.12...lock_api-v0.4.13)

---
updated-dependencies:
- dependency-name: lock_api
  dependency-version: 0.4.13
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-30 08:17:20 -04:00
dependabot[bot] 6233b47dd3
build(deps): bump libloading from 0.8.7 to 0.8.8 (#3940)
Bumps [libloading](https://github.com/nagisa/rust_libloading) from 0.8.7 to 0.8.8.
- [Commits](https://github.com/nagisa/rust_libloading/commits)

---
updated-dependencies:
- dependency-name: libloading
  dependency-version: 0.8.8
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-29 10:44:53 -04:00
dependabot[bot] 19bfb14f1f
build(deps): bump pprof from 0.14.0 to 0.15.0 (#3938)
Bumps [pprof](https://github.com/tikv/pprof-rs) from 0.14.0 to 0.15.0.
- [Changelog](https://github.com/tikv/pprof-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tikv/pprof-rs/commits)

---
updated-dependencies:
- dependency-name: pprof
  dependency-version: 0.15.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-28 11:13:34 -04:00
dependabot[bot] c6eea70f1a
build(deps): bump hyper-util from 0.1.12 to 0.1.13 (#3939)
Bumps [hyper-util](https://github.com/hyperium/hyper-util) from 0.1.12 to 0.1.13.
- [Release notes](https://github.com/hyperium/hyper-util/releases)
- [Changelog](https://github.com/hyperium/hyper-util/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/hyper-util/compare/v0.1.12...v0.1.13)

---
updated-dependencies:
- dependency-name: hyper-util
  dependency-version: 0.1.13
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-28 11:13:08 -04:00
dependabot[bot] 96d7c25704
build(deps): bump the boring group with 3 updates (#3937)
Bumps the boring group with 3 updates: [boring](https://github.com/cloudflare/boring), [tokio-boring](https://github.com/cloudflare/boring) and [boring-sys](https://github.com/cloudflare/boring).


Updates `boring` from 4.16.0 to 4.17.0
- [Release notes](https://github.com/cloudflare/boring/releases)
- [Changelog](https://github.com/cloudflare/boring/blob/master/RELEASE_NOTES)
- [Commits](https://github.com/cloudflare/boring/compare/v4.16.0...v4.17.0)

Updates `tokio-boring` from 4.16.0 to 4.17.0
- [Release notes](https://github.com/cloudflare/boring/releases)
- [Changelog](https://github.com/cloudflare/boring/blob/master/RELEASE_NOTES)
- [Commits](https://github.com/cloudflare/boring/compare/v4.16.0...v4.17.0)

Updates `boring-sys` from 4.16.0 to 4.17.0
- [Release notes](https://github.com/cloudflare/boring/releases)
- [Changelog](https://github.com/cloudflare/boring/blob/master/RELEASE_NOTES)
- [Commits](https://github.com/cloudflare/boring/compare/v4.16.0...v4.17.0)

---
updated-dependencies:
- dependency-name: boring
  dependency-version: 4.17.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: boring
- dependency-name: tokio-boring
  dependency-version: 4.17.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: boring
- dependency-name: boring-sys
  dependency-version: 4.17.0
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: boring
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-28 08:23:55 -04:00
dependabot[bot] 1450af00d8
build(deps): bump the opentelemetry group with 2 updates (#3934)
Bumps the opentelemetry group with 2 updates: [opentelemetry](https://github.com/open-telemetry/opentelemetry-rust) and [opentelemetry_sdk](https://github.com/open-telemetry/opentelemetry-rust).


Updates `opentelemetry` from 0.29.1 to 0.30.0
- [Release notes](https://github.com/open-telemetry/opentelemetry-rust/releases)
- [Commits](https://github.com/open-telemetry/opentelemetry-rust/compare/opentelemetry-0.29.1...opentelemetry-0.30.0)

Updates `opentelemetry_sdk` from 0.29.0 to 0.30.0
- [Release notes](https://github.com/open-telemetry/opentelemetry-rust/releases)
- [Commits](https://github.com/open-telemetry/opentelemetry-rust/compare/opentelemetry_sdk-0.29.0...opentelemetry_sdk-0.30.0)

---
updated-dependencies:
- dependency-name: opentelemetry
  dependency-version: 0.30.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: opentelemetry
- dependency-name: opentelemetry_sdk
  dependency-version: 0.30.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: opentelemetry
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-27 07:17:39 -07:00
dependabot[bot] 27f62ad034
build(deps): bump mio from 1.0.3 to 1.0.4 (#3933)
Bumps [mio](https://github.com/tokio-rs/mio) from 1.0.3 to 1.0.4.
- [Release notes](https://github.com/tokio-rs/mio/releases)
- [Changelog](https://github.com/tokio-rs/mio/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/mio/commits)

---
updated-dependencies:
- dependency-name: mio
  dependency-version: 1.0.4
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-27 09:35:24 -04:00
dependabot[bot] fefa7c0cbf
build(deps): bump socket2 from 0.5.9 to 0.5.10 (#3936)
Bumps [socket2](https://github.com/rust-lang/socket2) from 0.5.9 to 0.5.10.
- [Release notes](https://github.com/rust-lang/socket2/releases)
- [Changelog](https://github.com/rust-lang/socket2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/socket2/commits)

---
updated-dependencies:
- dependency-name: socket2
  dependency-version: 0.5.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-27 09:33:06 -04:00
katelyn martin b3549bc767
chore(app/test): remove unused functions (#3929)
`linkerd-app-test` exposes some functions that we never use elsewhere.

this commit removes these functions.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-05-23 09:25:12 -07:00
katelyn martin c00ce3241b
chore(app/test): remove unused `service` submodule (#3928)
`linkerd_app_test::service` contains facilities that are unused.

this commit removes this submodule from the `linkerd-app-test` library.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-05-23 09:25:00 -07:00
dependabot[bot] 21fd4ec51b
build(deps): bump rustversion from 1.0.20 to 1.0.21 (#3931)
Bumps [rustversion](https://github.com/dtolnay/rustversion) from 1.0.20 to 1.0.21.
- [Release notes](https://github.com/dtolnay/rustversion/releases)
- [Commits](https://github.com/dtolnay/rustversion/compare/1.0.20...1.0.21)

---
updated-dependencies:
- dependency-name: rustversion
  dependency-version: 1.0.21
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-23 08:38:35 -04:00
dependabot[bot] fa0c104931
build(deps): bump cc from 1.2.23 to 1.2.24 (#3930)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.23 to 1.2.24.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.23...cc-v1.2.24)

---
updated-dependencies:
- dependency-name: cc
  dependency-version: 1.2.24
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-23 08:38:10 -04:00
katelyn martin cab7adc456
chore(meshtls/boring): sort dependencies (#3927)
Signed-off-by: katelyn martin <kate@buoyant.io>
2025-05-22 16:20:58 -04:00
katelyn martin 478e1e151f
chore(deps): bump DavidAnson/markdownlint-cli2-action (#3923)
* chore(docs): address `no-generic-link-test` lint (#3923)

this addresses errors observed by dependabot when upgrading to the
latest version of `markdownlint`.

there is a new lint, added in DavidAnson/markdownlint#1459, that
introduces forbidden link text to discourage generic `here` text in
links.

this fixes sentences that included a link labeled "here".

* https://github.com/linkerd/linkerd2-proxy/pull/3918
* https://github.com/linkerd/linkerd2-proxy/actions/runs/15043224730/job/42279610780?pr=3918
* https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md059.md
* https://github.com/DavidAnson/markdownlint/pull/1459
* https://github.com/DavidAnson/markdownlint/issues/681

```
 Summary: 3 error(s)
Error: docs/FUZZING.md:17:13 MD059/descriptive-link-text Link text should be descriptive [Context: "[here]"] https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md059.md
Error: docs/FUZZING.md💯2 MD059/descriptive-link-text Link text should be descriptive [Context: "[here]"] https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md059.md
Error: README.md:90:2 MD059/descriptive-link-text Link text should be descriptive [Context: "[here]"] https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md059.md
Error: Failed with exit code: 1
```

Signed-off-by: katelyn martin <kate@buoyant.io>

* build(deps): bump DavidAnson/markdownlint-cli2-action (#3923)

Bumps [DavidAnson/markdownlint-cli2-action](https://github.com/davidanson/markdownlint-cli2-action) from 19.1.0 to 20.0.0.
- [Release notes](https://github.com/davidanson/markdownlint-cli2-action/releases)
- [Commits](05f32210e8...992badcdf2)

---
updated-dependencies:
- dependency-name: DavidAnson/markdownlint-cli2-action
  dependency-version: 20.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-22 13:16:37 -07:00
dependabot[bot] 1eeae37018
build(deps): bump jiff from 0.2.13 to 0.2.14 (#3926)
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.13 to 0.2.14.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.13...jiff-static-0.2.14)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-21 10:29:08 -04:00
dependabot[bot] 83d4eacb27
build(deps): bump hyper-util from 0.1.11 to 0.1.12 (#3925)
Bumps [hyper-util](https://github.com/hyperium/hyper-util) from 0.1.11 to 0.1.12.
- [Release notes](https://github.com/hyperium/hyper-util/releases)
- [Changelog](https://github.com/hyperium/hyper-util/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/hyper-util/compare/v0.1.11...v0.1.12)

---
updated-dependencies:
- dependency-name: hyper-util
  dependency-version: 0.1.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-20 09:15:20 -04:00
dependabot[bot] ddc590f38b
build(deps): bump the icu4x group with 2 updates (#3924)
Bumps the icu4x group with 2 updates: [icu_properties](https://github.com/unicode-org/icu4x) and [icu_properties_data](https://github.com/unicode-org/icu4x).


Updates `icu_properties` from 2.0.0 to 2.0.1
- [Release notes](https://github.com/unicode-org/icu4x/releases)
- [Changelog](https://github.com/unicode-org/icu4x/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unicode-org/icu4x/commits)

Updates `icu_properties_data` from 2.0.0 to 2.0.1
- [Release notes](https://github.com/unicode-org/icu4x/releases)
- [Changelog](https://github.com/unicode-org/icu4x/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unicode-org/icu4x/commits)

---
updated-dependencies:
- dependency-name: icu_properties
  dependency-version: 2.0.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: icu4x
- dependency-name: icu_properties_data
  dependency-version: 2.0.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: icu4x
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-20 09:14:43 -04:00
dependabot[bot] 0f42f15102
build(deps): bump codecov/codecov-action from 5.4.2 to 5.4.3 (#3920)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.4.2 to 5.4.3.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](ad3126e916...18283e04ce)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-version: 5.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-16 16:21:34 -04:00
dependabot[bot] 20f47ad9de
build(deps): bump errno from 0.3.11 to 0.3.12 (#3922)
Bumps [errno](https://github.com/lambda-fairy/rust-errno) from 0.3.11 to 0.3.12.
- [Release notes](https://github.com/lambda-fairy/rust-errno/releases)
- [Changelog](https://github.com/lambda-fairy/rust-errno/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lambda-fairy/rust-errno/compare/v0.3.11...v0.3.12)

---
updated-dependencies:
- dependency-name: errno
  dependency-version: 0.3.12
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-16 10:01:34 -04:00
dependabot[bot] 7abe88119c
build(deps): bump cc from 1.2.22 to 1.2.23 (#3921)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.22 to 1.2.23.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.22...cc-v1.2.23)

---
updated-dependencies:
- dependency-name: cc
  dependency-version: 1.2.23
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-16 10:01:02 -04:00
katelyn martin 37c0f96cfc
nit(app): consolidate `impl Config` blocks (#3919)
this is a trivial, cosmetic change.

`Config` has two consecutive `impl` blocks in the `linkerd-app` library.
these do not include distinct generics or trait bounds, so the methods
contained therein do not need to live in two distinct `impl` blocks.

this commit consolidates these blocks.

while we are performing this change, we add two `=== impl T ===`
banners, which are used throughout the project as greppable strings to
find methods and trait implementations for a given type.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-05-16 09:37:02 -04:00
dependabot[bot] 79e10775f0
build(deps): bump generator from 0.8.4 to 0.8.5 (#3917)
Bumps [generator](https://github.com/Xudong-Huang/generator-rs) from 0.8.4 to 0.8.5.
- [Release notes](https://github.com/Xudong-Huang/generator-rs/releases)
- [Commits](https://github.com/Xudong-Huang/generator-rs/compare/0.8.4...0.8.5)

---
updated-dependencies:
- dependency-name: generator
  dependency-version: 0.8.5
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-14 09:29:51 -04:00
dependabot[bot] a2eadec54a
build(deps): bump resolv-conf from 0.7.3 to 0.7.4 (#3916)
Bumps [resolv-conf](https://github.com/hickory-dns/resolv-conf) from 0.7.3 to 0.7.4.
- [Release notes](https://github.com/hickory-dns/resolv-conf/releases)
- [Commits](https://github.com/hickory-dns/resolv-conf/compare/v0.7.3...v0.7.4)

---
updated-dependencies:
- dependency-name: resolv-conf
  dependency-version: 0.7.4
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-13 09:53:37 -04:00
katelyn martin 7b7ffbc69d
chore(deps): define `tracing` workspace dependency (#3834)
this commit hoists `tracing`, used liberally throughout our project,
such that it is managed as a single workspace dependency.

this will be helpful someday when a 0.2 release happens.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-05-12 16:00:34 -04:00
katelyn martin 00b5de1936
refactor(proxy/http): a concrete `orig_proto` error (#3901)
this commit introduces a concrete error type for the `orig_proto`
upgrade layer.

this layer is used by the proxy's http client to transparently upgrade
outbound http/1 traffic to http/2. rather than boxing errors, we define
a concrete error type to facilitate inspecting errors in the future.

for now, the top-level http client continues to box errors thrown by the
"orig_proto" upgrade client.

see also, #3894 (ea75ac0).

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-05-12 15:59:56 -04:00
katelyn martin d3a176446c
fix: report error causes properly (#3915)
the `linkerd-error` crate includes two functions that can be used to
examine the cause of a dynamic, boxed error. for example, here is the
`is_caused_by()` function, used in some of our error recovery logic:

```rust
/// Determines whether the provided error was caused by an `E` typed error.
pub fn is_caused_by<E: std::error::Error + 'static>(
    mut error: &(dyn std::error::Error + 'static),
) -> bool {
    loop {
        if error.is::<E>() {
            return true;
        }
        error = match error.source() {
            Some(e) => e,
            None => return false,
        };
    }
}
```

we rely on [`thiserror`](https://github.com/dtolnay/thiserror/) to
generate boilerplate code for our error structures. this includes an
attribute called `transparent` that will delegate down to an inner
error.

however, this delegation means that the causal chains inspected by
the function above might not properly identify an inner error. this
test, for example, fails:

```rust
// linkerd/dns/src/lib.rs
#[derive(Debug, Clone, Error)]
#[error("invalid SRV record {:?}", self.0)]
struct InvalidSrv(rdata::SRV);

#[derive(Debug, Error)]
enum SrvRecordError {
    #[error(transparent)]
    Invalid(#[from] InvalidSrv),
    #[error("failed to resolve SRV record: {0}")]
    Resolve(#[from] hickory_resolver::ResolveError),
}

#[test]
fn srv_record_reports_cause_correctly() {
    let srv = "foobar.linkerd-dst-headless.linkerd.svc.cluster.local."
        .parse::<hickory_resolver::Name>()
        .map(|name| rdata::SRV::new(1, 1, 8086, name))
        .expect("a valid domain name");

    let error = SrvRecordError::Invalid(InvalidSrv(srv));
    let error: Box<dyn std::error::Error + 'static> = Box::new(error);

    assert!(linkerd_error::is_caused_by::<InvalidSrv>(&*error));
    assert!(linkerd_error::cause_ref::<InvalidSrv>(&*error).is_some());
}
```

the `transparent` attribute will delegate directly down to `InvalidSrv`
when `Error::source()` is invoked. this means that our downcasting logic
in `linkerd-error` used to ascertain causes of dynamic, boxed errors
will fail to identify a `SrvRecordError` as being caused by an
`InvalidSrv`.

by replacing the `transparent` attribute with a `"{0}"` display
attribute, we continue to transparently show the inner error when
printed as a string, but will include `InvalidSrv` in the causal chain.

this branch replaces `transparent` attributes in an assortment of
error variants.

---

* test(dns): add a failing test

this commit adds a failing unit test. this test shows that dns errors
might not report their cause correctly, due to thiserror's `transparent`
attribute passing directly through to `InvalidSrv`'s cause.

Signed-off-by: katelyn martin <kate@buoyant.io>

* fix(dns): replace `error(transparent)` attribute

this commit fixes the failing unit test introduced in the previous
commit.

the `transparent` attribute will delegate directly down to `InvalidSrv`
when `Error::source()` is invoke. this means that our downcasting logic
in `linkerd-error` used to ascertain causes of dynamic, boxed errors
will fail to identify a `SrvRecordError` as being caused by an
`InvalidSrv`.

by replacing the `transparent` attribute with a `"{0}"` display
attribute, we continue to transparently show the inner error when
printed as a string, but will include `InvalidSrv` in the causal chain.

Signed-off-by: katelyn martin <kate@buoyant.io>

* fix: errors report inner sources

this commit performs the same transformation as the previous commit,
replacing `transparent` with equivalent pass-through `"{0}"` display
strings, adding `#[source]` where needed.

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-05-12 15:52:06 -04:00
katelyn martin 015c499891
refactor(app/outbound): `Connect` fields are not pub (#3895)
this structure exposes its fields, but those fields are never accessed
elsewhere, aside from test code.

this commit removes the `pub` directives from the address and tls
fields. in their stead, test interfaces are added to allow the
`tagged_transport` test suite to function.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-05-12 15:38:59 -04:00
katelyn martin ea75ac0126
refactor(proxy/http): http/1 client is a `Service<T>` (#3894)
this is a small mechanical refactor to the http/1 client.

our http/2 and "orig_proto" clients are tower services. our http/1
client, on the other hand, exposes a concrete inherent method `request`.

to be consistent, this changes our http client to treat this http/1
client as a service as well.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-05-12 15:38:26 -04:00
katelyn martin 3a795967af
nit(app/integration): sort cargo dependencies (#3887)
this alphabetizes dependencies in `linkerd-app-integration`'s
manifest.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-05-12 15:37:52 -04:00
dependabot[bot] c5c2c24b0d
build(deps): bump libloading from 0.8.6 to 0.8.7 (#3914)
Bumps [libloading](https://github.com/nagisa/rust_libloading) from 0.8.6 to 0.8.7.
- [Commits](https://github.com/nagisa/rust_libloading/compare/0.8.6...0.8.7)

---
updated-dependencies:
- dependency-name: libloading
  dependency-version: 0.8.7
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-12 10:00:18 -04:00
dependabot[bot] 971ec0e14d
build(deps): bump multimap from 0.10.0 to 0.10.1 (#3913)
Bumps [multimap](https://github.com/havarnov/multimap) from 0.10.0 to 0.10.1.
- [Commits](https://github.com/havarnov/multimap/commits)

---
updated-dependencies:
- dependency-name: multimap
  dependency-version: 0.10.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-12 10:00:01 -04:00
dependabot[bot] f45a6185f6
build(deps): bump tempfile from 3.19.1 to 3.20.0 (#3912)
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.19.1 to 3.20.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.19.1...v3.20.0)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-version: 3.20.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-12 09:58:57 -04:00
dependabot[bot] 6ea7f158a5
build(deps): bump aws-lc-rs from 1.13.0 to 1.13.1 (#3911)
Bumps [aws-lc-rs](https://github.com/aws/aws-lc-rs) from 1.13.0 to 1.13.1.
- [Release notes](https://github.com/aws/aws-lc-rs/releases)
- [Commits](https://github.com/aws/aws-lc-rs/compare/v1.13.0...v1.13.1)

---
updated-dependencies:
- dependency-name: aws-lc-rs
  dependency-version: 1.13.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-09 13:12:34 -04:00
dependabot[bot] 0e9f9443b8
build(deps): bump cc from 1.2.21 to 1.2.22 (#3910)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.21 to 1.2.22.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.21...cc-v1.2.22)

---
updated-dependencies:
- dependency-name: cc
  dependency-version: 1.2.22
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-09 13:12:23 -04:00
dependabot[bot] 34dae165d6
build(deps): bump idna_adapter from 1.2.0 to 1.2.1 (#3909)
Bumps [idna_adapter](https://github.com/hsivonen/idna_adapter) from 1.2.0 to 1.2.1.
- [Commits](https://github.com/hsivonen/idna_adapter/compare/v1.2.0...v1.2.1)

---
updated-dependencies:
- dependency-name: idna_adapter
  dependency-version: 1.2.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-09 13:12:15 -04:00
dependabot[bot] 9063a6df66
build(deps): bump backtrace from 0.3.74 to 0.3.75 (#3907)
Bumps [backtrace](https://github.com/rust-lang/backtrace-rs) from 0.3.74 to 0.3.75.
- [Release notes](https://github.com/rust-lang/backtrace-rs/releases)
- [Commits](https://github.com/rust-lang/backtrace-rs/compare/0.3.74...0.3.75)

---
updated-dependencies:
- dependency-name: backtrace
  dependency-version: 0.3.75
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-07 10:21:51 -04:00
dependabot[bot] a9ce356bf8
build(deps): bump jiff from 0.2.12 to 0.2.13 (#3906)
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.12 to 0.2.13.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.12...jiff-static-0.2.13)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.13
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-06 11:11:16 -04:00
dependabot[bot] dd432b3143
build(deps): bump tokio from 1.44.2 to 1.45.0 (#3905)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.44.2 to 1.45.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.44.2...tokio-1.45.0)

---
updated-dependencies:
- dependency-name: tokio
  dependency-version: 1.45.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-06 10:52:23 -04:00
dependabot[bot] d35e12facb
build(deps): bump jiff from 0.2.11 to 0.2.12 (#3900)
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.11 to 0.2.12.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.11...jiff-static-0.2.12)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 09:19:42 -04:00
dependabot[bot] 430eb75667
build(deps): bump the hickory group with 2 updates (#3899)
Bumps the hickory group with 2 updates: [hickory-resolver](https://github.com/hickory-dns/hickory-dns) and [hickory-proto](https://github.com/hickory-dns/hickory-dns).


Updates `hickory-resolver` from 0.25.1 to 0.25.2
- [Release notes](https://github.com/hickory-dns/hickory-dns/releases)
- [Changelog](https://github.com/hickory-dns/hickory-dns/blob/main/OLD-CHANGELOG.md)
- [Commits](https://github.com/hickory-dns/hickory-dns/compare/v0.25.1...v0.25.2)

Updates `hickory-proto` from 0.25.1 to 0.25.2
- [Release notes](https://github.com/hickory-dns/hickory-dns/releases)
- [Changelog](https://github.com/hickory-dns/hickory-dns/blob/main/OLD-CHANGELOG.md)
- [Commits](https://github.com/hickory-dns/hickory-dns/compare/v0.25.1...v0.25.2)

---
updated-dependencies:
- dependency-name: hickory-resolver
  dependency-version: 0.25.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: hickory
- dependency-name: hickory-proto
  dependency-version: 0.25.2
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: hickory
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 09:18:40 -04:00
dependabot[bot] 025f0a19cb
build(deps): bump the symbolic group with 2 updates (#3896)
Bumps the symbolic group with 2 updates: [symbolic-common](https://github.com/getsentry/symbolic) and [symbolic-demangle](https://github.com/getsentry/symbolic).


Updates `symbolic-common` from 12.15.4 to 12.15.5
- [Release notes](https://github.com/getsentry/symbolic/releases)
- [Changelog](https://github.com/getsentry/symbolic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/symbolic/compare/12.15.4...12.15.5)

Updates `symbolic-demangle` from 12.15.4 to 12.15.5
- [Release notes](https://github.com/getsentry/symbolic/releases)
- [Changelog](https://github.com/getsentry/symbolic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/symbolic/compare/12.15.4...12.15.5)

---
updated-dependencies:
- dependency-name: symbolic-common
  dependency-version: 12.15.5
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: symbolic
- dependency-name: symbolic-demangle
  dependency-version: 12.15.5
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: symbolic
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-02 11:00:55 -04:00
dependabot[bot] d9ed5e3835
build(deps): bump jiff from 0.2.10 to 0.2.11 (#3898)
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.10 to 0.2.11.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.10...jiff-static-0.2.11)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-02 11:00:28 -04:00
dependabot[bot] f2e4961a4b
build(deps): bump cc from 1.2.20 to 1.2.21 (#3897)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.20 to 1.2.21.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.20...cc-v1.2.21)

---
updated-dependencies:
- dependency-name: cc
  dependency-version: 1.2.21
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-02 10:59:54 -04:00
dependabot[bot] facaf571d8
build(deps): bump sha2 from 0.10.8 to 0.10.9 (#3893)
Bumps [sha2](https://github.com/RustCrypto/hashes) from 0.10.8 to 0.10.9.
- [Commits](https://github.com/RustCrypto/hashes/compare/sha2-v0.10.8...sha2-v0.10.9)

---
updated-dependencies:
- dependency-name: sha2
  dependency-version: 0.10.9
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-01 10:55:25 -04:00
dependabot[bot] 905f71fa25
build(deps): bump resolv-conf from 0.7.1 to 0.7.3 (#3892)
Bumps [resolv-conf](https://github.com/hickory-dns/resolv-conf) from 0.7.1 to 0.7.3.
- [Release notes](https://github.com/hickory-dns/resolv-conf/releases)
- [Commits](https://github.com/hickory-dns/resolv-conf/compare/v0.7.1...v0.7.3)

---
updated-dependencies:
- dependency-name: resolv-conf
  dependency-version: 0.7.3
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-01 10:55:14 -04:00
dependabot[bot] c822b72786
build(deps): bump synstructure from 0.13.1 to 0.13.2 (#3891)
Bumps [synstructure](https://github.com/mystor/synstructure) from 0.13.1 to 0.13.2.
- [Commits](https://github.com/mystor/synstructure/commits)

---
updated-dependencies:
- dependency-name: synstructure
  dependency-version: 0.13.2
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-01 10:54:55 -04:00
dependabot[bot] b6a07aa01e
build(deps): bump tokio-metrics from 0.4.1 to 0.4.2 (#3890)
Bumps [tokio-metrics](https://github.com/tokio-rs/tokio-metrics) from 0.4.1 to 0.4.2.
- [Release notes](https://github.com/tokio-rs/tokio-metrics/releases)
- [Changelog](https://github.com/tokio-rs/tokio-metrics/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/tokio-metrics/compare/v0.4.1...v0.4.2)

---
updated-dependencies:
- dependency-name: tokio-metrics
  dependency-version: 0.4.2
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-01 10:54:44 -04:00
dependabot[bot] f657ceabb4
build(deps): bump aws-lc-fips-sys from 0.13.5 to 0.13.6 (#3889)
Bumps [aws-lc-fips-sys](https://github.com/aws/aws-lc-rs) from 0.13.5 to 0.13.6.
- [Release notes](https://github.com/aws/aws-lc-rs/releases)
- [Commits](https://github.com/aws/aws-lc-rs/compare/aws-lc-fips-sys/v0.13.5...aws-lc-fips-sys/v0.13.6)

---
updated-dependencies:
- dependency-name: aws-lc-fips-sys
  dependency-version: 0.13.6
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-29 09:12:22 -04:00
dependabot[bot] 89e28324da
build(deps): bump syn from 2.0.100 to 2.0.101 (#3886)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.100 to 2.0.101.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.100...2.0.101)

---
updated-dependencies:
- dependency-name: syn
  dependency-version: 2.0.101
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-28 09:40:18 -04:00
Scott Fleener 577a67b2c6
feat(meshtls): Add aws-lc-rs as optional rustls backend (#3883)
This has a few benefits. Primarily this gives us a reasonable path to creating FIPS-enabled builds on architectures other than x86-64, as well as a path away from using BoringSSL as a backend.

Additionally, rustls has been using the aws-lc-rs library as the default backend for a little while now, so this gives us the opportunity to stay in line with the most widely used option in the ecosystem.

Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-04-28 08:38:40 -04:00
dependabot[bot] b4fb4277d4
build(deps): bump actions/download-artifact from 4.2.1 to 4.3.0 (#3885)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4.2.1 to 4.3.0.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](95815c38cf...d3f86a106a)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: 4.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-25 10:28:33 -04:00
dependabot[bot] 5e626ef240
build(deps): bump cc from 1.2.19 to 1.2.20 (#3884)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.19 to 1.2.20.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.19...cc-v1.2.20)

---
updated-dependencies:
- dependency-name: cc
  dependency-version: 1.2.20
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-25 09:35:30 -04:00
dependabot[bot] d4c8a74596
build(deps): bump tokio-util from 0.7.14 to 0.7.15 (#3882)
Bumps [tokio-util](https://github.com/tokio-rs/tokio) from 0.7.14 to 0.7.15.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-util-0.7.14...tokio-util-0.7.15)

---
updated-dependencies:
- dependency-name: tokio-util
  dependency-version: 0.7.15
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-24 13:22:17 -04:00
dependabot[bot] ff162dba22
build(deps): bump getrandom from 0.2.15 to 0.2.16 (#3881)
Bumps [getrandom](https://github.com/rust-random/getrandom) from 0.2.15 to 0.2.16.
- [Changelog](https://github.com/rust-random/getrandom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-random/getrandom/compare/v0.2.15...v0.2.16)

---
updated-dependencies:
- dependency-name: getrandom
  dependency-version: 0.2.16
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-23 10:53:37 -04:00
dependabot[bot] 266ec108ac
build(deps): bump the symbolic group with 2 updates (#3880)
Bumps the symbolic group with 2 updates: [symbolic-common](https://github.com/getsentry/symbolic) and [symbolic-demangle](https://github.com/getsentry/symbolic).


Updates `symbolic-common` from 12.15.3 to 12.15.4
- [Release notes](https://github.com/getsentry/symbolic/releases)
- [Changelog](https://github.com/getsentry/symbolic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/symbolic/compare/12.15.3...12.15.4)

Updates `symbolic-demangle` from 12.15.3 to 12.15.4
- [Release notes](https://github.com/getsentry/symbolic/releases)
- [Changelog](https://github.com/getsentry/symbolic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/symbolic/compare/12.15.3...12.15.4)

---
updated-dependencies:
- dependency-name: symbolic-common
  dependency-version: 12.15.4
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: symbolic
- dependency-name: symbolic-demangle
  dependency-version: 12.15.4
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: symbolic
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-23 10:53:25 -04:00
dependabot[bot] c4ded832b8
build(deps): bump jiff from 0.2.9 to 0.2.10 (#3879)
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.9 to 0.2.10.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.9...jiff-static-0.2.10)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-22 10:44:42 -04:00
dependabot[bot] dd38e6b45a
build(deps): bump tokio-metrics from 0.4.0 to 0.4.1 (#3878)
Bumps [tokio-metrics](https://github.com/tokio-rs/tokio-metrics) from 0.4.0 to 0.4.1.
- [Release notes](https://github.com/tokio-rs/tokio-metrics/releases)
- [Changelog](https://github.com/tokio-rs/tokio-metrics/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/tokio-metrics/compare/v0.4.0...v0.4.1)

---
updated-dependencies:
- dependency-name: tokio-metrics
  dependency-version: 0.4.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-22 10:43:19 -04:00
katelyn martin ad5952f021
nit(http/retry): remove extra body poll in tests (#3877)
the initial replay body, circa the usage of our "compatibility" layer
(4b53081, #3598), used to need an extra poll to confirm the absence of
trailers before it would report itself as reaching the end of the
stream. these tests were added in (afda8a7b3, #3583).

this was an artifact of how the compatibility middleware masked the
previous `poll_data()` and `poll_trailer()` methods behind a
forward-compatible `poll_frame()`- and `frame()`-oriented interface.

this commit removes these extra calls to `initial.frame().await`, now
that the initial body will report the end of stream without an extra
call to await a `None`.

X-ref: #3598
X-ref: #3583

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-04-21 09:54:12 -07:00
Oliver Gould d25bbf262a
chore(dev): introduce copilot instructions (#3873)
This introduces a GitHub Copilot instructions file under .github to guide AI-driven code generation and updates the devcontainer configuration accordingly.

The new instructions enforce Rust styling, error handling, and tracing conventions across the project. It ensures generated code passes `cargo fmt` and `clippy`, avoids unwraps, and uses structured logging.
2025-04-21 12:24:34 -04:00
Oliver Gould ce62199344
fix(client-policy): enable TLS hostnames via overrides (#3871)
In 65db3dd we enabled overriding the behavior to export TLS hostnames for
outbound traffic, but we omitted TLS hostname labels.

This change updates the tls module to mirror the http module's behavior.
2025-04-21 12:13:51 -04:00
dependabot[bot] 5ebea46ca2
build(deps): bump rand from 0.9.0 to 0.9.1 (#3872)
Bumps [rand](https://github.com/rust-random/rand) from 0.9.0 to 0.9.1.
- [Release notes](https://github.com/rust-random/rand/releases)
- [Changelog](https://github.com/rust-random/rand/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-random/rand/compare/0.9.0...rand_core-0.9.1)

---
updated-dependencies:
- dependency-name: rand
  dependency-version: 0.9.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-21 07:59:03 -07:00
dependabot[bot] 0c343ce118
build(deps): bump jiff from 0.2.8 to 0.2.9 (#3876)
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.8 to 0.2.9.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.8...jiff-static-0.2.9)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-21 09:24:57 -04:00
dependabot[bot] d3943c6833
build(deps): bump signal-hook-registry from 1.4.2 to 1.4.5 (#3875)
Bumps [signal-hook-registry](https://github.com/vorner/signal-hook) from 1.4.2 to 1.4.5.
- [Changelog](https://github.com/vorner/signal-hook/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vorner/signal-hook/compare/registry-v1.4.2...registry-v1.4.5)

---
updated-dependencies:
- dependency-name: signal-hook-registry
  dependency-version: 1.4.5
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-21 09:24:17 -04:00
dependabot[bot] 9135162dc8
build(deps): bump softprops/action-gh-release from 2.2.1 to 2.2.2 (#3874)
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.2.1 to 2.2.2.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](c95fe14893...da05d55257)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.2.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-21 09:23:36 -04:00
dependabot[bot] 2a34d40df4
build(deps): bump codecov/codecov-action from 5.4.0 to 5.4.2 (#3867)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.4.0 to 5.4.2.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](0565863a31...ad3126e916)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-version: 5.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-17 21:24:48 -07:00
dependabot[bot] ea1aa58255
build(deps): bump libc from 0.2.171 to 0.2.172 (#3868)
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.171 to 0.2.172.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.172/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.171...0.2.172)

---
updated-dependencies:
- dependency-name: libc
  dependency-version: 0.2.172
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-17 21:24:26 -07:00
dependabot[bot] 46b90f8ae1
build(deps): bump proc-macro2 from 1.0.94 to 1.0.95 (#3869)
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.94 to 1.0.95.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.94...1.0.95)

---
updated-dependencies:
- dependency-name: proc-macro2
  dependency-version: 1.0.95
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-17 21:24:12 -07:00
dependabot[bot] 13ab2f4825
build(deps): bump jiff from 0.2.6 to 0.2.8 (#3866)
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.6 to 0.2.8.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.6...jiff-static-0.2.8)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-14 10:14:56 -04:00
dependabot[bot] dc3a31c156
build(deps): bump anyhow from 1.0.97 to 1.0.98 (#3865)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.97 to 1.0.98.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.97...1.0.98)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-version: 1.0.98
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-14 10:14:31 -04:00
dependabot[bot] c5e9098f3d
build(deps): bump data-encoding from 2.8.0 to 2.9.0 (#3864)
Bumps [data-encoding](https://github.com/ia0/data-encoding) from 2.8.0 to 2.9.0.
- [Commits](https://github.com/ia0/data-encoding/compare/v2.8.0...v2.9.0)

---
updated-dependencies:
- dependency-name: data-encoding
  dependency-version: 2.9.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-14 10:14:19 -04:00
katelyn martin 8a3a7aa072
chore(deps): group symbolic dependencies (#3863)
we use the `symbolic-common` and `symbolic-demangle` crates in our
dependency tree. these live in the same repo, here:
<https://github.com/getsentry/symbolic>

this commit introduces a "group" so that dependabot will upgrade them in
lockstep, rather than individually, such as in pull requests like
 #3853, #3852, #3857, #3858, or #3860.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-04-11 16:07:49 -04:00
dependabot[bot] 6bd80d4898
build(deps): bump symbolic-common from 12.15.1 to 12.15.3 (#3862)
Bumps [symbolic-common](https://github.com/getsentry/symbolic) from 12.15.1 to 12.15.3.
- [Release notes](https://github.com/getsentry/symbolic/releases)
- [Changelog](https://github.com/getsentry/symbolic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/symbolic/commits/12.15.3)

---
updated-dependencies:
- dependency-name: symbolic-common
  dependency-version: 12.15.3
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-11 10:04:42 -04:00
dependabot[bot] ab11b85fee
build(deps): bump cc from 1.2.18 to 1.2.19 (#3861)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.18 to 1.2.19.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.18...cc-v1.2.19)

---
updated-dependencies:
- dependency-name: cc
  dependency-version: 1.2.19
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-11 10:04:26 -04:00
dependabot[bot] bd859fdb69
build(deps): bump symbolic-demangle from 12.15.1 to 12.15.3 (#3860)
Bumps [symbolic-demangle](https://github.com/getsentry/symbolic) from 12.15.1 to 12.15.3.
- [Release notes](https://github.com/getsentry/symbolic/releases)
- [Changelog](https://github.com/getsentry/symbolic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/symbolic/commits/12.15.3)

---
updated-dependencies:
- dependency-name: symbolic-demangle
  dependency-version: 12.15.3
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-11 10:04:17 -04:00
dependabot[bot] 36f1fac274
build(deps): bump rustls from 0.23.25 to 0.23.26 in the rustls group (#3859)
Bumps the rustls group with 1 update: [rustls](https://github.com/rustls/rustls).


Updates `rustls` from 0.23.25 to 0.23.26
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.23.25...v/0.23.26)

---
updated-dependencies:
- dependency-name: rustls
  dependency-version: 0.23.26
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: rustls
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-11 10:04:03 -04:00
dependabot[bot] 2f345f9aea
build(deps): bump symbolic-common from 12.15.0 to 12.15.1 (#3858)
Bumps [symbolic-common](https://github.com/getsentry/symbolic) from 12.15.0 to 12.15.1.
- [Release notes](https://github.com/getsentry/symbolic/releases)
- [Changelog](https://github.com/getsentry/symbolic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/symbolic/commits)

---
updated-dependencies:
- dependency-name: symbolic-common
  dependency-version: 12.15.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-10 09:55:34 -04:00
dependabot[bot] a9c123566f
build(deps): bump symbolic-demangle from 12.15.0 to 12.15.1 (#3857)
Bumps [symbolic-demangle](https://github.com/getsentry/symbolic) from 12.15.0 to 12.15.1.
- [Release notes](https://github.com/getsentry/symbolic/releases)
- [Changelog](https://github.com/getsentry/symbolic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/symbolic/commits)

---
updated-dependencies:
- dependency-name: symbolic-demangle
  dependency-version: 12.15.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-10 09:55:24 -04:00
katelyn martin 6426c38906
fix(http/prom): record bodies when eos reached (#3856)
* chore(app/outbound): `linkerd-mock-http-body` test dependency

this adds a development dependency, so we can use this mock body type in
the outbound proxy's unit tests.

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(app/outbound): additional http route metrics tests

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(app/outbound): additional grpc route metrics tests

Signed-off-by: katelyn martin <kate@buoyant.io>

* fix(http/prom): record bodies when eos reached

this commit fixes a bug discovered by @alpeb, which was introduced in
proxy v2.288.0.

> The associated metric is `outbound_http_route_request_statuses_total`:
>
> ```
> $ linkerd dg proxy-metrics -n booksapp deploy/webapp|rg outbound_http_route_request_statuses_total.*authors
> outbound_http_route_request_statuses_total{parent_group="core",parent_kind="Service",parent_namespace="booksapp",parent_name="authors",parent_port="7001",parent_section_name="",route_group="",route_kind="default",route_namespace="",route_name="http",hostname="",http_status="204",error=""} 5
> outbound_http_route_request_statuses_total{parent_group="core",parent_kind="Service",parent_namespace="booksapp",parent_name="authors",parent_port="7001",parent_section_name="",route_group="",route_kind="default",route_namespace="",route_name="http",hostname="",http_status="201",error="UNKNOWN"} 5
> outbound_http_route_request_statuses_total{parent_group="core",parent_kind="Service",parent_namespace="booksapp",parent_name="authors",parent_port="7001",parent_section_name="",route_group="",route_kind="default",route_namespace="",route_name="http",hostname="",http_status="200",error="UNKNOWN"} 10
> ```
>
> The problem was introduced in `edge-25.3.4`, with the proxy `v2.288.0`.
> Before that the metrics looked like:
>
> ```
> $ linkerd dg proxy-metrics -n booksapp deploy/webapp|rg outbound_http_route_request_statuses_total.*authors
> outbound_http_route_request_statuses_total{parent_group="core",parent_kind="Service",parent_namespace="booksapp",parent_name="authors",parent_port="7001",parent_section_name="",route_group="",route_kind="default",route_namespace="",route_name="http",hostname="",http_status="200",error=""} 193
> outbound_http_route_request_statuses_total{parent_group="core",parent_kind="Service",parent_namespace="booksapp",parent_name="authors",parent_port="7001",parent_section_name="",route_group="",route_kind="default",route_namespace="",route_name="http",hostname="",http_status="204",error=""} 96
> outbound_http_route_request_statuses_total{parent_group="core",parent_kind="Service",parent_namespace="booksapp",parent_name="authors",parent_port="7001",parent_section_name="",route_group="",route_kind="default",route_namespace="",route_name="http",hostname="",http_status="201",error=""} 96
> ```
>
> So the difference is the non-empty value for `error=UNKNOWN` even
> when `https_status` is 2xx, which `linkerd viz stat-outbound`
> interprets as failed requests.

in #3086 we introduced a suite of route- and backend-level metrics. that
subsystem contains a body middleware that will report itself as having
reached the end-of-stream by delegating directly down to its inner
body's `is_end_stream()` hint.

this is roughly correct, but is slightly distinct from the actual
invariant: a `linkerd_http_prom::record_response::ResponseBody<B>` must
call its `end_stream` helper to classify the outcome and increment the
corresponding time series in the
`outbound_http_route_request_statuses_total` metric family.

in #3504 we upgraded our hyper dependency. while doing so, we neglected
to include a call to `end_stream` if a data frame is yielded and the
inner body reports itself as having reached the end-of-stream.

this meant that instrumented bodies would be polled until the end is
reached, but were being dropped before a `None` was encountered.

this commit fixes this issue in two ways, to be defensive:

* invoke `end_stream()` if a non-trailers frame is yielded, and the
  inner body now reports itself as having ended. this restores the
  behavior in place prior to #3504. see the relevant component of that
  diff, here:
  <https://github.com/linkerd/linkerd2-proxy/pull/3504/files#diff-45d0bc344f76c111551a8eaf5d3f0e0c22ee6e6836a626e46402a6ae3cbc0035L262-R274>

* rather than delegating to the inner `<B as Body>::is_end_stream()`
  method, report the end-of-stream being reached by inspecting whether
  or not the inner response state has been taken. this is the state that
  directly indicates whether or not the `ResponseBody<B>` middleware is
  finished.

X-ref: #3504
X-ref: #3086
X-ref: linkerd/linkerd2#8733
Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-04-09 15:30:55 -04:00
dependabot[bot] 985580f9b5
build(deps): bump miniz_oxide from 0.8.7 to 0.8.8 (#3855)
Bumps [miniz_oxide](https://github.com/Frommi/miniz_oxide) from 0.8.7 to 0.8.8.
- [Changelog](https://github.com/Frommi/miniz_oxide/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Frommi/miniz_oxide/compare/0.8.7...0.8.8)

---
updated-dependencies:
- dependency-name: miniz_oxide
  dependency-version: 0.8.8
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-09 10:59:41 -04:00
dependabot[bot] ad7fcf2dfb
build(deps): bump crossbeam-channel from 0.5.14 to 0.5.15 (#3854)
Bumps [crossbeam-channel](https://github.com/crossbeam-rs/crossbeam) from 0.5.14 to 0.5.15.
- [Release notes](https://github.com/crossbeam-rs/crossbeam/releases)
- [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-channel-0.5.14...crossbeam-channel-0.5.15)

---
updated-dependencies:
- dependency-name: crossbeam-channel
  dependency-version: 0.5.15
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-09 10:59:35 -04:00
dependabot[bot] f6bbab6640
build(deps): bump symbolic-common from 12.14.1 to 12.15.0 (#3853)
Bumps [symbolic-common](https://github.com/getsentry/symbolic) from 12.14.1 to 12.15.0.
- [Release notes](https://github.com/getsentry/symbolic/releases)
- [Changelog](https://github.com/getsentry/symbolic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/symbolic/commits)

---
updated-dependencies:
- dependency-name: symbolic-common
  dependency-version: 12.15.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-09 10:59:28 -04:00
dependabot[bot] 5f2f8fbacd
build(deps): bump symbolic-demangle from 12.14.1 to 12.15.0 (#3852)
Bumps [symbolic-demangle](https://github.com/getsentry/symbolic) from 12.14.1 to 12.15.0.
- [Release notes](https://github.com/getsentry/symbolic/releases)
- [Changelog](https://github.com/getsentry/symbolic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/symbolic/commits)

---
updated-dependencies:
- dependency-name: symbolic-demangle
  dependency-version: 12.15.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-09 10:59:20 -04:00
dependabot[bot] 096f547ffb
build(deps): bump tj-actions/changed-files from 46.0.4 to 46.0.5 (#3851)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 46.0.4 to 46.0.5.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](6cb76d07be...ed68ef82c0)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-version: 46.0.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-09 10:59:09 -04:00
dependabot[bot] abeb366500
build(deps): bump jiff from 0.2.5 to 0.2.6 (#3849)
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.5 to 0.2.6.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.5...jiff-static-0.2.6)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-08 12:05:56 -04:00
dependabot[bot] c17a6acee8
build(deps): bump hostname from 0.4.0 to 0.4.1 (#3850)
Bumps [hostname](https://github.com/svartalf/hostname) from 0.4.0 to 0.4.1.
- [Release notes](https://github.com/svartalf/hostname/releases)
- [Changelog](https://github.com/djc/hostname/blob/main/CHANGELOG.md)
- [Commits](https://github.com/svartalf/hostname/commits)

---
updated-dependencies:
- dependency-name: hostname
  dependency-version: 0.4.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-08 12:05:23 -04:00
dependabot[bot] a9f7a9ae9d
build(deps): bump indexmap from 2.8.0 to 2.9.0 (#3848)
Bumps [indexmap](https://github.com/indexmap-rs/indexmap) from 2.8.0 to 2.9.0.
- [Changelog](https://github.com/indexmap-rs/indexmap/blob/main/RELEASES.md)
- [Commits](https://github.com/indexmap-rs/indexmap/compare/2.8.0...2.9.0)

---
updated-dependencies:
- dependency-name: indexmap
  dependency-version: 2.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-07 10:18:15 -04:00
dependabot[bot] 6de15c0a55
build(deps): bump tokio from 1.44.1 to 1.44.2 (#3847)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.44.1 to 1.44.2.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.44.1...tokio-1.44.2)

---
updated-dependencies:
- dependency-name: tokio
  dependency-version: 1.44.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-07 10:17:40 -04:00
dependabot[bot] 77837c5e45
build(deps): bump smallvec from 1.14.0 to 1.15.0 (#3846)
Bumps [smallvec](https://github.com/servo/rust-smallvec) from 1.14.0 to 1.15.0.
- [Release notes](https://github.com/servo/rust-smallvec/releases)
- [Commits](https://github.com/servo/rust-smallvec/compare/v1.14.0...v1.15.0)

---
updated-dependencies:
- dependency-name: smallvec
  dependency-version: 1.15.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-07 10:17:17 -04:00
dependabot[bot] e6fee10099
build(deps): bump prettyplease from 0.2.31 to 0.2.32 (#3845)
Bumps [prettyplease](https://github.com/dtolnay/prettyplease) from 0.2.31 to 0.2.32.
- [Release notes](https://github.com/dtolnay/prettyplease/releases)
- [Commits](https://github.com/dtolnay/prettyplease/compare/0.2.31...0.2.32)

---
updated-dependencies:
- dependency-name: prettyplease
  dependency-version: 0.2.32
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-07 10:17:00 -04:00
dependabot[bot] 52a30254c7
build(deps): bump errno from 0.3.10 to 0.3.11 (#3844)
Bumps [errno](https://github.com/lambda-fairy/rust-errno) from 0.3.10 to 0.3.11.
- [Release notes](https://github.com/lambda-fairy/rust-errno/releases)
- [Changelog](https://github.com/lambda-fairy/rust-errno/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lambda-fairy/rust-errno/compare/v0.3.10...v0.3.11)

---
updated-dependencies:
- dependency-name: errno
  dependency-version: 0.3.11
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-04 12:25:48 -04:00
dependabot[bot] fee5b9734a
build(deps): bump cc from 1.2.17 to 1.2.18 (#3843)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.17 to 1.2.18.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.17...cc-v1.2.18)

---
updated-dependencies:
- dependency-name: cc
  dependency-version: 1.2.18
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-04 15:55:47 +00:00
katelyn martin 33a177d054
chore(deps): add `tokio-boring` to dependabot group (#3842)
this adds `tokio-boring` to the `boring` group.

this will group these crates together and bump them in lockstep.

see, for example:
* #3838
* #3840

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-04-04 11:44:05 -04:00
dependabot[bot] 6cc16b430e
build(deps): bump tokio-boring from 4.15.0 to 4.16.0 (#3838)
Bumps [tokio-boring](https://github.com/cloudflare/boring) from 4.15.0 to 4.16.0.
- [Release notes](https://github.com/cloudflare/boring/releases)
- [Changelog](https://github.com/cloudflare/boring/blob/master/RELEASE_NOTES)
- [Commits](https://github.com/cloudflare/boring/compare/v4.15.0...v4.16.0)

---
updated-dependencies:
- dependency-name: tokio-boring
  dependency-version: 4.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-04 11:34:16 -04:00
dependabot[bot] 18109a447e
build(deps): bump opentelemetry in the opentelemetry group (#3837)
Bumps the opentelemetry group with 1 update: [opentelemetry](https://github.com/open-telemetry/opentelemetry-rust).


Updates `opentelemetry` from 0.29.0 to 0.29.1
- [Release notes](https://github.com/open-telemetry/opentelemetry-rust/releases)
- [Commits](https://github.com/open-telemetry/opentelemetry-rust/compare/opentelemetry-0.29.0...opentelemetry-0.29.1)

---
updated-dependencies:
- dependency-name: opentelemetry
  dependency-version: 0.29.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: opentelemetry
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-04 11:03:32 -04:00
dependabot[bot] 05b4ab7314
build(deps): bump miniz_oxide from 0.8.5 to 0.8.7 (#3841)
Bumps [miniz_oxide](https://github.com/Frommi/miniz_oxide) from 0.8.5 to 0.8.7.
- [Changelog](https://github.com/Frommi/miniz_oxide/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Frommi/miniz_oxide/compare/0.8.5...0.8.7)

---
updated-dependencies:
- dependency-name: miniz_oxide
  dependency-version: 0.8.7
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-04 10:51:20 -04:00
dependabot[bot] 483cd0d3ff
build(deps): bump tj-actions/changed-files (#3839)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from b74df86ccb65173a8e33ba5492ac1a2ca6b216fd to 6cb76d07bee4c9772c6882c06c37837bf82a04d3.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](b74df86ccb...6cb76d07be)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-version: 6cb76d07bee4c9772c6882c06c37837bf82a04d3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-04 10:50:18 -04:00
dependabot[bot] 5444732bab
build(deps): bump flate2 from 1.1.0 to 1.1.1 (#3835)
Bumps [flate2](https://github.com/rust-lang/flate2-rs) from 1.1.0 to 1.1.1.
- [Release notes](https://github.com/rust-lang/flate2-rs/releases)
- [Commits](https://github.com/rust-lang/flate2-rs/compare/1.1.0...1.1.1)

---
updated-dependencies:
- dependency-name: flate2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-02 11:47:35 -04:00
katelyn martin 686934cec6
chore(proxy/http): use `hyper_util::rt::tokio::TokioExecutor` (#3833)
this commit removes the `linkerd-http-executor` crate, and replaces all
usage of its `TracingExecutor` type with the `TokioExecutor` type
provided by `hyper-util`.

this work is based upon hyperium/hyper-util#166. that change, included
in the 0.1.11 release, altered the `TokioExecutor` type so that it
propagates tracing context when the `tracing` feature is enabled.

with that change made, our `TracingExecutor` type is now redundant.

* https://github.com/hyperium/hyper-util/pull/166
* https://github.com/hyperium/hyper-util/blob/master/CHANGELOG.md#0111-2025-03-31

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-04-01 13:19:53 -04:00
katelyn martin c01e7e268a
feat(app,dns): add prometheus metrics to `Dns` (#3822)
this commit introduces a new metric family tracking the rate and outcome
of dns lookups made by the linkerd2 proxy. this metric family has three
labels, counting the number of DNS resolutions for each distinct
control plane client, by record type (A/AAAA or SRV), and by outcome
(success or failure).

this metric is named `control_dns_resolutions_total`.

this commit generally does this via the addition of some new interfaces
to `linkerd-dns`'s `Resolver` structure. the `resolve_addrs()` method is
extended to increment particular counters if they have been installed.

the `linkerd-app` crate's `Dns` type now encapsulates its resolver, and
callers acquire a new resolver by providing a client name to its
`resolver()` method. this uses the client name to construct label sets
and create the corresponding time series for each client.

once proxies with this patch are running, and the viz extension has been
installed, one can query this metric like so:

**nb:** this screenshot shows an early prototype, this metric has since
been renamed.

![linkerd-dns-prometheus-metrics](https://github.com/user-attachments/assets/3138dcfc-6800-4c0f-8215-61d84085032b)

this promQL query...

```
sum(rate(control_dns_resolutions_total[1m])) by (app,client,result) > 0
```

...will show the per-minute rate of dns lookups/failures across each
application workload, for each control-plane client, for each possible
outcome.

Signed-off-by: katelyn martin <kate@buoyant.io>
Co-authored-by: Oliver Gould <ver@buoyant.io>
2025-04-01 16:02:17 +00:00
Oliver Gould c631974d97
feat(inbound): support unsafe authority labels via configuration (#3830)
In linkerd/linkerd2-proxy#3547, we removed unsafe authority labels. This was a
breaking change, since the behavior was considered unsafe.

To support a graceful migration, this change adds an environment configuration,
`LINKERD2_PROXY_INBOUND_AUTHORITY_LABELS=unsafe`, that reverts to the prior
behavior.

It may be configured in linkerd2 via the proxy.additionalEnv helm value.
2025-04-01 18:17:09 +03:00
dependabot[bot] f3b67eaaa7
build(deps): bump tj-actions/changed-files (#3831)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 27ae6b33eaed7bf87272fdeb9f1c54f9facc9d99 to b74df86ccb65173a8e33ba5492ac1a2ca6b216fd.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](27ae6b33ea...b74df86ccb)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-01 11:16:53 -04:00
dependabot[bot] c426634f6d
build(deps): bump hyper-util from 0.1.10 to 0.1.11 (#3832)
Bumps [hyper-util](https://github.com/hyperium/hyper-util) from 0.1.10 to 0.1.11.
- [Release notes](https://github.com/hyperium/hyper-util/releases)
- [Changelog](https://github.com/hyperium/hyper-util/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/hyper-util/compare/v0.1.10...v0.1.11)

---
updated-dependencies:
- dependency-name: hyper-util
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-01 11:16:00 -04:00
dependabot[bot] 652ab23578
build(deps): bump governor from 0.8.0 to 0.10.0 (#3817)
Bumps [governor](https://github.com/boinkor-net/governor) from 0.8.0 to 0.10.0.
- [Release notes](https://github.com/boinkor-net/governor/releases)
- [Changelog](https://github.com/boinkor-net/governor/blob/master/release.toml)
- [Commits](https://github.com/boinkor-net/governor/compare/v0.8.0...v0.10.0)

---
updated-dependencies:
- dependency-name: governor
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-31 18:58:17 +00:00
Oliver Gould 9d2df887a7
chore(deny): allow Zlib (#3829) 2025-03-31 14:43:45 -04:00
dependabot[bot] a3d854ee8e
build(deps): bump once_cell from 1.21.2 to 1.21.3 (#3826)
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.21.2 to 1.21.3.
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.21.2...v1.21.3)

---
updated-dependencies:
- dependency-name: once_cell
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-31 08:47:13 -07:00
dependabot[bot] 89971fc130
build(deps): bump socket2 from 0.5.8 to 0.5.9 (#3825)
Bumps [socket2](https://github.com/rust-lang/socket2) from 0.5.8 to 0.5.9.
- [Release notes](https://github.com/rust-lang/socket2/releases)
- [Changelog](https://github.com/rust-lang/socket2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/socket2/commits)

---
updated-dependencies:
- dependency-name: socket2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-31 08:46:57 -07:00
katelyn martin 523d3ed25d
chore(deps): group grpc dependabot groups (#3821)
* https://github.com/linkerd/linkerd2/blob/main/.github/dependabot.yml#L81-L86
* #3809
* https://github.com/linkerd/linkerd2-proxy-api/pull/455#discussion_r2017528014

tonic and prost are interconnected. we should bump them in lockstep.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-31 08:44:46 -07:00
Oliver Gould e0c4d42317
chore(deps): bump linkerd2-proxy-api from git to v0.16.0 (#3827) 2025-03-31 08:10:21 -07:00
Oliver Gould 2e4ca134b5
fix(ci): work around broken `linkerd install --crds` (#3828)
The latest edge doesn't properly install gateway API crds. This changes our
justfile to install the resources from the upstream release instead of the
Linkerd CLI.
2025-03-31 14:55:09 +00:00
katelyn martin cdfcbc10f0
nit(app): tweak debug event message (#3823)
this commit changes a message for a debug-level tracing event.

this block builds a trace collector. we can call it that, instead of the
more generic term "client". there are many clients being built here,
including identity, policy, and destination controller clients.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-27 15:34:00 -07:00
katelyn martin 0404a69250
nit(docs): fix broken intradoc links (#3820)
this commit fixes some broken links now that we have updated to the
latest 1.0 version of `http-body`.

this should address some warnings that can be seen in pull requests'
"files" tab in github. see, for example:
`https://github.com/linkerd/linkerd2-proxy/pull/3818/files`.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-27 15:12:41 -07:00
katelyn martin ae8caa630b
refactor(app/core): remove unused dns configuration surface (#3819)
`LINKERD2_PROXY_RESOLV_CONF` is an environment variable that ostensibly
is used to set the path of the resolver configuration file.

this connects to a `resolv_conf_path` field in the application's dns
`Config` structure, but that field is never used.

because it is marked as public, this isn't caught by the compiler's dead
code analysis.

see `resolv.conf(5)` for more information.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-27 16:45:52 -04:00
dependabot[bot] df39864cea
build(deps): bump once_cell from 1.21.1 to 1.21.2 (#3818)
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.21.1 to 1.21.2.
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.21.1...v1.21.2)

---
updated-dependencies:
- dependency-name: once_cell
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-27 16:43:54 -04:00
katelyn martin 9300d3b4a5
chore(deps): dependabot group for unicode components (#3815)
* chore(deps): dependabot group for unicode components

this commit introduces a new dependabot group.

this will update all of the crates maintained by the icu4x organization
in lockstep. we depend upon these transitively to handle urls.

```
; cargo tree | rg icu_ | rg 'icu_\w*' --only-matching | sort | uniq
icu_collections
icu_locid
icu_locid_transform
icu_locid_transform_data
icu_normalizer
icu_normalizer_data
icu_properties
icu_properties_data
icu_provider
icu_provider_macros
```

see:

- https://docs.rs/icu/latest/icu/
- https://icu.unicode.org/
- https://github.com/orgs/unicode-org/repositories?type=all
- https://crates.io/crates/idna
- #3811
- #3812
- #3813

Signed-off-by: katelyn martin <kate@buoyant.io>

* nit: alphabetize

Signed-off-by: katelyn martin <kate@buoyant.io>

* review: use a glob

Co-authored-by: Oliver Gould <ver@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
Co-authored-by: Oliver Gould <ver@buoyant.io>
2025-03-27 14:55:43 -04:00
katelyn martin 92e55e46f1
chore(deps): update unicode dependencies (#3816)
this commit updates our `icu_*` dependencies.

see:
* #3811
* #3812
* #3813
* #3815

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-27 14:54:19 -04:00
katelyn martin 6691c16b79
nit(proxy-resolve): address `XXX` comment (#3814)
this commit addresses a todo comment in the `linkerd-proxy-resolve`
crate. this comment mentioned that a `match` block was originally an `if
let` block. a clippy lint is locally ignored as well, regarding `match`
statements with a single pattern.

contrary to the comment, `if let` *does* work with pin projection, as of
today.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-27 14:54:02 -04:00
katelyn martin 3c2d5ddfc3
chore(deps): add `tonic` dependabot group (#3809)
this commit adds a group to the dependabot configuration.

this will mean that dependabot updates `tonic` and `tonic-build` in
lockstep.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-26 16:13:53 -04:00
dependabot[bot] 9ef862b8c7
build(deps): bump rustls-webpki in the rustls group (#3808)
Bumps the rustls group with 1 update: [rustls-webpki](https://github.com/rustls/webpki).


Updates `rustls-webpki` from 0.103.0 to 0.103.1
- [Release notes](https://github.com/rustls/webpki/releases)
- [Commits](https://github.com/rustls/webpki/compare/v/0.103.0...v/0.103.1)

---
updated-dependencies:
- dependency-name: rustls-webpki
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rustls
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-26 10:58:28 -04:00
katelyn martin a3ce71954e
fix(dns-resolve): add a lower-bound TTL for dns refreshing (#3807)
DNS servers may return extremely low TTLs in some cases. When we're polling DNS to power a load balancer, we need to enforce a minimum duration to prevent tight-looping DNS queries.

This change adds a 5s minimum time between DNS lookups when resolving control plane components.

fixes linkerd/linkerd2#13508
2025-03-25 16:37:38 -07:00
dependabot[bot] 135a7352ae
build(deps): bump log from 0.4.26 to 0.4.27 (#3806)
Bumps [log](https://github.com/rust-lang/log) from 0.4.26 to 0.4.27.
- [Release notes](https://github.com/rust-lang/log/releases)
- [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/log/compare/0.4.26...0.4.27)

---
updated-dependencies:
- dependency-name: log
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-25 10:44:51 -04:00
dependabot[bot] 85d1d31f06
build(deps): bump deranged from 0.4.0 to 0.4.1 (#3805)
* build(deps): bump deranged from 0.4.0 to 0.4.1

Bumps [deranged](https://github.com/jhpratt/deranged) from 0.4.0 to 0.4.1.
- [Commits](https://github.com/jhpratt/deranged/commits)

---
updated-dependencies:
- dependency-name: deranged
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(proxy/tap): fix inference error

https://github.com/jhpratt/deranged/issues/19

`deranged` added some additional interfaces in 0.4.1 that seem to affect
this `Into<T>` invocation. use `From::from` instead, so we can
explicitly indicate that we wish to convert this into an integer for
comparison.

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: katelyn martin <kate@buoyant.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: katelyn martin <kate@buoyant.io>
2025-03-24 11:16:37 -04:00
dependabot[bot] a7c12ea54c
build(deps): bump time from 0.3.40 to 0.3.41 (#3804)
Bumps [time](https://github.com/time-rs/time) from 0.3.40 to 0.3.41.
- [Release notes](https://github.com/time-rs/time/releases)
- [Changelog](https://github.com/time-rs/time/blob/main/CHANGELOG.md)
- [Commits](https://github.com/time-rs/time/compare/v0.3.40...v0.3.41)

---
updated-dependencies:
- dependency-name: time
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-24 06:53:24 -07:00
dependabot[bot] 59e330f561
build(deps): bump jiff from 0.2.4 to 0.2.5 (#3803)
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.4 to 0.2.5.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.4...jiff-static-0.2.5)

---
updated-dependencies:
- dependency-name: jiff
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-24 06:53:02 -07:00
dependabot[bot] f20851ee0b
build(deps): bump jiff-tzdb from 0.1.3 to 0.1.4 (#3802)
Bumps [jiff-tzdb](https://github.com/BurntSushi/jiff) from 0.1.3 to 0.1.4.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-tzdb-0.1.3...jiff-tzdb-0.1.4)

---
updated-dependencies:
- dependency-name: jiff-tzdb
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-24 06:52:48 -07:00
dependabot[bot] a92e6e97e7
build(deps): bump the opentelemetry group with 2 updates (#3801)
Bumps the opentelemetry group with 2 updates: [opentelemetry](https://github.com/open-telemetry/opentelemetry-rust) and [opentelemetry_sdk](https://github.com/open-telemetry/opentelemetry-rust).


Updates `opentelemetry` from 0.28.0 to 0.29.0
- [Release notes](https://github.com/open-telemetry/opentelemetry-rust/releases)
- [Commits](https://github.com/open-telemetry/opentelemetry-rust/compare/opentelemetry-0.28.0...opentelemetry-0.29.0)

Updates `opentelemetry_sdk` from 0.28.0 to 0.29.0
- [Release notes](https://github.com/open-telemetry/opentelemetry-rust/releases)
- [Commits](https://github.com/open-telemetry/opentelemetry-rust/compare/opentelemetry_sdk-0.28.0...opentelemetry_sdk-0.29.0)

---
updated-dependencies:
- dependency-name: opentelemetry
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: opentelemetry
- dependency-name: opentelemetry_sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: opentelemetry
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-24 06:47:06 -07:00
dependabot[bot] 2108f3433e
build(deps): bump tj-actions/changed-files (#3800)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 6482371e862961013f9584015cf362c4f664b20c to 27ae6b33eaed7bf87272fdeb9f1c54f9facc9d99.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](6482371e86...27ae6b33ea)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-24 06:45:04 -07:00
Oliver Gould 9f4c019844
fix(app): avoid unused import on non-linux builds (#3799) 2025-03-21 10:53:16 -07:00
Oliver Gould 41b93cb805
chore(ci): disable unnecessary k3s components (#3798)
We can run our testing k3d cluster with minimal components enabled. This will
speed up the cluster creation and deletion process (i.e. especially in CI).
2025-03-21 17:15:17 +00:00
katelyn martin 76d969544f
chore(deps): upgrade to tower 0.5 (#3744)
* chore(deps)!: upgrade to tower 0.5

this commit updates our tower dependency from 0.4 to 0.5.

note that this commit does not affect the `tower-service` and
`tower-layer` crates, reëxported by `tower` itself. the `Service<T>`
trait and the closely related `Layer<S>` trait have not been changed.

the `tower` crate's utilities have changed in various ways, some of
particular note for the linkerd2 proxy. see these items, excerpted from
the tower changelog:

- **retry**: **Breaking Change** `retry::Policy::retry` now accepts `&mut Req` and `&mut Res` instead of the previous mutable versions. This
  increases the flexibility of the retry policy. To update, update your method signature to include `mut` for both parameters. ([tower-rs/tower#584])
- **retry**: **Breaking Change** Change Policy to accept &mut self ([tower-rs/tower#681])
- **retry**: **Breaking Change** `Budget` is now a trait. This allows end-users to implement their own budget and bucket implementations. ([tower-rs/tower#703])
- **util**: **Breaking Change** `Either::A` and `Either::B` have been renamed `Either::Left` and `Either::Right`, respectively. ([tower-rs/tower#637])
- **util**: **Breaking Change** `Either` now requires its two services to have the same error type. ([tower-rs/tower#637])
- **util**: **Breaking Change** `Either` no longer implemenmts `Future`. ([tower-rs/tower#637])
- **buffer**: **Breaking Change** `Buffer<S, Request>` is now generic over `Buffer<Request, S::Future>.` ([tower-rs/tower#654])

see:

* <https://github.com/tower-rs/tower/pull/584>
* <https://github.com/tower-rs/tower/pull/681>
* <https://github.com/tower-rs/tower/pull/703>
* <https://github.com/tower-rs/tower/pull/637>
* <https://github.com/tower-rs/tower/pull/654>

the `Either` trait bounds are particularly impactful for us. because
this runs counter to how we treat errors (skewing towards boxed errors,
in general), we temporarily vendor a version of `Either` from the 0.4
release, whose variants have been renamed to match the 0.5 interface.

updating to box the inner `A` and `B` services' errors, so we satiate
the new `A::Error = B::Error` bounds, can be addressed as a follow-on.
that's intentionally left as a separate change, due to the net size of
our patchset between this branch and #3504.

* <https://github.com/tower-rs/tower/compare/v0.4.x...master>
* <https://github.com/tower-rs/tower/blob/master/tower/CHANGELOG.md>

this work is based upon #3504. for more information, see:

* https://github.com/linkerd/linkerd2/issues/8733
* https://github.com/linkerd/linkerd2-proxy/pull/3504

Signed-off-by: katelyn martin <kate@buoyant.io>
X-Ref: https://github.com/tower-rs/tower/pull/815
X-Ref: https://github.com/tower-rs/tower/pull/817
X-Ref: https://github.com/tower-rs/tower/pull/818
X-Ref: https://github.com/tower-rs/tower/pull/819

* fix(stack/loadshed): update test affected by tower-rs/tower#635

this commit updates a test that was affected by breaking changes in
tower's `Buffer` middleware. see this excerpt from the description of
that change:

> I had to change some of the integration tests slightly as part of this
> change. This is because the buffer implementation using semaphore
> permits is _very subtly_ different from one using a bounded channel. In
> the `Semaphore`-based implementation, a semaphore permit is stored in
> the `Message` struct sent over the channel. This is so that the capacity
> is used as long as the message is in flight. However, when the worker
> task is processing a message that's been recieved from the channel,
> the permit is still not dropped. Essentially, the one message actively
> held by the worker task _also_ occupies one "slot" of capacity, so the
> actual channel capacity is one less than the value passed to the
> constructor, _once the first request has been sent to the worker_. The
> bounded MPSC changed this behavior so that capacity is only occupied
> while a request is actually in the channel, which broke some tests
> that relied on the old (and technically wrong) behavior.

bear particular attention to this:

> The bounded MPSC changed this behavior so that capacity is only
> occupied while a request is actually in the channel, which broke some
> tests that relied on the old (and technically wrong) behavior.

that pr adds an additional message to the channel in tests exercising
the laod-shedding behavior, on account of the previous (incorrect)
behavior.

https://github.com/tower-rs/tower/pull/635/files#r797108274

this commit performs the same change for our corresponding test, adding
an additional `ready()` call before we hit the buffer's limit.

Signed-off-by: katelyn martin <kate@buoyant.io>

* review: use vendored `Either` for consistency

https://github.com/linkerd/linkerd2-proxy/pull/3744#discussion_r1999878537

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-21 17:08:34 +00:00
Oliver Gould bab244210e
chore(just): set installGatewayAPI in CRD install (#3797) 2025-03-21 12:59:20 -04:00
Alejandro Pedraza f1768a3044
fix(transport): repair IPv6 support (#3793)
In #3626, we refactored the origin_dst determination logic to utilize
socket2 calls. However, this change inadvertently disrupted IPv6 and
dual-stack support, causing the server to fail to start when deployed on
such network configurations:

```
WARN ThreadId(01) inbound: linkerd_app_core::serve: Server failed to accept connection error=No such file or directory (os error 2)
```

This change reintroduces detection of the current network family,
calling socket2's `original_dst()` or `original_dst_ipv6()` depending on
the case.

Tested fine in both IPv6 and dual-stack Kind clusters.
2025-03-21 09:54:12 -07:00
katelyn martin 76d4181499
chore(deps)!: upgrade to hyper 1.x (#3504)
##  chore(deps): upgrade to hyperium 1.x crates

this branch performs an exciting upgrade for our proxy.

this branch upgrades a number of our dependencies so that we use the 1.0
release family of the `hyper` http framework, and its ecosystem. see the
[v1.0 announcement][hyper-v1] for more information.

this branch upgrades the following dependencies:

* `h2`: 0.3 -> 0.4
* `http`: 0.2 -> 1
* `http-body`: 0.4 -> 1
* `hyper`: 0.14.32 -> 1
* `prost`: 0.12 -> 0.13
* `prost-build`: 0.12 -> 0.13
* `prost-types`: 0.12 -> 0.13
* `tonic`: 0.10 -> 0.12
* `tonic-build`: 0.10 -> 0.12

a `hyper-util` dependency is added, which provides among other things,
legacy-compatible interfaces such as `hyper_util::client::legacy::Client`, or
glue to use `hyper` with the tokio runtime.

see <https://docs.rs/hyper-util/latest/hyper_util/> for more information.

a `http-body-util` dependency is added, which provides a `BodyExt` trait and a
channel-backed body for use in unit tests. the `deprecated` feature flag that
was active on our `0.14` hyper dependency has been removed, along with the
`stream` and `runtime` feature flags.

the `linkerd2-proxy-api` dependency is updated. see:
<https://github.com/linkerd/linkerd2-proxy-api/pull/421>

### 📝 notes for review

bear particular attention to changes involving `http_body::Body` middleware.

the change from two separate `poll_data()` and `poll_trailers()` functions,
to a single `poll_frame()` method, induces some subtle changes to various
pieces of middleware.

also bear in mind that failing to set a timer, in our case
`hyper_util::rt::TokioTimer`, can cause http/2 clients, or http/1 and http/2
servers, to panic. make sure that any uses of
`hyper::server::conn::http1::Builder`, `hyper::client::conn::http1::Builder`,
or `hyper::client::conn::http2::Builder` install a timer.

###  breaking change: `l5d-proxy-error` values

the `l5d-proxy-error` header can be examined to observe the cause of proxy
errors encountered when sending meshed traffic. by virtue of this using a newer
`hyper` client in the proxy, some error messages may in turn look different.
for example, an error like `"connect timed out after 1s"` may now appear as
`"client error (Connect)"`.

### 📚 other notes

this work, by virtue of touching so many parts of the system, is carried out
in distinct commits. an initial commit upgrades the dependencies at th
workspace level. subsequent commits will not compile if the `--workspace` flag
is provided, but the intent of this branch is to update each crate
individually.

use commands like, e.g. `cargo check --tests -p linkerd-proxy-http` to build
particular crates at intermediate commits within this branch.

this commit is also only the final leaf in an _extended_ line of work. this
has been done to mitigate the effort of reviewing this change, and the risk of
churn in the event of any unanticipated errors. see the top-level comment in
https://github.com/linkerd/linkerd2/issues/8733 for an overview of all of the
work that brought us to this juncture.

[hyper-v1]: https://seanmonstar.com/blog/hyper-v1/

---

* chore(deps): upgrade to hyper 1.x

note: this commit will not compile, code changes are intentionally
elided from this commit.

this commit upgrades hyper, http, tonic, prost, related dependencies,
and their assorted cargo features.

see <https://github.com/linkerd/linkerd2/issues/8733>.

see also:

* https://github.com/linkerd/linkerd2-proxy/pull/3379
* https://github.com/linkerd/linkerd2-proxy/pull/3380
* https://github.com/linkerd/linkerd2-proxy/pull/3382
* https://github.com/linkerd/linkerd2-proxy/pull/3405
* https://github.com/hyperium/hyper/pull/3796
* https://github.com/linkerd/linkerd2-proxy/pull/3411
* https://github.com/linkerd/linkerd2-proxy/pull/3421
* https://github.com/linkerd/linkerd2-proxy/pull/3427
* https://github.com/linkerd/linkerd2-proxy/pull/3428
* https://github.com/linkerd/linkerd2-proxy/pull/3432
* https://github.com/linkerd/linkerd2-proxy/pull/3433
* https://github.com/linkerd/linkerd2-proxy/pull/3444
* https://github.com/linkerd/linkerd2-proxy/pull/3445
* https://github.com/linkerd/linkerd2-proxy/pull/3454
* https://github.com/linkerd/linkerd2-proxy/pull/3455
* https://github.com/linkerd/linkerd2-proxy/pull/3456
* https://github.com/linkerd/linkerd2-proxy/pull/3457
* https://github.com/linkerd/linkerd2-proxy/pull/3461
* https://github.com/linkerd/linkerd2-proxy/pull/3459
* https://github.com/linkerd/linkerd2-proxy/pull/3465
* https://github.com/linkerd/linkerd2-proxy/pull/3466
* https://github.com/linkerd/linkerd2-proxy/pull/3467
* https://github.com/linkerd/linkerd2-proxy/pull/3468
* https://github.com/linkerd/linkerd2-proxy-api/pull/421
* https://github.com/linkerd/linkerd2/pull/13492
* https://github.com/linkerd/linkerd2/pull/13493
* https://github.com/hyperium/hyper/pull/3816
* https://github.com/linkerd/linkerd2-proxy/pull/3472
* https://github.com/linkerd/linkerd2-proxy/pull/3473
* https://github.com/linkerd/linkerd2-proxy/pull/3479
* https://github.com/tokio-rs/tokio/pull/7059
* https://github.com/linkerd/linkerd2-proxy/pull/3509
* https://github.com/hyperium/http-body/pull/140/
* https://github.com/linkerd/linkerd2-proxy/pull/3515
* https://github.com/hyperium/http-body/pull/141/
* https://github.com/linkerd/linkerd2-proxy/pull/3530
* https://github.com/linkerd/linkerd2-proxy/pull/3531
* https://github.com/linkerd/linkerd2-proxy/pull/3540
* https://github.com/linkerd/linkerd2-proxy/pull/3556
* https://github.com/linkerd/linkerd2-proxy/pull/3558
* https://github.com/linkerd/linkerd2-proxy/pull/3559
* https://github.com/linkerd/linkerd2-proxy/pull/3564
* https://github.com/linkerd/linkerd2-proxy/pull/3567
* https://github.com/linkerd/linkerd2-proxy/pull/3573
* https://github.com/linkerd/linkerd2-proxy/pull/3583
* https://github.com/hyperium/http-body/pull/144
* https://github.com/linkerd/linkerd2-proxy/pull/3585
* https://github.com/linkerd/linkerd2-proxy/pull/3586
* https://github.com/linkerd/linkerd2-proxy/pull/3597
* https://github.com/linkerd/linkerd2-proxy/pull/3598
* https://github.com/linkerd/linkerd2-proxy/pull/3611
* https://github.com/linkerd/linkerd2-proxy/pull/3614
* https://github.com/linkerd/linkerd2-proxy/pull/3615
* https://github.com/linkerd/linkerd2-proxy/pull/3616
* https://github.com/linkerd/linkerd2-proxy/pull/3647
* https://github.com/linkerd/linkerd2-proxy/pull/3651
* https://github.com/linkerd/linkerd2-proxy/pull/3653
* https://github.com/linkerd/linkerd2-proxy/pull/3654
* https://github.com/linkerd/linkerd2-proxy/pull/3655
* https://github.com/linkerd/linkerd2-proxy/pull/3656
* https://github.com/linkerd/linkerd2-proxy/pull/3657
* https://github.com/linkerd/linkerd2-proxy/pull/3660
* https://github.com/linkerd/linkerd2-proxy/pull/3671
* https://github.com/linkerd/linkerd2-proxy/pull/3672
* https://github.com/linkerd/linkerd2-proxy/pull/3673
* https://github.com/linkerd/linkerd2-proxy/pull/3676
* https://github.com/hyperium/http-body/pull/147
* https://github.com/linkerd/linkerd2-proxy/pull/3692
* https://github.com/linkerd/linkerd2-proxy/pull/3699
* https://github.com/linkerd/linkerd2-proxy/pull/3700
* https://github.com/linkerd/linkerd2-proxy/pull/3701
* https://github.com/linkerd/linkerd2-proxy/pull/3708
* https://github.com/linkerd/drain-rs/pull/36
* https://github.com/linkerd/linkerd2-proxy/pull/3715
* https://github.com/linkerd/linkerd2-proxy/pull/3717
* https://github.com/eminence/procfs/pull/340

---

squash:

chore(deps): add hyper-util workspace dependency

chore(deps): add http-body-util workspace dependency

chore(deps): upgrade linkerd2-proxy-api

this commit represents main as of linkerd/linkerd2-proxy-api#421.

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(http/box): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(hyper-balance): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(http/retain): ugrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(http/stream-timeouts): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(http/classify): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(http/upgrade): upgrade to hyper 1.x

NOTE: there is a comment noting that the upgrade middleware does not
expect to be cloneable. it is unfortunately, however, at odds with the
new bounds expected of extensions.

so, `Http11Upgrade` is now Clone'able, but a comment is left in place
noting this weakened invariant.

it's worth investigating how upgrades have changed since, in more
detail, but for the current moment we are interested in being
especially conservative about changing behavior, and focusing on api
changes like `Body::poll_frame(..)`.

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(metrics): upgrade to hyper 1.x

a brief note; this commit happened to tickle an unfortunate sharp edge
in `BoxBody` and `Full`'s respective constructors. type inference could
not figure out how to construct the body, so we refrain from boxing the
response body now.

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(http/metrics): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(http/prom): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(http/insert): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(http/retry): deprecate linkerd-http-body-compat

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(mock/http-body): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(http/retry): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(proxy/tap): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(proxy/http): update to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(app/core): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(app/test): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(app/admin): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(app/outbound): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(app/inbound): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(app/integration): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(app): upgrade to hyper 1.x

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(transport-header): update generated code

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(spiffe-proto): update generated code

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(opencensus-proto): update generated code

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(opentelemetry-proto): update generated code

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(deny.toml): update cargo-deny directives

this commit updates the contents of `deny.toml`.

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore: `compile` has been renamed to `compile_protos`

this addresses deprecation warnings, updating calls to a function that
has since been renamed.

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(deps): remove `linkerd-http-body-compat` dependencies

this commit removes this crate, which we added to future proof code for
this upgrade, from its dependents.

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(http/body-compat): remove `linkerd-http-body-compat` crate

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(deps): update to drain 0.2.1

see https://github.com/linkerd/drain-rs/pull/41.

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-21 12:53:11 -04:00
dependabot[bot] a41642a7fd
build(deps): bump cc from 1.2.16 to 1.2.17 (#3794)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.16 to 1.2.17.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.16...cc-v1.2.17)

---
updated-dependencies:
- dependency-name: cc
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-21 07:13:33 -07:00
dependabot[bot] 4de4ab12ce
build(deps): bump backtrace from 0.3.73 to 0.3.74 (#3795)
Bumps [backtrace](https://github.com/rust-lang/backtrace-rs) from 0.3.73 to 0.3.74.
- [Release notes](https://github.com/rust-lang/backtrace-rs/releases)
- [Commits](https://github.com/rust-lang/backtrace-rs/compare/0.3.73...0.3.74)

---
updated-dependencies:
- dependency-name: backtrace
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-21 07:13:21 -07:00
dependabot[bot] 97adbd47ae
build(deps): bump Swatinem/rust-cache from 2.7.7 to 2.7.8 (#3780)
Bumps [Swatinem/rust-cache](https://github.com/swatinem/rust-cache) from 2.7.7 to 2.7.8.
- [Release notes](https://github.com/swatinem/rust-cache/releases)
- [Changelog](https://github.com/Swatinem/rust-cache/blob/master/CHANGELOG.md)
- [Commits](f0deed1e0e...9d47c6ad4b)

---
updated-dependencies:
- dependency-name: Swatinem/rust-cache
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-20 12:21:17 -07:00
dependabot[bot] 869e420733
build(deps): bump actions/download-artifact from 4.2.0 to 4.2.1 (#3789)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4.2.0 to 4.2.1.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](b14cf4c926...95815c38cf)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-20 12:20:59 -07:00
dependabot[bot] bd4f430740
build(deps): bump actions/upload-artifact from 4.6.1 to 4.6.2 (#3788)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.1 to 4.6.2.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](4cec3d8aa0...ea165f8d65)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-20 12:20:44 -07:00
katelyn martin 6a5cce8854
nit: golf `NameRef::try_from_ascii_str()` (#3786)
this golfs down the return expression in
`NameRef::try_from_ascii_str()`.

rather than binding our `s` to a temporary variable, in order to return
a `Self(s)` result, we can take the same result and use `Result::map` to
convert a `Result<&'a str, InvalidName>` to a
`Result<NameRef<'a>, InvalidName>`.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-20 12:12:22 -07:00
dependabot[bot] acbea26364
build(deps): bump tj-actions/changed-files (#3790)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 0b975f61488402a699abcebd6a1e25924cf85218 to 6482371e862961013f9584015cf362c4f664b20c.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](0b975f6148...6482371e86)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-20 11:07:47 -04:00
dependabot[bot] 7f5c42a2b2
build(deps): bump loom from 0.7.1 to 0.7.2 (#3791)
Bumps [loom](https://github.com/tokio-rs/loom) from 0.7.1 to 0.7.2.
- [Release notes](https://github.com/tokio-rs/loom/releases)
- [Changelog](https://github.com/tokio-rs/loom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/loom/commits)

---
updated-dependencies:
- dependency-name: loom
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-20 11:07:25 -04:00
dependabot[bot] 7caef34cda
build(deps): bump tempfile from 3.19.0 to 3.19.1 (#3792)
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.19.0 to 3.19.1.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.19.0...v3.19.1)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-20 11:07:11 -04:00
katelyn martin 03e9adb489
chore(dns): upgrade to `hickory-resolver` v0.25 (#3787)
* build(deps): bump the hickory group with 2 updates

Bumps the hickory group with 2 updates: [hickory-resolver](https://github.com/hickory-dns/hickory-dns) and [hickory-proto](https://github.com/hickory-dns/hickory-dns).


Updates `hickory-resolver` from 0.24.4 to 0.25.1
- [Release notes](https://github.com/hickory-dns/hickory-dns/releases)
- [Changelog](https://github.com/hickory-dns/hickory-dns/blob/main/OLD-CHANGELOG.md)
- [Commits](https://github.com/hickory-dns/hickory-dns/compare/v0.24.4...v0.25.1)

Updates `hickory-proto` from 0.24.4 to 0.25.1
- [Release notes](https://github.com/hickory-dns/hickory-dns/releases)
- [Changelog](https://github.com/hickory-dns/hickory-dns/blob/main/OLD-CHANGELOG.md)
- [Commits](https://github.com/hickory-dns/hickory-dns/compare/v0.24.4...v0.25.1)

---
updated-dependencies:
- dependency-name: hickory-resolver
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: hickory
- dependency-name: hickory-proto
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: hickory
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(dns): address breaking changes in `hickory-resolver`

see also #3782.

this commit addresses breaking changes in the v0.25.0 release of
`hickory-resolver`, used by our `linkerd-dns` crate to handle DNS
resolution.

see the release notes, here:
<https://github.com/hickory-dns/hickory-dns/releases/tag/v0.25.0>

> 0.25.0 represents a large release for the Hickory DNS project. Over 14
> months since 0.24.0, we've [..] addressed a number of findings from our
> first security audit.

changes that are relevant to us include:

> * Support for TLS using native-tls or OpenSSL has been removed. We now
>   only provide first-party support for rustls (0.23, for DNS over TLS,
>   HTTP/2, QUIC and HTTP/3). We support ring or aws-lc-rs for
>   cryptographic operations both for DNSSEC and TLS. The
>   dns-over-rustls,dns-over-native-tls, dns-over-openssl,
>   dns-over-https-rustls, dns-over-https, dns-over-quic and dns-over-h3
>   features have been removed in favor of a set of
>   {tls,https,quic,h3}-{aws-lc-rs,ring} features across our library
>   crates.
>
> * The synchronous API in the resolver and client crates, which
>   previously provided a thin partial wrapper over the asynchronous
>   API, has been removed. Downstream users will have to migrate to the
>   asynchronous API.
>
> * Error types are now exposed directly in the crate roots.

this commit updates references to the
`hickory_resolver::error::ResolveError` error with
`hickory_resolver::ResolveError` now that the errors submodule is
private. (hickory-dns/hickory-dns#2530)

this commit replaces references to
`hickory_resolver::TokioAsyncResolver` with its new name,
`hickory_resolver::TokioResolver`. (hickory-dns/hickory-dns#2521)

this commit inspects "no records found" errors according to the new api.
this particular change isn't especially documented, explicitly, but
occurred in hickory-dns/hickory-dns#2094. see in particular, in that
respect, corresponding changes in the upstream repo's own code. for
example: https://github.com/hickory-dns/hickory-dns/pull/2094/files#diff-330847b46040a30d449f85e8a804bea085f0974d3cba80d79d83acc56f33542dL176-R178

```diff
-  match error.kind() {
-       ResolveErrorKind::NoRecordsFound { query, soa, .. } => {
+   match error.proto().map(ProtoError::kind) {
+       Some(ProtoErrorKind::NoRecordsFound { query, soa, .. }) => {
```

there is a small pull request being proposed upstream to introduce a
`Builder::with_options()` method, which would make our construction of a
dns resolver marginally more idiomatic. this however, is not a blocker,
by any means.

X-Ref: hickory-dns/hickory-dns#2521
X-Ref: hickory-dns/hickory-dns#2830
X-Ref: hickory-dns/hickory-dns#2094
X-Ref: hickory-dns/hickory-dns#2877
Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: katelyn martin <kate@buoyant.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-19 22:00:17 -04:00
dependabot[bot] 924403f62c
build(deps): bump actions/download-artifact from 4.1.9 to 4.2.0 (#3781)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4.1.9 to 4.2.0.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](cc20338598...b14cf4c926)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-19 11:37:37 -04:00
dependabot[bot] 949cd5625c
build(deps): bump prettyplease from 0.2.30 to 0.2.31 (#3784)
Bumps [prettyplease](https://github.com/dtolnay/prettyplease) from 0.2.30 to 0.2.31.
- [Release notes](https://github.com/dtolnay/prettyplease/releases)
- [Commits](https://github.com/dtolnay/prettyplease/compare/0.2.30...0.2.31)

---
updated-dependencies:
- dependency-name: prettyplease
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-19 11:30:01 -04:00
dependabot[bot] a16235b937
build(deps): bump tokio from 1.43.0 to 1.44.1 (#3783)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.43.0 to 1.44.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.43.0...tokio-1.44.1)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-19 11:29:46 -04:00
Zahari Dichev a961efc883
chore(ci): add windows release target to relase matrix (#3771)
This PR adds os param to our package job in the release workflow.
This allows us to build and release Windows artifacts.

Signed-off-by: Zahari Dichev <zaharidichev@gmail.com>
2025-03-18 15:45:54 -07:00
katelyn martin 04d86a0375
refactor(http/upgrade): remove `HttpConnect` extension (#3779)
this branch is motivated by [review feedback](https://github.com/linkerd/linkerd2-proxy/pull/3504#discussion_r1999706761) from #3504. see
linkerd/linkerd2#8733 for more information on upgrading `hyper`. there,
we asked:

> I wonder if we should be a little more defensive about cloning [`HttpConnect`]. What does cloning it mean? When handling a CONNECT request, we can't clone the request, really. (Technically, we can't clone the body, but practically, it means we can't clone the request). Can we easily track whether this was accidentally cloned (i.e. with a custom Clone impl or Arc or some such) and validate at runtime (i.e., in proxy::http::h1) that everything is copacetic?

`linkerd-http-upgrade` provides a `HttpConnect` type that is intended
for use as a response extension. this commit performs a refactor,
removing this type.

we use this extension in a single piece of tower middleware. typically,
these sorts of extensions are intended for e.g. passing state between
distinct layers of tower middleware, or otherwise facilitating
extensions to the HTTP family of protocols.

this extension is only constructed and subsequently referenced within a
single file, in the `linkerd_proxy_http::http::h1::Client`. we can
perform the same task by using the `is_http_connect` boolean we use to
conditionally insert this extension.

then, this branch removes a helper function for a computation whose
amortization is no longer as helpful. now that we are passing
`is_http_connect` down into this function, we are no longer inspecting
the response's extensions. because of that, the only work to do is to
check the status code, which is a very cheap comparison.

this also restates an `if version != HTTP_11 { .. }` conditional block as
a match statement. this is a code motion change, none of the inner blocks
are changed.

reviewers are encouraged to examine this branch commit-by-commit; because
of the sensitivity of this change, this refactor is performed in small,
methodical changes.

for posterity, i've run the linkerd/linkerd2 test suite against this branch, as of
57dd7f4a60.

---

* refactor(http/upgrade): remove `HttpConnect` extension

`linkerd-http-upgrade` provides a `HttpConnect` type that is intended
for use as a response extension. this commit performs a refactor,
removing this type.

we use this extension in a single piece of tower middleware. typically,
these sorts of extensions are intended for e.g. passing state between
distinct layers of tower middleware, or otherwise facilitating
extensions to the HTTP family of protocols.

this extension is only constructed and subsequently referenced within a
single file, in the `linkerd_proxy_http::http::h1::Client`. we can
perform the same task by using the `is_http_connect` boolean we use to
conditionally insert this extension.

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(proxy/http): fold helper function

this removes a helper function for a computation whose amortization is
no longer as helpful.

now that we are passing `is_http_connect` down into this function, we
are no longer inspecting the response's extensions. because of that, the
only work to do is to check the status code, which is a very cheap
comparison.

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(proxy/http): match on response status

this commit refactors a sequence of conditional blocks in a helper
function used to identity HTTP/1.1 upgrades.

this commit replaces this sequence of conditional blocks with a match
statement.

Signed-off-by: katelyn martin <kate@buoyant.io>

* nit(proxy/http): rename `res` to `rsp`

we follow a convention where we tend to name responses `rsp`, not `res`
or `resp`. this commit applies that convention to this helper function.

Signed-off-by: katelyn martin <kate@buoyant.io>

* nit(proxy/http): import `Version`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(proxy/http): match on http version

this restates an `if version != HTTP_11 { .. }` conditional block as a
match statement.

this is a code motion change, none of the inner blocks are changed.

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(proxy/http): add comments on http/1.1

this commit adds a brief comment noting that upgrades are a concept
specific to http/1.1.

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-18 18:42:01 -04:00
dependabot[bot] 13478ae70a
build(deps): bump tj-actions/changed-files (#3777)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 9200e69727eb73eb060652b19946b8a2fdfb654b to 0b975f61488402a699abcebd6a1e25924cf85218.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](9200e69727...0b975f6148)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-18 12:54:48 -07:00
Zahari Dichev 61588895f7
chore(just): add .exe extension to windows binaries (#3769)
Signed-off-by: Zahari Dichev <zaharidichev@gmail.com>
2025-03-18 12:34:09 -07:00
dependabot[bot] 912bacb7c5
build(deps): bump itoa from 1.0.14 to 1.0.15 (#3773)
Bumps [itoa](https://github.com/dtolnay/itoa) from 1.0.14 to 1.0.15.
- [Release notes](https://github.com/dtolnay/itoa/releases)
- [Commits](https://github.com/dtolnay/itoa/compare/1.0.14...1.0.15)

---
updated-dependencies:
- dependency-name: itoa
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-18 11:00:53 -04:00
dependabot[bot] 5da8af300e
build(deps): bump time from 0.3.39 to 0.3.40 (#3774)
Bumps [time](https://github.com/time-rs/time) from 0.3.39 to 0.3.40.
- [Release notes](https://github.com/time-rs/time/releases)
- [Changelog](https://github.com/time-rs/time/blob/main/CHANGELOG.md)
- [Commits](https://github.com/time-rs/time/compare/v0.3.39...v0.3.40)

---
updated-dependencies:
- dependency-name: time
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-18 11:00:43 -04:00
dependabot[bot] 487377c888
build(deps): bump widestring from 1.1.0 to 1.2.0 (#3775)
Bumps [widestring](https://github.com/starkat99/widestring-rs) from 1.1.0 to 1.2.0.
- [Release notes](https://github.com/starkat99/widestring-rs/releases)
- [Changelog](https://github.com/starkat99/widestring-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/starkat99/widestring-rs/compare/v1.1.0...v1.2.0)

---
updated-dependencies:
- dependency-name: widestring
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-18 11:00:29 -04:00
dependabot[bot] c83a2a1ac6
build(deps): bump aligned-vec from 0.6.2 to 0.6.4 (#3776)
Bumps [aligned-vec](https://github.com/sarah-ek/aligned-vec) from 0.6.2 to 0.6.4.
- [Commits](https://github.com/sarah-ek/aligned-vec/compare/v0.6.2...v0.6.4)

---
updated-dependencies:
- dependency-name: aligned-vec
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-18 10:59:25 -04:00
dependabot[bot] 396cfcec2f
build(deps): bump rustls from 0.23.24 to 0.23.25 in the rustls group (#3772)
Bumps the rustls group with 1 update: [rustls](https://github.com/rustls/rustls).


Updates `rustls` from 0.23.24 to 0.23.25
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.23.24...v/0.23.25)

---
updated-dependencies:
- dependency-name: rustls
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: rustls
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-18 10:58:33 -04:00
Scott Fleener 65db3dd927
feat(policy): Allow outbound hostname metrics (#3770)
Outbound hostname metrics were recently disabled. This conditionally re-enables those through a `LINKERD2_PROXY_OUTBOUND_METRICS_HOSTNAME_LABELS` env var, wired through the policy/routing config with the option of individual policies and routes to set this separately from the global config.

Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-03-18 13:27:54 +00:00
dependabot[bot] 123d7a344e
build(deps): bump async-trait from 0.1.87 to 0.1.88 (#3764)
Bumps [async-trait](https://github.com/dtolnay/async-trait) from 0.1.87 to 0.1.88.
- [Release notes](https://github.com/dtolnay/async-trait/releases)
- [Commits](https://github.com/dtolnay/async-trait/compare/0.1.87...0.1.88)

---
updated-dependencies:
- dependency-name: async-trait
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 10:15:41 -04:00
dependabot[bot] 594f013902
build(deps): bump asn1-rs from 0.7.0 to 0.7.1 (#3765)
Bumps [asn1-rs](https://github.com/rusticata/asn1-rs) from 0.7.0 to 0.7.1.
- [Release notes](https://github.com/rusticata/asn1-rs/releases)
- [Changelog](https://github.com/rusticata/asn1-rs/blob/asn1-rs-0.7.1/CHANGELOG.md)
- [Commits](https://github.com/rusticata/asn1-rs/compare/asn1-rs-0.7.0...asn1-rs-0.7.1)

---
updated-dependencies:
- dependency-name: asn1-rs
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 10:15:17 -04:00
dependabot[bot] d7f961750f
build(deps): bump libc from 0.2.170 to 0.2.171 (#3766)
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.170 to 0.2.171.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.171/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.170...0.2.171)

---
updated-dependencies:
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 10:14:38 -04:00
dependabot[bot] 2c2fc8b0d9
build(deps): bump uuid from 1.15.1 to 1.16.0 (#3767)
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.15.1 to 1.16.0.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.15.1...v1.16.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 10:14:12 -04:00
dependabot[bot] e746454f50
build(deps): bump the rustls group across 1 directory with 4 updates (#3768)
Bumps the rustls group with 4 updates in the / directory: [tokio-rustls](https://github.com/rustls/tokio-rustls), [ring](https://github.com/briansmith/ring), [rustls-webpki](https://github.com/rustls/webpki) and [rustls](https://github.com/rustls/rustls).


Updates `tokio-rustls` from 0.26.1 to 0.26.2
- [Release notes](https://github.com/rustls/tokio-rustls/releases)
- [Commits](https://github.com/rustls/tokio-rustls/compare/v/0.26.1...v/0.26.2)

Updates `ring` from 0.17.13 to 0.17.14
- [Changelog](https://github.com/briansmith/ring/blob/main/RELEASES.md)
- [Commits](https://github.com/briansmith/ring/commits)

Updates `rustls-webpki` from 0.102.8 to 0.103.0
- [Release notes](https://github.com/rustls/webpki/releases)
- [Commits](https://github.com/rustls/webpki/compare/v/0.102.8...v/0.103.0)

Updates `rustls` from 0.23.23 to 0.23.24
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.23.23...v/0.23.24)

---
updated-dependencies:
- dependency-name: tokio-rustls
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rustls
- dependency-name: ring
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rustls
- dependency-name: rustls-webpki
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: rustls
- dependency-name: rustls
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: rustls
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 10:13:48 -04:00
katelyn martin 23784c01a3
chore: use workspace-level package metadata (#3761)
this commit adds a `[workspace.package]` table at the root of the cargo
workspace. constituent manifests are updated to use the workspace-level
metadata.

this is generally a superficial chore, but has a pleasant future upside:
when new rust editions are released (e.g. 2024), we will only need to
update the edition specified at the root of the workspace.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-15 12:54:50 -04:00
dependabot[bot] c5215ad21e
build(deps): bump tj-actions/changed-files from 45.0.7 to 45.0.8 (#3760)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 45.0.7 to 45.0.8.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](dcc7a0cba8...9200e69727)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-14 11:50:48 -04:00
dependabot[bot] 2ab03e2b95
build(deps): bump tempfile from 3.17.1 to 3.19.0 (#3759)
* build(deps): bump tempfile from 3.17.1 to 3.19.0

Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.17.1 to 3.19.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.17.1...v3.19.0)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(deny.toml): skip rustix v0.38

this commit adds mention of rustix, whose 1.0 release is still
propagating through the ecosystem, to the deny.toml.

nb: this also removes the bitflags directive, which no longer included a
duplicate version.

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: katelyn martin <kate@buoyant.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: katelyn martin <kate@buoyant.io>
2025-03-14 11:38:13 -04:00
dependabot[bot] 56faf968db
build(deps): bump once_cell from 1.21.0 to 1.21.1 (#3756)
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.21.0 to 1.21.1.
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.21.0...v1.21.1)

---
updated-dependencies:
- dependency-name: once_cell
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-14 11:31:41 -04:00
dependabot[bot] a616e96779
build(deps): bump aligned-vec from 0.6.1 to 0.6.2 (#3757)
Bumps [aligned-vec](https://github.com/sarah-ek/aligned-vec) from 0.6.1 to 0.6.2.
- [Commits](https://github.com/sarah-ek/aligned-vec/commits/v0.6.2)

---
updated-dependencies:
- dependency-name: aligned-vec
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-14 11:31:15 -04:00
dependabot[bot] 5a373bc569
build(deps): bump tokio-util from 0.7.13 to 0.7.14 (#3758)
Bumps [tokio-util](https://github.com/tokio-rs/tokio) from 0.7.13 to 0.7.14.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-util-0.7.13...tokio-util-0.7.14)

---
updated-dependencies:
- dependency-name: tokio-util
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-14 11:30:08 -04:00
katelyn martin 11e990ee16
refactor(stack/loadshed): unit test instruments spawned tasks (#3755)
this commit performs a small refactor to one of the unit tests in
`linkerd-stack`'s load-shedding middleware.

this adds a span to the worker tasks spawned in this test, so that
tracing logs can be associated with particular oneshot services.

see #3744 for more information on upgrading our tower dependency. this
is cherry-picked from investigations on that branch related to breaking
changes in 0.5 related to the `Buffer` middleware.

after this change, logs now look like this:

```
; RUST_LOG="trace" cargo test -p linkerd-stack buffer_load_shed -- --nocapture

running 1 test
[     0.002770s] TRACE worker{id=oneshot1}: tower::buffer::service: sending request to buffer worker
[     0.002809s] TRACE worker{id=oneshot2}: tower::buffer::service: sending request to buffer worker
[     0.002823s] TRACE worker{id=oneshot3}: tower::buffer::service: sending request to buffer worker
[     0.002843s] DEBUG worker{id=oneshot4}: linkerd_stack::loadshed: Service has become unavailable
[     0.002851s] DEBUG worker{id=oneshot4}: linkerd_stack::loadshed: Service shedding load
[     0.002878s] TRACE tower::buffer::worker: worker polling for next message
[     0.002885s] TRACE tower::buffer::worker: processing new request
[     0.002892s] TRACE worker{id=oneshot1}: tower::buffer::worker: resumed=false worker received request; waiting for service readiness
[     0.002901s] DEBUG worker{id=oneshot1}: tower::buffer::worker: service.ready=true processing request
[     0.002914s] TRACE worker{id=oneshot1}: tower::buffer::worker: returning response future
[     0.002926s] TRACE tower::buffer::worker: worker polling for next message
[     0.002931s] TRACE tower::buffer::worker: processing new request
[     0.002935s] TRACE worker{id=oneshot2}: tower::buffer::worker: resumed=false worker received request; waiting for service readiness
[     0.002946s] TRACE worker{id=oneshot2}: tower::buffer::worker: service.ready=false delay
[     0.002983s] TRACE worker{id=oneshot5}: tower::buffer::service: sending request to buffer worker
[     0.003001s] DEBUG worker{id=oneshot6}: linkerd_stack::loadshed: Service has become unavailable
[     0.003007s] DEBUG worker{id=oneshot6}: linkerd_stack::loadshed: Service shedding load
[     0.003017s] DEBUG worker{id=oneshot7}: linkerd_stack::loadshed: Service has become unavailable
[     0.003024s] DEBUG worker{id=oneshot7}: linkerd_stack::loadshed: Service shedding load
[     0.003035s] TRACE tower::buffer::worker: worker polling for next message
[     0.003041s] TRACE tower::buffer::worker: resuming buffered request
[     0.003045s] TRACE worker{id=oneshot2}: tower::buffer::worker: resumed=true worker received request; waiting for service readiness
[     0.003052s] DEBUG worker{id=oneshot2}: tower::buffer::worker: service.ready=true processing request
[     0.003060s] TRACE worker{id=oneshot2}: tower::buffer::worker: returning response future
[     0.003068s] TRACE tower::buffer::worker: worker polling for next message
[     0.003073s] TRACE tower::buffer::worker: processing new request
[     0.003077s] TRACE worker{id=oneshot3}: tower::buffer::worker: resumed=false worker received request; waiting for service readiness
[     0.003084s] DEBUG worker{id=oneshot3}: tower::buffer::worker: service.ready=true processing request
[     0.003091s] TRACE worker{id=oneshot3}: tower::buffer::worker: returning response future
[     0.003099s] TRACE tower::buffer::worker: worker polling for next message
[     0.003103s] TRACE tower::buffer::worker: processing new request
[     0.003107s] TRACE worker{id=oneshot5}: tower::buffer::worker: resumed=false worker received request; waiting for service readiness
[     0.003114s] DEBUG worker{id=oneshot5}: tower::buffer::worker: service.ready=true processing request
[     0.003121s] TRACE worker{id=oneshot5}: tower::buffer::worker: returning response future
[     0.003129s] TRACE tower::buffer::worker: worker polling for next message
test loadshed::tests::buffer_load_shed ... ok
```

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-13 13:26:21 -04:00
dependabot[bot] 5fa3745b57
build(deps): bump resolv-conf from 0.7.0 to 0.7.1 (#3751)
Bumps [resolv-conf](https://github.com/hickory-dns/resolv-conf) from 0.7.0 to 0.7.1.
- [Commits](https://github.com/hickory-dns/resolv-conf/commits)

---
updated-dependencies:
- dependency-name: resolv-conf
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-13 09:43:41 -04:00
dependabot[bot] e67ac67288
build(deps): bump http from 0.2.11 to 0.2.12 (#3754)
Bumps [http](https://github.com/hyperium/http) from 0.2.11 to 0.2.12.
- [Release notes](https://github.com/hyperium/http/releases)
- [Changelog](https://github.com/hyperium/http/blob/v0.2.12/CHANGELOG.md)
- [Commits](https://github.com/hyperium/http/compare/v0.2.11...v0.2.12)

---
updated-dependencies:
- dependency-name: http
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-13 09:42:47 -04:00
dependabot[bot] a8390b2ee6
build(deps): bump syn from 2.0.99 to 2.0.100 (#3752)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.99 to 2.0.100.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.99...2.0.100)

---
updated-dependencies:
- dependency-name: syn
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-13 09:42:08 -04:00
katelyn martin c35cf270cf
chore(deps): address RUSTSEC-2025-0014 (#3750)
this commit replaces `humantime`, which is no longer maintained, with
`jiff`.

see this error when `main` today is built:

```
error[unmaintained]: humantime is unmaintained
   ┌─ /linkerd/linkerd2-proxy/Cargo.lock:78:1
   │
78 │ humantime 2.1.0 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unmaintained advisory detected
   │
   ├ ID: RUSTSEC-2025-0014
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2025-0014
   ├ Latest `humantime` crates.io release is four years old and GitHub repository has
     not seen commits in four years. Question about maintenance status has not gotten
     any reaction from maintainer: https://github.com/tailhook/humantime/issues/31

     ## Possible alternatives

      * [jiff](https://crates.io/crates/jiff) provides same kind of functionality
   ├ Announcement: https://github.com/tailhook/humantime/issues/31
   ├ Solution: No safe upgrade is available!
   ├ humantime v2.1.0
     └── linkerd-http-access-log v0.1.0
         └── linkerd-app-inbound v0.1.0
             ├── linkerd-app v0.1.0
             │   ├── linkerd-app-integration v0.1.0
             │   └── linkerd2-proxy v0.1.0
             ├── linkerd-app-admin v0.1.0
             │   ├── linkerd-app v0.1.0 (*)
             │   └── (dev) linkerd-app-integration v0.1.0 (*)
             └── linkerd-app-gateway v0.1.0
                 └── linkerd-app v0.1.0 (*)

advisories FAILED, bans ok, licenses ok, sources ok
```

see:
  * https://github.com/rustsec/advisory-db/pull/2249.
  * https://github.com/tailhook/humantime/issues/31.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-12 16:05:03 -07:00
dependabot[bot] d3b4ad6362
build(deps): bump dtoa from 1.0.9 to 1.0.10 (#3749)
Bumps [dtoa](https://github.com/dtolnay/dtoa) from 1.0.9 to 1.0.10.
- [Release notes](https://github.com/dtolnay/dtoa/releases)
- [Commits](https://github.com/dtolnay/dtoa/compare/1.0.9...1.0.10)

---
updated-dependencies:
- dependency-name: dtoa
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-12 09:58:59 -04:00
dependabot[bot] 332e29af5c
build(deps): bump prettyplease from 0.2.29 to 0.2.30 (#3747)
Bumps [prettyplease](https://github.com/dtolnay/prettyplease) from 0.2.29 to 0.2.30.
- [Release notes](https://github.com/dtolnay/prettyplease/releases)
- [Commits](https://github.com/dtolnay/prettyplease/compare/0.2.29...0.2.30)

---
updated-dependencies:
- dependency-name: prettyplease
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-12 09:58:28 -04:00
dependabot[bot] 6d7b165727
build(deps): bump once_cell from 1.20.3 to 1.21.0 (#3748)
Bumps [once_cell](https://github.com/matklad/once_cell) from 1.20.3 to 1.21.0.
- [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md)
- [Commits](https://github.com/matklad/once_cell/compare/v1.20.3...v1.21.0)

---
updated-dependencies:
- dependency-name: once_cell
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-12 09:58:02 -04:00
dependabot[bot] df651278f2
build(deps): bump quote from 1.0.39 to 1.0.40 (#3746)
Bumps [quote](https://github.com/dtolnay/quote) from 1.0.39 to 1.0.40.
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.39...1.0.40)

---
updated-dependencies:
- dependency-name: quote
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-12 09:57:24 -04:00
Oliver Gould 16b2ff7232
chore(cargo): make prometheus-client a workspace dependency (#3743) 2025-03-11 22:38:39 +00:00
Oliver Gould 46babf0849
chore(metrics): use kubert-prometheus-process metrics (#3742)
kubert-prometheus-process is a new crate that includes all of Linkerd's system
metrics and more. This also helps avoid annoying compilation build issues on
non-Linux systems.
2025-03-11 18:37:17 -04:00
katelyn martin 575ba0008b
chore(deps): use `prometheus-client` v0.23 (#3732)
this updates the prometheus client dependency.

additionally, this commit updates the `kubert-prometheus-tokio`
dependency, so that we agree on the client library in use.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-11 21:42:13 +00:00
Oliver Gould 4c79bdf730
chore(metrics): clean up feature flagging (#3741)
linkerd-metrics exposes a 'stack' feature but uses a 'linkerd-stack' feature
internally. This change cleans this up.
2025-03-11 15:46:39 -04:00
Oliver Gould 87d6d38510
chore(app-core): remove unused linkerd-system dep (#3740) 2025-03-11 19:43:27 +00:00
Oliver Gould ed42c2ad3a
feat(runtime): support CORES_MIN, CORES_MAX, and CORES_MAX_RATIO (#3731)
When the proxy boots up, it needs to select a number of I/O worker threads to
allocate to the runtime. This change adds a new environment variable that allows
this value to scale based on the number of CPUs available on on the host.

A CORES_MAX_RATIO value of 1.0 will allocate one worker thread per CPU core. A
lesser value will allocate fewer worker threads. Values are rounded to the
nearest whole number.

The CORES_MIN value sets a lower bound on the number of worker threads to use.
The CORES_MAX value sets an upper bound.
2025-03-11 18:53:30 +00:00
katelyn martin 13a79167d7
refactor(stack/switch_ready): use `Either<A, B>` future (#3739)
this commit makes a noöp change to the `SwitchReady<A, B>` machinery
provided by our `linkerd-stack` library.

this commit is a small refactor that is intended to pave the way for an
impending upgrade to tower v0.5, which notably includes breaking changes
to the `tower::util::Either<A, B>` service.

as of tower v0.5, by way of https://github.com/tower-rs/tower/pull/637,
the `Either<A, B>` service is no longer itself a `Future`. so, we can
instead use the future provided by `futures`.

for more information, see:
* https://github.com/linkerd/linkerd2/issues/8733
* https://github.com/linkerd/linkerd2-proxy/pull/3504
* https://github.com/linkerd/linkerd2-proxy/pull/3504/files#r1988082658
* https://github.com/tower-rs/tower/pull/637

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-11 14:50:51 -04:00
Oliver Gould 1c15dd087d
chore(linkerd2-proxy): always enable multicore features (#3738)
The proxy predates the multi-threaded tokio runtime. When switching to it, we
added a 'multicore' feature to adopt it incrementally. This has been the only
supported configuration for many years now.

This change removes the needless feature flag to simplify the runtime
configuration.
2025-03-11 17:08:26 +00:00
Oliver Gould a683ff5c67
feat(outbound): instrument per-parent connection protocol counts (#3733)
The outbound proxy makes protocol decisions based on the discovery response,
keyed on a "parent" reference.

This change adds a `protocol::metrics` middleware that records connection counts
by parent reference.
2025-03-11 09:49:45 -07:00
dependabot[bot] ec168c3977
build(deps): bump tinyvec from 1.8.1 to 1.9.0 (#3737)
Bumps [tinyvec](https://github.com/Lokathor/tinyvec) from 1.8.1 to 1.9.0.
- [Changelog](https://github.com/Lokathor/tinyvec/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Lokathor/tinyvec/compare/v1.8.1...v1.9.0)

---
updated-dependencies:
- dependency-name: tinyvec
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-11 07:18:58 -07:00
dependabot[bot] 0dc3c8dde4
build(deps): bump indexmap from 2.7.1 to 2.8.0 (#3736)
Bumps [indexmap](https://github.com/indexmap-rs/indexmap) from 2.7.1 to 2.8.0.
- [Changelog](https://github.com/indexmap-rs/indexmap/blob/main/RELEASES.md)
- [Commits](https://github.com/indexmap-rs/indexmap/compare/2.7.1...2.8.0)

---
updated-dependencies:
- dependency-name: indexmap
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-11 07:18:47 -07:00
dependabot[bot] f2bc4cd76d
build(deps): bump bytes from 1.10.0 to 1.10.1 (#3735)
Bumps [bytes](https://github.com/tokio-rs/bytes) from 1.10.0 to 1.10.1.
- [Release notes](https://github.com/tokio-rs/bytes/releases)
- [Changelog](https://github.com/tokio-rs/bytes/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/bytes/compare/v1.10.0...v1.10.1)

---
updated-dependencies:
- dependency-name: bytes
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-11 07:18:36 -07:00
dependabot[bot] 72ee0b31d2
build(deps): bump quote from 1.0.38 to 1.0.39 (#3734)
Bumps [quote](https://github.com/dtolnay/quote) from 1.0.38 to 1.0.39.
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.38...1.0.39)

---
updated-dependencies:
- dependency-name: quote
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-11 07:18:23 -07:00
Oliver Gould 64c608ca8d
feat(inbound): record metrics about transport header usage (#3723)
Inbound proxies may receive meshed traffic directly on the proxy's inbound port
with a transport header, informing inbound routing behavior.

This change updates the inbound proxy to record metrics about the usage of
transport headers, including the total number of requests with a transport
header by session protocol and target port.
2025-03-10 14:07:38 -07:00
Oliver Gould 25bc9730ee
feat: instrument HTTP protocol detection metrics (#3722)
This change updates the DetectHttp middleware to record metrics about HTTP
protocol detection. Specfically, it records the the counts of results and a very
coarse histogram of the time taken to detect the protocol.

The inbound, outbound, and admin (via inbound) stacks are updated to record
metrics against the main registry.
2025-03-10 11:12:56 -07:00
Oliver Gould e7c2afd5c1
feat(http/detect)!: error when the socket is closed (#3721)
* refactor(http): consolidate HTTP protocol detection

Linkerd's HTTP protocol detection logic is spread across a few crates: the
linkerd-detect crate is generic over the actual protocol detection logic, and
the linkerd-proxy-http crate provides an implementation. There are no other
implemetations of the Detect interface. This leads to gnarly type signatures in
the form `Result<Option<http::Variant>, DetectTimeoutError>`: simultaneously
verbose and not particularly informative (what does the None case mean exactly).

This commit introduces a new crate, `linkerd-http-detect`, consolidating this
logic and removes the prior implementations. The admin, inbound, and outbound
stacks are updated to use these new types. This work is done in anticipation of
introducing metrics that report HTTP detection behavior.

There are no functional changes.

* feat(http/detect)!: error when the socket is closed

When a proxy does protocol detection, the initial read may indicate that the
connection was closed by the client with no data being written to the socket. In
such a case, the proxy continues to process the connection as if may be proxied,
but we expect this to fail immediately. This can lead to unexpected proxy
behavior: for example, inbound proxies may report policy denials.

To address this, this change surfaces an error (as if the read call failed).
This could, theoretically, impact some bizarre clients that initiate half-open
connections. These corner cases can use explicit opaque policies to bypass
detection.
2025-03-10 08:31:17 -07:00
dependabot[bot] 606b51ba32
build(deps): bump thiserror from 2.0.11 to 2.0.12 (#3728)
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 2.0.11 to 2.0.12.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/2.0.11...2.0.12)

---
updated-dependencies:
- dependency-name: thiserror
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-10 08:02:20 -07:00
dependabot[bot] 3a7d207950
build(deps): bump ryu from 1.0.19 to 1.0.20 (#3729)
Bumps [ryu](https://github.com/dtolnay/ryu) from 1.0.19 to 1.0.20.
- [Release notes](https://github.com/dtolnay/ryu/releases)
- [Commits](https://github.com/dtolnay/ryu/compare/1.0.19...1.0.20)

---
updated-dependencies:
- dependency-name: ryu
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-10 08:01:36 -07:00
dependabot[bot] 77b21876cd
build(deps): bump serde from 1.0.218 to 1.0.219 (#3727)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.218 to 1.0.219.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.218...v1.0.219)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-10 08:01:20 -07:00
dependabot[bot] 5a0fe3d221
build(deps): bump time from 0.3.37 to 0.3.39 (#3726)
Bumps [time](https://github.com/time-rs/time) from 0.3.37 to 0.3.39.
- [Release notes](https://github.com/time-rs/time/releases)
- [Changelog](https://github.com/time-rs/time/blob/main/CHANGELOG.md)
- [Commits](https://github.com/time-rs/time/compare/v0.3.37...v0.3.39)

---
updated-dependencies:
- dependency-name: time
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-10 08:01:02 -07:00
Oliver Gould fc928b637a
feat(inbound): include srv_port label in server metrics (#3725)
We include a group/version/kind for inbound server resources, but we do not
indicate which specific port the server is applied to. This is important context
to understand the inbound proxy's behavior, especially when using the default
servers.

This change adds a `srv_port` label to inbound server metrics to definitively
and consistently indicate the server port used for inbound policy.
2025-03-09 20:40:22 -04:00
Oliver Gould 9f5a6cce27
fix(inbound): correct error message when transport header is missing (#3724)
The RefusedNoTarget error type is a remnant of an older version of the direct
stack. This commit updates the error message to reflect the current state of the
code: we require ALPN-negotiated transport headers on all direct connections.
2025-03-09 19:46:45 -04:00
Oliver Gould c87d202098
refactor(http): consolidate HTTP protocol detection (#3720)
Linkerd's HTTP protocol detection logic is spread across a few crates: the
linkerd-detect crate is generic over the actual protocol detection logic, and
the linkerd-proxy-http crate provides an implementation. There are no other
implemetations of the Detect interface. This leads to gnarly type signatures in
the form `Result<Option<http::Variant>, DetectTimeoutError>`: simultaneously
verbose and not particularly informative (what does the None case mean exactly).

This commit introduces a new crate, `linkerd-http-detect`, consolidating this
logic and removes the prior implementations. The admin, inbound, and outbound
stacks are updated to use these new types. This work is done in anticipation of
introducing metrics that report HTTP detection behavior.

There are no functional changes.
2025-03-09 08:27:25 -07:00
Oliver Gould 114ee8d878
fix(just): make dev versions semver (#3719)
Our build can occaisionally fail when the sha is not a valid semver label:

    --- stdout
    cargo:rustc-env=GIT_SHA=025979070
    cargo:rustc-env=LINKERD2_PROXY_BUILD_DATE=2025-03-08T16:32:34Z
    --- stderr
    thread 'main' panicked at linkerd/app/core/build.rs:18:17:
    LINKERD2_PROXY_VERSION must be semver: version='0.0.0-dev.025979070'
       error='invalid leading zero in pre-release identifier'

To fix this, the dot is removed so the version string is 0.0.0-dev025979070,
which is valid.
2025-03-08 18:30:06 -05:00
katelyn martin 4f24b84ee0
chore(deps): `tower` is a workspace dependency (#3718)
pr #3715 missed a small handful of cargo dependencies. this commit marks
these so that they also use the workspace-level tower version.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-08 10:17:51 -08:00
katelyn martin 09ecbd79b7
chore(deps): `drain` is a workspace dependency (#3717)
see https://github.com/linkerd/linkerd2/issues/8733 and
https://github.com/linkerd/linkerd2-proxy/pull/3504 for more
information.

see also linkerd/drain-rs#36 for a related pull request that
updated `drain`'s `tower` dependency. see #3715 (2f97549a) for a related
pull request that made `tower` a workspace dependency.

see #3456 (c740b6d8), #3466 (ca50d6bb), #3473 (b87455a9), and #3701
(cf4ef39), for some other previous pr's that moved dependencies to be
managed at the workspace level.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-07 16:34:24 -05:00
katelyn martin 4589be41ee
nit(detect): sort dependencies (#3716)
this is a follow-on to #3715.

this commit sorts the dependencies in this manifest.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-07 13:05:13 -08:00
katelyn martin 2f97549aed
chore(deps): `tower` crates are workspace dependencies (#3715)
* chore(deps): `tower` is a workspace dependency

see https://github.com/linkerd/linkerd2/issues/8733 for more
information.

see https://github.com/linkerd/linkerd2-proxy/pull/3504 as well.

see #3456 (c740b6d8), #3466 (ca50d6bb), #3473 (b87455a9), and #3701
(cf4ef39) for some other previous pr's that moved dependencies to be
managed at the workspace level.

see also https://github.com/linkerd/drain-rs/pull/36 for another related
pull request that relates to our tower dependency.

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(deps): `tower-service` is a workspace dependency

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(deps): `tower-test` is a workspace dependency

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-07 14:58:18 -05:00
katelyn martin d2111e59b9
chore(deps): update to ring 0.17.13 (#3713)
https://rustsec.org/advisories/RUSTSEC-2025-0009.html

0.17.11 is vulnerable to RUSTSEC-2025-0009. this commit updates the
`ring` dependency to a patched version.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-07 12:19:13 -05:00
dependabot[bot] 4a2bf8d876
build(deps): bump rustversion from 1.0.19 to 1.0.20 (#3712)
Bumps [rustversion](https://github.com/dtolnay/rustversion) from 1.0.19 to 1.0.20.
- [Release notes](https://github.com/dtolnay/rustversion/releases)
- [Commits](https://github.com/dtolnay/rustversion/compare/1.0.19...1.0.20)

---
updated-dependencies:
- dependency-name: rustversion
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 07:28:18 -08:00
dependabot[bot] bba79fd1dd
build(deps): bump either from 1.14.0 to 1.15.0 (#3711)
Bumps [either](https://github.com/rayon-rs/either) from 1.14.0 to 1.15.0.
- [Commits](https://github.com/rayon-rs/either/compare/1.14.0...1.15.0)

---
updated-dependencies:
- dependency-name: either
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 07:28:04 -08:00
dependabot[bot] c6c369c41f
build(deps): bump semver from 1.0.25 to 1.0.26 (#3710)
Bumps [semver](https://github.com/dtolnay/semver) from 1.0.25 to 1.0.26.
- [Commits](https://github.com/dtolnay/semver/compare/1.0.25...1.0.26)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 07:27:52 -08:00
dependabot[bot] a1d49e9ee8
build(deps): bump unicode-ident from 1.0.17 to 1.0.18 (#3709)
Bumps [unicode-ident](https://github.com/dtolnay/unicode-ident) from 1.0.17 to 1.0.18.
- [Commits](https://github.com/dtolnay/unicode-ident/compare/1.0.17...1.0.18)

---
updated-dependencies:
- dependency-name: unicode-ident
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 07:27:39 -08:00
katelyn martin 90e005a832
chore(deps): remove unused `opencensus`, `opentelemetry` dependencies (#3708)
noticed while addressing `cargo-deny` errors in #3504. these crates
include a few unused dependencies, which we can remove. while we
are in the neighborhood, we make some subjective tweaks to tidy up
these imports.

---

* chore(opentelemetry): remove unused `http` dependency

Signed-off-by: katelyn martin <kate@buoyant.io>

* nit(opentelemetry): tidy imports

this groups imports at the crate level, and directly imports some
imports from their respective crates rather than through an alias of
said crate. a `self` prefix is added to clarify imports from submodules
of this crate.

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(opentelemetry): remove unused `tokio-stream` dependency

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(opencensus): remove unused `http` dependency

Signed-off-by: katelyn martin <kate@buoyant.io>

* nit(opencensus): use self prefix in import

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-06 14:03:16 -08:00
Scott Fleener 40a622ee48
fix(inbound): instrument http connections in tagged transport stack (#3707)
Currently, TCP metrics are not logged for HTTP requests coming in through the tagged transport header stack.

This adds that instrumentation, like we do for the opaque and gateway stacks already present.

Signed-off-by: Scott Fleener <scott@buoyant.io>
2025-03-06 20:19:30 +00:00
katelyn martin cf4ef39a89
chore(deps): `prost-build` is a workspace dependency (#3701)
see https://github.com/linkerd/linkerd2/issues/8733 for more
information.

this commit moves `prost-build` so that it is now managed as a workspace
dependency. while only used in tests, these tests can fail if this is
not versioned in lockstep with our other protobuffer dependencies.

see #3456 (c740b6d8), #3466 (ca50d6bb), and especially #3473 (b87455a9)
for some other previous pr's that moved dependencies to be managed at
the workspace level.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-06 08:24:19 -08:00
dependabot[bot] cd34762962
build(deps): bump serde_json from 1.0.139 to 1.0.140 (#3706)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.139 to 1.0.140.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.139...v1.0.140)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-06 05:48:14 -05:00
dependabot[bot] d98cff0b74
build(deps): bump pin-project from 1.1.9 to 1.1.10 (#3705)
Bumps [pin-project](https://github.com/taiki-e/pin-project) from 1.1.9 to 1.1.10.
- [Release notes](https://github.com/taiki-e/pin-project/releases)
- [Changelog](https://github.com/taiki-e/pin-project/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/pin-project/compare/v1.1.9...v1.1.10)

---
updated-dependencies:
- dependency-name: pin-project
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-06 05:47:41 -05:00
dependabot[bot] 0b4420ec6a
build(deps): bump symbolic-demangle from 12.13.4 to 12.14.1 (#3704)
Bumps [symbolic-demangle](https://github.com/getsentry/symbolic) from 12.13.4 to 12.14.1.
- [Release notes](https://github.com/getsentry/symbolic/releases)
- [Changelog](https://github.com/getsentry/symbolic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/symbolic/compare/12.13.4...12.14.1)

---
updated-dependencies:
- dependency-name: symbolic-demangle
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-06 05:46:53 -05:00
dependabot[bot] f1c8eb0487
build(deps): bump httparse from 1.10.0 to 1.10.1 (#3703)
Bumps [httparse](https://github.com/seanmonstar/httparse) from 1.10.0 to 1.10.1.
- [Release notes](https://github.com/seanmonstar/httparse/releases)
- [Commits](https://github.com/seanmonstar/httparse/compare/v1.10.0...v1.10.1)

---
updated-dependencies:
- dependency-name: httparse
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-06 05:46:10 -05:00
katelyn martin f5b4f6b1c6
refactor(app/integration): remove artificial `Sync` bounds (#3700)
see https://github.com/linkerd/linkerd2/issues/8733 for more
information.

we are in the process of upgrading to hyper 1.x.

in the process of doing so, we will wish to use our friendly `BoxBody`
type, which provides a convenient and reusable interface to abstract
over different artitrary `B`-typed request and response bodies.

unfortunately, by virtue of its definition, it is not a `Sync` type:

```rust
 pub struct BoxBody {
     inner: Pin<Box<dyn Body<Data = Data, Error = Error> + Send + 'static>>,
 }

 #[pin_project]
 pub struct Data {
     #[pin]
     inner: Box<dyn bytes::Buf + Send + 'static>,
 }
```

these are erased `Box<dyn ..>` objects that only ensure `Send`-ness.

rather than changing that, because that is the proper definition of the
type, we should update code in our test client and test server to stop
requesting arbitrary `Sync` bounds.

this commit removes `Sync` bounds from various places that in fact only
need be `Send + 'static`.

this will help facilitate making use of `BoxBody` in #3504.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-04 15:29:03 -08:00
katelyn martin dacf85896e
refactor(app/integration): forward-compatible test code (#3699)
see https://github.com/linkerd/linkerd2/issues/8733 for more
information.

see https://github.com/linkerd/linkerd2-proxy/pull/3559 and
https://github.com/linkerd/linkerd2-proxy/pull/3614 for more information
on the `ForwardCompatibleBody<B>` wrapper.

`telemetry::log_stream::collect_logs` is a function responsible for
digesting a streaming body, and deserializing each chunk into a
`serde_json::Value`, until either (a) a shutdown signal is received, or
(b) the end of the body is reached.

this commit updates test code in `linkerd-app-integration` so that it
interacts with request and response bodies via an adapter that polls for
frames in a manner consistent with the 1.0 api of `http_body`.

this allows us to limit the diff in
https://github.com/linkerd/linkerd2-proxy/pull/3504, which will only
need to remove this adapter once using hyper 1.0.

* https://github.com/linkerd/linkerd2/issues/8733
* https://github.com/linkerd/linkerd2-proxy/pull/3671
* https://github.com/linkerd/linkerd2-proxy/pull/3672
* https://github.com/linkerd/linkerd2-proxy/pull/3673
* https://github.com/linkerd/linkerd2-proxy/pull/3676

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-04 11:37:58 -08:00
katelyn martin d4bfd607c5
refactor(app/integration): remove unused `TcpConn::target_addr()` (#3695)
this method is not used by any test code, nor any other internal code.

this commit removes
`linkerd_app_integration::tcp::TcpConn::target_addr()`.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-04 10:06:11 -08:00
katelyn martin 16614ca2d5
refactor(app/integration): remove unused `request_init_method()` (#3698)
`TapEventExt` provides an extension trait interface that we use to
extends `linkerd_proxy_api::tap::TapEvent` with additional interfaces
for use in integration tests.

this commit removes `request_init_path()`. this method was originally
added in 3ac6b72c4 (#154), but was never actually implemented and will
only ever panic when invoked. thus, it can be removed.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-04 16:03:53 +00:00
katelyn martin 8117c51a4a
nit(app/integration): tidy `tcp` imports (#3696)
we follow a convention of grouping imported symbols at the crate-level.

this commit tidies up imports in `linkerd_app_integration::tcp` to
follow this convention.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-04 07:59:24 -08:00
katelyn martin 799583af90
refactor(app/integration): call `tcp::client()` directly (#3694)
`linkerd_app_integration::tcp` provides a `TcpClient` type that is
distinct from the primary `linkerd_app_integration::client::Client` type
broadly used in integration tests.

this commit makes a small change to reduce indirection, and clarify that
this is constructing a different client implementation from a different
submodule.

this removes `linkerd_app_integration::client::tcp()`, and updates test
code to call the `tcp::client()` function that this is masking.

this is the client-side equivalent to #3688 (a10d1d7e).

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-04 07:59:13 -08:00
katelyn martin 4e3119cd45
refactor(app/integration): clean up `Server` constructors (#3693)
this commit removes some misdirection from the various constructors for
our test server.

currently, we expose a family of constructor functions `server::new()`,
`server::http1()`, ..., and so forth.

each of these invoke a private `server::Server::http1()`,
`server::Server::http2()`, `server::Server::http2_tls()`, ...,
counterpart, which then delegates down once more to another private
constructor `server::Server::new()`.

this is all a bit roundabout, particularly because these private
constructors are not used by any other internal code in the `server`
submodule.

this commit removes these inherent `Server` constructors, since they are
private and not used by any test code. each free-standing constructor
function is altered to instead directly construct a `Server`.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-04 00:42:01 +00:00
katelyn martin ce7e6645e3
refactor(app/integration): remove `Request`, `Response` aliases (#3692)
* refactor(app/integration): remove `Request`, `Response` aliases

see https://github.com/linkerd/linkerd2/issues/8733.

this commit removes two type aliases from our test server
implementation. these are each tied to the defunct `hyper::Body` type.

since much of this code was originally written (between 2017 and 2020)
we've since developed some patterns / idioms elsewhere for dealing with
request and response bodies.

to help set the stage for tweaks to which interfaces need
`hyper::body::Incoming`, which types work with our general default of
`BoxBody`, and which can be generic across arbitrary `B`-typed bodies,
we remove these aliases and provide the body parameter to `Request` and
`Response`.

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/integration): remove `Request`, `Response` aliases

see https://github.com/linkerd/linkerd2/issues/8733.

this commit removes two type aliases from our test client
implementation. these are each tied to the defunct `hyper::Body` type.

since much of this code was originally written (between 2017 and 2020)
we've since developed some patterns / idioms elsewhere for dealing with
request and response bodies.

to help set the stage for tweaks to which interfaces need
`hyper::body::Incoming`, which types work with our general default of
`BoxBody`, and which can be generic across arbitrary `B`-typed bodies,
we remove these aliases and provide the body parameter to `Request` and
`Response`.

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-03 23:46:09 +00:00
katelyn martin 84c3b8491e
nit(app/integration): add/remove whitespace for consistency (#3689)
* nit(app/integration): add whitespace for consistency

we follow a convention of an empty line between functions.

this commit adds an empty line.

Signed-off-by: katelyn martin <kate@buoyant.io>

* nit(app/integration): remove whitespace for consistency

Signed-off-by: katelyn martin <kate@buoyant.io>

* nit(app/integration): add whitespace for consistency

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-03 18:39:55 -05:00
katelyn martin abc8364f39
nit(app/integration): use `OK`, `NOT_FOUND` constants (#3691)
these constants exist, and are generally considered a best practice for
these situations.

this commit replaces numeric literals with named constants.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-03 18:39:03 -05:00
katelyn martin f4eac760f0
refactor(app/integration): use `linker_app_core::Error` (#3690)
the test server implementation in `linkerd_app_integration` defines an
`BoxError` alias. we have a boxed error type in
`linkerd_app_core::Error` that achieves the same purpose, that we can
use instead.

this commit replaces this type alias with a reëxport of
`linkerd_app_core::Error`.

see also, #3685, which removed another similar alias.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-03 18:38:48 -05:00
katelyn martin a10d1d7ef8
refactor(app/integration): call `tcp::server()` directly (#3688)
`linkerd_app_integration::tcp` provides a `TcpServer` type that is
distinct from the primary `linkerd_app_integration::server::Server` type
broadly used in integration tests.

this commit makes a small change to reduce indirection, and clarify that
this is constructing a different server implementation from a
different submodule.

this removes `linkerd_app_integration::server::tcp()`, and updates test
code to call the `tcp::server()` function that this is masking.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-03 16:20:45 -05:00
katelyn martin cd3a200a5e
refactor(app/integration): remove inert `NewService<T>` (#3687)
elsewhere in our codebase, we follow a pattern that can be called a
"new service". this is a `Service<T>` whose response `S` is itself
a `Service<U>`.

new services are often useful for dealing with particular connection
semantics, and provide us a way to model a connection that services many
requests.

our test server code makes use of a `Svc`, which wraps a reference to a
map of uri's and routes. there is an associated `NewSvc` type that does
not provide any material benefit. this `NewSvc` type is a `Service<()>`
that never exerts backpressure, nor performs any action besides
`Arc::clone`ing the map of routes.

this commit golfs down `linkerd_app_integration::server::Server`, by
directly cloning the routes into a `Svc(_)`, without the need for
polling a future or handling an (impossible) error.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-03 16:20:29 -05:00
katelyn martin be868306f5
refactor(app/integration): inline `Running` future (#3686)
`linkerd_app_integration::running()` is a public function that is not
used by any external callers. this function is used in one place, when
setting up test client used for integration tests.

this commit inlines this logic, and moves the associated `Running` type
alias down alongside the `Run` enum.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-03 14:22:16 -05:00
Oliver Gould 93aecec642
chore(just): add windows os target (#3683)
To support cross-compilation to windows, this change adds an 'os' param to the
justfile, used in the release to cross-build to x86_64-pc-windows-gnu.

This will produce a binary named 'linkerd2-proxy-v2.999.9-x86_64.exe'.

The proxy does not yet compile on windows, so this is a placeholder for now.
2025-03-03 19:07:05 +00:00
katelyn martin 7aa7f069ea
refactor(app/integration): use `linkerd_app_core::Error` (#3685)
`linkerd_app_integration` defines an `Error` alias.

we have a boxed error type in `linkerd_app_core::Error` that achieves
the same purpose, that we can use instead.

this commit replaces this type alias with a reëxport of
`linkerd_app_core::Error`.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-03 14:05:34 -05:00
Oliver Gould 3afd59cac2
fix(ci): remove EmbarkStudios/cargo-deny-action (#3684)
cargo-deny-action is broken: EmbarkStudios/cargo-deny-action#91

This change replaces the action with a manual invocation.
2025-03-03 17:57:56 +00:00
katelyn martin 672727effa
refactor(app/integration): clarify `<SyncSvc as Service<T>>::call()` (#3677)
* refactor(app/integration): use `Result::expect()`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/integration): clarify `<SyncSvc as Service<T>>::call()`

this commit makes some cosmetic changes to
`linkerd_app_integration::tap::SyncSvc`'s implementation of
`tower::Service<T>`.

documentation comments are added to clarify something that makes this
service slightly interesting, and notably different from code suitable
for use in production / real-world contexts.

this service wraps an underlying `Client`, and provides a service
implementation that deals with arbitrary `B`-typed request bodies.
this provides a flexible adapter that simplifies test code.

this service, however, *blocks* the calling thread (off-task) to collect
the body into a cheaply-cloneable `Bytes`.

this commit outlines that logic into an associated function and adds
additional documentation noting this property, and the basis for this
assumption.

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/integration): loosen `SyncSvc` bounds

the bounds placed upon the inbound request's `B`-typed body are overly
restrictive for `<SyncSvc as Service<T>>`. this commit removes some
superfluous bounds, so that only those that are currently needed by this
code are now required.

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-03-03 10:57:49 -05:00
dependabot[bot] 7e52a0acc6
build(deps): bump syn from 2.0.98 to 2.0.99 (#3679)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.98 to 2.0.99.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.98...2.0.99)

---
updated-dependencies:
- dependency-name: syn
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-03 09:04:56 -05:00
dependabot[bot] ae60a095bb
build(deps): bump async-trait from 0.1.86 to 0.1.87 (#3680)
Bumps [async-trait](https://github.com/dtolnay/async-trait) from 0.1.86 to 0.1.87.
- [Release notes](https://github.com/dtolnay/async-trait/releases)
- [Commits](https://github.com/dtolnay/async-trait/compare/0.1.86...0.1.87)

---
updated-dependencies:
- dependency-name: async-trait
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-03 09:04:49 -05:00
dependabot[bot] b230f7b792
build(deps): bump proc-macro2 from 1.0.93 to 1.0.94 (#3681)
Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.93 to 1.0.94.
- [Release notes](https://github.com/dtolnay/proc-macro2/releases)
- [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.93...1.0.94)

---
updated-dependencies:
- dependency-name: proc-macro2
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-03 09:04:41 -05:00
dependabot[bot] 7038e314bb
build(deps): bump anyhow from 1.0.96 to 1.0.97 (#3682)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.96 to 1.0.97.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.96...1.0.97)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-03 09:04:33 -05:00
katelyn martin 6b4ca820c7
refactor(app/outbound): forward-compatible test code (#3676)
see https://github.com/linkerd/linkerd2/issues/8733 for more
information.

see https://github.com/linkerd/linkerd2-proxy/pull/3559 and
https://github.com/linkerd/linkerd2-proxy/pull/3614 for more information
on the `ForwardCompatibleBody<B>` wrapper.

this branch updates test code in `linkerd-app-outbound` related to
timeouts so that it interacts with request and response bodies via an
adapter that polls for frames in a manner consistent with the 1.0 api of
`http_body`.

this allows us to limit the diff in
https://github.com/linkerd/linkerd2-proxy/pull/3504, which will only
need to remove this adapter once using hyper 1.0.

see #3671, #3672, and #3673, which performed the same change for
`linkerd-app-inbound`, other code in `linkerd-app-outbound`, and
`linkerd-app-integration`, respectively.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-02-28 11:01:44 -05:00
katelyn martin 67b4d419cf
refactor(app/integration): forward-compatible test code (#3673)
see https://github.com/linkerd/linkerd2/issues/8733 for more
information.

see https://github.com/linkerd/linkerd2-proxy/pull/3559 and
https://github.com/linkerd/linkerd2-proxy/pull/3614 for more information
on the `ForwardCompatibleBody<B>` wrapper.

this branch updates test code in `linkerd-app-integration` so that it
interacts with request and response bodies via an adapter that polls for
frames in a manner consistent with the 1.0 api of `http_body`.

this allows us to limit the diff in
https://github.com/linkerd/linkerd2-proxy/pull/3504, which will only
need to remove this adapter once using hyper 1.0.

see #3671 and #3672, which perform the same change for
`linkerd-app-inbound` and `linkerd-app-outbound`, respectively.

---

* chore(app/integration): `linkerd-http-body-compat` test dependency

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/integration): generalize `hyper::Body`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/integration): use `ForwardCompatibleBody`

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-02-28 09:34:03 -05:00
katelyn martin f934c8040b
refactor(app/outbound): forward-compatible test code (#3672)
see https://github.com/linkerd/linkerd2/issues/8733 for more
information.

see https://github.com/linkerd/linkerd2-proxy/pull/3559 and
https://github.com/linkerd/linkerd2-proxy/pull/3614 for more information
on the `ForwardCompatibleBody<B>` wrapper.

this branch updates test code in `linkerd-app-outbound` so that it
interacts with request and response bodies via an adapter that polls for
frames in a manner consistent with the 1.0 api of `http_body`.

this allows us to limit the diff in
https://github.com/linkerd/linkerd2-proxy/pull/3504, which will only
need to remove this adapter once using hyper 1.0.

see #3671 and #3673, which perform the same change for
`linkerd-app-inbound` and `linkerd-app-integration`, respectively.

---

* chore(app/outbound): `linkerd-http-body-compat` test dependency

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/outbound): use `Response::into_body()`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/outbound): use `ForwardCompatibleBody`

see https://github.com/linkerd/linkerd2/issues/8733.

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/outbound): use `ForwardCompatibleBody`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/outbound): use `ForwardCompatibleBody`

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/outbound): use `ForwardCompatibleBody`

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-02-28 09:33:55 -05:00
katelyn martin d02c377222
refactor(app/inbound): forward-compatible test code (#3671)
see https://github.com/linkerd/linkerd2/issues/8733 for more
information.

see https://github.com/linkerd/linkerd2-proxy/pull/3559 and
https://github.com/linkerd/linkerd2-proxy/pull/3614 for more information
on the `ForwardCompatibleBody<B>` wrapper.

this branch updates test code in `linkerd-app-inbound` so that it
interacts with request and response bodies via an adapter that polls for
frames in a manner consistent with the 1.0 api of `http_body`.

this allows us to limit the diff in
https://github.com/linkerd/linkerd2-proxy/pull/3504, which will only
need to remove this adapter once using hyper 1.0.

see #3672 and #3673, which perform the same change for
`linkerd-app-outbound` and `linkerd-app-integration`, respectively.

---

* refactor(app/inbound): `linkerd-http-body-compat` test dependency

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor(app/inbound): use `ForwardCompatibleBody`

see https://github.com/linkerd/linkerd2/issues/8733.

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-02-28 09:33:48 -05:00
dependabot[bot] ecbc3ec1fe
build(deps): bump cc from 1.2.15 to 1.2.16 (#3675)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.15 to 1.2.16.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.15...cc-v1.2.16)

---
updated-dependencies:
- dependency-name: cc
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-28 05:24:45 -08:00
dependabot[bot] 2584fcd9a0
build(deps): bump the boring group with 2 updates (#3667)
Bumps the boring group with 2 updates: [boring](https://github.com/cloudflare/boring) and [boring-sys](https://github.com/cloudflare/boring).


Updates `boring` from 4.14.0 to 4.15.0
- [Release notes](https://github.com/cloudflare/boring/releases)
- [Changelog](https://github.com/cloudflare/boring/blob/master/RELEASE_NOTES)
- [Commits](https://github.com/cloudflare/boring/compare/v4.14.0...v4.15.0)

Updates `boring-sys` from 4.14.0 to 4.15.0
- [Release notes](https://github.com/cloudflare/boring/releases)
- [Changelog](https://github.com/cloudflare/boring/blob/master/RELEASE_NOTES)
- [Commits](https://github.com/cloudflare/boring/compare/v4.14.0...v4.15.0)

---
updated-dependencies:
- dependency-name: boring
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: boring
- dependency-name: boring-sys
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: boring
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-27 13:34:13 -05:00
dependabot[bot] d4ab1b774c
build(deps): bump the tracing group with 2 updates (#3669)
Bumps the tracing group with 2 updates: [tracing-subscriber](https://github.com/tokio-rs/tracing) and [tracing-serde](https://github.com/tokio-rs/tracing).


Updates `tracing-subscriber` from 0.3.18 to 0.3.19
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-subscriber-0.3.18...tracing-subscriber-0.3.19)

Updates `tracing-serde` from 0.1.3 to 0.2.0
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-serde-0.1.3...tracing-serde-0.2.0)

---
updated-dependencies:
- dependency-name: tracing-subscriber
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: tracing
- dependency-name: tracing-serde
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: tracing
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-27 13:34:04 -05:00
dependabot[bot] a92a3871cd
build(deps): bump tokio-boring from 4.14.0 to 4.15.0 (#3670)
Bumps [tokio-boring](https://github.com/cloudflare/boring) from 4.14.0 to 4.15.0.
- [Release notes](https://github.com/cloudflare/boring/releases)
- [Changelog](https://github.com/cloudflare/boring/blob/master/RELEASE_NOTES)
- [Commits](https://github.com/cloudflare/boring/compare/v4.14.0...v4.15.0)

---
updated-dependencies:
- dependency-name: tokio-boring
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-27 13:33:54 -05:00
Oliver Gould e4307a61ee
chore(dependabot): group dependency updates (#3666)
This change updates the dependabot configuration to group certain ecosystems of
dependencies, especially rustls.
2025-02-27 10:14:58 -08:00
dependabot[bot] 46db23783d
build(deps): bump zerofrom from 0.1.5 to 0.1.6 (#3665)
Bumps [zerofrom](https://github.com/unicode-org/icu4x) from 0.1.5 to 0.1.6.
- [Release notes](https://github.com/unicode-org/icu4x/releases)
- [Changelog](https://github.com/unicode-org/icu4x/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unicode-org/icu4x/commits)

---
updated-dependencies:
- dependency-name: zerofrom
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-27 17:28:44 +00:00
dependabot[bot] ec6239f6b7
build(deps): bump litemap from 0.7.4 to 0.7.5 (#3664)
Bumps [litemap](https://github.com/unicode-org/icu4x) from 0.7.4 to 0.7.5.
- [Release notes](https://github.com/unicode-org/icu4x/releases)
- [Changelog](https://github.com/unicode-org/icu4x/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unicode-org/icu4x/commits)

---
updated-dependencies:
- dependency-name: litemap
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-27 09:20:28 -08:00
dependabot[bot] f3ba58d2a9
build(deps): bump uuid from 1.15.0 to 1.15.1 (#3663)
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.15.0 to 1.15.1.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.15.0...v1.15.1)

---
updated-dependencies:
- dependency-name: uuid
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-27 09:20:11 -08:00
dependabot[bot] 33fc3e3f0f
build(deps): bump zerofrom-derive from 0.1.5 to 0.1.6 (#3662)
Bumps [zerofrom-derive](https://github.com/unicode-org/icu4x) from 0.1.5 to 0.1.6.
- [Release notes](https://github.com/unicode-org/icu4x/releases)
- [Changelog](https://github.com/unicode-org/icu4x/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unicode-org/icu4x/commits)

---
updated-dependencies:
- dependency-name: zerofrom-derive
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-27 09:18:34 -08:00
dependabot[bot] 3119806c85
build(deps): bump codecov/codecov-action from 5.3.1 to 5.4.0 (#3661)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.3.1 to 5.4.0.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](13ce06bfc6...0565863a31)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-27 09:18:12 -08:00
katelyn martin 5945c92447
chore(app/trace-collector): remove `Default` bound (#3660)
see #3651 and linkerd/linkerd2#8733.

#3651 missed this unused trait bound, which we want to loosen
to account for changes in hyper's api.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-02-26 08:18:00 -08:00
dependabot[bot] 3597b90ce2
build(deps): bump actions/download-artifact from 4.1.8 to 4.1.9 (#3658)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4.1.8 to 4.1.9.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](fa0a91b85d...cc20338598)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-26 10:07:58 -05:00
dependabot[bot] fcb5773b19
build(deps): bump uuid from 1.14.0 to 1.15.0 (#3659)
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.14.0 to 1.15.0.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.14.0...v1.15.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-26 10:07:38 -05:00
katelyn martin 8daafde63b
chore(proxy/identity-client): remove `Default` bounds (#3653)
https://github.com/linkerd/linkerd2/issues/8733 for more information.

see also, https://github.com/linkerd/linkerd2-proxy/pull/3651 for
another related pull request.

in hyper 1.x, `Incoming` bodies do not provide a `Default`
implementation. compare the trait implementations here:

* https://docs.rs/hyper/0.14.31/hyper/body/struct.Body.html#impl-Default-for-Body
* https://docs.rs/hyper/latest/hyper/body/struct.Incoming.html#trait-implementations

this commit removes these bounds from
`linkerd_proxy_identity_client::Certify<C, S>`.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-02-26 10:06:56 -05:00
katelyn martin 9aca7b6894
nit(opencensus): format use statements (#3652)
this commit makes some superficial adjustments to import statements in
`linkerd-opencensus`. we have a convention of using crate-level symbol
groupings in `use` statements. this commit follows that convention.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-02-25 16:02:28 -05:00
katelyn martin 4df3d57c32
chore(service-profiles): remove `Default` bounds (#3657)
see https://github.com/linkerd/linkerd2/issues/8733 for more
information.

see also, #3651 #3653, #3654, and #3655 for some related pull requests.

in hyper 1.x, `Incoming` bodies do not provide a `Default`
implementation. compare the trait implementations here:

* https://docs.rs/hyper/0.14.31/hyper/body/struct.Body.html#impl-Default-for-Body
* https://docs.rs/hyper/latest/hyper/body/struct.Incoming.html#trait-implementations

this commit removes `Default` bounds from `Client<R, S>` used to create
watches on service profiles.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-02-25 16:01:39 -05:00
katelyn martin f054e54bce
chore(proxy/api-resolve): remove `Default` bounds (#3656)
see https://github.com/linkerd/linkerd2/issues/8733 for more information.

see also, #3651 #3653, and #3654 for some related pull requests.

in hyper 1.x, `Incoming` bodies do not provide a `Default`
implementation. compare the trait implementations here:

* https://docs.rs/hyper/0.14.31/hyper/body/struct.Body.html#impl-Default-for-Body
* https://docs.rs/hyper/latest/hyper/body/struct.Incoming.html#trait-implementations

this commit removes `Default` bounds from `Resolve<S>`.

this means that in `linkerd-app`, we can invoke
`new_recover_default()` when using hyper 1.x (_see #3504_)

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-02-25 16:01:28 -05:00
katelyn martin 09a0c0f4eb
chore(app/outbound): remove `Default` bounds (#3655)
see https://github.com/linkerd/linkerd2/issues/8733 for more information.

see also, #3651 #3653, and #3654 for some related pull requests.

in hyper 1.x, `Incoming` bodies do not provide a `Default` implementation. compare the trait implementations here:

* https://docs.rs/hyper/0.14.31/hyper/body/struct.Body.html#impl-Default-for-Body
* https://docs.rs/hyper/latest/hyper/body/struct.Incoming.html#trait-implementations

this commit removes `Default` bounds from policy lookup in the outbound
proxy. this means that in `linkerd-app`, we can invoke
`Outbound::build_policies()` when using hyper 1.x (_see #3504_)

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-02-25 16:01:16 -05:00
katelyn martin 1a12be5eb6
chore(app/inbound): remove `Default` bounds (#3654)
see https://github.com/linkerd/linkerd2/issues/8733 for more information.

see also, #3651 and #3653 for some related pull requests.

in hyper 1.x, `Incoming` bodies do not provide a `Default`
implementation. compare the trait implementations here:

* https://docs.rs/hyper/0.14.31/hyper/body/struct.Body.html#impl-Default-for-Body
* https://docs.rs/hyper/latest/hyper/body/struct.Incoming.html#trait-implementations

this commit removes `Default` bounds from policy lookup in the inbound
proxy.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-02-25 16:00:56 -05:00
katelyn martin 5ee4f711cf
chore(app/trace_collector): remove `Default` bounds (#3651)
see https://github.com/linkerd/linkerd2/issues/8733 for more information.

in hyper 1.x, `Incoming` bodies do not provide a `Default`
implementation. compare the trait implementations here:

* https://docs.rs/hyper/0.14.31/hyper/body/struct.Body.html#impl-Default-for-Body
* https://docs.rs/hyper/latest/hyper/body/struct.Incoming.html#trait-implementations

this commit removes these bounds from the
`linkerd_app::trace_collector::otel_collector::SpanExporter<T, S>` and
other connected functions.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-02-25 16:00:28 -05:00
dependabot[bot] ea8a970c70
build(deps): bump either from 1.13.0 to 1.14.0 (#3649)
Bumps [either](https://github.com/rayon-rs/either) from 1.13.0 to 1.14.0.
- [Commits](https://github.com/rayon-rs/either/compare/1.13.0...1.14.0)

---
updated-dependencies:
- dependency-name: either
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-25 12:01:14 -05:00
dependabot[bot] bb0a1ec57d
build(deps): bump portable-atomic from 1.10.0 to 1.11.0 (#3648)
Bumps [portable-atomic](https://github.com/taiki-e/portable-atomic) from 1.10.0 to 1.11.0.
- [Release notes](https://github.com/taiki-e/portable-atomic/releases)
- [Changelog](https://github.com/taiki-e/portable-atomic/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/portable-atomic/compare/v1.10.0...v1.11.0)

---
updated-dependencies:
- dependency-name: portable-atomic
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-25 12:01:03 -05:00
katelyn martin 8e5d0fdc0c
chore(tls): remove redundant i/o bounds (#3647)
this commit removes a redundant set of trait bounds from
`linkerd_tls::Client<L, C>`'s `tower::Service<T>` implementation.

this client type is generic over a `C`-typed `MakeConnection`. this
trait is effectively an alias for particular services, and already by
definition is prerequisite upon `Connection` responses that are
an asynchronous reader/writer.

see the definition of the trait, here:

```rust
// linkerd/stack/src/connect.rs

pub trait MakeConnection<T> {
    /// An I/O type that represents a connection to the remote endpoint.
    type Connection: AsyncRead + AsyncWrite;

    /// Metadata associated with the established connection.
    type Metadata;

    type Error: Into<Error>;

    type Future: Future<Output = Result<(Self::Connection, Self::Metadata), Self::Error>>;

    /// Determines whether the connector is ready to establish a connection.
    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>;

    /// Establishes a connection.
    fn connect(&mut self, t: T) -> Self::Future;

    // contd...
}
```

thus, we can remove these bounds from the tls client. the connection is
already, by virtue of `C: MakeConnection`, an `AsyncRead + AsyncWrite`
type.

see https://github.com/linkerd/linkerd2/issues/8733.

Signed-off-by: katelyn martin <kate@buoyant.io>
2025-02-24 11:03:23 -05:00
dependabot[bot] 78e6c7a40c
build(deps): bump actions/upload-artifact from 4.6.0 to 4.6.1 (#3646)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.0 to 4.6.1.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](65c4c4a1dd...4cec3d8aa0)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 09:30:06 -05:00
dependabot[bot] d0c10e02d6
build(deps): bump EmbarkStudios/cargo-deny-action from 2.0.5 to 2.0.6 (#3645)
Bumps [EmbarkStudios/cargo-deny-action](https://github.com/embarkstudios/cargo-deny-action) from 2.0.5 to 2.0.6.
- [Release notes](https://github.com/embarkstudios/cargo-deny-action/releases)
- [Commits](13fd9ef18c...0484eedcba)

---
updated-dependencies:
- dependency-name: EmbarkStudios/cargo-deny-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 09:29:53 -05:00
dependabot[bot] f86d5f9e88
build(deps): bump pem from 3.0.4 to 3.0.5 (#3644)
Bumps [pem](https://github.com/jcreekmore/pem-rs) from 3.0.4 to 3.0.5.
- [Changelog](https://github.com/jcreekmore/pem-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jcreekmore/pem-rs/compare/v3.0.4...v3.0.5)

---
updated-dependencies:
- dependency-name: pem
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 09:29:41 -05:00
dependabot[bot] c5c33d580d
build(deps): bump ring from 0.17.9 to 0.17.11 (#3643)
Bumps [ring](https://github.com/ctz/ring) from 0.17.9 to 0.17.11.
- [Release notes](https://github.com/ctz/ring/releases)
- [Commits](https://github.com/ctz/ring/compare/0.17.9...0.17.11)

---
updated-dependencies:
- dependency-name: ring
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 09:29:23 -05:00
dependabot[bot] f24e13c983
build(deps): bump libc from 0.2.169 to 0.2.170 (#3642)
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.169 to 0.2.170.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.170/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.169...0.2.170)

---
updated-dependencies:
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 09:29:11 -05:00
dependabot[bot] a8dea3cd05
build(deps): bump uuid from 1.13.2 to 1.14.0 (#3641)
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.13.2 to 1.14.0.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.13.2...v1.14.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 09:28:59 -05:00
dependabot[bot] 6fd566715b
build(deps): bump flate2 from 1.0.35 to 1.1.0 (#3640)
Bumps [flate2](https://github.com/rust-lang/flate2-rs) from 1.0.35 to 1.1.0.
- [Release notes](https://github.com/rust-lang/flate2-rs/releases)
- [Changelog](https://github.com/rust-lang/flate2-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/flate2-rs/compare/1.0.35...1.1.0)

---
updated-dependencies:
- dependency-name: flate2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 09:28:42 -05:00
Zahari Dichev 46ea686439
chore(transport): Ignore TCP_USER_TIMEOUT on non-Linux systems and warn (#3628)
Signed-off-by: Zahari Dichev <zaharidichev@gmail.com>
2025-02-21 18:40:14 +00:00
Zahari Dichev fc4efc90e5
chore(app): make spire compilation possible for non-linux targets (#3627)
Signed-off-by: Zahari Dichev <zaharidichev@gmail.com>
2025-02-21 08:56:01 -08:00
dependabot[bot] 2656df4be8
build(deps): bump unicode-ident from 1.0.16 to 1.0.17 (#3635)
Bumps [unicode-ident](https://github.com/dtolnay/unicode-ident) from 1.0.16 to 1.0.17.
- [Release notes](https://github.com/dtolnay/unicode-ident/releases)
- [Commits](https://github.com/dtolnay/unicode-ident/compare/1.0.16...1.0.17)

---
updated-dependencies:
- dependency-name: unicode-ident
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-21 10:16:55 -05:00
dependabot[bot] c08124d358
build(deps): bump serde from 1.0.217 to 1.0.218 (#3637)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.217 to 1.0.218.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.217...v1.0.218)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-21 10:16:45 -05:00
dependabot[bot] 6b76a8552a
build(deps): bump log from 0.4.25 to 0.4.26 (#3638)
Bumps [log](https://github.com/rust-lang/log) from 0.4.25 to 0.4.26.
- [Release notes](https://github.com/rust-lang/log/releases)
- [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/log/compare/0.4.25...0.4.26)

---
updated-dependencies:
- dependency-name: log
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-21 10:16:24 -05:00
dependabot[bot] 09e7918133
build(deps): bump cc from 1.2.14 to 1.2.15 (#3639)
Bumps [cc](https://github.com/rust-lang/cc-rs) from 1.2.14 to 1.2.15.
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.14...cc-v1.2.15)

---
updated-dependencies:
- dependency-name: cc
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-21 10:16:11 -05:00
dependabot[bot] e3f6fb7eae
build(deps): bump anyhow from 1.0.95 to 1.0.96 (#3636)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.95 to 1.0.96.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.95...1.0.96)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-21 10:15:22 -05:00
dependabot[bot] 0ca220b37b
build(deps): bump tokio-boring from 4.13.0 to 4.14.0 (#3631)
Bumps [tokio-boring](https://github.com/cloudflare/boring) from 4.13.0 to 4.14.0.
- [Release notes](https://github.com/cloudflare/boring/releases)
- [Changelog](https://github.com/cloudflare/boring/blob/master/RELEASE_NOTES)
- [Commits](https://github.com/cloudflare/boring/compare/v4.13.0...v4.14.0)

---
updated-dependencies:
- dependency-name: tokio-boring
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: katelyn martin <kate@buoyant.io>
2025-02-20 12:24:06 -05:00
dependabot[bot] 733885aed8
build(deps): bump EmbarkStudios/cargo-deny-action from 2.0.4 to 2.0.5 (#3629)
Bumps [EmbarkStudios/cargo-deny-action](https://github.com/embarkstudios/cargo-deny-action) from 2.0.4 to 2.0.5.
- [Release notes](https://github.com/embarkstudios/cargo-deny-action/releases)
- [Commits](e2f4ede4a4...13fd9ef18c)

---
updated-dependencies:
- dependency-name: EmbarkStudios/cargo-deny-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-20 11:29:01 -05:00
dependabot[bot] bfa5d8bd8c
build(deps): bump serde_json from 1.0.138 to 1.0.139 (#3632)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.138 to 1.0.139.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.138...v1.0.139)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-20 11:28:45 -05:00
dependabot[bot] 4d5a9e45f3
build(deps): bump hickory-resolver from 0.24.3 to 0.24.4 (#3630)
Bumps [hickory-resolver](https://github.com/hickory-dns/hickory-dns) from 0.24.3 to 0.24.4.
- [Release notes](https://github.com/hickory-dns/hickory-dns/releases)
- [Changelog](https://github.com/hickory-dns/hickory-dns/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hickory-dns/hickory-dns/compare/v0.24.3...v0.24.4)

---
updated-dependencies:
- dependency-name: hickory-resolver
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-20 11:28:25 -05:00
dependabot[bot] f619f0fc0a
build(deps): bump hickory-proto from 0.24.3 to 0.24.4 (#3634)
Bumps [hickory-proto](https://github.com/hickory-dns/hickory-dns) from 0.24.3 to 0.24.4.
- [Release notes](https://github.com/hickory-dns/hickory-dns/releases)
- [Changelog](https://github.com/hickory-dns/hickory-dns/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hickory-dns/hickory-dns/compare/v0.24.3...v0.24.4)

---
updated-dependencies:
- dependency-name: hickory-proto
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-20 11:28:04 -05:00
dependabot[bot] 25324b6a15
build(deps): bump boring-sys from 4.13.0 to 4.14.0 (#3633)
Bumps [boring-sys](https://github.com/cloudflare/boring) from 4.13.0 to 4.14.0.
- [Release notes](https://github.com/cloudflare/boring/releases)
- [Changelog](https://github.com/cloudflare/boring/blob/master/RELEASE_NOTES)
- [Commits](https://github.com/cloudflare/boring/compare/v4.13.0...v4.14.0)

---
updated-dependencies:
- dependency-name: boring-sys
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-20 11:27:33 -05:00
369 changed files with 8121 additions and 7547 deletions

View File

@ -3,7 +3,7 @@
"build": {
"dockerfile": "Dockerfile",
"args": {
"DEV_VERSION": "v45",
"DEV_VERSION": "v47",
"http_proxy": "${localEnv:http_proxy}",
"https_proxy": "${localEnv:https_proxy}"
}
@ -23,7 +23,15 @@
"zxh404.vscode-proto3"
],
"settings": {
"files.insertFinalNewline": true
"files.insertFinalNewline": true,
"[git-commit]": {
"editor.rulers": [
72,
80
],
"editor.wordWrap": "wordWrapColumn",
"editor.wordWrapColumn": 80
}
}
}
},

156
.github/copilot-instructions.md vendored Normal file
View File

@ -0,0 +1,156 @@
# Linkerd2 Proxy Copilot Instructions
## Code Generation
- Code MUST pass `cargo fmt`.
- Code MUST pass `cargo clippy --all-targets --all-features -- -D warnings`.
- Markdown MUST pass `markdownlint-cli2`.
- Prefer `?` for error propagation.
- Avoid `unwrap()` and `expect()` outside tests.
- Use `tracing` crate macros (`tracing::info!`, etc.) for structured logging.
### Comments
Comments should explain **why**, not **what**. Focus on high-level rationale and
design intent at the function or block level, rather than line-by-line
descriptions.
- Use comments to capture:
- System-facing or interface-level concerns
- Key invariants, preconditions, and postconditions
- Design decisions and trade-offs
- Cross-references to architecture or design documentation
- Avoid:
- Line-by-line commentary explaining obvious code
- Restating what the code already clearly expresses
- For public APIs:
- Use `///` doc comments to describe the contract, behavior, parameters, and
usage examples
- For internal rationale:
- Use `//` comments sparingly to note non-obvious reasoning or edge-case
handling
- Be neutral and factual.
### Rust File Organization
For Rust source files, enforce this layout:
1. **Nonpublic imports**
- Declare all `use` statements for private/internal crates first.
- Group imports to avoid duplicates and do **not** add blank lines between
`use` statements.
2. **Module declarations**
- List all `mod` declarations.
3. **Reexports**
- Follow with `pub use` statements.
4. **Type definitions**
- Define `struct`, `enum`, `type`, and `trait` declarations.
- Sort by visibility: `pub` first, then `pub(crate)`, then private.
- Public types should be documented with `///` comments.
5. **Impl blocks**
- Implement methods in the same order as types above.
- Precede each types `impl` block with a header comment: `// === <TypeName> ===`
6. **Tests**
- End with a `tests` module guarded by `#[cfg(test)]`.
- If the infile test module exceeds 100lines, move it to
`tests/<filename>.rs` as a child integrationtest module.
## Test Generation
- Async tests MUST use `tokio::test`.
- Synchronous tests use `#[test]`.
- Include at least one failingedgecase test per public function.
- Use `tracing::info!` for logging in tests, usually in place of comments.
## Code Review
### Rust
- Point out any `unsafe` blocks and justify their safety.
- Flag functions >50 LOC for refactor suggestions.
- Highlight missing docs on public items.
### Markdown
- Use `markdownlint-cli2` to check for linting errors.
- Lines SHOULD be wrapped at 80 characters.
- Fenced code blocks MUST include a language identifier.
### Copilot Instructions
- Start each instruction with an imperative, presenttense verb.
- Keep each instruction under 120 characters.
- Provide one directive per instruction; avoid combining multiple ideas.
- Use "MUST" and "SHOULD" sparingly to emphasize critical rules.
- Avoid semicolons and complex punctuation within bullets.
- Do not reference external links, documents, or specific coding standards.
## Commit Messages
Commits follow the Conventional Commits specification:
### Subject
Subjects are in the form: `<type>[optional scope]: <description>`
- **Type**: feat, fix, docs, refactor, test, chore, ci, build, perf, revert
(others by agreement)
- **Scope**: optional, lowercase; may include `/` to denote submodules (e.g.
`http/detect`)
- **Description**: imperative mood, present tense, no trailing period
- MUST be less than 72 characters
- Omit needless words!
### Body
Non-trivial commits SHOULD include a body summarizing the change.
- Explain *why* the change was needed.
- Describe *what* was done at a high level.
- Use present-tense narration.
- Use complete sentences, paragraphs, and punctuation.
- Preceded by a blank line.
- Wrapped at 80 characters.
- Omit needless words!
### Breaking changes
If the change introduces a backwards-incompatible change, it MUST be marked as
such.
- Indicated by `!` after the type/scope (e.g. `feat(inbound)!: …`)
- Optionally including a `BREAKING CHANGE:` section in the footer explaining the
change in behavior.
### Examples
```text
feat(auth): add JWT refresh endpoint
There is currently no way to refresh a JWT token.
This exposes a new `/refresh` route that returns a refreshed token.
```
```text
feat(api)!: remove deprecated v1 routes
The `/v1/*` endpoints have been deprecated for a long time and are no
longer called by clients.
This change removes the `/v1/*` endpoints and all associated code,
including integration tests and documentation.
BREAKING CHANGE: The previously-deprecated `/v1/*` endpoints were removed.
```
## Pull Requests
- The subject line MUST be in the conventional commit format.
- Autogenerate a PR body summarizing the problem, solution, and verification steps.
- List breaking changes under a separate **Breaking Changes** heading.

View File

@ -11,12 +11,6 @@ updates:
allow:
- dependency-type: "all"
ignore:
# These dependencies will be updated via higher-level aggregator dependencies like `clap`,
# `futures`, `prost`, `tracing`, and `trust-dns-resolver`:
- dependency-name: "futures-*"
- dependency-name: "prost-derive"
- dependency-name: "tracing-*"
- dependency-name: "trust-dns-proto"
# These dependencies are for platforms that we don't support:
- dependency-name: "hermit-abi"
- dependency-name: "redox_*"
@ -25,9 +19,37 @@ updates:
- dependency-name: "web-sys"
- dependency-name: "windows*"
groups:
boring:
patterns:
- "tokio-boring"
- "boring*"
futures:
patterns:
- "futures*"
grpc:
patterns:
- "prost*"
- "tonic*"
hickory:
patterns:
- "hickory*"
icu4x:
patterns:
- "icu_*"
opentelemetry:
patterns:
- "opentelemetry*"
rustls:
patterns:
- "tokio-rustls"
- "rustls*"
- "ring"
symbolic:
patterns:
- "symbolic-*"
tracing:
patterns:
- "tracing*"
- package-ecosystem: cargo
directory: /linkerd/addr/fuzz

View File

@ -22,13 +22,13 @@ permissions:
jobs:
build:
runs-on: ubuntu-24.04
container: ghcr.io/linkerd/dev:v45-rust
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
container: ghcr.io/linkerd/dev:v47-rust
timeout-minutes: 20
continue-on-error: true
steps:
- run: rustup toolchain install --profile=minimal beta
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- run: git config --global --add safe.directory "$PWD" # actions/runner#2033
- run: just toolchain=beta fetch
- run: just toolchain=beta build

View File

@ -21,11 +21,11 @@ env:
jobs:
meta:
timeout-minutes: 5
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- id: changed
uses: tj-actions/changed-files@dcc7a0cba800f454d79fff4b993e8c3555bcc0a8
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c
with:
files: |
.codecov.yml
@ -40,19 +40,19 @@ jobs:
codecov:
needs: meta
if: (github.event_name == 'push' && github.ref == 'refs/heads/main') || needs.meta.outputs.any_changed == 'true'
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
timeout-minutes: 30
container:
image: docker://ghcr.io/linkerd/dev:v45-rust
image: docker://ghcr.io/linkerd/dev:v47-rust
options: --security-opt seccomp=unconfined # 🤷
env:
CXX: "/usr/bin/clang++-19"
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: Swatinem/rust-cache@f0deed1e0edfc6a9be95417288c0e1099b1eeec3
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0
- run: cargo tarpaulin --locked --workspace --exclude=linkerd2-proxy --exclude=linkerd-transport-header --exclude=opencensus-proto --exclude=spire-proto --no-run
- run: cargo tarpaulin --locked --workspace --exclude=linkerd2-proxy --exclude=linkerd-transport-header --exclude=opencensus-proto --exclude=spire-proto --skip-clean --ignore-tests --no-fail-fast --out=Xml
# Some tests are especially flakey in coverage tests. That's fine. We
# only really care to measure how much of our codebase is covered.
continue-on-error: true
- uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3
- uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24

View File

@ -26,13 +26,13 @@ permissions:
jobs:
list-changed:
timeout-minutes: 3
runs-on: ubuntu-24.04
container: docker://rust:1.83.0
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
container: docker://rust:1.88.0
steps:
- run: apt update && apt install -y jo
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- run: git config --global --add safe.directory "$PWD" # actions/runner#2033
- uses: tj-actions/changed-files@dcc7a0cba800f454d79fff4b993e8c3555bcc0a8
- uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c
id: changed-files
- name: list changed crates
id: list-changed
@ -47,15 +47,15 @@ jobs:
build:
needs: [list-changed]
timeout-minutes: 40
runs-on: ubuntu-24.04
container: docker://rust:1.83.0
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
container: docker://rust:1.88.0
strategy:
matrix:
dir: ${{ fromJson(needs.list-changed.outputs.dirs) }}
steps:
- run: rustup toolchain add nightly
- run: cargo install cargo-fuzz
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- run: git config --global --add safe.directory "$PWD" # actions/runner#2033
- working-directory: ${{matrix.dir}}
run: cargo +nightly fetch

View File

@ -12,9 +12,9 @@ on:
jobs:
markdownlint:
timeout-minutes: 5
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: DavidAnson/markdownlint-cli2-action@05f32210e84442804257b2a6f20b273450ec8265
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- uses: DavidAnson/markdownlint-cli2-action@992badcdf24e3b8eb7e87ff9287fe931bcb00c6e
with:
globs: "**/*.md"

View File

@ -22,13 +22,13 @@ permissions:
jobs:
build:
runs-on: ubuntu-24.04
container: ghcr.io/linkerd/dev:v45-rust
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
container: ghcr.io/linkerd/dev:v47-rust
timeout-minutes: 20
continue-on-error: true
steps:
- run: rustup toolchain install --profile=minimal nightly
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- run: git config --global --add safe.directory "$PWD" # actions/runner#2033
- run: just toolchain=nightly fetch
- run: just toolchain=nightly profile=release build

View File

@ -14,24 +14,24 @@ concurrency:
jobs:
meta:
timeout-minutes: 5
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- id: build
uses: tj-actions/changed-files@dcc7a0cba800f454d79fff4b993e8c3555bcc0a8
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c
with:
files: |
.github/workflows/pr.yml
justfile
Dockerfile
- id: actions
uses: tj-actions/changed-files@dcc7a0cba800f454d79fff4b993e8c3555bcc0a8
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c
with:
files: |
.github/workflows/**
.devcontainer/*
- id: cargo
uses: tj-actions/changed-files@dcc7a0cba800f454d79fff4b993e8c3555bcc0a8
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c
with:
files_ignore: "Cargo.toml"
files: |
@ -40,7 +40,7 @@ jobs:
if: steps.cargo.outputs.any_changed == 'true'
run: ./.github/list-crates.sh ${{ steps.cargo.outputs.all_changed_files }}
- id: rust
uses: tj-actions/changed-files@dcc7a0cba800f454d79fff4b993e8c3555bcc0a8
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c
with:
files: |
**/*.rs
@ -57,7 +57,7 @@ jobs:
info:
timeout-minutes: 3
needs: meta
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
steps:
- name: Info
run: |
@ -74,30 +74,27 @@ jobs:
actions:
needs: meta
if: needs.meta.outputs.actions_changed == 'true'
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
steps:
- uses: linkerd/dev/actions/setup-tools@v45
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: linkerd/dev/actions/setup-tools@v47
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- run: just action-lint
- run: just action-dev-check
rust:
needs: meta
if: needs.meta.outputs.cargo_changed == 'true' || needs.meta.outputs.rust_changed == 'true'
runs-on: ubuntu-24.04
container: ghcr.io/linkerd/dev:v45-rust
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
container: ghcr.io/linkerd/dev:v47-rust
permissions:
contents: read
timeout-minutes: 20
steps:
- run: git config --global --add safe.directory "$PWD" # actions/runner#2033
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: Swatinem/rust-cache@f0deed1e0edfc6a9be95417288c0e1099b1eeec3
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0
- run: just fetch
- name: Run cargo deny check bans licenses sources
uses: EmbarkStudios/cargo-deny-action@e2f4ede4a4e60ea15ff31bc0647485d80c66cfba
with:
command: check bans licenses sources
- run: cargo deny --all-features check bans licenses sources
- run: just check-fmt
- run: just clippy
- run: just doc
@ -110,15 +107,15 @@ jobs:
needs: meta
if: needs.meta.outputs.cargo_changed == 'true'
timeout-minutes: 20
runs-on: ubuntu-24.04
container: ghcr.io/linkerd/dev:v45-rust
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
container: ghcr.io/linkerd/dev:v47-rust
strategy:
matrix:
crate: ${{ fromJson(needs.meta.outputs.cargo_crates) }}
steps:
- run: git config --global --add safe.directory "$PWD" # actions/runner#2033
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: Swatinem/rust-cache@f0deed1e0edfc6a9be95417288c0e1099b1eeec3
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0
- run: just fetch
- run: just check-crate ${{ matrix.crate }}
@ -126,11 +123,11 @@ jobs:
needs: meta
if: needs.meta.outputs.cargo_changed == 'true' || needs.meta.outputs.rust_changed == 'true'
timeout-minutes: 20
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
env:
WAIT_TIMEOUT: 2m
steps:
- uses: linkerd/dev/actions/setup-tools@v45
- uses: linkerd/dev/actions/setup-tools@v47
- name: scurl https://run.linkerd.io/install-edge | sh
run: |
scurl https://run.linkerd.io/install-edge | sh
@ -139,9 +136,9 @@ jobs:
tag=$(linkerd version --client --short)
echo "linkerd $tag"
echo "LINKERD_TAG=$tag" >> "$GITHUB_ENV"
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- run: just docker
- run: just-k3d create
- run: just k3d-create
- run: just k3d-load-linkerd
- run: just linkerd-install
- run: just linkerd-check-control-plane-proxy
@ -152,7 +149,7 @@ jobs:
timeout-minutes: 3
needs: [meta, actions, rust, rust-crates, linkerd-install]
if: always()
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
permissions:
contents: write
@ -171,7 +168,7 @@ jobs:
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
run: exit 1
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
if: needs.meta.outputs.is_dependabot == 'true' && needs.meta.outputs.any_changed == 'true'
- name: "Merge dependabot changes"
if: needs.meta.outputs.is_dependabot == 'true' && needs.meta.outputs.any_changed == 'true'

View File

@ -13,7 +13,7 @@ concurrency:
jobs:
last-release:
if: github.repository == 'linkerd/linkerd2-proxy' # Don't run this in forks.
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
timeout-minutes: 5
env:
GH_REPO: ${{ github.repository }}
@ -41,10 +41,10 @@ jobs:
last-commit:
needs: last-release
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
timeout-minutes: 5
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Check if the most recent commit is after the last release
id: recency
env:
@ -62,7 +62,7 @@ jobs:
trigger-release:
needs: [last-release, last-commit]
if: needs.last-release.outputs.recent == 'false' && needs.last-commit.outputs.after-release == 'true'
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
timeout-minutes: 5
permissions:
actions: write

View File

@ -46,6 +46,7 @@ on:
default: true
env:
CARGO: "cargo auditable"
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
RUSTFLAGS: "-D warnings -A deprecated --cfg tokio_unstable"
@ -58,9 +59,25 @@ concurrency:
jobs:
meta:
timeout-minutes: 5
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
steps:
- id: meta
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
if: github.event_name == 'pull_request'
- id: workflow
if: github.event_name == 'pull_request'
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c
with:
files: |
.github/workflows/release.yml
- id: build
if: github.event_name == 'pull_request'
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c
with:
files: |
justfile
Cargo.toml
- id: version
env:
VERSION: ${{ inputs.version }}
shell: bash
@ -68,44 +85,45 @@ jobs:
set -euo pipefail
shopt -s extglob
if [[ "$GITHUB_EVENT_NAME" == pull_request ]]; then
echo version="0.0.0-test.${GITHUB_SHA:0:7}"
echo archs='["amd64"]'
echo version="0.0.0-test.${GITHUB_SHA:0:7}" >> "$GITHUB_OUTPUT"
exit 0
fi >> "$GITHUB_OUTPUT"
fi
if ! [[ "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z-]+)?(\+[0-9A-Za-z-]+)?$ ]]; then
echo "Invalid version: $VERSION" >&2
exit 1
fi
( echo version="${VERSION#v}"
echo archs='["amd64", "arm64", "arm"]'
echo version="${VERSION#v}" >> "$GITHUB_OUTPUT"
- id: platform
shell: bash
env:
WORKFLOW_CHANGED: ${{ steps.workflow.outputs.any_changed }}
run: |
if [[ "$GITHUB_EVENT_NAME" == pull_request && "$WORKFLOW_CHANGED" != 'true' ]]; then
( echo archs='["amd64"]'
echo oses='["linux"]' ) >> "$GITHUB_OUTPUT"
exit 0
fi
( echo archs='["amd64", "arm64"]'
echo oses='["linux", "windows"]'
) >> "$GITHUB_OUTPUT"
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
if: github.event_name == 'pull_request'
- id: changed
if: github.event_name == 'pull_request'
uses: tj-actions/changed-files@dcc7a0cba800f454d79fff4b993e8c3555bcc0a8
with:
files: |
.github/workflows/release.yml
justfile
Cargo.toml
outputs:
archs: ${{ steps.meta.outputs.archs }}
version: ${{ steps.meta.outputs.version }}
package: ${{ github.event_name == 'workflow_dispatch' || steps.changed.outputs.any_changed == 'true' }}
archs: ${{ steps.platform.outputs.archs }}
oses: ${{ steps.platform.outputs.oses }}
version: ${{ steps.version.outputs.version }}
package: ${{ github.event_name == 'workflow_dispatch' || steps.build.outputs.any_changed == 'true' || steps.workflow.outputs.any_changed == 'true' }}
profile: ${{ inputs.profile || 'release' }}
publish: ${{ inputs.publish }}
ref: ${{ inputs.ref || github.sha }}
tag: "${{ inputs.tag-prefix || 'release/' }}v${{ steps.meta.outputs.version }}"
tag: "${{ inputs.tag-prefix || 'release/' }}v${{ steps.version.outputs.version }}"
prerelease: ${{ inputs.prerelease }}
draft: ${{ inputs.draft }}
latest: ${{ inputs.latest }}
info:
needs: meta
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
timeout-minutes: 3
steps:
- name: Inputs
@ -126,38 +144,50 @@ jobs:
strategy:
matrix:
arch: ${{ fromJson(needs.meta.outputs.archs) }}
os: ${{ fromJson(needs.meta.outputs.oses) }}
libc: [gnu] # musl
exclude:
- os: windows
arch: arm64
# If we're not actually building on a release tag, don't short-circuit on
# errors. This helps us know whether a failure is platform-specific.
continue-on-error: ${{ needs.meta.outputs.publish != 'true' }}
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
timeout-minutes: 40
container: docker://ghcr.io/linkerd/dev:v45-rust-musl
container: docker://ghcr.io/linkerd/dev:v47-rust-musl
env:
LINKERD2_PROXY_VENDOR: ${{ github.repository_owner }}
LINKERD2_PROXY_VERSION: ${{ needs.meta.outputs.version }}
steps:
# TODO: add to dev image
- name: Install MiniGW
if: matrix.os == 'windows'
run: apt-get update && apt-get install -y mingw-w64
- name: Install cross compilation toolchain
if: matrix.arch == 'arm64'
run: apt-get update && apt-get install -y binutils-aarch64-linux-gnu
- name: Configure git
run: git config --global --add safe.directory "$PWD" # actions/runner#2033
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
with:
ref: ${{ needs.meta.outputs.ref }}
- uses: Swatinem/rust-cache@f0deed1e0edfc6a9be95417288c0e1099b1eeec3
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0
with:
key: ${{ matrix.arch }}
key: ${{ matrix.os }}-${{ matrix.arch }}
- run: just fetch
- run: just arch=${{ matrix.arch }} libc=${{ matrix.libc }} rustup
- run: just arch=${{ matrix.arch }} libc=${{ matrix.libc }} profile=${{ needs.meta.outputs.profile }} build
- run: just arch=${{ matrix.arch }} libc=${{ matrix.libc }} profile=${{ needs.meta.outputs.profile }} package
- uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08
- run: just arch=${{ matrix.arch }} libc=${{ matrix.libc }} os=${{ matrix.os }} rustup
- run: just arch=${{ matrix.arch }} libc=${{ matrix.libc }} os=${{ matrix.os }} profile=${{ needs.meta.outputs.profile }} build
- run: just arch=${{ matrix.arch }} libc=${{ matrix.libc }} os=${{ matrix.os }} profile=${{ needs.meta.outputs.profile }} package
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: ${{ matrix.arch }}-artifacts
name: ${{ matrix.arch }}-${{ matrix.os }}-artifacts
path: target/package/*
publish:
needs: [meta, package]
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
timeout-minutes: 5
permissions:
actions: write
@ -174,13 +204,13 @@ jobs:
git config --global user.name "$GITHUB_USERNAME"
git config --global user.email "$GITHUB_USERNAME"@users.noreply.github.com
# Tag the release.
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
with:
token: ${{ secrets.LINKERD2_PROXY_GITHUB_TOKEN || github.token }}
ref: ${{ needs.meta.outputs.ref }}
- run: git tag -a -m "$VERSION" "$TAG"
# Fetch the artifacts.
- uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
path: artifacts
- run: du -h artifacts/**/*
@ -188,7 +218,7 @@ jobs:
- if: needs.meta.outputs.publish == 'true'
run: git push origin "$TAG"
- if: needs.meta.outputs.publish == 'true'
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8
with:
name: ${{ env.VERSION }}
tag_name: ${{ env.TAG }}
@ -212,7 +242,7 @@ jobs:
needs: publish
if: always()
timeout-minutes: 3
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
steps:
- name: Results
run: |

View File

@ -13,8 +13,8 @@ on:
jobs:
sh-lint:
timeout-minutes: 5
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
steps:
- uses: linkerd/dev/actions/setup-tools@v45
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: linkerd/dev/actions/setup-tools@v47
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- run: just sh-lint

View File

@ -13,10 +13,10 @@ permissions:
jobs:
devcontainer:
runs-on: ubuntu-24.04
container: ghcr.io/linkerd/dev:v45-rust
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
container: ghcr.io/linkerd/dev:v47-rust
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- run: git config --global --add safe.directory "$PWD" # actions/runner#2033
- run: |
VERSION_REGEX='channel = "([0-9]+\.[0-9]+\.[0-9]+)"'
@ -35,10 +35,10 @@ jobs:
workflows:
runs-on: ubuntu-24.04
runs-on: ${{ vars.LINKERD2_PROXY_RUNNER || 'ubuntu-24.04' }}
steps:
- uses: linkerd/dev/actions/setup-tools@v45
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: linkerd/dev/actions/setup-tools@v47
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- shell: bash
run: |
VERSION_REGEX='channel = "([0-9]+\.[0-9]+\.[0-9]+)"'

1847
Cargo.lock

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,6 @@ members = [
"linkerd/app",
"linkerd/conditional",
"linkerd/distribute",
"linkerd/detect",
"linkerd/dns/name",
"linkerd/dns",
"linkerd/duplex",
@ -25,10 +24,9 @@ members = [
"linkerd/error-respond",
"linkerd/exp-backoff",
"linkerd/http/access-log",
"linkerd/http/body-compat",
"linkerd/http/box",
"linkerd/http/classify",
"linkerd/http/executor",
"linkerd/http/detect",
"linkerd/http/h2",
"linkerd/http/insert",
"linkerd/http/metrics",
@ -44,8 +42,6 @@ members = [
"linkerd/idle-cache",
"linkerd/io",
"linkerd/meshtls",
"linkerd/meshtls/boring",
"linkerd/meshtls/rustls",
"linkerd/meshtls/verifier",
"linkerd/metrics",
"linkerd/mock/http-body",
@ -73,12 +69,12 @@ members = [
"linkerd/reconnect",
"linkerd/retry",
"linkerd/router",
"linkerd/rustls",
"linkerd/service-profiles",
"linkerd/signal",
"linkerd/stack",
"linkerd/stack/metrics",
"linkerd/stack/tracing",
"linkerd/system",
"linkerd/tonic-stream",
"linkerd/tonic-watch",
"linkerd/tls",
@ -87,6 +83,7 @@ members = [
"linkerd/tracing",
"linkerd/transport-header",
"linkerd/transport-metrics",
"linkerd/workers",
"linkerd2-proxy",
"opencensus-proto",
"opentelemetry-proto",
@ -98,22 +95,43 @@ members = [
debug = 1
lto = true
[workspace.package]
version = "0.1.0"
authors = ["Linkerd Developers <cncf-linkerd-dev@lists.cncf.io>"]
license = "Apache-2.0"
edition = "2021"
publish = false
[workspace.dependencies]
bytes = { version = "1" }
h2 = { version = "0.3" }
http = { version = "0.2" }
http-body = { version = "0.4" }
hyper = { version = "0.14.32", default-features = false }
prost = { version = "0.12" }
prost-types = { version = "0.12" }
drain = { version = "0.2", default-features = false }
h2 = { version = "0.4" }
http = { version = "1" }
http-body = { version = "1" }
hyper = { version = "1", default-features = false }
prometheus-client = { version = "0.23" }
prost = { version = "0.13" }
prost-build = { version = "0.13", default-features = false }
prost-types = { version = "0.13" }
tokio-rustls = { version = "0.26", default-features = false, features = [
"ring",
"logging",
] }
tonic = { version = "0.10", default-features = false }
tonic-build = { version = "0.10", default-features = false }
tonic = { version = "0.13", default-features = false }
tonic-build = { version = "0.13", default-features = false }
tower = { version = "0.5", default-features = false }
tower-service = { version = "0.3" }
tower-test = { version = "0.4" }
tracing = { version = "0.1" }
[workspace.dependencies.http-body-util]
version = "0.1.3"
default-features = false
features = ["channel"]
[workspace.dependencies.hyper-util]
version = "0.1"
default-features = false
features = ["tokio", "tracing"]
[workspace.dependencies.linkerd2-proxy-api]
version = "0.15.0"
# git = "https://github.com/linkerd/linkerd2-proxy-api.git"
# branch = "main"
version = "0.17.0"

View File

@ -3,7 +3,7 @@
# This is intended **DEVELOPMENT ONLY**, i.e. so that proxy developers can
# easily test the proxy in the context of the larger `linkerd2` project.
ARG RUST_IMAGE=ghcr.io/linkerd/dev:v45-rust
ARG RUST_IMAGE=ghcr.io/linkerd/dev:v47-rust
# Use an arbitrary ~recent edge release image to get the proxy
# identity-initializing and linkerd-await wrappers.
@ -14,11 +14,16 @@ FROM $LINKERD2_IMAGE as linkerd2
FROM --platform=$BUILDPLATFORM $RUST_IMAGE as fetch
ARG PROXY_FEATURES=""
ARG TARGETARCH="amd64"
RUN apt-get update && \
apt-get install -y time && \
if [[ "$PROXY_FEATURES" =~ .*meshtls-boring.* ]] ; then \
apt-get install -y golang ; \
fi && \
case "$TARGETARCH" in \
amd64) true ;; \
arm64) apt-get install --no-install-recommends -y binutils-aarch64-linux-gnu ;; \
esac && \
rm -rf /var/lib/apt/lists/*
ENV CARGO_NET_RETRY=10
@ -33,7 +38,6 @@ RUN --mount=type=cache,id=cargo,target=/usr/local/cargo/registry \
FROM fetch as build
ENV CARGO_INCREMENTAL=0
ENV RUSTFLAGS="-D warnings -A deprecated --cfg tokio_unstable"
ARG TARGETARCH="amd64"
ARG PROFILE="release"
ARG LINKERD2_PROXY_VERSION=""
ARG LINKERD2_PROXY_VENDOR=""

View File

@ -86,8 +86,9 @@ minutes to review our [code of conduct][coc].
We test our code by way of fuzzing and this is described in [FUZZING.md](/docs/FUZZING.md).
A third party security audit focused on fuzzing Linkerd2-proxy was performed by
Ada Logics in 2021. The full report is available
[here](/docs/reports/linkerd2-proxy-fuzzing-report.pdf).
Ada Logics in 2021. The
[full report](/docs/reports/linkerd2-proxy-fuzzing-report.pdf) can be found in
the `docs/reports/` directory.
## License

View File

@ -2,7 +2,6 @@
targets = [
{ triple = "x86_64-unknown-linux-gnu" },
{ triple = "aarch64-unknown-linux-gnu" },
{ triple = "armv7-unknown-linux-gnu" },
]
[advisories]
@ -18,27 +17,20 @@ allow = [
"ISC",
"MIT",
"Unicode-3.0",
"Zlib",
]
# Ignore local workspace license values for unpublished crates.
private = { ignore = true }
confidence-threshold = 0.8
exceptions = [
{ allow = [
"Zlib",
], name = "adler32", version = "*" },
"ISC",
"OpenSSL",
], name = "aws-lc-sys", version = "*" },
{ allow = [
"ISC",
"MIT",
"OpenSSL",
], name = "ring", version = "*" },
]
[[licenses.clarify]]
name = "ring"
version = "*"
expression = "MIT AND ISC AND OpenSSL"
license-files = [
{ path = "LICENSE", hash = 0xbd0eed23 },
], name = "aws-lc-fips-sys", version = "*" },
]
[bans]
@ -50,28 +42,35 @@ deny = [
{ name = "rustls", wrappers = ["tokio-rustls"] },
# rustls-webpki should be used instead.
{ name = "webpki" },
# aws-lc-rs should be used instead.
{ name = "ring" }
]
skip = [
# `linkerd-trace-context`, `rustls-pemfile` and `tonic` depend on `base64`
# v0.13.1 while `rcgen` depends on v0.21.5
{ name = "base64" },
{ name = "bitflags", version = "1" },
# https://github.com/hawkw/matchers/pull/4
{ name = "regex-automata", version = "0.1" },
{ name = "regex-syntax", version = "0.6" },
# Some dependencies still use indexmap v1.
{ name = "indexmap", version = "1" },
{ name = "hashbrown", version = "0.12" },
# tonic/axum depend on a newer `tower`, which we are still catching up to.
# see #3744.
{ name = "tower", version = "0.5" },
]
skip-tree = [
# thiserror v2 is still propagating through the ecosystem
{ name = "thiserror", version = "1" },
# rand 0.9 is still propagating through the ecosystem
# rand v0.9 is still propagating through the ecosystem
{ name = "rand", version = "0.8" },
# rust v1.0 is still propagating through the ecosystem
{ name = "rustix", version = "0.38" },
# `pprof` uses a number of old dependencies. for now, we skip its subtree.
{ name = "pprof" },
# aws-lc-rs uses a slightly outdated version of bindgen
{ name = "bindgen", version = "0.69.5" },
# socket v0.6 is still propagating through the ecosystem
{ name = "socket2", version = "0.5" },
]
[sources]
unknown-registry = "deny"
unknown-git = "deny"
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
allow-registry = [
"https://github.com/rust-lang/crates.io-index",
]

View File

@ -12,9 +12,12 @@ engine.
We place the fuzz tests into folders within the individual crates that the fuzz
tests target. For example, we have a fuzz test that that target the crate
`/linkerd/addr` and the code in `/linkerd/addr/src` and thus the fuzz test that
targets this crate is put in `/linkerd/addr/fuzz`. The folder set up we use for
each of the fuzz tests is automatically generated by `cargo fuzz init`
(described [here](https://github.com/rust-fuzz/cargo-fuzz#cargo-fuzz-init)).
targets this crate is put in `/linkerd/addr/fuzz`.
The folder structure for each of the fuzz tests is automatically generated by
`cargo fuzz init`. See cargo fuzz's
[`README.md`](https://github.com/rust-fuzz/cargo-fuzz#cargo-fuzz-init) for more
information.
### Fuzz targets
@ -96,6 +99,5 @@ unit-test-like fuzzers, but are essentially just more substantial in nature. The
idea behind these fuzzers is to test end-to-end concepts more so than individual
components of the proxy.
The inbound fuzzer
[here](/linkerd/app/inbound/fuzz/fuzz_targets/fuzz_target_1.rs) is an example of
this.
The [inbound fuzzer](/linkerd/app/inbound/fuzz/fuzz_targets/fuzz_target_1.rs)
is an example of this.

View File

@ -1,18 +1,18 @@
[package]
name = "hyper-balance"
version = "0.1.0"
authors = ["Linkerd Developers <cncf-linkerd-dev@lists.cncf.io>"]
license = "Apache-2.0"
edition = "2021"
publish = false
version = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
edition = { workspace = true }
publish = { workspace = true }
[dependencies]
futures = { version = "0.3", default-features = false }
http = { workspace = true }
http-body = { workspace = true }
hyper = { workspace = true, features = ["deprecated"] }
hyper = { workspace = true }
pin-project = "1"
tower = { version = "0.4", default-features = false, features = ["load"] }
tower = { workspace = true, default-features = false, features = ["load"] }
tokio = { version = "1", features = ["macros"] }
[dev-dependencies]

View File

@ -102,32 +102,20 @@ where
self.body.is_end_stream()
}
fn poll_data(
fn poll_frame(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
let this = self.project();
let ret = futures::ready!(this.body.poll_data(cx));
let ret = futures::ready!(this.body.poll_frame(cx));
// Once a data frame is received, the handle is dropped. On subsequent calls, this
// Once a frame is received, the handle is dropped. On subsequent calls, this
// is a noop.
drop(this.handle.take());
Poll::Ready(ret)
}
fn poll_trailers(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
let this = self.project();
// If this is being called, the handle definitely should have been dropped
// already.
drop(this.handle.take());
this.body.poll_trailers(cx)
}
#[inline]
fn size_hint(&self) -> hyper::body::SizeHint {
self.body.size_hint()
@ -157,35 +145,21 @@ impl<T: Send + 'static, B: Body> Body for PendingUntilEosBody<T, B> {
self.body.is_end_stream()
}
fn poll_data(
fn poll_frame(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
let mut this = self.project();
let body = &mut this.body;
tokio::pin!(body);
let ret = futures::ready!(body.poll_data(cx));
let frame = futures::ready!(body.poll_frame(cx));
// If this was the last frame, then drop the handle immediately.
if this.body.is_end_stream() {
drop(this.handle.take());
}
Poll::Ready(ret)
}
fn poll_trailers(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
let this = self.project();
let ret = futures::ready!(this.body.poll_trailers(cx));
// Once trailers are received, the handle is dropped immediately (in case the body
// is retained longer for some reason).
drop(this.handle.take());
Poll::Ready(ret)
Poll::Ready(frame)
}
#[inline]
@ -198,7 +172,7 @@ impl<T: Send + 'static, B: Body> Body for PendingUntilEosBody<T, B> {
mod tests {
use super::{PendingUntilEos, PendingUntilFirstData};
use futures::future::poll_fn;
use http_body::Body;
use http_body::{Body, Frame};
use std::collections::VecDeque;
use std::io::Cursor;
use std::pin::Pin;
@ -225,11 +199,13 @@ mod tests {
assert_ready!(task::spawn(poll_fn(|cx| {
let body = &mut body;
tokio::pin!(body);
body.poll_data(cx)
body.poll_frame(cx)
}))
.poll())
.expect("data some")
.expect("data ok");
.expect("frame is some")
.expect("frame is ok")
.into_data()
.expect("frame is data");
assert!(wk.upgrade().is_none());
}
@ -282,10 +258,10 @@ mod tests {
let res = assert_ready!(task::spawn(poll_fn(|cx| {
let body = &mut body;
tokio::pin!(body);
body.poll_data(cx)
body.poll_frame(cx)
}))
.poll());
assert!(res.expect("data is some").is_err());
assert!(res.expect("frame is some").is_err());
assert!(wk.upgrade().is_none());
}
@ -308,21 +284,21 @@ mod tests {
assert_ready!(task::spawn(poll_fn(|cx| {
let body = &mut body;
tokio::pin!(body);
body.poll_data(cx)
body.poll_frame(cx)
}))
.poll())
.expect("data some")
.expect("data ok");
.expect("frame is some")
.expect("frame is ok");
assert!(wk.upgrade().is_some());
assert_ready!(task::spawn(poll_fn(|cx| {
let body = &mut body;
tokio::pin!(body);
body.poll_data(cx)
body.poll_frame(cx)
}))
.poll())
.expect("data some")
.expect("data ok");
.expect("frame is some")
.expect("frame is ok");
assert!(wk.upgrade().is_none());
}
@ -355,40 +331,42 @@ mod tests {
assert_ready!(task::spawn(poll_fn(|cx| {
let body = &mut body;
tokio::pin!(body);
body.poll_data(cx)
body.poll_frame(cx)
}))
.poll())
.expect("data")
.expect("data ok");
.expect("frame is some")
.expect("frame is ok");
assert!(wk.upgrade().is_some());
assert_ready!(task::spawn(poll_fn(|cx| {
let body = &mut body;
tokio::pin!(body);
body.poll_data(cx)
body.poll_frame(cx)
}))
.poll())
.expect("data")
.expect("data ok");
.expect("frame is some")
.expect("frame is ok");
assert!(wk.upgrade().is_some());
assert_ready!(task::spawn(poll_fn(|cx| {
let body = &mut body;
tokio::pin!(body);
body.poll_frame(cx)
}))
.poll())
.expect("frame is some")
.expect("frame is ok")
.into_trailers()
.expect("is trailers");
assert!(wk.upgrade().is_none());
let poll = assert_ready!(task::spawn(poll_fn(|cx| {
let body = &mut body;
tokio::pin!(body);
body.poll_data(cx)
body.poll_frame(cx)
}))
.poll());
assert!(poll.is_none());
assert!(wk.upgrade().is_some());
assert_ready!(task::spawn(poll_fn(|cx| {
let body = &mut body;
tokio::pin!(body);
body.poll_trailers(cx)
}))
.poll())
.expect("trailers ok")
.expect("trailers");
assert!(wk.upgrade().is_none());
}
@ -411,7 +389,7 @@ mod tests {
let poll = assert_ready!(task::spawn(poll_fn(|cx| {
let body = &mut body;
tokio::pin!(body);
body.poll_data(cx)
body.poll_frame(cx)
}))
.poll());
assert!(poll.expect("some").is_err());
@ -437,20 +415,21 @@ mod tests {
self.0.is_empty() & self.1.is_none()
}
fn poll_data(
fn poll_frame(
mut self: Pin<&mut Self>,
_: &mut Context<'_>,
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
Poll::Ready(self.as_mut().0.pop_front().map(Cursor::new).map(Ok))
}
fn poll_trailers(
mut self: Pin<&mut Self>,
_: &mut Context<'_>,
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
let mut this = self.as_mut();
assert!(this.0.is_empty());
Poll::Ready(Ok(this.1.take()))
// Return the next data frame from the sequence of chunks.
if let Some(chunk) = this.0.pop_front() {
let frame = Some(Ok(Frame::data(Cursor::new(chunk))));
return Poll::Ready(frame);
}
// Yield the trailers once all data frames have been yielded.
let trailers = this.1.take().map(Frame::<Self::Data>::trailers).map(Ok);
Poll::Ready(trailers)
}
}
@ -464,18 +443,13 @@ mod tests {
self.0.is_none()
}
fn poll_data(
fn poll_frame(
mut self: Pin<&mut Self>,
_: &mut Context<'_>,
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
Poll::Ready(Some(Err(self.as_mut().0.take().expect("err"))))
}
) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
let err = self.as_mut().0.take().expect("err");
fn poll_trailers(
mut self: Pin<&mut Self>,
_: &mut Context<'_>,
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
Poll::Ready(Err(self.as_mut().0.take().expect("err")))
Poll::Ready(Some(Err(err)))
}
}
}

View File

@ -15,9 +15,13 @@ toolchain := ""
features := ""
export LINKERD2_PROXY_VERSION := env_var_or_default("LINKERD2_PROXY_VERSION", "0.0.0-dev." + `git rev-parse --short HEAD`)
export LINKERD2_PROXY_VERSION := env_var_or_default("LINKERD2_PROXY_VERSION", "0.0.0-dev" + `git rev-parse --short HEAD`)
export LINKERD2_PROXY_VENDOR := env_var_or_default("LINKERD2_PROXY_VENDOR", `whoami` + "@" + `hostname`)
# TODO: these variables will be included in dev v48
export AWS_LC_SYS_CFLAGS_aarch64_unknown_linux_gnu := env_var_or_default("AWS_LC_SYS_CFLAGS_aarch64_unknown_linux_gnu", "-fuse-ld=/usr/aarch64-linux-gnu/bin/ld")
export AWS_LC_SYS_CFLAGS_aarch64_unknown_linux_musl := env_var_or_default("AWS_LC_SYS_CFLAGS_aarch64_unknown_linux_musl", "-fuse-ld=/usr/aarch64-linux-gnu/bin/ld")
# The version name to use for packages.
package_version := "v" + LINKERD2_PROXY_VERSION
@ -26,28 +30,30 @@ docker-repo := "localhost/linkerd/proxy"
docker-tag := `git rev-parse --abbrev-ref HEAD | sed 's|/|.|g'` + "." + `git rev-parse --short HEAD`
docker-image := docker-repo + ":" + docker-tag
# The architecture name to use for packages. Either 'amd64', 'arm64', or 'arm'.
# The architecture name to use for packages. Either 'amd64' or 'arm64'.
arch := "amd64"
# The OS name to use for packages. Either 'linux' or 'windows'.
os := "linux"
libc := 'gnu'
# If a `arch` is specified, then we change the default cargo `--target`
# to support cross-compilation. Otherwise, we use `rustup` to find the default.
_target := if arch == 'amd64' {
_target := if os + '-' + arch == "linux-amd64" {
"x86_64-unknown-linux-" + libc
} else if arch == "arm64" {
} else if os + '-' + arch == "linux-arm64" {
"aarch64-unknown-linux-" + libc
} else if arch == "arm" {
"armv7-unknown-linux-" + libc + "eabihf"
} else if os + '-' + arch == "windows-amd64" {
"x86_64-pc-windows-" + libc
} else {
error("unsupported arch=" + arch)
error("unsupported: os=" + os + " arch=" + arch + " libc=" + libc)
}
_cargo := 'just-cargo profile=' + profile + ' target=' + _target + ' toolchain=' + toolchain
_target_dir := "target" / _target / profile
_target_bin := _target_dir / "linkerd2-proxy"
_package_name := "linkerd2-proxy-" + package_version + "-" + arch + if libc == 'musl' { '-static' } else { '' }
_target_bin := _target_dir / "linkerd2-proxy" + if os == 'windows' { '.exe' } else { '' }
_package_name := "linkerd2-proxy-" + package_version + "-" + os + "-" + arch + if libc == 'musl' { '-static' } else { '' }
_package_dir := "target/package" / _package_name
shasum := "shasum -a 256"
@ -135,7 +141,7 @@ _strip:
_package_bin := _package_dir / "bin" / "linkerd2-proxy"
# XXX {aarch64,arm}-musl builds do not enable PIE, so we use target-specific
# XXX aarch64-musl builds do not enable PIE, so we use target-specific
# files to document those differences.
_expected_checksec := '.checksec' / arch + '-' + libc + '.json'
@ -254,6 +260,12 @@ _tag-set:
_k3d-ready:
@just-k3d ready
export K3D_CLUSTER_NAME := "l5d-proxy"
export K3D_CREATE_FLAGS := "--no-lb"
export K3S_DISABLE := "local-storage,traefik,servicelb,metrics-server@server:*"
k3d-create: && _k3d-ready
@just-k3d create
k3d-load-linkerd: _tag-set _k3d-ready
for i in \
'{{ _controller-image }}:{{ linkerd-tag }}' \
@ -270,6 +282,7 @@ k3d-load-linkerd: _tag-set _k3d-ready
# Install crds on the test cluster.
_linkerd-crds-install: _k3d-ready
{{ _kubectl }} apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/standard-install.yaml
{{ _linkerd }} install --crds \
| {{ _kubectl }} apply -f -
{{ _kubectl }} wait crd --for condition=established \

View File

@ -1,10 +1,10 @@
[package]
name = "linkerd-addr"
version = "0.1.0"
authors = ["Linkerd Developers <cncf-linkerd-dev@lists.cncf.io>"]
license = "Apache-2.0"
edition = "2021"
publish = false
version = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
edition = { workspace = true }
publish = { workspace = true }
[dependencies]
http = { workspace = true }

View File

@ -1,9 +1,10 @@
[package]
name = "linkerd-addr-fuzz"
version = "0.0.0"
authors = ["Linkerd Developers <cncf-linkerd-dev@lists.cncf.io>"]
publish = false
edition = "2021"
version = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
edition = { workspace = true }
publish = { workspace = true }
[package.metadata]
cargo-fuzz = true
@ -12,7 +13,7 @@ cargo-fuzz = true
libfuzzer-sys = "0.4"
linkerd-addr = { path = ".." }
linkerd-tracing = { path = "../../tracing", features = ["ansi"] }
tracing = "0.1"
tracing = { workspace = true }
# Prevent this from interfering with workspaces
[workspace]

View File

@ -100,15 +100,11 @@ impl Addr {
// them ourselves.
format!("[{}]", a.ip())
};
http::uri::Authority::from_str(&ip).unwrap_or_else(|err| {
panic!("SocketAddr ({}) must be valid authority: {}", a, err)
})
}
Addr::Socket(a) => {
http::uri::Authority::from_str(&a.to_string()).unwrap_or_else(|err| {
panic!("SocketAddr ({}) must be valid authority: {}", a, err)
})
http::uri::Authority::from_str(&ip)
.unwrap_or_else(|err| panic!("SocketAddr ({a}) must be valid authority: {err}"))
}
Addr::Socket(a) => http::uri::Authority::from_str(&a.to_string())
.unwrap_or_else(|err| panic!("SocketAddr ({a}) must be valid authority: {err}")),
}
}
@ -265,14 +261,14 @@ mod tests {
];
for (host, expected_result) in cases {
let a = Addr::from_str(host).unwrap();
assert_eq!(a.is_loopback(), *expected_result, "{:?}", host)
assert_eq!(a.is_loopback(), *expected_result, "{host:?}")
}
}
fn test_to_http_authority(cases: &[&str]) {
let width = cases.iter().map(|s| s.len()).max().unwrap_or(0);
for host in cases {
print!("trying {:1$} ... ", host, width);
print!("trying {host:width$} ... ");
Addr::from_str(host).unwrap().to_http_authority();
println!("ok");
}

View File

@ -1,10 +1,10 @@
[package]
name = "linkerd-app"
version = "0.1.0"
authors = ["Linkerd Developers <cncf-linkerd-dev@lists.cncf.io>"]
license = "Apache-2.0"
edition = "2021"
publish = false
version = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
edition = { workspace = true }
publish = { workspace = true }
description = """
Configures and executes the proxy
@ -18,6 +18,7 @@ pprof = ["linkerd-app-admin/pprof"]
[dependencies]
futures = { version = "0.3", default-features = false }
hyper-util = { workspace = true }
linkerd-app-admin = { path = "./admin" }
linkerd-app-core = { path = "./core" }
linkerd-app-gateway = { path = "./gateway" }
@ -27,11 +28,12 @@ linkerd-error = { path = "../error" }
linkerd-opencensus = { path = "../opencensus" }
linkerd-opentelemetry = { path = "../opentelemetry" }
linkerd-tonic-stream = { path = "../tonic-stream" }
linkerd-workers = { path = "../workers" }
rangemap = "1"
regex = "1"
thiserror = "2"
tokio = { version = "1", features = ["rt"] }
tokio-stream = { version = "0.1", features = ["time", "sync"] }
tonic = { workspace = true, default-features = false, features = ["prost"] }
tower = "0.4"
tracing = "0.1"
tower = { workspace = true }
tracing = { workspace = true }

View File

@ -1,10 +1,10 @@
[package]
name = "linkerd-app-admin"
version = "0.1.0"
authors = ["Linkerd Developers <cncf-linkerd-dev@lists.cncf.io>"]
license = "Apache-2.0"
edition = "2021"
publish = false
version = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
edition = { workspace = true }
publish = { workspace = true }
description = """
The linkerd proxy's admin server.
"""
@ -19,21 +19,22 @@ bytes = { workspace = true }
deflate = { version = "1", optional = true, features = ["gzip"] }
http = { workspace = true }
http-body = { workspace = true }
hyper = { workspace = true, features = ["deprecated", "http1", "http2"] }
http-body-util = { workspace = true }
hyper = { workspace = true, features = ["http1", "http2"] }
futures = { version = "0.3", default-features = false }
pprof = { version = "0.14", optional = true, features = ["prost-codec"] }
pprof = { version = "0.15", optional = true, features = ["prost-codec"] }
serde = "1"
serde_json = "1"
thiserror = "2"
tokio = { version = "1", features = ["macros", "sync", "parking_lot"] }
tracing = "0.1"
tracing = { workspace = true }
linkerd-app-core = { path = "../core" }
linkerd-app-inbound = { path = "../inbound" }
linkerd-tracing = { path = "../../tracing" }
[dependencies.tower]
version = "0.4"
workspace = true
default-features = false
features = [
"buffer",

View File

@ -13,7 +13,7 @@
use futures::future::{self, TryFutureExt};
use http::StatusCode;
use linkerd_app_core::{
metrics::{self as metrics, FmtMetrics},
metrics::{self as metrics, legacy::FmtMetrics},
proxy::http::{Body, BoxBody, ClientHandle, Request, Response},
trace, Error, Result,
};
@ -32,7 +32,7 @@ pub use self::readiness::{Latch, Readiness};
#[derive(Clone)]
pub struct Admin<M> {
metrics: metrics::Serve<M>,
metrics: metrics::legacy::Serve<M>,
tracing: trace::Handle,
ready: Readiness,
shutdown_tx: mpsc::UnboundedSender<()>,
@ -52,7 +52,7 @@ impl<M> Admin<M> {
tracing: trace::Handle,
) -> Self {
Self {
metrics: metrics::Serve::new(metrics),
metrics: metrics::legacy::Serve::new(metrics),
ready,
shutdown_tx,
enable_shutdown,
@ -172,14 +172,14 @@ impl<M> Admin<M> {
fn not_found() -> Response<BoxBody> {
Response::builder()
.status(http::StatusCode::NOT_FOUND)
.body(BoxBody::new(hyper::Body::empty()))
.body(BoxBody::empty())
.expect("builder with known status code must not fail")
}
fn method_not_allowed() -> Response<BoxBody> {
Response::builder()
.status(http::StatusCode::METHOD_NOT_ALLOWED)
.body(BoxBody::new(hyper::Body::empty()))
.body(BoxBody::empty())
.expect("builder with known status code must not fail")
}
@ -329,7 +329,7 @@ mod tests {
let r = Request::builder()
.method(Method::GET)
.uri("http://0.0.0.0/ready")
.body(hyper::Body::empty())
.body(BoxBody::empty())
.unwrap();
let f = admin.clone().oneshot(r);
timeout(TIMEOUT, f).await.expect("timeout").expect("call")

View File

@ -57,7 +57,7 @@ fn mk_rsp(status: StatusCode, val: &impl serde::Serialize) -> http::Response<Box
// Serialize the value into JSON, and then place the bytes in a boxed response body.
let json = serde_json::to_vec(val)
.map(Bytes::from)
.map(http_body::Full::new)
.map(http_body_util::Full::new)
.map(BoxBody::new);
match json {

View File

@ -22,14 +22,15 @@ where
}
http::Method::PUT => {
use http_body_util::BodyExt;
let body = req
.into_body()
.collect()
.await
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?
.map_err(io::Error::other)?
.aggregate();
match level.set_from(body.chunk()) {
Ok(_) => mk_rsp(StatusCode::NO_CONTENT, hyper::Body::empty()),
Ok(_) => mk_rsp(StatusCode::NO_CONTENT, BoxBody::empty()),
Err(error) => {
tracing::warn!(%error, "Setting log level failed");
mk_rsp(StatusCode::BAD_REQUEST, error)
@ -41,7 +42,7 @@ where
.status(StatusCode::METHOD_NOT_ALLOWED)
.header(header::ALLOW, "GET")
.header(header::ALLOW, "PUT")
.body(BoxBody::new(hyper::Body::empty()))
.body(BoxBody::empty())
.expect("builder with known status code must not fail"),
})
}

View File

@ -51,11 +51,13 @@ where
// If the request is a QUERY, use the request body
method if method.as_str() == "QUERY" => {
// TODO(eliza): validate that the request has a content-length...
use http_body_util::BodyExt;
let body = recover!(
http_body::Body::collect(req.into_body())
req.into_body()
.collect()
.await
.map_err(Into::into)
.map(http_body::Collected::aggregate),
.map(http_body_util::Collected::aggregate),
"Reading log stream request body",
StatusCode::BAD_REQUEST
);
@ -74,7 +76,7 @@ where
.status(StatusCode::METHOD_NOT_ALLOWED)
.header(header::ALLOW, "GET")
.header(header::ALLOW, "QUERY")
.body(BoxBody::new(hyper::Body::empty()))
.body(BoxBody::empty())
.expect("builder with known status code must not fail"));
}
};
@ -99,7 +101,7 @@ where
// https://github.com/hawkw/thingbuf/issues/62 would allow us to avoid the
// copy by passing the channel's pooled buffer directly to hyper, and
// returning it to the channel to be reused when hyper is done with it.
let (mut tx, body) = hyper::Body::channel();
let (mut tx, body) = http_body_util::channel::Channel::<Bytes, Error>::new(1024);
tokio::spawn(
async move {
// TODO(eliza): we could definitely implement some batching here.

View File

@ -1,8 +1,8 @@
use linkerd_app_core::{
classify,
config::ServerConfig,
detect, drain, errors, identity,
metrics::{self, FmtMetrics},
drain, errors, identity,
metrics::{self, legacy::FmtMetrics},
proxy::http,
serve,
svc::{self, ExtractParam, InsertParam, Param},
@ -122,6 +122,7 @@ impl Config {
.push_on_service(http::BoxResponse::layer())
.arc_new_clone_http();
let inbound::DetectMetrics(detect_metrics) = metrics.detect.clone();
let tcp = http
.unlift_new()
.push(http::NewServeHttp::layer({
@ -136,11 +137,11 @@ impl Config {
}))
.push_filter(
|(http, tcp): (
Result<Option<http::Variant>, detect::DetectTimeoutError<_>>,
http::Detection,
Tcp,
)| {
match http {
Ok(Some(version)) => Ok(Http { version, tcp }),
http::Detection::Http(version) => Ok(Http { version, tcp }),
// If detection timed out, we can make an educated guess at the proper
// behavior:
// - If the connection was meshed, it was most likely transported over
@ -148,7 +149,7 @@ impl Config {
// - If the connection was unmeshed, it was mostly likely HTTP/1.
// - If we received some unexpected SNI, the client is mostly likely
// confused/stale.
Err(_timeout) => {
http::Detection::ReadTimeout(_timeout) => {
let version = match tcp.tls {
tls::ConditionalServerTls::None(_) => http::Variant::Http1,
tls::ConditionalServerTls::Some(tls::ServerTls::Established {
@ -166,7 +167,7 @@ impl Config {
}
// If the connection failed HTTP detection, check if we detected TLS for
// another target. This might indicate that the client is confused/stale.
Ok(None) => match tcp.tls {
http::Detection::NotHttp => match tcp.tls {
tls::ConditionalServerTls::Some(tls::ServerTls::Passthru { sni }) => {
Err(UnexpectedSni(sni, tcp.client).into())
}
@ -177,9 +178,12 @@ impl Config {
)
.arc_new_tcp()
.lift_new_with_target()
.push(detect::NewDetectService::layer(svc::stack::CloneParam::from(
detect::Config::<http::DetectHttp>::from_timeout(DETECT_TIMEOUT),
)))
.push(http::NewDetect::layer(move |tcp: &Tcp| {
http::DetectParams {
read_timeout: DETECT_TIMEOUT,
metrics: detect_metrics.metrics(tcp.policy.server_label())
}
}))
.push(transport::metrics::NewServer::layer(metrics.proxy.transport))
.push_map_target(move |(tls, addrs): (tls::ConditionalServerTls, B::Addrs)| {
Tcp {
@ -210,7 +214,7 @@ impl Config {
impl Param<transport::labels::Key> for Tcp {
fn param(&self) -> transport::labels::Key {
transport::labels::Key::inbound_server(
self.tls.clone(),
self.tls.as_ref().map(|t| t.labels()),
self.addr.into(),
self.policy.server_label(),
)
@ -268,7 +272,8 @@ impl Param<metrics::ServerLabel> for Http {
impl Param<metrics::EndpointLabels> for Permitted {
fn param(&self) -> metrics::EndpointLabels {
metrics::InboundEndpointLabels {
tls: self.http.tcp.tls.clone(),
tls: self.http.tcp.tls.as_ref().map(|t| t.labels()),
authority: None,
target_addr: self.http.tcp.addr.into(),
policy: self.permit.labels.clone(),
}

View File

@ -1,10 +1,10 @@
[package]
name = "linkerd-app-core"
version = "0.1.0"
authors = ["Linkerd Developers <cncf-linkerd-dev@lists.cncf.io>"]
license = "Apache-2.0"
edition = "2021"
publish = false
version = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
edition = { workspace = true }
publish = { workspace = true }
description = """
Core infrastructure for the proxy application
@ -13,30 +13,23 @@ independently of the inbound and outbound proxy logic.
"""
[dependencies]
bytes = { workspace = true }
drain = { version = "0.1", features = ["retain"] }
drain = { workspace = true, features = ["retain"] }
http = { workspace = true }
http-body = { workspace = true }
hyper = { workspace = true, features = ["deprecated", "http1", "http2"] }
hyper = { workspace = true, features = ["http1", "http2"] }
futures = { version = "0.3", default-features = false }
ipnet = "2.11"
prometheus-client = "0.22"
regex = "1"
serde_json = "1"
prometheus-client = { workspace = true }
thiserror = "2"
tokio = { version = "1", features = ["macros", "sync", "parking_lot"] }
tokio-stream = { version = "0.1", features = ["time"] }
tonic = { workspace = true, default-features = false, features = ["prost"] }
tracing = "0.1"
parking_lot = "0.12"
tracing = { workspace = true }
pin-project = "1"
linkerd-addr = { path = "../../addr" }
linkerd-conditional = { path = "../../conditional" }
linkerd-dns = { path = "../../dns" }
linkerd-detect = { path = "../../detect" }
linkerd-duplex = { path = "../../duplex" }
linkerd-errno = { path = "../../errno" }
linkerd-error = { path = "../../error" }
linkerd-error-respond = { path = "../../error-respond" }
linkerd-exp-backoff = { path = "../../exp-backoff" }
@ -63,6 +56,7 @@ linkerd-proxy-tcp = { path = "../../proxy/tcp" }
linkerd-proxy-transport = { path = "../../proxy/transport" }
linkerd-reconnect = { path = "../../reconnect" }
linkerd-router = { path = "../../router" }
linkerd-rustls = { path = "../../rustls" }
linkerd-service-profiles = { path = "../../service-profiles" }
linkerd-stack = { path = "../../stack" }
linkerd-stack-metrics = { path = "../../stack/metrics" }
@ -74,17 +68,14 @@ linkerd-tls = { path = "../../tls" }
linkerd-trace-context = { path = "../../trace-context" }
[dependencies.tower]
version = "0.4"
workspace = true
default-features = false
features = ["make", "spawn-ready", "timeout", "util", "limit"]
[target.'cfg(target_os = "linux")'.dependencies]
linkerd-system = { path = "../../system" }
[build-dependencies]
semver = "1"
[dev-dependencies]
linkerd-http-body-compat = { path = "../../http/body-compat" }
bytes = { workspace = true }
http-body-util = { workspace = true }
linkerd-mock-http-body = { path = "../../mock/http-body" }
quickcheck = { version = "1", default-features = false }

View File

@ -4,11 +4,11 @@ fn set_env(name: &str, cmd: &mut Command) {
let value = match cmd.output() {
Ok(output) => String::from_utf8(output.stdout).unwrap(),
Err(err) => {
println!("cargo:warning={}", err);
println!("cargo:warning={err}");
"".to_string()
}
};
println!("cargo:rustc-env={}={}", name, value);
println!("cargo:rustc-env={name}={value}");
}
fn version() -> String {

View File

@ -1,5 +1,4 @@
use crate::profiles;
pub use classify::gate;
use linkerd_error::Error;
use linkerd_proxy_client_policy as client_policy;
use linkerd_proxy_http::{classify, HasH2Reason, ResponseTimeoutError};
@ -214,7 +213,7 @@ fn h2_error(err: &Error) -> String {
if let Some(reason) = err.h2_reason() {
// This should output the error code in the same format as the spec,
// for example: PROTOCOL_ERROR
format!("h2({:?})", reason)
format!("h2({reason:?})")
} else {
trace!("classifying found non-h2 error: {:?}", err);
String::from("unclassified")

View File

@ -1,7 +1,7 @@
pub use crate::exp_backoff::ExponentialBackoff;
use crate::{
proxy::http::{self, h1, h2},
svc::{queue, CloneParam, ExtractParam, Param},
proxy::http::{h1, h2},
svc::{queue, ExtractParam, Param},
transport::{DualListenAddr, Keepalive, ListenAddr, UserTimeout},
};
use std::time::Duration;
@ -59,14 +59,6 @@ impl<T> ExtractParam<queue::Timeout, T> for QueueConfig {
}
}
// === impl ProxyConfig ===
impl ProxyConfig {
pub fn detect_http(&self) -> CloneParam<linkerd_detect::Config<http::DetectHttp>> {
linkerd_detect::Config::from_timeout(self.detect_protocol_timeout).into()
}
}
// === impl ServerConfig ===
impl Param<DualListenAddr> for ServerConfig {

View File

@ -69,8 +69,10 @@ impl fmt::Display for ControlAddr {
}
}
pub type RspBody =
linkerd_http_metrics::requests::ResponseBody<http::balance::Body<hyper::Body>, classify::Eos>;
pub type RspBody = linkerd_http_metrics::requests::ResponseBody<
http::balance::Body<hyper::body::Incoming>,
classify::Eos,
>;
#[derive(Clone, Debug, Default)]
pub struct Metrics {
@ -99,7 +101,7 @@ impl Config {
identity: identity::NewClient,
) -> svc::ArcNewService<
(),
svc::BoxCloneSyncService<http::Request<tonic::body::BoxBody>, http::Response<RspBody>>,
svc::BoxCloneSyncService<http::Request<tonic::body::Body>, http::Response<RspBody>>,
> {
let addr = self.addr;
tracing::trace!(%addr, "Building");
@ -112,7 +114,7 @@ impl Config {
warn!(error, "Failed to resolve control-plane component");
if let Some(e) = crate::errors::cause_ref::<dns::ResolveError>(&*error) {
if let Some(ttl) = e.negative_ttl() {
return Ok(Either::Left(
return Ok::<_, Error>(Either::Left(
IntervalStream::new(time::interval(ttl)).map(|_| ()),
));
}
@ -129,9 +131,9 @@ impl Config {
self.connect.user_timeout,
))
.push(tls::Client::layer(identity))
.push_connect_timeout(self.connect.timeout)
.push_connect_timeout(self.connect.timeout) // Client<NewClient, ConnectTcp>
.push_map_target(|(_version, target)| target)
.push(self::client::layer(self.connect.http2))
.push(self::client::layer::<_, _>(self.connect.http2))
.push_on_service(svc::MapErr::layer_boxed())
.into_new_service();

View File

@ -1,25 +1,50 @@
pub use linkerd_dns::*;
use std::path::PathBuf;
use self::metrics::Labels;
use linkerd_metrics::prom::{Counter, Family, Registry};
use std::time::Duration;
pub use linkerd_dns::*;
mod metrics;
#[derive(Clone, Debug)]
pub struct Config {
pub min_ttl: Option<Duration>,
pub max_ttl: Option<Duration>,
pub resolv_conf_path: PathBuf,
}
pub struct Dns {
pub resolver: Resolver,
resolver: Resolver,
resolutions: Family<Labels, Counter>,
}
// === impl Dns ===
impl Dns {
/// Returns a new [`Resolver`].
pub fn resolver(&self, client: &'static str) -> Resolver {
let metrics = self.metrics(client);
self.resolver.clone().with_metrics(metrics)
}
}
// === impl Config ===
impl Config {
pub fn build(self) -> Dns {
pub fn build(self, registry: &mut Registry) -> Dns {
let resolutions = Family::default();
registry.register(
"resolutions",
"Counts the number of DNS records that have been resolved.",
resolutions.clone(),
);
let resolver =
Resolver::from_system_config_with(&self).expect("system DNS config must be valid");
Dns { resolver }
Dns {
resolver,
resolutions,
}
}
}

View File

@ -0,0 +1,115 @@
use super::{Dns, Metrics};
use linkerd_metrics::prom::encoding::{
EncodeLabel, EncodeLabelSet, EncodeLabelValue, LabelSetEncoder, LabelValueEncoder,
};
use std::fmt::{Display, Write};
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub(super) struct Labels {
client: &'static str,
record_type: RecordType,
result: Outcome,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
enum RecordType {
A,
Srv,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
enum Outcome {
Ok,
NotFound,
}
// === impl Dns ===
impl Dns {
pub(super) fn metrics(&self, client: &'static str) -> Metrics {
let family = &self.resolutions;
let a_records_resolved = (*family.get_or_create(&Labels {
client,
record_type: RecordType::A,
result: Outcome::Ok,
}))
.clone();
let a_records_not_found = (*family.get_or_create(&Labels {
client,
record_type: RecordType::A,
result: Outcome::NotFound,
}))
.clone();
let srv_records_resolved = (*family.get_or_create(&Labels {
client,
record_type: RecordType::Srv,
result: Outcome::Ok,
}))
.clone();
let srv_records_not_found = (*family.get_or_create(&Labels {
client,
record_type: RecordType::Srv,
result: Outcome::NotFound,
}))
.clone();
Metrics {
a_records_resolved,
a_records_not_found,
srv_records_resolved,
srv_records_not_found,
}
}
}
// === impl Labels ===
impl EncodeLabelSet for Labels {
fn encode(&self, mut encoder: LabelSetEncoder<'_>) -> Result<(), std::fmt::Error> {
let Self {
client,
record_type,
result,
} = self;
("client", *client).encode(encoder.encode_label())?;
("record_type", record_type).encode(encoder.encode_label())?;
("result", result).encode(encoder.encode_label())?;
Ok(())
}
}
// === impl Outcome ===
impl EncodeLabelValue for &Outcome {
fn encode(&self, encoder: &mut LabelValueEncoder<'_>) -> Result<(), std::fmt::Error> {
encoder.write_str(self.to_string().as_str())
}
}
impl Display for Outcome {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Ok => "ok",
Self::NotFound => "not_found",
})
}
}
// === impl RecordType ===
impl EncodeLabelValue for &RecordType {
fn encode(&self, encoder: &mut LabelValueEncoder<'_>) -> Result<(), std::fmt::Error> {
encoder.write_str(self.to_string().as_str())
}
}
impl Display for RecordType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::A => "A/AAAA",
Self::Srv => "SRV",
})
}
}

View File

@ -2,7 +2,8 @@ use super::{
header::{GRPC_MESSAGE, GRPC_STATUS},
respond::{HttpRescue, SyntheticHttpResponse},
};
use http::{header::HeaderValue, HeaderMap};
use http::header::HeaderValue;
use http_body::Frame;
use linkerd_error::{Error, Result};
use pin_project::pin_project;
use std::{
@ -31,7 +32,7 @@ enum Inner<R, B> {
emit_headers: bool,
},
/// The underlying body `B` yielded an error and was "rescued".
Rescued { trailers: Option<http::HeaderMap> },
Rescued,
}
// === impl ResponseBody ===
@ -66,41 +67,28 @@ where
type Data = B::Data;
type Error = B::Error;
fn poll_data(
fn poll_frame(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
) -> Poll<Option<std::result::Result<http_body::Frame<Self::Data>, Self::Error>>> {
let ResponseBodyProj(inner) = self.as_mut().project();
match inner.project() {
InnerProj::Passthru(inner) => inner.poll_data(cx),
InnerProj::Rescued { trailers: _ } => Poll::Ready(None),
InnerProj::Passthru(inner) => inner.poll_frame(cx),
InnerProj::GrpcRescue {
inner,
rescue,
emit_headers,
} => match inner.poll_data(cx) {
} => match inner.poll_frame(cx) {
Poll::Ready(Some(Err(error))) => {
// The inner body has yielded an error, which we will try to rescue. If so,
// store our synthetic trailers reporting the error.
// yield synthetic trailers reporting the error.
let trailers = Self::rescue(error, rescue, *emit_headers)?;
self.set_rescued(trailers);
Poll::Ready(None)
self.set(Self(Inner::Rescued));
Poll::Ready(Some(Ok(Frame::trailers(trailers))))
}
data => data,
poll => poll,
},
}
}
#[inline]
fn poll_trailers(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
let ResponseBodyProj(inner) = self.project();
match inner.project() {
InnerProj::Passthru(inner) => inner.poll_trailers(cx),
InnerProj::GrpcRescue { inner, .. } => inner.poll_trailers(cx),
InnerProj::Rescued { trailers } => Poll::Ready(Ok(trailers.take())),
InnerProj::Rescued => Poll::Ready(None),
}
}
@ -110,7 +98,7 @@ where
match inner {
Inner::Passthru(inner) => inner.is_end_stream(),
Inner::GrpcRescue { inner, .. } => inner.is_end_stream(),
Inner::Rescued { trailers } => trailers.is_none(),
Inner::Rescued => true,
}
}
@ -120,7 +108,7 @@ where
match inner {
Inner::Passthru(inner) => inner.size_hint(),
Inner::GrpcRescue { inner, .. } => inner.size_hint(),
Inner::Rescued { .. } => http_body::SizeHint::with_exact(0),
Inner::Rescued => http_body::SizeHint::with_exact(0),
}
}
}
@ -163,18 +151,6 @@ where
}
}
impl<R, B> ResponseBody<R, B> {
/// Marks this body as "rescued".
///
/// No more data frames will be yielded, and the given trailers will be returned when this
/// body is polled.
fn set_rescued(mut self: Pin<&mut Self>, trailers: HeaderMap) {
let trailers = Some(trailers);
let new = Self(Inner::Rescued { trailers });
self.set(new);
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -205,7 +181,7 @@ mod tests {
.then_yield_data(Poll::Ready(Some(Ok("inter".into()))))
.then_yield_data(Poll::Ready(Some(Err("an error midstream".into()))))
.then_yield_data(Poll::Ready(Some(Ok("rupted".into()))))
.then_yield_trailer(Poll::Ready(Ok(Some(trailers))));
.then_yield_trailer(Poll::Ready(Some(Ok(trailers))));
let rescue = MockRescue;
let emit_headers = false;
ResponseBody::grpc_rescue(inner, rescue, emit_headers)
@ -235,7 +211,7 @@ mod tests {
.then_yield_data(Poll::Ready(Some(Ok("inter".into()))))
.then_yield_data(Poll::Ready(Some(Err("an error midstream".into()))))
.then_yield_data(Poll::Ready(Some(Ok("rupted".into()))))
.then_yield_trailer(Poll::Ready(Ok(Some(trailers))));
.then_yield_trailer(Poll::Ready(Some(Ok(trailers))));
let rescue = MockRescue;
let emit_headers = true;
ResponseBody::grpc_rescue(inner, rescue, emit_headers)
@ -289,7 +265,7 @@ mod tests {
trls
};
let rescue = {
let inner = MockBody::default().then_yield_trailer(Poll::Ready(Ok(Some(trailers))));
let inner = MockBody::default().then_yield_trailer(Poll::Ready(Some(Ok(trailers))));
let rescue = MockRescue;
let emit_headers = false;
ResponseBody::grpc_rescue(inner, rescue, emit_headers)
@ -299,12 +275,13 @@ mod tests {
assert_eq!(trailers.expect("has trailers")["trailer"], "caboose");
}
async fn body_to_string<B>(body: B) -> (String, Option<HeaderMap>)
async fn body_to_string<B>(mut body: B) -> (String, Option<HeaderMap>)
where
B: http_body::Body + Unpin,
B::Error: std::fmt::Debug,
{
let mut body = linkerd_http_body_compat::ForwardCompatibleBody::new(body);
use http_body_util::BodyExt;
let mut data = String::new();
let mut trailers = None;

View File

@ -25,6 +25,7 @@ pub mod metrics;
pub mod proxy;
pub mod serve;
pub mod svc;
pub mod tls_info;
pub mod transport;
pub use self::build_info::{BuildInfo, BUILD_INFO};
@ -32,7 +33,6 @@ pub use drain;
pub use ipnet::{IpNet, Ipv4Net, Ipv6Net};
pub use linkerd_addr::{self as addr, Addr, AddrMatch, IpMatch, NameAddr, NameMatch};
pub use linkerd_conditional::Conditional;
pub use linkerd_detect as detect;
pub use linkerd_dns;
pub use linkerd_error::{cause_ref, is_caused_by, Error, Infallible, Recover, Result};
pub use linkerd_exp_backoff as exp_backoff;

View File

@ -15,7 +15,7 @@ use crate::{
use linkerd_addr::Addr;
pub use linkerd_metrics::*;
use linkerd_proxy_server_policy as policy;
use prometheus_client::encoding::EncodeLabelValue;
use prometheus_client::encoding::{EncodeLabelSet, EncodeLabelValue};
use std::{
fmt::{self, Write},
net::SocketAddr,
@ -54,7 +54,7 @@ pub struct Proxy {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ControlLabels {
addr: Addr,
server_id: tls::ConditionalClientTls,
server_id: tls::ConditionalClientTlsLabels,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@ -65,14 +65,15 @@ pub enum EndpointLabels {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct InboundEndpointLabels {
pub tls: tls::ConditionalServerTls,
pub tls: tls::ConditionalServerTlsLabels,
pub authority: Option<http::uri::Authority>,
pub target_addr: SocketAddr,
pub policy: RouteAuthzLabels,
}
/// A label referencing an inbound `Server` (i.e. for policy).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct ServerLabel(pub Arc<policy::Meta>);
pub struct ServerLabel(pub Arc<policy::Meta>, pub u16);
/// Labels referencing an inbound server and authorization.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
@ -97,7 +98,7 @@ pub struct RouteAuthzLabels {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct OutboundEndpointLabels {
pub server_id: tls::ConditionalClientTls,
pub server_id: tls::ConditionalClientTlsLabels,
pub authority: Option<http::uri::Authority>,
pub labels: Option<String>,
pub zone_locality: OutboundZoneLocality,
@ -154,10 +155,10 @@ where
I: Iterator<Item = (&'i String, &'i String)>,
{
let (k0, v0) = labels_iter.next()?;
let mut out = format!("{}_{}=\"{}\"", prefix, k0, v0);
let mut out = format!("{prefix}_{k0}=\"{v0}\"");
for (k, v) in labels_iter {
write!(out, ",{}_{}=\"{}\"", prefix, k, v).expect("label concat must succeed");
write!(out, ",{prefix}_{k}=\"{v}\"").expect("label concat must succeed");
}
Some(out)
}
@ -165,7 +166,7 @@ where
// === impl Metrics ===
impl Metrics {
pub fn new(retain_idle: Duration) -> (Self, impl FmtMetrics + Clone + Send + 'static) {
pub fn new(retain_idle: Duration) -> (Self, impl legacy::FmtMetrics + Clone + Send + 'static) {
let (control, control_report) = {
let m = http_metrics::Requests::<ControlLabels, Class>::default();
let r = m.clone().into_report(retain_idle).with_prefix("control");
@ -222,6 +223,7 @@ impl Metrics {
opentelemetry,
};
use legacy::FmtMetrics as _;
let report = endpoint_report
.and_report(profile_route_report)
.and_report(retry_report)
@ -242,15 +244,17 @@ impl svc::Param<ControlLabels> for control::ControlAddr {
fn param(&self) -> ControlLabels {
ControlLabels {
addr: self.addr.clone(),
server_id: self.identity.clone(),
server_id: self.identity.as_ref().map(tls::ClientTls::labels),
}
}
}
impl FmtLabels for ControlLabels {
impl legacy::FmtLabels for ControlLabels {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "addr=\"{}\",", self.addr)?;
TlsConnect::from(&self.server_id).fmt_labels(f)?;
let Self { addr, server_id } = self;
write!(f, "addr=\"{addr}\",")?;
TlsConnect::from(server_id).fmt_labels(f)?;
Ok(())
}
@ -278,13 +282,19 @@ impl ProfileRouteLabels {
}
}
impl FmtLabels for ProfileRouteLabels {
impl legacy::FmtLabels for ProfileRouteLabels {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.direction.fmt_labels(f)?;
write!(f, ",dst=\"{}\"", self.addr)?;
let Self {
direction,
addr,
labels,
} = self;
if let Some(labels) = self.labels.as_ref() {
write!(f, ",{}", labels)?;
direction.fmt_labels(f)?;
write!(f, ",dst=\"{addr}\"")?;
if let Some(labels) = labels.as_ref() {
write!(f, ",{labels}")?;
}
Ok(())
@ -305,7 +315,7 @@ impl From<OutboundEndpointLabels> for EndpointLabels {
}
}
impl FmtLabels for EndpointLabels {
impl legacy::FmtLabels for EndpointLabels {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Inbound(i) => (Direction::In, i).fmt_labels(f),
@ -314,65 +324,98 @@ impl FmtLabels for EndpointLabels {
}
}
impl FmtLabels for InboundEndpointLabels {
impl legacy::FmtLabels for InboundEndpointLabels {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(
(TargetAddr(self.target_addr), TlsAccept::from(&self.tls)),
&self.policy,
)
.fmt_labels(f)?;
let Self {
tls,
authority,
target_addr,
policy,
} = self;
if let Some(a) = authority.as_ref() {
Authority(a).fmt_labels(f)?;
write!(f, ",")?;
}
((TargetAddr(*target_addr), TlsAccept::from(tls)), policy).fmt_labels(f)?;
Ok(())
}
}
impl FmtLabels for ServerLabel {
impl legacy::FmtLabels for ServerLabel {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self(meta, port) = self;
write!(
f,
"srv_group=\"{}\",srv_kind=\"{}\",srv_name=\"{}\"",
self.0.group(),
self.0.kind(),
self.0.name()
"srv_group=\"{}\",srv_kind=\"{}\",srv_name=\"{}\",srv_port=\"{}\"",
meta.group(),
meta.kind(),
meta.name(),
port
)
}
}
impl FmtLabels for ServerAuthzLabels {
impl EncodeLabelSet for ServerLabel {
fn encode(&self, mut enc: prometheus_client::encoding::LabelSetEncoder<'_>) -> fmt::Result {
prom::EncodeLabelSetMut::encode_label_set(self, &mut enc)
}
}
impl prom::EncodeLabelSetMut for ServerLabel {
fn encode_label_set(&self, enc: &mut prom::encoding::LabelSetEncoder<'_>) -> fmt::Result {
use prometheus_client::encoding::EncodeLabel;
("srv_group", self.0.group()).encode(enc.encode_label())?;
("srv_kind", self.0.kind()).encode(enc.encode_label())?;
("srv_name", self.0.name()).encode(enc.encode_label())?;
("srv_port", self.1).encode(enc.encode_label())?;
Ok(())
}
}
impl legacy::FmtLabels for ServerAuthzLabels {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.server.fmt_labels(f)?;
let Self { server, authz } = self;
server.fmt_labels(f)?;
write!(
f,
",authz_group=\"{}\",authz_kind=\"{}\",authz_name=\"{}\"",
self.authz.group(),
self.authz.kind(),
self.authz.name()
authz.group(),
authz.kind(),
authz.name()
)
}
}
impl FmtLabels for RouteLabels {
impl legacy::FmtLabels for RouteLabels {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.server.fmt_labels(f)?;
let Self { server, route } = self;
server.fmt_labels(f)?;
write!(
f,
",route_group=\"{}\",route_kind=\"{}\",route_name=\"{}\"",
self.route.group(),
self.route.kind(),
self.route.name(),
route.group(),
route.kind(),
route.name(),
)
}
}
impl FmtLabels for RouteAuthzLabels {
impl legacy::FmtLabels for RouteAuthzLabels {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.route.fmt_labels(f)?;
let Self { route, authz } = self;
route.fmt_labels(f)?;
write!(
f,
",authz_group=\"{}\",authz_kind=\"{}\",authz_name=\"{}\"",
self.authz.group(),
self.authz.kind(),
self.authz.name(),
authz.group(),
authz.kind(),
authz.name(),
)
}
}
@ -383,19 +426,28 @@ impl svc::Param<OutboundZoneLocality> for OutboundEndpointLabels {
}
}
impl FmtLabels for OutboundEndpointLabels {
impl legacy::FmtLabels for OutboundEndpointLabels {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(a) = self.authority.as_ref() {
let Self {
server_id,
authority,
labels,
// TODO(kate): this label is not currently emitted.
zone_locality: _,
target_addr,
} = self;
if let Some(a) = authority.as_ref() {
Authority(a).fmt_labels(f)?;
write!(f, ",")?;
}
let ta = TargetAddr(self.target_addr);
let tls = TlsConnect::from(&self.server_id);
let ta = TargetAddr(*target_addr);
let tls = TlsConnect::from(server_id);
(ta, tls).fmt_labels(f)?;
if let Some(labels) = self.labels.as_ref() {
write!(f, ",{}", labels)?;
if let Some(labels) = labels.as_ref() {
write!(f, ",{labels}")?;
}
Ok(())
@ -411,19 +463,20 @@ impl fmt::Display for Direction {
}
}
impl FmtLabels for Direction {
impl legacy::FmtLabels for Direction {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "direction=\"{}\"", self)
write!(f, "direction=\"{self}\"")
}
}
impl FmtLabels for Authority<'_> {
impl legacy::FmtLabels for Authority<'_> {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "authority=\"{}\"", self.0)
let Self(authority) = self;
write!(f, "authority=\"{authority}\"")
}
}
impl FmtLabels for Class {
impl legacy::FmtLabels for Class {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let class = |ok: bool| if ok { "success" } else { "failure" };
@ -445,8 +498,7 @@ impl FmtLabels for Class {
Class::Error(msg) => write!(
f,
"classification=\"failure\",grpc_status=\"\",error=\"{}\"",
msg
"classification=\"failure\",grpc_status=\"\",error=\"{msg}\""
),
}
}
@ -472,9 +524,15 @@ impl StackLabels {
}
}
impl FmtLabels for StackLabels {
impl legacy::FmtLabels for StackLabels {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.direction.fmt_labels(f)?;
write!(f, ",protocol=\"{}\",name=\"{}\"", self.protocol, self.name)
let Self {
direction,
protocol,
name,
} = self;
direction.fmt_labels(f)?;
write!(f, ",protocol=\"{protocol}\",name=\"{name}\"")
}
}

View File

@ -0,0 +1,70 @@
use linkerd_metrics::prom;
use prometheus_client::encoding::{EncodeLabelSet, EncodeLabelValue, LabelValueEncoder};
use std::{
fmt::{Error, Write},
sync::{Arc, OnceLock},
};
static TLS_INFO: OnceLock<Arc<TlsInfo>> = OnceLock::new();
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, EncodeLabelSet)]
pub struct TlsInfo {
tls_suites: MetricValueList,
tls_kx_groups: MetricValueList,
tls_rand: String,
tls_key_provider: String,
tls_fips: bool,
}
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
struct MetricValueList {
values: Vec<&'static str>,
}
impl FromIterator<&'static str> for MetricValueList {
fn from_iter<T: IntoIterator<Item = &'static str>>(iter: T) -> Self {
MetricValueList {
values: iter.into_iter().collect(),
}
}
}
impl EncodeLabelValue for MetricValueList {
fn encode(&self, encoder: &mut LabelValueEncoder<'_>) -> Result<(), Error> {
for value in &self.values {
value.encode(encoder)?;
encoder.write_char(',')?;
}
Ok(())
}
}
pub fn metric() -> prom::Family<TlsInfo, prom::ConstGauge> {
let fam = prom::Family::<TlsInfo, prom::ConstGauge>::new_with_constructor(|| {
prom::ConstGauge::new(1)
});
let tls_info = TLS_INFO.get_or_init(|| {
let provider = linkerd_rustls::get_default_provider();
let tls_suites = provider
.cipher_suites
.iter()
.flat_map(|cipher_suite| cipher_suite.suite().as_str())
.collect::<MetricValueList>();
let tls_kx_groups = provider
.kx_groups
.iter()
.flat_map(|suite| suite.name().as_str())
.collect::<MetricValueList>();
Arc::new(TlsInfo {
tls_suites,
tls_kx_groups,
tls_rand: format!("{:?}", provider.secure_random),
tls_key_provider: format!("{:?}", provider.key_provider),
tls_fips: provider.fips(),
})
});
let _ = fam.get_or_create(tls_info);
fam
}

View File

@ -1,7 +1,7 @@
use crate::metrics::ServerLabel as PolicyServerLabel;
pub use crate::metrics::{Direction, OutboundEndpointLabels};
use linkerd_conditional::Conditional;
use linkerd_metrics::FmtLabels;
use linkerd_metrics::legacy::FmtLabels;
use linkerd_tls as tls;
use std::{fmt, net::SocketAddr};
@ -20,16 +20,16 @@ pub enum Key {
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct ServerLabels {
direction: Direction,
tls: tls::ConditionalServerTls,
tls: tls::ConditionalServerTlsLabels,
target_addr: SocketAddr,
policy: Option<PolicyServerLabel>,
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct TlsAccept<'t>(pub &'t tls::ConditionalServerTls);
pub struct TlsAccept<'t>(pub &'t tls::ConditionalServerTlsLabels);
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub(crate) struct TlsConnect<'t>(&'t tls::ConditionalClientTls);
pub(crate) struct TlsConnect<'t>(pub &'t tls::ConditionalClientTlsLabels);
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct TargetAddr(pub SocketAddr);
@ -38,7 +38,7 @@ pub struct TargetAddr(pub SocketAddr);
impl Key {
pub fn inbound_server(
tls: tls::ConditionalServerTls,
tls: tls::ConditionalServerTlsLabels,
target_addr: SocketAddr,
server: PolicyServerLabel,
) -> Self {
@ -62,7 +62,7 @@ impl FmtLabels for Key {
}
Self::InboundClient => {
const NO_TLS: tls::client::ConditionalClientTls =
const NO_TLS: tls::client::ConditionalClientTlsLabels =
Conditional::None(tls::NoClientTls::Loopback);
Direction::In.fmt_labels(f)?;
@ -75,7 +75,7 @@ impl FmtLabels for Key {
impl ServerLabels {
fn inbound(
tls: tls::ConditionalServerTls,
tls: tls::ConditionalServerTlsLabels,
target_addr: SocketAddr,
policy: PolicyServerLabel,
) -> Self {
@ -90,7 +90,7 @@ impl ServerLabels {
fn outbound(target_addr: SocketAddr) -> Self {
ServerLabels {
direction: Direction::Out,
tls: tls::ConditionalServerTls::None(tls::NoServerTls::Loopback),
tls: tls::ConditionalServerTlsLabels::None(tls::NoServerTls::Loopback),
target_addr,
policy: None,
}
@ -99,14 +99,17 @@ impl ServerLabels {
impl FmtLabels for ServerLabels {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.direction.fmt_labels(f)?;
let Self {
direction,
tls,
target_addr,
policy,
} = self;
direction.fmt_labels(f)?;
f.write_str(",peer=\"src\",")?;
(
(TargetAddr(self.target_addr), TlsAccept(&self.tls)),
self.policy.as_ref(),
)
.fmt_labels(f)?;
((TargetAddr(*target_addr), TlsAccept(tls)), policy.as_ref()).fmt_labels(f)?;
Ok(())
}
@ -114,27 +117,28 @@ impl FmtLabels for ServerLabels {
// === impl TlsAccept ===
impl<'t> From<&'t tls::ConditionalServerTls> for TlsAccept<'t> {
fn from(c: &'t tls::ConditionalServerTls) -> Self {
impl<'t> From<&'t tls::ConditionalServerTlsLabels> for TlsAccept<'t> {
fn from(c: &'t tls::ConditionalServerTlsLabels) -> Self {
TlsAccept(c)
}
}
impl FmtLabels for TlsAccept<'_> {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
let Self(tls) = self;
match tls {
Conditional::None(tls::NoServerTls::Disabled) => {
write!(f, "tls=\"disabled\"")
}
Conditional::None(why) => {
write!(f, "tls=\"no_identity\",no_tls_reason=\"{}\"", why)
write!(f, "tls=\"no_identity\",no_tls_reason=\"{why}\"")
}
Conditional::Some(tls::ServerTls::Established { client_id, .. }) => match client_id {
Some(id) => write!(f, "tls=\"true\",client_id=\"{}\"", id),
Conditional::Some(tls::ServerTlsLabels::Established { client_id }) => match client_id {
Some(id) => write!(f, "tls=\"true\",client_id=\"{id}\""),
None => write!(f, "tls=\"true\",client_id=\"\""),
},
Conditional::Some(tls::ServerTls::Passthru { sni }) => {
write!(f, "tls=\"opaque\",sni=\"{}\"", sni)
Conditional::Some(tls::ServerTlsLabels::Passthru { sni }) => {
write!(f, "tls=\"opaque\",sni=\"{sni}\"")
}
}
}
@ -142,23 +146,25 @@ impl FmtLabels for TlsAccept<'_> {
// === impl TlsConnect ===
impl<'t> From<&'t tls::ConditionalClientTls> for TlsConnect<'t> {
fn from(s: &'t tls::ConditionalClientTls) -> Self {
impl<'t> From<&'t tls::ConditionalClientTlsLabels> for TlsConnect<'t> {
fn from(s: &'t tls::ConditionalClientTlsLabels) -> Self {
TlsConnect(s)
}
}
impl FmtLabels for TlsConnect<'_> {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
let Self(tls) = self;
match tls {
Conditional::None(tls::NoClientTls::Disabled) => {
write!(f, "tls=\"disabled\"")
}
Conditional::None(why) => {
write!(f, "tls=\"no_identity\",no_tls_reason=\"{}\"", why)
write!(f, "tls=\"no_identity\",no_tls_reason=\"{why}\"")
}
Conditional::Some(tls::ClientTls { server_id, .. }) => {
write!(f, "tls=\"true\",server_id=\"{}\"", server_id)
Conditional::Some(tls::ClientTlsLabels { server_id }) => {
write!(f, "tls=\"true\",server_id=\"{server_id}\"")
}
}
}
@ -168,12 +174,13 @@ impl FmtLabels for TlsConnect<'_> {
impl FmtLabels for TargetAddr {
fn fmt_labels(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self(target_addr) = self;
write!(
f,
"target_addr=\"{}\",target_ip=\"{}\",target_port=\"{}\"",
self.0,
self.0.ip(),
self.0.port()
target_addr,
target_addr.ip(),
target_addr.port()
)
}
}
@ -194,23 +201,25 @@ mod tests {
use std::sync::Arc;
let labels = ServerLabels::inbound(
tls::ConditionalServerTls::Some(tls::ServerTls::Established {
tls::ConditionalServerTlsLabels::Some(tls::ServerTlsLabels::Established {
client_id: Some("foo.id.example.com".parse().unwrap()),
negotiated_protocol: None,
}),
([192, 0, 2, 4], 40000).into(),
PolicyServerLabel(Arc::new(Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "testserver".into(),
})),
PolicyServerLabel(
Arc::new(Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "testserver".into(),
}),
40000,
),
);
assert_eq!(
labels.to_string(),
"direction=\"inbound\",peer=\"src\",\
target_addr=\"192.0.2.4:40000\",target_ip=\"192.0.2.4\",target_port=\"40000\",\
tls=\"true\",client_id=\"foo.id.example.com\",\
srv_group=\"policy.linkerd.io\",srv_kind=\"server\",srv_name=\"testserver\""
srv_group=\"policy.linkerd.io\",srv_kind=\"server\",srv_name=\"testserver\",srv_port=\"40000\""
);
}
}

View File

@ -1,10 +1,10 @@
[package]
name = "linkerd-app-gateway"
version = "0.1.0"
authors = ["Linkerd Developers <cncf-linkerd-dev@lists.cncf.io>"]
license = "Apache-2.0"
edition = "2021"
publish = false
version = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
edition = { workspace = true }
publish = { workspace = true }
[dependencies]
http = { workspace = true }
@ -17,8 +17,8 @@ once_cell = "1"
thiserror = "2"
tokio = { version = "1", features = ["sync"] }
tonic = { workspace = true, default-features = false }
tower = { version = "0.4", default-features = false }
tracing = "0.1"
tower = { workspace = true, default-features = false }
tracing = { workspace = true }
[dev-dependencies]
linkerd-app-inbound = { path = "../inbound", features = ["test-util"] }
@ -26,6 +26,6 @@ linkerd-app-outbound = { path = "../outbound", features = ["test-util"] }
linkerd-proxy-server-policy = { path = "../../proxy/server-policy" }
tokio = { version = "1", features = ["rt", "macros"] }
tokio-test = "0.4"
tower = { version = "0.4", default-features = false, features = ["util"] }
tower-test = "0.4"
tower = { workspace = true, default-features = false, features = ["util"] }
tower-test = { workspace = true }
linkerd-app-test = { path = "../test" }

View File

@ -90,7 +90,7 @@ impl Gateway {
detect_timeout,
queue,
addr,
meta,
meta.into(),
),
None => {
tracing::debug!(

View File

@ -153,7 +153,7 @@ fn mk_routes(profile: &profiles::Profile) -> Option<outbound::http::Routes> {
if let Some((addr, metadata)) = profile.endpoint.clone() {
return Some(outbound::http::Routes::Endpoint(
Remote(ServerAddr(addr)),
metadata,
metadata.into(),
));
}

View File

@ -62,7 +62,7 @@ async fn upgraded_request_remains_relative_form() {
impl svc::Param<ServerLabel> for Target {
fn param(&self) -> ServerLabel {
ServerLabel(policy::Meta::new_default("test"))
ServerLabel(policy::Meta::new_default("test"), 4143)
}
}

View File

@ -64,10 +64,10 @@ impl Gateway {
SessionProtocol::Http1 => http::Variant::Http1,
SessionProtocol::Http2 => http::Variant::H2,
};
return Ok(svc::Either::A(Http { parent, version }));
return Ok(svc::Either::Left(Http { parent, version }));
}
Ok(svc::Either::B(Opaq(parent)))
Ok(svc::Either::Right(Opaq(parent)))
},
opaq,
)

View File

@ -1,10 +1,10 @@
[package]
name = "linkerd-app-inbound"
version = "0.1.0"
authors = ["Linkerd Developers <cncf-linkerd-dev@lists.cncf.io>"]
license = "Apache-2.0"
edition = "2021"
publish = false
version = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
edition = { workspace = true }
publish = { workspace = true }
description = """
Configures and runs the inbound proxy
"""
@ -13,8 +13,7 @@ Configures and runs the inbound proxy
test-util = [
"linkerd-app-test",
"linkerd-idle-cache/test-util",
"linkerd-meshtls/rustls",
"linkerd-meshtls-rustls/test-util",
"linkerd-meshtls/test-util",
]
[dependencies]
@ -25,8 +24,7 @@ linkerd-app-core = { path = "../core" }
linkerd-app-test = { path = "../test", optional = true }
linkerd-http-access-log = { path = "../../http/access-log" }
linkerd-idle-cache = { path = "../../idle-cache" }
linkerd-meshtls = { path = "../../meshtls", optional = true }
linkerd-meshtls-rustls = { path = "../../meshtls/rustls", optional = true }
linkerd-meshtls = { path = "../../meshtls", optional = true, default-features = false }
linkerd-proxy-client-policy = { path = "../../proxy/client-policy" }
linkerd-tonic-stream = { path = "../../tonic-stream" }
linkerd-tonic-watch = { path = "../../tonic-watch" }
@ -37,30 +35,32 @@ rangemap = "1"
thiserror = "2"
tokio = { version = "1", features = ["sync"] }
tonic = { workspace = true, default-features = false }
tower = { version = "0.4", features = ["util"] }
tracing = "0.1"
tower = { workspace = true, features = ["util"] }
tracing = { workspace = true }
[dependencies.linkerd-proxy-server-policy]
path = "../../proxy/server-policy"
features = ["proto"]
[target.'cfg(fuzzing)'.dependencies]
hyper = { workspace = true, features = ["deprecated", "http1", "http2"] }
hyper = { workspace = true, features = ["http1", "http2"] }
linkerd-app-test = { path = "../test" }
arbitrary = { version = "1", features = ["derive"] }
libfuzzer-sys = { version = "0.4", features = ["arbitrary-derive"] }
linkerd-meshtls-rustls = { path = "../../meshtls/rustls", features = [
linkerd-meshtls = { path = "../../meshtls", features = [
"test-util",
] }
[dev-dependencies]
hyper = { workspace = true, features = ["deprecated", "http1", "http2"] }
http-body-util = { workspace = true }
hyper = { workspace = true, features = ["http1", "http2"] }
hyper-util = { workspace = true }
linkerd-app-test = { path = "../test" }
linkerd-http-metrics = { path = "../../http/metrics", features = ["test-util"] }
linkerd-http-box = { path = "../../http/box" }
linkerd-idle-cache = { path = "../../idle-cache", features = ["test-util"] }
linkerd-io = { path = "../../io", features = ["tokio-test"] }
linkerd-meshtls = { path = "../../meshtls", features = ["rustls"] }
linkerd-meshtls-rustls = { path = "../../meshtls/rustls", features = [
linkerd-meshtls = { path = "../../meshtls", features = [
"test-util",
] }
linkerd-proxy-server-policy = { path = "../../proxy/server-policy", features = [

View File

@ -1,9 +1,10 @@
[package]
name = "linkerd-app-inbound-fuzz"
version = "0.0.0"
version = { workspace = true }
authors = ["Automatically generated"]
publish = false
edition = "2021"
license = { workspace = true }
edition = { workspace = true }
publish = { workspace = true }
[package.metadata]
cargo-fuzz = true
@ -17,13 +18,12 @@ linkerd-app-core = { path = "../../core" }
linkerd-app-inbound = { path = ".." }
linkerd-app-test = { path = "../../test" }
linkerd-idle-cache = { path = "../../../idle-cache", features = ["test-util"] }
linkerd-meshtls = { path = "../../../meshtls", features = ["rustls"] }
linkerd-meshtls-rustls = { path = "../../../meshtls/rustls", features = [
linkerd-meshtls = { path = "../../../meshtls", features = [
"test-util",
] }
linkerd-tracing = { path = "../../../tracing", features = ["ansi"] }
tokio = { version = "1", features = ["full"] }
tracing = "0.1"
tracing = { workspace = true }
# Prevent this from interfering with workspaces
[workspace]

View File

@ -53,12 +53,12 @@ impl<N> Inbound<N> {
move |t: T| -> Result<_, Error> {
let addr: OrigDstAddr = t.param();
if addr.port() == proxy_port {
return Ok(svc::Either::B(t));
return Ok(svc::Either::Right(t));
}
let policy = policies.get_policy(addr);
tracing::debug!(policy = ?&*policy.borrow(), "Accepted");
Ok(svc::Either::A(Accept {
Ok(svc::Either::Left(Accept {
client_addr: t.param(),
orig_dst_addr: addr,
policy,
@ -182,7 +182,11 @@ mod tests {
}
fn inbound() -> Inbound<()> {
Inbound::new(test_util::default_config(), test_util::runtime().0)
Inbound::new(
test_util::default_config(),
test_util::runtime().0,
&mut Default::default(),
)
}
fn new_panic<T>(msg: &'static str) -> svc::ArcNewTcp<T, io::DuplexStream> {

View File

@ -3,8 +3,8 @@ use crate::{
Inbound,
};
use linkerd_app_core::{
detect, identity, io,
metrics::ServerLabel,
identity, io,
metrics::{prom, ServerLabel},
proxy::http,
svc, tls,
transport::{
@ -20,6 +20,10 @@ use tracing::info;
#[cfg(test)]
mod tests;
#[derive(Clone, Debug)]
pub struct MetricsFamilies(pub HttpDetectMetrics);
pub type HttpDetectMetrics = http::DetectMetricsFamilies<ServerLabel>;
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct Forward {
client_addr: Remote<ClientAddr>,
@ -48,9 +52,6 @@ struct Detect {
tls: Tls,
}
#[derive(Copy, Clone, Debug)]
struct ConfigureHttpDetect;
#[derive(Clone)]
struct TlsParams {
timeout: tls::server::Timeout,
@ -64,7 +65,11 @@ type TlsIo<I> = tls::server::Io<identity::ServerIo<tls::server::DetectIo<I>>, I>
impl Inbound<svc::ArcNewTcp<Http, io::BoxedIo>> {
/// Builds a stack that terminates mesh TLS and detects whether the traffic is HTTP (as hinted
/// by policy).
pub(crate) fn push_detect<T, I, F, FSvc>(self, forward: F) -> Inbound<svc::ArcNewTcp<T, I>>
pub(crate) fn push_detect<T, I, F, FSvc>(
self,
MetricsFamilies(metrics): MetricsFamilies,
forward: F,
) -> Inbound<svc::ArcNewTcp<T, I>>
where
T: svc::Param<OrigDstAddr> + svc::Param<Remote<ClientAddr>> + svc::Param<AllowPolicy>,
T: Clone + Send + 'static,
@ -75,14 +80,18 @@ impl Inbound<svc::ArcNewTcp<Http, io::BoxedIo>> {
FSvc::Error: Into<Error>,
FSvc::Future: Send,
{
self.push_detect_http(forward.clone())
self.push_detect_http(metrics, forward.clone())
.push_detect_tls(forward)
}
/// Builds a stack that handles HTTP detection once TLS detection has been performed. If the
/// connection is determined to be HTTP, the inner stack is used; otherwise the connection is
/// passed to the provided 'forward' stack.
fn push_detect_http<I, F, FSvc>(self, forward: F) -> Inbound<svc::ArcNewTcp<Tls, I>>
fn push_detect_http<I, F, FSvc>(
self,
metrics: HttpDetectMetrics,
forward: F,
) -> Inbound<svc::ArcNewTcp<Tls, I>>
where
I: io::AsyncRead + io::AsyncWrite + io::PeerAddr,
I: Debug + Send + Sync + Unpin + 'static,
@ -111,42 +120,59 @@ impl Inbound<svc::ArcNewTcp<Http, io::BoxedIo>> {
.push_switch(
|(detected, Detect { tls, .. })| -> Result<_, Infallible> {
match detected {
Ok(Some(http)) => Ok(svc::Either::A(Http { http, tls })),
Ok(None) => Ok(svc::Either::B(tls)),
http::Detection::Http(http) => {
Ok(svc::Either::Left(Http { http, tls }))
}
http::Detection::NotHttp => Ok(svc::Either::Right(tls)),
// When HTTP detection fails, forward the connection to the application as
// an opaque TCP stream.
Err(timeout) => match tls.policy.protocol() {
Protocol::Http1 { .. } => {
// If the protocol was hinted to be HTTP/1.1 but detection
// failed, we'll usually be handling HTTP/1, but we may actually
// be handling HTTP/2 via protocol upgrade. Our options are:
// handle the connection as HTTP/1, assuming it will be rare for
// a proxy to initiate TLS, etc and not send the 16B of
// connection header; or we can handle it as opaque--but there's
// no chance the server will be able to handle the H2 protocol
// upgrade. So, it seems best to assume it's HTTP/1 and let the
// proxy handle the protocol error if we're in an edge case.
info!(%timeout, "Handling connection as HTTP/1 due to policy");
Ok(svc::Either::A(Http {
http: http::Variant::Http1,
tls,
}))
http::Detection::ReadTimeout(timeout) => {
match tls.policy.protocol() {
Protocol::Http1 { .. } => {
// If the protocol was hinted to be HTTP/1.1 but detection
// failed, we'll usually be handling HTTP/1, but we may actually
// be handling HTTP/2 via protocol upgrade. Our options are:
// handle the connection as HTTP/1, assuming it will be rare for
// a proxy to initiate TLS, etc and not send the 16B of
// connection header; or we can handle it as opaque--but there's
// no chance the server will be able to handle the H2 protocol
// upgrade. So, it seems best to assume it's HTTP/1 and let the
// proxy handle the protocol error if we're in an edge case.
info!(
?timeout,
"Handling connection as HTTP/1 due to policy"
);
Ok(svc::Either::Left(Http {
http: http::Variant::Http1,
tls,
}))
}
// Otherwise, the protocol hint must have
// been `Detect` or the protocol was updated
// after detection was initiated, otherwise
// we would have avoided detection below.
// Continue handling the connection as if it
// were opaque.
_ => {
info!(
?timeout,
"Handling connection as opaque due to policy"
);
Ok(svc::Either::Right(tls))
}
}
// Otherwise, the protocol hint must have been `Detect` or the
// protocol was updated after detection was initiated, otherwise we
// would have avoided detection below. Continue handling the
// connection as if it were opaque.
_ => {
info!(%timeout, "Handling connection as opaque");
Ok(svc::Either::B(tls))
}
},
}
}
},
forward.into_inner(),
)
.lift_new_with_target()
.push(detect::NewDetectService::layer(ConfigureHttpDetect))
.push(http::NewDetect::layer(
move |Detect { timeout, tls }: &Detect| http::DetectParams {
read_timeout: *timeout,
metrics: metrics.metrics(tls.policy.server_label()),
},
))
.arc_new_tcp();
http.push_on_service(svc::MapTargetLayer::new(io::BoxedIo::new))
@ -159,7 +185,7 @@ impl Inbound<svc::ArcNewTcp<Http, io::BoxedIo>> {
move |tls: Tls| -> Result<_, Infallible> {
let http = match tls.policy.protocol() {
Protocol::Detect { timeout, .. } => {
return Ok(svc::Either::B(Detect { timeout, tls }));
return Ok(svc::Either::Right(Detect { timeout, tls }));
}
// Meshed HTTP/1 services may actually be transported over HTTP/2 connections
// between proxies, so we have to do detection.
@ -167,7 +193,7 @@ impl Inbound<svc::ArcNewTcp<Http, io::BoxedIo>> {
// TODO(ver) outbound clients should hint this with ALPN so we don't
// have to detect this situation.
Protocol::Http1 { .. } if tls.status.is_some() => {
return Ok(svc::Either::B(Detect {
return Ok(svc::Either::Right(Detect {
timeout: detect_timeout,
tls,
}));
@ -178,7 +204,7 @@ impl Inbound<svc::ArcNewTcp<Http, io::BoxedIo>> {
Protocol::Http2 { .. } | Protocol::Grpc { .. } => http::Variant::H2,
_ => unreachable!("opaque protocols must not hit the HTTP stack"),
};
Ok(svc::Either::A(Http { http, tls }))
Ok(svc::Either::Left(Http { http, tls }))
},
detect.into_inner(),
)
@ -232,10 +258,10 @@ impl<I> Inbound<svc::ArcNewTcp<Tls, TlsIo<I>>> {
// whether app TLS was employed, but we use this as a signal that we should
// not perform additional protocol detection.
if matches!(protocol, Protocol::Tls { .. }) {
return Ok(svc::Either::B(tls));
return Ok(svc::Either::Right(tls));
}
Ok(svc::Either::A(tls))
Ok(svc::Either::Left(tls))
},
forward
.clone()
@ -259,14 +285,14 @@ impl<I> Inbound<svc::ArcNewTcp<Tls, TlsIo<I>>> {
if matches!(policy.protocol(), Protocol::Opaque { .. }) {
const TLS_PORT_SKIPPED: tls::ConditionalServerTls =
tls::ConditionalServerTls::None(tls::NoServerTls::PortSkipped);
return Ok(svc::Either::B(Tls {
return Ok(svc::Either::Right(Tls {
client_addr: t.param(),
orig_dst_addr: t.param(),
status: TLS_PORT_SKIPPED,
policy,
}));
}
Ok(svc::Either::A(t))
Ok(svc::Either::Left(t))
},
forward
.push_on_service(svc::MapTargetLayer::new(io::BoxedIo::new))
@ -299,7 +325,7 @@ impl svc::Param<Remote<ServerAddr>> for Forward {
impl svc::Param<transport::labels::Key> for Forward {
fn param(&self) -> transport::labels::Key {
transport::labels::Key::inbound_server(
self.tls.clone(),
self.tls.as_ref().map(|t| t.labels()),
self.orig_dst_addr.into(),
self.permit.labels.server.clone(),
)
@ -332,14 +358,6 @@ impl svc::Param<tls::ConditionalServerTls> for Tls {
}
}
// === impl ConfigureHttpDetect ===
impl svc::ExtractParam<detect::Config<http::DetectHttp>, Detect> for ConfigureHttpDetect {
fn extract_param(&self, detect: &Detect) -> detect::Config<http::DetectHttp> {
detect::Config::from_timeout(detect.timeout)
}
}
// === impl Http ===
impl svc::Param<http::Variant> for Http {
@ -411,7 +429,7 @@ impl svc::Param<ServerLabel> for Http {
impl svc::Param<transport::labels::Key> for Http {
fn param(&self) -> transport::labels::Key {
transport::labels::Key::inbound_server(
self.tls.status.clone(),
self.tls.status.as_ref().map(|t| t.labels()),
self.tls.orig_dst_addr.into(),
self.tls.policy.server_label(),
)
@ -442,3 +460,13 @@ impl<T> svc::InsertParam<tls::ConditionalServerTls, T> for TlsParams {
(tls, target)
}
}
// === impl MetricsFamilies ===
impl MetricsFamilies {
pub fn register(reg: &mut prom::Registry) -> Self {
Self(http::DetectMetricsFamilies::register(
reg.sub_registry_with_prefix("http"),
))
}
}

View File

@ -13,6 +13,12 @@ const HTTP1: &[u8] = b"GET / HTTP/1.1\r\nhost: example.com\r\n\r\n";
const HTTP2: &[u8] = b"PRI * HTTP/2.0\r\n";
const NOT_HTTP: &[u8] = b"foo\r\nbar\r\nblah\r\n";
const RESULTS_NOT_HTTP: &str = "results_total{result=\"not_http\",srv_group=\"policy.linkerd.io\",srv_kind=\"server\",srv_name=\"testsrv\",srv_port=\"1000\"}";
const RESULTS_HTTP1: &str = "results_total{result=\"http/1\",srv_group=\"policy.linkerd.io\",srv_kind=\"server\",srv_name=\"testsrv\",srv_port=\"1000\"}";
const RESULTS_HTTP2: &str = "results_total{result=\"http/2\",srv_group=\"policy.linkerd.io\",srv_kind=\"server\",srv_name=\"testsrv\",srv_port=\"1000\"}";
const RESULTS_READ_TIMEOUT: &str = "results_total{result=\"read_timeout\",srv_group=\"policy.linkerd.io\",srv_kind=\"server\",srv_name=\"testsrv\",srv_port=\"1000\"}";
const RESULTS_ERROR: &str = "results_total{result=\"error\",srv_group=\"policy.linkerd.io\",srv_kind=\"server\",srv_name=\"testsrv\",srv_port=\"1000\"}";
fn authzs() -> Arc<[Authorization]> {
Arc::new([Authorization {
authentication: Authentication::Unauthenticated,
@ -41,6 +47,35 @@ fn allow(protocol: Protocol) -> AllowPolicy {
allow
}
macro_rules! assert_contains_metric {
($registry:expr, $metric:expr, $value:expr) => {{
let mut buf = String::new();
prom::encoding::text::encode_registry(&mut buf, $registry).expect("encode registry failed");
let lines = buf.split_terminator('\n').collect::<Vec<_>>();
assert_eq!(
lines.iter().find(|l| l.starts_with($metric)),
Some(&&*format!("{} {}", $metric, $value)),
"metric '{}' not found in:\n{:?}",
$metric,
buf
);
}};
}
macro_rules! assert_not_contains_metric {
($registry:expr, $pattern:expr) => {{
let mut buf = String::new();
prom::encoding::text::encode_registry(&mut buf, $registry).expect("encode registry failed");
let lines = buf.split_terminator('\n').collect::<Vec<_>>();
assert!(
!lines.iter().any(|l| l.starts_with($pattern)),
"metric '{}' found in:\n{:?}",
$pattern,
buf
);
}};
}
#[tokio::test(flavor = "current_thread")]
async fn detect_tls_opaque() {
let _trace = trace::test::trace_init();
@ -77,14 +112,21 @@ async fn detect_http_non_http() {
let (ior, mut iow) = io::duplex(100);
iow.write_all(NOT_HTTP).await.unwrap();
let mut registry = prom::Registry::default();
inbound()
.with_stack(new_panic("http stack must not be used"))
.push_detect_http(new_ok())
.push_detect_http(super::HttpDetectMetrics::register(&mut registry), new_ok())
.into_inner()
.new_service(target)
.oneshot(ior)
.await
.expect("should succeed");
assert_contains_metric!(&registry, RESULTS_NOT_HTTP, 1);
assert_contains_metric!(&registry, RESULTS_HTTP1, 0);
assert_contains_metric!(&registry, RESULTS_HTTP2, 0);
assert_contains_metric!(&registry, RESULTS_READ_TIMEOUT, 0);
assert_contains_metric!(&registry, RESULTS_ERROR, 0);
}
#[tokio::test(flavor = "current_thread")]
@ -108,14 +150,24 @@ async fn detect_http() {
let (ior, mut iow) = io::duplex(100);
iow.write_all(HTTP1).await.unwrap();
let mut registry = prom::Registry::default();
inbound()
.with_stack(new_ok())
.push_detect_http(new_panic("tcp stack must not be used"))
.push_detect_http(
super::HttpDetectMetrics::register(&mut registry),
new_panic("tcp stack must not be used"),
)
.into_inner()
.new_service(target)
.oneshot(ior)
.await
.expect("should succeed");
assert_contains_metric!(&registry, RESULTS_NOT_HTTP, 0);
assert_contains_metric!(&registry, RESULTS_HTTP1, 1);
assert_contains_metric!(&registry, RESULTS_HTTP2, 0);
assert_contains_metric!(&registry, RESULTS_READ_TIMEOUT, 0);
assert_contains_metric!(&registry, RESULTS_ERROR, 0);
}
#[tokio::test(flavor = "current_thread")]
@ -134,14 +186,24 @@ async fn hinted_http1() {
let (ior, mut iow) = io::duplex(100);
iow.write_all(HTTP1).await.unwrap();
let mut registry = prom::Registry::default();
inbound()
.with_stack(new_ok())
.push_detect_http(new_panic("tcp stack must not be used"))
.push_detect_http(
super::HttpDetectMetrics::register(&mut registry),
new_panic("tcp stack must not be used"),
)
.into_inner()
.new_service(target)
.oneshot(ior)
.await
.expect("should succeed");
assert_contains_metric!(&registry, RESULTS_NOT_HTTP, 0);
assert_contains_metric!(&registry, RESULTS_HTTP1, 1);
assert_contains_metric!(&registry, RESULTS_HTTP2, 0);
assert_contains_metric!(&registry, RESULTS_READ_TIMEOUT, 0);
assert_contains_metric!(&registry, RESULTS_ERROR, 0);
}
#[tokio::test(flavor = "current_thread")]
@ -160,14 +222,24 @@ async fn hinted_http1_supports_http2() {
let (ior, mut iow) = io::duplex(100);
iow.write_all(HTTP2).await.unwrap();
let mut registry = prom::Registry::default();
inbound()
.with_stack(new_ok())
.push_detect_http(new_panic("tcp stack must not be used"))
.push_detect_http(
super::HttpDetectMetrics::register(&mut registry),
new_panic("tcp stack must not be used"),
)
.into_inner()
.new_service(target)
.oneshot(ior)
.await
.expect("should succeed");
assert_contains_metric!(&registry, RESULTS_NOT_HTTP, 0);
assert_contains_metric!(&registry, RESULTS_HTTP1, 0);
assert_contains_metric!(&registry, RESULTS_HTTP2, 1);
assert_contains_metric!(&registry, RESULTS_READ_TIMEOUT, 0);
assert_contains_metric!(&registry, RESULTS_ERROR, 0);
}
#[tokio::test(flavor = "current_thread")]
@ -185,14 +257,25 @@ async fn hinted_http2() {
let (ior, _) = io::duplex(100);
let mut registry = prom::Registry::default();
inbound()
.with_stack(new_ok())
.push_detect_http(new_panic("tcp stack must not be used"))
.push_detect_http(
super::HttpDetectMetrics::register(&mut registry),
new_panic("tcp stack must not be used"),
)
.into_inner()
.new_service(target)
.oneshot(ior)
.await
.expect("should succeed");
// No detection is performed when HTTP/2 is hinted, so no metrics are recorded.
assert_not_contains_metric!(&registry, RESULTS_NOT_HTTP);
assert_not_contains_metric!(&registry, RESULTS_HTTP1);
assert_not_contains_metric!(&registry, RESULTS_HTTP2);
assert_not_contains_metric!(&registry, RESULTS_READ_TIMEOUT);
assert_not_contains_metric!(&registry, RESULTS_ERROR);
}
fn client_id() -> tls::ClientId {
@ -210,7 +293,11 @@ fn orig_dst_addr() -> OrigDstAddr {
}
fn inbound() -> Inbound<()> {
Inbound::new(test_util::default_config(), test_util::runtime().0)
Inbound::new(
test_util::default_config(),
test_util::runtime().0,
&mut Default::default(),
)
}
fn new_panic<T, I: 'static>(msg: &'static str) -> svc::ArcNewTcp<T, I> {

View File

@ -15,6 +15,10 @@ use std::fmt::Debug;
use thiserror::Error;
use tracing::{debug_span, info_span};
mod metrics;
pub use self::metrics::MetricsFamilies;
/// Creates I/O errors when a connection cannot be forwarded because no transport
/// header was present.
#[derive(Debug, Default)]
@ -25,8 +29,8 @@ struct RefusedNoHeader;
pub struct RefusedNoIdentity(());
#[derive(Debug, Error)]
#[error("a named target must be provided on gateway connections")]
struct RefusedNoTarget;
#[error("direct connections require transport header negotiation")]
struct TransportHeaderRequired(());
#[derive(Debug, Clone)]
pub(crate) struct LocalTcp {
@ -93,7 +97,7 @@ impl<N> Inbound<N> {
self,
policies: impl policy::GetPolicy + Clone + Send + Sync + 'static,
gateway: svc::ArcNewTcp<GatewayTransportHeader, GatewayIo<I>>,
http: svc::ArcNewTcp<LocalHttp, io::PrefixedIo<TlsIo<I>>>,
http: svc::ArcNewTcp<LocalHttp, SensorIo<io::PrefixedIo<TlsIo<I>>>>,
) -> Inbound<svc::ArcNewTcp<T, I>>
where
T: Param<Remote<ClientAddr>> + Param<OrigDstAddr>,
@ -108,11 +112,12 @@ impl<N> Inbound<N> {
{
self.map_stack(|config, rt, inner| {
let detect_timeout = config.proxy.detect_protocol_timeout;
let metrics = rt.metrics.direct.clone();
let identity = rt
.identity
.server()
.with_alpn(vec![transport_header::PROTOCOL.into()])
.spawn_with_alpn(vec![transport_header::PROTOCOL.into()])
.expect("TLS credential store must be held");
inner
@ -135,7 +140,14 @@ impl<N> Inbound<N> {
// forwarding, or we may be processing an HTTP gateway connection. HTTP gateway
// connections that have a transport header must provide a target name as a part of
// the header.
.push_switch(Ok::<Local, Infallible>, http)
.push_switch(
Ok::<Local, Infallible>,
svc::stack(http)
.push(transport::metrics::NewServer::layer(
rt.metrics.proxy.transport.clone(),
))
.into_inner(),
)
.push_switch(
{
let policies = policies.clone();
@ -145,14 +157,14 @@ impl<N> Inbound<N> {
port,
name: None,
protocol,
} => Ok(svc::Either::A({
} => Ok(svc::Either::Left({
// When the transport header targets an alternate port (but does
// not identify an alternate target name), we check the new
// target's policy (rather than the inbound proxy's address).
let addr = (client.local_addr.ip(), port).into();
let policy = policies.get_policy(OrigDstAddr(addr));
match protocol {
None => svc::Either::A(LocalTcp {
None => svc::Either::Left(LocalTcp {
server_addr: Remote(ServerAddr(addr)),
client_addr: client.client_addr,
client_id: client.client_id,
@ -162,7 +174,7 @@ impl<N> Inbound<N> {
// When TransportHeader includes the protocol, but does not
// include an alternate name we go through the Inbound HTTP
// stack.
svc::Either::B(LocalHttp {
svc::Either::Right(LocalHttp {
addr: Remote(ServerAddr(addr)),
policy,
protocol,
@ -176,7 +188,7 @@ impl<N> Inbound<N> {
port,
name: Some(name),
protocol,
} => Ok(svc::Either::B({
} => Ok(svc::Either::Right({
// When the transport header provides an alternate target, the
// connection is a gateway connection. We check the _gateway
// address's_ policy (rather than the target address).
@ -204,6 +216,7 @@ impl<N> Inbound<N> {
)
.check_new_service::<(TransportHeader, ClientInfo), _>()
// Use ALPN to determine whether a transport header should be read.
.push(metrics::NewRecord::layer(metrics))
.push(svc::ArcNewService::layer())
.push(NewTransportHeaderServer::layer(detect_timeout))
.check_new_service::<ClientInfo, _>()
@ -215,7 +228,7 @@ impl<N> Inbound<N> {
if client.header_negotiated() {
Ok(client)
} else {
Err(RefusedNoTarget.into())
Err(TransportHeaderRequired(()).into())
}
})
.push(svc::ArcNewService::layer())
@ -298,9 +311,8 @@ impl Param<Remote<ServerAddr>> for AuthorizedLocalTcp {
impl Param<transport::labels::Key> for AuthorizedLocalTcp {
fn param(&self) -> transport::labels::Key {
transport::labels::Key::inbound_server(
tls::ConditionalServerTls::Some(tls::ServerTls::Established {
tls::ConditionalServerTlsLabels::Some(tls::ServerTlsLabels::Established {
client_id: Some(self.client_id.clone()),
negotiated_protocol: None,
}),
self.addr.into(),
self.permit.labels.server.clone(),
@ -331,9 +343,8 @@ impl Param<Remote<ClientAddr>> for LocalHttp {
impl Param<transport::labels::Key> for LocalHttp {
fn param(&self) -> transport::labels::Key {
transport::labels::Key::inbound_server(
tls::ConditionalServerTls::Some(tls::ServerTls::Established {
tls::ConditionalServerTlsLabels::Some(tls::ServerTlsLabels::Established {
client_id: Some(self.client.client_id.clone()),
negotiated_protocol: None,
}),
self.addr.into(),
self.policy.server_label(),
@ -422,6 +433,14 @@ impl Param<tls::ConditionalServerTls> for GatewayTransportHeader {
}
}
impl Param<tls::ConditionalServerTlsLabels> for GatewayTransportHeader {
fn param(&self) -> tls::ConditionalServerTlsLabels {
tls::ConditionalServerTlsLabels::Some(tls::ServerTlsLabels::Established {
client_id: Some(self.client.client_id.clone()),
})
}
}
impl Param<tls::ClientId> for GatewayTransportHeader {
fn param(&self) -> tls::ClientId {
self.client.client_id.clone()

View File

@ -0,0 +1,91 @@
use super::ClientInfo;
use linkerd_app_core::{
metrics::prom::{self, EncodeLabelSetMut},
svc, tls,
transport_header::{SessionProtocol, TransportHeader},
};
#[cfg(test)]
mod tests;
#[derive(Clone, Debug)]
pub struct NewRecord<N> {
inner: N,
metrics: MetricsFamilies,
}
#[derive(Clone, Debug, Default)]
pub struct MetricsFamilies {
connections: prom::Family<Labels, prom::Counter>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
struct Labels {
header: TransportHeader,
client_id: tls::ClientId,
}
impl MetricsFamilies {
pub fn register(reg: &mut prom::Registry) -> Self {
let connections = prom::Family::default();
reg.register(
"connections",
"TCP connections with transport headers",
connections.clone(),
);
Self { connections }
}
}
impl<N> NewRecord<N> {
pub fn layer(metrics: MetricsFamilies) -> impl svc::layer::Layer<N, Service = Self> + Clone {
svc::layer::mk(move |inner| Self {
inner,
metrics: metrics.clone(),
})
}
}
impl<N> svc::NewService<(TransportHeader, ClientInfo)> for NewRecord<N>
where
N: svc::NewService<(TransportHeader, ClientInfo)>,
{
type Service = N::Service;
fn new_service(&self, (header, client): (TransportHeader, ClientInfo)) -> Self::Service {
self.metrics
.connections
.get_or_create(&Labels {
header: header.clone(),
client_id: client.client_id.clone(),
})
.inc();
self.inner.new_service((header, client))
}
}
impl prom::EncodeLabelSetMut for Labels {
fn encode_label_set(&self, enc: &mut prom::encoding::LabelSetEncoder<'_>) -> std::fmt::Result {
use prom::encoding::EncodeLabel;
(
"session_protocol",
self.header.protocol.as_ref().map(|p| match p {
SessionProtocol::Http1 => "http/1",
SessionProtocol::Http2 => "http/2",
}),
)
.encode(enc.encode_label())?;
("target_port", self.header.port).encode(enc.encode_label())?;
("target_name", self.header.name.as_deref()).encode(enc.encode_label())?;
("client_id", self.client_id.to_str()).encode(enc.encode_label())?;
Ok(())
}
}
impl prom::encoding::EncodeLabelSet for Labels {
fn encode(&self, mut enc: prom::encoding::LabelSetEncoder<'_>) -> Result<(), std::fmt::Error> {
self.encode_label_set(&mut enc)
}
}

View File

@ -0,0 +1,115 @@
use super::*;
use crate::direct::ClientInfo;
use futures::future;
use linkerd_app_core::{
io,
metrics::prom,
svc, tls,
transport::addrs::{ClientAddr, OrigDstAddr, Remote},
transport_header::{SessionProtocol, TransportHeader},
Error,
};
use std::str::FromStr;
fn new_ok<T>() -> svc::ArcNewTcp<T, io::BoxedIo> {
svc::ArcNewService::new(|_| svc::BoxService::new(svc::mk(|_| future::ok::<(), Error>(()))))
}
macro_rules! assert_counted {
($registry:expr, $proto:expr, $port:expr, $name:expr, $value:expr) => {{
let mut buf = String::new();
prom::encoding::text::encode_registry(&mut buf, $registry).expect("encode registry failed");
let metric = format!("connections_total{{session_protocol=\"{}\",target_port=\"{}\",target_name=\"{}\",client_id=\"test.client\"}}", $proto, $port, $name);
assert_eq!(
buf.split_terminator('\n')
.find(|l| l.starts_with(&*metric)),
Some(&*format!("{metric} {}", $value)),
"metric '{metric}' not found in:\n{buf}"
);
}};
}
// Added helper to setup and run the test
fn run_metric_test(header: TransportHeader) -> prom::Registry {
let mut registry = prom::Registry::default();
let families = MetricsFamilies::register(&mut registry);
let new_record = svc::layer::Layer::layer(&NewRecord::layer(families.clone()), new_ok());
// common client info
let client_id = tls::ClientId::from_str("test.client").unwrap();
let client_addr = Remote(ClientAddr(([127, 0, 0, 1], 40000).into()));
let local_addr = OrigDstAddr(([127, 0, 0, 1], 4143).into());
let client_info = ClientInfo {
client_id: client_id.clone(),
alpn: Some(tls::NegotiatedProtocol("transport.l5d.io/v1".into())),
client_addr,
local_addr,
};
let _svc = svc::NewService::new_service(&new_record, (header.clone(), client_info.clone()));
registry
}
#[test]
fn records_metrics_http1_local() {
let header = TransportHeader {
port: 8080,
name: None,
protocol: Some(SessionProtocol::Http1),
};
let registry = run_metric_test(header);
assert_counted!(&registry, "http/1", 8080, "", 1);
}
#[test]
fn records_metrics_http2_local() {
let header = TransportHeader {
port: 8081,
name: None,
protocol: Some(SessionProtocol::Http2),
};
let registry = run_metric_test(header);
assert_counted!(&registry, "http/2", 8081, "", 1);
}
#[test]
fn records_metrics_opaq_local() {
let header = TransportHeader {
port: 8082,
name: None,
protocol: None,
};
let registry = run_metric_test(header);
assert_counted!(&registry, "", 8082, "", 1);
}
#[test]
fn records_metrics_http1_gateway() {
let header = TransportHeader {
port: 8080,
name: Some("mysvc.myns.svc.cluster.local".parse().unwrap()),
protocol: Some(SessionProtocol::Http1),
};
let registry = run_metric_test(header);
assert_counted!(&registry, "http/1", 8080, "mysvc.myns.svc.cluster.local", 1);
}
#[test]
fn records_metrics_http2_gateway() {
let header = TransportHeader {
port: 8081,
name: Some("mysvc.myns.svc.cluster.local".parse().unwrap()),
protocol: Some(SessionProtocol::Http2),
};
let registry = run_metric_test(header);
assert_counted!(&registry, "http/2", 8081, "mysvc.myns.svc.cluster.local", 1);
}
#[test]
fn records_metrics_opaq_gateway() {
let header = TransportHeader {
port: 8082,
name: Some("mysvc.myns.svc.cluster.local".parse().unwrap()),
protocol: None,
};
let registry = run_metric_test(header);
assert_counted!(&registry, "", 8082, "mysvc.myns.svc.cluster.local", 1);
}

View File

@ -238,11 +238,14 @@ pub mod fuzz {
impl svc::Param<policy::ServerLabel> for Target {
fn param(&self) -> policy::ServerLabel {
policy::ServerLabel(Arc::new(policy::Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "testsrv".into(),
}))
policy::ServerLabel(
Arc::new(policy::Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "testsrv".into(),
}),
1000,
)
}
}

View File

@ -83,6 +83,7 @@ impl<C> Inbound<C> {
{
self.map_stack(|config, rt, connect| {
let allow_profile = config.allow_discovery.clone();
let unsafe_authority_labels = config.unsafe_authority_labels;
let h1_params = config.proxy.connect.http1;
let h2_params = config.proxy.connect.http2.clone();
@ -122,7 +123,9 @@ impl<C> Inbound<C> {
rt.metrics
.proxy
.http_endpoint
.to_layer::<classify::Response, _, _>(),
.to_layer_via::<classify::Response, _, _, _>(
endpoint_labels(unsafe_authority_labels),
),
)
.push_on_service(http_tracing::client(rt.span_sink.clone(), super::trace_labels()))
.push_on_service(http::BoxResponse::layer())
@ -163,14 +166,14 @@ impl<C> Inbound<C> {
|(rx, logical): (Option<profiles::Receiver>, Logical)| -> Result<_, Infallible> {
if let Some(rx) = rx {
if let Some(addr) = rx.logical_addr() {
return Ok(svc::Either::A(Profile {
return Ok(svc::Either::Left(Profile {
addr,
logical,
profiles: rx,
}));
}
}
Ok(svc::Either::B(logical))
Ok(svc::Either::Right(logical))
},
http.clone().into_inner(),
)
@ -189,7 +192,7 @@ impl<C> Inbound<C> {
// discovery (so that we skip the profile stack above).
let addr = match logical.logical.clone() {
Some(addr) => addr,
None => return Ok(svc::Either::B((None, logical))),
None => return Ok(svc::Either::Right((None, logical))),
};
if !allow_profile.matches(addr.name()) {
tracing::debug!(
@ -197,9 +200,9 @@ impl<C> Inbound<C> {
suffixes = %allow_profile,
"Skipping discovery, address not in configured DNS suffixes",
);
return Ok(svc::Either::B((None, logical)));
return Ok(svc::Either::Right((None, logical)));
}
Ok(svc::Either::A(logical))
Ok(svc::Either::Left(logical))
},
router
.check_new_service::<(Option<profiles::Receiver>, Logical), http::Request<_>>()
@ -387,12 +390,17 @@ impl Param<transport::labels::Key> for Logical {
}
}
impl Param<metrics::EndpointLabels> for Logical {
fn param(&self) -> metrics::EndpointLabels {
fn endpoint_labels(
unsafe_authority_labels: bool,
) -> impl svc::ExtractParam<metrics::EndpointLabels, Logical> + Clone {
move |t: &Logical| -> metrics::EndpointLabels {
metrics::InboundEndpointLabels {
tls: self.tls.clone(),
target_addr: self.addr.into(),
policy: self.permit.labels.clone(),
tls: t.tls.as_ref().map(|t| t.labels()),
authority: unsafe_authority_labels
.then(|| t.logical.as_ref().map(|d| d.as_http_authority()))
.flatten(),
target_addr: t.addr.into(),
policy: t.permit.labels.clone(),
}
.into()
}

View File

@ -11,8 +11,8 @@ use linkerd_app_core::{
classify,
errors::header::L5D_PROXY_ERROR,
identity, io, metrics,
proxy::http::{self, Body as _, BoxBody},
svc::{self, http::TracingExecutor, NewService, Param},
proxy::http::{self, BoxBody},
svc::{self, http::TokioExecutor, NewService, Param},
tls,
transport::{ClientAddr, OrigDstAddr, Remote, ServerAddr},
Error, NameAddr, ProxyRuntime,
@ -33,7 +33,7 @@ fn build_server<I>(
where
I: io::AsyncRead + io::AsyncWrite + io::PeerAddr + Send + Unpin + 'static,
{
Inbound::new(cfg, rt)
Inbound::new(cfg, rt, &mut Default::default())
.with_stack(connect)
.map_stack(|cfg, _, s| {
s.push_map_target(|t| Param::<Remote<ServerAddr>>::param(&t))
@ -47,8 +47,10 @@ where
#[tokio::test(flavor = "current_thread")]
async fn unmeshed_http1_hello_world() {
let server = hyper::server::conn::http1::Builder::new();
let mut server = hyper::server::conn::http1::Builder::new();
server.timer(hyper_util::rt::TokioTimer::new());
let mut client = hyper::client::conn::http1::Builder::new();
let _trace = trace_init();
// Build a mock "connector" that returns the upstream "server" IO.
@ -68,7 +70,7 @@ async fn unmeshed_http1_hello_world() {
let req = Request::builder()
.method(http::Method::GET)
.uri("http://foo.svc.cluster.local:5550")
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap();
let rsp = client
.send_request(req)
@ -91,8 +93,10 @@ async fn unmeshed_http1_hello_world() {
#[tokio::test(flavor = "current_thread")]
async fn downgrade_origin_form() {
// Reproduces https://github.com/linkerd/linkerd2/issues/5298
let server = hyper::server::conn::http1::Builder::new();
let client = hyper::client::conn::http2::Builder::new(TracingExecutor);
let mut server = hyper::server::conn::http1::Builder::new();
server.timer(hyper_util::rt::TokioTimer::new());
let mut client = hyper::client::conn::http2::Builder::new(TokioExecutor::new());
client.timer(hyper_util::rt::TokioTimer::new());
let _trace = trace_init();
// Build a mock "connector" that returns the upstream "server" IO.
@ -112,7 +116,7 @@ async fn downgrade_origin_form() {
let (client_io, server_io) = io::duplex(4096);
let (client, conn) = client
.handshake(client_io)
.handshake(hyper_util::rt::TokioIo::new(client_io))
.await
.expect("Client must connect");
@ -142,7 +146,7 @@ async fn downgrade_origin_form() {
.uri("/")
.header(http::header::HOST, "foo.svc.cluster.local")
.header("l5d-orig-proto", "HTTP/1.1")
.body(hyper::Body::default())
.body(BoxBody::empty())
.unwrap();
let rsp = client
.send_request(req)
@ -164,8 +168,10 @@ async fn downgrade_origin_form() {
#[tokio::test(flavor = "current_thread")]
async fn downgrade_absolute_form() {
let client = hyper::client::conn::http2::Builder::new(TracingExecutor);
let server = hyper::server::conn::http1::Builder::new();
let mut client = hyper::client::conn::http2::Builder::new(TokioExecutor::new());
client.timer(hyper_util::rt::TokioTimer::new());
let mut server = hyper::server::conn::http1::Builder::new();
server.timer(hyper_util::rt::TokioTimer::new());
let _trace = trace_init();
// Build a mock "connector" that returns the upstream "server" IO.
@ -186,7 +192,7 @@ async fn downgrade_absolute_form() {
let (client_io, server_io) = io::duplex(4096);
let (client, conn) = client
.handshake(client_io)
.handshake(hyper_util::rt::TokioIo::new(client_io))
.await
.expect("Client must connect");
@ -216,7 +222,7 @@ async fn downgrade_absolute_form() {
.uri("http://foo.svc.cluster.local:5550/")
.header(http::header::HOST, "foo.svc.cluster.local")
.header("l5d-orig-proto", "HTTP/1.1; absolute-form")
.body(hyper::Body::default())
.body(BoxBody::empty())
.unwrap();
let rsp = client
.send_request(req)
@ -260,7 +266,7 @@ async fn http1_bad_gateway_meshed_response_error_header() {
let req = Request::builder()
.method(http::Method::GET)
.uri("http://foo.svc.cluster.local:5550")
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap();
let rsp = client
.send_request(req)
@ -272,7 +278,7 @@ async fn http1_bad_gateway_meshed_response_error_header() {
// because we don't build a real HTTP endpoint stack, which adds error
// context to this error, and the client rescue layer is below where the
// logical error context is added.
check_error_header(rsp.headers(), "server is not listening");
check_error_header(rsp.headers(), "client error (Connect)");
// Wait for all of the background tasks to complete, panicking if any returned an error.
drop(client);
@ -307,7 +313,7 @@ async fn http1_bad_gateway_unmeshed_response() {
let req = Request::builder()
.method(http::Method::GET)
.uri("http://foo.svc.cluster.local:5550")
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap();
let rsp = client
.send_request(req)
@ -355,7 +361,7 @@ async fn http1_connect_timeout_meshed_response_error_header() {
let req = Request::builder()
.method(http::Method::GET)
.uri("http://foo.svc.cluster.local:5550")
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap();
let rsp = client
.send_request(req)
@ -368,7 +374,7 @@ async fn http1_connect_timeout_meshed_response_error_header() {
// because we don't build a real HTTP endpoint stack, which adds error
// context to this error, and the client rescue layer is below where the
// logical error context is added.
check_error_header(rsp.headers(), "connect timed out after 1s");
check_error_header(rsp.headers(), "client error (Connect)");
// Wait for all of the background tasks to complete, panicking if any returned an error.
drop(client);
@ -405,7 +411,7 @@ async fn http1_connect_timeout_unmeshed_response_error_header() {
let req = Request::builder()
.method(http::Method::GET)
.uri("http://foo.svc.cluster.local:5550")
.body(hyper::Body::default())
.body(BoxBody::empty())
.unwrap();
let rsp = client
.send_request(req)
@ -435,7 +441,8 @@ async fn h2_response_meshed_error_header() {
let connect = support::connect().endpoint_fn_boxed(Target::addr(), connect_error());
// Build a client using the connect that always errors.
let mut client = hyper::client::conn::http2::Builder::new(TracingExecutor);
let mut client = hyper::client::conn::http2::Builder::new(TokioExecutor::new());
client.timer(hyper_util::rt::TokioTimer::new());
let profiles = profile::resolver();
let profile_tx =
profiles.profile_tx(NameAddr::from_str_and_port("foo.svc.cluster.local", 5550).unwrap());
@ -450,7 +457,7 @@ async fn h2_response_meshed_error_header() {
let req = Request::builder()
.method(http::Method::GET)
.uri("http://foo.svc.cluster.local:5550")
.body(hyper::Body::default())
.body(BoxBody::empty())
.unwrap();
let rsp = client
.send_request(req)
@ -475,7 +482,8 @@ async fn h2_response_unmeshed_error_header() {
let connect = support::connect().endpoint_fn_boxed(Target::addr(), connect_error());
// Build a client using the connect that always errors.
let mut client = hyper::client::conn::http2::Builder::new(TracingExecutor);
let mut client = hyper::client::conn::http2::Builder::new(TokioExecutor::new());
client.timer(hyper_util::rt::TokioTimer::new());
let profiles = profile::resolver();
let profile_tx =
profiles.profile_tx(NameAddr::from_str_and_port("foo.svc.cluster.local", 5550).unwrap());
@ -490,7 +498,7 @@ async fn h2_response_unmeshed_error_header() {
let req = Request::builder()
.method(http::Method::GET)
.uri("http://foo.svc.cluster.local:5550")
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap();
let rsp = client
.send_request(req)
@ -517,7 +525,8 @@ async fn grpc_meshed_response_error_header() {
let connect = support::connect().endpoint_fn_boxed(Target::addr(), connect_error());
// Build a client using the connect that always errors.
let mut client = hyper::client::conn::http2::Builder::new(TracingExecutor);
let mut client = hyper::client::conn::http2::Builder::new(TokioExecutor::new());
client.timer(hyper_util::rt::TokioTimer::new());
let profiles = profile::resolver();
let profile_tx =
profiles.profile_tx(NameAddr::from_str_and_port("foo.svc.cluster.local", 5550).unwrap());
@ -533,7 +542,7 @@ async fn grpc_meshed_response_error_header() {
.method(http::Method::GET)
.uri("http://foo.svc.cluster.local:5550")
.header(http::header::CONTENT_TYPE, "application/grpc")
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap();
let rsp = client
.send_request(req)
@ -558,7 +567,8 @@ async fn grpc_unmeshed_response_error_header() {
let connect = support::connect().endpoint_fn_boxed(Target::addr(), connect_error());
// Build a client using the connect that always errors.
let mut client = hyper::client::conn::http2::Builder::new(TracingExecutor);
let mut client = hyper::client::conn::http2::Builder::new(TokioExecutor::new());
client.timer(hyper_util::rt::TokioTimer::new());
let profiles = profile::resolver();
let profile_tx =
profiles.profile_tx(NameAddr::from_str_and_port("foo.svc.cluster.local", 5550).unwrap());
@ -574,7 +584,7 @@ async fn grpc_unmeshed_response_error_header() {
.method(http::Method::GET)
.uri("http://foo.svc.cluster.local:5550")
.header(http::header::CONTENT_TYPE, "application/grpc")
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap();
let rsp = client
.send_request(req)
@ -599,7 +609,8 @@ async fn grpc_response_class() {
// Build a mock connector serves a gRPC server that returns errors.
let connect = {
let server = hyper::server::conn::http2::Builder::new(TracingExecutor);
let mut server = hyper::server::conn::http2::Builder::new(TokioExecutor::new());
server.timer(hyper_util::rt::TokioTimer::new());
support::connect().endpoint_fn_boxed(
Target::addr(),
grpc_status_server(server, tonic::Code::Unknown),
@ -607,7 +618,8 @@ async fn grpc_response_class() {
};
// Build a client using the connect that always errors.
let mut client = hyper::client::conn::http2::Builder::new(TracingExecutor);
let mut client = hyper::client::conn::http2::Builder::new(TokioExecutor::new());
client.timer(hyper_util::rt::TokioTimer::new());
let profiles = profile::resolver();
let profile_tx =
profiles.profile_tx(NameAddr::from_str_and_port("foo.svc.cluster.local", 5550).unwrap());
@ -628,32 +640,43 @@ async fn grpc_response_class() {
.method(http::Method::POST)
.uri("http://foo.svc.cluster.local:5550")
.header(http::header::CONTENT_TYPE, "application/grpc")
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap();
let mut rsp = client
let rsp = client
.send_request(req)
.await
.expect("HTTP client request failed");
tracing::info!(?rsp);
assert_eq!(rsp.status(), http::StatusCode::OK);
rsp.body_mut().data().await;
let trls = rsp.body_mut().trailers().await.unwrap().unwrap();
use http_body_util::BodyExt;
let mut body = rsp.into_body();
let trls = body
.frame()
.await
.unwrap()
.unwrap()
.into_trailers()
.expect("trailers frame");
assert_eq!(trls.get("grpc-status").unwrap().to_str().unwrap(), "2");
let response_total = metrics
.get_response_total(
&metrics::EndpointLabels::Inbound(metrics::InboundEndpointLabels {
tls: Target::meshed_h2().1,
tls: Target::meshed_h2().1.map(|t| t.labels()),
authority: None,
target_addr: "127.0.0.1:80".parse().unwrap(),
policy: metrics::RouteAuthzLabels {
route: metrics::RouteLabels {
server: metrics::ServerLabel(Arc::new(policy::Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "testsrv".into(),
})),
server: metrics::ServerLabel(
Arc::new(policy::Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "testsrv".into(),
}),
80,
),
route: policy::Meta::new_default("default"),
},
authz: Arc::new(policy::Meta::Resource {
@ -672,6 +695,104 @@ async fn grpc_response_class() {
drop(bg);
}
#[tokio::test(flavor = "current_thread")]
async fn unsafe_authority_labels_true() {
let _trace = trace_init();
let mut cfg = default_config();
cfg.unsafe_authority_labels = true;
test_unsafe_authority_labels(cfg, Some("foo.svc.cluster.local:5550".parse().unwrap())).await;
}
#[tokio::test(flavor = "current_thread")]
async fn unsafe_authority_labels_false() {
let _trace = trace_init();
let cfg = default_config();
test_unsafe_authority_labels(cfg, None).await;
}
async fn test_unsafe_authority_labels(
cfg: Config,
expected_authority: Option<http::uri::Authority>,
) {
let connect = {
let mut server = hyper::server::conn::http1::Builder::new();
server.timer(hyper_util::rt::TokioTimer::new());
support::connect().endpoint_fn_boxed(Target::addr(), hello_server(server))
};
// Build a client using the connect that always errors.
let mut client = hyper::client::conn::http1::Builder::new();
let profiles = profile::resolver();
let profile_tx =
profiles.profile_tx(NameAddr::from_str_and_port("foo.svc.cluster.local", 5550).unwrap());
profile_tx.send(profile::Profile::default()).unwrap();
let (rt, _shutdown) = runtime();
let metrics = rt
.metrics
.clone()
.http_endpoint
.into_report(time::Duration::from_secs(3600));
let server = build_server(cfg, rt, profiles, connect).new_service(Target::meshed_http1());
let (mut client, bg) = http_util::connect_and_accept_http1(&mut client, server).await;
// Send a request and assert that it is OK with the expected header
// message.
let req = Request::builder()
.method(http::Method::POST)
.uri("http://foo.svc.cluster.local:5550")
.header(http::header::CONTENT_TYPE, "text/plain")
.body(BoxBody::default())
.unwrap();
let rsp = client
.send_request(req)
.await
.expect("HTTP client request failed");
tracing::info!(?rsp);
assert_eq!(rsp.status(), http::StatusCode::OK);
use http_body_util::BodyExt;
let mut body = rsp.into_body();
while let Some(Ok(_)) = body.frame().await {}
tracing::info!("{metrics:#?}");
let response_total = metrics
.get_response_total(
&metrics::EndpointLabels::Inbound(metrics::InboundEndpointLabels {
tls: Target::meshed_http1().1.as_ref().map(|t| t.labels()),
authority: expected_authority,
target_addr: "127.0.0.1:80".parse().unwrap(),
policy: metrics::RouteAuthzLabels {
route: metrics::RouteLabels {
server: metrics::ServerLabel(
Arc::new(policy::Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "testsrv".into(),
}),
80,
),
route: policy::Meta::new_default("default"),
},
authz: Arc::new(policy::Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "serverauthorization".into(),
name: "testsaz".into(),
}),
},
}),
Some(http::StatusCode::OK),
&classify::Class::Http(Ok(http::StatusCode::OK)),
)
.expect("response_total not found");
assert_eq!(response_total, 1.0);
drop(bg);
}
#[tracing::instrument]
fn hello_server(
server: hyper::server::conn::http1::Builder,
@ -681,13 +802,14 @@ fn hello_server(
let _e = span.enter();
tracing::info!("mock connecting");
let (client_io, server_io) = support::io::duplex(4096);
let hello_svc = hyper::service::service_fn(|request: Request<hyper::Body>| async move {
tracing::info!(?request);
Ok::<_, io::Error>(Response::new(BoxBody::from_static("Hello world!")))
});
let hello_svc =
hyper::service::service_fn(|request: Request<hyper::body::Incoming>| async move {
tracing::info!(?request);
Ok::<_, io::Error>(Response::new(BoxBody::from_static("Hello world!")))
});
tokio::spawn(
server
.serve_connection(server_io, hello_svc)
.serve_connection(hyper_util::rt::TokioIo::new(server_io), hello_svc)
.in_current_span(),
);
Ok(io::BoxedIo::new(client_io))
@ -696,7 +818,7 @@ fn hello_server(
#[tracing::instrument]
fn grpc_status_server(
server: hyper::server::conn::http2::Builder<TracingExecutor>,
server: hyper::server::conn::http2::Builder<TokioExecutor>,
status: tonic::Code,
) -> impl Fn(Remote<ServerAddr>) -> io::Result<io::BoxedIo> {
move |endpoint| {
@ -707,26 +829,29 @@ fn grpc_status_server(
tokio::spawn(
server
.serve_connection(
server_io,
hyper::service::service_fn(move |request: Request<hyper::Body>| async move {
tracing::info!(?request);
let (mut tx, rx) = hyper::Body::channel();
tokio::spawn(async move {
let mut trls = ::http::HeaderMap::new();
trls.insert(
"grpc-status",
(status as u32).to_string().parse().unwrap(),
);
tx.send_trailers(trls).await
});
Ok::<_, io::Error>(
http::Response::builder()
.version(::http::Version::HTTP_2)
.header("content-type", "application/grpc")
.body(rx)
.unwrap(),
)
}),
hyper_util::rt::TokioIo::new(server_io),
hyper::service::service_fn(
move |request: Request<hyper::body::Incoming>| async move {
tracing::info!(?request);
let (mut tx, rx) =
http_body_util::channel::Channel::<bytes::Bytes, Error>::new(1024);
tokio::spawn(async move {
let mut trls = ::http::HeaderMap::new();
trls.insert(
"grpc-status",
(status as u32).to_string().parse().unwrap(),
);
tx.send_trailers(trls).await
});
Ok::<_, io::Error>(
http::Response::builder()
.version(::http::Version::HTTP_2)
.header("content-type", "application/grpc")
.body(rx)
.unwrap(),
)
},
),
)
.in_current_span(),
);
@ -736,12 +861,7 @@ fn grpc_status_server(
#[tracing::instrument]
fn connect_error() -> impl Fn(Remote<ServerAddr>) -> io::Result<io::BoxedIo> {
move |_| {
Err(io::Error::new(
io::ErrorKind::Other,
"server is not listening",
))
}
move |_| Err(io::Error::other("server is not listening"))
}
#[tracing::instrument]
@ -883,11 +1003,14 @@ impl svc::Param<policy::AllowPolicy> for Target {
impl svc::Param<policy::ServerLabel> for Target {
fn param(&self) -> policy::ServerLabel {
policy::ServerLabel(Arc::new(policy::Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "testsrv".into(),
}))
policy::ServerLabel(
Arc::new(policy::Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "testsrv".into(),
}),
80,
)
}
}

View File

@ -20,12 +20,15 @@ pub mod test_util;
#[cfg(fuzzing)]
pub use self::http::fuzz as http_fuzz;
pub use self::{metrics::InboundMetrics, policy::DefaultPolicy};
pub use self::{
detect::MetricsFamilies as DetectMetrics, metrics::InboundMetrics, policy::DefaultPolicy,
};
use linkerd_app_core::{
config::{ConnectConfig, ProxyConfig, QueueConfig},
drain,
http_tracing::SpanSink,
identity, io,
metrics::prom,
proxy::{tap, tcp},
svc,
transport::{self, Remote, ServerAddr},
@ -52,6 +55,9 @@ pub struct Config {
/// Configures how HTTP requests are buffered *for each inbound port*.
pub http_request_queue: QueueConfig,
/// Enables unsafe authority labels.
pub unsafe_authority_labels: bool,
}
#[derive(Clone)]
@ -107,10 +113,6 @@ impl<S> Inbound<S> {
&self.runtime.identity
}
pub fn proxy_metrics(&self) -> &metrics::Proxy {
&self.runtime.metrics.proxy
}
/// A helper for gateways to instrument policy checks.
pub fn authorize_http<N>(
&self,
@ -148,9 +150,9 @@ impl<S> Inbound<S> {
}
impl Inbound<()> {
pub fn new(config: Config, runtime: ProxyRuntime) -> Self {
pub fn new(config: Config, runtime: ProxyRuntime, prom: &mut prom::Registry) -> Self {
let runtime = Runtime {
metrics: InboundMetrics::new(runtime.metrics),
metrics: InboundMetrics::new(runtime.metrics, prom),
identity: runtime.identity,
tap: runtime.tap,
span_sink: runtime.span_sink,
@ -166,7 +168,11 @@ impl Inbound<()> {
#[cfg(any(test, feature = "test-util"))]
pub fn for_test() -> (Self, drain::Signal) {
let (rt, drain) = test_util::runtime();
let this = Self::new(test_util::default_config(), rt);
let this = Self::new(
test_util::default_config(),
rt,
&mut prom::Registry::default(),
);
(this, drain)
}

View File

@ -13,7 +13,7 @@ pub(crate) mod error;
pub use linkerd_app_core::metrics::*;
/// Holds outbound proxy metrics.
/// Holds LEGACY inbound proxy metrics.
#[derive(Clone, Debug)]
pub struct InboundMetrics {
pub http_authz: authz::HttpAuthzMetrics,
@ -25,21 +25,32 @@ pub struct InboundMetrics {
/// Holds metrics that are common to both inbound and outbound proxies. These metrics are
/// reported separately
pub proxy: Proxy,
pub detect: crate::detect::MetricsFamilies,
pub direct: crate::direct::MetricsFamilies,
}
impl InboundMetrics {
pub(crate) fn new(proxy: Proxy) -> Self {
pub(crate) fn new(proxy: Proxy, reg: &mut prom::Registry) -> Self {
let detect =
crate::detect::MetricsFamilies::register(reg.sub_registry_with_prefix("tcp_detect"));
let direct = crate::direct::MetricsFamilies::register(
reg.sub_registry_with_prefix("tcp_transport_header"),
);
Self {
http_authz: authz::HttpAuthzMetrics::default(),
http_errors: error::HttpErrorMetrics::default(),
tcp_authz: authz::TcpAuthzMetrics::default(),
tcp_errors: error::TcpErrorMetrics::default(),
proxy,
detect,
direct,
}
}
}
impl FmtMetrics for InboundMetrics {
impl legacy::FmtMetrics for InboundMetrics {
fn fmt_metrics(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.http_authz.fmt_metrics(f)?;
self.http_errors.fmt_metrics(f)?;

View File

@ -1,8 +1,9 @@
use crate::policy::{AllowPolicy, HttpRoutePermit, Meta, ServerPermit};
use linkerd_app_core::{
metrics::{
metrics, Counter, FmtLabels, FmtMetrics, RouteAuthzLabels, RouteLabels, ServerAuthzLabels,
ServerLabel, TargetAddr, TlsAccept,
legacy::{Counter, FmtLabels, FmtMetrics},
metrics, RouteAuthzLabels, RouteLabels, ServerAuthzLabels, ServerLabel, TargetAddr,
TlsAccept,
},
tls,
transport::OrigDstAddr,
@ -67,7 +68,7 @@ pub struct HTTPLocalRateLimitLabels {
#[derive(Debug, Hash, PartialEq, Eq)]
struct Key<L> {
target: TargetAddr,
tls: tls::ConditionalServerTls,
tls: tls::ConditionalServerTlsLabels,
labels: L,
}
@ -80,7 +81,7 @@ type HttpLocalRateLimitKey = Key<HTTPLocalRateLimitLabels>;
// === impl HttpAuthzMetrics ===
impl HttpAuthzMetrics {
pub fn allow(&self, permit: &HttpRoutePermit, tls: tls::ConditionalServerTls) {
pub fn allow(&self, permit: &HttpRoutePermit, tls: tls::ConditionalServerTlsLabels) {
self.0
.allow
.lock()
@ -93,7 +94,7 @@ impl HttpAuthzMetrics {
&self,
labels: ServerLabel,
dst: OrigDstAddr,
tls: tls::ConditionalServerTls,
tls: tls::ConditionalServerTlsLabels,
) {
self.0
.route_not_found
@ -103,7 +104,12 @@ impl HttpAuthzMetrics {
.incr();
}
pub fn deny(&self, labels: RouteLabels, dst: OrigDstAddr, tls: tls::ConditionalServerTls) {
pub fn deny(
&self,
labels: RouteLabels,
dst: OrigDstAddr,
tls: tls::ConditionalServerTlsLabels,
) {
self.0
.deny
.lock()
@ -116,7 +122,7 @@ impl HttpAuthzMetrics {
&self,
labels: HTTPLocalRateLimitLabels,
dst: OrigDstAddr,
tls: tls::ConditionalServerTls,
tls: tls::ConditionalServerTlsLabels,
) {
self.0
.http_local_rate_limit
@ -187,7 +193,7 @@ impl FmtMetrics for HttpAuthzMetrics {
// === impl TcpAuthzMetrics ===
impl TcpAuthzMetrics {
pub fn allow(&self, permit: &ServerPermit, tls: tls::ConditionalServerTls) {
pub fn allow(&self, permit: &ServerPermit, tls: tls::ConditionalServerTlsLabels) {
self.0
.allow
.lock()
@ -196,7 +202,7 @@ impl TcpAuthzMetrics {
.incr();
}
pub fn deny(&self, policy: &AllowPolicy, tls: tls::ConditionalServerTls) {
pub fn deny(&self, policy: &AllowPolicy, tls: tls::ConditionalServerTlsLabels) {
self.0
.deny
.lock()
@ -205,7 +211,7 @@ impl TcpAuthzMetrics {
.incr();
}
pub fn terminate(&self, policy: &AllowPolicy, tls: tls::ConditionalServerTls) {
pub fn terminate(&self, policy: &AllowPolicy, tls: tls::ConditionalServerTlsLabels) {
self.0
.terminate
.lock()
@ -246,18 +252,24 @@ impl FmtMetrics for TcpAuthzMetrics {
impl FmtLabels for HTTPLocalRateLimitLabels {
fn fmt_labels(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.server.fmt_labels(f)?;
if let Some(rl) = &self.rate_limit {
let Self {
server,
rate_limit,
scope,
} = self;
server.fmt_labels(f)?;
if let Some(rl) = rate_limit {
write!(
f,
",ratelimit_group=\"{}\",ratelimit_kind=\"{}\",ratelimit_name=\"{}\",ratelimit_scope=\"{}\"",
rl.group(),
rl.kind(),
rl.name(),
self.scope,
scope,
)
} else {
write!(f, ",ratelimit_scope=\"{}\"", self.scope)
write!(f, ",ratelimit_scope=\"{scope}\"")
}
}
}
@ -265,7 +277,7 @@ impl FmtLabels for HTTPLocalRateLimitLabels {
// === impl Key ===
impl<L> Key<L> {
fn new(labels: L, dst: OrigDstAddr, tls: tls::ConditionalServerTls) -> Self {
fn new(labels: L, dst: OrigDstAddr, tls: tls::ConditionalServerTlsLabels) -> Self {
Self {
tls,
target: TargetAddr(dst.into()),
@ -276,24 +288,30 @@ impl<L> Key<L> {
impl<L: FmtLabels> FmtLabels for Key<L> {
fn fmt_labels(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
(self.target, (&self.labels, TlsAccept(&self.tls))).fmt_labels(f)
let Self {
target,
tls,
labels,
} = self;
(target, (labels, TlsAccept(tls))).fmt_labels(f)
}
}
impl ServerKey {
fn from_policy(policy: &AllowPolicy, tls: tls::ConditionalServerTls) -> Self {
fn from_policy(policy: &AllowPolicy, tls: tls::ConditionalServerTlsLabels) -> Self {
Self::new(policy.server_label(), policy.dst_addr(), tls)
}
}
impl RouteAuthzKey {
fn from_permit(permit: &HttpRoutePermit, tls: tls::ConditionalServerTls) -> Self {
fn from_permit(permit: &HttpRoutePermit, tls: tls::ConditionalServerTlsLabels) -> Self {
Self::new(permit.labels.clone(), permit.dst, tls)
}
}
impl ServerAuthzKey {
fn from_permit(permit: &ServerPermit, tls: tls::ConditionalServerTls) -> Self {
fn from_permit(permit: &ServerPermit, tls: tls::ConditionalServerTlsLabels) -> Self {
Self::new(permit.labels.clone(), permit.dst, tls)
}
}

View File

@ -8,7 +8,7 @@ use crate::{
};
use linkerd_app_core::{
errors::{FailFastError, LoadShedError},
metrics::FmtLabels,
metrics::legacy::FmtLabels,
tls,
};
use std::fmt;

View File

@ -1,6 +1,9 @@
use super::ErrorKind;
use linkerd_app_core::{
metrics::{metrics, Counter, FmtMetrics, ServerLabel},
metrics::{
legacy::{Counter, FmtMetrics},
metrics, ServerLabel,
},
svc::{self, stack::NewMonitor},
transport::{labels::TargetAddr, OrigDstAddr},
Error,

View File

@ -1,6 +1,9 @@
use super::ErrorKind;
use linkerd_app_core::{
metrics::{metrics, Counter, FmtMetrics},
metrics::{
legacy::{Counter, FmtMetrics},
metrics,
},
svc::{self, stack::NewMonitor},
transport::{labels::TargetAddr, OrigDstAddr},
Error,

View File

@ -133,7 +133,7 @@ impl AllowPolicy {
#[inline]
pub fn server_label(&self) -> ServerLabel {
ServerLabel(self.server.borrow().meta.clone())
ServerLabel(self.server.borrow().meta.clone(), self.dst.port())
}
pub fn ratelimit_label(&self, error: &RateLimitError) -> HTTPLocalRateLimitLabels {
@ -220,7 +220,7 @@ impl ServerPermit {
protocol: server.protocol.clone(),
labels: ServerAuthzLabels {
authz: authz.meta.clone(),
server: ServerLabel(server.meta.clone()),
server: ServerLabel(server.meta.clone(), dst.port()),
},
}
}

View File

@ -33,9 +33,8 @@ static INVALID_POLICY: once_cell::sync::OnceCell<ServerPolicy> = once_cell::sync
impl<S> Api<S>
where
S: tonic::client::GrpcService<tonic::body::BoxBody, Error = Error> + Clone,
S::ResponseBody:
http::Body<Data = tonic::codegen::Bytes, Error = Error> + Default + Send + 'static,
S: tonic::client::GrpcService<tonic::body::Body, Error = Error> + Clone,
S::ResponseBody: http::Body<Data = tonic::codegen::Bytes, Error = Error> + Send + 'static,
{
pub(super) fn new(
workload: Arc<str>,
@ -58,10 +57,9 @@ where
impl<S> Service<u16> for Api<S>
where
S: tonic::client::GrpcService<tonic::body::BoxBody, Error = Error>,
S: tonic::client::GrpcService<tonic::body::Body, Error = Error>,
S: Clone + Send + Sync + 'static,
S::ResponseBody:
http::Body<Data = tonic::codegen::Bytes, Error = Error> + Default + Send + 'static,
S::ResponseBody: http::Body<Data = tonic::codegen::Bytes, Error = Error> + Send + 'static,
S::Future: Send + 'static,
{
type Response =

View File

@ -40,10 +40,10 @@ impl Config {
limits: ReceiveLimits,
) -> impl GetPolicy + Clone + Send + Sync + 'static
where
C: tonic::client::GrpcService<tonic::body::BoxBody, Error = Error>,
C: tonic::client::GrpcService<tonic::body::Body, Error = Error>,
C: Clone + Unpin + Send + Sync + 'static,
C::ResponseBody: http::Body<Data = tonic::codegen::Bytes, Error = Error>,
C::ResponseBody: Default + Send + 'static,
C::ResponseBody: Send + 'static,
C::Future: Send,
{
match self {

View File

@ -248,8 +248,11 @@ impl<T, N> HttpPolicyService<T, N> {
);
}
}
self.metrics
.deny(labels, self.connection.dst, self.connection.tls.clone());
self.metrics.deny(
labels,
self.connection.dst,
self.connection.tls.as_ref().map(|t| t.labels()),
);
return Err(HttpRouteUnauthorized(()).into());
}
};
@ -279,14 +282,19 @@ impl<T, N> HttpPolicyService<T, N> {
}
};
self.metrics.allow(&permit, self.connection.tls.clone());
self.metrics
.allow(&permit, self.connection.tls.as_ref().map(|t| t.labels()));
Ok((permit, r#match, route))
}
fn mk_route_not_found(&self) -> Error {
let labels = self.policy.server_label();
self.metrics
.route_not_found(labels, self.connection.dst, self.connection.tls.clone());
self.metrics.route_not_found(
labels,
self.connection.dst,
self.connection.tls.as_ref().map(|t| t.labels()),
);
HttpRouteNotFound(()).into()
}
@ -306,7 +314,7 @@ impl<T, N> HttpPolicyService<T, N> {
self.metrics.ratelimit(
self.policy.ratelimit_label(&err),
self.connection.dst,
self.connection.tls.clone(),
self.connection.tls.as_ref().map(|t| t.labels()),
);
err.into()
})

View File

@ -1,6 +1,7 @@
use super::*;
use crate::policy::{Authentication, Authorization, Meta, Protocol, ServerPolicy};
use linkerd_app_core::{svc::Service, Infallible};
use linkerd_http_box::BoxBody;
use linkerd_proxy_server_policy::{LocalRateLimit, RateLimitError};
macro_rules! conn {
@ -40,7 +41,7 @@ macro_rules! new_svc {
metrics: HttpAuthzMetrics::default(),
inner: |(permit, _): (HttpRoutePermit, ())| {
let f = $rsp;
svc::mk(move |req: ::http::Request<hyper::Body>| {
svc::mk(move |req: ::http::Request<BoxBody>| {
futures::future::ready((f)(permit.clone(), req))
})
},
@ -56,9 +57,9 @@ macro_rules! new_svc {
new_svc!(
$proto,
conn!(),
|permit: HttpRoutePermit, _req: ::http::Request<hyper::Body>| {
|permit: HttpRoutePermit, _req: ::http::Request<BoxBody>| {
let mut rsp = ::http::Response::builder()
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap();
rsp.extensions_mut().insert(permit.clone());
Ok::<_, Infallible>(rsp)
@ -119,11 +120,7 @@ async fn http_route() {
// Test that authorization policies allow requests:
let rsp = svc
.call(
::http::Request::builder()
.body(hyper::Body::default())
.unwrap(),
)
.call(::http::Request::builder().body(BoxBody::default()).unwrap())
.await
.expect("serves");
let permit = rsp
@ -137,7 +134,7 @@ async fn http_route() {
.call(
::http::Request::builder()
.method(::http::Method::POST)
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap(),
)
.await
@ -149,7 +146,7 @@ async fn http_route() {
.call(
::http::Request::builder()
.method(::http::Method::DELETE)
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap(),
)
.await
@ -213,11 +210,7 @@ async fn http_route() {
.expect("must send");
assert!(svc
.call(
::http::Request::builder()
.body(hyper::Body::default())
.unwrap(),
)
.call(::http::Request::builder().body(BoxBody::default()).unwrap(),)
.await
.expect_err("fails")
.is::<HttpRouteUnauthorized>());
@ -226,7 +219,7 @@ async fn http_route() {
.call(
::http::Request::builder()
.method(::http::Method::POST)
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap(),
)
.await
@ -237,7 +230,7 @@ async fn http_route() {
.call(
::http::Request::builder()
.method(::http::Method::DELETE)
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap(),
)
.await
@ -285,14 +278,14 @@ async fn http_filter_header() {
},
}],
}]));
let inner = |permit: HttpRoutePermit, req: ::http::Request<hyper::Body>| -> Result<_> {
let inner = |permit: HttpRoutePermit, req: ::http::Request<BoxBody>| -> Result<_> {
assert_eq!(req.headers().len(), 1);
assert_eq!(
req.headers().get("testkey"),
Some(&"testval".parse().unwrap())
);
let mut rsp = ::http::Response::builder()
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap();
rsp.extensions_mut().insert(permit);
Ok(rsp)
@ -300,11 +293,7 @@ async fn http_filter_header() {
let (mut svc, _tx) = new_svc!(proto, conn!(), inner);
let rsp = svc
.call(
::http::Request::builder()
.body(hyper::Body::default())
.unwrap(),
)
.call(::http::Request::builder().body(BoxBody::default()).unwrap())
.await
.expect("serves");
let permit = rsp
@ -354,16 +343,12 @@ async fn http_filter_inject_failure() {
}],
}]));
let inner = |_: HttpRoutePermit,
_: ::http::Request<hyper::Body>|
-> Result<::http::Response<hyper::Body>> { unreachable!() };
_: ::http::Request<BoxBody>|
-> Result<::http::Response<BoxBody>> { unreachable!() };
let (mut svc, _tx) = new_svc!(proto, conn!(), inner);
let err = svc
.call(
::http::Request::builder()
.body(hyper::Body::default())
.unwrap(),
)
.call(::http::Request::builder().body(BoxBody::default()).unwrap())
.await
.expect_err("fails");
assert_eq!(
@ -397,22 +382,14 @@ async fn rate_limit_allow() {
// First request should be allowed
let rsp = svc
.call(
::http::Request::builder()
.body(hyper::Body::default())
.unwrap(),
)
.call(::http::Request::builder().body(BoxBody::default()).unwrap())
.await
.expect("serves");
assert_eq!(rsp.status(), ::http::StatusCode::OK);
// Second request should be allowed as well
let rsp = svc
.call(
::http::Request::builder()
.body(hyper::Body::default())
.unwrap(),
)
.call(::http::Request::builder().body(BoxBody::default()).unwrap())
.await
.expect("serves");
assert_eq!(rsp.status(), ::http::StatusCode::OK);
@ -440,22 +417,14 @@ async fn rate_limit_deny() {
// First request should be allowed
let rsp = svc
.call(
::http::Request::builder()
.body(hyper::Body::default())
.unwrap(),
)
.call(::http::Request::builder().body(BoxBody::default()).unwrap())
.await
.expect("serves");
assert_eq!(rsp.status(), ::http::StatusCode::OK);
// Second request should be denied
let rsp = svc
.call(
::http::Request::builder()
.body(hyper::Body::default())
.unwrap(),
)
.call(::http::Request::builder().body(BoxBody::default()).unwrap())
.await
.expect_err("should deny");
let err = rsp
@ -526,7 +495,7 @@ async fn grpc_route() {
::http::Request::builder()
.uri("/foo.bar.bah/baz")
.method(::http::Method::POST)
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap(),
)
.await
@ -542,7 +511,7 @@ async fn grpc_route() {
::http::Request::builder()
.uri("/foo.bar.bah/qux")
.method(::http::Method::POST)
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap(),
)
.await
@ -554,7 +523,7 @@ async fn grpc_route() {
::http::Request::builder()
.uri("/boo.bar.bah/bah")
.method(::http::Method::POST)
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap(),
)
.await
@ -606,14 +575,14 @@ async fn grpc_filter_header() {
},
}],
}]));
let inner = |permit: HttpRoutePermit, req: ::http::Request<hyper::Body>| -> Result<_> {
let inner = |permit: HttpRoutePermit, req: ::http::Request<BoxBody>| -> Result<_> {
assert_eq!(req.headers().len(), 1);
assert_eq!(
req.headers().get("testkey"),
Some(&"testval".parse().unwrap())
);
let mut rsp = ::http::Response::builder()
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap();
rsp.extensions_mut().insert(permit);
Ok(rsp)
@ -625,7 +594,7 @@ async fn grpc_filter_header() {
::http::Request::builder()
.uri("/foo.bar.bah/baz")
.method(::http::Method::POST)
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap(),
)
.await
@ -683,8 +652,8 @@ async fn grpc_filter_inject_failure() {
}],
}]));
let inner = |_: HttpRoutePermit,
_: ::http::Request<hyper::Body>|
-> Result<::http::Response<hyper::Body>> { unreachable!() };
_: ::http::Request<BoxBody>|
-> Result<::http::Response<BoxBody>> { unreachable!() };
let (mut svc, _tx) = new_svc!(proto, conn!(), inner);
let err = svc
@ -692,7 +661,7 @@ async fn grpc_filter_inject_failure() {
::http::Request::builder()
.uri("/foo.bar.bah/baz")
.method(::http::Method::POST)
.body(hyper::Body::default())
.body(BoxBody::default())
.unwrap(),
)
.await

View File

@ -74,11 +74,10 @@ impl<S> Store<S> {
opaque_ports: RangeInclusiveSet<u16>,
) -> Self
where
S: tonic::client::GrpcService<tonic::body::BoxBody, Error = Error>,
S: tonic::client::GrpcService<tonic::body::Body, Error = Error>,
S: Clone + Send + Sync + 'static,
S::Future: Send,
S::ResponseBody:
http::Body<Data = tonic::codegen::Bytes, Error = Error> + Default + Send + 'static,
S::ResponseBody: http::Body<Data = tonic::codegen::Bytes, Error = Error> + Send + 'static,
{
let opaque_default = Self::make_opaque(default.clone());
// The initial set of policies never expire from the cache.
@ -139,11 +138,10 @@ impl<S> Store<S> {
impl<S> GetPolicy for Store<S>
where
S: tonic::client::GrpcService<tonic::body::BoxBody, Error = Error>,
S: tonic::client::GrpcService<tonic::body::Body, Error = Error>,
S: Clone + Send + Sync + 'static,
S::Future: Send,
S::ResponseBody:
http::Body<Data = tonic::codegen::Bytes, Error = Error> + Default + Send + 'static,
S::ResponseBody: http::Body<Data = tonic::codegen::Bytes, Error = Error> + Send + 'static,
{
fn get_policy(&self, dst: OrigDstAddr) -> AllowPolicy {
// Lookup the policy for the target port in the cache. If it doesn't

View File

@ -77,7 +77,8 @@ where
// This new services requires a ClientAddr, so it must necessarily be built for each
// connection. So we can just increment the counter here since the service can only
// be used at most once.
self.metrics.allow(&permit, tls.clone());
self.metrics
.allow(&permit, tls.as_ref().map(|t| t.labels()));
let inner = self.inner.new_service((permit, target));
TcpPolicy::Authorized(Authorized {
@ -97,7 +98,7 @@ where
?tls, %client,
"Connection denied"
);
self.metrics.deny(&policy, tls);
self.metrics.deny(&policy, tls.as_ref().map(|t| t.labels()));
TcpPolicy::Unauthorized(deny)
}
}
@ -167,7 +168,7 @@ where
%client,
"Connection terminated due to policy change",
);
metrics.terminate(&policy, tls);
metrics.terminate(&policy, tls.as_ref().map(|t| t.labels()));
return Err(denied.into());
}
}

View File

@ -43,11 +43,14 @@ async fn unauthenticated_allowed() {
kind: "serverauthorization".into(),
name: "unauth".into()
}),
server: ServerLabel(Arc::new(Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "test".into()
}))
server: ServerLabel(
Arc::new(Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "test".into()
}),
1000
)
},
}
);
@ -96,11 +99,14 @@ async fn authenticated_identity() {
kind: "serverauthorization".into(),
name: "tls-auth".into()
}),
server: ServerLabel(Arc::new(Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "test".into()
}))
server: ServerLabel(
Arc::new(Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "test".into()
}),
1000
)
}
}
);
@ -159,11 +165,14 @@ async fn authenticated_suffix() {
kind: "serverauthorization".into(),
name: "tls-auth".into()
}),
server: ServerLabel(Arc::new(Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "test".into()
})),
server: ServerLabel(
Arc::new(Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "test".into()
}),
1000
),
}
}
);
@ -219,11 +228,14 @@ async fn tls_unauthenticated() {
kind: "serverauthorization".into(),
name: "tls-unauth".into()
}),
server: ServerLabel(Arc::new(Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "test".into()
})),
server: ServerLabel(
Arc::new(Meta::Resource {
group: "policy.linkerd.io".into(),
kind: "server".into(),
name: "test".into()
}),
1000
),
}
}
);
@ -251,7 +263,7 @@ fn orig_dst_addr() -> OrigDstAddr {
OrigDstAddr(([192, 0, 2, 2], 1000).into())
}
impl tonic::client::GrpcService<tonic::body::BoxBody> for MockSvc {
impl tonic::client::GrpcService<tonic::body::Body> for MockSvc {
type ResponseBody = linkerd_app_core::control::RspBody;
type Error = Error;
type Future = futures::future::Pending<Result<http::Response<Self::ResponseBody>, Self::Error>>;
@ -263,7 +275,7 @@ impl tonic::client::GrpcService<tonic::body::BoxBody> for MockSvc {
unreachable!()
}
fn call(&mut self, _req: http::Request<tonic::body::BoxBody>) -> Self::Future {
fn call(&mut self, _req: http::Request<tonic::body::Body>) -> Self::Future {
unreachable!()
}
}

View File

@ -27,10 +27,10 @@ impl Inbound<()> {
limits: ReceiveLimits,
) -> impl policy::GetPolicy + Clone + Send + Sync + 'static
where
C: tonic::client::GrpcService<tonic::body::BoxBody, Error = Error>,
C: tonic::client::GrpcService<tonic::body::Body, Error = Error>,
C: Clone + Unpin + Send + Sync + 'static,
C::ResponseBody: http::Body<Data = tonic::codegen::Bytes, Error = Error>,
C::ResponseBody: Default + Send + 'static,
C::ResponseBody: Send + 'static,
C::Future: Send,
{
self.config
@ -55,6 +55,8 @@ impl Inbound<()> {
I: Debug + Unpin + Send + Sync + 'static,
P: profiles::GetProfile<Error = Error>,
{
let detect_metrics = self.runtime.metrics.detect.clone();
// Handles connections to ports that can't be determined to be HTTP.
let forward = self
.clone()
@ -97,7 +99,7 @@ impl Inbound<()> {
// Determines how to handle an inbound connection, dispatching it to the appropriate
// stack.
http.push_http_tcp_server()
.push_detect(forward)
.push_detect(detect_metrics, forward)
.push_accept(addr.port(), policies, direct)
.into_inner()
}

View File

@ -3,9 +3,7 @@ pub use futures::prelude::*;
use linkerd_app_core::{
config,
dns::Suffix,
drain, exp_backoff,
identity::rustls,
metrics,
drain, exp_backoff, identity, metrics,
proxy::{
http::{h1, h2},
tap,
@ -89,6 +87,7 @@ pub fn default_config() -> Config {
},
discovery_idle_timeout: Duration::from_secs(20),
profile_skip_timeout: Duration::from_secs(1),
unsafe_authority_labels: false,
}
}
@ -97,7 +96,7 @@ pub fn runtime() -> (ProxyRuntime, drain::Signal) {
let (tap, _) = tap::new();
let (metrics, _) = metrics::Metrics::new(std::time::Duration::from_secs(10));
let runtime = ProxyRuntime {
identity: rustls::creds::default_for_test().1.into(),
identity: identity::creds::default_for_test().1,
metrics: metrics.proxy,
tap,
span_sink: None,

View File

@ -1,10 +1,10 @@
[package]
name = "linkerd-app-integration"
version = "0.1.0"
authors = ["Linkerd Developers <cncf-linkerd-dev@lists.cncf.io>"]
license = "Apache-2.0"
edition = "2021"
publish = false
version = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
edition = { workspace = true }
publish = { workspace = true }
description = """
Proxy integration tests
@ -22,40 +22,51 @@ futures = { version = "0.3", default-features = false, features = ["executor"] }
h2 = { workspace = true }
http = { workspace = true }
http-body = { workspace = true }
hyper = { workspace = true, features = [
"backports",
"deprecated",
"http1",
"http2",
"stream",
"client",
"server",
] }
http-body-util = { workspace = true }
hyper-util = { workspace = true, features = ["service"] }
ipnet = "2"
linkerd-app = { path = "..", features = ["allow-loopback"] }
linkerd-app-core = { path = "../core" }
linkerd-metrics = { path = "../../metrics", features = ["test_util"] }
linkerd2-proxy-api = { workspace = true, features = [
"destination",
"arbitrary",
] }
linkerd-app-test = { path = "../test" }
linkerd-meshtls = { path = "../../meshtls", features = ["test-util"] }
linkerd-metrics = { path = "../../metrics", features = ["test_util"] }
linkerd-rustls = { path = "../../rustls" }
linkerd-tracing = { path = "../../tracing" }
maplit = "1"
parking_lot = "0.12"
regex = "1"
socket2 = "0.5"
tokio = { version = "1", features = ["io-util", "net", "rt", "macros"] }
tokio-stream = { version = "0.1", features = ["sync"] }
tokio-rustls = { workspace = true }
rustls-pemfile = "2.2"
tower = { version = "0.4", default-features = false }
tonic = { workspace = true, features = ["transport"], default-features = false }
tracing = "0.1"
tracing-subscriber = { version = "0.3", default-features = false, features = [
socket2 = "0.6"
tokio = { version = "1", features = ["io-util", "net", "rt", "macros"] }
tokio-rustls = { workspace = true }
tokio-stream = { version = "0.1", features = ["sync"] }
tonic = { workspace = true, features = ["transport", "router"], default-features = false }
tower = { workspace = true, default-features = false }
tracing = { workspace = true }
[dependencies.hyper]
workspace = true
features = [
"client",
"http1",
"http2",
"server",
]
[dependencies.linkerd2-proxy-api]
workspace = true
features = [
"arbitrary",
"destination",
]
[dependencies.tracing-subscriber]
version = "0.3"
default-features = false
features = [
"fmt",
"std",
] }
]
[dev-dependencies]
flate2 = { version = "1", default-features = false, features = [
@ -63,8 +74,5 @@ flate2 = { version = "1", default-features = false, features = [
] }
# Log streaming isn't enabled by default globally, but we want to test it.
linkerd-app-admin = { path = "../admin", features = ["log-streaming"] }
# No code from this crate is actually used; only necessary to enable the Rustls
# implementation.
linkerd-meshtls = { path = "../../meshtls", features = ["rustls"] }
linkerd-tracing = { path = "../../tracing", features = ["ansi"] }
serde_json = "1"

View File

@ -1,15 +1,17 @@
use super::*;
use linkerd_app_core::proxy::http::TracingExecutor;
use http::{Request, Response};
use linkerd_app_core::{proxy::http::TokioExecutor, svc::http::BoxBody};
use parking_lot::Mutex;
use std::io;
use tokio::{net::TcpStream, task::JoinHandle};
use tokio_rustls::rustls::{self, ClientConfig};
use tracing::info_span;
type ClientError = hyper::Error;
type Request = http::Request<hyper::Body>;
type Response = http::Response<hyper::Body>;
type Sender = mpsc::UnboundedSender<(Request, oneshot::Sender<Result<Response, ClientError>>)>;
type ClientError = hyper_util::client::legacy::Error;
type Sender = mpsc::UnboundedSender<(
Request<BoxBody>,
oneshot::Sender<Result<Response<hyper::body::Incoming>, ClientError>>,
)>;
#[derive(Clone)]
pub struct TlsConfig {
@ -74,9 +76,6 @@ pub fn http2_tls<T: Into<String>>(addr: SocketAddr, auth: T, tls: TlsConfig) ->
Client::new(addr, auth.into(), Run::Http2, Some(tls))
}
pub fn tcp(addr: SocketAddr) -> tcp::TcpClient {
tcp::client(addr)
}
pub struct Client {
addr: SocketAddr,
run: Run,
@ -132,11 +131,19 @@ impl Client {
pub fn request(
&self,
builder: http::request::Builder,
) -> impl Future<Output = Result<Response, ClientError>> + Send + Sync + 'static {
self.send_req(builder.body(Bytes::new().into()).unwrap())
) -> impl Future<Output = Result<Response<hyper::body::Incoming>, ClientError>> + Send + 'static
{
let req = builder.body(BoxBody::empty()).unwrap();
self.send_req(req)
}
pub async fn request_body(&self, req: Request) -> Response {
pub async fn request_body<B>(&self, req: Request<B>) -> Response<hyper::body::Incoming>
where
B: Body + Send + 'static,
B::Data: Send + 'static,
B::Error: Into<Error>,
{
let req = req.map(BoxBody::new);
self.send_req(req).await.expect("response")
}
@ -152,11 +159,16 @@ impl Client {
}
}
#[tracing::instrument(skip(self))]
pub(crate) fn send_req(
#[tracing::instrument(skip(self, req))]
pub(crate) fn send_req<B>(
&self,
mut req: Request,
) -> impl Future<Output = Result<Response, ClientError>> + Send + Sync + 'static {
mut req: Request<B>,
) -> impl Future<Output = Result<Response<hyper::body::Incoming>, ClientError>> + Send + 'static
where
B: Body + Send + 'static,
B::Data: Send + 'static,
B::Error: Into<Error>,
{
if req.uri().scheme().is_none() {
if self.tls.is_some() {
*req.uri_mut() = format!("https://{}{}", self.authority, req.uri().path())
@ -170,7 +182,8 @@ impl Client {
}
tracing::debug!(headers = ?req.headers(), "request");
let (tx, rx) = oneshot::channel();
let _ = self.tx.send((req.map(Into::into), tx));
let req = req.map(BoxBody::new);
let _ = self.tx.send((req, tx));
async { rx.await.expect("request cancelled") }.in_current_span()
}
@ -220,13 +233,17 @@ enum Run {
Http2,
}
pub type Running = Pin<Box<dyn Future<Output = ()> + Send + 'static>>;
fn run(
addr: SocketAddr,
version: Run,
tls: Option<TlsConfig>,
) -> (Sender, JoinHandle<()>, Running) {
let (tx, rx) =
mpsc::unbounded_channel::<(Request, oneshot::Sender<Result<Response, ClientError>>)>();
let (tx, rx) = mpsc::unbounded_channel::<(
Request<BoxBody>,
oneshot::Sender<Result<Response<hyper::body::Incoming>, ClientError>>,
)>();
let test_name = thread_name();
let absolute_uris = if let Run::Http1 { absolute_uris } = version {
@ -235,7 +252,12 @@ fn run(
false
};
let (running_tx, running) = running();
let (running_tx, running) = {
let (tx, rx) = oneshot::channel();
let rx = Box::pin(rx.map(|_| ()));
(tx, rx)
};
let conn = Conn {
addr,
absolute_uris,
@ -250,10 +272,9 @@ fn run(
let span = info_span!("test client", peer_addr = %addr, ?version, test = %test_name);
let work = async move {
let client = hyper::Client::builder()
let client = hyper_util::client::legacy::Client::builder(TokioExecutor::new())
.http2_only(http2_only)
.executor(TracingExecutor)
.build::<Conn, hyper::Body>(conn);
.build::<Conn, BoxBody>(conn);
tracing::trace!("client task started");
let mut rx = rx;
let (drain_tx, drain) = drain::channel();
@ -263,7 +284,6 @@ fn run(
// instance would remain un-dropped.
async move {
while let Some((req, cb)) = rx.recv().await {
let req = req.map(hyper::Body::from);
tracing::trace!(?req);
let req = client.request(req);
tokio::spawn(
@ -295,9 +315,11 @@ struct Conn {
}
impl tower::Service<hyper::Uri> for Conn {
type Response = RunningIo;
type Response = hyper_util::rt::TokioIo<RunningIo>;
type Error = io::Error;
type Future = Pin<Box<dyn Future<Output = io::Result<RunningIo>> + Send + 'static>>;
type Future = Pin<
Box<dyn Future<Output = io::Result<hyper_util::rt::TokioIo<RunningIo>>> + Send + 'static>,
>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
@ -327,19 +349,19 @@ impl tower::Service<hyper::Uri> for Conn {
} else {
Box::pin(io) as Pin<Box<dyn Io + Send + 'static>>
};
Ok(RunningIo {
Ok(hyper_util::rt::TokioIo::new(RunningIo {
io,
abs_form,
_running: Some(running),
})
}))
})
}
}
impl hyper::client::connect::Connection for RunningIo {
fn connected(&self) -> hyper::client::connect::Connected {
impl hyper_util::client::legacy::connect::Connection for RunningIo {
fn connected(&self) -> hyper_util::client::legacy::connect::Connected {
// Setting `proxy` to true will configure Hyper to use absolute-form
// URIs on this connection.
hyper::client::connect::Connected::new().proxy(self.abs_form)
hyper_util::client::legacy::connect::Connected::new().proxy(self.abs_form)
}
}

View File

@ -2,7 +2,7 @@ use super::*;
pub use linkerd2_proxy_api::destination as pb;
use linkerd2_proxy_api::net;
use linkerd_app_core::proxy::http::TracingExecutor;
use linkerd_app_core::proxy::http::TokioExecutor;
use parking_lot::Mutex;
use std::collections::VecDeque;
use std::net::IpAddr;
@ -262,10 +262,7 @@ impl pb::destination_server::Destination for Controller {
}
tracing::warn!(?dst, ?updates, "request does not match");
let msg = format!(
"expected get call for {:?} but got get call for {:?}",
dst, req
);
let msg = format!("expected get call for {dst:?} but got get call for {req:?}");
calls.push_front(Dst::Call(dst, updates));
return Err(grpc::Status::new(grpc::Code::Unavailable, msg));
}
@ -343,7 +340,7 @@ pub(crate) async fn run<T, B>(
delay: Option<Pin<Box<dyn Future<Output = ()> + Send>>>,
) -> Listening
where
T: tower::Service<http::Request<hyper::body::Body>, Response = http::Response<B>>,
T: tower::Service<http::Request<hyper::body::Incoming>, Response = http::Response<B>>,
T: Clone + Send + 'static,
T::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
T::Future: Send,
@ -372,11 +369,16 @@ where
let _ = listening_tx.send(());
}
let http = hyper::server::conn::http2::Builder::new(TracingExecutor);
let mut http = hyper::server::conn::http2::Builder::new(TokioExecutor::new());
loop {
let (sock, addr) = listener.accept().await?;
let span = tracing::debug_span!("conn", %addr).or_current();
let serve = http.serve_connection(sock, svc.clone());
let serve = http
.timer(hyper_util::rt::TokioTimer::new())
.serve_connection(
hyper_util::rt::TokioIo::new(sock),
hyper_util::service::TowerToHyperService::new(svc.clone()),
);
let f = async move {
serve.await.map_err(|error| {
tracing::error!(

View File

@ -8,7 +8,8 @@ use std::{
};
use linkerd2_proxy_api::identity as pb;
use tokio_rustls::rustls::{self, pki_types::CertificateDer, server::WebPkiClientVerifier};
use linkerd_rustls::get_default_provider;
use tokio_rustls::rustls::{self, server::WebPkiClientVerifier};
use tonic as grpc;
pub struct Identity {
@ -34,10 +35,6 @@ type Certify = Box<
> + Send,
>;
static TLS_VERSIONS: &[&rustls::SupportedProtocolVersion] = &[&rustls::version::TLS13];
static TLS_SUPPORTED_CIPHERSUITES: &[rustls::SupportedCipherSuite] =
&[rustls::crypto::ring::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256];
struct Certificates {
pub leaf: Vec<u8>,
pub intermediates: Vec<Vec<u8>>,
@ -54,13 +51,13 @@ impl Certificates {
let leaf = certs
.next()
.expect("no leaf cert in pemfile")
.map_err(|_| io::Error::new(io::ErrorKind::Other, "rustls error reading certs"))?
.map_err(|_| io::Error::other("rustls error reading certs"))?
.as_ref()
.to_vec();
let intermediates = certs
.map(|cert| cert.map(|cert| cert.as_ref().to_vec()))
.collect::<Result<Vec<_>, _>>()
.map_err(|_| io::Error::new(io::ErrorKind::Other, "rustls error reading certs"))?;
.map_err(|_| io::Error::other("rustls error reading certs"))?;
Ok(Certificates {
leaf,
@ -104,19 +101,16 @@ impl Identity {
use std::io::Cursor;
let mut roots = rustls::RootCertStore::empty();
let trust_anchors = rustls_pemfile::certs(&mut Cursor::new(trust_anchors))
.map(|bytes| bytes.map(CertificateDer::from))
.collect::<Result<Vec<_>, _>>()
.expect("error parsing pemfile");
let (added, skipped) = roots.add_parsable_certificates(trust_anchors);
assert_ne!(added, 0, "trust anchors must include at least one cert");
assert_eq!(skipped, 0, "no certs in pemfile should be invalid");
let mut provider = rustls::crypto::ring::default_provider();
provider.cipher_suites = TLS_SUPPORTED_CIPHERSUITES.to_vec();
let provider = Arc::new(provider);
let provider = get_default_provider();
let client_config = rustls::ClientConfig::builder_with_provider(provider.clone())
.with_protocol_versions(TLS_VERSIONS)
.with_safe_default_protocol_versions()
.expect("client config must be valid")
.with_root_certificates(roots.clone())
.with_no_client_auth();
@ -128,7 +122,7 @@ impl Identity {
.expect("server verifier must be valid");
let server_config = rustls::ServerConfig::builder_with_provider(provider)
.with_protocol_versions(TLS_VERSIONS)
.with_safe_default_protocol_versions()
.expect("server config must be valid")
.with_client_cert_verifier(client_cert_verifier)
.with_single_cert(certs.chain(), key)
@ -219,7 +213,7 @@ impl Controller {
let f = f.take().expect("called twice?");
let fut = f(req)
.map_ok(grpc::Response::new)
.map_err(|e| grpc::Status::new(grpc::Code::Internal, format!("{}", e)));
.map_err(|e| grpc::Status::new(grpc::Code::Internal, format!("{e}")));
Box::pin(fut)
});
self.expect_calls.lock().push_back(func);

View File

@ -3,6 +3,7 @@
#![warn(rust_2018_idioms, clippy::disallowed_methods, clippy::disallowed_types)]
#![forbid(unsafe_code)]
#![recursion_limit = "256"]
#![allow(clippy::result_large_err)]
mod test_env;
@ -28,7 +29,7 @@ pub use futures::{future, FutureExt, TryFuture, TryFutureExt};
pub use http::{HeaderMap, Request, Response, StatusCode};
pub use http_body::Body;
pub use linkerd_app as app;
pub use linkerd_app_core::{drain, Addr};
pub use linkerd_app_core::{drain, Addr, Error};
pub use linkerd_app_test::*;
pub use linkerd_tracing::test::*;
use socket2::Socket;
@ -50,8 +51,6 @@ pub use tower::Service;
pub const ENV_TEST_PATIENCE_MS: &str = "RUST_TEST_PATIENCE_MS";
pub const DEFAULT_TEST_PATIENCE: Duration = Duration::from_millis(15);
pub type Error = Box<dyn std::error::Error + Send + Sync + 'static>;
/// Retry an assertion up to a specified number of times, waiting
/// `RUST_TEST_PATIENCE_MS` between retries.
///
@ -219,15 +218,6 @@ impl Shutdown {
pub type ShutdownRx = Pin<Box<dyn Future<Output = ()> + Send>>;
/// A channel used to signal when a Client's related connection is running or closed.
pub fn running() -> (oneshot::Sender<()>, Running) {
let (tx, rx) = oneshot::channel();
let rx = Box::pin(rx.map(|_| ()));
(tx, rx)
}
pub type Running = Pin<Box<dyn Future<Output = ()> + Send + Sync + 'static>>;
pub fn s(bytes: &[u8]) -> &str {
::std::str::from_utf8(bytes).unwrap()
}
@ -258,7 +248,7 @@ impl fmt::Display for HumanDuration {
let secs = self.0.as_secs();
let subsec_ms = self.0.subsec_nanos() as f64 / 1_000_000f64;
if secs == 0 {
write!(fmt, "{}ms", subsec_ms)
write!(fmt, "{subsec_ms}ms")
} else {
write!(fmt, "{}s", secs as f64 + subsec_ms)
}
@ -267,7 +257,7 @@ impl fmt::Display for HumanDuration {
pub async fn cancelable<E: Send + 'static>(
drain: drain::Watch,
f: impl Future<Output = Result<(), E>> + Send + 'static,
f: impl Future<Output = Result<(), E>>,
) -> Result<(), E> {
tokio::select! {
res = f => res,

View File

@ -2,6 +2,7 @@ use super::*;
pub use api::{inbound, outbound};
use api::{inbound::inbound_server_policies_server, outbound::outbound_policies_server};
use futures::stream;
use http_body_util::combinators::UnsyncBoxBody;
use linkerd2_proxy_api as api;
use parking_lot::Mutex;
use std::collections::VecDeque;
@ -34,6 +35,9 @@ pub struct InboundSender(Tx<inbound::Server>);
#[derive(Debug, Clone)]
pub struct OutboundSender(Tx<outbound::OutboundPolicy>);
#[derive(Clone)]
struct RoutesSvc(grpc::service::Routes);
type Tx<T> = mpsc::UnboundedSender<Result<T, grpc::Status>>;
type Rx<T> = UnboundedReceiverStream<Result<T, grpc::Status>>;
type WatchStream<T> = Pin<Box<dyn Stream<Item = Result<T, grpc::Status>> + Send + Sync + 'static>>;
@ -298,7 +302,7 @@ impl Controller {
}
pub async fn run(self) -> controller::Listening {
let svc = grpc::transport::Server::builder()
let routes = grpc::service::Routes::default()
.add_service(
inbound_server_policies_server::InboundServerPoliciesServer::new(Server(Arc::new(
self.inbound,
@ -306,9 +310,9 @@ impl Controller {
)
.add_service(outbound_policies_server::OutboundPoliciesServer::new(
Server(Arc::new(self.outbound)),
))
.into_service();
controller::run(svc, "support policy controller", None).await
));
controller::run(RoutesSvc(routes), "support policy controller", None).await
}
}
@ -509,6 +513,35 @@ impl<Req, Rsp> Inner<Req, Rsp> {
}
}
// === impl RoutesSvc ===
impl Service<Request<hyper::body::Incoming>> for RoutesSvc {
type Response =
<grpc::service::Routes as Service<Request<UnsyncBoxBody<Bytes, grpc::Status>>>>::Response;
type Error =
<grpc::service::Routes as Service<Request<UnsyncBoxBody<Bytes, grpc::Status>>>>::Error;
type Future =
<grpc::service::Routes as Service<Request<UnsyncBoxBody<Bytes, grpc::Status>>>>::Future;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
let Self(routes) = self;
<grpc::service::Routes as Service<Request<UnsyncBoxBody<Bytes, grpc::Status>>>>::poll_ready(
routes, cx,
)
}
fn call(&mut self, req: Request<hyper::body::Incoming>) -> Self::Future {
use http_body_util::{combinators::UnsyncBoxBody, BodyExt};
let Self(routes) = self;
let req = req.map(|body| {
UnsyncBoxBody::new(body.map_err(|err| grpc::Status::from_error(Box::new(err))))
});
routes.call(req)
}
}
fn grpc_no_results() -> grpc::Status {
grpc::Status::new(
grpc::Code::NotFound,

View File

@ -108,7 +108,7 @@ impl fmt::Debug for MockOrigDst {
match self {
Self::Addr(addr) => f
.debug_tuple("MockOrigDst::Addr")
.field(&format_args!("{}", addr))
.field(&format_args!("{addr}"))
.finish(),
Self::Direct => f.debug_tuple("MockOrigDst::Direct").finish(),
Self::None => f.debug_tuple("MockOrigDst::None").finish(),
@ -416,9 +416,9 @@ async fn run(proxy: Proxy, mut env: TestEnv, random_ports: bool) -> Listening {
use std::fmt::Write;
let mut ports = inbound_default_ports.iter();
if let Some(port) = ports.next() {
let mut var = format!("{}", port);
let mut var = format!("{port}");
for port in ports {
write!(&mut var, ",{}", port).expect("writing to String should never fail");
write!(&mut var, ",{port}").expect("writing to String should never fail");
}
info!("{}={:?}", app::env::ENV_INBOUND_PORTS, var);
env.put(app::env::ENV_INBOUND_PORTS, var);

View File

@ -1,5 +1,7 @@
use super::app_core::svc::http::TracingExecutor;
use super::app_core::svc::http::TokioExecutor;
use super::*;
use http::{Request, Response};
use linkerd_app_core::svc::http::BoxBody;
use std::{
io,
sync::atomic::{AtomicUsize, Ordering},
@ -12,23 +14,35 @@ pub fn new() -> Server {
}
pub fn http1() -> Server {
Server::http1()
Server {
routes: Default::default(),
version: Run::Http1,
tls: None,
}
}
pub fn http1_tls(tls: Arc<ServerConfig>) -> Server {
Server::http1_tls(tls)
Server {
routes: Default::default(),
version: Run::Http1,
tls: Some(tls),
}
}
pub fn http2() -> Server {
Server::http2()
Server {
routes: Default::default(),
version: Run::Http2,
tls: None,
}
}
pub fn http2_tls(tls: Arc<ServerConfig>) -> Server {
Server::http2_tls(tls)
}
pub fn tcp() -> tcp::TcpServer {
tcp::server()
Server {
routes: Default::default(),
version: Run::Http2,
tls: Some(tls),
}
}
pub struct Server {
@ -45,9 +59,8 @@ pub struct Listening {
pub(super) http_version: Option<Run>,
}
type Request = http::Request<hyper::Body>;
type Response = http::Response<hyper::Body>;
type RspFuture = Pin<Box<dyn Future<Output = Result<Response, BoxError>> + Send + Sync + 'static>>;
type RspFuture<B = BoxBody> =
Pin<Box<dyn Future<Output = Result<Response<B>, Error>> + Send + 'static>>;
impl Listening {
pub fn connections(&self) -> usize {
@ -92,29 +105,6 @@ impl Listening {
}
impl Server {
fn new(run: Run, tls: Option<Arc<ServerConfig>>) -> Self {
Server {
routes: HashMap::new(),
version: run,
tls,
}
}
fn http1() -> Self {
Server::new(Run::Http1, None)
}
fn http1_tls(tls: Arc<ServerConfig>) -> Self {
Server::new(Run::Http1, Some(tls))
}
fn http2() -> Self {
Server::new(Run::Http2, None)
}
fn http2_tls(tls: Arc<ServerConfig>) -> Self {
Server::new(Run::Http2, Some(tls))
}
/// Return a string body as a 200 OK response, with the string as
/// the response body.
pub fn route(mut self, path: &str, resp: &str) -> Self {
@ -126,11 +116,11 @@ impl Server {
/// to send back.
pub fn route_fn<F>(self, path: &str, cb: F) -> Self
where
F: Fn(Request) -> Response + Send + Sync + 'static,
F: Fn(Request<BoxBody>) -> Response<BoxBody> + Send + Sync + 'static,
{
self.route_async(path, move |req| {
let res = cb(req);
async move { Ok::<_, BoxError>(res) }
async move { Ok::<_, Error>(res) }
})
}
@ -138,9 +128,9 @@ impl Server {
/// a response to send back.
pub fn route_async<F, U>(mut self, path: &str, cb: F) -> Self
where
F: Fn(Request) -> U + Send + Sync + 'static,
U: TryFuture<Ok = Response> + Send + Sync + 'static,
U::Error: Into<BoxError> + Send + 'static,
F: Fn(Request<BoxBody>) -> U + Send + Sync + 'static,
U: TryFuture<Ok = Response<BoxBody>> + Send + 'static,
U::Error: Into<Error> + Send + 'static,
{
let func = move |req| Box::pin(cb(req).map_err(Into::into)) as RspFuture;
self.routes.insert(path.into(), Route(Box::new(func)));
@ -148,16 +138,17 @@ impl Server {
}
pub fn route_with_latency(self, path: &str, resp: &str, latency: Duration) -> Self {
let resp = Bytes::from(resp.to_string());
let body = resp.to_owned();
self.route_async(path, move |_| {
let resp = resp.clone();
let body = body.clone();
async move {
tokio::time::sleep(latency).await;
Ok::<_, BoxError>(
Ok::<_, Error>(
http::Response::builder()
.status(200)
.body(hyper::Body::from(resp.clone()))
.unwrap(),
.status(StatusCode::OK)
.body(http_body_util::Full::new(Bytes::from(body.clone())))
.unwrap()
.map(BoxBody::new),
)
}
})
@ -193,7 +184,7 @@ impl Server {
drain.clone(),
async move {
tracing::info!("support server running");
let mut new_svc = NewSvc(Arc::new(self.routes));
let svc = Svc(Arc::new(self.routes));
if let Some(delay) = delay {
let _ = listening_tx.take().unwrap().send(());
delay.await;
@ -213,31 +204,40 @@ impl Server {
.instrument(span.clone())
.await?;
let srv_conn_count = srv_conn_count.clone();
let svc = new_svc.call(());
let svc = svc.clone();
let f = async move {
tracing::trace!("serving...");
let svc = svc.await;
tracing::trace!("service acquired");
srv_conn_count.fetch_add(1, Ordering::Release);
let svc = svc.map_err(|e| {
tracing::error!("support/server new_service error: {}", e)
})?;
use hyper_util::{rt::TokioIo, service::TowerToHyperService};
let (sock, svc) = (TokioIo::new(sock), TowerToHyperService::new(svc));
let result = match self.version {
Run::Http1 => hyper::server::conn::http1::Builder::new()
.timer(hyper_util::rt::TokioTimer::new())
.serve_connection(sock, svc)
.await
.map_err(|e| tracing::error!("support/server error: {}", e)),
Run::Http2 => hyper::server::conn::http2::Builder::new(TracingExecutor)
.serve_connection(sock, svc)
.await
.map_err(|e| tracing::error!("support/server error: {}", e)),
Run::Http2 => {
hyper::server::conn::http2::Builder::new(TokioExecutor::new())
.timer(hyper_util::rt::TokioTimer::new())
.serve_connection(sock, svc)
.await
.map_err(|e| tracing::error!("support/server error: {}", e))
}
};
tracing::trace!(?result, "serve done");
result
};
tokio::spawn(
cancelable(drain.clone(), f).instrument(span.clone().or_current()),
);
// let fut = Box::pin(cancelable(drain.clone(), f).instrument(span.clone().or_current()))
let drain = drain.clone();
tokio::spawn(async move {
tokio::select! {
res = f => res,
_ = drain.signaled() => {
tracing::debug!("canceled!");
Ok(())
}
}
});
}
}
.instrument(
@ -266,17 +266,19 @@ pub(super) enum Run {
Http2,
}
struct Route(Box<dyn Fn(Request) -> RspFuture + Send + Sync>);
struct Route(Box<dyn Fn(Request<BoxBody>) -> RspFuture + Send + Sync>);
impl Route {
fn string(body: &str) -> Route {
let body = Bytes::from(body.to_string());
let body = http_body_util::Full::new(Bytes::from(body.to_string()));
Route(Box::new(move |_| {
let body = body.clone();
Box::pin(future::ok(
http::Response::builder()
.status(200)
.body(hyper::Body::from(body.clone()))
.unwrap(),
.status(StatusCode::OK)
.body(body)
.unwrap()
.map(BoxBody::new),
))
}))
}
@ -288,58 +290,53 @@ impl std::fmt::Debug for Route {
}
}
type BoxError = Box<dyn std::error::Error + Send + Sync>;
#[derive(Debug)]
#[derive(Clone, Debug)]
struct Svc(Arc<HashMap<String, Route>>);
impl Svc {
fn route(&mut self, req: Request) -> RspFuture {
fn route<B>(
&mut self,
req: Request<B>,
) -> impl Future<Output = Result<Response<BoxBody>, crate::app_core::Error>> + Send
where
B: Body + Send + Sync + 'static,
B::Data: Send + 'static,
B::Error: std::error::Error + Send + Sync + 'static,
{
match self.0.get(req.uri().path()) {
Some(Route(ref func)) => {
tracing::trace!(path = %req.uri().path(), "found route for path");
func(req)
func(req.map(BoxBody::new))
}
None => {
tracing::warn!("server 404: {:?}", req.uri().path());
let res = http::Response::builder()
.status(404)
.body(Default::default())
.unwrap();
Box::pin(async move { Ok(res) })
Box::pin(futures::future::ok(
http::Response::builder()
.status(StatusCode::NOT_FOUND)
.body(BoxBody::empty())
.unwrap(),
))
}
}
}
}
impl tower::Service<Request> for Svc {
type Response = Response;
type Error = BoxError;
impl<B> tower::Service<Request<B>> for Svc
where
B: Body + Send + Sync + 'static,
B::Data: Send,
B::Error: std::error::Error + Send + Sync,
{
type Response = Response<BoxBody>;
type Error = Error;
type Future = RspFuture;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: Request) -> Self::Future {
self.route(req)
}
}
#[derive(Debug)]
struct NewSvc(Arc<HashMap<String, Route>>);
impl Service<()> for NewSvc {
type Response = Svc;
type Error = ::std::io::Error;
type Future = future::Ready<Result<Svc, Self::Error>>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, _: ()) -> Self::Future {
future::ok(Svc(Arc::clone(&self.0)))
fn call(&mut self, req: Request<B>) -> Self::Future {
Box::pin(self.route(req))
}
}
@ -357,7 +354,6 @@ async fn accept_connection(
_running: None,
})
}
None => Ok(RunningIo {
io: Box::pin(io),
abs_form: false,

View File

@ -2,6 +2,7 @@ use super::*;
use futures::stream;
use http_body::Body;
use linkerd2_proxy_api::tap as pb;
use linkerd_app_core::svc::http::BoxBody;
pub fn client(addr: SocketAddr) -> Client {
let api = pb::tap_client::TapClient::new(SyncSvc(client::http2(addr, "localhost")));
@ -106,7 +107,6 @@ pub trait TapEventExt {
//fn id(&self) -> (u32, u64);
fn event(&self) -> &pb::tap_event::http::Event;
fn request_init_method(&self) -> String;
fn request_init_authority(&self) -> &str;
fn request_init_path(&self) -> &str;
@ -134,41 +134,31 @@ impl TapEventExt for pb::TapEvent {
}
}
fn request_init_method(&self) -> String {
match self.event() {
pb::tap_event::http::Event::RequestInit(_ev) => {
//TODO: ugh
unimplemented!("method");
}
e => panic!("not RequestInit event: {:?}", e),
}
}
fn request_init_authority(&self) -> &str {
match self.event() {
pb::tap_event::http::Event::RequestInit(ev) => &ev.authority,
e => panic!("not RequestInit event: {:?}", e),
e => panic!("not RequestInit event: {e:?}"),
}
}
fn request_init_path(&self) -> &str {
match self.event() {
pb::tap_event::http::Event::RequestInit(ev) => &ev.path,
e => panic!("not RequestInit event: {:?}", e),
e => panic!("not RequestInit event: {e:?}"),
}
}
fn response_init_status(&self) -> u16 {
match self.event() {
pb::tap_event::http::Event::ResponseInit(ev) => ev.http_status as u16,
e => panic!("not ResponseInit event: {:?}", e),
e => panic!("not ResponseInit event: {e:?}"),
}
}
fn response_end_bytes(&self) -> u64 {
match self.event() {
pb::tap_event::http::Event::ResponseEnd(ev) => ev.response_bytes,
e => panic!("not ResponseEnd event: {:?}", e),
e => panic!("not ResponseEnd event: {e:?}"),
}
}
@ -180,7 +170,7 @@ impl TapEventExt for pb::TapEvent {
}) => code,
_ => panic!("not Eos GrpcStatusCode: {:?}", ev.eos),
},
ev => panic!("not ResponseEnd event: {:?}", ev),
ev => panic!("not ResponseEnd event: {ev:?}"),
}
}
}
@ -188,15 +178,14 @@ impl TapEventExt for pb::TapEvent {
struct SyncSvc(client::Client);
type ResponseFuture =
Pin<Box<dyn Future<Output = Result<http::Response<hyper::Body>, String>> + Send>>;
Pin<Box<dyn Future<Output = Result<http::Response<hyper::body::Incoming>, String>> + Send>>;
impl<B> tower::Service<http::Request<B>> for SyncSvc
where
B: Body + Send + 'static,
B::Data: Send + 'static,
B::Error: Send + 'static,
B: Body,
B::Error: std::fmt::Debug,
{
type Response = http::Response<hyper::Body>;
type Response = http::Response<hyper::body::Incoming>;
type Error = String;
type Future = ResponseFuture;
@ -205,20 +194,31 @@ where
}
fn call(&mut self, req: http::Request<B>) -> Self::Future {
// this is okay to do because the body should always be complete, we
// just can't prove it.
let req = futures::executor::block_on(async move {
let (parts, body) = req.into_parts();
let body = match body.collect().await.map(http_body::Collected::to_bytes) {
Ok(body) => body,
Err(_) => unreachable!("body should not fail"),
};
http::Request::from_parts(parts, body)
});
Box::pin(
self.0
.send_req(req.map(Into::into))
.map_err(|err| err.to_string()),
)
use http_body_util::Full;
let Self(client) = self;
let req = req.map(Self::collect_body).map(Full::new).map(BoxBody::new);
let fut = client.send_req(req).map_err(|err| err.to_string());
Box::pin(fut)
}
}
impl SyncSvc {
/// Collects the given [`Body`], returning a [`Bytes`].
///
/// NB: This blocks the current thread until the provided body has been collected. This is
/// an acceptable practice in test code for the sake of simplicitly, because we will always
/// provide [`SyncSvc`] with bodies that are complete.
fn collect_body<B>(body: B) -> Bytes
where
B: Body,
B::Error: std::fmt::Debug,
{
futures::executor::block_on(async move {
use http_body_util::BodyExt;
body.collect()
.await
.expect("body should not fail")
.to_bytes()
})
}
}

View File

@ -1,10 +1,11 @@
use super::*;
use std::collections::VecDeque;
use std::io;
use std::net::TcpListener as StdTcpListener;
use std::sync::atomic::{AtomicUsize, Ordering};
use tokio::net::TcpStream;
use tokio::task::JoinHandle;
use std::{
collections::VecDeque,
io,
net::TcpListener as StdTcpListener,
sync::atomic::{AtomicUsize, Ordering},
};
use tokio::{net::TcpStream, task::JoinHandle};
type TcpConnSender = mpsc::UnboundedSender<(
Option<Vec<u8>>,
@ -148,10 +149,6 @@ impl TcpServer {
}
impl TcpConn {
pub fn target_addr(&self) -> SocketAddr {
self.addr
}
pub async fn read(&self) -> Vec<u8> {
self.try_read()
.await

View File

@ -381,7 +381,7 @@ mod cross_version {
}
fn default_dst_name(port: u16) -> String {
format!("{}:{}", HOST, port)
format!("{HOST}:{port}")
}
fn send_default_dst(
@ -484,7 +484,7 @@ mod http2 {
let body = {
let body = res.into_body();
let body = http_body::Body::collect(body)
let body = http_body_util::BodyExt::collect(body)
.await
.unwrap()
.to_bytes()

View File

@ -24,7 +24,7 @@ async fn nonblocking_identity_detection() {
let msg1 = "custom tcp hello\n";
let msg2 = "custom tcp bye";
let srv = server::tcp()
let srv = crate::tcp::server()
.accept(move |read| {
assert_eq!(read, msg1.as_bytes());
msg2
@ -33,7 +33,7 @@ async fn nonblocking_identity_detection() {
.await;
let proxy = proxy.inbound(srv).run_with_test_env(env).await;
let client = client::tcp(proxy.inbound);
let client = crate::tcp::client(proxy.inbound);
// Create an idle connection and then an active connection. Ensure that
// protocol detection on the idle connection does not block communication on

View File

@ -1,5 +1,6 @@
use crate::*;
use linkerd2_proxy_api::destination as pb;
use linkerd_app_core::svc::http::BoxBody;
use std::sync::atomic::{AtomicUsize, Ordering};
struct Service {
@ -14,11 +15,17 @@ impl Service {
let counter = response_counter.clone();
let svc = server::http1()
.route_fn("/load-profile", |_| {
Response::builder().status(201).body("".into()).unwrap()
Response::builder()
.status(201)
.body(BoxBody::empty())
.unwrap()
})
.route_fn("/", move |_req| {
counter.fetch_add(1, Ordering::SeqCst);
Response::builder().status(200).body(name.into()).unwrap()
Response::builder()
.status(200)
.body(BoxBody::from_static(name))
.unwrap()
})
.run()
.await;
@ -56,7 +63,7 @@ async fn wait_for_profile_stage(client: &client::Client, metrics: &client::Clien
for _ in 0i32..10 {
assert_eq!(client.get("/load-profile").await, "");
let m = metrics.get("/metrics").await;
let stage_metric = format!("rt_load_profile=\"{}\"", stage);
let stage_metric = format!("rt_load_profile=\"{stage}\"");
if m.contains(stage_metric.as_str()) {
break;
}

View File

@ -1,3 +1,5 @@
use linkerd_app_core::svc::http::BoxBody;
use crate::*;
use std::sync::atomic::{AtomicUsize, Ordering};
@ -71,7 +73,10 @@ impl TestBuilder {
// This route is just called by the test setup, to trigger the proxy
// to start fetching the ServiceProfile.
.route_fn("/load-profile", |_| {
Response::builder().status(201).body("".into()).unwrap()
Response::builder()
.status(201)
.body(BoxBody::empty())
.unwrap()
});
if self.default_routes {
@ -83,12 +88,12 @@ impl TestBuilder {
let port = srv.addr.port();
let ctrl = controller::new();
let dst_tx = ctrl.destination_tx(format!("{}:{}", host, port));
let dst_tx = ctrl.destination_tx(format!("{host}:{port}"));
dst_tx.send_addr(srv.addr);
let ctrl = controller::new();
let dst_tx = ctrl.destination_tx(format!("{}:{}", host, port));
let dst_tx = ctrl.destination_tx(format!("{host}:{port}"));
dst_tx.send_addr(srv.addr);
let profile_tx = ctrl.profile_tx(srv.addr.to_string());
@ -121,7 +126,7 @@ impl TestBuilder {
::std::thread::sleep(Duration::from_secs(1));
Response::builder()
.status(200)
.body("slept".into())
.body(BoxBody::from_static("slept"))
.unwrap()
})
.route_async("/0.5", move |req| {
@ -129,17 +134,20 @@ impl TestBuilder {
async move {
// Read the entire body before responding, so that the
// client doesn't fail when writing it out.
let body = http_body::Body::collect(req.into_body())
let body = http_body_util::BodyExt::collect(req.into_body())
.await
.map(http_body::Collected::to_bytes);
.map(http_body_util::Collected::to_bytes);
let bytes = body.as_ref().map(Bytes::len);
tracing::debug!(?bytes, "recieved body");
Ok::<_, Error>(if fail {
Response::builder().status(533).body("nope".into()).unwrap()
Response::builder()
.status(533)
.body(BoxBody::from_static("nope"))
.unwrap()
} else {
Response::builder()
.status(200)
.body("retried".into())
.body(BoxBody::from_static("retried"))
.unwrap()
})
}
@ -147,11 +155,14 @@ impl TestBuilder {
.route_fn("/0.5/sleep", move |_req| {
::std::thread::sleep(Duration::from_secs(1));
if counter2.fetch_add(1, Ordering::Relaxed) % 2 == 0 {
Response::builder().status(533).body("nope".into()).unwrap()
Response::builder()
.status(533)
.body(BoxBody::from_static("nope"))
.unwrap()
} else {
Response::builder()
.status(200)
.body("retried".into())
.body(BoxBody::from_static("retried"))
.unwrap()
}
})
@ -159,12 +170,15 @@ impl TestBuilder {
if counter3.fetch_add(1, Ordering::Relaxed) % 2 == 0 {
Response::builder()
.status(533)
.body(vec![b'x'; 1024 * 100].into())
.body(BoxBody::new(http_body_util::Full::new(Bytes::from(vec![
b'x';
1024 * 100
]))))
.unwrap()
} else {
Response::builder()
.status(200)
.body("retried".into())
.body(BoxBody::from_static("retried"))
.unwrap()
}
})
@ -185,6 +199,8 @@ impl TestBuilder {
}
mod cross_version {
use std::convert::Infallible;
use super::*;
pub(super) async fn retry_if_profile_allows(version: server::Server) {
@ -248,7 +264,7 @@ mod cross_version {
let req = client
.request_builder("/0.5")
.method(http::Method::POST)
.body("req has a body".into())
.body(BoxBody::from_static("req has a body"))
.unwrap();
let res = client.request_body(req).await;
assert_eq!(res.status(), 200);
@ -269,7 +285,7 @@ mod cross_version {
let req = client
.request_builder("/0.5")
.method(http::Method::PUT)
.body("req has a body".into())
.body(BoxBody::from_static("req has a body"))
.unwrap();
let res = client.request_body(req).await;
assert_eq!(res.status(), 200);
@ -287,13 +303,14 @@ mod cross_version {
.await;
let client = test.client;
let (mut tx, body) = hyper::body::Body::channel();
let (mut tx, body) = http_body_util::channel::Channel::<Bytes, Infallible>::new(1024);
let req = client
.request_builder("/0.5")
.method("POST")
.body(body)
.unwrap();
let res = tokio::spawn(async move { client.request_body(req).await });
let fut = client.send_req(req);
let res = tokio::spawn(fut);
tx.send_data(Bytes::from_static(b"hello"))
.await
.expect("the whole body should be read");
@ -301,7 +318,7 @@ mod cross_version {
.await
.expect("the whole body should be read");
drop(tx);
let res = res.await.unwrap();
let res = res.await.unwrap().unwrap();
assert_eq!(res.status(), 200);
}
@ -364,7 +381,9 @@ mod cross_version {
let req = client
.request_builder("/0.5")
.method("POST")
.body(hyper::Body::from(&[1u8; 64 * 1024 + 1][..]))
.body(BoxBody::new(http_body_util::Full::new(Bytes::from(
&[1u8; 64 * 1024 + 1][..],
))))
.unwrap();
let res = client.request_body(req).await;
assert_eq!(res.status(), 533);
@ -386,13 +405,14 @@ mod cross_version {
.await;
let client = test.client;
let (mut tx, body) = hyper::body::Body::channel();
let (mut tx, body) = http_body_util::channel::Channel::<Bytes, Infallible>::new(1024);
let req = client
.request_builder("/0.5")
.method("POST")
.body(body)
.unwrap();
let res = tokio::spawn(async move { client.request_body(req).await });
let fut = client.send_req(req);
let res = tokio::spawn(fut);
// send a 32k chunk
tx.send_data(Bytes::from(&[1u8; 32 * 1024][..]))
.await
@ -406,7 +426,7 @@ mod cross_version {
.await
.expect("the whole body should be read");
drop(tx);
let res = res.await.unwrap();
let res = res.await.unwrap().unwrap();
assert_eq!(res.status(), 533);
}
@ -590,6 +610,8 @@ mod http2 {
}
mod grpc_retry {
use std::convert::Infallible;
use super::*;
use http::header::{HeaderName, HeaderValue};
static GRPC_STATUS: HeaderName = HeaderName::from_static("grpc-status");
@ -613,7 +635,7 @@ mod grpc_retry {
let rsp = Response::builder()
.header(GRPC_STATUS.clone(), header)
.status(200)
.body(hyper::Body::empty())
.body(BoxBody::empty())
.unwrap();
tracing::debug!(headers = ?rsp.headers());
rsp
@ -661,9 +683,16 @@ mod grpc_retry {
let mut trailers = HeaderMap::with_capacity(1);
trailers.insert(GRPC_STATUS.clone(), status);
tracing::debug!(?trailers);
let (mut tx, body) = hyper::body::Body::channel();
let (mut tx, body) =
http_body_util::channel::Channel::<Bytes, Error>::new(1024);
tx.send_trailers(trailers).await.unwrap();
Ok::<_, Error>(Response::builder().status(200).body(body).unwrap())
Ok::<_, Error>(
Response::builder()
.status(200)
.body(body)
.unwrap()
.map(BoxBody::new),
)
}
}
});
@ -704,10 +733,17 @@ mod grpc_retry {
let mut trailers = HeaderMap::with_capacity(1);
trailers.insert(GRPC_STATUS.clone(), GRPC_STATUS_OK.clone());
tracing::debug!(?trailers);
let (mut tx, body) = hyper::body::Body::channel();
let (mut tx, body) =
http_body_util::channel::Channel::<Bytes, Error>::new(1024);
tx.send_data("hello world".into()).await.unwrap();
tx.send_trailers(trailers).await.unwrap();
Ok::<_, Error>(Response::builder().status(200).body(body).unwrap())
Ok::<_, Error>(
Response::builder()
.status(200)
.body(body)
.unwrap()
.map(BoxBody::new),
)
}
}
});
@ -752,13 +788,20 @@ mod grpc_retry {
let mut trailers = HeaderMap::with_capacity(1);
trailers.insert(GRPC_STATUS.clone(), GRPC_STATUS_OK.clone());
tracing::debug!(?trailers);
let (mut tx, body) = hyper::body::Body::channel();
let (mut tx, body) =
http_body_util::channel::Channel::<Bytes, Infallible>::new(1024);
tokio::spawn(async move {
tx.send_data("hello".into()).await.unwrap();
tx.send_data("world".into()).await.unwrap();
tx.send_trailers(trailers).await.unwrap();
});
Ok::<_, Error>(Response::builder().status(200).body(body).unwrap())
Ok::<_, Error>(
Response::builder()
.status(200)
.body(body)
.unwrap()
.map(BoxBody::new),
)
}
}
});
@ -790,21 +833,38 @@ mod grpc_retry {
assert_eq!(retries.load(Ordering::Relaxed), 1);
}
async fn data(body: &mut hyper::Body) -> Bytes {
async fn data<B>(body: &mut B) -> B::Data
where
B: http_body::Body + Unpin,
B::Data: std::fmt::Debug,
B::Error: std::fmt::Debug,
{
use http_body_util::BodyExt;
let data = body
.data()
.frame()
.await
.expect("body data frame must not be eaten")
.unwrap();
.expect("a result")
.expect("a frame")
.into_data()
.expect("a chunk of data");
tracing::info!(?data);
data
}
async fn trailers(body: &mut hyper::Body) -> http::HeaderMap {
async fn trailers<B>(body: &mut B) -> http::HeaderMap
where
B: http_body::Body + Unpin,
B::Error: std::fmt::Debug,
{
use http_body_util::BodyExt;
let trailers = body
.trailers()
.frame()
.await
.expect("trailers future should not fail")
.expect("response should have trailers");
.expect("a result")
.expect("a frame")
.into_trailers()
.ok()
.expect("a trailers frame");
tracing::info!(?trailers);
trailers
}

View File

@ -1,3 +1,5 @@
use linkerd_app_core::svc::http::BoxBody;
use crate::*;
#[tokio::test]
@ -26,10 +28,13 @@ async fn h2_exercise_goaways_connections() {
let (shdn, rx) = shutdown_signal();
let body = Bytes::from(vec![b'1'; RESPONSE_SIZE]);
let body = http_body_util::Full::new(Bytes::from(vec![b'1'; RESPONSE_SIZE]));
let srv = server::http2()
.route_fn("/", move |_req| {
Response::builder().body(body.clone().into()).unwrap()
Response::builder()
.body(body.clone())
.unwrap()
.map(BoxBody::new)
})
.run()
.await;
@ -50,8 +55,8 @@ async fn h2_exercise_goaways_connections() {
.into_iter()
.map(Response::into_body)
.map(|body| {
http_body::Body::collect(body)
.map_ok(http_body::Collected::aggregate)
http_body_util::BodyExt::collect(body)
.map_ok(http_body_util::Collected::aggregate)
// Make sure the bodies weren't cut off
.map_ok(|buf| assert_eq!(buf.remaining(), RESPONSE_SIZE))
})
@ -72,7 +77,7 @@ async fn http1_closes_idle_connections() {
let (shdn, rx) = shutdown_signal();
const RESPONSE_SIZE: usize = 1024 * 16;
let body = Bytes::from(vec![b'1'; RESPONSE_SIZE]);
let body = http_body_util::Full::new(Bytes::from(vec![b'1'; RESPONSE_SIZE]));
let shdn = Arc::new(Mutex::new(Some(shdn)));
let srv = server::http1()
@ -80,7 +85,10 @@ async fn http1_closes_idle_connections() {
// Trigger a shutdown signal while the request is made
// but a response isn't returned yet.
shdn.lock().take().expect("only 1 request").signal();
Response::builder().body(body.clone().into()).unwrap()
Response::builder()
.body(body.clone())
.unwrap()
.map(BoxBody::new)
})
.run()
.await;
@ -101,7 +109,7 @@ async fn tcp_waits_for_proxies_to_close() {
let msg1 = "custom tcp hello\n";
let msg2 = "custom tcp bye";
let srv = server::tcp()
let srv = crate::tcp::server()
// Trigger a shutdown while TCP stream is busy
.accept_fut(move |mut sock| {
async move {
@ -117,7 +125,7 @@ async fn tcp_waits_for_proxies_to_close() {
.await;
let proxy = proxy::new().inbound(srv).shutdown_signal(rx).run().await;
let client = client::tcp(proxy.inbound);
let client = crate::tcp::client(proxy.inbound);
let tcp_client = client.connect().await;

View File

@ -254,7 +254,7 @@ async fn grpc_headers_end() {
assert_eq!(res.status(), 200);
assert_eq!(res.headers()["grpc-status"], "1");
let body = res.into_body();
let bytes = http_body::Body::collect(body)
let bytes = http_body_util::BodyExt::collect(body)
.await
.unwrap()
.to_bytes()

View File

@ -119,7 +119,7 @@ impl TcpFixture {
const BYE_MSG: &'static str = "custom tcp bye";
async fn server() -> server::Listening {
server::tcp()
crate::tcp::server()
.accept(move |read| {
assert_eq!(read, Self::HELLO_MSG.as_bytes());
TcpFixture::BYE_MSG
@ -145,7 +145,7 @@ impl TcpFixture {
.run()
.await;
let client = client::tcp(proxy.inbound);
let client = crate::tcp::client(proxy.inbound);
let metrics = client::http1(proxy.admin, "localhost");
let src_labels = metrics::labels()
@ -184,7 +184,7 @@ impl TcpFixture {
.run()
.await;
let client = client::tcp(proxy.outbound);
let client = crate::tcp::client(proxy.outbound);
let metrics = client::http1(proxy.admin, "localhost");
let src_labels = metrics::labels()
@ -292,7 +292,7 @@ async fn metrics_endpoint_outbound_response_count() {
test_http_count("response_total", Fixture::outbound()).await
}
async fn test_http_count(metric: &str, fixture: impl Future<Output = Fixture>) {
async fn test_http_count(metric_name: &str, fixture: impl Future<Output = Fixture>) {
let _trace = trace_init();
let Fixture {
client,
@ -305,9 +305,13 @@ async fn test_http_count(metric: &str, fixture: impl Future<Output = Fixture>) {
..
} = fixture.await;
let metric = labels.metric(metric);
let metric = labels.metric(metric_name);
assert!(metric.is_not_in(metrics.get("/metrics").await));
let scrape = metrics.get("/metrics").await;
assert!(
metric.is_not_in(scrape),
"{metric:?} should not be in /metrics"
);
info!("client.get(/)");
assert_eq!(client.get("/").await, "hello");
@ -319,6 +323,7 @@ async fn test_http_count(metric: &str, fixture: impl Future<Output = Fixture>) {
mod response_classification {
use super::Fixture;
use crate::*;
use linkerd_app_core::svc::http::BoxBody;
use tracing::info;
const REQ_STATUS_HEADER: &str = "x-test-status-requested";
@ -353,7 +358,7 @@ mod response_classification {
// TODO: tests for grpc statuses
unreachable!("not called in test")
} else {
Response::new("".into())
Response::new(BoxBody::empty())
};
*rsp.status_mut() = status;
rsp
@ -1304,7 +1309,7 @@ async fn metrics_compression() {
let mut body = {
let body = resp.into_body();
http_body::Body::collect(body)
http_body_util::BodyExt::collect(body)
.await
.expect("response body concat")
.aggregate()
@ -1313,9 +1318,9 @@ async fn metrics_compression() {
body.copy_to_bytes(body.remaining()),
));
let mut scrape = String::new();
decoder.read_to_string(&mut scrape).unwrap_or_else(|_| {
panic!("decode gzip (requested Accept-Encoding: {})", encoding)
});
decoder
.read_to_string(&mut scrape)
.unwrap_or_else(|_| panic!("decode gzip (requested Accept-Encoding: {encoding})"));
scrape
}
};

View File

@ -26,7 +26,7 @@ async fn is_valid_json() {
assert!(!json.is_empty());
for obj in json {
println!("{}\n", obj);
println!("{obj}\n");
}
}
@ -53,7 +53,7 @@ async fn query_is_valid_json() {
assert!(!json.is_empty());
for obj in json {
println!("{}\n", obj);
println!("{obj}\n");
}
}
@ -74,12 +74,9 @@ async fn valid_get_does_not_error() {
let json = logs.await.unwrap();
for obj in json {
println!("{}\n", obj);
println!("{obj}\n");
if obj.get("error").is_some() {
panic!(
"expected the log stream to contain no error responses!\njson = {}",
obj
);
panic!("expected the log stream to contain no error responses!\njson = {obj}");
}
}
}
@ -101,12 +98,9 @@ async fn valid_query_does_not_error() {
let json = logs.await.unwrap();
for obj in json {
println!("{}\n", obj);
println!("{obj}\n");
if obj.get("error").is_some() {
panic!(
"expected the log stream to contain no error responses!\njson = {}",
obj
);
panic!("expected the log stream to contain no error responses!\njson = {obj}");
}
}
}
@ -142,9 +136,7 @@ async fn multi_filter() {
level.and_then(|value| value.as_str()),
Some("DEBUG") | Some("INFO") | Some("WARN") | Some("ERROR")
),
"level must be DEBUG, INFO, WARN, or ERROR\n level: {:?}\n json: {:#?}",
level,
obj
"level must be DEBUG, INFO, WARN, or ERROR\n level: {level:?}\n json: {obj:#?}"
);
}
@ -175,9 +167,9 @@ async fn get_log_stream(
let req = client
.request_body(
client
.request_builder(&format!("{}?{}", PATH, filter))
.request_builder(&format!("{PATH}?{filter}"))
.method(http::Method::GET)
.body(hyper::Body::from(filter))
.body(http_body_util::Full::new(Bytes::from(filter)))
.unwrap(),
)
.await;
@ -199,7 +191,7 @@ async fn query_log_stream(
client
.request_builder(PATH)
.method("QUERY")
.body(hyper::Body::from(filter))
.body(http_body_util::Full::new(Bytes::from(filter)))
.unwrap(),
)
.await;
@ -210,19 +202,28 @@ async fn query_log_stream(
/// Spawns a task to collect all the logs in a streaming body and parse them as
/// JSON.
fn collect_logs(
mut body: hyper::Body,
) -> (JoinHandle<Vec<serde_json::Value>>, oneshot::Sender<()>) {
fn collect_logs<B>(mut body: B) -> (JoinHandle<Vec<serde_json::Value>>, oneshot::Sender<()>)
where
B: Body<Data = Bytes> + Send + Unpin + 'static,
B::Error: std::error::Error,
{
use http_body_util::BodyExt;
let (done_tx, done_rx) = oneshot::channel();
let result = tokio::spawn(async move {
let mut result = Vec::new();
let logs = &mut result;
let fut = async move {
while let Some(res) = body.data().await {
while let Some(res) = body.frame().await {
let chunk = match res {
Ok(chunk) => chunk,
Ok(frame) => {
if let Ok(data) = frame.into_data() {
data
} else {
break;
}
}
Err(e) => {
println!("body failed: {}", e);
println!("body failed: {e}");
break;
}
};

View File

@ -80,10 +80,7 @@ impl Test {
.await
};
env.put(
app::env::ENV_INBOUND_DETECT_TIMEOUT,
format!("{:?}", TIMEOUT),
);
env.put(app::env::ENV_INBOUND_DETECT_TIMEOUT, format!("{TIMEOUT:?}"));
(self.set_env)(&mut env);
@ -113,7 +110,7 @@ async fn inbound_timeout() {
let _trace = trace_init();
let (proxy, metrics) = Test::default().run().await;
let client = client::tcp(proxy.inbound);
let client = crate::tcp::client(proxy.inbound);
let _tcp_client = client.connect().await;
@ -127,26 +124,6 @@ async fn inbound_timeout() {
.await;
}
/// Tests that the detect metric is labeled and incremented on I/O error.
#[tokio::test]
async fn inbound_io_err() {
let _trace = trace_init();
let (proxy, metrics) = Test::default().run().await;
let client = client::tcp(proxy.inbound);
let tcp_client = client.connect().await;
tcp_client.write(TcpFixture::HELLO_MSG).await;
drop(tcp_client);
metric(&proxy)
.label("error", "i/o")
.value(1u64)
.assert_in(&metrics)
.await;
}
/// Tests that the detect metric is not incremented when TLS is successfully
/// detected.
#[tokio::test]
@ -167,7 +144,7 @@ async fn inbound_success() {
"foo.ns1.svc.cluster.local",
client_config.clone(),
);
let no_tls_client = client::tcp(proxy.inbound);
let no_tls_client = crate::tcp::client(proxy.inbound);
let metric = metric(&proxy)
.label("error", "tls detection timeout")
@ -192,44 +169,6 @@ async fn inbound_success() {
metric.assert_in(&metrics).await;
}
/// Tests both of the above cases together.
#[tokio::test]
async fn inbound_multi() {
let _trace = trace_init();
let (proxy, metrics) = Test::default().run().await;
let client = client::tcp(proxy.inbound);
let metric = metric(&proxy);
let timeout_metric = metric.clone().label("error", "tls detection timeout");
let io_metric = metric.label("error", "i/o");
let tcp_client = client.connect().await;
tokio::time::sleep(TIMEOUT + Duration::from_millis(15)) // just in case
.await;
timeout_metric.clone().value(1u64).assert_in(&metrics).await;
drop(tcp_client);
let tcp_client = client.connect().await;
tcp_client.write(TcpFixture::HELLO_MSG).await;
drop(tcp_client);
io_metric.clone().value(1u64).assert_in(&metrics).await;
timeout_metric.clone().value(1u64).assert_in(&metrics).await;
let tcp_client = client.connect().await;
tokio::time::sleep(TIMEOUT + Duration::from_millis(15)) // just in case
.await;
io_metric.clone().value(1u64).assert_in(&metrics).await;
timeout_metric.clone().value(2u64).assert_in(&metrics).await;
drop(tcp_client);
}
/// Tests that TLS detect failure metrics are collected for the direct stack.
#[tokio::test]
async fn inbound_direct_multi() {
@ -244,7 +183,7 @@ async fn inbound_direct_multi() {
let proxy = proxy::new().inbound(srv).inbound_direct();
let (proxy, metrics) = Test::new(proxy).run().await;
let client = client::tcp(proxy.inbound);
let client = crate::tcp::client(proxy.inbound);
let metric = metrics::metric(METRIC).label("target_addr", proxy.inbound);
let timeout_metric = metric.clone().label("error", "tls detection timeout");
@ -291,7 +230,7 @@ async fn inbound_invalid_ip() {
.run()
.await;
let client = client::tcp(proxy.inbound);
let client = crate::tcp::client(proxy.inbound);
let metric = metric(&proxy)
.label("error", "unexpected")
.label("target_addr", fake_ip);
@ -354,7 +293,7 @@ async fn inbound_direct_success() {
.await;
let tls_client = client::http1(proxy2.outbound, auth);
let no_tls_client = client::tcp(proxy1.inbound);
let no_tls_client = crate::tcp::client(proxy1.inbound);
let metric = metrics::metric(METRIC)
.label("target_addr", proxy1.inbound)

View File

@ -1,5 +1,5 @@
use crate::*;
use linkerd_app_core::svc::http::TracingExecutor;
use linkerd_app_core::svc::http::{BoxBody, TokioExecutor};
use std::error::Error as _;
use tokio::time::timeout;
@ -53,7 +53,7 @@ async fn outbound_tcp() {
let msg1 = "custom tcp hello\n";
let msg2 = "custom tcp bye";
let srv = server::tcp()
let srv = crate::tcp::server()
.accept(move |read| {
assert_eq!(read, msg1.as_bytes());
msg2
@ -70,7 +70,7 @@ async fn outbound_tcp() {
.run()
.await;
let client = client::tcp(proxy.outbound);
let client = crate::tcp::client(proxy.outbound);
let tcp_client = client.connect().await;
@ -91,7 +91,7 @@ async fn outbound_tcp_external() {
let msg1 = "custom tcp hello\n";
let msg2 = "custom tcp bye";
let srv = server::tcp()
let srv = crate::tcp::server()
.accept(move |read| {
assert_eq!(read, msg1.as_bytes());
msg2
@ -109,7 +109,7 @@ async fn outbound_tcp_external() {
.run()
.await;
let client = client::tcp(proxy.outbound);
let client = crate::tcp::client(proxy.outbound);
let tcp_client = client.connect().await;
@ -130,7 +130,7 @@ async fn inbound_tcp() {
let msg1 = "custom tcp hello\n";
let msg2 = "custom tcp bye";
let srv = server::tcp()
let srv = crate::tcp::server()
.accept(move |read| {
assert_eq!(read, msg1.as_bytes());
msg2
@ -139,7 +139,7 @@ async fn inbound_tcp() {
.await;
let proxy = proxy::new().inbound(srv).run().await;
let client = client::tcp(proxy.inbound);
let client = crate::tcp::client(proxy.inbound);
let tcp_client = client.connect().await;
@ -201,7 +201,7 @@ async fn test_inbound_server_speaks_first(env: TestEnv) {
let _trace = trace_init();
let (tx, rx) = mpsc::channel(1);
let srv = server::tcp()
let srv = crate::tcp::server()
.accept_fut(move |sock| serve_server_first(sock, tx))
.run()
.await;
@ -231,7 +231,7 @@ async fn inbound_tcp_server_first_no_discovery() {
let _trace = trace_init();
let (tx, rx) = mpsc::channel(1);
let srv = server::tcp()
let srv = crate::tcp::server()
.accept_fut(move |sock| serve_server_first(sock, tx))
.run()
.await;
@ -303,7 +303,7 @@ async fn outbound_opaque_tcp_server_first() {
let _trace = trace_init();
let (tx, rx) = mpsc::channel(1);
let srv = server::tcp()
let srv = crate::tcp::server()
.accept_fut(move |sock| serve_server_first(sock, tx))
.run()
.await;
@ -360,7 +360,7 @@ async fn serve_server_first(mut sock: tokio::net::TcpStream, tx: mpsc::Sender<()
async fn server_first_client(addr: SocketAddr, mut rx: mpsc::Receiver<()>) {
const TIMEOUT: Duration = Duration::from_secs(5);
let client = client::tcp(addr);
let client = crate::tcp::client(addr);
let tcp_client = client.connect().await;
@ -383,7 +383,7 @@ async fn tcp_connections_close_if_client_closes() {
let (tx, mut rx) = mpsc::channel::<()>(1);
let srv = server::tcp()
let srv = crate::tcp::server()
.accept_fut(move |mut sock| {
async move {
let _tx = tx;
@ -402,7 +402,7 @@ async fn tcp_connections_close_if_client_closes() {
.await;
let proxy = proxy::new().inbound(srv).run().await;
let client = client::tcp(proxy.inbound);
let client = crate::tcp::client(proxy.inbound);
let tcp_client = client.connect().await;
tcp_client.write(msg1).await;
@ -493,7 +493,7 @@ macro_rules! http1_tests {
assert_eq!(req.headers().get("host").unwrap(), host);
Response::builder()
.version(http::Version::HTTP_10)
.body("".into())
.body(linkerd_app_core::svc::http::BoxBody::empty())
.unwrap()
})
.run()
@ -530,7 +530,7 @@ macro_rules! http1_tests {
.route_fn("/", move |req| {
assert_eq!(req.headers()["host"], host);
assert_eq!(req.uri().to_string(), format!("http://{}/", auth));
Response::new("".into())
Response::new(linkerd_app_core::svc::http::BoxBody::empty())
})
.run()
.await;
@ -582,7 +582,7 @@ macro_rules! http1_tests {
let chatproto_req = "[chatproto-c]{send}: hi all\n";
let chatproto_res = "[chatproto-s]{recv}: welcome!\n";
let srv = server::tcp()
let srv = crate::tcp::server()
.accept_fut(move |mut sock| {
async move {
// Read upgrade_req...
@ -608,7 +608,7 @@ macro_rules! http1_tests {
let mk = $proxy;
let proxy = mk(srv).await;
let client = client::tcp(proxy.inbound);
let client = crate::tcp::client(proxy.inbound);
let tcp_client = client.connect().await;
@ -731,7 +731,7 @@ macro_rules! http1_tests {
let tunneled_req = b"{send}: hi all\n";
let tunneled_res = b"{recv}: welcome!\n";
let srv = server::tcp()
let srv = crate::tcp::server()
.accept_fut(move |mut sock| {
async move {
// Read connect_req...
@ -764,7 +764,7 @@ macro_rules! http1_tests {
let mk = $proxy;
let proxy = mk(srv).await;
let client = client::tcp(proxy.inbound);
let client = crate::tcp::client(proxy.inbound);
let tcp_client = client.connect().await;
@ -823,7 +823,7 @@ macro_rules! http1_tests {
let tunneled_req = b"{send}: hi all\n";
let tunneled_res = b"{recv}: welcome!\n";
let srv = server::tcp()
let srv = crate::tcp::server()
.accept_fut(move |mut sock| {
async move {
// Read connect_req...
@ -856,7 +856,7 @@ macro_rules! http1_tests {
let mk = $proxy;
let proxy = mk(srv).await;
let client = client::tcp(proxy.inbound);
let client = crate::tcp::client(proxy.inbound);
let tcp_client = client.connect().await;
@ -887,7 +887,7 @@ macro_rules! http1_tests {
async fn http11_connect_bad_requests() {
let _trace = trace_init();
let srv = server::tcp()
let srv = crate::tcp::server()
.accept(move |_sock| -> Vec<u8> {
unreachable!("shouldn't get through the proxy");
})
@ -898,7 +898,7 @@ macro_rules! http1_tests {
// A TCP client is used since the HTTP client would stop these requests
// from ever touching the network.
let client = client::tcp(proxy.inbound);
let client = crate::tcp::client(proxy.inbound);
let bad_uris = vec!["/origin-form", "/", "http://test/bar", "http://test", "*"];
@ -970,7 +970,7 @@ macro_rules! http1_tests {
let req = client
.request_builder("/")
.method("POST")
.body("hello".into())
.body(linkerd_app_core::svc::http::BoxBody::from_static("hello"))
.unwrap();
let resp = client.request_body(req).await;
@ -993,7 +993,7 @@ macro_rules! http1_tests {
Ok::<_, std::io::Error>(
Response::builder()
.header("transfer-encoding", "chunked")
.body("world".into())
.body(linkerd_app_core::svc::http::BoxBody::from_static("world"))
.unwrap(),
)
})
@ -1007,7 +1007,7 @@ macro_rules! http1_tests {
.request_builder("/")
.method("POST")
.header("transfer-encoding", "chunked")
.body("hello".into())
.body(linkerd_app_core::svc::http::BoxBody::from_static("hello"))
.unwrap();
let resp = client.request_body(req).await;
@ -1032,7 +1032,7 @@ macro_rules! http1_tests {
} else {
StatusCode::OK
};
let mut res = Response::new("".into());
let mut res = Response::new(linkerd_app_core::svc::http::BoxBody::empty());
*res.status_mut() = status;
res
})
@ -1071,7 +1071,7 @@ macro_rules! http1_tests {
Response::builder()
.status(status)
.header("content-length", "0")
.body("".into())
.body(linkerd_app_core::svc::http::BoxBody::empty())
.unwrap()
})
.run()
@ -1117,7 +1117,10 @@ macro_rules! http1_tests {
})
.unwrap_or(200);
Response::builder().status(status).body("".into()).unwrap()
Response::builder()
.status(status)
.body(linkerd_app_core::svc::http::BoxBody::empty())
.unwrap()
})
.run()
.await;
@ -1180,7 +1183,7 @@ macro_rules! http1_tests {
assert_eq!(req.method(), "HEAD");
Response::builder()
.header("content-length", "55")
.body("".into())
.body(linkerd_app_core::svc::http::BoxBody::empty())
.unwrap()
})
.run()
@ -1210,7 +1213,7 @@ macro_rules! http1_tests {
let _trace = trace_init();
// test both http/1.0 and 1.1
let srv = server::tcp()
let srv = crate::tcp::server()
.accept(move |_read| {
"\
HTTP/1.0 200 OK\r\n\
@ -1390,14 +1393,14 @@ async fn http10_without_host() {
assert_eq!(req.uri().to_string(), "/");
Response::builder()
.version(http::Version::HTTP_10)
.body("".into())
.body(BoxBody::empty())
.unwrap()
})
.run()
.await;
let proxy = proxy::new().inbound(srv).run().await;
let client = client::tcp(proxy.inbound);
let client = crate::tcp::client(proxy.inbound);
let tcp_client = client.connect().await;
@ -1587,7 +1590,7 @@ async fn http2_request_without_authority() {
let srv = server::http2()
.route_fn("/", |req| {
assert_eq!(req.uri().authority(), None);
Response::new("".into())
Response::new(BoxBody::empty())
})
.run()
.await;
@ -1602,14 +1605,15 @@ async fn http2_request_without_authority() {
let io = tokio::net::TcpStream::connect(&addr)
.await
.expect("connect error");
let (mut client, conn) = hyper::client::conn::http2::Builder::new(TracingExecutor)
.handshake(io)
let (mut client, conn) = hyper::client::conn::http2::Builder::new(TokioExecutor::new())
.timer(hyper_util::rt::TokioTimer::new())
.handshake(hyper_util::rt::TokioIo::new(io))
.await
.expect("handshake error");
tokio::spawn(conn.map_err(|e| tracing::info!("conn error: {:?}", e)));
let req = Request::new(hyper::Body::empty());
let req = Request::new(BoxBody::empty());
// these properties are specifically what we want, and set by default
assert_eq!(req.uri(), "/");
assert_eq!(req.version(), http::Version::HTTP_11);
@ -1633,12 +1637,14 @@ async fn http2_rst_stream_is_propagated() {
let proxy = proxy::new().inbound(srv).run().await;
let client = client::http2(proxy.inbound, "transparency.example.com");
let err: hyper::Error = client
let err: hyper_util::client::legacy::Error = client
.request(client.request_builder("/"))
.await
.expect_err("client request should error");
let rst = err
.source()
.expect("error should have a source")
.source()
.expect("error should have a source")
.downcast_ref::<h2::Error>()

View File

@ -1,10 +1,10 @@
[package]
name = "linkerd-app-outbound"
version = "0.1.0"
authors = ["Linkerd Developers <cncf-linkerd-dev@lists.cncf.io>"]
license = "Apache-2.0"
edition = "2021"
publish = false
version = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
edition = { workspace = true }
publish = { workspace = true }
description = """
Configures and runs the outbound proxy
"""
@ -13,7 +13,7 @@ Configures and runs the outbound proxy
default = []
allow-loopback = []
test-subscriber = []
test-util = ["linkerd-app-test", "linkerd-meshtls-rustls/test-util"]
test-util = ["linkerd-app-test", "linkerd-meshtls/test-util", "dep:http-body"]
prometheus-client-rust-242 = [] # TODO
@ -21,17 +21,18 @@ prometheus-client-rust-242 = [] # TODO
ahash = "0.8"
bytes = { workspace = true }
http = { workspace = true }
http-body = { workspace = true, optional = true }
futures = { version = "0.3", default-features = false }
linkerd2-proxy-api = { workspace = true, features = ["outbound"] }
once_cell = "1"
parking_lot = "0.12"
pin-project = "1"
prometheus-client = "0.22"
prometheus-client = { workspace = true }
thiserror = "2"
tokio = { version = "1", features = ["sync"] }
tonic = { workspace = true, default-features = false }
tower = { version = "0.4", features = ["util"] }
tracing = "0.1"
tower = { workspace = true, features = ["util"] }
tracing = { workspace = true }
linkerd-app-core = { path = "../core" }
linkerd-app-test = { path = "../test", optional = true }
@ -41,7 +42,7 @@ linkerd-http-prom = { path = "../../http/prom" }
linkerd-http-retry = { path = "../../http/retry" }
linkerd-http-route = { path = "../../http/route" }
linkerd-identity = { path = "../../identity" }
linkerd-meshtls-rustls = { path = "../../meshtls/rustls", optional = true }
linkerd-meshtls = { path = "../../meshtls", optional = true, default-features = false }
linkerd-opaq-route = { path = "../../opaq-route" }
linkerd-proxy-client-policy = { path = "../../proxy/client-policy", features = [
"proto",
@ -54,19 +55,22 @@ linkerd-tonic-watch = { path = "../../tonic-watch" }
[dev-dependencies]
futures-util = "0.3"
http-body = { workspace = true }
hyper = { workspace = true, features = ["backports", "deprecated", "http1", "http2"] }
http-body-util = { workspace = true, features = ["channel"] }
hyper = { workspace = true, features = ["http1", "http2"] }
hyper-util = { workspace = true }
tokio = { version = "1", features = ["macros", "sync", "time"] }
tokio-rustls = { workspace = true }
tokio-test = "0.4"
tower-test = "0.4"
tower-test = { workspace = true }
linkerd-app-test = { path = "../test", features = ["client-policy"] }
linkerd-http-box = { path = "../../http/box" }
linkerd-http-prom = { path = "../../http/prom", features = ["test-util"] }
linkerd-io = { path = "../../io", features = ["tokio-test"] }
linkerd-meshtls = { path = "../../meshtls", features = ["rustls"] }
linkerd-meshtls-rustls = { path = "../../meshtls/rustls", features = [
linkerd-meshtls = { path = "../../meshtls", features = [
"test-util",
] }
linkerd-mock-http-body = { path = "../../mock/http-body" }
linkerd-stack = { path = "../../stack", features = ["test-util"] }
linkerd-tracing = { path = "../../tracing", features = ["ansi"] }

View File

@ -134,7 +134,13 @@ impl<N> Outbound<N> {
.unwrap_or_else(|| (orig_dst, Default::default()));
// TODO(ver) We should be able to figure out resource coordinates for
// the endpoint?
synthesize_forward_policy(&META, detect_timeout, queue, addr, meta)
synthesize_forward_policy(
&META,
detect_timeout,
queue,
addr,
meta.into(),
)
},
);
return Ok((Some(profile), policy));
@ -189,7 +195,7 @@ pub fn synthesize_forward_policy(
timeout: Duration,
queue: policy::Queue,
addr: SocketAddr,
metadata: policy::EndpointMetadata,
metadata: Arc<policy::EndpointMetadata>,
) -> ClientPolicy {
policy_for_backend(
meta,

View File

@ -32,7 +32,7 @@ pub use self::balance::BalancerMetrics;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Dispatch {
Balance(NameAddr, EwmaConfig),
Forward(Remote<ServerAddr>, Metadata),
Forward(Remote<ServerAddr>, Arc<Metadata>),
/// A backend dispatcher that explicitly fails all requests.
Fail {
message: Arc<str>,
@ -49,7 +49,7 @@ pub struct DispatcherFailed(Arc<str>);
pub struct Endpoint<T> {
addr: Remote<ServerAddr>,
is_local: bool,
metadata: Metadata,
metadata: Arc<Metadata>,
parent: T,
queue: QueueConfig,
close_server_connection_on_remote_proxy_error: bool,
@ -120,28 +120,30 @@ impl<N> Outbound<N> {
move |parent: T| -> Result<_, Infallible> {
Ok(match parent.param() {
Dispatch::Balance(addr, ewma) => {
svc::Either::A(svc::Either::A(balance::Balance {
svc::Either::Left(svc::Either::Left(balance::Balance {
addr,
ewma,
parent,
queue,
}))
}
Dispatch::Forward(addr, metadata) => svc::Either::A(svc::Either::B({
let is_local = inbound_ips.contains(&addr.ip());
let http2 = http2.override_from(metadata.http2_client_params());
Endpoint {
is_local,
addr,
metadata,
parent,
queue,
close_server_connection_on_remote_proxy_error: true,
http1,
http2,
}
})),
Dispatch::Fail { message } => svc::Either::B(message),
Dispatch::Forward(addr, metadata) => {
svc::Either::Left(svc::Either::Right({
let is_local = inbound_ips.contains(&addr.ip());
let http2 = http2.override_from(metadata.http2_client_params());
Endpoint {
is_local,
addr,
metadata,
parent,
queue,
close_server_connection_on_remote_proxy_error: true,
http1,
http2,
}
}))
}
Dispatch::Fail { message } => svc::Either::Right(message),
})
},
svc::stack(fail).check_new_clone().into_inner(),
@ -277,6 +279,13 @@ impl<T> svc::Param<tls::ConditionalClientTls> for Endpoint<T> {
}
}
impl<T> svc::Param<tls::ConditionalClientTlsLabels> for Endpoint<T> {
fn param(&self) -> tls::ConditionalClientTlsLabels {
let tls: tls::ConditionalClientTls = self.param();
tls.as_ref().map(tls::ClientTls::labels)
}
}
impl<T> svc::Param<http::Variant> for Endpoint<T>
where
T: svc::Param<http::Variant>,

View File

@ -121,7 +121,7 @@ where
let http2 = http2.override_from(metadata.http2_client_params());
Endpoint {
addr: Remote(ServerAddr(addr)),
metadata,
metadata: metadata.into(),
is_local,
parent: target.parent,
queue: http_queue,

Some files were not shown because too many files have changed in this diff Show More