fix: unjank the demo #85
4
.gitignore
vendored
4
.gitignore
vendored
@ -2,3 +2,7 @@ target
|
||||
private_repos
|
||||
log/
|
||||
*.tgz
|
||||
examples/rust/examples/rust/webapp/helm/
|
||||
|
|
||||
examples/rust/examples/rust/webapp/Dockerfile.harmony
|
||||
examples/rust/webapp/helm/harmony-example-rust-webapp-chart/
|
||||
.gitignore
|
||||
|
||||
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1726,6 +1726,7 @@ name = "harmony"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bollard",
|
||||
"chrono",
|
||||
"cidr",
|
||||
"convert_case",
|
||||
|
||||
@ -53,3 +53,4 @@ chrono = "0.4"
|
||||
similar = "2"
|
||||
uuid = { version = "1.11", features = ["v4", "fast-rng", "macro-diagnostics"] }
|
||||
pretty_assertions = "1.4.1"
|
||||
bollard = "0.19.1"
|
||||
|
||||
@ -1,18 +1,41 @@
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
use harmony::{
|
||||
data::Id,
|
||||
inventory::Inventory,
|
||||
maestro::Maestro,
|
||||
modules::application::{
|
||||
ApplicationScore, RustWebFramework, RustWebapp,
|
||||
features::{ContinuousDelivery, Monitoring},
|
||||
modules::{
|
||||
application::{
|
||||
ApplicationScore, RustWebFramework, RustWebapp,
|
||||
features::{ContinuousDelivery, Monitoring},
|
||||
},
|
||||
tenant::TenantScore,
|
||||
},
|
||||
topology::{
|
||||
K8sAnywhereTopology, Url,
|
||||
tenant::{ResourceLimits, TenantConfig, TenantNetworkPolicy},
|
||||
},
|
||||
topology::{K8sAnywhereTopology, Url},
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let tenant = TenantScore {
|
||||
config: TenantConfig {
|
||||
id: Id::from_string("1234".to_string()),
|
||||
name: "harmonydemo-staging".to_string(),
|
||||
resource_limits: ResourceLimits {
|
||||
cpu_request_cores: 6.0,
|
||||
cpu_limit_cores: 4.0,
|
||||
memory_request_gb: 4.0,
|
||||
|
johnride
commented
The Tenant should not be visible at the applcation scope. An application will auto detect the tenant it is supposed to be in from the environment (such as the content of the loaded kubeconfig). For example, a client cannot provision its own tenant as it may not have permission on the host cluster to do so. There may be exceptions and more complex use cases coming up soon, but for the sake of this example we want to keep it 100% focused on the application and especially how simple it it to deploy a fully featured infrastructure around an application with as close to zero config as possible. The Tenant should not be visible at the applcation scope. An application will auto detect the tenant it is supposed to be in from the environment (such as the content of the loaded kubeconfig).
For example, a client cannot provision its own tenant as it may not have permission on the host cluster to do so.
There may be exceptions and more complex use cases coming up soon, but for the sake of this example we want to keep it 100% focused on the application and especially how **simple** it it to deploy a fully featured infrastructure around an application with as close to zero config as possible.
|
||||
memory_limit_gb: 4.0,
|
||||
storage_total_gb: 10.0,
|
||||
},
|
||||
network_policy: TenantNetworkPolicy::default(),
|
||||
},
|
||||
};
|
||||
|
||||
let application = Arc::new(RustWebapp {
|
||||
name: "harmony-example-rust-webapp".to_string(),
|
||||
domain: Url::Url(url::Url::parse("https://rustapp.harmony.example.com").unwrap()),
|
||||
@ -35,6 +58,6 @@ async fn main() {
|
||||
let mut maestro = Maestro::initialize(Inventory::autoload(), topology)
|
||||
.await
|
||||
.unwrap();
|
||||
maestro.register_all(vec![Box::new(app)]);
|
||||
maestro.register_all(vec![Box::new(tenant), Box::new(app)]);
|
||||
harmony_cli::init(maestro, None).await.unwrap();
|
||||
}
|
||||
|
||||
@ -59,6 +59,7 @@ tokio-util = "0.7.15"
|
||||
strum = { version = "0.27.1", features = ["derive"] }
|
||||
tempfile = "3.20.0"
|
||||
serde_with = "3.14.0"
|
||||
bollard.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions.workspace = true
|
||||
|
||||
@ -1,6 +1,3 @@
|
||||
use std::{backtrace, collections::HashMap};
|
||||
|
||||
use k8s_openapi::{Metadata, NamespaceResourceScope, Resource};
|
||||
use log::debug;
|
||||
use serde::Serialize;
|
||||
use serde_with::skip_serializing_none;
|
||||
@ -34,10 +31,11 @@ pub struct Helm {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Source {
|
||||
#[serde(rename = "repoURL")]
|
||||
pub repo_url: Url,
|
||||
pub repo_url: String,
|
||||
pub target_revision: Option<String>,
|
||||
pub chart: String,
|
||||
pub helm: Helm,
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
@ -90,7 +88,7 @@ impl Default for ArgoApplication {
|
||||
namespace: Default::default(),
|
||||
project: Default::default(),
|
||||
source: Source {
|
||||
|
wjro
commented
I would write some documentation for why you replaced url with string I would write some documentation for why you replaced url with string
|
||||
repo_url: Url::parse("http://asdf").expect("Couldn't parse to URL"),
|
||||
repo_url: "http://asdf".to_string(),
|
||||
target_revision: None,
|
||||
chart: "".to_string(),
|
||||
helm: Helm {
|
||||
@ -109,6 +107,7 @@ impl Default for ArgoApplication {
|
||||
api_versions: vec![],
|
||||
namespace: None,
|
||||
},
|
||||
path: "".to_string(),
|
||||
},
|
||||
sync_policy: SyncPolicy {
|
||||
automated: Automated {
|
||||
@ -138,10 +137,10 @@ impl From<CDApplicationConfig> for ArgoApplication {
|
||||
namespace: Some(value.namespace),
|
||||
project: "default".to_string(),
|
||||
source: Source {
|
||||
repo_url: Url::parse(value.helm_chart_repo_url.to_string().as_str())
|
||||
.expect("couldn't convert to URL"),
|
||||
repo_url: value.helm_chart_repo_url,
|
||||
target_revision: Some(value.version.to_string()),
|
||||
chart: value.helm_chart_name,
|
||||
chart: value.helm_chart_name.clone(),
|
||||
path: value.helm_chart_name,
|
||||
helm: Helm {
|
||||
pass_credentials: None,
|
||||
parameters: vec![],
|
||||
@ -218,7 +217,7 @@ spec:
|
||||
let mut yaml_value: Value =
|
||||
serde_yaml::from_str(yaml_str.as_str()).expect("couldn't parse string to YAML");
|
||||
|
||||
let mut spec = yaml_value
|
||||
let spec = yaml_value
|
||||
.get_mut("spec")
|
||||
.expect("couldn't get spec from yaml")
|
||||
.as_mapping_mut()
|
||||
@ -271,7 +270,7 @@ mod tests {
|
||||
namespace: Some("test-ns".to_string()),
|
||||
project: "test-project".to_string(),
|
||||
source: Source {
|
||||
repo_url: Url::parse("http://test").unwrap(),
|
||||
repo_url: "http://test".to_string(),
|
||||
target_revision: None,
|
||||
chart: "test-chart".to_string(),
|
||||
helm: Helm {
|
||||
@ -290,6 +289,7 @@ mod tests {
|
||||
api_versions: vec![],
|
||||
namespace: None,
|
||||
},
|
||||
path: "".to_string(),
|
||||
},
|
||||
sync_policy: SyncPolicy {
|
||||
automated: Automated {
|
||||
|
||||
@ -9,12 +9,9 @@ use crate::{
|
||||
config::HARMONY_DATA_DIR,
|
||||
data::Version,
|
||||
inventory::Inventory,
|
||||
modules::{
|
||||
application::{
|
||||
Application, ApplicationFeature, HelmPackage, OCICompliant,
|
||||
features::{ArgoApplication, ArgoHelmScore},
|
||||
},
|
||||
helm::chart::HelmChartScore,
|
||||
modules::application::{
|
||||
Application, ApplicationFeature, HelmPackage, OCICompliant,
|
||||
features::{ArgoApplication, ArgoHelmScore},
|
||||
},
|
||||
score::Score,
|
||||
topology::{DeploymentTarget, HelmCommand, K8sclient, MultiTargetTopology, Topology, Url},
|
||||
@ -162,7 +159,7 @@ impl<
|
||||
info!("Pushed new helm chart {helm_chart}");
|
||||
|
||||
error!("TODO Make building image configurable/skippable");
|
||||
let image = self.application.build_push_oci_image().await?;
|
||||
// let image = self.application.build_push_oci_image().await?;
|
||||
info!("Pushed new docker image {image}");
|
||||
|
||||
info!("Installing ContinuousDelivery feature");
|
||||
@ -188,12 +185,12 @@ impl<
|
||||
info!("Deploying to target {target:?}");
|
||||
let score = ArgoHelmScore {
|
||||
namespace: "harmonydemo-staging".to_string(),
|
||||
openshift: true,
|
||||
openshift: false,
|
||||
domain: "argo.harmonydemo.apps.st.mcd".to_string(),
|
||||
argo_apps: vec![ArgoApplication::from(CDApplicationConfig {
|
||||
// helm pull oci://hub.nationtech.io/harmony/harmony-example-rust-webapp-chart/harmony-example-rust-webapp-chart --version 0.1.0
|
||||
// helm pull oci://hub.nationtech.io/harmony/harmony-example-rust-webapp-chart --version 0.1.0
|
||||
version: Version::from("0.1.0").unwrap(),
|
||||
helm_chart_repo_url: Url::Url(url::Url::parse("oci://hub.nationtech.io/harmony/harmony-example-rust-webapp-chart/harmony-example-rust-webapp-chart").unwrap()),
|
||||
helm_chart_repo_url: "hub.nationtech.io/harmony".to_string(),
|
||||
helm_chart_name: "harmony-example-rust-webapp-chart".to_string(),
|
||||
values_overrides: None,
|
||||
name: "harmony-demo-rust-webapp".to_string(),
|
||||
@ -225,7 +222,7 @@ impl<
|
||||
/// more CD systems
|
||||
pub struct CDApplicationConfig {
|
||||
pub version: Version,
|
||||
pub helm_chart_repo_url: Url,
|
||||
pub helm_chart_repo_url: String,
|
||||
pub helm_chart_name: String,
|
||||
pub values_overrides: Option<Value>,
|
||||
pub name: String,
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
use async_trait::async_trait;
|
||||
use k8s_openapi::Resource;
|
||||
use log::error;
|
||||
use non_blank_string_rs::NonBlankString;
|
||||
use serde::Serialize;
|
||||
@ -647,7 +646,7 @@ server:
|
||||
# Argo CD server ingress configuration
|
||||
ingress:
|
||||
# -- Enable an ingress resource for the Argo CD server
|
||||
enabled: false
|
||||
enabled: true
|
||||
# -- Specific implementation for ingress controller. One of `generic`, `aws` or `gke`
|
||||
## Additional configuration might be required in related configuration sections
|
||||
controller: generic
|
||||
|
||||
@ -4,13 +4,10 @@ use log::info;
|
||||
use crate::{
|
||||
inventory::Inventory,
|
||||
modules::{
|
||||
application::{Application, ApplicationFeature},
|
||||
application::ApplicationFeature,
|
||||
monitoring::{
|
||||
application_monitoring::k8s_application_monitoring_score::ApplicationPrometheusMonitoringScore,
|
||||
kube_prometheus::{
|
||||
helm_prometheus_alert_score::HelmPrometheusAlertingScore,
|
||||
types::{NamespaceSelector, ServiceMonitor},
|
||||
},
|
||||
kube_prometheus::types::{NamespaceSelector, ServiceMonitor},
|
||||
},
|
||||
},
|
||||
score::Score,
|
||||
|
||||
@ -416,7 +416,7 @@ ingress:
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "chart.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- default .Chart.Name $.Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
@ -424,7 +424,7 @@ Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
*/}}
|
||||
{{- define "chart.fullname" -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- $name := default .Chart.Name $.Values.nameOverride }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
"#;
|
||||
@ -437,12 +437,12 @@ kind: Service
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
type: {{ $.Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: 3000
|
||||
- name: main
|
||||
port: {{ $.Values.service.port | default 3000 }}
|
||||
targetPort: {{ $.Values.service.port | default 3000 }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: {{ include "chart.name" . }}
|
||||
"#;
|
||||
@ -455,7 +455,7 @@ kind: Deployment
|
||||
metadata:
|
||||
|
johnride
commented
Thanks for fixing my demo hardcoding crap 😅 Thanks for fixing my demo hardcoding crap 😅
|
||||
name: {{ include "chart.fullname" . }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
replicas: {{ $.Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ include "chart.name" . }}
|
||||
@ -466,28 +466,28 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
image: "{{ $.Values.image.repository }}:{{ $.Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ $.Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 3000
|
||||
- name: main
|
||||
containerPort: {{ $.Values.service.port | default 3000 }}
|
||||
protocol: TCP
|
||||
"#;
|
||||
fs::write(templates_dir.join("deployment.yaml"), deployment_yaml)?;
|
||||
|
||||
// Create templates/ingress.yaml
|
||||
let ingress_yaml = r#"
|
||||
{{- if .Values.ingress.enabled -}}
|
||||
{{- if $.Values.ingress.enabled -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}
|
||||
annotations:
|
||||
{{- toYaml .Values.ingress.annotations | nindent 4 }}
|
||||
{{- toYaml $.Values.ingress.annotations | nindent 4 }}
|
||||
spec:
|
||||
{{- if .Values.ingress.tls }}
|
||||
{{- if $.Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
{{- range $.Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
@ -496,7 +496,7 @@ spec:
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
{{- range $.Values.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
@ -507,7 +507,7 @@ spec:
|
||||
service:
|
||||
name: {{ include "chart.fullname" $ }}
|
||||
port:
|
||||
number: 3000
|
||||
number: {{ $.Values.service.port | default 3000 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user
These would be better in the examples's own gitignore file
examples/rust/.gitignore. Eventually we may have hundreds of examples, we don't want thousands of lines in this file.But thinking a bit further, this points towards a problem on the way we manage these generated files. They should probably end up in a harmony specific directory that we can then ignore in a single line for all examples. Maybe
harmony_generatedorharmony_build?