Skip to content

Commit df44e69

Browse files
authored
Merge pull request #450 from kzys/log-path
Make LogPath and MetricsPath configurable
2 parents 1cad9d9 + 52c0edf commit df44e69

File tree

6 files changed

+181
-82
lines changed

6 files changed

+181
-82
lines changed

proto/firecracker.pb.go

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

proto/firecracker.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ message CreateVMRequest {
3636
JailerConfig JailerConfig = 10;
3737

3838
uint32 TimeoutSeconds = 11;
39+
40+
string LogFifoPath = 12;
41+
string MetricsFifoPath = 13;
3942
}
4043

4144
message CreateVMResponse {

runtime/runc_jailer.go

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -270,32 +270,41 @@ func (j *runcJailer) BuildJailedRootHandler(cfg *config.Config, machineConfig *f
270270
}
271271
}
272272

273+
func (j *runcJailer) makeLinkInJail(src string) (string, error) {
274+
root := j.RootPath()
275+
276+
base := filepath.Base(src)
277+
dst := filepath.Join(root, base)
278+
279+
// Since Firecracker is unaware that we are in a jailed environment and
280+
// what owner/group to set this as when creating, we will manually have
281+
// to adjust the permission bits ourselves
282+
if err := linkAndChown(src, dst, j.Config.UID, j.Config.GID); err != nil {
283+
return "", err
284+
}
285+
286+
// this path needs to be relative to the root path, and since we are
287+
// placing the file in the root path the value should just be the file name.
288+
return base, nil
289+
}
290+
273291
// BuildLinkFifoHandler will return a new firecracker.Handler with the function
274292
// that will allow linking of the fifos making them visible to Firecracker.
275293
func (j *runcJailer) BuildLinkFifoHandler() firecracker.Handler {
276294
return firecracker.Handler{
277295
Name: jailerFifoHandlerName,
278296
Fn: func(ctx context.Context, m *firecracker.Machine) error {
279-
contentsPath := j.RootPath()
280-
fifoFileName := filepath.Base(m.Cfg.LogFifo)
281-
newFifoPath := filepath.Join(contentsPath, fifoFileName)
282-
// Since Firecracker is unaware that we are in a jailed environment and
283-
// what owner/group to set this as when creating, we will manually have
284-
// to adjust the permission bits ourselves
285-
if err := linkAndChown(m.Cfg.LogFifo, newFifoPath, j.Config.UID, j.Config.GID); err != nil {
297+
logFifo, err := j.makeLinkInJail(m.Cfg.LogPath)
298+
if err != nil {
286299
return err
287300
}
288-
// this path needs to be relative to the root path, and since we are
289-
// placing the file in the root path the LogFifo value should just be the
290-
// file name.
291-
m.Cfg.LogFifo = fifoFileName
292-
293-
metricFifoFileName := filepath.Base(m.Cfg.MetricsFifo)
294-
newMetricFifoPath := filepath.Join(contentsPath, metricFifoFileName)
295-
if err := linkAndChown(m.Cfg.MetricsFifo, newMetricFifoPath, j.Config.UID, j.Config.GID); err != nil {
301+
m.Cfg.LogFifo = logFifo
302+
303+
metricsFifo, err := j.makeLinkInJail(m.Cfg.MetricsPath)
304+
if err != nil {
296305
return err
297306
}
298-
m.Cfg.MetricsFifo = metricFifoFileName
307+
m.Cfg.MetricsFifo = metricsFifo
299308

300309
return nil
301310
},

runtime/service.go

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"strconv"
2525
"strings"
2626
"sync"
27+
"syscall"
2728
"time"
2829

2930
// disable gosec check for math/rand. We just need a random starting
@@ -635,8 +636,8 @@ func (s *service) GetVMInfo(requestCtx context.Context, request *proto.GetVMInfo
635636
return &proto.GetVMInfoResponse{
636637
VMID: s.vmID,
637638
SocketPath: s.shimDir.FirecrackerSockPath(),
638-
LogFifoPath: s.machineConfig.LogFifo,
639-
MetricsFifoPath: s.machineConfig.MetricsFifo,
639+
LogFifoPath: s.machineConfig.LogPath,
640+
MetricsFifoPath: s.machineConfig.MetricsPath,
640641
CgroupPath: cgroupPath,
641642
}, nil
642643
}
@@ -736,13 +737,34 @@ func (s *service) buildVMConfiguration(req *proto.CreateVMRequest) (*firecracker
736737
Path: relVSockPath,
737738
ID: "agent_api",
738739
}},
739-
LogFifo: s.shimDir.FirecrackerLogFifoPath(),
740-
MetricsFifo: s.shimDir.FirecrackerMetricsFifoPath(),
741-
MachineCfg: machineConfigurationFromProto(s.config, req.MachineCfg),
742-
LogLevel: s.config.DebugHelper.GetFirecrackerLogLevel(),
743-
VMID: s.vmID,
740+
MachineCfg: machineConfigurationFromProto(s.config, req.MachineCfg),
741+
LogLevel: s.config.DebugHelper.GetFirecrackerLogLevel(),
742+
VMID: s.vmID,
744743
}
745744

745+
logPath := s.shimDir.FirecrackerLogFifoPath()
746+
if req.LogFifoPath != "" {
747+
logPath = req.LogFifoPath
748+
}
749+
err = syscall.Mkfifo(logPath, 0700)
750+
if err != nil {
751+
return nil, err
752+
}
753+
754+
metricsPath := s.shimDir.FirecrackerMetricsFifoPath()
755+
if req.MetricsFifoPath != "" {
756+
metricsPath = req.MetricsFifoPath
757+
}
758+
err = syscall.Mkfifo(metricsPath, 0700)
759+
if err != nil {
760+
return nil, err
761+
}
762+
763+
// The Config struct has LogFifo and MetricsFifo, but they will be deprecated since
764+
// Firecracker doesn't have the corresponding fields anymore.
765+
cfg.LogPath = logPath
766+
cfg.MetricsPath = metricsPath
767+
746768
if req.JailerConfig != nil {
747769
cfg.NetNS = req.JailerConfig.NetNS
748770
}

runtime/service_integ_test.go

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package main
1515

1616
import (
17+
"bufio"
1718
"bytes"
1819
"context"
1920
"fmt"
@@ -1870,6 +1871,23 @@ loop:
18701871
require.Equal(t, expected, actual)
18711872
}
18721873

1874+
func requireNonEmptyFifo(t testing.TB, path string) {
1875+
file, err := os.Open(path)
1876+
require.NoError(t, err)
1877+
defer file.Close()
1878+
1879+
reader := bufio.NewReader(file)
1880+
1881+
// Since this is a FIFO, reading till EOF would block if its writer-end is still open.
1882+
line, err := reader.ReadString('\n')
1883+
require.NoError(t, err)
1884+
require.NotEqualf(t, "", line, "%s must not be empty", path)
1885+
1886+
info, err := os.Stat(path)
1887+
require.NoError(t, err)
1888+
require.Equal(t, os.ModeNamedPipe, info.Mode()&os.ModeType, "%s is a FIFO file", path)
1889+
}
1890+
18731891
func TestCreateVM_Isolated(t *testing.T) {
18741892
prepareIntegTest(t)
18751893

@@ -1923,25 +1941,55 @@ func TestCreateVM_Isolated(t *testing.T) {
19231941
},
19241942
}
19251943

1944+
runTest := func(t *testing.T, request proto.CreateVMRequest, validate func(t *testing.T, err error)) {
1945+
vmID := testNameToVMID(t.Name())
1946+
1947+
tempDir, err := ioutil.TempDir("", vmID)
1948+
require.NoError(t, err)
1949+
defer os.RemoveAll(tempDir)
1950+
1951+
logFile := filepath.Join(tempDir, "log.fifo")
1952+
metricsFile := filepath.Join(tempDir, "metrics.fifo")
1953+
1954+
request.VMID = vmID
1955+
request.LogFifoPath = logFile
1956+
request.MetricsFifoPath = metricsFile
1957+
1958+
resp, createVMErr := fcClient.CreateVM(ctx, &request)
1959+
1960+
// Even CreateVM fails, the log file and the metrics file must have some data.
1961+
requireNonEmptyFifo(t, logFile)
1962+
requireNonEmptyFifo(t, metricsFile)
1963+
1964+
// Some test cases are expected to have an error, some are not.
1965+
validate(t, createVMErr)
1966+
1967+
// No VM to stop.
1968+
if createVMErr != nil {
1969+
return
1970+
}
1971+
1972+
// Ensure the response fields are populated correctly
1973+
assert.Equal(t, request.VMID, resp.VMID)
1974+
1975+
_, err = fcClient.StopVM(ctx, &proto.StopVMRequest{VMID: request.VMID})
1976+
require.Equal(t, status.Code(err), codes.OK)
1977+
}
1978+
19261979
for _, subtest := range subtests {
19271980
request := subtest.request
19281981
validate := subtest.validate
1929-
19301982
t.Run(subtest.name, func(t *testing.T) {
1931-
request.VMID = testNameToVMID(t.Name())
1932-
1933-
resp, err := fcClient.CreateVM(ctx, &request)
1934-
validate(t, err)
1935-
if err != nil {
1936-
// No VM to stop.
1937-
return
1938-
}
1939-
1940-
// Ensure the response fields are populated correctly
1941-
assert.Equal(t, request.VMID, resp.VMID)
1983+
runTest(t, request, validate)
1984+
})
19421985

1943-
_, err = fcClient.StopVM(ctx, &proto.StopVMRequest{VMID: request.VMID})
1944-
require.Equal(t, status.Code(err), codes.OK)
1986+
requestWithJailer := subtest.request
1987+
requestWithJailer.JailerConfig = &proto.JailerConfig{
1988+
UID: 30000,
1989+
GID: 30000,
1990+
}
1991+
t.Run(subtest.name+" with Jailer", func(t *testing.T) {
1992+
runTest(t, requestWithJailer, validate)
19451993
})
19461994
}
19471995
}

runtime/service_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,8 @@ func TestBuildVMConfiguration(t *testing.T) {
253253
Path: relVSockPath,
254254
ID: "agent_api",
255255
}}
256-
tc.expectedCfg.LogFifo = svc.shimDir.FirecrackerLogFifoPath()
257-
tc.expectedCfg.MetricsFifo = svc.shimDir.FirecrackerMetricsFifoPath()
256+
tc.expectedCfg.LogPath = svc.shimDir.FirecrackerLogFifoPath()
257+
tc.expectedCfg.MetricsPath = svc.shimDir.FirecrackerMetricsFifoPath()
258258

259259
drives := make([]models.Drive, tc.expectedStubDriveCount)
260260
for i := 0; i < tc.expectedStubDriveCount; i++ {

0 commit comments

Comments
 (0)