Skip to content

Commit f200302

Browse files
mjcarsongabaker
authored andcommitted
Fixed several bugs in Thorium
🐛 Bug Fixes - *(operator)* Fixed issue where the config could not be made into a CRD - *(scaler)* Scalers now only requests details on clusters they care about - *(agent)* Fixed issue where the agent was not injecting kwargs correctly - *(api)* Fixed issue where the API was incorrectly rejecting result paths Change Details fix(agent): Fixed issue where the agent was not injecting kwargs correctly This was causing the agent to add a list of values after each kwargs instead of repeating the kwarg for each value. This means Thorium will now use --kwarg <value> --kwarg <value> instead of --kwarg <value> <value>. fix(api): Fixed issue where the API was incorrectly rejecting result paths This was due to an incorrect check for '..' in file paths. fix(operator): Fixed issue where the config could not be made into a CRD This was caused by an enum having different types for each branch. The downside of this fix is that our config does allow someone to configure certificate validation settings while also disabling certificate validation. That could lead to some confusing scenarios where you think validation is enabled but its not. fix(scaler): Scalers now only requests details on clusters they care about This helps resolves issues where the scaler tries to get info on clusters that it cannot and will not schedule on. Closes #31
1 parent 7c94a0b commit f200302

22 files changed

Lines changed: 499 additions & 247 deletions

File tree

Cargo.lock

Lines changed: 144 additions & 120 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ members = [
1616
]
1717

1818
[workspace.package]
19-
version = "1.1.1"
19+
version = "1.1.2"
2020
authors = ["mcarson <mcarson@sandia.gov>", "gmbaker <gmbaker@sandia.gov>", "jehamza <jehamza@sandia.gov>"]
2121
edition = "2024"
2222

agent/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ infer = { version = "0.19.0", default-features = false, features = ["std"] }
3636

3737
# enable cgroups support for linux
3838
[target.'cfg(target_os = "linux")'.dependencies]
39-
thorium = { version = "1.1.1", path="../api", default-features = false, features = ["client", "cgroups", "crossbeam-err", "trace"]}
39+
thorium = { version = "1.1.2", path="../api", default-features = false, features = ["client", "cgroups", "crossbeam-err", "trace"]}
4040
cgroups-rs = "0.3"
4141
controlgroup = "0.3"
4242

4343

4444
# disable cgroups support when on windows
4545
[target.'cfg(any(target_os = "windows", target_os = "macos"))'.dependencies]
46-
thorium = { version = "1.1.1", path="../api", default-features = false, features = ["client", "crossbeam-err", "trace"]}
46+
thorium = { version = "1.1.2", path="../api", default-features = false, features = ["client", "crossbeam-err", "trace"]}
4747

4848

4949
[features]

agent/src/libs/agents/registry.rs

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use crossbeam::channel::Sender;
44
use path_clean::PathClean;
55
use std::path::PathBuf;
66
use thorium::{
7-
models::{ArgStrategy, GenericJob, GenericJobKwargs, GenericJobOpts, Image, KwargDependency},
87
Error,
8+
models::{ArgStrategy, GenericJob, GenericJobKwargs, GenericJobOpts, Image, KwargDependency},
99
};
1010
use tracing::instrument;
1111

@@ -158,17 +158,22 @@ impl Cmd {
158158
wipe = false;
159159
// expand this arg if its a joint arg
160160
let (key, value) = Self::expander(arg);
161-
// inject value source docker config
162-
self.built.push(key.clone());
163161
// check if this arg should be overridden
164162
if self.kwargs.contains_key(&key) {
165163
// enable wipe until hit another kwarg
166164
wipe = true;
167165
// override value if one was set
168-
let mut new_value = self.kwargs.remove(&key).unwrap();
169-
// override value with our own value
170-
self.built.append(&mut new_value);
166+
let new_values = self.kwargs.remove(&key).unwrap();
167+
// for each of our values add our kwarg
168+
for new_value in new_values {
169+
// add our key
170+
self.built.push(key.clone());
171+
// override value with our own value
172+
self.built.push(new_value);
173+
}
171174
} else if value.is_some() {
175+
// add our key
176+
self.built.push(key.clone());
172177
// push value from docker info
173178
self.built.push(value.unwrap());
174179
}
@@ -183,9 +188,14 @@ impl Cmd {
183188
}
184189
}
185190
// append all left over custom kwargs args if any were set
186-
for (key, mut values) in self.kwargs.drain() {
187-
self.built.push(key);
188-
self.built.append(&mut values);
191+
for (key, values) in self.kwargs.drain() {
192+
// add our kwargs
193+
for value in values {
194+
// add our key
195+
self.built.push(key.clone());
196+
// add our value
197+
self.built.push(value);
198+
}
189199
}
190200
}
191201

