@@ -14,7 +14,7 @@ use actix_web::{
1414use datastore:: { serialize_scalar, Committed , FilesystemDataStore , Key , KeyType , Value } ;
1515use error:: Result ;
1616use http:: StatusCode ;
17- use log:: info;
17+ use log:: { debug , info} ;
1818use model:: ephemeral_storage:: { Bind , Init } ;
1919use model:: generator:: { RawSettingsGenerator , Strength } ;
2020use 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.
655681async 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 ,
0 commit comments