Skip to content

Commit

Permalink
Merge pull request #3721 from jmt-lab/jmt/thar-be-updates/config
Browse files Browse the repository at this point in the history
thar-be-updates: migrate to use configuration file
  • Loading branch information
jmt-lab authored Mar 4, 2024
2 parents f6c1b7a + 01c5e34 commit 061be84
Show file tree
Hide file tree
Showing 14 changed files with 174 additions and 76 deletions.
2 changes: 2 additions & 0 deletions Release.toml
Original file line number Diff line number Diff line change
Expand Up @@ -278,4 +278,6 @@ version = "1.19.3"
"(1.19.2, 1.19.3)" = [
"migrate_v1.19.3_prairiedog-config-file-v0-1-0.lz4",
"migrate_v1.19.3_prairiedog-services-cfg-v0-1-0.lz4",
"migrate_v1.19.3_thar-be-updates-config-file-v0-1-0.lz4",
"migrate_v1.19.3_thar-be-updates-affected-services-v0-1-0.lz4",
]
4 changes: 3 additions & 1 deletion packages/os/os.spec
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Source13: cis-checks-k8s-metadata-json
%endif
Source14: certdog-toml
Source15: prairiedog-toml
Source16: thar-be-updates-toml

# 1xx sources: systemd units
Source100: apiserver.service
Expand Down Expand Up @@ -474,7 +475,7 @@ install -d %{buildroot}%{_cross_datadir}/updog
install -p -m 0644 %{_cross_repo_root_json} %{buildroot}%{_cross_datadir}/updog

install -d %{buildroot}%{_cross_templatedir}
install -p -m 0644 %{S:5} %{S:6} %{S:7} %{S:8} %{S:14} %{S:15} %{buildroot}%{_cross_templatedir}
install -p -m 0644 %{S:5} %{S:6} %{S:7} %{S:8} %{S:14} %{S:15} %{S:16} %{buildroot}%{_cross_templatedir}

install -d %{buildroot}%{_cross_unitdir}
install -p -m 0644 \
Expand Down Expand Up @@ -585,6 +586,7 @@ install -p -m 0644 %{S:400} %{S:401} %{S:402} %{buildroot}%{_cross_licensedir}
%files -n %{_cross_os}thar-be-updates
%{_cross_bindir}/thar-be-updates
%{_cross_tmpfilesdir}/thar-be-updates.conf
%{_cross_templatedir}/thar-be-updates-toml

