Compare commits
3 Commits
bea386a2e2
...
feat/cnpgO
| Author | SHA1 | Date | |
|---|---|---|---|
| f242aafebb | |||
| 3e14ebd62c | |||
| 1b19638df4 |
15
Cargo.lock
generated
15
Cargo.lock
generated
@@ -1835,6 +1835,21 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "example-operatorhub-catalogsource"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cidr",
|
||||||
|
"env_logger",
|
||||||
|
"harmony",
|
||||||
|
"harmony_cli",
|
||||||
|
"harmony_macros",
|
||||||
|
"harmony_types",
|
||||||
|
"log",
|
||||||
|
"tokio",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "example-opnsense"
|
name = "example-opnsense"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|||||||
@@ -2,20 +2,19 @@ use std::str::FromStr;
|
|||||||
|
|
||||||
use harmony::{
|
use harmony::{
|
||||||
inventory::Inventory,
|
inventory::Inventory,
|
||||||
modules::{k8s::apps::OperatorHubCatalogSourceScore, tenant::TenantScore},
|
modules::{k8s::apps::OperatorHubCatalogSourceScore, postgresql::CloudNativePgOperatorScore},
|
||||||
topology::{tenant::TenantConfig, K8sAnywhereTopology},
|
topology::K8sAnywhereTopology,
|
||||||
};
|
};
|
||||||
use harmony_types::id::Id;
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
|
||||||
let operatorhub_catalog = OperatorHubCatalogSourceScore::default();
|
let operatorhub_catalog = OperatorHubCatalogSourceScore::default();
|
||||||
|
let cnpg_operator = CloudNativePgOperatorScore::default();
|
||||||
|
|
||||||
harmony_cli::run(
|
harmony_cli::run(
|
||||||
Inventory::autoload(),
|
Inventory::autoload(),
|
||||||
K8sAnywhereTopology::from_env(),
|
K8sAnywhereTopology::from_env(),
|
||||||
vec![Box::new(operatorhub_catalog)],
|
vec![Box::new(operatorhub_catalog), Box::new(cnpg_operator)],
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
mod failover;
|
||||||
mod ha_cluster;
|
mod ha_cluster;
|
||||||
pub mod ingress;
|
pub mod ingress;
|
||||||
mod failover;
|
|
||||||
pub use failover::*;
|
pub use failover::*;
|
||||||
use harmony_types::net::IpAddress;
|
use harmony_types::net::IpAddress;
|
||||||
mod host_binding;
|
mod host_binding;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
mod catalogsources_operators_coreos_com;
|
mod catalogsources_operators_coreos_com;
|
||||||
pub use catalogsources_operators_coreos_com::*;
|
pub use catalogsources_operators_coreos_com::*;
|
||||||
|
mod subscriptions_operators_coreos_com;
|
||||||
|
pub use subscriptions_operators_coreos_com::*;
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
use k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta;
|
||||||
|
use kube::CustomResource;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(CustomResource, Deserialize, Serialize, Clone, Debug)]
|
||||||
|
#[kube(
|
||||||
|
group = "operators.coreos.com",
|
||||||
|
version = "v1alpha1",
|
||||||
|
kind = "Subscription",
|
||||||
|
plural = "subscriptions",
|
||||||
|
namespaced = true,
|
||||||
|
schema = "disabled"
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct SubscriptionSpec {
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub channel: Option<String>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub config: Option<SubscriptionConfig>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub install_plan_approval: Option<String>,
|
||||||
|
|
||||||
|
pub name: String,
|
||||||
|
|
||||||
|
pub source: String,
|
||||||
|
|
||||||
|
pub source_namespace: String,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub starting_csv: Option<String>,
|
||||||
|
}
|
||||||
|
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct SubscriptionConfig {
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub env: Option<Vec<k8s_openapi::api::core::v1::EnvVar>>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub node_selector: Option<std::collections::BTreeMap<String, String>>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub tolerations: Option<Vec<k8s_openapi::api::core::v1::Toleration>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Subscription {
|
||||||
|
fn default() -> Self {
|
||||||
|
Subscription {
|
||||||
|
metadata: ObjectMeta::default(),
|
||||||
|
spec: SubscriptionSpec::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SubscriptionSpec {
|
||||||
|
fn default() -> SubscriptionSpec {
|
||||||
|
SubscriptionSpec {
|
||||||
|
name: String::new(),
|
||||||
|
source: String::new(),
|
||||||
|
source_namespace: String::new(),
|
||||||
|
channel: None,
|
||||||
|
config: None,
|
||||||
|
install_plan_approval: None,
|
||||||
|
starting_csv: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
mod operatorhub;
|
mod operatorhub;
|
||||||
pub use operatorhub::*;
|
pub use operatorhub::*;
|
||||||
pub mod crd;
|
pub mod crd;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
pub mod apps;
|
||||||
pub mod deployment;
|
pub mod deployment;
|
||||||
pub mod ingress;
|
pub mod ingress;
|
||||||
pub mod namespace;
|
pub mod namespace;
|
||||||
pub mod resource;
|
pub mod resource;
|
||||||
pub mod apps;
|
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ pub mod load_balancer;
|
|||||||
pub mod monitoring;
|
pub mod monitoring;
|
||||||
pub mod okd;
|
pub mod okd;
|
||||||
pub mod opnsense;
|
pub mod opnsense;
|
||||||
|
pub mod postgresql;
|
||||||
pub mod prometheus;
|
pub mod prometheus;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
pub mod tenant;
|
pub mod tenant;
|
||||||
pub mod tftp;
|
pub mod tftp;
|
||||||
pub mod postgresql;
|
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ pub trait PostgreSQL: Send + Sync {
|
|||||||
/// Returns None if no public endpoint (internal-only cluster).
|
/// Returns None if no public endpoint (internal-only cluster).
|
||||||
/// UNSTABLE: This is opinionated for initial multisite use cases. Networking abstraction is complex
|
/// UNSTABLE: This is opinionated for initial multisite use cases. Networking abstraction is complex
|
||||||
/// (cf. k8s Ingress -> Gateway API evolution); may move to higher-order Networking/PostgreSQLNetworking trait.
|
/// (cf. k8s Ingress -> Gateway API evolution); may move to higher-order Networking/PostgreSQLNetworking trait.
|
||||||
async fn get_public_endpoint(&self, cluster_name: &str) -> Result<Option<PostgreSQLEndpoint>, String>;
|
async fn get_public_endpoint(
|
||||||
|
&self,
|
||||||
|
cluster_name: &str,
|
||||||
|
) -> Result<Option<PostgreSQLEndpoint>, String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
|
|
||||||
pub mod capability;
|
pub mod capability;
|
||||||
mod score;
|
mod score;
|
||||||
|
|
||||||
|
|
||||||
pub mod failover;
|
pub mod failover;
|
||||||
|
mod operator;
|
||||||
|
pub use operator::*;
|
||||||
|
|||||||
102
harmony/src/modules/postgresql/operator.rs
Normal file
102
harmony/src/modules/postgresql/operator.rs
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
use k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use crate::interpret::Interpret;
|
||||||
|
use crate::modules::k8s::apps::crd::{Subscription, SubscriptionSpec};
|
||||||
|
use crate::modules::k8s::resource::K8sResourceScore;
|
||||||
|
use crate::score::Score;
|
||||||
|
use crate::topology::{K8sclient, Topology};
|
||||||
|
|
||||||
|
/// Install the CloudNativePg (CNPG) Operator via an OperatorHub `Subscription`.
|
||||||
|
///
|
||||||
|
/// This Score creates a a `Subscription` Custom Resource in the specified namespace.
|
||||||
|
///
|
||||||
|
/// The default implementation pulls the `cloudnative-pg` operator from the
|
||||||
|
/// `operatorhubio-catalog` source.
|
||||||
|
///
|
||||||
|
/// # Goals
|
||||||
|
/// - Deploy the CNPG Operator to manage PostgreSQL clusters in OpenShift/OKD environments.
|
||||||
|
///
|
||||||
|
/// # Usage
|
||||||
|
/// ```
|
||||||
|
/// use harmony::modules::postgresql::CloudNativePgOperatorScore;
|
||||||
|
/// let score = CloudNativePgOperatorScore::default();
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Or, you can take control of most relevant fiedls this way :
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use harmony::modules::postgresql::CloudNativePgOperatorScore;
|
||||||
|
///
|
||||||
|
/// let score = CloudNativePgOperatorScore {
|
||||||
|
/// namespace: "custom-cnpg-namespace".to_string(),
|
||||||
|
/// channel: "unstable-i-want-bleedingedge-v498437".to_string(),
|
||||||
|
/// install_plan_approval: "Manual".to_string(),
|
||||||
|
/// source: "operatorhubio-catalog-but-different".to_string(),
|
||||||
|
/// source_namespace: "i-customize-everything-marketplace".to_string(),
|
||||||
|
/// };
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Limitations
|
||||||
|
/// - **OperatorHub dependency**: Requires OperatorHub catalog sources (e.g., `operatorhubio-catalog` in `openshift-marketplace`).
|
||||||
|
/// - **OKD/OpenShift assumption**: Catalog/source names and namespaces are hardcoded for OKD-like setups; adjust for upstream OpenShift.
|
||||||
|
/// - **Hardcoded values in Default implementation**: Operator name (`cloudnative-pg`), channel (`stable-v1`), automatic install plan approval.
|
||||||
|
/// - **No config options**: Does not support custom `SubscriptionConfig` (env vars, node selectors, tolerations).
|
||||||
|
/// - **Single namespace**: Targets one namespace per score instance.
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub struct CloudNativePgOperatorScore {
|
||||||
|
pub namespace: String,
|
||||||
|
pub channel: String,
|
||||||
|
pub install_plan_approval: String,
|
||||||
|
pub source: String,
|
||||||
|
pub source_namespace: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for CloudNativePgOperatorScore {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
namespace: "openshift-operators".to_string(),
|
||||||
|
channel: "stable-v1".to_string(),
|
||||||
|
install_plan_approval: "Automatic".to_string(),
|
||||||
|
source: "operatorhubio-catalog".to_string(),
|
||||||
|
source_namespace: "openshift-marketplace".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CloudNativePgOperatorScore {
|
||||||
|
pub fn new(namespace: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
namespace: namespace.to_string(),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Topology + K8sclient> Score<T> for CloudNativePgOperatorScore {
|
||||||
|
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||||
|
let metadata = ObjectMeta {
|
||||||
|
name: Some("cloudnative-pg".to_string()),
|
||||||
|
namespace: Some(self.namespace.clone()),
|
||||||
|
..ObjectMeta::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let spec = SubscriptionSpec {
|
||||||
|
channel: Some(self.channel.clone()),
|
||||||
|
config: None,
|
||||||
|
install_plan_approval: Some(self.install_plan_approval.clone()),
|
||||||
|
name: "cloudnative-pg".to_string(),
|
||||||
|
source: self.source.clone(),
|
||||||
|
source_namespace: self.source_namespace.clone(),
|
||||||
|
starting_csv: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let subscription = Subscription { metadata, spec };
|
||||||
|
|
||||||
|
K8sResourceScore::single(subscription, Some(self.namespace.clone())).create_interpret()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> String {
|
||||||
|
format!("CloudNativePgOperatorScore({})", self.namespace)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
pub mod id;
|
pub mod id;
|
||||||
pub mod net;
|
pub mod net;
|
||||||
pub mod switch;
|
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
|
pub mod switch;
|
||||||
|
|||||||
Reference in New Issue
Block a user