helpers.go 6.6 KB

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