Skip to content

Commit 8ad3ea6

Browse files
fletcherwfedora Cloud User
authored andcommitted
pluto: use apiclient API rather than CLI
Replace the calls to shell out to `apiclient` with direct API calls. Add logging so that we can better monitor time spent on each portion of pluto.
1 parent db53108 commit 8ad3ea6

File tree

4 files changed

+59
-48
lines changed

4 files changed

+59
-48
lines changed

sources/Cargo.lock

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

sources/api/pluto/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ exclude = ["README.md"]
1313
fips = ["aws-lc-rs/fips", "aws-smithy-experimental/crypto-aws-lc-fips", "rustls/fips"]
1414

1515
[dependencies]
16+
apiclient.workspace = true
1617
aws-config.workspace = true
1718
aws-lc-rs = { workspace = true, features = ["bindgen"] }
1819
aws-sdk-eks.workspace = true
@@ -24,10 +25,13 @@ base64.workspace = true
2425
bottlerocket-modeled-types.workspace = true
2526
bottlerocket-settings-models.workspace = true
2627
constants.workspace = true
28+
http.workspace = true
2729
imdsclient.workspace = true
30+
log.workspace = true
2831
rustls.workspace = true
2932
serde = { workspace = true, features = ["derive"] }
3033
serde_json.workspace = true
34+
simplelog.workspace = true
3135
snafu.workspace = true
3236
tempfile.workspace = true
3337
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }

sources/api/pluto/src/api.rs

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
use bottlerocket_settings_models::{AwsSettingsV1, KubernetesSettingsV1, NetworkSettingsV1};
22
use serde::Deserialize;
3-
use snafu::{ensure, ResultExt, Snafu};
4-
use std::ffi::OsStr;
5-
use tokio::process::Command;
3+
use snafu::{ResultExt, Snafu};
64

