Skip to content

Commit 185414a

Browse files
committed
Continue install flow
1 parent dc1bc19 commit 185414a

File tree

16 files changed

+313
-49
lines changed

16 files changed

+313
-49
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ utoipa = { workspace = true }
2626
snafu = { workspace = true }
2727
which = { workspace = true }
2828
serde = { workspace = true }
29+
tera = { workspace = true }
2930
url = { workspace = true }
3031

3132
[build-dependencies]
@@ -50,6 +51,7 @@ utoipa = "3.3.0"
5051
axum = "0.6.18"
5152
snafu = "0.7.4"
5253
which = "4.4.0"
54+
tera = "1.18.1"
5355
url = "2.3.1"
5456
xdg = "2.4.1"
5557
phf = "0.11.1"

src/constants.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ pub const DEFAULT_LOCAL_CLUSTER_NAME: &str = "stackable-data-platform";
66
pub const DEFAULT_CACHE_MAX_AGE_IN_SECS: u64 = 3_600; // One hour in seconds
77

88
pub const HELM_ERROR_PREFIX: &str = "ERROR:";
9+
pub const HELM_DEFAULT_CHART_VERSION: &str = ">0.0.0-0";

src/helm.rs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
use std::fmt::Display;
12
use std::str::{self, Utf8Error};
23
use std::{collections::HashMap, ffi::CStr, os::raw::c_char};
34

45
use serde::Deserialize;
56
use snafu::{ResultExt, Snafu};
67
use tracing::{debug, error, info, instrument};
78

8-
use crate::constants::HELM_ERROR_PREFIX;
9+
use crate::constants::{HELM_DEFAULT_CHART_VERSION, HELM_ERROR_PREFIX};
910

1011
#[derive(Debug, Deserialize)]
1112
#[serde(rename_all = "camelCase")]
@@ -78,16 +79,34 @@ pub enum HelmInstallReleaseStatus {
7879
/// Indicates that a release is already installed with a different version
7980
/// than requested.
8081
ReleaseAlreadyInstalledWithversion {
82+
release_name: String,
8183
current_version: String,
8284
requested_version: String,
8385
},
8486

8587
/// Indicates that a release is already installed, but no specific version
8688
/// was requested.
87-
ReleaseAlreadyInstalledUnspecified(String),
89+
ReleaseAlreadyInstalledUnspecified {
90+
release_name: String,
91+
current_version: String,
92+
},
8893

8994
/// Indicates that the release was installed successfully.
90-
Installed,
95+
Installed(String),
96+
}
97+
98+
impl Display for HelmInstallReleaseStatus {
99+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100+
match self {
101+
HelmInstallReleaseStatus::ReleaseAlreadyInstalledWithversion {
102+
release_name,
103+
current_version,
104+
requested_version,
105+
} => write!(f, "The release {release_name} ({current_version}) is already installed (requested {requested_version}), skipping."),
106+
HelmInstallReleaseStatus::ReleaseAlreadyInstalledUnspecified{release_name, current_version} => write!(f, "The release {release_name} ({current_version}) is already installed and no specific version was requested, skipping."),
107+
HelmInstallReleaseStatus::Installed(release_name) => write!(f, "The release {release_name} was successfully installed."),
108+
}
109+
}
91110
}
92111

