Skip to content

Commit cff4136

Browse files
committed
implemented vm
1 parent ec02fac commit cff4136

File tree

6 files changed

+299
-164
lines changed

6 files changed

+299
-164
lines changed

disk.go

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
package vz
22

33
import (
4-
"fmt"
54
"os"
65
)
76

87
// CreateDiskImage is creating disk image with specified filename and filesize.
98
// For example, if you want to create disk with 64GiB, you can set "64 * 1024 * 1024 * 1024" to size.
10-
func CreateDiskImage(name string, size int64) error {
11-
f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE, 0600)
9+
//
10+
// Note that if you have specified a pathname which already exists, this function
11+
// returns os.ErrExist error. So you can handle it with os.IsExist function.
12+
func CreateDiskImage(pathname string, size int64) error {
13+
f, err := os.OpenFile(pathname, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
1214
if err != nil {
13-
return fmt.Errorf("failed to create disk image: %w", err)
15+
return err
1416
}
1517
defer f.Close()
1618

1719
if err := f.Truncate(size); err != nil {
18-
return fmt.Errorf("failed to truncate: %w", err)
20+
return err
1921
}
2022
return nil
2123
}

example/macOS/installer.go

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
"github.com/Code-Hex/vz/v2"
9+
)
10+
11+
func installMacOS(ctx context.Context) error {
12+
restoreImagePath := GetRestoreImagePath()
13+
restoreImage, err := vz.LoadMacOSRestoreImageFromPath(restoreImagePath)
14+
if err != nil {
15+
return fmt.Errorf("failed to load restore image: %w", err)
16+
}
17+
configurationRequirements := restoreImage.MostFeaturefulSupportedConfiguration()
18+
config, err := setupVirtualMachineWithMacOSConfigurationRequirements(
19+
configurationRequirements,
20+
)
21+
if err != nil {
22+
return fmt.Errorf("failed to setup config: %w", err)
23+
}
24+
vm := vz.NewVirtualMachine(config)
25+
26+
installer := vz.NewMacOSInstaller(vm, restoreImagePath)
27+
28+
ctx, cancel := context.WithCancel(ctx)
29+
defer cancel()
30+
31+
go func() {
32+
ticker := time.NewTicker(500 * time.Millisecond)
33+
defer ticker.Stop()
34+
for {
35+
select {
36+
case <-ctx.Done():
37+
fmt.Println("install has been cancelled")
38+
return
39+
case <-installer.Done():
40+
fmt.Println("install has been completed")
41+
return
42+
case <-ticker.C:
43+
fmt.Printf("install: %d\r", int(installer.FractionCompleted()*100))
44+
}
45+
}
46+
}()
47+
48+
return installer.Install(ctx)
49+
}
50+
51+
func setupVirtualMachineWithMacOSConfigurationRequirements(macOSConfiguration *vz.MacOSConfigurationRequirements) (*vz.VirtualMachineConfiguration, error) {
52+
platformConfig, err := createMacInstallerPlatformConfiguration(macOSConfiguration)
53+
if err != nil {
54+
return nil, fmt.Errorf("failed to create mac platform config: %w", err)
55+
}
56+
return setupVMConfiguration(platformConfig)
57+
}
58+
59+
func createMacInstallerPlatformConfiguration(macOSConfiguration *vz.MacOSConfigurationRequirements) (*vz.MacPlatformConfiguration, error) {
60+
hardwareModel := macOSConfiguration.HardwareModel()
61+
if err := CreateFileAndWriteTo(
62+
hardwareModel.DataRepresentation(),
63+
GetHardwareModelPath(),
64+
); err != nil {
65+
return nil, fmt.Errorf("failed to write hardware model data: %w", err)
66+
}
67+
68+
machineIdentifier := vz.NewMacMachineIdentifier()
69+
if err := CreateFileAndWriteTo(
70+
machineIdentifier.DataRepresentation(),
71+
GetMachineIdentifierPath(),
72+
); err != nil {
73+
return nil, fmt.Errorf("failed to write machine identifier data: %w", err)
74+
}
75+
76+
auxiliaryStorage, err := vz.NewMacAuxiliaryStorage(
77+
GetAuxiliaryStoragePath(),
78+
vz.WithCreatingStorage(hardwareModel),
79+
)
80+
if err != nil {
81+
return nil, fmt.Errorf("failed to create a new mac auxiliary storage: %w", err)
82+
}
83+
return vz.NewMacPlatformConfiguration(
84+
vz.WithAuxiliaryStorage(auxiliaryStorage),
85+
vz.WithHardwareModel(hardwareModel),
86+
vz.WithMachineIdentifier(machineIdentifier),
87+
), nil
88+
}

