Relative paths for included charts and oci support

This commit is contained in:
Nikolai Rodionov 2024-01-12 18:40:05 +01:00
parent 77f1d0dcb9
commit ebc93dc6d0
Signed by: allanger
GPG Key ID: 0AA46A90E25592AD
6 changed files with 188 additions and 27 deletions

View File

@ -4,14 +4,14 @@ version: latest
extensions: extensions:
- name: Add virtual service to the chartc - name: Add virtual service to the chartc
target_dir: templates/extensions target_dir: templates/extensions
source_dir: ./examples/extensions/vaultwarden source_dir: ../../extensions/vaultwarden
patches: patches:
- name: Git patch 1 - name: Git patch 1
git: git:
path: ./examples/patches/git/patch.diff path: ../../patches/git/patch.diff
- name: Git patch 2 - name: Git patch 2
git: git:
path: ./examples/patches/git/patch-2.diff path: ../../patches/git/patch-2.diff
- name: yaml-fmt - name: yaml-fmt
custom_command: custom_command:
commands: commands:

View File

@ -3,6 +3,9 @@ include:
- kind: Charts - kind: Charts
path: ./examples/use/charts/vaultwardens.yaml path: ./examples/use/charts/vaultwardens.yaml
repositories: repositories:
- name: bitnami-oci
helm:
url: oci://registry-1.docker.io/bitnamicharts/
- name: metrics-server - name: metrics-server
helm: helm:
url: https://kubernetes-sigs.github.io/metrics-server/ url: https://kubernetes-sigs.github.io/metrics-server/
@ -18,6 +21,11 @@ repositories:
helm: helm:
url: https://fluxcd-community.github.io/helm-charts url: https://fluxcd-community.github.io/helm-charts
charts: charts:
- name: postgresql
repository: bitnami-oci
version: 13.2.29
mirrors:
- badhouseplants-git
- name: flux2 - name: flux2
repository: flux-community repository: flux-community
extensions: extensions:

View File