93112
#[repr(C)]
@@ -153,11 +172,11 @@ pub fn install_release_from_repo(
153172
if chart_version == current_version {
154173
return Ok(
155174
HelmInstallReleaseStatus::ReleaseAlreadyInstalledWithversion {
175+
release_name: release_name.to_string(),
156176
current_version: current_version.to_string(),
157177
requested_version: chart_version.to_string(),
158178
},
159179
);
160-
// return Ok(format!("The release {release_name} ({current_version}) is already installed, skipping."));
161180
} else {
162181
return Err(HelmError::InstallReleaseError {
163182
source: HelmInstallReleaseError::ReleaseAlreadyInstalled {
@@ -170,16 +189,17 @@ pub fn install_release_from_repo(
170189
}
171190
None => {
172191
return Ok(
173-
HelmInstallReleaseStatus::ReleaseAlreadyInstalledUnspecified(
174-
current_version.into(),
175-
),
192+
HelmInstallReleaseStatus::ReleaseAlreadyInstalledUnspecified {
193+
release_name: release_name.to_string(),
194+
current_version,
195+
},
176196
)
177197
}
178198
}
179199
}
180200

181201
let full_chart_name = format!("{repo_name}/{chart_name}");
182-
let chart_version = chart_version.unwrap_or(">0.0.0-0"); // TODO (Techassi): Move this into a constant
202+
let chart_version = chart_version.unwrap_or(HELM_DEFAULT_CHART_VERSION);
183203

184204
debug!(
185205
"Installing Helm release {} ({}) from chart {}",
@@ -195,7 +215,9 @@ pub fn install_release_from_repo(
195215
suppress_output,
196216
)?;
197217

198-
Ok(HelmInstallReleaseStatus::Installed)
218+
Ok(HelmInstallReleaseStatus::Installed(
219+
release_name.to_string(),
220+
))
199221
}
200222

201223
fn install_release(

src/platform/operator/spec.rs

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ use std::{fmt::Display, str::FromStr};
33
use snafu::Snafu;
44
use tracing::{info, instrument};
55

6+
use crate::helm;
7+
68
pub const VALID_OPERATORS: &[&str] = &[
79
"airflow",
810
"commons",
@@ -21,14 +23,6 @@ pub const VALID_OPERATORS: &[&str] = &[
2123
"zookeeper",
2224
];
2325

24-
/// OperatorSpec describes the format of an operator name with optional version number. The string format is
25-
/// `<OPERATOR_NAME>(=<VERSION>)`. Valid values values are: `operator`, `operator=1.2.3` or `operator=1.2.3-rc1`.
26-
#[derive(Clone, Debug)]
27-
pub struct OperatorSpec {
28-
pub version: Option<String>,
29-
pub name: String,
30-
}
31-
3226
#[derive(Debug, Snafu, PartialEq)]
3327
pub enum OperatorSpecParseError {
3428
#[snafu(display("invalid equal sign count in operator spec, expected one"))]
@@ -44,6 +38,14 @@ pub enum OperatorSpecParseError {
4438
InvalidName { name: String },
4539
}
4640

41+
/// OperatorSpec describes the format of an operator name with optional version number. The string format is
42+
/// `<OPERATOR_NAME>(=<VERSION>)`. Valid values values are: `operator`, `operator=1.2.3` or `operator=1.2.3-rc1`.
43+
#[derive(Clone, Debug)]
44+
pub struct OperatorSpec {
45+
pub version: Option<String>,
46+
pub name: String,
47+
}
48+
4749
impl Display for OperatorSpec {
4850
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4951
write!(
@@ -124,12 +126,22 @@ impl TryFrom<&str> for OperatorSpec {
124126
}
125127

126128
impl OperatorSpec {
127-
pub fn new(name: String, version: Option<String>) -> Result<Self, OperatorSpecParseError> {
128-
if !VALID_OPERATORS.contains(&name.as_str()) {
129-
return Err(OperatorSpecParseError::InvalidName { name });
129+
pub fn new<T>(name: T, version: Option<String>) -> Result<Self, OperatorSpecParseError>
130+
where
131+
T: AsRef<str>,
132+
{
133+
let name = name.as_ref();
134+
135+
if !VALID_OPERATORS.contains(&name) {
136+
return Err(OperatorSpecParseError::InvalidName {
137+
name: name.to_string(),
138+
});
130139
}
131140

132-
Ok(Self { version, name })
141+
Ok(Self {
142+
version,
143+
name: name.to_string(),
144+
})
133145
}
134146

135147
/// Returns the name used by Helm
@@ -151,14 +163,26 @@ impl OperatorSpec {
151163

152164
/// Installs the operator using Helm
153165
#[instrument(skip_all)]
154-
pub fn install(&self) {
166+
pub fn install(&self) -> Result<(), helm::HelmError> {
155167
info!("Installing operator {}", self);
156168

157169
let helm_name = self.helm_name();
158170
let helm_repo = self.helm_repo();
171+
let version = match &self.version {
172+
Some(version) => Some(version.as_str()),
173+
None => None,
174+
};
159175

160176
// Install using Helm
161-
todo!()
177+
match helm::install_release_from_repo(
178+
&self.name, &helm_name, &helm_repo, &helm_name, version, None, "", true,
179+
) {
180+
Ok(status) => {
181+
println!("{status}");
182+
Ok(())
183+
}
184+
Err(err) => Err(err),
185+
}
162186
}
163187
}
164188

src/platform/product.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ use serde::{Deserialize, Serialize};
44
#[serde(rename_all = "camelCase")]
55
pub struct ProductSpec {
66
#[serde(rename = "operatorVersion")]
7-
version: String,
7+
pub version: String,
88
}

src/platform/release/spec.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,27 @@
11
use indexmap::IndexMap;
22
use serde::{Deserialize, Serialize};
3+
use snafu::{ResultExt, Snafu};
34
use tracing::{info, instrument};
45

56
#[cfg(feature = "openapi")]
67
use utoipa::ToSchema;
78

8-
use crate::platform::product::ProductSpec;
9+
use crate::{
10+
helm::HelmError,
11+
platform::{
12+
operator::{OperatorSpec, OperatorSpecParseError},
13+
product::ProductSpec,
14+
},
15+
};
16+
17+
#[derive(Debug, Snafu)]
18+
pub enum ReleaseInstallError {
19+
#[snafu(display("failed to parse operator spec: {source}"))]
20+
OperatorSpecParseError { source: OperatorSpecParseError },
21+
22+
#[snafu(display("failed with Helm error: {source}"))]
23+
HelmError { source: HelmError },
24+
}
925

1026
#[derive(Clone, Debug, Deserialize, Serialize)]
1127
#[serde(rename_all = "camelCase")]
@@ -24,19 +40,29 @@ pub struct ReleaseSpec {
2440

2541
impl ReleaseSpec {
2642
#[instrument(skip_all)]
27-
pub fn install(&self, include_products: &[String], exclude_products: &[String]) {
43+
pub fn install(
44+
&self,
45+
include_products: &[String],
46+
exclude_products: &[String],
47+
) -> Result<(), ReleaseInstallError> {
2848
info!("Installing release");
2949

3050
for (product_name, product) in &self.products {
3151
let included = include_products.is_empty() || include_products.contains(&product_name);
3252
let excluded = exclude_products.contains(&product_name);
3353

3454
if included && !excluded {
55+
info!("Installing product {}", product_name);
56+
57+
// Create operator spec
58+
let operator = OperatorSpec::new(product_name, Some(product.version.clone()))
59+
.context(OperatorSpecParseSnafu {})?;
60+
3561
// Install operator
36-
todo!()
62+
operator.install().context(HelmSnafu {})?
3763
}
3864
}
3965

40-
todo!()
66+
Ok(())
4167
}
4268
}

src/platform/stack/mod.rs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,9 @@ use indexmap::IndexMap;
22
use serde::{Deserialize, Serialize};
33

44
mod spec;
5-
use snafu::Snafu;
65
pub use spec::*;
76

8-
use crate::{
9-
common::{List, SpecIter},
10-
utils::params::IntoParametersError,
11-
};
7+
use crate::common::{List, SpecIter};
128

139
/// This struct describes a complete demos v2 file
1410
#[derive(Debug, Deserialize, Serialize)]
@@ -25,12 +21,3 @@ impl SpecIter<StackSpecV2> for StacksV2 {
2521
}
2622

2723
pub type StackList = List<StacksV2, StackSpecV2>;
28-
29-
#[derive(Debug, Snafu)]
30-
pub enum StackError {
31-
#[snafu(display("parameter parse error: {source}"))]
32-
ParameterError { source: IntoParametersError },
33-
34-
#[snafu(display("no such stack"))]
35-
NoSuchStack,
36-
}

src/platform/stack/spec.rs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use serde::{Deserialize, Serialize};
2-
use snafu::ResultExt;
2+
use snafu::{ResultExt, Snafu};
33
use tracing::{info, instrument};
44

55
#[cfg(feature = "openapi")]
@@ -9,16 +9,33 @@ use crate::{
99
common::ManifestSpec,
1010
platform::{
1111
demo::DemoParameter,
12-
release::ReleaseList,
13-
stack::{ParameterSnafu, StackError},
12+
release::{ReleaseInstallError, ReleaseList},
13+
},
14+
utils::{
15+
params::{
16+
IntoParameters, IntoParametersError, Parameter, RawParameter, RawParameterParseError,
17+
},
18+
path::PathOrUrl,
19+
read::read_yaml_data_with_templating,
1420
},
15-
utils::params::{IntoParameters, Parameter, RawParameter, RawParameterParseError},
1621
};
1722

1823
pub type RawStackParameterParseError = RawParameterParseError;
1924
pub type RawStackParameter = RawParameter;
2025
pub type StackParameter = Parameter;
2126

27+
#[derive(Debug, Snafu)]
28+
pub enum StackError {
29+
#[snafu(display("parameter parse error: {source}"))]
30+
ParameterError { source: IntoParametersError },
31+
32+
#[snafu(display("no such stack"))]
33+
NoSuchStack,
34+
35+
#[snafu(display("release install error: {source}"))]
36+
ReleaseInstallError { source: ReleaseInstallError },
37+
}
38+
2239
/// This struct describes a stack with the v2 spec
2340
#[derive(Debug, Clone, Deserialize, Serialize)]
2441
#[serde(rename_all = "camelCase")]
@@ -53,23 +70,37 @@ impl StackSpecV2 {
5370
pub fn install(&self, release_list: ReleaseList) -> Result<(), StackError> {
5471
info!("Installing stack");
5572

73+
// Get the release by name
5674
let release = release_list
5775
.get(&self.release)
5876
.ok_or(StackError::NoSuchStack)?;
5977

60-
release.install(&self.operators, &[]);
78+
// Install the release
79+
release
80+
.install(&self.operators, &[])
81+
.context(ReleaseInstallSnafu {})?;
6182

6283
todo!()
6384
}
6485

6586
#[instrument(skip_all)]
6687
pub fn install_stack_manifests(&self, parameters: &[String]) -> Result<(), StackError> {
6788
info!("Installing stack manifests");
89+
6890
let parameters = parameters
6991
.to_owned()
7092
.into_params(&self.parameters)
7193
.context(ParameterSnafu {})?;
7294

95+
for manifest in &self.manifests {
96+
match manifest {
97+
ManifestSpec::HelmChart(helm_file) => {
98+
let helm_chart = read_yaml_data_with_templating(helm_file, &parameters);
99+
}
100+
ManifestSpec::PlainYaml(_) => todo!(),
101+
}
102+
}
103+
73104
todo!()
74105
}
75106

0 commit comments

Comments
 (0)