Skip to content

Commit 7ee43cc

Browse files
ManciukicJonathan Woollett-Light
andcommitted
fix: Support creating file with open_file_nonblock
Updates the `OpenOptions` with `.create(true)` to support creating a file when if it doesn't exist. This also brings the functionality inline with the documentation which notes `Create and opens a File for writing to it.`. This improves usability simplifying setting up the logger. Co-authored-by: Jonathan Woollett-Light <jcawl@amazon.co.uk> Signed-off-by: Jonathan Woollett-Light <jcawl@amazon.co.uk> Signed-off-by: Riccardo Mancini <mancio@amazon.com>
1 parent 203091e commit 7ee43cc

File tree

7 files changed

+24
-63
lines changed

7 files changed

+24
-63
lines changed

docs/getting-started.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,6 @@ sudo iptables -t nat -A POSTROUTING -o "$HOST_IFACE" -j MASQUERADE
239239
API_SOCKET="/tmp/firecracker.socket"
240240
LOGFILE="./firecracker.log"
241241

242-
# Create log file
243-
touch $LOGFILE
244-
245242
# Set log file
246243
sudo curl -X PUT --unix-socket "${API_SOCKET}" \
247244
--data "{

src/vmm/src/device_manager/mod.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
use std::convert::Infallible;
99
use std::fmt::Debug;
10-
use std::os::unix::prelude::OpenOptionsExt;
1110
use std::path::PathBuf;
1211
use std::sync::{Arc, Mutex};
1312