@@ -419,11 +429,18 @@ mod tests {
419429
samples: vec!["sample1".into(), "sample2".into()],
420430
ephemeral: vec!["file.txt".into(), "other.txt".into()],
421431
parent_ephemeral: HashMap::default(),
422-
repos: vec![RepoDependency {
423-
url: "github.com/curl/curl".into(),
424-
commitish: Some("master".into()),
425-
kind: Some(CommitishKinds::Branch),
426-
}],
432+
repos: vec![
433+
RepoDependency {
434+
url: "github.com/curl/curl".into(),
435+
commitish: Some("main".into()),
436+
kind: Some(CommitishKinds::Branch),
437+
},
438+
RepoDependency {
439+
url: "github.com/notcurl/notcurl".into(),
440+
commitish: Some("main".into()),
441+
kind: Some(CommitishKinds::Branch),
442+
},
443+
],
427444
trigger_depth: None,
428445
}
429446
}
@@ -750,6 +767,7 @@ mod tests {
750767
"corn.py",
751768
"--inputs",
752769
"sample1",
770+
"--inputs",
753771
"sample2"
754772
)
755773
);
@@ -796,6 +814,7 @@ mod tests {
796814
"pos2",
797815
"--inputs",
798816
"sample1",
817+
"--inputs",
799818
"sample2"
800819
)
801820
);
@@ -840,7 +859,9 @@ mod tests {
840859
"corn.py",
841860
"--inputs",
842861
"sample0",
862+
"--inputs",
843863
"sample1",
864+
"--inputs",
844865
"sample2"
845866
)
846867
);
@@ -974,7 +995,7 @@ mod tests {
974995

975996
/// Test a barebones job with samples but no overlays
976997
#[tokio::test]
977-
async fn empty_ephemnerals_kwargs() {
998+
async fn empty_ephemerals_kwargs() {
978999
// create a temporary log channel
9791000
let (mut logs_tx, _logs_rx) = crossbeam::channel::unbounded::<String>();
9801001
// generate an image and set the kwarg to pass in samples with
@@ -1009,6 +1030,7 @@ mod tests {
10091030
"corn.py",
10101031
"--ephemeral",
10111032
"file.txt",
1033+
"--ephemeral",
10121034
"other.txt"
10131035
)
10141036
);
@@ -1055,6 +1077,7 @@ mod tests {
10551077
"pos2",
10561078
"--ephemeral",
10571079
"file.txt",
1080+
"--ephemeral",
10581081
"other.txt"
10591082
)
10601083
);
@@ -1099,7 +1122,9 @@ mod tests {
10991122
"corn.py",
11001123
"--ephemeral",
11011124
"first.txt",
1125+
"--ephemeral",
11021126
"file.txt",
1127+
"--ephemeral",
11031128
"other.txt"
11041129
)
11051130
);
@@ -1115,7 +1140,7 @@ mod tests {
11151140
// generate a job
11161141
let mut job = generate_job();
11171142
// build stage args with just kwargs
1118-
job.args = job.args.kwarg("--1", vec!["1"]);
1143+
job.args = job.args.kwarg("--nums", vec!["1", "2"]);
11191144
// make this job a generator
11201145
job.generator = true;
11211146
let cmd = Cmd::new(
@@ -1149,8 +1174,10 @@ mod tests {
11491174
let args = vec_string!(
11501175
"/usr/bin/python3",
11511176
"corn.py",
1152-
"--1",
1177+
"--nums",
11531178
"1",
1179+
"--nums",
1180+
"2",
11541181
"--reaction",
11551182
&reaction,
11561183
"--job",
@@ -1355,7 +1382,9 @@ mod tests {
13551382
"pos2",
13561383
"--inputs",
13571384
"sample0",
1385+
"--inputs",
13581386
"sample1",
1387+
"--inputs",
13591388
"sample2",
13601389
"--corn",
13611390
"--beans"
@@ -1463,7 +1492,9 @@ mod tests {
14631492
"pos2",
14641493
"--ephemeral",
14651494
"first.txt",
1495+
"--ephemeral",
14661496
"file.txt",
1497+
"--ephemeral",
14671498
"other.txt",
14681499
"--corn",
14691500
"--beans"
@@ -1601,8 +1632,12 @@ mod tests {
16011632
"sample2",
16021633
"--image1-results",
16031634
"/tmp/thorium/testing/prior-results/sample1/image1",
1635+
"--image1-results",
16041636
"/tmp/thorium/testing/prior-results/sample2/image1",
1605-
"/tmp/thorium/testing/prior-results/github.com/curl/curl/image1"
1637+
"--image1-results",
1638+
"/tmp/thorium/testing/prior-results/github.com/curl/curl/image1",
1639+
"--image1-results",
1640+
"/tmp/thorium/testing/prior-results/github.com/notcurl/notcurl/image1"
16061641
)
16071642
);
16081643
// remove the test directory

api/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,9 @@ once_cell = { version = "1.21.3", optional = true }
134134
utoipa = { version = "5", features = ["axum_extras", "chrono", "uuid", "time", "url"], optional = true }
135135
utoipa-swagger-ui = { version = "9", features = ["axum"], optional = true }
136136
lettre = { version = "0.11", features = ["tokio1", "tokio1-rustls-tls", "builder", "smtp-transport"], default-features = false, optional = true }
137-
thorium-derive = { path = "../thorium-derive", version = "1.1.1", optional = true}
137+
thorium-derive = { path = "../thorium-derive", version = "1.1.2", optional = true}
138+
percent-encoding = { version = "2.3.1", optional = true }
139+
dashmap = { version = "6.1", optional = true }
138140

139141
# rkyv dependencies
140142
rkyv = { version = "=0.7.43", features = ["arbitrary_enum_discriminant", "uuid", "validation"], optional = true }

api/src/conf.rs

Lines changed: 92 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1960,6 +1960,54 @@ pub struct Scylla {
19601960
pub auth: Option<ScyllaAuth>,
19611961
}
19621962

1963+
/// The options for Elastic certificate validation
1964+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema)]
1965+
pub enum ElasticCertValidation {
1966+
/// Perform full validation based on a PEM encoded ca cert with CN/SAN checks enabled
1967+
Full(PathBuf),
1968+
/// Validate against a cert generated by a specific PEM encoded CA cert at a path
1969+
/// without CN/SAN checks
1970+
CA(PathBuf),
1971+
}
1972+
1973+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema)]
1974+
pub struct ElasticResults {
1975+
/// The name of the sample results index in elastic
1976+
#[serde(default = "default_elastic_sample_results_index")]
1977+
pub samples: String,
1978+
/// The name of the repo results index in elastic
1979+
#[serde(default = "default_elastic_repo_results_index")]
1980+
pub repos: String,
1981+
}
1982+
1983+
impl Default for ElasticResults {
1984+
fn default() -> Self {
1985+
Self {
1986+
samples: default_elastic_sample_results_index(),
1987+
repos: default_elastic_repo_results_index(),
1988+
}
1989+
}
1990+
}
1991+
1992+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema)]
1993+
pub struct ElasticTags {
1994+
/// The name of the sample tags index in elastic
1995+
#[serde(default = "default_elastic_sample_tags_index")]
1996+
pub samples: String,
1997+
/// The name of the repo tags index in elastic
1998+
#[serde(default = "default_elastic_repo_tags_index")]
1999+
pub repos: String,
2000+
}
2001+
2002+
impl Default for ElasticTags {
2003+
fn default() -> Self {
2004+
Self {
2005+
samples: default_elastic_sample_tags_index(),
2006+
repos: default_elastic_repo_tags_index(),
2007+
}
2008+
}
2009+
}
2010+
19632011
/// Adds a "thorium_" namespace to given elastic index
19642012
fn elastic_namespace(index: &str) -> String {
19652013
format!("thorium_{index}")
@@ -1993,7 +2041,10 @@ fn default_max_analyzed_offset() -> u32 {
19932041
1_000_000
19942042
}
19952043

1996-
/// Scylla settings
2044+
/// Elastic settings
2045+
///
2046+
/// The cert validation settings are overly complex to support the operator being able
2047+
/// to set this as a valid CRD in K8s.
19972048
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema)]
19982049
pub struct Elastic {
19992050
/// The node to connect to
@@ -2002,6 +2053,12 @@ pub struct Elastic {
20022053
pub username: String,
20032054
/// The password to use when authenticating
20042055
pub password: String,
2056+
/// The options for certificate validation
2057+
#[serde(default)]
2058+
pub cert_validation: Option<ElasticCertValidation>,
2059+
/// Disable certificate validation
2060+
#[serde(default)]
2061+
pub insecure_certificates: bool,
20052062
/// The options for results in elastic
20062063
#[serde(default)]
20072064
pub results: ElasticResults,
@@ -2017,40 +2074,41 @@ pub struct Elastic {
20172074
pub max_analyzed_offset: u32,
20182075
}
20192076

2020-
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema)]
2021-
pub struct ElasticResults {
2022-
/// The name of the sample results index in elastic
2023-
#[serde(default = "default_elastic_sample_results_index")]
2024-
pub samples: String,
2025-
/// The name of the repo results index in elastic
2026-
#[serde(default = "default_elastic_repo_results_index")]
2027-
pub repos: String,
2028-
}
2029-
2030-
impl Default for ElasticResults {
2031-
fn default() -> Self {
2032-
Self {
2033-
samples: default_elastic_sample_results_index(),
2034-
repos: default_elastic_repo_results_index(),
2077+
impl Elastic {
2078+
/// Cast this elastic cert config into a ```CertificateValidation``` object
2079+
#[cfg(feature = "api")]
2080+
pub async fn to_cert_validation(&self) -> elasticsearch::cert::CertificateValidation {
2081+
// if insecure certificates is turned on then ignore certificate validation
2082+
if self.insecure_certificates {
2083+
return elasticsearch::cert::CertificateValidation::None;
20352084
}
2036-
}
2037-
}
2038-
2039-
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema)]
2040-
pub struct ElasticTags {
2041-
/// The name of the sample tags index in elastic
2042-
#[serde(default = "default_elastic_sample_tags_index")]
2043-
pub samples: String,
2044-
/// The name of the repo tags index in elastic
2045-
#[serde(default = "default_elastic_repo_tags_index")]
2046-
pub repos: String,
2047-
}
2048-
2049-
impl Default for ElasticTags {
2050-
fn default() -> Self {
2051-
Self {
2052-
samples: default_elastic_sample_tags_index(),
2053-
repos: default_elastic_repo_tags_index(),
2085+
// handle each specific type of cert validation config
2086+
match &self.cert_validation {
2087+
None => elasticsearch::cert::CertificateValidation::Default,
2088+
Some(ElasticCertValidation::Full(path)) => {
2089+
// read our CA cert from disk
2090+
let ca_bytes = tokio::fs::read(path).await.expect(&format!(
2091+
"Failed to read elastic validation cert at {path:?}"
2092+
));
2093+
// build our cert
2094+
let cert = elasticsearch::cert::Certificate::from_pem(&ca_bytes).expect(&format!(
2095+
"Failed to parse certificate at {path:?} as a PEM encoded CA cert"
2096+
));
2097+
// return the right validation behavior
2098+
elasticsearch::cert::CertificateValidation::Full(cert)
2099+
}
2100+
Some(ElasticCertValidation::CA(path)) => {
2101+
// read our CA cert from disk
2102+
let ca_bytes = tokio::fs::read(path).await.expect(&format!(
2103+
"Failed to read elastic validation cert at {path:?}"
2104+
));
2105+
// build our cert
2106+
let cert = elasticsearch::cert::Certificate::from_pem(&ca_bytes).expect(&format!(
2107+
"Failed to parse certificate at {path:?} as a PEM encoded CA cert"
2108+
));
2109+
// return the right validation behavior
2110+
elasticsearch::cert::CertificateValidation::Certificate(cert)
2111+
}
20542112
}
20552113
}
20562114
}

0 commit comments

Comments
 (0)