194 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			194 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Go
		
	
	
	
| package computestorage
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"syscall"
 | |
| 
 | |
| 	"github.com/Microsoft/go-winio/pkg/security"
 | |
| 	"github.com/Microsoft/go-winio/vhd"
 | |
| 	"github.com/pkg/errors"
 | |
| 	"golang.org/x/sys/windows"
 | |
| )
 | |
| 
 | |
| const defaultVHDXBlockSizeInMB = 1
 | |
| 
 | |
| // SetupContainerBaseLayer is a helper to setup a containers scratch. It
 | |
| // will create and format the vhdx's inside and the size is configurable with the sizeInGB
 | |
| // parameter.
 | |
| //
 | |
| // `layerPath` is the path to the base container layer on disk.
 | |
| //
 | |
| // `baseVhdPath` is the path to where the base vhdx for the base layer should be created.
 | |
| //
 | |
| // `diffVhdPath` is the path where the differencing disk for the base layer should be created.
 | |
| //
 | |
| // `sizeInGB` is the size in gigabytes to make the base vhdx.
 | |
| func SetupContainerBaseLayer(ctx context.Context, layerPath, baseVhdPath, diffVhdPath string, sizeInGB uint64) (err error) {
 | |
| 	var (
 | |
| 		hivesPath  = filepath.Join(layerPath, "Hives")
 | |
| 		layoutPath = filepath.Join(layerPath, "Layout")
 | |
| 	)
 | |
| 
 | |
| 	// We need to remove the hives directory and layout file as `SetupBaseOSLayer` fails if these files
 | |
| 	// already exist. `SetupBaseOSLayer` will create these files internally. We also remove the base and
 | |
| 	// differencing disks if they exist in case we're asking for a different size.
 | |
| 	if _, err := os.Stat(hivesPath); err == nil {
 | |
| 		if err := os.RemoveAll(hivesPath); err != nil {
 | |
| 			return errors.Wrap(err, "failed to remove prexisting hives directory")
 | |
| 		}
 | |
| 	}
 | |
| 	if _, err := os.Stat(layoutPath); err == nil {
 | |
| 		if err := os.RemoveAll(layoutPath); err != nil {
 | |
| 			return errors.Wrap(err, "failed to remove prexisting layout file")
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if _, err := os.Stat(baseVhdPath); err == nil {
 | |
| 		if err := os.RemoveAll(baseVhdPath); err != nil {
 | |
| 			return errors.Wrap(err, "failed to remove base vhdx path")
 | |
| 		}
 | |
| 	}
 | |
| 	if _, err := os.Stat(diffVhdPath); err == nil {
 | |
| 		if err := os.RemoveAll(diffVhdPath); err != nil {
 | |
| 			return errors.Wrap(err, "failed to remove differencing vhdx")
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	createParams := &vhd.CreateVirtualDiskParameters{
 | |
| 		Version: 2,
 | |
| 		Version2: vhd.CreateVersion2{
 | |
| 			MaximumSize:      sizeInGB * 1024 * 1024 * 1024,
 | |
| 			BlockSizeInBytes: defaultVHDXBlockSizeInMB * 1024 * 1024,
 | |
| 		},
 | |
| 	}
 | |
| 	handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
 | |
| 	if err != nil {
 | |
| 		return errors.Wrap(err, "failed to create vhdx")
 | |
| 	}
 | |
| 
 | |
| 	defer func() {
 | |
| 		if err != nil {
 | |
| 			_ = syscall.CloseHandle(handle)
 | |
| 			os.RemoveAll(baseVhdPath)
 | |
| 			os.RemoveAll(diffVhdPath)
 | |
| 		}
 | |
| 	}()
 | |
| 
 | |
| 	if err = FormatWritableLayerVhd(ctx, windows.Handle(handle)); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	// Base vhd handle must be closed before calling SetupBaseLayer in case of Container layer
 | |
| 	if err = syscall.CloseHandle(handle); err != nil {
 | |
| 		return errors.Wrap(err, "failed to close vhdx handle")
 | |
| 	}
 | |
| 
 | |
| 	options := OsLayerOptions{
 | |
| 		Type: OsLayerTypeContainer,
 | |
| 	}
 | |
| 
 | |
| 	// SetupBaseOSLayer expects an empty vhd handle for a container layer and will
 | |
| 	// error out otherwise.
 | |
| 	if err = SetupBaseOSLayer(ctx, layerPath, 0, options); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	// Create the differencing disk that will be what's copied for the final rw layer
 | |
| 	// for a container.
 | |
| 	if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
 | |
| 		return errors.Wrap(err, "failed to create differencing disk")
 | |
| 	}
 | |
| 
 | |
| 	if err = security.GrantVmGroupAccess(baseVhdPath); err != nil {
 | |
| 		return errors.Wrapf(err, "failed to grant vm group access to %s", baseVhdPath)
 | |
| 	}
 | |
| 	if err = security.GrantVmGroupAccess(diffVhdPath); err != nil {
 | |
| 		return errors.Wrapf(err, "failed to grant vm group access to %s", diffVhdPath)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // SetupUtilityVMBaseLayer is a helper to setup a UVMs scratch space. It will create and format
 | |
| // the vhdx inside and the size is configurable by the sizeInGB parameter.
 | |
| //
 | |
| // `uvmPath` is the path to the UtilityVM filesystem.
 | |
| //
 | |
| // `baseVhdPath` is the path to where the base vhdx for the UVM should be created.
 | |
| //
 | |
| // `diffVhdPath` is the path where the differencing disk for the UVM should be created.
 | |
| //
 | |
| // `sizeInGB` specifies the size in gigabytes to make the base vhdx.
 | |
| func SetupUtilityVMBaseLayer(ctx context.Context, uvmPath, baseVhdPath, diffVhdPath string, sizeInGB uint64) (err error) {
 | |
| 	// Remove the base and differencing disks if they exist in case we're asking for a different size.
 | |
| 	if _, err := os.Stat(baseVhdPath); err == nil {
 | |
| 		if err := os.RemoveAll(baseVhdPath); err != nil {
 | |
| 			return errors.Wrap(err, "failed to remove base vhdx")
 | |
| 		}
 | |
| 	}
 | |
| 	if _, err := os.Stat(diffVhdPath); err == nil {
 | |
| 		if err := os.RemoveAll(diffVhdPath); err != nil {
 | |
| 			return errors.Wrap(err, "failed to remove differencing vhdx")
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Just create the vhdx for utilityVM layer, no need to format it.
 | |
| 	createParams := &vhd.CreateVirtualDiskParameters{
 | |
| 		Version: 2,
 | |
| 		Version2: vhd.CreateVersion2{
 | |
| 			MaximumSize:      sizeInGB * 1024 * 1024 * 1024,
 | |
| 			BlockSizeInBytes: defaultVHDXBlockSizeInMB * 1024 * 1024,
 | |
| 		},
 | |
| 	}
 | |
| 	handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
 | |
| 	if err != nil {
 | |
| 		return errors.Wrap(err, "failed to create vhdx")
 | |
| 	}
 | |
| 
 | |
| 	defer func() {
 | |
| 		if err != nil {
 | |
| 			_ = syscall.CloseHandle(handle)
 | |
| 			os.RemoveAll(baseVhdPath)
 | |
| 			os.RemoveAll(diffVhdPath)
 | |
| 		}
 | |
| 	}()
 | |
| 
 | |
| 	// If it is a UtilityVM layer then the base vhdx must be attached when calling
 | |
| 	// `SetupBaseOSLayer`
 | |
| 	attachParams := &vhd.AttachVirtualDiskParameters{
 | |
| 		Version: 2,
 | |
| 	}
 | |
| 	if err := vhd.AttachVirtualDisk(handle, vhd.AttachVirtualDiskFlagNone, attachParams); err != nil {
 | |
| 		return errors.Wrapf(err, "failed to attach virtual disk")
 | |
| 	}
 | |
| 
 | |
| 	options := OsLayerOptions{
 | |
| 		Type: OsLayerTypeVM,
 | |
| 	}
 | |
| 	if err := SetupBaseOSLayer(ctx, uvmPath, windows.Handle(handle), options); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// Detach and close the handle after setting up the layer as we don't need the handle
 | |
| 	// for anything else and we no longer need to be attached either.
 | |
| 	if err = vhd.DetachVirtualDisk(handle); err != nil {
 | |
| 		return errors.Wrap(err, "failed to detach vhdx")
 | |
| 	}
 | |
| 	if err = syscall.CloseHandle(handle); err != nil {
 | |
| 		return errors.Wrap(err, "failed to close vhdx handle")
 | |
| 	}
 | |
| 
 | |
| 	// Create the differencing disk that will be what's copied for the final rw layer
 | |
| 	// for a container.
 | |
| 	if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
 | |
| 		return errors.Wrap(err, "failed to create differencing disk")
 | |
| 	}
 | |
| 
 | |
| 	if err := security.GrantVmGroupAccess(baseVhdPath); err != nil {
 | |
| 		return errors.Wrapf(err, "failed to grant vm group access to %s", baseVhdPath)
 | |
| 	}
 | |
| 	if err := security.GrantVmGroupAccess(diffVhdPath); err != nil {
 | |
| 		return errors.Wrapf(err, "failed to grant vm group access to %s", diffVhdPath)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 |