podman

Форк
0
214 строк · 5.3 Кб
1
package config
2

3
import (
4
	"fmt"
5
	"os"
6
	"os/exec"
7
	"strconv"
8
	"strings"
9
)
10

11
// VirtualMachine is the top-level type. It describes the virtual machine
12
// configuration (bootloader, devices, ...).
13
type VirtualMachine struct {
14
	Vcpus       uint           `json:"vcpus"`
15
	MemoryBytes uint64         `json:"memoryBytes"`
16
	Bootloader  Bootloader     `json:"bootloader"`
17
	Devices     []VirtioDevice `json:"devices,omitempty"`
18
	Timesync    *TimeSync      `json:"timesync,omitempty"`
19
}
20

21
// TimeSync enables synchronization of the host time to the linux guest after the host was suspended.
22
// This requires qemu-guest-agent to be running in the guest, and to be listening on a vsock socket
23
type TimeSync struct {
24
	VsockPort uint
25
}
26

27
// The VMComponent interface represents a VM element (device, bootloader, ...)
28
// which can be converted from/to commandline parameters
29
type VMComponent interface {
30
	FromOptions([]option) error
31
	ToCmdLine() ([]string, error)
32
}
33

34
// NewVirtualMachine creates a new VirtualMachine instance. The virtual machine
35
// will use vcpus virtual CPUs and it will be allocated memoryBytes bytes of
36
// RAM. bootloader specifies which kernel/initrd/kernel args it will be using.
37
func NewVirtualMachine(vcpus uint, memoryBytes uint64, bootloader Bootloader) *VirtualMachine {
38
	return &VirtualMachine{
39
		Vcpus:       vcpus,
40
		MemoryBytes: memoryBytes,
41
		Bootloader:  bootloader,
42
	}
43
}
44

45
// ToCmdLine generates a list of arguments for use with the [os/exec] package.
46
// These arguments will start a virtual machine with the devices/bootloader/...
47
// described by vm If the virtual machine configuration described by vm is
48
// invalid, an error will be returned.
49
func (vm *VirtualMachine) ToCmdLine() ([]string, error) {
50
	// TODO: missing binary name/path
51
	args := []string{}
52

53
	if vm.Vcpus != 0 {
54
		args = append(args, "--cpus", strconv.FormatUint(uint64(vm.Vcpus), 10))
55
	}
56
	if vm.MemoryBytes != 0 {
57
		args = append(args, "--memory", strconv.FormatUint(vm.MemoryBytes, 10))
58
	}
59

60
	if vm.Bootloader == nil {
61
		return nil, fmt.Errorf("missing bootloader configuration")
62
	}
63
	bootloaderArgs, err := vm.Bootloader.ToCmdLine()
64
	if err != nil {
65
		return nil, err
66
	}
67
	args = append(args, bootloaderArgs...)
68

69
	for _, dev := range vm.Devices {
70
		devArgs, err := dev.ToCmdLine()
71
		if err != nil {
72
			return nil, err
73
		}
74
		args = append(args, devArgs...)
75
	}
76

77
	return args, nil
78
}
79

80
func (vm *VirtualMachine) extraFiles() []*os.File {
81
	extraFiles := []*os.File{}
82
	for _, dev := range vm.Devices {
83
		virtioNet, ok := dev.(*VirtioNet)
84
		if !ok {
85
			continue
86
		}
87
		if virtioNet.Socket != nil {
88
			extraFiles = append(extraFiles, virtioNet.Socket)
89
		}
90
	}
91

92
	return extraFiles
93
}
94

95
// Cmd creates an exec.Cmd to start vfkit with the configured devices.
96
// In particular it will set ExtraFiles appropriately when mapping
97
// a file with a network interface.
98
func (vm *VirtualMachine) Cmd(vfkitPath string) (*exec.Cmd, error) {
99
	args, err := vm.ToCmdLine()
100
	if err != nil {
101
		return nil, err
102
	}
103

104
	cmd := exec.Command(vfkitPath, args...)
105
	cmd.ExtraFiles = vm.extraFiles()
106

107
	return cmd, nil
108
}
109

110
func (vm *VirtualMachine) AddDevicesFromCmdLine(cmdlineOpts []string) error {
111
	for _, deviceOpts := range cmdlineOpts {
112
		dev, err := deviceFromCmdLine(deviceOpts)
113
		if err != nil {
114
			return err
115
		}
116
		vm.Devices = append(vm.Devices, dev)
117
	}
118
	return nil
119
}
120

121
func (vm *VirtualMachine) VirtioGPUDevices() []*VirtioGPU {
122
	gpuDevs := []*VirtioGPU{}
123
	for _, dev := range vm.Devices {
124
		if gpuDev, isVirtioGPU := dev.(*VirtioGPU); isVirtioGPU {
125
			gpuDevs = append(gpuDevs, gpuDev)
126
		}
127
	}
128

129
	return gpuDevs
130
}
131

132
func (vm *VirtualMachine) VirtioVsockDevices() []*VirtioVsock {
133
	vsockDevs := []*VirtioVsock{}
134
	for _, dev := range vm.Devices {
135
		if vsockDev, isVirtioVsock := dev.(*VirtioVsock); isVirtioVsock {
136
			vsockDevs = append(vsockDevs, vsockDev)
137
		}
138
	}
139

140
	return vsockDevs
141
}
142

143
// AddDevice adds a dev to vm. This device can be created with one of the
144
// VirtioXXXNew methods.
145
func (vm *VirtualMachine) AddDevice(dev VirtioDevice) error {
146
	vm.Devices = append(vm.Devices, dev)
147

148
	return nil
149
}
150

151
func (vm *VirtualMachine) AddTimeSyncFromCmdLine(cmdlineOpts string) error {
152
	if cmdlineOpts == "" {
153
		return nil
154
	}
155
	timesync, err := timesyncFromCmdLine(cmdlineOpts)
156
	if err != nil {
157
		return err
158
	}
159
	vm.Timesync = timesync
160

161
	return nil
162
}
163

164
func (vm *VirtualMachine) TimeSync() *TimeSync {
165
	return vm.Timesync
166
}
167

168
func TimeSyncNew(vsockPort uint) (VMComponent, error) {
169
	return &TimeSync{
170
		VsockPort: vsockPort,
171
	}, nil
172
}
173

174
func (ts *TimeSync) ToCmdLine() ([]string, error) {
175
	args := []string{}
176
	if ts.VsockPort != 0 {
177
		args = append(args, fmt.Sprintf("vsockPort=%d", ts.VsockPort))
178
	}
179
	return []string{"--timesync", strings.Join(args, ",")}, nil
180
}
181

182
func (ts *TimeSync) FromOptions(options []option) error {
183
	for _, option := range options {
184
		switch option.key {
185
		case "vsockPort":
186
			vsockPort, err := strconv.ParseUint(option.value, 10, 64)
187
			if err != nil {
188
				return err
189
			}
190
			ts.VsockPort = uint(vsockPort)
191
		default:
192
			return fmt.Errorf("unknown option for timesync parameter: %s", option.key)
193
		}
194
	}
195

196
	if ts.VsockPort == 0 {
197
		return fmt.Errorf("missing 'vsockPort' option for timesync parameter")
198
	}
199

200
	return nil
201
}
202

203
func timesyncFromCmdLine(optsStr string) (*TimeSync, error) {
204
	var timesync TimeSync
205

206
	optsStrv := strings.Split(optsStr, ",")
207
	options := strvToOptions(optsStrv)
208

209
	if err := timesync.FromOptions(options); err != nil {
210
		return nil, err
211
	}
212

213
	return &timesync, nil
214
}
215

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.