webhook_bridge/src/kubernetes.rs
Tom Alexander a95339539b
Some checks failed
semver Build semver has succeeded
format Build format has succeeded
rust-test Build rust-test has succeeded
clippy Build clippy has failed
build Build build has succeeded
Use default namespace kubernetes client.
2024-09-29 02:44:58 -04:00

126 lines
4.5 KiB
Rust

use std::borrow::Borrow;
use std::borrow::Cow;
use kube::api::PostParams;
use kube::Api;
use kube::CustomResourceExt;
use regex::Regex;
use tracing::debug;
use tracing::info;
use crate::crd_pipeline_run::PipelineParam;
use crate::crd_pipeline_run::PipelineRun;
use crate::discovery::PipelineTemplate;
use crate::hook_push::HookPush;
use crate::hook_push::PipelineParamters;
pub(crate) async fn run_pipelines(
hook: HookPush,
pipelines: Vec<PipelineTemplate>,
kubernetes_client: kube::Client,
) -> Result<(), Box<dyn std::error::Error>> {
// let jobs: Api<PipelineRun> = Api::namespaced(kubernetes_client, "webhook-bridge");
let jobs: Api<PipelineRun> = Api::default_namespaced(kubernetes_client);
tracing::debug!("Using crd: {}", serde_json::to_string(&PipelineRun::crd())?);
for mut pipeline in pipelines {
info!(
"Kicking off {} for repo {}/{}",
pipeline.name,
hook.get_repo_owner()?,
hook.get_repo_name()?,
);
if pipeline.pipeline.spec.params.is_none() {
pipeline.pipeline.spec.params = Some(Vec::new());
}
if let Some(param_list) = pipeline.pipeline.spec.params.as_mut() {
param_list.push(PipelineParam {
name: Some("JOB_NAME".to_owned()),
value: Some(serde_json::Value::String(pipeline.name.clone())),
});
param_list.push(PipelineParam {
name: Some("REPO_OWNER".to_owned()),
value: Some(serde_json::Value::String(
hook.get_repo_owner()?.into_owned(),
)),
});
param_list.push(PipelineParam {
name: Some("REPO_NAME".to_owned()),
value: Some(serde_json::Value::String(
hook.get_repo_name()?.into_owned(),
)),
});
let hook_repo_url = hook.get_repo_url()?;
param_list.push(PipelineParam {
name: Some("REPO_URL".to_owned()),
value: pipeline
.clone_uri
.map(|uri| serde_json::Value::String(uri))
.or_else(|| Some(serde_json::Value::String(hook_repo_url.into_owned()))),
});
param_list.push(PipelineParam {
name: Some("PULL_BASE_SHA".to_owned()),
value: Some(serde_json::Value::String(
hook.get_pull_base_sha()?.into_owned(),
)),
});
param_list.push(PipelineParam {
name: Some("PULL_BASE_REF".to_owned()),
value: Some(serde_json::Value::String(
hook.get_pull_base_ref()?.into_owned(),
)),
});
}
if pipeline.pipeline.metadata.generate_name.is_none()
&& pipeline.pipeline.metadata.name.is_some()
{
std::mem::swap(
&mut pipeline.pipeline.metadata.generate_name,
&mut pipeline.pipeline.metadata.name,
);
if let Some(ref mut name) = pipeline.pipeline.metadata.generate_name {
let mut new_name_stub = sanitize_kubernetes_identifier(format!(
"{}-{}-{}",
name,
hook.get_repo_name()?,
hook.get_repo_owner()?
))?
.into_owned();
new_name_stub.truncate(63);
(*name) = new_name_stub + "-";
debug!("Using generate name: {}", name);
}
}
let pp = PostParams::default();
let created_run = jobs.create(&pp, &pipeline.pipeline).await?;
info!("Created PipelineRun {:?}", created_run.metadata.name);
}
Ok(())
}
fn sanitize_kubernetes_identifier<'a, O: Into<Cow<'a, str>>>(
original: O,
) -> Result<Cow<'a, str>, Box<dyn std::error::Error>> {
let validate_identifier_regex =
Regex::new(r"[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*")?;
let original = original.into();
if !validate_identifier_regex.is_match(original.borrow()) {
return Ok(original);
}
let mut clean_identifier = String::with_capacity(original.len());
for c in original.chars() {
match c {
'a'..='z' | 'A'..='Z' | '0'..='9' | '.' | '-' => {
clean_identifier.push(c);
}
_ => {
clean_identifier.push('-');
}
};
}
Ok(Cow::Owned(clean_identifier))
}