helpers.go 6.7 KB

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