Skip to content

Commit

Permalink
feat(helm): begin implementation of helm actor
Browse files Browse the repository at this point in the history
  • Loading branch information
HoKim98 committed Jul 31, 2024
1 parent 9bcd184 commit 41cddfa
Show file tree
Hide file tree
Showing 29 changed files with 1,069 additions and 86 deletions.
9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ members = [
"crates/cassette-plugin-cdl-dataset-stream-reader",
"crates/cassette-plugin-cdl-zone",
"crates/cassette-plugin-helm-api",
"crates/cassette-plugin-helm-core",
"crates/cassette-plugin-jwt",
"crates/cassette-plugin-kubernetes-api",
"crates/cassette-plugin-kubernetes-core",
Expand Down Expand Up @@ -41,7 +42,7 @@ blocks_in_conditions = "allow" # opentelemetry tracing macro would be noisy

[workspace.dependencies]
ark-core = { git = "https://github.com/ulagbulag/OpenARK" }
ark-core-k8s = { git = "https://github.com/ulagbulag/OpenARK" }
ark-core-k8s = { git = "https://github.com/ulagbulag/OpenARK", default-features = false }
dash-pipe-provider = { git = "https://github.com/ulagbulag/OpenARK", default-features = false }
dash-api = { git = "https://github.com/ulagbulag/OpenARK", default-features = false }
vine-api = { git = "https://github.com/ulagbulag/OpenARK", default-features = false }
Expand Down Expand Up @@ -86,6 +87,12 @@ patternfly-yew = { version = "0.6", default-features = false, features = [
"yew-nested-router",
] }
regex = { version = "1.10", default-features = false }
reqwest = { version = "0.12", default-features = false, features = [
"charset",
"http2",
"json",
"macos-system-configuration",
] }
schemars = { version = "0.8", default-features = false, features = ["uuid1"] }
serde = { version = "1.0", default-features = false }
serde_json = { version = "1.0", default-features = false }
Expand Down
3 changes: 3 additions & 0 deletions crates/cassette-core/src/components/actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ pub struct Props {
pub uri: String,
pub values: Rc<DataTable>,

#[prop_or_default]
pub create: Option<bool>,

#[prop_or_default]
pub delete: Option<bool>,

Expand Down
11 changes: 11 additions & 0 deletions crates/cassette-core/src/data/actor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use schemars::schema::RootSchema;
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct JsonSchemaActor {
#[serde(default)]
pub create: Option<RootSchema>,

#[serde(default)]
pub update: Option<RootSchema>,
}
1 change: 1 addition & 0 deletions crates/cassette-core/src/data/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod actor;
#[cfg(feature = "cdl")]
pub mod cdl;
pub mod csv;
Expand Down
1 change: 1 addition & 0 deletions crates/cassette-core/src/keycode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub const KEYCODE_ENTER: u32 = 13;
2 changes: 2 additions & 0 deletions crates/cassette-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ pub mod cassette;
pub mod components;
pub mod data;
pub mod document;
#[cfg(feature = "ui")]
pub mod keycode;
pub mod net;
pub mod result;
pub mod task;
Expand Down
89 changes: 66 additions & 23 deletions crates/cassette-core/src/net/fetch.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{fmt, future::Future, marker::PhantomData, mem, ops, rc::Rc};
use std::{borrow::Cow, fmt, future::Future, marker::PhantomData, mem, ops, rc::Rc};

#[cfg(feature = "stream")]
use anyhow::Result;
Expand All @@ -13,34 +13,50 @@ use yew::platform::spawn_local;

use crate::cassette::GenericCassetteTaskHandle;

pub type FetchRequestWithoutBody<Url> = FetchRequest<Url, ()>;
pub type FetchRequestWithoutBody<Uri> = FetchRequest<Uri, ()>;

pub struct FetchRequest<Url, Req> {
pub struct FetchRequest<Uri, Req> {
pub method: Method,
pub name: &'static str,
pub url: Url,
pub name: Cow<'static, str>,
pub uri: Uri,
pub body: Option<Body<Req>>,
}

pub enum Body<T> {
Json(T),
}

impl<Url, Req> FetchRequest<Url, Req> {
impl<Uri, Req> FetchRequest<Uri, Req> {
pub fn try_fetch<State, Res>(self, base_url: &str, state: State)
where
State: 'static + GenericCassetteTaskHandle<FetchState<Res>>,
for<'a> <State as GenericCassetteTaskHandle<FetchState<Res>>>::Ref<'a>:
ops::Deref<Target = FetchState<Res>>,
Req: 'static + Serialize,
Res: 'static + DeserializeOwned,
Url: fmt::Display,
Uri: fmt::Display,
{
let handler = |result| match result {
crate::result::HttpResult::Ok(data) => FetchState::Completed(data),
crate::result::HttpResult::Err(error) => FetchState::Error(error),
};
self.try_fetch_with(base_url, state, handler)
self.try_fetch_with(base_url, state, handler, false)
}

pub fn try_fetch_force<State, Res>(self, base_url: &str, state: State)
where
State: 'static + GenericCassetteTaskHandle<FetchState<Res>>,
for<'a> <State as GenericCassetteTaskHandle<FetchState<Res>>>::Ref<'a>:
ops::Deref<Target = FetchState<Res>>,
Req: 'static + Serialize,
Res: 'static + DeserializeOwned,
Uri: fmt::Display,
{
let handler = |result| match result {
crate::result::HttpResult::Ok(data) => FetchState::Completed(data),
crate::result::HttpResult::Err(error) => FetchState::Error(error),
};
self.try_fetch_with(base_url, state, handler, true)
}

pub fn try_fetch_unchecked<State, Res>(self, base_url: &str, state: State)
Expand All @@ -50,33 +66,51 @@ impl<Url, Req> FetchRequest<Url, Req> {
ops::Deref<Target = FetchState<Res>>,
Req: 'static + Serialize,
Res: 'static + DeserializeOwned,
Url: fmt::Display,
Uri: fmt::Display,
{
let handler = FetchState::Completed;
self.try_fetch_with(base_url, state, handler)
self.try_fetch_with(base_url, state, handler, false)
}

fn try_fetch_with<State, Res, ResRaw, F>(self, base_url: &str, state: State, handler: F)
pub fn try_fetch_unchecked_force<State, Res>(self, base_url: &str, state: State)
where
State: 'static + GenericCassetteTaskHandle<FetchState<Res>>,
for<'a> <State as GenericCassetteTaskHandle<FetchState<Res>>>::Ref<'a>:
ops::Deref<Target = FetchState<Res>>,
Req: 'static + Serialize,
Res: 'static + DeserializeOwned,
Uri: fmt::Display,
{
let handler = FetchState::Completed;
self.try_fetch_with(base_url, state, handler, true)
}

fn try_fetch_with<State, Res, ResRaw, F>(
self,
base_url: &str,
state: State,
handler: F,
force: bool,
) where
State: 'static + GenericCassetteTaskHandle<FetchState<Res>>,
for<'a> <State as GenericCassetteTaskHandle<FetchState<Res>>>::Ref<'a>:
ops::Deref<Target = FetchState<Res>>,
Req: 'static + Serialize,
Res: 'static + DeserializeOwned,
ResRaw: 'static + DeserializeOwned,
Url: fmt::Display,
Uri: fmt::Display,
F: 'static + FnOnce(ResRaw) -> FetchState<Res>,
{
if matches!(*state.get(), FetchState::Pending) {
if force || matches!(*state.get(), FetchState::Pending) {
state.set(FetchState::Fetching);

let Self {
method,
name,
url: suffix_url,
uri,
body,
} = self;
let url = format!("{base_url}{suffix_url}");
let url = format!("{base_url}{uri}");

let state = state.clone();
spawn_local(async move {
Expand All @@ -92,10 +126,19 @@ impl<Url, Req> FetchRequest<Url, Req> {

let value = match builder {
Ok(builder) => match builder.send().await {
Ok(response) => match response.json().await {
Ok(data) => handler(data),
Ok(response) => match response.text().await {
Ok(text) => match ::serde_json::from_str(&text) {
Ok(data) => handler(data),
Err(_) => {
if text.is_empty() {
FetchState::Error("No Response".into())
} else {
FetchState::Error(text)
}
}
},
Err(error) => {
FetchState::Error(format!("Failed to parse the {name}: {error}"))
FetchState::Error(format!("Failed to read the {name}: {error}"))
}
},
Err(error) => {
Expand All @@ -104,15 +147,15 @@ impl<Url, Req> FetchRequest<Url, Req> {
},
Err(state) => state,
};
if matches!(*state.get(), FetchState::Pending | FetchState::Fetching) {
if force || matches!(*state.get(), FetchState::Pending | FetchState::Fetching) {
state.set(value);
}
})
}
}
}

impl<Url, Req> FetchRequest<Url, Req> {
impl<Uri, Req> FetchRequest<Uri, Req> {
pub fn try_stream_with<'reader, State, Res, F, Fut>(
self,
base_url: &str,
Expand All @@ -124,7 +167,7 @@ impl<Url, Req> FetchRequest<Url, Req> {
ops::Deref<Target = FetchState<Res>>,
Req: 'static + Serialize,
Res: 'static + DeserializeOwned,
Url: fmt::Display,
Uri: fmt::Display,
F: 'static + FnMut(StreamContext<'reader, State, Req, Res>) -> Fut,
Fut: Future<Output = Result<StreamState<Req, Res>>>,
{
Expand All @@ -134,10 +177,10 @@ impl<Url, Req> FetchRequest<Url, Req> {
let Self {
method,
name,
url: suffix_url,
uri,
mut body,
} = self;
let url = format!("{base_url}{suffix_url}");
let url = format!("{base_url}{uri}");

let mut last_data = None;
let state = state.clone();
Expand Down
18 changes: 10 additions & 8 deletions crates/cassette-core/src/net/gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ use yew::prelude::*;
use super::fetch::{FetchRequest, FetchState};

#[hook]
pub fn use_fetch<Req, Res, Url>(
request: impl 'static + FnOnce() -> FetchRequest<Url, Req>,
pub fn use_fetch<Req, Res, Uri>(
request: impl 'static + FnOnce() -> FetchRequest<Uri, Req>,
) -> UseStateHandle<FetchState<Res>>
where
Req: 'static + Serialize,
Res: 'static + DeserializeOwned,
Url: 'static + fmt::Display,
Uri: 'static + fmt::Display,
{
let state = use_state(|| FetchState::<Res>::Pending);
{
Expand All @@ -24,13 +24,13 @@ where
}

#[hook]
fn use_fetch_unchecked<Req, Res, Url>(
request: impl 'static + FnOnce() -> FetchRequest<Url, Req>,
fn use_fetch_unchecked<Req, Res, Uri>(
request: impl 'static + FnOnce() -> FetchRequest<Uri, Req>,
) -> UseStateHandle<FetchState<Res>>
where
Req: 'static + Serialize,
Res: 'static + DeserializeOwned,
Url: 'static + fmt::Display,
Uri: 'static + fmt::Display,
{
let state = use_state(|| FetchState::<Res>::Pending);
{
Expand Down Expand Up @@ -92,10 +92,12 @@ pub fn use_gateway_status() -> String {

#[cfg(not(feature = "examples"))]
{
use std::borrow::Cow;

let state = use_fetch_unchecked::<(), String, _>(move || super::fetch::FetchRequest {
method: super::fetch::Method::GET,
name: "gateway health",
url: "/_health",
name: Cow::Borrowed("gateway health"),
uri: "/_health",
body: None,
});
state.to_string()
Expand Down
5 changes: 4 additions & 1 deletion crates/cassette-gateway/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ openssl-tls = [
"actix-web/openssl",
"cassette-plugin-cdl-api/openssl-tls",
"kube/openssl-tls",
"reqwest?/native-tls",
]
rustls-tls = [
"actix-web/rustls",
"cassette-plugin-cdl-api/rustls-tls",
"kube/rustls-tls",
"reqwest?/rustls-tls",
]

# OpenARK
Expand All @@ -52,7 +54,7 @@ vine = [
cdl = ["cassette-core/cdl", "dep:cassette-plugin-cdl-api"]

## Helm
helm = ["dep:cassette-plugin-helm-api"]
helm = ["dep:cassette-plugin-helm-api", "dep:reqwest"]

## Kubernetes
kubernetes = ["dep:cassette-plugin-kubernetes-api"]
Expand All @@ -73,6 +75,7 @@ clap = { workspace = true }
futures = { workspace = true }
kube = { workspace = true, features = ["client", "runtime", "ws"] }
mime = { workspace = true }
reqwest = { workspace = true, optional = true }
serde = { workspace = true }
tokio = { workspace = true, features = ["full"] }
tracing = { workspace = true }
Expand Down
8 changes: 7 additions & 1 deletion crates/cassette-plugin-helm-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "cassette-plugin-helm-api"

authors = { workspace = true }
description = { workspace = true }
documentation = "https://docs.rs/cassette-plugin-kubernetes-api"
documentation = "https://docs.rs/cassette-plugin-helm-api"
edition = { workspace = true }
include = { workspace = true }
keywords = { workspace = true }
Expand All @@ -25,6 +25,7 @@ vine = ["cassette-plugin-kubernetes-api/vine"]

[dependencies]
cassette-core = { path = "../cassette-core", features = ["api"] }
cassette-plugin-helm-core = { path = "../cassette-plugin-helm-core" }
cassette-plugin-kubernetes-api = { path = "../cassette-plugin-kubernetes-api" }
cassette-plugin-kubernetes-core = { path = "../cassette-plugin-kubernetes-core" }

Expand All @@ -33,5 +34,10 @@ anyhow = { workspace = true }
itertools = { workspace = true }
k8s-openapi = { workspace = true }
kube = { workspace = true }
reqwest = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
serde_yml = { workspace = true }
tokio = { workspace = true, features = ["process"] }
tracing = { workspace = true }
uuid = { workspace = true }
Loading

0 comments on commit 41cddfa

Please sign in to comment.