@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
pub(crate) struct Extension { pub(crate) struct Extension {
name: Option<String>, name: Option<String>,
target_dir: String, target_dir: String,
source_dir: String, pub(crate) source_dir: String,
} }
impl Extension { impl Extension {

View File

@ -1,5 +1,5 @@
use log::info; use log::info;
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)] #[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
pub(crate) enum IncludeTypes { pub(crate) enum IncludeTypes {
@ -23,33 +23,33 @@ pub(crate) fn apply_includes(config: &mut super::Config) -> Result<(), Box<dyn s
Some(mut existing_charts) => { Some(mut existing_charts) => {
existing_charts.append(&mut charts); existing_charts.append(&mut charts);
existing_charts existing_charts
}, }
None => charts, None => charts,
}; };
config.charts = Some(extended_charts); config.charts = Some(extended_charts);
}, }
IncludeTypes::Mirrors => { IncludeTypes::Mirrors => {
let mut mirrors = include_mirrors(include.path)?; let mut mirrors = include_mirrors(include.path)?;
let extended_mirrors = match config.mirrors.clone() { let extended_mirrors = match config.mirrors.clone() {
Some(mut existing_mirrors) => { Some(mut existing_mirrors) => {
existing_mirrors.append(&mut mirrors); existing_mirrors.append(&mut mirrors);
existing_mirrors existing_mirrors
}, }
None => mirrors, None => mirrors,
}; };
config.mirrors = Some(extended_mirrors); config.mirrors = Some(extended_mirrors);
}, }
IncludeTypes::Repositories => { IncludeTypes::Repositories => {
let mut repositories = include_repositories(include.path)?; let mut repositories = include_repositories(include.path)?;
let extended_repositories = match config.repositories.clone() { let extended_repositories = match config.repositories.clone() {
Some(mut existing_repositories) => { Some(mut existing_repositories) => {
existing_repositories.append(&mut repositories); existing_repositories.append(&mut repositories);
existing_repositories existing_repositories
}, }
None => repositories, None => repositories,
}; };
config.repositories = Some(extended_repositories); config.repositories = Some(extended_repositories);
}, }
}; };
} }
Ok(()) Ok(())
@ -58,17 +58,74 @@ pub(crate) fn apply_includes(config: &mut super::Config) -> Result<(), Box<dyn s
fn include_chart(path: String) -> Result<Vec<super::Chart>, Box<dyn std::error::Error>> { fn include_chart(path: String) -> Result<Vec<super::Chart>, Box<dyn std::error::Error>> {
info!("trying to include chart from {}", path.clone()); info!("trying to include chart from {}", path.clone());
let file = std::fs::File::open(path.clone())?; let file = std::fs::File::open(path.clone())?;
let charts: Vec<super::Chart> = match serde_yaml::from_reader(file) {
let chart_dir = match std::path::Path::new(&path).parent() {
Some(dir) => match dir.to_str() {
Some(dir) => dir.to_string(),
None => {
return Err(Box::from(format!(
"chart parrent dir not found for {}",
path
)));
}
},
None => {
return Err(Box::from(format!(
"chart parrent dir not found for {}",
path
)));
}
};
let mut charts: Vec<super::Chart> = match serde_yaml::from_reader(file) {
Ok(res) => res, Ok(res) => res,
Err(_) => { Err(_) => {
let file = std::fs::File::open(path.clone())?; let file = std::fs::File::open(path.clone())?;
let chart: super::Chart = serde_yaml::from_reader(file)?; let chart: super::Chart = serde_yaml::from_reader(file)?;
vec!(chart) vec![chart]
}, }
}; };
charts.iter_mut().for_each(|chart| {
match chart.extensions {
Some(ref mut extensions) => extensions.iter_mut().for_each(|extension| {
if is_path_relative(extension.source_dir.clone()) {
let clean_path = match extension.source_dir.clone().starts_with("./") {
true => extension.source_dir.clone().replacen("./", "", 1),
false => extension.source_dir.clone(),
};
if is_path_relative(clean_path.clone()) {
let new_path = format!("{}/{}", chart_dir, clean_path);
extension.source_dir = new_path;
}
}
}),
None => info!("no extensions set, nothing to update"),
};
match chart.patches {
Some(ref mut patches) => patches.iter_mut().for_each(| patch| {
if is_path_relative(patch.get_path().clone()) {
let clean_path = match patch.get_path().clone().starts_with("./") {
true => patch.get_path().clone().replacen("./", "", 1),
false => patch.get_path().clone(),
};
if is_path_relative(clean_path.clone()) {
let new_path = format!("{}/{}", chart_dir, clean_path);
patch.set_path(new_path);
}
}
}),
None => info!("no patch set, nothing to update"),
};
});
Ok(charts) Ok(charts)
} }
fn is_path_relative(path: String) -> bool {
!path.starts_with("/")
}
fn include_mirrors(path: String) -> Result<Vec<super::Mirror>, Box<dyn std::error::Error>> { fn include_mirrors(path: String) -> Result<Vec<super::Mirror>, Box<dyn std::error::Error>> {
info!("trying to include chart from {}", path.clone()); info!("trying to include chart from {}", path.clone());
let file = std::fs::File::open(path.clone())?; let file = std::fs::File::open(path.clone())?;
@ -77,13 +134,15 @@ fn include_mirrors(path: String) -> Result<Vec<super::Mirror>, Box<dyn std::erro
Err(_) => { Err(_) => {
let file = std::fs::File::open(path.clone())?; let file = std::fs::File::open(path.clone())?;
let chart: super::Mirror = serde_yaml::from_reader(file)?; let chart: super::Mirror = serde_yaml::from_reader(file)?;
vec!(chart) vec![chart]
}, }
}; };
Ok(mirrors) Ok(mirrors)
} }
fn include_repositories(path: String) -> Result<Vec<super::Repository>, Box<dyn std::error::Error>> { fn include_repositories(
path: String,
) -> Result<Vec<super::Repository>, Box<dyn std::error::Error>> {
info!("trying to include chart from {}", path.clone()); info!("trying to include chart from {}", path.clone());
let file = std::fs::File::open(path.clone())?; let file = std::fs::File::open(path.clone())?;
let repositories: Vec<super::Repository> = match serde_yaml::from_reader(file) { let repositories: Vec<super::Repository> = match serde_yaml::from_reader(file) {
@ -91,9 +150,8 @@ fn include_repositories(path: String) -> Result<Vec<super::Repository>, Box<dyn
Err(_) => { Err(_) => {
let file = std::fs::File::open(path.clone())?; let file = std::fs::File::open(path.clone())?;
let chart: super::Repository = serde_yaml::from_reader(file)?; let chart: super::Repository = serde_yaml::from_reader(file)?;
vec!(chart) vec![chart]
}, }
}; };
Ok(repositories) Ok(repositories)
} }

View File