%files -n %{_cross_os}host-containers
%{_cross_bindir}/host-containers
Expand Down
5 changes: 5 additions & 0 deletions packages/os/thar-be-updates-toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[required-extensions]
updates = "v1"
std = { version = "v1", helpers = ["default"] }
+++
version-lock = "{{{default "latest" settings.updates.version-lock}}}"
21 changes: 16 additions & 5 deletions sources/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions sources/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ members = [
"api/migration/migrations/v1.19.2/add-ecs-enable-container-metadata",
"api/migration/migrations/v1.19.3/prairiedog-config-file-v0-1-0",
"api/migration/migrations/v1.19.3/prairiedog-services-cfg-v0-1-0",
"api/migration/migrations/v1.19.3/thar-be-updates-config-file-v0-1-0",
"api/migration/migrations/v1.19.3/thar-be-updates-affected-services-v0-1-0",

"bloodhound",

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "thar-be-updates-affected-services-v0-1-0"
version = "0.1.0"
authors = ["Jarrett Tierney <[email protected]>"]
license = "Apache-2.0 OR MIT"
edition = "2021"
publish = false
exclude = ["README.md"]

[dependencies]
migration-helpers = { path = "../../../migration-helpers", version = "0.1.0" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use migration_helpers::common_migrations::{
MetadataListReplacement, ReplaceMetadataListsMigration,
};
use migration_helpers::{migrate, Result};
use std::process;
fn run() -> Result<()> {
migrate(ReplaceMetadataListsMigration(vec![
MetadataListReplacement {
setting: "settings.updates",
metadata: "affected-services",
old_vals: &["updog"],
new_vals: &["updog", "thar-be-updates"],
},
]))
}
fn main() {
if let Err(e) = run() {
eprintln!("{}", e);
process::exit(1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "thar-be-updates-config-file-v0-1-0"
version = "0.1.0"
edition = "2021"
authors = ["Jarrett Tierney <[email protected]>"]
license = "Apache-2.0 OR MIT"
publish = false
exclude = ["README.md"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
migration-helpers = { path = "../../../migration-helpers", version = "0.1.0" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use migration_helpers::common_migrations::AddPrefixesMigration;
use migration_helpers::{migrate, Result};
use std::process;

fn run() -> Result<()> {
migrate(AddPrefixesMigration(vec![
"configuration-files.thar-be-updates-toml",
"services.thar-be-updates",
]))
}

fn main() {
if let Err(e) = run() {
eprintln!("{}", e);
process::exit(1);
}
}
7 changes: 2 additions & 5 deletions sources/api/thar-be-updates/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,11 @@ build = "build.rs"
exclude = ["README.md"]

[dependencies]
apiclient = { path = "../apiclient", version = "0.1" }
constants = { path = "../../constants", version = "0.1" }
bottlerocket-release = { path = "../../bottlerocket-release", version = "0.1" }
chrono = { version = "0.4", default-features = false, features = ["std", "serde", "clock"] }
fs2 = "0.4"
http = "0.2"
log = "0.4"
models = { path = "../../models", version = "0.1" }
modeled-types = { path = "../../models/modeled-types", version = "0.1" }
nix = "0.26"
num-derive = "0.3"
num-traits = "0.2"
Expand All @@ -29,7 +26,7 @@ signpost = { path = "../../updater/signpost", version = "0.1" }
simplelog = "0.12"
snafu = "0.7"
tempfile = "3"
tokio = { version = "~1.32", default-features = false, features = ["macros", "rt-multi-thread"] } # LTS
toml = "0.8"
update_metadata = { path = "../../updater/update_metadata", version = "0.1" }

[build-dependencies]
Expand Down
27 changes: 11 additions & 16 deletions sources/api/thar-be-updates/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::status::{UpdateCommand, UpdateState};
use http::StatusCode;
use num_derive::{FromPrimitive, ToPrimitive};
use snafu::Snafu;
use std::path::PathBuf;
Expand Down Expand Up @@ -54,20 +53,16 @@ pub enum Error {
source: std::io::Error,
},

#[snafu(display("Error sending {} to {}: {}", method, uri, source))]
APIRequest {
method: String,
uri: String,
#[snafu(source(from(apiclient::Error, Box::new)))]
source: Box<apiclient::Error>,
#[snafu(display("Error reading configuration file at {}: {}", path.display(), source))]
ReadConfig {
path: PathBuf,
source: std::io::Error,
},

#[snafu(display("Error {} when sending {} to {}: {}", code, method, uri, response_body))]
APIResponse {
method: String,
uri: String,
code: StatusCode,
response_body: String,
#[snafu(display("Error deserializing configuration at {}: {}", path.display(), source))]
Deserialization {
path: PathBuf,
source: toml::de::Error,
},

#[snafu(display("Error deserializing response as JSON from {}: {}", uri, source))]
Expand Down Expand Up @@ -120,6 +115,9 @@ pub enum Error {
source: serde_json::Error,
},

#[snafu(display("Failed to get required setting '{}'", setting))]
GetSettingOption { setting: String },

#[snafu(display("Failed to parse version string '{}' into semver version", version))]
SemVer {
version: String,
Expand Down Expand Up @@ -149,9 +147,6 @@ pub enum Error {

#[snafu(display("Logger setup error: {}", source))]
Logger { source: log::SetLoggerError },

#[snafu(display("Unable to create a tokio runtime: {}", source))]
Runtime { source: std::io::Error },
}

/// Map errors to specific exit codes to return to caller
Expand Down
46 changes: 26 additions & 20 deletions sources/api/thar-be-updates/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use simplelog::{Config as LogConfig, LevelFilter, SimpleLogger};
use snafu::ensure;
use snafu::{OptionExt, ResultExt};
use std::fs::File;
use std::path::Path;
use std::path::{Path, PathBuf};
use std::process::{exit, Command};
use std::str::FromStr;
use std::{env, process};
Expand All @@ -37,12 +37,13 @@ use thar_be_updates::status::{
};

const UPDATE_STATUS_DIR: &str = "/run/cache/thar-be-updates";
const DEFAULT_CONFIG_FILE: &str = "/etc/thar-be-updates.toml";

/// Stores the command line arguments
struct Args {
subcommand: UpdateCommand,
log_level: LevelFilter,
socket_path: String,
config_path: PathBuf,
}

/// Prints an usage message
Expand All @@ -59,10 +60,9 @@ fn usage() -> ! {
deactivate Reverts update activation by marking current active partition for boot
Global options:
[ --socket-path PATH ] Bottlerocket API socket path (default {})
[ --config-path PATH ] configuration file (default {})
[ --log-level trace|debug|info|warn|error ] (default info)",
program_name,
constants::API_SOCKET,
program_name, DEFAULT_CONFIG_FILE,
);
process::exit(2);
}
Expand All @@ -77,7 +77,7 @@ fn usage_msg<S: AsRef<str>>(msg: S) -> ! {
fn parse_args(args: std::env::Args) -> Args {
let mut subcommand = None;
let mut log_level = None;
let mut socket_path = None;
let mut config_path = None;

let mut iter = args.skip(1).peekable();
while let Some(arg) = iter.next() {
Expand All @@ -91,11 +91,11 @@ fn parse_args(args: std::env::Args) -> Args {
}));
}

"--socket-path" => {
socket_path = Some(
iter.next()
.unwrap_or_else(|| usage_msg("Did not give argument to --socket-path")),
)
"--config-path" => {
config_path =
Some(PathBuf::from(iter.next().unwrap_or_else(|| {
usage_msg("Did not give argument to --config-path")
})))
}
// Assume any arguments not prefixed with '-' is a subcommand
s if !s.starts_with('-') => {
Expand All @@ -112,7 +112,7 @@ fn parse_args(args: std::env::Args) -> Args {
Args {
subcommand: subcommand.unwrap_or_else(|| usage()),
log_level: log_level.unwrap_or(LevelFilter::Info),
socket_path: socket_path.unwrap_or_else(|| constants::API_SOCKET.to_string()),
config_path: config_path.unwrap_or_else(|| PathBuf::from(DEFAULT_CONFIG_FILE)),
}
}

Expand Down Expand Up @@ -180,7 +180,10 @@ macro_rules! fork_and_return {

/// Spawns updog process to get list of updates and check if any of them can be updated to.
/// Returns true if there is an available update, returns false otherwise.
fn refresh(status: &mut UpdateStatus, socket_path: &str) -> Result<bool> {
fn refresh<P>(status: &mut UpdateStatus, config_path: P) -> Result<bool>
where
P: AsRef<Path>,
{
fork_and_return!({
debug!("Spawning 'updog whats'");
let output = Command::new("updog")
Expand All @@ -194,7 +197,7 @@ fn refresh(status: &mut UpdateStatus, socket_path: &str) -> Result<bool> {
}
let update_info: Vec<update_metadata::Update> =
serde_json::from_slice(&output.stdout).context(error::UpdateInfoSnafu)?;
status.update_available_updates(socket_path, update_info)
status.update_available_updates(config_path, update_info)
})
}

Expand Down Expand Up @@ -255,15 +258,18 @@ fn deactivate(status: &mut UpdateStatus) -> Result<()> {
}

/// Given the update command, this drives the update state machine.
fn drive_state_machine(
fn drive_state_machine<P>(
update_status: &mut UpdateStatus,
operation: &UpdateCommand,
socket_path: &str,
) -> Result<()> {
config_path: P,
) -> Result<()>
where
P: AsRef<Path>,
{
let new_state = match (operation, update_status.update_state()) {
(UpdateCommand::Refresh, UpdateState::Idle)
| (UpdateCommand::Refresh, UpdateState::Available) => {
if refresh(update_status, socket_path)? {
if refresh(update_status, config_path)? {
// Transitions state to `Available` if there is an available update
UpdateState::Available
} else {
Expand All @@ -273,7 +279,7 @@ fn drive_state_machine(
}
// Refreshing the list of updates is allowed under every update state
(UpdateCommand::Refresh, _) => {
refresh(update_status, socket_path)?;
refresh(update_status, config_path)?;
// No need to transition state here as we're already beyond `Available`
update_status.update_state().to_owned()
}
Expand Down Expand Up @@ -348,7 +354,7 @@ fn run() -> Result<()> {
// The commands inside drive_state_machine update the update_status object (hence &mut) to
// reflect success or failure, and we want to reflect that in our status file regardless of
// success, so we store the result rather than returning early here.
let result = drive_state_machine(&mut update_status, &args.subcommand, &args.socket_path);
let result = drive_state_machine(&mut update_status, &args.subcommand, &args.config_path);
write_update_status(&update_status)?;
result
}
Expand Down
Loading

0 comments on commit 061be84

Please sign in to comment.