Skip to content

Commit

Permalink
feat: Support customizing the container templates for wasmcloud and nats
Browse files Browse the repository at this point in the history
Signed-off-by: Joonas Bergius <[email protected]>
  • Loading branch information
joonas committed Jan 9, 2025
1 parent 4ccfb20 commit 6b7f684
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 43 deletions.
22 changes: 11 additions & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "wasmcloud-operator"
version = "0.4.2"
version = "0.5.0"
edition = "2021"

[[bin]]
Expand Down
2 changes: 1 addition & 1 deletion crates/types/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "wasmcloud-operator-types"
version = "0.1.8"
version = "0.1.9"
edition = "2021"

[package.metadata.cargo-machete]
Expand Down
36 changes: 34 additions & 2 deletions crates/types/src/v1alpha1/wasmcloud_host_config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use k8s_openapi::api::core::v1::{PodSpec, ResourceRequirements, Volume};
use k8s_openapi::api::core::v1::{Container, PodSpec, ResourceRequirements, Volume};
use kube::CustomResource;
use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -104,9 +104,23 @@ pub struct KubernetesSchedulingOptions {
/// https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ for valid
/// values to use here.
pub resources: Option<WasmCloudHostConfigResources>,
#[schemars(schema_with = "pod_schema")]
/// Any other pod template spec options to set for the underlying wasmCloud host pods.
#[schemars(schema_with = "pod_schema")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pod_template_additions: Option<PodSpec>,
/// Allow for customization of either the wasmcloud or nats leaf container inside of the wasmCloud host pod.
pub container_template_additions: Option<ContainerTemplateAdditions>,
}

#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct ContainerTemplateAdditions {
#[schemars(schema_with = "container_schema")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub nats: Option<Container>,
#[schemars(schema_with = "container_schema")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub wasmcloud: Option<Container>,
}

#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema)]
Expand Down Expand Up @@ -165,6 +179,24 @@ fn pod_schema(_gen: &mut SchemaGenerator) -> Schema {
val.schema.into()
}

/// This is a workaround for the fact that we can't override the Container schema to make name
/// an optional field. It generates the OpenAPI schema for the Container type the same way that
/// kube.rs does while dropping any required fields.
fn container_schema(_gen: &mut SchemaGenerator) -> Schema {
let gen = schemars::gen::SchemaSettings::openapi3()
.with(|s| {
s.inline_subschemas = true;
s.meta_schema = None;
})
.with_visitor(kube::core::schema::StructuralSchemaRewriter)
.into_generator();
let mut val = gen.into_root_schema_for::<Container>();
// Drop `name` as a required field as it will be filled in from container
// definition coming the controller that this configuration gets merged into.
val.schema.object.as_mut().unwrap().required = BTreeSet::new();
val.schema.into()
}

fn default_host_replicas() -> u32 {
1
}
Expand Down
75 changes: 47 additions & 28 deletions src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use k8s_openapi::api::core::v1::{
};
use k8s_openapi::api::rbac::v1::{PolicyRule, Role, RoleBinding, RoleRef, Subject};
use k8s_openapi::apimachinery::pkg::apis::meta::v1::LabelSelector;
use k8s_openapi::DeepMerge;
use kube::{
api::{Api, ObjectMeta, Patch, PatchParams},
client::Client as KubeClient,
Expand Down Expand Up @@ -546,7 +547,7 @@ async fn pod_template(config: &WasmCloudHostConfig, ctx: Arc<Context>) -> Result
});
}

let containers = vec![
let mut containers = vec![
Container {
name: "nats-leaf".to_string(),
image: Some(leaf_image),
Expand Down Expand Up @@ -586,6 +587,22 @@ async fn pod_template(config: &WasmCloudHostConfig, ctx: Arc<Context>) -> Result
},
];

if let Some(cta) = &config
.spec
.scheduling_options
.as_ref()
.and_then(|so| so.container_template_additions.clone())
{
if let Some(mut nats_container) = cta.nats.clone() {
nats_container.merge_from(containers[0].clone());
containers[0] = nats_container;
}
if let Some(mut wasmcloud_container) = cta.wasmcloud.clone() {
wasmcloud_container.merge_from(containers[1].clone());
containers[1] = wasmcloud_container;
}
}

let service_account = config.name_any();
let mut template = PodTemplateSpec {
metadata: Some(ObjectMeta {
Expand Down Expand Up @@ -830,35 +847,37 @@ async fn configure_hosts(config: &WasmCloudHostConfig, ctx: Arc<Context>) -> Res
];
}

if let Some(scheduling_options) = &config.spec.scheduling_options {
if scheduling_options.daemonset {
let mut spec = daemonset_spec(config, ctx.clone()).await?;
spec.template.spec.as_mut().unwrap().containers[1]
.env
.as_mut()
.unwrap()
.append(&mut env_vars);
let ds = DaemonSet {
metadata: ObjectMeta {
name: Some(config.name_any()),
namespace: Some(config.namespace().unwrap()),
owner_references: Some(vec![config.controller_owner_ref(&()).unwrap()]),
labels: Some(common_labels()),
..Default::default()
},
spec: Some(spec),
if config
.spec
.scheduling_options
.as_ref()
.is_some_and(|so| so.daemonset)
{
let mut spec = daemonset_spec(config, ctx.clone()).await?;
spec.template.spec.as_mut().unwrap().containers[1]
.env
.as_mut()
.unwrap()
.append(&mut env_vars);
let ds = DaemonSet {
metadata: ObjectMeta {
name: Some(config.name_any()),
namespace: Some(config.namespace().unwrap()),
owner_references: Some(vec![config.controller_owner_ref(&()).unwrap()]),
labels: Some(common_labels()),
..Default::default()
};
},
spec: Some(spec),
..Default::default()
};

let api =
Api::<DaemonSet>::namespaced(ctx.client.clone(), &config.namespace().unwrap());
api.patch(
&config.name_any(),
&PatchParams::apply(CLUSTER_CONFIG_FINALIZER),
&Patch::Apply(ds),
)
.await?;
}
let api = Api::<DaemonSet>::namespaced(ctx.client.clone(), &config.namespace().unwrap());
api.patch(
&config.name_any(),
&PatchParams::apply(CLUSTER_CONFIG_FINALIZER),
&Patch::Apply(ds),
)
.await?;
} else {
let mut spec = deployment_spec(config, ctx.clone()).await?;
spec.template.spec.as_mut().unwrap().containers[1]
Expand Down

0 comments on commit 6b7f684

Please sign in to comment.