mirror of
https://github.com/rancher/plugins.git
synced 2025-07-09 05:04:51 +00:00
187 lines
5.9 KiB
Go
187 lines
5.9 KiB
Go
package uvm
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/Microsoft/hcsshim/internal/guid"
|
|
"github.com/Microsoft/hcsshim/internal/hcs"
|
|
"github.com/Microsoft/hcsshim/internal/mergemaps"
|
|
"github.com/Microsoft/hcsshim/internal/schema2"
|
|
"github.com/Microsoft/hcsshim/internal/schemaversion"
|
|
"github.com/Microsoft/hcsshim/internal/uvmfolder"
|
|
"github.com/Microsoft/hcsshim/internal/wcow"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// OptionsWCOW are the set of options passed to CreateWCOW() to create a utility vm.
|
|
type OptionsWCOW struct {
|
|
*Options
|
|
|
|
LayerFolders []string // Set of folders for base layers and scratch. Ordered from top most read-only through base read-only layer, followed by scratch
|
|
}
|
|
|
|
// NewDefaultOptionsWCOW creates the default options for a bootable version of
|
|
// WCOW. The caller `MUST` set the `LayerFolders` path on the returned value.
|
|
//
|
|
// `id` the ID of the compute system. If not passed will generate a new GUID.
|
|
//
|
|
// `owner` the owner of the compute system. If not passed will use the
|
|
// executable files name.
|
|
func NewDefaultOptionsWCOW(id, owner string) *OptionsWCOW {
|
|
opts := &OptionsWCOW{
|
|
Options: &Options{
|
|
ID: id,
|
|
Owner: owner,
|
|
MemorySizeInMB: 1024,
|
|
AllowOvercommit: true,
|
|
EnableDeferredCommit: false,
|
|
ProcessorCount: defaultProcessorCount(),
|
|
},
|
|
}
|
|
|
|
if opts.ID == "" {
|
|
opts.ID = guid.New().String()
|
|
}
|
|
if opts.Owner == "" {
|
|
opts.Owner = filepath.Base(os.Args[0])
|
|
}
|
|
|
|
return opts
|
|
}
|
|
|
|
// CreateWCOW creates an HCS compute system representing a utility VM.
|
|
//
|
|
// WCOW Notes:
|
|
// - The scratch is always attached to SCSI 0:0
|
|
//
|
|
func CreateWCOW(opts *OptionsWCOW) (_ *UtilityVM, err error) {
|
|
logrus.Debugf("uvm::CreateWCOW %+v", opts)
|
|
|
|
if opts.Options == nil {
|
|
opts.Options = &Options{}
|
|
}
|
|
|
|
uvm := &UtilityVM{
|
|
id: opts.ID,
|
|
owner: opts.Owner,
|
|
operatingSystem: "windows",
|
|
scsiControllerCount: 1,
|
|
vsmbShares: make(map[string]*vsmbShare),
|
|
}
|
|
|
|
if len(opts.LayerFolders) < 2 {
|
|
return nil, fmt.Errorf("at least 2 LayerFolders must be supplied")
|
|
}
|
|
uvmFolder, err := uvmfolder.LocateUVMFolder(opts.LayerFolders)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to locate utility VM folder from layer folders: %s", err)
|
|
}
|
|
|
|
// TODO: BUGBUG Remove this. @jhowardmsft
|
|
// It should be the responsiblity of the caller to do the creation and population.
|
|
// - Update runhcs too (vm.go).
|
|
// - Remove comment in function header
|
|
// - Update tests that rely on this current behaviour.
|
|
// Create the RW scratch in the top-most layer folder, creating the folder if it doesn't already exist.
|
|
scratchFolder := opts.LayerFolders[len(opts.LayerFolders)-1]
|
|
logrus.Debugf("uvm::CreateWCOW scratch folder: %s", scratchFolder)
|
|
|
|
// Create the directory if it doesn't exist
|
|
if _, err := os.Stat(scratchFolder); os.IsNotExist(err) {
|
|
logrus.Debugf("uvm::CreateWCOW creating folder: %s ", scratchFolder)
|
|
if err := os.MkdirAll(scratchFolder, 0777); err != nil {
|
|
return nil, fmt.Errorf("failed to create utility VM scratch folder: %s", err)
|
|
}
|
|
}
|
|
|
|
// Create sandbox.vhdx in the scratch folder based on the template, granting the correct permissions to it
|
|
scratchPath := filepath.Join(scratchFolder, "sandbox.vhdx")
|
|
if _, err := os.Stat(scratchPath); os.IsNotExist(err) {
|
|
if err := wcow.CreateUVMScratch(uvmFolder, scratchFolder, uvm.id); err != nil {
|
|
return nil, fmt.Errorf("failed to create scratch: %s", err)
|
|
}
|
|
}
|
|
|
|
doc := &hcsschema.ComputeSystem{
|
|
Owner: uvm.owner,
|
|
SchemaVersion: schemaversion.SchemaV21(),
|
|
ShouldTerminateOnLastHandleClosed: true,
|
|
VirtualMachine: &hcsschema.VirtualMachine{
|
|
StopOnReset: true,
|
|
Chipset: &hcsschema.Chipset{
|
|
Uefi: &hcsschema.Uefi{
|
|
BootThis: &hcsschema.UefiBootEntry{
|
|
DevicePath: `\EFI\Microsoft\Boot\bootmgfw.efi`,
|
|
DeviceType: "VmbFs",
|
|
},
|
|
},
|
|
},
|
|
ComputeTopology: &hcsschema.Topology{
|
|
Memory: &hcsschema.Memory2{
|
|
SizeInMB: opts.MemorySizeInMB,
|
|
AllowOvercommit: opts.AllowOvercommit,
|
|
// EnableHotHint is not compatible with physical.
|
|
EnableHotHint: opts.AllowOvercommit,
|
|
EnableDeferredCommit: opts.EnableDeferredCommit,
|
|
},
|
|
Processor: &hcsschema.Processor2{
|
|
Count: defaultProcessorCount(),
|
|
},
|
|
},
|
|
GuestConnection: &hcsschema.GuestConnection{},
|
|
Devices: &hcsschema.Devices{
|
|
Scsi: map[string]hcsschema.Scsi{
|
|
"0": {
|
|
Attachments: map[string]hcsschema.Attachment{
|
|
"0": {
|
|
Path: scratchPath,
|
|
Type_: "VirtualDisk",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
HvSocket: &hcsschema.HvSocket2{
|
|
HvSocketConfig: &hcsschema.HvSocketSystemConfig{
|
|
// Allow administrators and SYSTEM to bind to vsock sockets
|
|
// so that we can create a GCS log socket.
|
|
DefaultBindSecurityDescriptor: "D:P(A;;FA;;;SY)(A;;FA;;;BA)",
|
|
},
|
|
},
|
|
VirtualSmb: &hcsschema.VirtualSmb{
|
|
DirectFileMappingInMB: 1024, // Sensible default, but could be a tuning parameter somewhere
|
|
Shares: []hcsschema.VirtualSmbShare{
|
|
{
|
|
Name: "os",
|
|
Path: filepath.Join(uvmFolder, `UtilityVM\Files`),
|
|
Options: &hcsschema.VirtualSmbShareOptions{
|
|
ReadOnly: true,
|
|
PseudoOplocks: true,
|
|
TakeBackupPrivilege: true,
|
|
CacheIo: true,
|
|
ShareRead: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
uvm.scsiLocations[0][0].hostPath = doc.VirtualMachine.Devices.Scsi["0"].Attachments["0"].Path
|
|
|
|
fullDoc, err := mergemaps.MergeJSON(doc, ([]byte)(opts.AdditionHCSDocumentJSON))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to merge additional JSON '%s': %s", opts.AdditionHCSDocumentJSON, err)
|
|
}
|
|
|
|
hcsSystem, err := hcs.CreateComputeSystem(uvm.id, fullDoc)
|
|
if err != nil {
|
|
logrus.Debugln("failed to create UVM: ", err)
|
|
return nil, err
|
|
}
|
|
uvm.hcsSystem = hcsSystem
|
|
return uvm, nil
|
|
}
|