75
/// The result type for the [`api`] module.
86
pub(super) type Result<T> = std::result::Result<T, Error>;
@@ -128,53 +126,56 @@ struct APISettingsResponse {
128126

129127
#[derive(Debug, Snafu)]
130128
pub(crate) enum Error {
131-
#[snafu(display("Failed to call apiclient: {}", source))]
132-
CommandFailure { source: std::io::Error },
133-
#[snafu(display("apiclient execution failed: {}", reason))]
134-
ExecutionFailure { reason: String },
129+
#[snafu(display("Failed to call API get_prefixes: {}", source))]
130+
GetPrefix { source: apiclient::get::Error },
135131
#[snafu(display("Deserialization of configuration file failed: {}", source))]
136132
Deserialize {
137133
#[snafu(source(from(serde_json::Error, Box::new)))]
138134
source: Box<serde_json::Error>,
139135
},
140-
}
141-
142-
pub(crate) async fn client_command<I, S>(args: I) -> Result<Vec<u8>>
143-
where
144-
I: IntoIterator<Item = S>,
145-
S: AsRef<OsStr>,
146-
{
147-
let result = Command::new("/usr/bin/apiclient")
148-
.args(args)
149-
.output()
150-
.await
151-
.context(CommandFailureSnafu)?;
152-
153-
ensure!(
154-
result.status.success(),
155-
ExecutionFailureSnafu {
156-
reason: String::from_utf8_lossy(&result.stderr)
157-
}
158-
);
136+
#[snafu(display("Setting settings values in API failed: {}", source))]
137+
SetSettings { source: apiclient::Error },
159138

160-
Ok(result.stdout)
139+
#[snafu(display("Failed to serialize generated settings: {}", source))]
140+
Serialize { source: serde_json::Error },
161141
}
162142

163143
/// Gets the info that we need to know about the EKS cluster from the Bottlerocket API.
164144
pub(crate) async fn get_aws_k8s_info() -> Result<SettingsView> {
165-
let view_str = client_command(&[
166-
"get",
167-
"settings.aws",
168-
"settings.network",
169-
"settings.kubernetes",
170-
])
171-
.await?;
145+
let prefixes = ["settings.aws", "settings.network", "settings.kubernetes"]
146+
.into_iter()
147+
.map(str::to_string)
148+
.collect();
149+
let response = apiclient::get::get_prefixes(constants::API_SOCKET, prefixes)
150+
.await
151+
.context(GetPrefixSnafu)?;
172152

173153
let api_response: APISettingsResponse =
174-
serde_json::from_slice(view_str.as_slice()).context(DeserializeSnafu)?;
154+
serde_json::from_value::<APISettingsResponse>(response).context(DeserializeSnafu)?;
175155
Ok(api_response.settings)
176156
}
177157

158+
/// Send the settings to the datastore through the API
159+
pub(crate) async fn set_settings(settings: &KubernetesSettingsV1) -> Result<()> {
160+
let generated_settings = serde_json::json!({
161+
"kubernetes": serde_json::to_value(settings).context(SerializeSnafu)?
162+
});
163+
let request_body = generated_settings.to_string();
164+
165+
let uri = &format!(
166+
"{}?tx={}",
167+
constants::API_SETTINGS_URI,
168+
constants::LAUNCH_TRANSACTION,
169+
);
170+
let method = "PATCH";
171+
// Ignore response code/body, raw_request already checks for success.
172+
let _ = apiclient::raw_request(constants::API_SOCKET, uri, method, Some(request_body))
173+
.await
174+
.context(SetSettingsSnafu)?;
175+
176+
Ok(())
177+
}
178+
178179
#[cfg(test)]
179180
mod test {
180181
use super::*;

sources/api/pluto/src/main.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,15 @@ mod aws;
3636
mod ec2;
3737
mod eks;
3838

39+
#[macro_use]
40+
extern crate log;
41+
3942
use api::{settings_view_get, settings_view_set, SettingsViewDelta};
4043
use aws_smithy_experimental::hyper_1_0::CryptoMode;
4144
use base64::Engine;
4245
use bottlerocket_modeled_types::{KubernetesClusterDnsIp, KubernetesHostnameOverrideSource};
4346
use imdsclient::ImdsClient;
47+
use simplelog::{Config as LogConfig, LevelFilter, SimpleLogger};
4448
use snafu::{ensure, OptionExt, ResultExt};
4549
use std::fs::File;
4650
use std::io::{BufRead, BufReader, Write};
@@ -136,9 +140,6 @@ mod error {
136140
#[snafu(display("Failed to read line: {}", source))]
137141
IoReadLine { source: std::io::Error },
138142

139-
#[snafu(display("Failed to serialize generated settings: {}", source))]
140-
Serialize { source: serde_json::Error },
141-
142143
#[snafu(display("Failed to set generated settings: {}", source))]
143144
SetFailure { source: api::Error },
144145

@@ -162,6 +163,9 @@ mod error {
162163

163164
#[snafu(display("Unable to create tempdir: {}", source))]
164165
Tempdir { source: std::io::Error },
166+
167+
#[snafu(display("Logger setup error: {}", source))]
168+
Logger { source: log::SetLoggerError },
165169
}
166170
}
167171

@@ -488,6 +492,11 @@ fn set_aws_config(aws_k8s_info: &SettingsViewDelta, filepath: &Path) -> Result<(
488492
}
489493

490494
async fn run() -> Result<()> {
495+
// SimpleLogger will send errors to stderr and anything less to stdout.
496+
SimpleLogger::init(LevelFilter::Info, LogConfig::default()).context(error::LoggerSnafu)?;
497+
info!("Pluto started");
498+
499+
info!("Retrieving settings values");
491500
let mut client = ImdsClient::new();
492501
let current_settings = api::get_aws_k8s_info().await.context(error::AwsInfoSnafu)?;
493502
let mut aws_k8s_info = SettingsViewDelta::from_api_response(current_settings);
@@ -498,23 +507,16 @@ async fn run() -> Result<()> {
498507
let aws_config_file_path = temp_dir.path().join(AWS_CONFIG_FILE);
499508
set_aws_config(&aws_k8s_info, Path::new(&aws_config_file_path))?;
500509

510+
info!("Generating kubernetes settings");
501511
generate_cluster_dns_ip(&mut client, &mut aws_k8s_info).await?;
502512
generate_node_ip(&mut client, &mut aws_k8s_info).await?;
503513
generate_max_pods(&mut client, &mut aws_k8s_info).await?;
504514
generate_provider_id(&mut client, &mut aws_k8s_info).await?;
505515
generate_node_name(&mut client, &mut aws_k8s_info).await?;
506516

507517
if let Some(k8s_settings) = &aws_k8s_info.delta().kubernetes {
508-
let generated_settings = serde_json::json!({
509-
"kubernetes": serde_json::to_value(k8s_settings).context(error::SerializeSnafu)?
510-
});
511-
let json_str = generated_settings.to_string();
512-
let uri = &format!(
513-
"{}?tx={}",
514-
constants::API_SETTINGS_URI,
515-
constants::LAUNCH_TRANSACTION
516-
);
517-
api::client_command(&["raw", "-m", "PATCH", "-u", uri, "-d", json_str.as_str()])
518+
info!("Sending settings values to the API");
519+
api::set_settings(k8s_settings)
518520
.await
519521
.context(error::SetFailureSnafu)?;
520522
}

0 commit comments

Comments
 (0)