@@ -36,6 +35,7 @@ use crate::devices::virtio::device::VirtioDevice;
3635
use crate::devices::virtio::transport::mmio::{IrqTrigger, MmioTransport};
3736
use crate::resources::VmResources;
3837
use crate::snapshot::Persist;
38+
use crate::utils::open_file_write_nonblock;
3939
use crate::vstate::bus::BusError;
4040
use crate::vstate::memory::GuestMemoryMmap;
4141
use crate::{EmulateSerialInitError, EventManager, Vm};
@@ -127,14 +127,7 @@ impl DeviceManager {
127127
output: Option<&PathBuf>,
128128
) -> Result<Arc<Mutex<SerialDevice>>, std::io::Error> {
129129
let (serial_in, serial_out) = match output {
130-
Some(ref path) => (
131-
None,
132-
std::fs::OpenOptions::new()
133-
.custom_flags(libc::O_NONBLOCK)
134-
.write(true)
135-
.open(path)
136-
.map(SerialOut::File)?,
137-
),
130+
Some(path) => (None, open_file_write_nonblock(path).map(SerialOut::File)?),
138131
None => {
139132
Self::set_stdout_nonblocking();
140133

src/vmm/src/logger/logging.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
use std::fmt::Debug;
55
use std::io::Write;
6-
use std::os::unix::fs::OpenOptionsExt;
76
use std::path::PathBuf;
87
use std::str::FromStr;
98
use std::sync::{Mutex, OnceLock};
@@ -14,6 +13,7 @@ use serde::{Deserialize, Deserializer, Serialize};
1413
use utils::time::LocalTime;
1514

1615
use super::metrics::{IncMetric, METRICS};
16+
use crate::utils::open_file_write_nonblock;
1717

1818
/// Default level filter for logger matching the swagger specification
1919
/// (`src/firecracker/swagger/firecracker.yaml`).
@@ -62,11 +62,7 @@ impl Logger {
6262
);
6363

6464
if let Some(log_path) = config.log_path {
65-
let file = std::fs::OpenOptions::new()
66-
.custom_flags(libc::O_NONBLOCK)
67-
.write(true)
68-
.open(log_path)
69-
.map_err(LoggerUpdateError)?;
65+
let file = open_file_write_nonblock(&log_path).map_err(LoggerUpdateError)?;
7066

7167
guard.target = Some(file);
7268
};

src/vmm/src/utils/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@ pub mod signal;
1010
/// Module with state machine
1111
pub mod sm;
1212

13+
use std::fs::{File, OpenOptions};
1314
use std::num::Wrapping;
15+
use std::os::unix::fs::OpenOptionsExt;
16+
use std::path::Path;
17+
use std::result::Result;
18+
19+
use libc::O_NONBLOCK;
1420

1521
/// How many bits to left-shift by to convert MiB to bytes
1622
const MIB_TO_BYTES_SHIFT: usize = 20;
@@ -64,3 +70,15 @@ pub const fn align_down(addr: u64, align: u64) -> u64 {
6470
debug_assert!(align != 0);
6571
addr & !(align - 1)
6672
}
73+
74+
/// Create and open a File for writing to it.
75+
/// In case we open a FIFO, in order to not block the instance if nobody is consuming the message
76+
/// that is flushed to it, we are opening it with `O_NONBLOCK` flag.
77+
/// In this case, writing to a pipe will start failing when reaching 64K of unconsumed content.
78+
pub fn open_file_write_nonblock(path: &Path) -> Result<File, std::io::Error> {
79+
OpenOptions::new()
80+
.custom_flags(O_NONBLOCK)
81+
.create(true)
82+
.write(true)
83+
.open(path)
84+
}

src/vmm/src/vmm_config/metrics.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use std::path::PathBuf;
66

77
use serde::{Deserialize, Serialize};
88

9-
use super::open_file_nonblock;
109
use crate::logger::{FcLineWriter, METRICS};
10+
use crate::utils::open_file_write_nonblock;
1111

1212
/// Strongly typed structure used to describe the metrics system.
1313
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
@@ -26,7 +26,7 @@ pub enum MetricsConfigError {
2626
/// Configures the metrics as described in `metrics_cfg`.
2727
pub fn init_metrics(metrics_cfg: MetricsConfig) -> Result<(), MetricsConfigError> {
2828
let writer = FcLineWriter::new(
29-
open_file_nonblock(&metrics_cfg.metrics_path)
29+
open_file_write_nonblock(&metrics_cfg.metrics_path)
3030
.map_err(|err| MetricsConfigError::InitializationFailure(err.to_string()))?,
3131
);
3232
METRICS
@@ -42,12 +42,6 @@ mod tests {
4242

4343
#[test]
4444
fn test_init_metrics() {
45-
// Error case: initializing metrics with invalid pipe returns error.
46-
let desc = MetricsConfig {
47-
metrics_path: PathBuf::from("not_found_file_metrics"),
48-
};
49-
init_metrics(desc).unwrap_err();
50-
5145
// Initializing metrics with valid pipe is ok.
5246
let metrics_file = TempFile::new().unwrap();
5347
let desc = MetricsConfig {

src/vmm/src/vmm_config/mod.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,8 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
use std::convert::{From, TryInto};
5-
use std::fs::{File, OpenOptions};
65
use std::io;
7-
use std::os::unix::fs::OpenOptionsExt;
8-
use std::path::Path;
96

10-
use libc::O_NONBLOCK;
117
use serde::{Deserialize, Serialize};
128

139
use crate::rate_limiter::{BucketUpdate, RateLimiter, TokenBucket};
@@ -167,18 +163,6 @@ impl RateLimiterConfig {
167163
}
168164
}
169165

170-
/// Create and opens a File for writing to it.
171-
/// In case we open a FIFO, in order to not block the instance if nobody is consuming the message
172-
/// that is flushed to the two pipes, we are opening it with `O_NONBLOCK` flag.
173-
/// In this case, writing to a pipe will start failing when reaching 64K of unconsumed content.
174-
fn open_file_nonblock(path: &Path) -> Result<File, std::io::Error> {
175-
OpenOptions::new()
176-
.custom_flags(O_NONBLOCK)
177-
.read(true)
178-
.write(true)
179-
.open(path)
180-
}
181-
182166
#[cfg(test)]
183167
mod tests {
184168
use super::*;

tests/integration_tests/functional/test_logging.py

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -71,27 +71,6 @@ def check_log_message_format(log_str, instance_id, level, show_level, show_origi
7171
assert tag_level_no <= configured_level_no
7272

7373

74-
def test_log_config_failure(uvm_plain):
75-
"""
76-
Check passing invalid FIFOs is detected and reported as an error.
77-
"""
78-
microvm = uvm_plain
79-
microvm.spawn(log_file=None)
80-
microvm.basic_config()
81-
82-
# only works if log level is Debug
83-
microvm.time_api_requests = False
84-
85-
expected_msg = re.escape("No such file or directory (os error 2)")
86-
with pytest.raises(RuntimeError, match=expected_msg):
87-
microvm.api.logger.put(
88-
log_path="invalid log file",
89-
level="Info",
90-
show_level=True,
91-
show_log_origin=True,
92-
)
93-
94-
9574
def test_api_requests_logs(uvm_plain):
9675
"""
9776
Test that API requests are logged.

0 commit comments

Comments
 (0)