Skip to content

Commit f5579da

Browse files
committed
apiserver: add network configure endpoint
Adds POST /actions/network/configure endpoint to write network configuration content directly to /.bottlerocket/net.toml. Includes error handling for UTF-8 validation, directory creation, and file writing operations. Signed-off-by: Yutong Sun <yutongsu@amazon.com>
1 parent 956895e commit f5579da

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

sources/api/apiserver/src/server/error.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,27 @@ pub enum Error {
203203

204204
// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^=
205205

206+
// Network configuration errors
207+
#[snafu(display("Network configuration content is not valid UTF-8"))]
208+
NetworkConfigContent { source: std::string::FromUtf8Error },
209+
210+
#[snafu(display("Failed to create network configuration directory '{}'", path.display()))]
211+
NetworkConfigDir {
212+
path: std::path::PathBuf,
213+
source: std::io::Error,
214+
},
215+
216+
#[snafu(display("Network configuration directory '{}' does not exist. This directory should be managed by the system", path.display()))]
217+
NetworkConfigDirMissing { path: std::path::PathBuf },
218+
219+
#[snafu(display("Failed to write network configuration to '{}'", path.display()))]
220+
NetworkConfigWrite {
221+
path: std::path::PathBuf,
222+
source: std::io::Error,
223+
},
224+
225+
// =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^= =^..^=
226+
206227
// Update related errors
207228
#[snafu(display("Unable to start the update dispatcher: {} ", source))]
208229
UpdateDispatcher { source: io::Error },

sources/api/apiserver/src/server/mod.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use actix_web::{
1414
use datastore::{serialize_scalar, Committed, FilesystemDataStore, Key, KeyType, Value};
1515
use error::Result;
1616
use http::StatusCode;
17-
use log::info;
17+
use log::{debug, info};
1818
use model::ephemeral_storage::{Bind, Init};
1919
use model::generator::{RawSettingsGenerator, Strength};
2020
use model::{ConfigurationFiles, Model, Report, Services, Settings};
@@ -136,6 +136,7 @@ where
136136
.route("/prepare-update", web::post().to(prepare_update))
137137
.route("/activate-update", web::post().to(activate_update))
138138
.route("/deactivate-update", web::post().to(deactivate_update))
139+
.route("/network/configure", web::post().to(configure_network))
139140
.route(
140141
"/ephemeral-storage/init",
141142
web::post().to(initialize_ephemeral_storage),
@@ -651,6 +652,31 @@ async fn reboot() -> Result<HttpResponse> {
651652
Ok(HttpResponse::NoContent().finish())
652653
}
653654

655+
/// Configures network settings by writing content to /.bottlerocket/net.toml.
656+
/// The configuration will be applied at next boot - a reboot is required for changes to take effect.
657+
async fn configure_network(body: web::Bytes) -> Result<HttpResponse> {
658+
debug!("Configuring network settings");
659+
660+
// Convert the body bytes to a UTF-8 string
661+
let content = String::from_utf8(body.to_vec()).context(error::NetworkConfigContentSnafu)?;
662+
663+
let config_dir = Path::new("/.bottlerocket");
664+
let config_file = config_dir.join("net.toml");
665+
666+
// Ensure the directory exists. The target directory (/.bottlerocket) is managed by the system,
667+
// we should throw error immediately if that does not exist.
668+
ensure!(
669+
config_dir.exists(),
670+
error::NetworkConfigDirMissingSnafu { path: config_dir }
671+
);
672+
673+
// Write the configuration content to the file
674+
std::fs::write(&config_file, content)
675+
.context(error::NetworkConfigWriteSnafu { path: &config_file })?;
676+
677+
Ok(HttpResponse::NoContent().finish())
678+
}
679+
654680
/// Gets the set of report types supported by this host.
655681
async fn list_reports() -> Result<ReportListResponse> {
656682
// Add each report to list response when adding a new handler
@@ -908,6 +934,7 @@ impl ResponseError for error::Error {
908934
InvalidPrefix { .. } => StatusCode::BAD_REQUEST,
909935
DeserializeJson { .. } => StatusCode::BAD_REQUEST,
910936
InvalidKeyPair { .. } => StatusCode::BAD_REQUEST,
937+
NetworkConfigContent { .. } => StatusCode::BAD_REQUEST,
911938

912939
// 404 Not Found
913940
MissingData { .. } => StatusCode::NOT_FOUND,
@@ -962,6 +989,9 @@ impl ResponseError for error::Error {
962989
ReportExec { .. } => StatusCode::INTERNAL_SERVER_ERROR,
963990
ReportResult { .. } => StatusCode::INTERNAL_SERVER_ERROR,
964991
DeserializeSettingsGenerator { .. } => StatusCode::INTERNAL_SERVER_ERROR,
992+
NetworkConfigDir { .. } => StatusCode::INTERNAL_SERVER_ERROR,
993+
NetworkConfigDirMissing { .. } => StatusCode::INTERNAL_SERVER_ERROR,
994+
NetworkConfigWrite { .. } => StatusCode::INTERNAL_SERVER_ERROR,
965995
DeserializeStrength { .. } => StatusCode::BAD_REQUEST,
966996
InvalidStrength { .. } => StatusCode::BAD_REQUEST,
967997
DisallowStrongToWeakStrength { .. } => StatusCode::BAD_REQUEST,

sources/api/openapi.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,30 @@ paths:
712712
423:
713713
description: "Update write lock held. Try again in a moment"
714714

715+
/actions/network/configure:
716+
post:
717+
summary: "Configure network settings from net.toml content"
718+
operationId: "configure_network"
719+
requestBody:
720+
required: true
721+
content:
722+
text/plain:
723+
schema:
724+
type: string
725+
example: |
726+
version = 2
727+
728+
[eth0]
729+
dhcp4 = true
730+
primary = true
731+
responses:
732+
204:
733+
description: "Network configuration successfully written"
734+
400:
735+
description: "Invalid UTF-8 content or malformed configuration"
736+
500:
737+
description: "Server error writing configuration"
738+
715739
/updates/status:
716740
get:
717741
summary: "Get update status"

0 commit comments

Comments
 (0)