Skip to content

Commit d1db6a2

Browse files
committed
ignition: Start the http server directly over vsock
Currently, the ignition http server listens on a unix socket. The network traffic is then tunneled over vsock. However, as the http server runs in the vfkit process, we can directly create a vsock listener to communicate with the VM. This should be more efficient as this removes the tcpproxy layer, and more importantly, this removes the creation of the on-disk unix socket, which had a hardcoded name. Signed-off-by: Christophe Fergeau <[email protected]>
1 parent fb45cbc commit d1db6a2

File tree

5 files changed

+32
-32
lines changed

5 files changed

+32
-32
lines changed

cmd/vfkit/main.go

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -197,13 +197,7 @@ func runVFKit(vmConfig *config.VirtualMachine, opts *cmdline.Options) error {
197197
func runVirtualMachine(vmConfig *config.VirtualMachine, vm *vf.VirtualMachine) error {
198198
if vm.Config().Ignition != nil {
199199
go func() {
200-
file, err := os.Open(vmConfig.Ignition.ConfigPath)
201-
if err != nil {
202-
log.Error(err)
203-
}
204-
defer file.Close()
205-
reader := file
206-
if err := startIgnitionProvisionerServer(reader, vmConfig.Ignition.SocketPath); err != nil {
200+
if err := startIgnitionProvisionerServer(vm, vmConfig.Ignition.ConfigPath, vmConfig.Ignition.VsockPort); err != nil {
207201
log.Error(err)
208202
}
209203
log.Debug("ignition vsock server exited")
@@ -224,7 +218,7 @@ func runVirtualMachine(vmConfig *config.VirtualMachine, vm *vf.VirtualMachine) e
224218
port := vsock.Port
225219
socketURL := vsock.SocketURL
226220
if socketURL == "" {
227-
// the timesync code adds a vsock device without an associated URL.
221+
// timesync and ignition add a vsock device without an associated URL.
228222
continue
229223
}
230224
var listenStr string
@@ -277,22 +271,22 @@ func runVirtualMachine(vmConfig *config.VirtualMachine, vm *vf.VirtualMachine) e
277271
return <-errCh
278272
}
279273

280-
func startIgnitionProvisionerServer(ignitionPath string, ignitionSocketPath string) error {
281-
ignitionReader, err := os.Open(ignitionPath)
274+
func startIgnitionProvisionerServer(vm *vf.VirtualMachine, configPath string, vsockPort uint32) error {
275+
ignitionReader, err := os.Open(configPath)
282276
if err != nil {
283277
return err
284278
}
285279
defer ignitionReader.Close()
286280

287-
listener, err := net.Listen("unix", ignitionSocketPath)
281+
vsockDevices := vm.SocketDevices()
282+
if len(vsockDevices) != 1 {
283+
return fmt.Errorf("VM has too many/not enough virtio-vsock devices (%d)", len(vsockDevices))
284+
}
285+
listener, err := vsockDevices[0].Listen(vsockPort)
288286
if err != nil {
289287
return err
290288
}
291289

292-
util.RegisterExitHandler(func() {
293-
os.Remove(ignitionSocketPath)
294-
})
295-
296290
defer func() {
297291
if err := listener.Close(); err != nil {
298292
log.Error(err)

pkg/config/config.go

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"math"
1717
"os"
1818
"os/exec"
19-
"path/filepath"
2019
"strconv"
2120
"strings"
2221

@@ -43,7 +42,8 @@ type TimeSync struct {
4342

4443
type Ignition struct {
4544
ConfigPath string `json:"configPath"`
46-
SocketPath string `json:"socketPath"`
45+
SocketPath string `json:"socketPath,omitempty"`
46+
VsockPort uint32 `json:"-"`
4747
}
4848

4949
// The VMComponent interface represents a VM element (device, bootloader, ...)
@@ -54,8 +54,9 @@ type VMComponent interface {
5454
}
5555

5656
const (
57-
ignitionVsockPort uint = 1024
58-
ignitionSocketName string = "ignition.sock"
57+
// the ignition vsock port is hardcoded to 1024 in ignition source code:
58+
// https://github.com/coreos/ignition/blob/d4ff84b2c28a28ad828b974befe3575563faacdd/internal/providers/applehv/applehv.go#L59-L68
59+
ignitionVsockPort uint32 = 1024
5960
)
6061

6162
// NewVirtualMachine creates a new VirtualMachine instance. The virtual machine
@@ -222,13 +223,13 @@ func (vm *VirtualMachine) TimeSync() *TimeSync {
222223
return vm.Timesync
223224
}
224225

225-
func IgnitionNew(configPath string, socketPath string) (*Ignition, error) {
226-
if configPath == "" || socketPath == "" {
226+
func IgnitionNew(configPath string, _ string) (*Ignition, error) {
227+
if configPath == "" {
227228
return nil, fmt.Errorf("config path and socket path cannot be empty")
228229
}
229230
return &Ignition{
230231
ConfigPath: configPath,
231-
SocketPath: socketPath,
232+
VsockPort: ignitionVsockPort,
232233
}, nil
233234
}
234235

@@ -241,13 +242,7 @@ func (vm *VirtualMachine) AddIgnitionFileFromCmdLine(cmdlineOpts string) error {
241242
return fmt.Errorf("ignition only accepts one option in command line argument")
242243
}
243244

244-
socketPath := filepath.Join(os.TempDir(), ignitionSocketName)
245-
dev, err := VirtioVsockNew(ignitionVsockPort, socketPath, true)
246-
if err != nil {
247-
return err
248-
}
249-
vm.Devices = append(vm.Devices, dev)
250-
ignition, err := IgnitionNew(opts[0], socketPath)
245+
ignition, err := IgnitionNew(opts[0], "")
251246
if err != nil {
252247
return err
253248
}

pkg/config/config_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ func TestAddIgnitionFile_OneOption(t *testing.T) {
2020
vm := &VirtualMachine{}
2121
err := vm.AddIgnitionFileFromCmdLine("file1")
2222
require.NoError(t, err)
23-
assert.Len(t, vm.Devices, 1)
24-
assert.Equal(t, uint32(ignitionVsockPort), vm.Devices[0].(*VirtioVsock).Port)
2523
assert.Equal(t, "file1", vm.Ignition.ConfigPath)
24+
assert.Equal(t, ignitionVsockPort, vm.Ignition.VsockPort)
2625
}
2726

2827
func TestNetworkBlockDevice(t *testing.T) {

pkg/config/json_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,10 @@ var jsonTests = map[string]jsonTest{
9191
ignition, err := IgnitionNew("config", "socket")
9292
require.NoError(t, err)
9393
vm.Ignition = ignition
94+
ignition.VsockPort = 0 // slight hack for the test to pass as VsockPort is not serialized
9495
return vm
9596
},
96-
expectedJSON: `{"vcpus":3,"memoryBytes":4194304000,"bootloader":{"kind":"linuxBootloader","vmlinuzPath":"/vmlinuz","initrdPath":"/initrd","kernelCmdLine":"console=hvc0"}, "ignition":{"kind":"ignition","configPath":"config","socketPath":"socket"}}`,
97+
expectedJSON: `{"vcpus":3,"memoryBytes":4194304000,"bootloader":{"kind":"linuxBootloader","vmlinuzPath":"/vmlinuz","initrdPath":"/initrd","kernelCmdLine":"console=hvc0"}, "ignition":{"kind":"ignition","configPath":"config"}}`,
9798
},
9899
"TestVirtioRNG": {
99100
newVM: func(t *testing.T) *VirtualMachine {

pkg/vf/vm.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,17 @@ func (cfg *VirtualMachineConfiguration) toVz() (*vz.VirtualMachineConfiguration,
148148
}
149149
}
150150

151+
if cfg.config.Ignition != nil && cfg.config.Ignition.VsockPort != 0 {
152+
// automatically add the vsock device we'll need for communication over VsockPort
153+
vsockDev := VirtioVsock{
154+
Port: cfg.config.Ignition.VsockPort,
155+
Listen: false,
156+
}
157+
if err := vsockDev.AddToVirtualMachineConfig(cfg); err != nil {
158+
return nil, err
159+
}
160+
}
161+
151162
cfg.SetStorageDevicesVirtualMachineConfiguration(cfg.storageDevicesConfiguration)
152163
cfg.SetDirectorySharingDevicesVirtualMachineConfiguration(cfg.directorySharingDevicesConfiguration)
153164
cfg.SetPointingDevicesVirtualMachineConfiguration(cfg.pointingDevicesConfiguration)

0 commit comments

Comments
 (0)