Skip to content

Commit

Permalink
move kube -> kube-client and try to make a facade crate (#652)
Browse files Browse the repository at this point in the history
* move kube -> kube-client and try to make a facade crate

Signed-off-by: clux <sszynrae@gmail.com>

* move relative imports from kube-runtime -> kube-client

Signed-off-by: clux <sszynrae@gmail.com>

* client: fd -e rs | xargs sed -i 's/kube\:\:/kube_client\:\:/g'

also add a standalone readme
Signed-off-by: clux <sszynrae@gmail.com>

* kube-derive path correcting (now always points at kube-core)

Signed-off-by: clux <sszynrae@gmail.com>

* kube-derive to point dev-deps at kube-core as well

Signed-off-by: clux <sszynrae@gmail.com>

* fix kube not re-exporting config when client feature set

Signed-off-by: clux <sszynrae@gmail.com>

* Update kube/src/lib.rs

Co-authored-by: kazk <kazk.dev@gmail.com>
Signed-off-by: clux <sszynrae@gmail.com>

* Update kube-client/README.md

Co-authored-by: kazk <kazk.dev@gmail.com>
Signed-off-by: clux <sszynrae@gmail.com>

* ensure kube::core == kube-client::core == kube-core

so that we can use same paths equally depending on where we require them

Signed-off-by: clux <sszynrae@gmail.com>

* add #[kube(kube_crate = "kube")] attr

defaults to kube and will append ::core if kube or kube_client
but users can also use it with kube_core directly

Signed-off-by: clux <sszynrae@gmail.com>

* revert change to kube-dervive dev-dependencies

they need to look like they came from the facade crate

Signed-off-by: clux <sszynrae@gmail.com>

* rename to #[kube(kube...)] and document

Signed-off-by: clux <sszynrae@gmail.com>

* doc tweaks and fixes

Signed-off-by: clux <sszynrae@gmail.com>

* start writing an architecture md

Signed-off-by: clux <sszynrae@gmail.com>

* fix imports from new events moudle after crate-split

Signed-off-by: clux <sszynrae@gmail.com>

* architecture mostly done

Signed-off-by: clux <sszynrae@gmail.com>

* kube root crate documentation and fmt

Signed-off-by: clux <sszynrae@gmail.com>

* maintain kube doc imports from kube-client

Signed-off-by: clux <sszynrae@gmail.com>

* use kube imports in examples

Signed-off-by: clux <sszynrae@gmail.com>

* Allow `#[derive(CustomResource)]` to take an arbitrary path to `kube_core` (#658)

* Allow `#[derive(CustomResource)]` to take an arbitrary path to `kube_core`

Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se>

* Update kube-derive/src/lib.rs

Co-authored-by: Eirik A <sszynrae@gmail.com>

Co-authored-by: Eirik A <sszynrae@gmail.com>
Signed-off-by: clux <sszynrae@gmail.com>

* Update kube-derive/src/lib.rs

Co-authored-by: kazk <kazk.dev@gmail.com>
Signed-off-by: clux <sszynrae@gmail.com>

minor doc improvements

Signed-off-by: clux <sszynrae@gmail.com>

Update architecture.md

Co-authored-by: kazk <kazk.dev@gmail.com>
Signed-off-by: clux <sszynrae@gmail.com>

Update architecture.md

Co-authored-by: kazk <kazk.dev@gmail.com>
Signed-off-by: clux <sszynrae@gmail.com>

Update architecture.md

Co-authored-by: kazk <kazk.dev@gmail.com>
Signed-off-by: clux <sszynrae@gmail.com>

Update architecture.md

Co-authored-by: kazk <kazk.dev@gmail.com>
Signed-off-by: clux <sszynrae@gmail.com>

Update architecture.md

Co-authored-by: kazk <kazk.dev@gmail.com>
Signed-off-by: clux <sszynrae@gmail.com>

Update examples/README.md

Co-authored-by: kazk <kazk.dev@gmail.com>
Signed-off-by: clux <sszynrae@gmail.com>

Update architecture.md

Co-authored-by: kazk <kazk.dev@gmail.com>

Update architecture.md

Co-authored-by: kazk <kazk.dev@gmail.com>

Update architecture.md

Co-authored-by: kazk <kazk.dev@gmail.com>

Update architecture.md

Co-authored-by: kazk <kazk.dev@gmail.com>

* conditions::is_accepted for crds with await_condition (#659)

* add conditions::is_accepted for crds - closes #655

Signed-off-by: clux <sszynrae@gmail.com>

* rename to established based on new information + timout guard

Signed-off-by: clux <sszynrae@gmail.com>

* simplify a bit

Signed-off-by: clux <sszynrae@gmail.com>

* traitify condition

Signed-off-by: clux <sszynrae@gmail.com>

* docs for Condition fn trait

Signed-off-by: clux <sszynrae@gmail.com>

* add example for await_condition as well

Signed-off-by: clux <sszynrae@gmail.com>

* fix pedantic lints

Signed-off-by: clux <sszynrae@gmail.com>

* add root docs for condition waiting and fill doc gaps in runtime

Signed-off-by: clux <sszynrae@gmail.com>

* runtime::events: remove client validation + simplify module (#662)

- simpler names for snappier docs
- removes client side validation - see #654
- everything in one file in root (200 lines after all)
- avoids clippy lint

Signed-off-by: clux <sszynrae@gmail.com>

* Update architecture.md

Co-authored-by: Teo Klestrup Röijezon <teo.roijezon@stackable.de>

Update architecture.md

Co-authored-by: Teo Klestrup Röijezon <teo.roijezon@stackable.de>

Update architecture.md

Co-authored-by: Teo Klestrup Röijezon <teo.roijezon@stackable.de>
Signed-off-by: clux <sszynrae@gmail.com>

* change core example in kube-client root

Signed-off-by: clux <sszynrae@gmail.com>

* add overlaps and crate delineation at the end

Signed-off-by: clux <sszynrae@gmail.com>

* Events api improvements (#663)

* add Resource::object_ref helper to simplify event recording

Signed-off-by: clux <sszynrae@gmail.com>

* a few more simplifications to events recorder

Signed-off-by: clux <sszynrae@gmail.com>

* fmt

Signed-off-by: clux <sszynrae@gmail.com>

* clippy + broken doc links

Signed-off-by: clux <sszynrae@gmail.com>

* one line clarification

Signed-off-by: clux <sszynrae@gmail.com>

* remove remnants of derive feature from kube-client

Signed-off-by: clux <sszynrae@gmail.com>

* only clone what is necessary

Signed-off-by: clux <sszynrae@gmail.com>

* code review doc comments

Signed-off-by: clux <sszynrae@gmail.com>

* 2021 edition (#664)

Signed-off-by: clux <sszynrae@gmail.com>

Co-authored-by: kazk <kazk.dev@gmail.com>
Co-authored-by: Teo Klestrup Röijezon <teo.roijezon@stackable.de>
  • Loading branch information
3 people committed Oct 22, 2021
1 parent 015979b commit 8effb4f
Show file tree
Hide file tree
Showing 76 changed files with 1,067 additions and 797 deletions.
6 changes: 5 additions & 1 deletion CONTRIBUTING.md
Expand Up @@ -27,6 +27,10 @@ satisfy the above requirement.
This project has adopted the [CNCF Code of
Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).

## Contact
## Support
### Documentation
The [high-level architecture document](./architecture.md) is written for contributors.

### Contact
You can ask general questions / share ideas / query the community at the [kube-rs discussions forum](https://github.com/kube-rs/kube-rs/discussions).
You can reach the maintainers of this project at [#kube](https://discord.gg/tokio) channel on the Tokio discord.
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -2,6 +2,7 @@
default-members = ["kube"]
members = [
"kube",
"kube-client",
"kube-core",
"kube-derive",
"kube-runtime",
Expand Down
6 changes: 3 additions & 3 deletions Makefile
Expand Up @@ -9,10 +9,10 @@ clippy:

fmt:
#rustup component add rustfmt --toolchain nightly
rustfmt +nightly --edition 2018 $$(find . -type f -iname *.rs)
rustfmt +nightly --edition 2021 $$(find . -type f -iname *.rs)

doc:
RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --lib --workspace --features=derive,ws,oauth,jsonpatch --open
RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --lib --workspace --features=derive,ws,oauth,jsonpatch,client,derive,runtime,admission --open

test:
cargo test --all
Expand All @@ -22,7 +22,7 @@ test:
cd kube && cargo test --lib --features=derive

readme:
rustdoc README.md --test --edition=2018
rustdoc README.md --test --edition=2021

kind-create:
kind create cluster
Expand Down
13 changes: 5 additions & 8 deletions README.md
Expand Up @@ -17,7 +17,6 @@ Select a version of `kube` along with the generated [k8s-openapi](https://github
```toml
[dependencies]
kube = "0.61.0"
kube-runtime = "0.61.0"
k8s-openapi = { version = "0.13.1", default-features = false, features = ["v1_22"] }
```

Expand All @@ -32,10 +31,9 @@ All crates herein are versioned and [released](./release.toml) together to guara

## Usage

See the [examples directory](./examples) for how to use any of these crates.
See the **[examples directory](./examples)** for how to use any of these crates.

- **[kube API Docs](https://docs.rs/kube/)**
- **[kube-runtime API Docs](https://docs.rs/kube-runtime/)**

Official examples:

Expand All @@ -54,19 +52,19 @@ Real world users:

## Api

The direct `Api` type takes a client, and is constructed with either the `::all` or `::namespaced` functions:
The [`Api`](https://docs.rs/kube/*/kube/struct.Api.html) is what interacts with kubernetes resources, and is generic over [`Resource`](https://docs.rs/kube/*/kube/trait.Resource.html):

```rust
use k8s_openapi::api::core::v1::Pod;
let pods: Api<Pod> = Api::namespaced(client, "default");
let pods: Api<Pod> = Api::namespaced(client, "apps");

let p = pods.get("blog").await?;
println!("Got blog pod with containers: {:?}", p.spec.unwrap().containers);

let patch = json!({"spec": {
"activeDeadlineSeconds": 5
}});
let pp = PatchParams::apply("my_manager");
let pp = PatchParams::apply("my_controller");
let patched = pods.patch("blog", &pp, &Patch::Apply(patch)).await?;
assert_eq!(patched.spec.active_deadline_seconds, Some(5));

Expand Down Expand Up @@ -105,7 +103,7 @@ There are a ton of kubebuilder-like instructions that you can annotate with here

## Runtime

The `kube_runtime` crate contains sets of higher level abstractions on top of the `Api` and `Resource` types so that you don't have to do all the `watch`/`resourceVersion`/storage book-keeping yourself.
The `runtime` module exports the `kube_runtime` crate and contains higher level abstractions on top of the `Api` and `Resource` types so that you don't have to do all the `watch`/`resourceVersion`/storage book-keeping yourself.

### Watchers

Expand Down Expand Up @@ -168,7 +166,6 @@ Kube has basic support ([with caveats](https://github.com/kube-rs/kube-rs/issues
```toml
[dependencies]
kube = { version = "0.61.0", default-features = false, features = ["client", "rustls-tls"] }
kube-runtime = { version = "0.61.0" }
k8s-openapi = { version = "0.13.1", default-features = false, features = ["v1_22"] }
```

Expand Down
212 changes: 212 additions & 0 deletions architecture.md

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions examples/Cargo.toml
Expand Up @@ -7,18 +7,19 @@ authors = [
"kazk <kazk.dev@gmail.com>",
]
publish = false
edition = "2018"
edition = "2021"
license = "Apache-2.0"

[package.metadata.release]
release = false

[features]
default = ["native-tls", "schema", "kubederive", "ws", "latest"]
default = ["native-tls", "schema", "kubederive", "ws", "latest", "runtime"]
kubederive = ["kube/derive"] # by default import kube-derive with its default features
schema = ["kube-derive/schema"] # crd_derive_no_schema shows how to opt out
native-tls = ["kube/client", "kube/native-tls"]
rustls-tls = ["kube/client", "kube/rustls-tls"]
runtime = ["kube/runtime"]
ws = ["kube/ws"]
latest = ["k8s-openapi/v1_22"]
deprecated = ["kube/deprecated-crd-v1beta1", "k8s-openapi/v1_21"]
Expand All @@ -32,8 +33,6 @@ env_logger = "0.9.0"
futures = "0.3.17"
kube = { path = "../kube", version = "^0.61.0", default-features = false, features = ["admission"] }
kube-derive = { path = "../kube-derive", version = "^0.61.0", default-features = false } # only needed to opt out of schema
kube-runtime = { path = "../kube-runtime", version = "^0.61.0"}
kube-core = { path = "../kube-core", version = "^0.61.0", default-features = false }
k8s-openapi = { version = "0.13.1", default-features = false }
log = "0.4.11"
serde = { version = "1.0.130", features = ["derive"] }
Expand Down
2 changes: 1 addition & 1 deletion examples/README.md
Expand Up @@ -23,7 +23,7 @@ NAMESPACE=dev cargo run --example log_stream -- kafka-manager-7d4f4bd8dc-f6c44
```

## kube admission controller example
Admission controllers are a bit of a special beast. They don't need `kube_runtime` because they simply get changes sent to them over `https`, but you do instead need a webserver, certificates, and either your controller deployed behind a `Service`, or as we do here: running locally with a private ip that your `k3d` cluster can reach.
Admission controllers are a bit of a special beast. They don't actually need `kube_client` (unless you need to verify something with the api-server) or `kube_runtime` (unless you also build a complementing reconciler) because, by themselves, they simply get changes sent to them over `https`. You will need a webserver, certificates, and either your controller deployed behind a `Service`, or as we do here: running locally with a private ip that your `k3d` cluster can reach.

```sh
export ADMISSION_PRIVATE_IP=192.168.1.163
Expand Down
5 changes: 1 addition & 4 deletions examples/admission_controller.rs
Expand Up @@ -2,10 +2,7 @@ use kube::core::{
admission::{AdmissionRequest, AdmissionResponse, AdmissionReview},
DynamicObject, ResourceExt,
};
use std::{
convert::{Infallible, TryInto},
error::Error,
};
use std::{convert::Infallible, error::Error};
#[macro_use] extern crate log;
use warp::{reply, Filter, Reply};

Expand Down
2 changes: 1 addition & 1 deletion examples/configmap_reflector.rs
Expand Up @@ -3,9 +3,9 @@ use futures::{StreamExt, TryStreamExt};
use k8s_openapi::api::core::v1::ConfigMap;
use kube::{
api::{Api, ListParams, ResourceExt},
runtime::{reflector, reflector::Store, utils::try_flatten_applied, watcher},
Client,
};
use kube_runtime::{reflector, reflector::Store, utils::try_flatten_applied, watcher};

fn spawn_periodic_reader(reader: Store<ConfigMap>) {
tokio::spawn(async move {
Expand Down
2 changes: 1 addition & 1 deletion examples/configmap_watcher.rs
Expand Up @@ -3,9 +3,9 @@ use futures::{StreamExt, TryStreamExt};
use k8s_openapi::api::core::v1::ConfigMap;
use kube::{
api::{Api, ListParams},
runtime::watcher,
Client,
};
use kube_runtime::watcher;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
Expand Down
6 changes: 3 additions & 3 deletions examples/configmapgen_controller.rs
Expand Up @@ -6,10 +6,10 @@ use k8s_openapi::{
apimachinery::pkg::apis::meta::v1::{ObjectMeta, OwnerReference},
};
use kube::{
api::{ListParams, Patch, PatchParams, Resource},
Api, Client, CustomResource,
api::{Api, ListParams, Patch, PatchParams, Resource},
runtime::controller::{Context, Controller, ReconcilerAction},
Client, CustomResource,
};
use kube_runtime::controller::{Context, Controller, ReconcilerAction};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use snafu::{Backtrace, OptionExt, ResultExt, Snafu};
Expand Down
38 changes: 6 additions & 32 deletions examples/crd_apply.rs
@@ -1,13 +1,13 @@
#[macro_use] extern crate log;
use futures::{StreamExt, TryStreamExt};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use apiexts::CustomResourceDefinition;
use k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions::v1 as apiexts;

use kube::{
api::{Api, ListParams, Patch, PatchParams, ResourceExt, WatchEvent},
api::{Api, Patch, PatchParams, ResourceExt},
runtime::wait::{await_condition, conditions},
Client, CustomResource, CustomResourceExt,
};

Expand Down Expand Up @@ -46,7 +46,10 @@ async fn main() -> anyhow::Result<()> {
info!("Creating crd: {}", serde_yaml::to_string(&Foo::crd())?);
crds.patch("foos.clux.dev", &ssapply, &Patch::Apply(Foo::crd()))
.await?;
wait_for_crd_ready(&crds).await?; // wait for k8s to deal with it

info!("Waiting for the api-server to accept the CRD");
let establish = await_condition(crds, "foos.clux.dev", conditions::is_crd_established());
let _ = tokio::time::timeout(std::time::Duration::from_secs(10), establish).await?;

// Start applying foos
let foos: Api<Foo> = Api::namespaced(client.clone(), &namespace);
Expand Down Expand Up @@ -78,32 +81,3 @@ async fn main() -> anyhow::Result<()> {

Ok(())
}

// manual way to check that a CRD has been installed
async fn wait_for_crd_ready(crds: &Api<CustomResourceDefinition>) -> anyhow::Result<()> {
if crds.get("foos.clux.dev").await.is_ok() {
return Ok(());
}
// Wait for the apply to take place (takes a sec or two during first install)
let lp = ListParams::default()
.fields(&format!("metadata.name={}", "foos.clux.dev")) // our crd only
.timeout(5); // should not take long
let mut stream = crds.watch(&lp, "0").await?.boxed();

while let Some(status) = stream.try_next().await? {
if let WatchEvent::Modified(s) = status {
info!("Modify event for {}", s.name());
if let Some(s) = s.status {
if let Some(conds) = s.conditions {
if let Some(pcond) = conds.iter().find(|c| c.type_ == "NamesAccepted") {
if pcond.status == "True" {
info!("crd was accepted: {:?}", pcond);
return Ok(());
}
}
}
}
}
}
Err(anyhow::anyhow!("Timed out waiting for crd to become accepted"))
}
31 changes: 8 additions & 23 deletions examples/crd_derive_schema.rs
Expand Up @@ -6,6 +6,7 @@ use kube::{
Api, ApiResource, DeleteParams, DynamicObject, GroupVersionKind, ListParams, Patch, PatchParams,
PostParams, WatchEvent,
},
runtime::wait::{await_condition, conditions},
Client, CustomResource, CustomResourceExt,
};
use schemars::JsonSchema;
Expand Down Expand Up @@ -224,30 +225,14 @@ async fn create_crd(client: Client) -> Result<CustomResourceDefinition> {
let api = Api::<CustomResourceDefinition>::all(client);
api.create(&PostParams::default(), &Foo::crd()).await?;

// Wait until ready
let timeout_secs = 15;
let lp = ListParams::default()
.fields("metadata.name=foos.clux.dev")
.timeout(timeout_secs);
let mut stream = api.watch(&lp, "0").await?.boxed_local();
while let Some(status) = stream.try_next().await? {
if let WatchEvent::Modified(crd) = status {
let accepted = crd
.status
.as_ref()
.and_then(|s| s.conditions.as_ref())
.map(|sc| {
sc.iter()
.any(|c| c.type_ == "NamesAccepted" && c.status == "True")
})
.unwrap_or(false);
if accepted {
return Ok(crd);
}
}
}
// Wait until it's accepted and established by the api-server
println!("Waiting for the api-server to accept the CRD");
let establish = await_condition(api.clone(), "foos.clux.dev", conditions::is_crd_established());
let _ = tokio::time::timeout(std::time::Duration::from_secs(10), establish).await?;

Err(anyhow!(format!("CRD not ready after {} seconds", timeout_secs)))
// It's served by the api - get it and return it
let crd = api.get("foos.clux.dev").await?;
Ok(crd)
}

// Delete the CRD if it exists and wait until it's deleted.
Expand Down
3 changes: 2 additions & 1 deletion examples/crd_reflector.rs
Expand Up @@ -4,9 +4,10 @@ use k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions::v1::CustomRe

use kube::{
api::{Api, ListParams, Patch, PatchParams, ResourceExt},
runtime::{reflector, utils::try_flatten_applied, watcher},
Client, CustomResource, CustomResourceExt,
};
use kube_runtime::{reflector, utils::try_flatten_applied, watcher};

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

Expand Down
2 changes: 1 addition & 1 deletion examples/deployment_reflector.rs
Expand Up @@ -3,9 +3,9 @@ use futures::{StreamExt, TryStreamExt};
use k8s_openapi::api::apps::v1::Deployment;
use kube::{
api::{Api, ListParams, ResourceExt},
runtime::{reflector, utils::try_flatten_applied, watcher},
Client,
};
use kube_runtime::{reflector, utils::try_flatten_applied, watcher};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
Expand Down
8 changes: 5 additions & 3 deletions examples/dynamic_watcher.rs
@@ -1,9 +1,11 @@
use futures::prelude::*;
use kube::{
api::{DynamicObject, GroupVersionKind, ListParams, ResourceExt},
discovery, Api, Client,
api::{Api, DynamicObject, GroupVersionKind, ListParams, ResourceExt},
discovery,
runtime::{utils::try_flatten_applied, watcher},
Client,
};
use kube_runtime::{utils::try_flatten_applied, watcher};

use std::env;

#[tokio::main]
Expand Down
2 changes: 1 addition & 1 deletion examples/event_watcher.rs
Expand Up @@ -3,9 +3,9 @@ use futures::{StreamExt, TryStreamExt};
use k8s_openapi::api::core::v1::Event;
use kube::{
api::{Api, ListParams},
runtime::{utils::try_flatten_applied, watcher},
Client,
};
use kube_runtime::{utils::try_flatten_applied, watcher};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
Expand Down
2 changes: 1 addition & 1 deletion examples/multi_watcher.rs
Expand Up @@ -6,9 +6,9 @@ use k8s_openapi::api::{
};
use kube::{
api::{Api, ListParams, ResourceExt},
runtime::{utils::try_flatten_applied, watcher},
Client,
};
use kube_runtime::{utils::try_flatten_applied, watcher};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
Expand Down
2 changes: 1 addition & 1 deletion examples/node_reflector.rs
Expand Up @@ -3,9 +3,9 @@ use futures::{StreamExt, TryStreamExt};
use k8s_openapi::api::core::v1::Node;
use kube::{
api::{Api, ListParams, ResourceExt},
runtime::{reflector, utils::try_flatten_applied, watcher},
Client,
};
use kube_runtime::{reflector, utils::try_flatten_applied, watcher};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
Expand Down
2 changes: 1 addition & 1 deletion examples/node_watcher.rs
Expand Up @@ -3,9 +3,9 @@ use futures::{StreamExt, TryStreamExt};
use k8s_openapi::api::core::v1::{Event, Node};
use kube::{
api::{Api, ListParams, ResourceExt},
runtime::{utils::try_flatten_applied, watcher},
Client,
};
use kube_runtime::{utils::try_flatten_applied, watcher};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
Expand Down
7 changes: 5 additions & 2 deletions examples/pod_reflector.rs
@@ -1,8 +1,11 @@
use color_eyre::Result;
use futures::prelude::*;
use k8s_openapi::api::core::v1::Pod;
use kube::{api::ListParams, Api, Client};
use kube_runtime::{reflector, watcher};
use kube::{
api::{Api, ListParams},
runtime::{reflector, watcher},
Client,
};

#[tokio::main]
async fn main() -> Result<()> {
Expand Down

0 comments on commit 8effb4f

Please sign in to comment.