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:
- name: Add virtual service to the chartc
target_dir: templates/extensions
source_dir: ./examples/extensions/vaultwarden
source_dir: ../../extensions/vaultwarden
patches:
- name: Git patch 1
git:
path: ./examples/patches/git/patch.diff
path: ../../patches/git/patch.diff
- name: Git patch 2
git:
path: ./examples/patches/git/patch-2.diff
path: ../../patches/git/patch-2.diff
- name: yaml-fmt
custom_command:
commands:

View File

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

View File

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

View File

@ -1,5 +1,5 @@
use log::info;
use serde::{Serialize, Deserialize};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
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) => {
existing_charts.append(&mut charts);
existing_charts
},
}
None => charts,
};
config.charts = Some(extended_charts);
},
}
IncludeTypes::Mirrors => {
let mut mirrors = include_mirrors(include.path)?;
let extended_mirrors = match config.mirrors.clone() {
Some(mut existing_mirrors) => {
existing_mirrors.append(&mut mirrors);
existing_mirrors
},
}
None => mirrors,
};
config.mirrors = Some(extended_mirrors);
},
}
IncludeTypes::Repositories => {
let mut repositories = include_repositories(include.path)?;
let extended_repositories = match config.repositories.clone() {
Some(mut existing_repositories) => {
existing_repositories.append(&mut repositories);
existing_repositories
},
}
None => repositories,
};
config.repositories = Some(extended_repositories);
},
}
};
}
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>> {
info!("trying to include chart from {}", 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,
Err(_) => {
let file = std::fs::File::open(path.clone())?;
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)
}
fn is_path_relative(path: String) -> bool {
!path.starts_with("/")
}
fn include_mirrors(path: String) -> Result<Vec<super::Mirror>, Box<dyn std::error::Error>> {
info!("trying to include chart from {}", 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(_) => {
let file = std::fs::File::open(path.clone())?;
let chart: super::Mirror = serde_yaml::from_reader(file)?;
vec!(chart)
},
vec![chart]
}
};
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());
let file = std::fs::File::open(path.clone())?;
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(_) => {
let file = std::fs::File::open(path.clone())?;
let chart: super::Repository = serde_yaml::from_reader(file)?;
vec!(chart)
},
vec![chart]
}
};
Ok(repositories)
}

View File

@ -52,10 +52,25 @@ impl Patch {
let patch_action = patch_action_from_definition(self.clone())?;
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 {
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 {
@ -86,6 +101,14 @@ impl PatchInterface for YqPatch {
cli_exec_from_dir(cmd, chart_local_path)?;
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 {
@ -145,6 +168,14 @@ impl PatchInterface for RegexpPatch {
}
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 {
@ -157,6 +188,14 @@ impl PatchInterface for GitPatch {
remove_dir_all(chart_local_path + "/.git")?;
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 {
@ -166,6 +205,15 @@ impl PatchInterface for CustomCommandPatch {
}
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(
@ -176,9 +224,11 @@ fn patch_action_from_definition(
} else if let Some(git) = patch.git {
return Ok(Box::new(GitPatch {
path: {
let path = PathBuf::from(git.path);
let can_path = fs::canonicalize(path).ok().unwrap();
can_path.into_os_string().into_string().ok().unwrap()
let path = PathBuf::from(git.path.clone());
match fs::canonicalize(path).ok(){
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 {

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(
&self,
workdir_path: String,
@ -105,9 +152,7 @@ impl Repo for Helm {
let repository_kind = self.repo_kind_from_url()?;
let path = match repository_kind {
RepoKind::Default => self.pull_default(workdir_path, vars)?,
RepoKind::Oci => {
todo!()
}
RepoKind::Oci => self.pull_oci(workdir_path, vars)?,
};
Ok(path)
}