example/macOS/main.go

+110-108
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ package main
33
import (
44
"context"
55
"fmt"
6+
"log"
67
"os"
8+
"os/signal"
79
"runtime"
10+
"syscall"
811
"time"
912

1013
"github.com/Code-Hex/vz/v2"
@@ -35,95 +38,55 @@ func main() {
3538
}
3639

3740
func run(ctx context.Context) error {
38-
defer time.Sleep(time.Second)
39-
return installMacOS(ctx)
40-
}
41-
42-
func installMacOS(ctx context.Context) error {
43-
restoreImagePath := GetRestoreImagePath()
44-
restoreImage, err := vz.LoadMacOSRestoreImageFromPath(restoreImagePath)
45-
if err != nil {
46-
return fmt.Errorf("failed to load restore image: %w", err)
47-
}
48-
configurationRequirements := restoreImage.MostFeaturefulSupportedConfiguration()
49-
config, err := setupVirtualMachineWithMacOSConfigurationRequirements(
50-
configurationRequirements,
51-
)
52-
if err != nil {
53-
return fmt.Errorf("failed to setup config: %w", err)
41+
if false {
42+
defer time.Sleep(time.Second)
43+
return installMacOS(ctx)
5444
}
55-
vm := vz.NewVirtualMachine(config)
56-
57-
installer := vz.NewMacOSInstaller(vm, restoreImagePath)
58-
59-
ctx, cancel := context.WithCancel(ctx)
60-
defer cancel()
61-
62-
go func() {
63-
ticker := time.NewTicker(500 * time.Millisecond)
64-
defer ticker.Stop()
65-
for {
66-
select {
67-
case <-ctx.Done():
68-
fmt.Println("install has been cancelled")
69-
return
70-
case <-installer.Done():
71-
fmt.Println("install has been completed")
72-
return
73-
case <-ticker.C:
74-
fmt.Printf("install: %d\r", int(installer.FractionCompleted()*100))
75-
}
76-
}
77-
}()
78-
79-
return installer.Install(ctx)
45+
return runVM(ctx)
8046
}
8147

82-
func setupVirtualMachineWithMacOSConfigurationRequirements(macOSConfiguration *vz.MacOSConfigurationRequirements) (*vz.VirtualMachineConfiguration, error) {
83-
config := vz.NewVirtualMachineConfiguration(
84-
vz.NewMacOSBootLoader(),
85-
computeCPUCount(),
86-
computeMemorySize(),
87-
)
88-
platformConfig, err := createMacPlatformConfiguration(macOSConfiguration)
48+
func runVM(ctx context.Context) error {
49+
platformConfig, err := createMacPlatformConfiguration()
8950
if err != nil {
90-
return nil, fmt.Errorf("failed to create mac platform config: %w", err)
51+
return err
9152
}
92-
config.SetPlatformVirtualMachineConfiguration(platformConfig)
93-
config.SetGraphicsDevicesVirtualMachineConfiguration([]vz.GraphicsDeviceConfiguration{
94-
createGraphicsDeviceConfiguration(),
95-
})
96-
blockDeviceConfig, err := createBlockDeviceConfiguration(GetDiskImagePath())
53+
config, err := setupVMConfiguration(platformConfig)
9754
if err != nil {
98-
return nil, fmt.Errorf("failed to create block device configuration: %w", err)
55+
return err
9956
}
100-
config.SetStorageDevicesVirtualMachineConfiguration([]vz.StorageDeviceConfiguration{blockDeviceConfig})
101-
102-
config.SetNetworkDevicesVirtualMachineConfiguration([]*vz.VirtioNetworkDeviceConfiguration{
103-
createNetworkDeviceConfiguration(),
104-
})
57+
vm := vz.NewVirtualMachine(config)
10558

106-
config.SetPointingDevicesVirtualMachineConfiguration([]vz.PointingDeviceConfiguration{
107-
createPointingDeviceConfiguration(),
108-
})
59+
signalCh := make(chan os.Signal, 1)
60+
signal.Notify(signalCh, syscall.SIGTERM)
10961

110-
config.SetKeyboardsVirtualMachineConfiguration([]vz.KeyboardConfiguration{
111-
createKeyboardConfiguration(),
112-
})
62+
errCh := make(chan error, 1)
11363

114-
config.SetAudioDevicesVirtualMachineConfiguration([]vz.AudioDeviceConfiguration{
115-
createAudioDeviceConfiguration(),
64+
vm.Start(func(err error) {
65+
if err != nil {
66+
errCh <- err
67+
}
11668
})
11769

118-
validated, err := config.Validate()
119-
if err != nil {
120-
return nil, fmt.Errorf("failed to validate configuration: %w", err)
121-
}
122-
if !validated {
123-
return nil, fmt.Errorf("invalid configuration")
70+
for {
71+
select {
72+
case <-signalCh:
73+
result, err := vm.RequestStop()
74+
if err != nil {
75+
return err
76+
}
77+
log.Println("recieved signal", result)
78+
case newState := <-vm.StateChangedNotify():
79+
if newState == vz.VirtualMachineStateRunning {
80+
log.Println("start VM is running")
81+
}
82+
if newState == vz.VirtualMachineStateStopped {
83+
log.Println("stopped successfully")
84+
return nil
85+
}
86+
case err := <-errCh:
87+
return fmt.Errorf("failed to start vm: %w", err)
88+
}
12489
}
125-
126-
return config, nil
12790
}
12891

12992
func computeCPUCount() uint {
@@ -161,8 +124,11 @@ func computeMemorySize() uint64 {
161124
func createBlockDeviceConfiguration(diskPath string) (*vz.VirtioBlockDeviceConfiguration, error) {
162125
// create disk image with 64 GiB
163126
if err := vz.CreateDiskImage(diskPath, 64*1024*1024*1024); err != nil {
164-
return nil, fmt.Errorf("failed to create disk image: %w", err)
127+
if !os.IsExist(err) {
128+
return nil, fmt.Errorf("failed to create disk image: %w", err)
129+
}
165130
}
131+
166132
diskImageAttachment, err := vz.NewDiskImageStorageDeviceAttachment(
167133
diskPath,
168134
false,
@@ -174,37 +140,6 @@ func createBlockDeviceConfiguration(diskPath string) (*vz.VirtioBlockDeviceConfi
174140
return storageDeviceConfig, nil
175141
}
176142

177-
func createMacPlatformConfiguration(macOSConfiguration *vz.MacOSConfigurationRequirements) (*vz.MacPlatformConfiguration, error) {
178-
hardwareModel := macOSConfiguration.HardwareModel()
179-
if err := CreateFileAndWriteTo(
180-
hardwareModel.DataRepresentation(),
181-
GetHardwareModelPath(),
182-
); err != nil {
183-
return nil, fmt.Errorf("failed to write hardware model data: %w", err)
184-
}
185-
186-
machineIdentifier := vz.NewMacMachineIdentifier()
187-
if err := CreateFileAndWriteTo(
188-
machineIdentifier.DataRepresentation(),
189-
GetMachineIdentifierPath(),
190-
); err != nil {
191-
return nil, fmt.Errorf("failed to write machine identifier data: %w", err)
192-
}
193-
194-
auxiliaryStorage, err := vz.NewMacAuxiliaryStorage(
195-
GetAuxiliaryStoragePath(),
196-
vz.WithCreating(hardwareModel),
197-
)
198-
if err != nil {
199-
return nil, fmt.Errorf("failed to create a new mac auxiliary storage: %w", err)
200-
}
201-
return vz.NewMacPlatformConfiguration(
202-
vz.WithAuxiliaryStorage(auxiliaryStorage),
203-
vz.WithHardwareModel(hardwareModel),
204-
vz.WithMachineIdentifier(machineIdentifier),
205-
), nil
206-
}
207-
208143
func createGraphicsDeviceConfiguration() *vz.MacGraphicsDeviceConfiguration {
209144
graphicDeviceConfig := vz.NewMacGraphicsDeviceConfiguration()
210145
graphicDeviceConfig.SetDisplays(
@@ -237,3 +172,70 @@ func createAudioDeviceConfiguration() *vz.VirtioSoundDeviceConfiguration {
237172
)
238173
return audioConfig
239174
}
175+
176+
func createMacPlatformConfiguration() (*vz.MacPlatformConfiguration, error) {
177+
auxiliaryStorage, err := vz.NewMacAuxiliaryStorage(GetAuxiliaryStoragePath())
178+
if err != nil {
179+
return nil, fmt.Errorf("failed to create a new mac auxiliary storage: %w", err)
180+
}
181+
hardwareModel, err := vz.NewMacHardwareModelWithDataPath(
182+
GetHardwareModelPath(),
183+
)
184+
if err != nil {
185+
return nil, fmt.Errorf("failed to create a new hardware model: %w", err)
186+
}
187+
machineIdentifier, err := vz.NewMacMachineIdentifierWithDataPath(
188+
GetMachineIdentifierPath(),
189+
)
190+
if err != nil {
191+
return nil, fmt.Errorf("failed to create a new machine identifier: %w", err)
192+
}
193+
return vz.NewMacPlatformConfiguration(
194+
vz.WithAuxiliaryStorage(auxiliaryStorage),
195+
vz.WithHardwareModel(hardwareModel),
196+
vz.WithMachineIdentifier(machineIdentifier),
197+
), nil
198+
}
199+
200+
func setupVMConfiguration(platformConfig vz.PlatformConfiguration) (*vz.VirtualMachineConfiguration, error) {
201+
config := vz.NewVirtualMachineConfiguration(
202+
vz.NewMacOSBootLoader(),
203+
computeCPUCount(),
204+
computeMemorySize(),
205+
)
206+
config.SetPlatformVirtualMachineConfiguration(platformConfig)
207+
config.SetGraphicsDevicesVirtualMachineConfiguration([]vz.GraphicsDeviceConfiguration{
208+
createGraphicsDeviceConfiguration(),
209+
})
210+
blockDeviceConfig, err := createBlockDeviceConfiguration(GetDiskImagePath())
211+
if err != nil {
212+
return nil, fmt.Errorf("failed to create block device configuration: %w", err)
213+
}
214+
config.SetStorageDevicesVirtualMachineConfiguration([]vz.StorageDeviceConfiguration{blockDeviceConfig})
215+
216+
config.SetNetworkDevicesVirtualMachineConfiguration([]*vz.VirtioNetworkDeviceConfiguration{
217+
createNetworkDeviceConfiguration(),
218+
})
219+
220+
config.SetPointingDevicesVirtualMachineConfiguration([]vz.PointingDeviceConfiguration{
221+
createPointingDeviceConfiguration(),
222+
})
223+
224+
config.SetKeyboardsVirtualMachineConfiguration([]vz.KeyboardConfiguration{
225+
createKeyboardConfiguration(),
226+
})
227+
228+
config.SetAudioDevicesVirtualMachineConfiguration([]vz.AudioDeviceConfiguration{
229+
createAudioDeviceConfiguration(),
230+
})
231+
232+
validated, err := config.Validate()
233+
if err != nil {
234+
return nil, fmt.Errorf("failed to validate configuration: %w", err)
235+
}
236+
if !validated {
237+
return nil, fmt.Errorf("invalid configuration")
238+
}
239+
240+
return config, nil
241+
}

0 commit comments

Comments
 (0)