...

Source file src/github.com/Microsoft/hcsshim/computestorage/helpers.go

Documentation: github.com/Microsoft/hcsshim/computestorage

     1  //go:build windows
     2  
     3  package computestorage
     4  
     5  import (
     6  	"context"
     7  	"os"
     8  	"path/filepath"
     9  	"syscall"
    10  
    11  	"github.com/Microsoft/go-winio/vhd"
    12  	"github.com/Microsoft/hcsshim/internal/memory"
    13  	"github.com/pkg/errors"
    14  	"golang.org/x/sys/windows"
    15  
    16  	"github.com/Microsoft/hcsshim/internal/security"
    17  )
    18  
    19  const defaultVHDXBlockSizeInMB = 1
    20  
    21  // SetupContainerBaseLayer is a helper to setup a containers scratch. It
    22  // will create and format the vhdx's inside and the size is configurable with the sizeInGB
    23  // parameter.
    24  //
    25  // `layerPath` is the path to the base container layer on disk.
    26  //
    27  // `baseVhdPath` is the path to where the base vhdx for the base layer should be created.
    28  //
    29  // `diffVhdPath` is the path where the differencing disk for the base layer should be created.
    30  //
    31  // `sizeInGB` is the size in gigabytes to make the base vhdx.
    32  func SetupContainerBaseLayer(ctx context.Context, layerPath, baseVhdPath, diffVhdPath string, sizeInGB uint64) (err error) {
    33  	var (
    34  		hivesPath  = filepath.Join(layerPath, "Hives")
    35  		layoutPath = filepath.Join(layerPath, "Layout")
    36  	)
    37  
    38  	// We need to remove the hives directory and layout file as `SetupBaseOSLayer` fails if these files
    39  	// already exist. `SetupBaseOSLayer` will create these files internally. We also remove the base and
    40  	// differencing disks if they exist in case we're asking for a different size.
    41  	if _, err := os.Stat(hivesPath); err == nil {
    42  		if err := os.RemoveAll(hivesPath); err != nil {
    43  			return errors.Wrap(err, "failed to remove prexisting hives directory")
    44  		}
    45  	}
    46  	if _, err := os.Stat(layoutPath); err == nil {
    47  		if err := os.RemoveAll(layoutPath); err != nil {
    48  			return errors.Wrap(err, "failed to remove prexisting layout file")
    49  		}
    50  	}
    51  
    52  	if _, err := os.Stat(baseVhdPath); err == nil {
    53  		if err := os.RemoveAll(baseVhdPath); err != nil {
    54  			return errors.Wrap(err, "failed to remove base vhdx path")
    55  		}
    56  	}
    57  	if _, err := os.Stat(diffVhdPath); err == nil {
    58  		if err := os.RemoveAll(diffVhdPath); err != nil {
    59  			return errors.Wrap(err, "failed to remove differencing vhdx")
    60  		}
    61  	}
    62  
    63  	createParams := &vhd.CreateVirtualDiskParameters{
    64  		Version: 2,
    65  		Version2: vhd.CreateVersion2{
    66  			MaximumSize:      sizeInGB * memory.GiB,
    67  			BlockSizeInBytes: defaultVHDXBlockSizeInMB * memory.MiB,
    68  		},
    69  	}
    70  	handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
    71  	if err != nil {
    72  		return errors.Wrap(err, "failed to create vhdx")
    73  	}
    74  
    75  	defer func() {
    76  		if err != nil {
    77  			_ = syscall.CloseHandle(handle)
    78  			os.RemoveAll(baseVhdPath)
    79  			os.RemoveAll(diffVhdPath)
    80  		}
    81  	}()
    82  
    83  	if err = FormatWritableLayerVhd(ctx, windows.Handle(handle)); err != nil {
    84  		return err
    85  	}
    86  	// Base vhd handle must be closed before calling SetupBaseLayer in case of Container layer
    87  	if err = syscall.CloseHandle(handle); err != nil {
    88  		return errors.Wrap(err, "failed to close vhdx handle")
    89  	}
    90  
    91  	options := OsLayerOptions{
    92  		Type: OsLayerTypeContainer,
    93  	}
    94  
    95  	// SetupBaseOSLayer expects an empty vhd handle for a container layer and will
    96  	// error out otherwise.
    97  	if err = SetupBaseOSLayer(ctx, layerPath, 0, options); err != nil {
    98  		return err
    99  	}
   100  	// Create the differencing disk that will be what's copied for the final rw layer
   101  	// for a container.
   102  	if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
   103  		return errors.Wrap(err, "failed to create differencing disk")
   104  	}
   105  
   106  	if err = security.GrantVmGroupAccess(baseVhdPath); err != nil {
   107  		return errors.Wrapf(err, "failed to grant vm group access to %s", baseVhdPath)
   108  	}
   109  	if err = security.GrantVmGroupAccess(diffVhdPath); err != nil {
   110  		return errors.Wrapf(err, "failed to grant vm group access to %s", diffVhdPath)
   111  	}
   112  	return nil
   113  }
   114  
   115  // SetupUtilityVMBaseLayer is a helper to setup a UVMs scratch space. It will create and format
   116  // the vhdx inside and the size is configurable by the sizeInGB parameter.
   117  //
   118  // `uvmPath` is the path to the UtilityVM filesystem.
   119  //
   120  // `baseVhdPath` is the path to where the base vhdx for the UVM should be created.
   121  //
   122  // `diffVhdPath` is the path where the differencing disk for the UVM should be created.
   123  //
   124  // `sizeInGB` specifies the size in gigabytes to make the base vhdx.
   125  func SetupUtilityVMBaseLayer(ctx context.Context, uvmPath, baseVhdPath, diffVhdPath string, sizeInGB uint64) (err error) {
   126  	// Remove the base and differencing disks if they exist in case we're asking for a different size.
   127  	if _, err := os.Stat(baseVhdPath); err == nil {
   128  		if err := os.RemoveAll(baseVhdPath); err != nil {
   129  			return errors.Wrap(err, "failed to remove base vhdx")
   130  		}
   131  	}
   132  	if _, err := os.Stat(diffVhdPath); err == nil {
   133  		if err := os.RemoveAll(diffVhdPath); err != nil {
   134  			return errors.Wrap(err, "failed to remove differencing vhdx")
   135  		}
   136  	}
   137  
   138  	// Just create the vhdx for utilityVM layer, no need to format it.
   139  	createParams := &vhd.CreateVirtualDiskParameters{
   140  		Version: 2,
   141  		Version2: vhd.CreateVersion2{
   142  			MaximumSize:      sizeInGB * memory.GiB,
   143  			BlockSizeInBytes: defaultVHDXBlockSizeInMB * memory.MiB,
   144  		},
   145  	}
   146  	handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
   147  	if err != nil {
   148  		return errors.Wrap(err, "failed to create vhdx")
   149  	}
   150  
   151  	defer func() {
   152  		if err != nil {
   153  			_ = syscall.CloseHandle(handle)
   154  			os.RemoveAll(baseVhdPath)
   155  			os.RemoveAll(diffVhdPath)
   156  		}
   157  	}()
   158  
   159  	// If it is a UtilityVM layer then the base vhdx must be attached when calling
   160  	// `SetupBaseOSLayer`
   161  	attachParams := &vhd.AttachVirtualDiskParameters{
   162  		Version: 2,
   163  	}
   164  	if err := vhd.AttachVirtualDisk(handle, vhd.AttachVirtualDiskFlagNone, attachParams); err != nil {
   165  		return errors.Wrapf(err, "failed to attach virtual disk")
   166  	}
   167  
   168  	options := OsLayerOptions{
   169  		Type: OsLayerTypeVM,
   170  	}
   171  	if err := SetupBaseOSLayer(ctx, uvmPath, windows.Handle(handle), options); err != nil {
   172  		return err
   173  	}
   174  
   175  	// Detach and close the handle after setting up the layer as we don't need the handle
   176  	// for anything else and we no longer need to be attached either.
   177  	if err = vhd.DetachVirtualDisk(handle); err != nil {
   178  		return errors.Wrap(err, "failed to detach vhdx")
   179  	}
   180  	if err = syscall.CloseHandle(handle); err != nil {
   181  		return errors.Wrap(err, "failed to close vhdx handle")
   182  	}
   183  
   184  	// Create the differencing disk that will be what's copied for the final rw layer
   185  	// for a container.
   186  	if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
   187  		return errors.Wrap(err, "failed to create differencing disk")
   188  	}
   189  
   190  	if err := security.GrantVmGroupAccess(baseVhdPath); err != nil {
   191  		return errors.Wrapf(err, "failed to grant vm group access to %s", baseVhdPath)
   192  	}
   193  	if err := security.GrantVmGroupAccess(diffVhdPath); err != nil {
   194  		return errors.Wrapf(err, "failed to grant vm group access to %s", diffVhdPath)
   195  	}
   196  	return nil
   197  }
   198  

View as plain text