@ -52,10 +52,25 @@ impl Patch {
let patch_action = patch_action_from_definition(self.clone())?; let patch_action = patch_action_from_definition(self.clone())?;
patch_action.apply(chart_local_path) patch_action.apply(chart_local_path)
} }
pub(crate) fn get_path(&self) -> String {
let patch_action = patch_action_from_definition(self.clone()).unwrap();
patch_action.get_path()
}
pub(crate) fn set_path(&mut self, path: String) {
if let Some(ref mut regexp) = self.regexp {
regexp.path = path;
} else if let Some(ref mut git) = self.git {
git.path = path;
} else if let Some(ref mut yq) = self.yq {
yq.file = path
}
}
} }
trait PatchInterface { trait PatchInterface {
fn apply(&self, chart_local_path: String) -> Result<(), Box<dyn std::error::Error>>; fn apply(&self, chart_local_path: String) -> Result<(), Box<dyn std::error::Error>>;
fn get_path(&self) -> String;
fn set_path(&mut self, new_path: String);
} }
impl PatchInterface for YqPatch { impl PatchInterface for YqPatch {
@ -86,6 +101,14 @@ impl PatchInterface for YqPatch {
cli_exec_from_dir(cmd, chart_local_path)?; cli_exec_from_dir(cmd, chart_local_path)?;
Ok(()) Ok(())
} }
fn get_path(&self) -> String {
self.file.clone()
}
fn set_path(&mut self, new_path: String) {
self.file = new_path
}
} }
impl PatchInterface for RegexpPatch { impl PatchInterface for RegexpPatch {
@ -145,6 +168,14 @@ impl PatchInterface for RegexpPatch {
} }
Ok(()) Ok(())
} }
fn get_path(&self) -> String {
self.path.clone()
}
fn set_path(&mut self, new_path: String) {
self.path = new_path
}
} }
impl PatchInterface for GitPatch { impl PatchInterface for GitPatch {
@ -157,6 +188,14 @@ impl PatchInterface for GitPatch {
remove_dir_all(chart_local_path + "/.git")?; remove_dir_all(chart_local_path + "/.git")?;
Ok(()) Ok(())
} }
fn get_path(&self) -> String {
self.path.clone()
}
fn set_path(&mut self, new_path: String) {
self.path = new_path
}
} }
impl PatchInterface for CustomCommandPatch { impl PatchInterface for CustomCommandPatch {
@ -166,6 +205,15 @@ impl PatchInterface for CustomCommandPatch {
} }
Ok(()) Ok(())
} }
fn get_path(&self) -> String {
// Empty stings, cause cc patch doesn't have a path
"".to_string()
}
fn set_path(&mut self, _new_path: String) {
()
}
} }
fn patch_action_from_definition( fn patch_action_from_definition(
@ -176,9 +224,11 @@ fn patch_action_from_definition(
} else if let Some(git) = patch.git { } else if let Some(git) = patch.git {
return Ok(Box::new(GitPatch { return Ok(Box::new(GitPatch {
path: { path: {
let path = PathBuf::from(git.path); let path = PathBuf::from(git.path.clone());
let can_path = fs::canonicalize(path).ok().unwrap(); match fs::canonicalize(path).ok(){
can_path.into_os_string().into_string().ok().unwrap() Some(can_path) => can_path.into_os_string().into_string().ok().unwrap(),
None => git.path.clone(),
}
}, },
})); }));
} else if let Some(custom_command) = patch.custom_command { } else if let Some(custom_command) = patch.custom_command {

View File

@ -46,6 +46,53 @@ impl Helm {
} }
} }
fn pull_oci(
&self,
workdir_path: String,
vars: HashMap<String, String>,
) -> Result<ChartLocal, Box<dyn std::error::Error>> {
let args = match self.version.as_str() {
LATEST_VERSION => "".to_string(),
_ => format!("--version {}", self.version.clone()),
};
let repo = match self.repository_url.ends_with("/"){
true => {
let mut repo = self.repository_url.clone();
repo.pop();
repo
},
false => self.repository_url.clone(),
};
let cmd = format!(
"helm pull {}/{} {} --destination {} --untar",
repo, &self.chart, args, workdir_path
);
cli_exec(cmd)?;
// Get the version
let cmd = format!("helm show chart {}/{}", workdir_path, &self.chart);
let helm_stdout = cli_exec(cmd)?;
let old_dir_name = format!("{}/{}", workdir_path, &self.chart);
let new_dir_name: String;
match serde_yaml::from_str::<super::Version>(&helm_stdout) {
Ok(res) => {
new_dir_name = format!("{}-{}", old_dir_name, res.version);
rename(old_dir_name, new_dir_name.clone())?;
}
Err(err) => return Err(Box::from(err)),
};
let cmd = "helm show chart . | yq '.version'".to_string();
let version = cli_exec_from_dir(cmd, new_dir_name.clone())?;
Ok(ChartLocal {
name: self.chart.clone(),
version,
path: new_dir_name,
repo_url: self.repository_url.clone(),
vars,
})
}
fn pull_default( fn pull_default(
&self, &self,
workdir_path: String, workdir_path: String,
@ -105,9 +152,7 @@ impl Repo for Helm {
let repository_kind = self.repo_kind_from_url()?; let repository_kind = self.repo_kind_from_url()?;
let path = match repository_kind { let path = match repository_kind {
RepoKind::Default => self.pull_default(workdir_path, vars)?, RepoKind::Default => self.pull_default(workdir_path, vars)?,
RepoKind::Oci => { RepoKind::Oci => self.pull_oci(workdir_path, vars)?,
todo!()
}
}; };
Ok(path) Ok(path)
} }