mirror of
https://github.com/geoffsee/predict-otron-9001.git
synced 2025-09-08 22:46:44 +00:00
Add Rust-based Helm Chart Generator Tool
- Scaffold `helm-chart-tool` with Cargo project files. - Implement core functionality: parse Cargo.toml, extract Kubernetes metadata, and generate Helm charts. - Include support for deployments, services, ingress, and helper templates. - Add README with detailed usage instructions. - Update `.gitignore` for generated Helm charts and related artifacts.
This commit is contained in:
80
.gitignore
vendored
80
.gitignore
vendored
@@ -1,8 +1,78 @@
|
|||||||
|
# IDE and editor files
|
||||||
.idea/
|
.idea/
|
||||||
.fastembed_cache/
|
.vscode/
|
||||||
target/
|
|
||||||
/.output.txt
|
|
||||||
.j**i?/
|
|
||||||
*.iml
|
*.iml
|
||||||
dist
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Rust build artifacts
|
||||||
|
target/
|
||||||
|
Cargo.lock
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# Node.js artifacts
|
||||||
node_modules/
|
node_modules/
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
package-lock.json
|
||||||
|
.npm
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# Web frontend build outputs
|
||||||
|
dist/
|
||||||
|
.trunk/
|
||||||
|
|
||||||
|
# ML model and embedding caches
|
||||||
|
.fastembed_cache/
|
||||||
|
.hf-cache/
|
||||||
|
.cache/
|
||||||
|
|
||||||
|
# Generated Helm charts
|
||||||
|
generated-helm-chart/
|
||||||
|
helm-chart/
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
*.log
|
||||||
|
logs/
|
||||||
|
.output.txt
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
tmp/
|
||||||
|
temp/
|
||||||
|
.tmp/
|
||||||
|
|
||||||
|
# OS generated files
|
||||||
|
Thumbs.db
|
||||||
|
.DS_Store?
|
||||||
|
ehthumbs.db
|
||||||
|
|
||||||
|
# JetBrains AI Assistant files
|
||||||
|
.j**i?/
|
||||||
|
|
||||||
|
# Test outputs and coverage
|
||||||
|
coverage/
|
||||||
|
.nyc_output/
|
||||||
|
junit.xml
|
||||||
|
|
||||||
|
# Docker artifacts
|
||||||
|
.dockerignore.bak
|
||||||
|
|
||||||
|
# Python artifacts (if any Python tooling is used)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
.Python
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
.env
|
||||||
|
.venv/
|
||||||
|
|
||||||
|
# Backup files
|
||||||
|
*.bak
|
||||||
|
*.backup
|
||||||
|
*~
|
||||||
|
18
helm-chart-tool/Cargo.toml
Normal file
18
helm-chart-tool/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "helm-chart-tool"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "helm-chart-tool"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
toml = "0.8"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
anyhow = "1.0"
|
||||||
|
clap = { version = "4.0", features = ["derive"] }
|
||||||
|
walkdir = "2.0"
|
218
helm-chart-tool/README.md
Normal file
218
helm-chart-tool/README.md
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
# Helm Chart Tool
|
||||||
|
|
||||||
|
A Rust-based tool that automatically generates Helm charts from Cargo.toml metadata in Rust workspace projects.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This tool scans a Rust workspace for crates containing Docker/Kubernetes metadata in their `Cargo.toml` files and generates a complete, production-ready Helm chart with deployments, services, ingress, and configuration templates.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Automatic Service Discovery**: Scans all `Cargo.toml` files in a workspace to find services with Kubernetes metadata
|
||||||
|
- **Complete Helm Chart Generation**: Creates Chart.yaml, values.yaml, deployment templates, service templates, ingress template, and helper templates
|
||||||
|
- **Metadata Extraction**: Uses `[package.metadata.kube]` sections from Cargo.toml files to extract:
|
||||||
|
- Docker image names
|
||||||
|
- Service ports
|
||||||
|
- Replica counts
|
||||||
|
- Service names
|
||||||
|
- **Production Ready**: Generated charts include health checks, resource limits, node selectors, affinity rules, and tolerations
|
||||||
|
- **Helm Best Practices**: Follows Helm chart conventions and passes `helm lint` validation
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Build the tool from source:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd helm-chart-tool
|
||||||
|
cargo build --release
|
||||||
|
```
|
||||||
|
|
||||||
|
The binary will be available at `target/release/helm-chart-tool`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./target/release/helm-chart-tool --workspace /path/to/rust/workspace --output ./my-helm-chart
|
||||||
|
```
|
||||||
|
|
||||||
|
### Command Line Options
|
||||||
|
|
||||||
|
- `--workspace, -w PATH`: Path to the workspace root (default: `.`)
|
||||||
|
- `--output, -o PATH`: Output directory for the Helm chart (default: `./helm-chart`)
|
||||||
|
- `--name, -n NAME`: Name of the Helm chart (default: `predict-otron-9000`)
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate chart from current workspace
|
||||||
|
./target/release/helm-chart-tool
|
||||||
|
|
||||||
|
# Generate chart from specific workspace with custom output
|
||||||
|
./target/release/helm-chart-tool -w /path/to/my/workspace -o ./charts/my-app -n my-application
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cargo.toml Metadata Format
|
||||||
|
|
||||||
|
The tool expects crates to have Kubernetes metadata in their `Cargo.toml` files:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[package]
|
||||||
|
name = "my-service"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
# Required: Kubernetes metadata
|
||||||
|
[package.metadata.kube]
|
||||||
|
image = "ghcr.io/myorg/my-service:latest"
|
||||||
|
replicas = 1
|
||||||
|
port = 8080
|
||||||
|
|
||||||
|
# Optional: Docker Compose metadata (currently not used but parsed)
|
||||||
|
[package.metadata.compose]
|
||||||
|
image = "ghcr.io/myorg/my-service:latest"
|
||||||
|
port = 8080
|
||||||
|
```
|
||||||
|
|
||||||
|
### Required Fields
|
||||||
|
|
||||||
|
- `image`: Full Docker image name including registry and tag
|
||||||
|
- `port`: Port number the service listens on
|
||||||
|
- `replicas`: Number of replicas to deploy (optional, defaults to 1)
|
||||||
|
|
||||||
|
## Generated Chart Structure
|
||||||
|
|
||||||
|
The tool generates a complete Helm chart with the following structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
helm-chart/
|
||||||
|
├── Chart.yaml # Chart metadata
|
||||||
|
├── values.yaml # Default configuration values
|
||||||
|
├── .helmignore # Files to ignore when packaging
|
||||||
|
└── templates/
|
||||||
|
├── _helpers.tpl # Template helper functions
|
||||||
|
├── ingress.yaml # Ingress configuration (optional)
|
||||||
|
├── {service}-deployment.yaml # Deployment for each service
|
||||||
|
└── {service}-service.yaml # Service for each service
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generated Files
|
||||||
|
|
||||||
|
#### Chart.yaml
|
||||||
|
- Standard Helm v2 chart metadata
|
||||||
|
- Includes keywords for AI/ML applications
|
||||||
|
- Maintainer information
|
||||||
|
|
||||||
|
#### values.yaml
|
||||||
|
- Individual service configurations
|
||||||
|
- Resource limits and requests
|
||||||
|
- Service types and ports
|
||||||
|
- Node selectors, affinity, and tolerations
|
||||||
|
- Global settings and ingress configuration
|
||||||
|
|
||||||
|
#### Deployment Templates
|
||||||
|
- Kubernetes Deployment manifests
|
||||||
|
- Health checks (liveness and readiness probes)
|
||||||
|
- Resource management
|
||||||
|
- Container port configuration from metadata
|
||||||
|
- Support for node selectors, affinity, and tolerations
|
||||||
|
|
||||||
|
#### Service Templates
|
||||||
|
- Kubernetes Service manifests
|
||||||
|
- ClusterIP services by default
|
||||||
|
- Port mapping from metadata
|
||||||
|
|
||||||
|
#### Ingress Template
|
||||||
|
- Optional ingress configuration
|
||||||
|
- Disabled by default
|
||||||
|
- Configurable through values.yaml
|
||||||
|
|
||||||
|
## Example Output
|
||||||
|
|
||||||
|
When run against the predict-otron-9000 workspace, the tool generates:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ ./target/release/helm-chart-tool --workspace .. --output ../generated-helm-chart
|
||||||
|
Parsing workspace at: ..
|
||||||
|
Output directory: ../generated-helm-chart
|
||||||
|
Chart name: predict-otron-9000
|
||||||
|
Found 4 services:
|
||||||
|
- leptos-chat: ghcr.io/geoffsee/leptos-chat:latest (port 8788)
|
||||||
|
- inference-engine: ghcr.io/geoffsee/inference-service:latest (port 8080)
|
||||||
|
- embeddings-engine: ghcr.io/geoffsee/embeddings-service:latest (port 8080)
|
||||||
|
- predict-otron-9000: ghcr.io/geoffsee/predict-otron-9000:latest (port 8080)
|
||||||
|
Helm chart generated successfully!
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
The generated charts pass Helm validation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ helm lint generated-helm-chart
|
||||||
|
==> Linting generated-helm-chart
|
||||||
|
[INFO] Chart.yaml: icon is recommended
|
||||||
|
1 chart(s) linted, 0 chart(s) failed
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
Deploy the generated chart:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install the chart
|
||||||
|
helm install my-release ./generated-helm-chart
|
||||||
|
|
||||||
|
# Upgrade the chart
|
||||||
|
helm upgrade my-release ./generated-helm-chart
|
||||||
|
|
||||||
|
# Uninstall the chart
|
||||||
|
helm uninstall my-release
|
||||||
|
```
|
||||||
|
|
||||||
|
### Customization
|
||||||
|
|
||||||
|
Customize the deployment by modifying `values.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Enable ingress
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: "nginx"
|
||||||
|
hosts:
|
||||||
|
- host: my-app.example.com
|
||||||
|
|
||||||
|
# Adjust resources for a specific service
|
||||||
|
predict_otron_9000:
|
||||||
|
replicas: 3
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: "4Gi"
|
||||||
|
cpu: "2000m"
|
||||||
|
requests:
|
||||||
|
memory: "2Gi"
|
||||||
|
cpu: "1000m"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Rust 2021+ (for building the tool)
|
||||||
|
- Helm 3.x (for deploying the generated charts)
|
||||||
|
- Kubernetes cluster (for deployment)
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
- Currently assumes all services need health checks on `/health` endpoint
|
||||||
|
- Resource limits are hardcoded defaults (can be overridden in values.yaml)
|
||||||
|
- Ingress configuration is basic (can be customized through values.yaml)
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
1. Add new features to the tool
|
||||||
|
2. Test with various Cargo.toml metadata configurations
|
||||||
|
3. Validate generated charts with `helm lint`
|
||||||
|
4. Ensure charts deploy successfully to test clusters
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This tool is part of the predict-otron-9000 project and follows the same license terms.
|
515
helm-chart-tool/src/main.rs
Normal file
515
helm-chart-tool/src/main.rs
Normal file
@@ -0,0 +1,515 @@
|
|||||||
|
use anyhow::{Context, Result};
|
||||||
|
use clap::{Arg, Command};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct CargoToml {
|
||||||
|
package: Option<Package>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct Package {
|
||||||
|
name: String,
|
||||||
|
metadata: Option<Metadata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct Metadata {
|
||||||
|
kube: Option<KubeMetadata>,
|
||||||
|
compose: Option<ComposeMetadata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct KubeMetadata {
|
||||||
|
image: String,
|
||||||
|
replicas: Option<u32>,
|
||||||
|
port: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct ComposeMetadata {
|
||||||
|
image: Option<String>,
|
||||||
|
port: Option<u16>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct ServiceInfo {
|
||||||
|
name: String,
|
||||||
|
image: String,
|
||||||
|
port: u16,
|
||||||
|
replicas: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let matches = Command::new("helm-chart-tool")
|
||||||
|
.about("Generate Helm charts from Cargo.toml metadata")
|
||||||
|
.arg(
|
||||||
|
Arg::new("workspace")
|
||||||
|
.short('w')
|
||||||
|
.long("workspace")
|
||||||
|
.value_name("PATH")
|
||||||
|
.help("Path to the workspace root")
|
||||||
|
.default_value("."),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("output")
|
||||||
|
.short('o')
|
||||||
|
.long("output")
|
||||||
|
.value_name("PATH")
|
||||||
|
.help("Output directory for the Helm chart")
|
||||||
|
.default_value("./helm-chart"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("chart-name")
|
||||||
|
.short('n')
|
||||||
|
.long("name")
|
||||||
|
.value_name("NAME")
|
||||||
|
.help("Name of the Helm chart")
|
||||||
|
.default_value("predict-otron-9000"),
|
||||||
|
)
|
||||||
|
.get_matches();
|
||||||
|
|
||||||
|
let workspace_path = matches.get_one::<String>("workspace").unwrap();
|
||||||
|
let output_path = matches.get_one::<String>("output").unwrap();
|
||||||
|
let chart_name = matches.get_one::<String>("chart-name").unwrap();
|
||||||
|
|
||||||
|
println!("Parsing workspace at: {}", workspace_path);
|
||||||
|
println!("Output directory: {}", output_path);
|
||||||
|
println!("Chart name: {}", chart_name);
|
||||||
|
|
||||||
|
let services = discover_services(workspace_path)?;
|
||||||
|
println!("Found {} services:", services.len());
|
||||||
|
for service in &services {
|
||||||
|
println!(" - {}: {} (port {})", service.name, service.image, service.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_helm_chart(output_path, chart_name, &services)?;
|
||||||
|
println!("Helm chart generated successfully!");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn discover_services(workspace_path: &str) -> Result<Vec<ServiceInfo>> {
|
||||||
|
let workspace_root = Path::new(workspace_path);
|
||||||
|
let mut services = Vec::new();
|
||||||
|
|
||||||
|
// Find all Cargo.toml files in the workspace
|
||||||
|
for entry in WalkDir::new(workspace_root)
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|e| e.ok())
|
||||||
|
{
|
||||||
|
if entry.file_name() == "Cargo.toml" && entry.path() != workspace_root.join("Cargo.toml") {
|
||||||
|
if let Ok(service_info) = parse_cargo_toml(entry.path()) {
|
||||||
|
services.push(service_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(services)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_cargo_toml(path: &Path) -> Result<ServiceInfo> {
|
||||||
|
let content = fs::read_to_string(path)
|
||||||
|
.with_context(|| format!("Failed to read Cargo.toml at {:?}", path))?;
|
||||||
|
|
||||||
|
let cargo_toml: CargoToml = toml::from_str(&content)
|
||||||
|
.with_context(|| format!("Failed to parse Cargo.toml at {:?}", path))?;
|
||||||
|
|
||||||
|
let package = cargo_toml.package
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("No package section found in {:?}", path))?;
|
||||||
|
|
||||||
|
let metadata = package.metadata
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("No metadata section found in {:?}", path))?;
|
||||||
|
|
||||||
|
let kube_metadata = metadata.kube
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("No kube metadata found in {:?}", path))?;
|
||||||
|
|
||||||
|
Ok(ServiceInfo {
|
||||||
|
name: package.name,
|
||||||
|
image: kube_metadata.image,
|
||||||
|
port: kube_metadata.port,
|
||||||
|
replicas: kube_metadata.replicas.unwrap_or(1),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_helm_chart(output_path: &str, chart_name: &str, services: &[ServiceInfo]) -> Result<()> {
|
||||||
|
let chart_dir = Path::new(output_path);
|
||||||
|
let templates_dir = chart_dir.join("templates");
|
||||||
|
|
||||||
|
// Create directories
|
||||||
|
fs::create_dir_all(&templates_dir)?;
|
||||||
|
|
||||||
|
// Generate Chart.yaml
|
||||||
|
generate_chart_yaml(chart_dir, chart_name)?;
|
||||||
|
|
||||||
|
// Generate values.yaml
|
||||||
|
generate_values_yaml(chart_dir, services)?;
|
||||||
|
|
||||||
|
// Generate templates for each service
|
||||||
|
for service in services {
|
||||||
|
generate_deployment_template(&templates_dir, service)?;
|
||||||
|
generate_service_template(&templates_dir, service)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate ingress template
|
||||||
|
generate_ingress_template(&templates_dir, services)?;
|
||||||
|
|
||||||
|
// Generate helper templates
|
||||||
|
generate_helpers_template(&templates_dir)?;
|
||||||
|
|
||||||
|
// Generate .helmignore
|
||||||
|
generate_helmignore(chart_dir)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_chart_yaml(chart_dir: &Path, chart_name: &str) -> Result<()> {
|
||||||
|
let chart_yaml = format!(
|
||||||
|
r#"apiVersion: v2
|
||||||
|
name: {}
|
||||||
|
description: A Helm chart for the predict-otron-9000 AI platform
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "0.1.0"
|
||||||
|
keywords:
|
||||||
|
- ai
|
||||||
|
- llm
|
||||||
|
- inference
|
||||||
|
- embeddings
|
||||||
|
- chat
|
||||||
|
maintainers:
|
||||||
|
- name: predict-otron-9000-team
|
||||||
|
"#,
|
||||||
|
chart_name
|
||||||
|
);
|
||||||
|
|
||||||
|
fs::write(chart_dir.join("Chart.yaml"), chart_yaml)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_values_yaml(chart_dir: &Path, services: &[ServiceInfo]) -> Result<()> {
|
||||||
|
let mut values = String::from(
|
||||||
|
r#"# Default values for predict-otron-9000
|
||||||
|
# This is a YAML-formatted file.
|
||||||
|
|
||||||
|
global:
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
serviceType: ClusterIP
|
||||||
|
|
||||||
|
# Ingress configuration
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
className: ""
|
||||||
|
annotations: {}
|
||||||
|
hosts:
|
||||||
|
- host: predict-otron-9000.local
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: predict-otron-9000
|
||||||
|
port:
|
||||||
|
number: 8080
|
||||||
|
tls: []
|
||||||
|
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
for service in services {
|
||||||
|
let service_config = format!(
|
||||||
|
r#"{}:
|
||||||
|
image:
|
||||||
|
repository: {}
|
||||||
|
tag: "latest"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
replicas: {}
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: {}
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "1000m"
|
||||||
|
requests:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "250m"
|
||||||
|
nodeSelector: {{}}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {{}}
|
||||||
|
|
||||||
|
"#,
|
||||||
|
service.name.replace("-", "_"),
|
||||||
|
service.image.split(':').next().unwrap_or(&service.image),
|
||||||
|
service.replicas,
|
||||||
|
service.port
|
||||||
|
);
|
||||||
|
values.push_str(&service_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::write(chart_dir.join("values.yaml"), values)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_deployment_template(templates_dir: &Path, service: &ServiceInfo) -> Result<()> {
|
||||||
|
let service_name_underscore = service.name.replace("-", "_");
|
||||||
|
let deployment_template = format!(
|
||||||
|
r#"apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{{{ include "predict-otron-9000.fullname" . }}}}-{}
|
||||||
|
labels:
|
||||||
|
{{{{- include "predict-otron-9000.labels" . | nindent 4 }}}}
|
||||||
|
app.kubernetes.io/component: {}
|
||||||
|
spec:
|
||||||
|
replicas: {{{{ .Values.{}.replicas }}}}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{{{- include "predict-otron-9000.selectorLabels" . | nindent 6 }}}}
|
||||||
|
app.kubernetes.io/component: {}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{{{- include "predict-otron-9000.selectorLabels" . | nindent 8 }}}}
|
||||||
|
app.kubernetes.io/component: {}
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: {}
|
||||||
|
image: "{{{{ .Values.{}.image.repository }}}}:{{{{ .Values.{}.image.tag }}}}"
|
||||||
|
imagePullPolicy: {{{{ .Values.{}.image.pullPolicy }}}}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {}
|
||||||
|
protocol: TCP
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
resources:
|
||||||
|
{{{{- toYaml .Values.{}.resources | nindent 12 }}}}
|
||||||
|
{{{{- with .Values.{}.nodeSelector }}}}
|
||||||
|
nodeSelector:
|
||||||
|
{{{{- toYaml . | nindent 8 }}}}
|
||||||
|
{{{{- end }}}}
|
||||||
|
{{{{- with .Values.{}.affinity }}}}
|
||||||
|
affinity:
|
||||||
|
{{{{- toYaml . | nindent 8 }}}}
|
||||||
|
{{{{- end }}}}
|
||||||
|
{{{{- with .Values.{}.tolerations }}}}
|
||||||
|
tolerations:
|
||||||
|
{{{{- toYaml . | nindent 8 }}}}
|
||||||
|
{{{{- end }}}}
|
||||||
|
"#,
|
||||||
|
service.name,
|
||||||
|
service.name,
|
||||||
|
service_name_underscore,
|
||||||
|
service.name,
|
||||||
|
service.name,
|
||||||
|
service.name,
|
||||||
|
service_name_underscore,
|
||||||
|
service_name_underscore,
|
||||||
|
service_name_underscore,
|
||||||
|
service.port,
|
||||||
|
service_name_underscore,
|
||||||
|
service_name_underscore,
|
||||||
|
service_name_underscore,
|
||||||
|
service_name_underscore
|
||||||
|
);
|
||||||
|
|
||||||
|
let filename = format!("{}-deployment.yaml", service.name);
|
||||||
|
fs::write(templates_dir.join(filename), deployment_template)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_service_template(templates_dir: &Path, service: &ServiceInfo) -> Result<()> {
|
||||||
|
let service_template = format!(
|
||||||
|
r#"apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{{{ include "predict-otron-9000.fullname" . }}}}-{}
|
||||||
|
labels:
|
||||||
|
{{{{- include "predict-otron-9000.labels" . | nindent 4 }}}}
|
||||||
|
app.kubernetes.io/component: {}
|
||||||
|
spec:
|
||||||
|
type: {{{{ .Values.{}.service.type }}}}
|
||||||
|
ports:
|
||||||
|
- port: {{{{ .Values.{}.service.port }}}}
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
{{{{- include "predict-otron-9000.selectorLabels" . | nindent 4 }}}}
|
||||||
|
app.kubernetes.io/component: {}
|
||||||
|
"#,
|
||||||
|
service.name,
|
||||||
|
service.name,
|
||||||
|
service.name.replace("-", "_"),
|
||||||
|
service.name.replace("-", "_"),
|
||||||
|
service.name
|
||||||
|
);
|
||||||
|
|
||||||
|
let filename = format!("{}-service.yaml", service.name);
|
||||||
|
fs::write(templates_dir.join(filename), service_template)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_ingress_template(templates_dir: &Path, services: &[ServiceInfo]) -> Result<()> {
|
||||||
|
let ingress_template = r#"{{- if .Values.ingress.enabled -}}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ include "predict-otron-9000.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "predict-otron-9000.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.ingress.className }}
|
||||||
|
ingressClassName: {{ .Values.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.ingress.hosts }}
|
||||||
|
- host: {{ .host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
{{- range .paths }}
|
||||||
|
- path: {{ .path }}
|
||||||
|
{{- if .pathType }}
|
||||||
|
pathType: {{ .pathType }}
|
||||||
|
{{- end }}
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "predict-otron-9000.fullname" $ }}-{{ .backend.service.name }}
|
||||||
|
port:
|
||||||
|
number: {{ .backend.service.port.number }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
fs::write(templates_dir.join("ingress.yaml"), ingress_template)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_helpers_template(templates_dir: &Path) -> Result<()> {
|
||||||
|
let helpers_template = r#"{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "predict-otron-9000.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
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).
|
||||||
|
If release name contains chart name it will be used as a full name.
|
||||||
|
*/}}
|
||||||
|
{{- define "predict-otron-9000.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride }}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||||
|
{{- if contains $name .Release.Name }}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create chart name and version as used by the chart label.
|
||||||
|
*/}}
|
||||||
|
{{- define "predict-otron-9000.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Common labels
|
||||||
|
*/}}
|
||||||
|
{{- define "predict-otron-9000.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "predict-otron-9000.chart" . }}
|
||||||
|
{{ include "predict-otron-9000.selectorLabels" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Selector labels
|
||||||
|
*/}}
|
||||||
|
{{- define "predict-otron-9000.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "predict-otron-9000.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create the name of the service account to use
|
||||||
|
*/}}
|
||||||
|
{{- define "predict-otron-9000.serviceAccountName" -}}
|
||||||
|
{{- if .Values.serviceAccount.create }}
|
||||||
|
{{- default (include "predict-otron-9000.fullname" .) .Values.serviceAccount.name }}
|
||||||
|
{{- else }}
|
||||||
|
{{- default "default" .Values.serviceAccount.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
fs::write(templates_dir.join("_helpers.tpl"), helpers_template)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_helmignore(chart_dir: &Path) -> Result<()> {
|
||||||
|
let helmignore_content = r#"# Patterns to ignore when building packages.
|
||||||
|
# This supports shell glob matching, relative path matching, and
|
||||||
|
# negation (prefixed with !). Only one pattern per line.
|
||||||
|
.DS_Store
|
||||||
|
# Common VCS dirs
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
.bzr/
|
||||||
|
.bzrignore
|
||||||
|
.hg/
|
||||||
|
.hgignore
|
||||||
|
.svn/
|
||||||
|
# Common backup files
|
||||||
|
*.swp
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
*.orig
|
||||||
|
*~
|
||||||
|
# Various IDEs
|
||||||
|
.project
|
||||||
|
.idea/
|
||||||
|
*.tmproj
|
||||||
|
.vscode/
|
||||||
|
"#;
|
||||||
|
|
||||||
|
fs::write(chart_dir.join(".helmignore"), helmignore_content)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
Reference in New Issue
Block a user