feat: Add openwebui installation example #277
13
Cargo.lock
generated
13
Cargo.lock
generated
@@ -2944,6 +2944,19 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "example-openwebui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"harmony",
|
||||
"harmony_cli",
|
||||
"harmony_macros",
|
||||
"harmony_types",
|
||||
"tokio",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "example-operatorhub-catalogsource"
|
||||
version = "0.1.0"
|
||||
|
||||
16
examples/openwebui/Cargo.toml
Normal file
16
examples/openwebui/Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "example-openwebui"
|
||||
edition = "2024"
|
||||
version.workspace = true
|
||||
readme.workspace = true
|
||||
license.workspace = true
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
harmony = { path = "../../harmony" }
|
||||
harmony_cli = { path = "../../harmony_cli" }
|
||||
harmony_macros = { path = "../../harmony_macros" }
|
||||
harmony_types = { path = "../../harmony_types" }
|
||||
tokio = { workspace = true }
|
||||
url = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
101
examples/openwebui/src/main.rs
Normal file
101
examples/openwebui/src/main.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use harmony::{
|
||||
inventory::Inventory,
|
||||
modules::helm::chart::{HelmChartScore, HelmRepository, NonBlankString},
|
||||
topology::{K8sAnywhereTopology, TlsRouter, Topology},
|
||||
};
|
||||
use harmony_macros::hurl;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
harmony_cli::cli_logger::init();
|
||||
|
||||
let ollama_url = "http://your-ollama-server:11434";
|
||||
deploy(ollama_url).await
|
||||
}
|
||||
|
||||
async fn deploy(ollama_url: &str) {
|
||||
let topology = K8sAnywhereTopology::from_env();
|
||||
topology.ensure_ready().await.unwrap();
|
||||
|
||||
let domain = topology
|
||||
.get_internal_domain()
|
||||
.await
|
||||
.unwrap()
|
||||
.expect("cluster ingress domain not found — ensure this is an OKD cluster");
|
||||
|
||||
let ingress_host = format!("openwebui.{}", domain);
|
||||
|
||||
let webui_secret_key = "CHANGE-ME-TO-A-STRONG-RANDOM-SECRET";
|
||||
|
||||
let values_yaml = format!(
|
||||
r#"ollama:
|
||||
enabled: false
|
||||
ollamaUrls:
|
||||
- "{ollama_url}"
|
||||
pipelines:
|
||||
enabled: false
|
||||
tika:
|
||||
enabled: false
|
||||
websocket:
|
||||
enabled: false
|
||||
replicaCount: 1
|
||||
persistence:
|
||||
enabled: true
|
||||
size: 5Gi
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClass: ""
|
||||
extraEnvVars:
|
||||
- name: WEBUI_SECRET_KEY
|
||||
value: "{webui_secret_key}"
|
||||
podSecurityContext:
|
||||
runAsNonRoot: true
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containerSecurityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
ingress:
|
||||
enabled: true
|
||||
annotations:
|
||||
route.openshift.io/termination: edge
|
||||
host: "{ingress_host}"
|
||||
tls: true
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
containerPort: 8080"#,
|
||||
ollama_url = ollama_url,
|
||||
ingress_host = ingress_host,
|
||||
webui_secret_key = webui_secret_key,
|
||||
);
|
||||
|
||||
let openwebui = HelmChartScore {
|
||||
namespace: Some(NonBlankString::from_str("openwebui").unwrap()),
|
||||
release_name: NonBlankString::from_str("openwebui").unwrap(),
|
||||
chart_name: NonBlankString::from_str("open-webui/open-webui").unwrap(),
|
||||
chart_version: None,
|
||||
values_overrides: None,
|
||||
values_yaml: Some(values_yaml),
|
||||
create_namespace: true,
|
||||
install_only: false,
|
||||
repository: Some(HelmRepository::new(
|
||||
"open-webui".to_string(),
|
||||
hurl!("https://open-webui.github.io/helm-charts/"),
|
||||
true,
|
||||
)),
|
||||
};
|
||||
|
||||
harmony_cli::run(
|
||||
Inventory::autoload(),
|
||||
topology,
|
||||
vec![Box::new(openwebui)],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
@@ -205,43 +205,45 @@ impl<T: Topology + HelmCommand> Interpret<T> for HelmChartInterpret {
|
||||
.unwrap_or_else(|| todo!("Get namespace from active kubernetes cluster"));
|
||||
|
||||
let ns_str = ns.to_string();
|
||||
if let Some(installed_chart) = self.find_installed_release(topology, &ns_str)? {
|
||||
return match self.expected_chart_field() {
|
||||
Some(expected)
|
||||
if Self::normalize_chart_field(&expected)
|
||||
== Self::normalize_chart_field(&installed_chart) =>
|
||||
{
|
||||
warn!(
|
||||
"Helm release '{}' already installed at desired version ('{}'); skipping.",
|
||||
self.score.release_name, installed_chart
|
||||
);
|
||||
Ok(Outcome::success(format!(
|
||||
"Helm Chart {} already at desired version",
|
||||
self.score.release_name
|
||||
)))
|
||||
}
|
||||
Some(expected) => Err(InterpretError::new(format!(
|
||||
"Helm release '{}' already installed as '{}', but score requests '{}'. \
|
||||
Refusing to upgrade/downgrade; resolve manually.",
|
||||
self.score.release_name, installed_chart, expected
|
||||
))),
|
||||
None => {
|
||||
warn!(
|
||||
"Helm release '{}' already installed as '{}'; score has no pinned \
|
||||
chart_version so skipping re-install.",
|
||||
self.score.release_name, installed_chart
|
||||
);
|
||||
Ok(Outcome::success(format!(
|
||||
"Helm Chart {} already installed (version not pinned)",
|
||||
self.score.release_name
|
||||
)))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
self.add_repo(topology)?;
|
||||
|
||||
let mut args = if self.score.install_only {
|
||||
// In install only mode we don't want to fail all the time, only when requesting
|
||||
// something that looks like an upgrade
|
||||
if let Some(installed_chart) = self.find_installed_release(topology, &ns_str)? {
|
||||
return match self.expected_chart_field() {
|
||||
Some(expected)
|
||||
if Self::normalize_chart_field(&expected)
|
||||
== Self::normalize_chart_field(&installed_chart) =>
|
||||
{
|
||||
warn!(
|
||||
"Helm release '{}' already installed at desired version ('{}'); skipping.",
|
||||
self.score.release_name, installed_chart
|
||||
);
|
||||
Ok(Outcome::success(format!(
|
||||
"Helm Chart {} already at desired version",
|
||||
self.score.release_name
|
||||
)))
|
||||
}
|
||||
Some(expected) => Err(InterpretError::new(format!(
|
||||
"Helm release '{}' already installed as '{}', but score requests '{}'. \
|
||||
Refusing to upgrade/downgrade; resolve manually.",
|
||||
self.score.release_name, installed_chart, expected
|
||||
))),
|
||||
None => {
|
||||
warn!(
|
||||
"Helm release '{}' already installed as '{}'; score has no pinned \
|
||||
chart_version so skipping re-install.",
|
||||
self.score.release_name, installed_chart
|
||||
);
|
||||
Ok(Outcome::success(format!(
|
||||
"Helm Chart {} already installed (version not pinned)",
|
||||
self.score.release_name
|
||||
)))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
vec!["install"]
|
||||
} else {
|
||||
vec!["upgrade", "--install"]
|
||||
|
||||
Reference in New Issue
Block a user