Skip to content

Commit

Permalink
Merge branch 'main' of github.com:kube-rs/kube into matei/fork-add-fu…
Browse files Browse the repository at this point in the history
…t-impl
  • Loading branch information
mateiidavid committed Apr 3, 2024
2 parents c7fc333 + cb77247 commit 1b81f4c
Show file tree
Hide file tree
Showing 16 changed files with 90 additions and 133 deletions.
32 changes: 31 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,38 @@
<!-- next-header -->
UNRELEASED
===================
* see https://github.com/kube-rs/kube/compare/0.89.0...main
* see https://github.com/kube-rs/kube/compare/0.90.0...main

[0.90.0](https://github.com/kube-rs/kube/releases/tag/0.90.0) / 2024-04-03
===================
<!-- Release notes generated using configuration in .github/release.yml at 0.90.0 -->
## Highlights
### [`kube::client::Body`](https://docs.rs/kube/latest/kube/client/struct.Body.html) Improvements
- Unit testing helpers #1444 + #1445,
- Accuracy; `size_hint` and `is_end_stream` implemented in #1452 + internal cleanups #1453 and #1455

### Dependency Cleanups
- `rustls` to 0.23 in #1457
- `once_cell` removed in #1447 (no longer needed)
- `futures` feature prune in #1442
- `chrono` features prune in #1448, and bump its min version pin in #1458

## What's Changed
### Added
* Add proxy `Body::collect_bytes` for easier unit tests by @clux in https://github.com/kube-rs/kube/pull/1445
### Changed
* update to `rustls` 0.23 by @tottoto in https://github.com/kube-rs/kube/pull/1457
### Fixed
* disable unused `futures` feature by @tottoto in https://github.com/kube-rs/kube/pull/1442
* Expose `Body::empty` for easier tests by @clux in https://github.com/kube-rs/kube/pull/1444
* replace `once_cell` Lazy with ordinary static by @tottoto in https://github.com/kube-rs/kube/pull/1447
* replace `chrono` feature `clock` with `now` by @tottoto in https://github.com/kube-rs/kube/pull/1448
* implement `http_body` trait method by @tottoto in https://github.com/kube-rs/kube/pull/1452
* Fix examples for custom clients not authenticating by @clux in https://github.com/kube-rs/kube/pull/1450
* Set a compatible minimum `chrono` version by @clux in https://github.com/kube-rs/kube/pull/1458


**Full Changelog**: https://github.com/kube-rs/kube/compare/0.89.0...0.90.0
[0.89.0](https://github.com/kube-rs/kube/releases/tag/0.89.0) / 2024-03-26
===================
<!-- Release notes generated using configuration in .github/release.yml at 0.89.0 -->
Expand Down
9 changes: 4 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ members = [
]

[workspace.package]
version = "0.89.0"
version = "0.90.0"
authors = [
"clux <[email protected]>",
"Natalie Klestrup Röijezon <[email protected]>",
Expand All @@ -38,7 +38,7 @@ async-trait = "0.1.64"
backoff = "0.4.0"
base64 = "0.22.0"
bytes = "1.1.0"
chrono = { version = "0.4.23", default-features = false }
chrono = { version = "0.4.34", default-features = false }
darling = "0.20.3"
derivative = "2.1.1"
either = "1.6.1"
Expand All @@ -52,21 +52,20 @@ http-body-util = "0.1.1"
hyper = "1.2.0"
hyper-util = "0.1.3"
hyper-openssl = "0.10.2"
hyper-rustls = "0.26.0"
hyper-rustls = { version = "0.27.0", default-features = false }
hyper-socks2 = { version = "0.9.0", default-features = false }
hyper-timeout = "0.5.1"
json-patch = "1.0.0"
jsonpath-rust = "0.5.0"
k8s-openapi = { version = "0.21.0", default-features = false }
once_cell = "1.8.0"
openssl = "0.10.36"
parking_lot = "0.12.0"
pem = "3.0.1"
pin-project = "1.0.4"
proc-macro2 = "1.0.29"
quote = "1.0.10"
rand = "0.8.3"
rustls = "0.22.0"
rustls = { version = "0.23.0", default-features = false }
rustls-pemfile = "2.0.0"
schemars = "0.8.6"
secrecy = "0.8.0"
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Select a version of `kube` along with the generated [k8s-openapi](https://github

```toml
[dependencies]
kube = { version = "0.89.0", features = ["runtime", "derive"] }
kube = { version = "0.90.0", features = ["runtime", "derive"] }
k8s-openapi = { version = "0.21.1", features = ["latest"] }
```

Expand Down Expand Up @@ -152,7 +152,7 @@ By default [rustls](https://github.com/ctz/rustls) is used for TLS, but `openssl

```toml
[dependencies]
kube = { version = "0.89.0", default-features = false, features = ["client", "openssl-tls"] }
kube = { version = "0.90.0", default-features = false, features = ["client", "openssl-tls"] }
k8s-openapi = { version = "0.21.0", features = ["latest"] }
```

Expand Down
42 changes: 0 additions & 42 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,6 @@ vulnerability = "deny"
unmaintained = "warn"
yanked = "warn"
notice = "warn"
ignore = [
# Ignoring issues related to `localtime_r` for now
# See https://github.com/kube-rs/kube/issues/650
#
# Potential segfault in the `time` crate
# Tracking issue: https://github.com/kube-rs/kube/issues/656
# PR to update `time`: https://github.com/chronotope/chrono/pull/578
"RUSTSEC-2020-0071",
# Potential segfault in `localtime_r` invocations
# Tracking issue: https://github.com/kube-rs/kube/issues/660
# Upstream issue: https://github.com/chronotope/chrono/issues/499
"RUSTSEC-2020-0159",
]


[licenses]
Expand All @@ -41,7 +28,6 @@ allow = [
"BSD-3-Clause",
"ISC",
"LicenseRef-ring",
"LicenseRef-webpki",
]

exceptions = [
Expand All @@ -61,22 +47,6 @@ license-files = [
{ path = "LICENSE", hash = 0xbd0eed23 },
]


[[licenses.clarify]]
name = "webpki"
expression = "LicenseRef-webpki"
license-files = [
{ path = "LICENSE", hash = 0x001c7e6c },
]

# rustls' webpki fork uses same license https://github.com/rustls/webpki
[[licenses.clarify]]
name = "rustls-webpki"
expression = "LicenseRef-webpki"
license-files = [
{ path = "LICENSE", hash = 0x001c7e6c },
]

[sources]
unknown-registry = "deny"
unknown-git = "deny"
Expand All @@ -98,14 +68,6 @@ name = "syn"
# https://github.com/jcreekmore/pem-rs/blob/master/Cargo.toml#L16
name = "base64"

[[bans.skip]]
# used by h2->hyper->hyper-openssl (we have latest)
# newer used by serde_json
name = "indexmap"
[[bans.skip]]
# via indexmap - have to also skip this
name = "hashbrown"

[[bans.skip]]
# latest via openssl->hyper-openssl (we have latest)
# newer via tower-http (we have latest)
Expand All @@ -117,7 +79,3 @@ name = "redox_syscall"

[[bans.skip-tree]]
name = "windows-sys"

[[bans.skip]]
# deep in dependency tree, dual use via tokio and hyper (needs a bump there)
name = "socket2"
2 changes: 1 addition & 1 deletion e2e/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ anyhow.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
futures.workspace = true
kube = { path = "../kube", version = "^0.89.0", default-features = false, features = ["client", "runtime", "ws", "admission", "gzip"] }
kube = { path = "../kube", version = "^0.90.0", default-features = false, features = ["client", "runtime", "ws", "admission", "gzip"] }
k8s-openapi.workspace = true
serde_json.workspace = true
tokio = { workspace = true, features = ["full"] }
4 changes: 2 additions & 2 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ garde = { version = "0.18.0", default-features = false, features = ["derive"] }
anyhow.workspace = true
futures = { workspace = true, features = ["async-await"] }
jsonpath-rust.workspace = true
kube = { path = "../kube", version = "^0.89.0", default-features = false, features = ["admission"] }
kube-derive = { path = "../kube-derive", version = "^0.89.0", default-features = false } # only needed to opt out of schema
kube = { path = "../kube", version = "^0.90.0", default-features = false, features = ["admission"] }
kube-derive = { path = "../kube-derive", version = "^0.90.0", default-features = false } # only needed to opt out of schema
k8s-openapi.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
Expand Down
2 changes: 2 additions & 0 deletions examples/custom_client_tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ async fn main() -> anyhow::Result<()> {
let https = config.openssl_https_connector()?;
let service = ServiceBuilder::new()
.layer(config.base_uri_layer())
.option_layer(config.auth_layer()?)
.service(hyper_util::client::legacy::Client::builder(TokioExecutor::new()).build(https));
Client::new(service, config.default_namespace)
} else {
let https = config.rustls_https_connector()?;
let service = ServiceBuilder::new()
.layer(config.base_uri_layer())
.option_layer(config.auth_layer()?)
.service(hyper_util::client::legacy::Client::builder(TokioExecutor::new()).build(https));
Client::new(service, config.default_namespace)
};
Expand Down
1 change: 1 addition & 0 deletions examples/custom_client_trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ async fn main() -> anyhow::Result<()> {
.layer(tower::limit::ConcurrencyLimitLayer::new(4))
// Add `DecompressionLayer` to make request headers interesting.
.layer(DecompressionLayer::new())
.option_layer(config.auth_layer()?)
.layer(
// Attribute names follow [Semantic Conventions].
// [Semantic Conventions]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#http-client
Expand Down
7 changes: 3 additions & 4 deletions kube-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ kubelet-debug = ["ws", "kube-core/kubelet-debug"]
oauth = ["client", "tame-oauth"]
oidc = ["client", "form_urlencoded"]
gzip = ["client", "tower-http/decompression-gzip"]
client = ["config", "__non_core", "hyper", "hyper-util", "http-body", "http-body-util", "tower", "tower-http", "hyper-timeout", "pin-project", "chrono", "jsonpath-rust", "bytes", "futures", "tokio", "tokio-util", "either"]
client = ["config", "__non_core", "hyper", "hyper-util", "http-body", "http-body-util", "tower", "tower-http", "hyper-timeout", "chrono", "jsonpath-rust", "bytes", "futures", "tokio", "tokio-util", "either"]
jsonpatch = ["kube-core/jsonpatch"]
admission = ["kube-core/admission"]
config = ["__non_core", "pem", "home"]
Expand Down Expand Up @@ -57,19 +57,18 @@ rustls = { workspace = true, optional = true }
rustls-pemfile = { workspace = true, optional = true }
bytes = { workspace = true, optional = true }
tokio = { workspace = true, features = ["time", "signal", "sync"], optional = true }
kube-core = { path = "../kube-core", version = "=0.89.0" }
kube-core = { path = "../kube-core", version = "=0.90.0" }
jsonpath-rust = { workspace = true, optional = true }
tokio-util = { workspace = true, features = ["io", "codec"], optional = true }
hyper = { workspace = true, features = ["client", "http1"], optional = true }
hyper-util = { workspace = true, features = ["client", "client-legacy", "http1", "tokio"], optional = true }
hyper-rustls = { workspace = true, optional = true }
hyper-rustls = { workspace = true, features = ["http1", "logging", "native-tokio", "ring", "tls12"], optional = true }
hyper-socks2 = { workspace = true, optional = true }
tokio-tungstenite = { workspace = true, optional = true }
tower = { workspace = true, features = ["buffer", "filter", "util"], optional = true }
tower-http = { workspace = true, features = ["auth", "map-response-body", "trace"], optional = true }
hyper-timeout = { workspace = true, optional = true }
tame-oauth = { workspace = true, features = ["gcp"], optional = true }
pin-project = { workspace = true, optional = true }
rand = { workspace = true, optional = true }
secrecy = { workspace = true, features = ["alloc", "serde"] }
tracing = { workspace = true, features = ["log"], optional = true }
Expand Down
70 changes: 25 additions & 45 deletions kube-client/src/client/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ use std::{
};

use bytes::Bytes;
use futures::stream::Stream;
use http_body::{Body as HttpBody, Frame};
use http_body_util::{combinators::UnsyncBoxBody, BodyExt};
use pin_project::pin_project;
use futures::{stream::Stream, TryStreamExt};
use http_body::{Body as HttpBody, Frame, SizeHint};
use http_body_util::{combinators::UnsyncBoxBody, BodyExt, BodyStream};

/// A request body.
pub struct Body {
Expand Down Expand Up @@ -44,6 +43,17 @@ impl Body {
{
Body::new(Kind::Wrap(body.map_err(Into::into).boxed_unsync()))
}

/// Collect all the data frames and trailers of the request body
pub async fn collect_bytes(self) -> Result<Bytes, crate::Error> {
Ok(self.collect().await?.to_bytes())
}

pub(crate) fn into_data_stream(
self,
) -> impl Stream<Item = Result<<Self as HttpBody>::Data, <Self as HttpBody>::Error>> {
Box::pin(BodyStream::new(self).try_filter_map(|frame| async { Ok(frame.into_data().ok()) }))
}
}

impl From<Bytes> for Body {
Expand Down Expand Up @@ -84,50 +94,20 @@ impl HttpBody for Body {
),
}
}
}

// Wrap `http_body::Body` to implement `Stream`.
#[pin_project]
pub struct BodyDataStream<B> {
#[pin]
body: B,
}

impl<B> BodyDataStream<B> {
pub(crate) fn new(body: B) -> Self {
Self { body }
}
}

impl<B> Stream for BodyDataStream<B>
where
B: HttpBody<Data = Bytes>,
{
type Item = Result<B::Data, B::Error>;

fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
loop {
return match ready!(self.as_mut().project().body.poll_frame(cx)) {
Some(Ok(frame)) => {
let Ok(bytes) = frame.into_data() else {
continue;
};
Poll::Ready(Some(Ok(bytes)))
}
Some(Err(err)) => Poll::Ready(Some(Err(err))),
None => Poll::Ready(None),
};
fn size_hint(&self) -> SizeHint {
match &self.kind {
Kind::Once(Some(bytes)) => SizeHint::with_exact(bytes.len() as u64),
Kind::Once(None) => SizeHint::with_exact(0),
Kind::Wrap(body) => body.size_hint(),
}
}
}

pub trait IntoBodyDataStream: HttpBody {
fn into_stream(self) -> BodyDataStream<Self>
where
Self: Sized,
{
BodyDataStream::new(self)
fn is_end_stream(&self) -> bool {
match &self.kind {
Kind::Once(Some(bytes)) => bytes.is_empty(),
Kind::Once(None) => true,
Kind::Wrap(body) => body.is_end_stream(),
}
}
}

impl<T> IntoBodyDataStream for T where T: HttpBody {}
26 changes: 9 additions & 17 deletions kube-client/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ use crate::{api::WatchEvent, error::ErrorResponse, Config, Error, Result};
mod auth;
mod body;
mod builder;
// Add `into_stream()` to `http::Body`
use body::IntoBodyDataStream as _;
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-client")))]
#[cfg(feature = "unstable-client")]
mod client_ext;
Expand Down Expand Up @@ -271,10 +269,7 @@ impl Client {
let res = handle_api_errors(res).await?;
// Map the error, since we want to convert this into an `AsyncBufReader` using
// `into_async_read` which specifies `std::io::Error` as the stream's error type.
let body = BodyExt::map_err(res.into_body(), |e| {
std::io::Error::new(std::io::ErrorKind::Other, e)
})
.into_stream();
let body = res.into_body().into_data_stream().map_err(std::io::Error::other);
Ok(body.into_async_read())
}

Expand Down Expand Up @@ -314,17 +309,14 @@ impl Client {
tracing::trace!("headers: {:?}", res.headers());

let frames = FramedRead::new(
StreamReader::new(
BodyExt::map_err(res.into_body(), |e| {
// Unexpected EOF from chunked decoder.
// Tends to happen when watching for 300+s. This will be ignored.
if e.to_string().contains("unexpected EOF during chunk") {
return std::io::Error::new(std::io::ErrorKind::UnexpectedEof, e);
}
std::io::Error::new(std::io::ErrorKind::Other, e)
})
.into_stream(),
),
StreamReader::new(res.into_body().into_data_stream().map_err(|e| {
// Unexpected EOF from chunked decoder.
// Tends to happen when watching for 300+s. This will be ignored.
if e.to_string().contains("unexpected EOF during chunk") {
return std::io::Error::new(std::io::ErrorKind::UnexpectedEof, e);
}
std::io::Error::other(e)
})),
LinesCodec::new(),
);

Expand Down
3 changes: 1 addition & 2 deletions kube-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ thiserror.workspace = true
form_urlencoded.workspace = true
http.workspace = true
json-patch = { workspace = true, optional = true }
once_cell.workspace = true
chrono = { workspace = true, features = ["clock"] }
chrono = { workspace = true, features = ["now"] }
schemars = { workspace = true, optional = true }
k8s-openapi.workspace = true

Expand Down
Loading

0 comments on commit 1b81f4c

Please sign in to comment.