Vendor opengcs and hcsshim
Signed-off-by: Darren Stahl <darst@microsoft.com>
This commit is contained in:
165
vendor/github.com/Microsoft/opengcs/client/createext4vhdx.go
generated
vendored
Normal file
165
vendor/github.com/Microsoft/opengcs/client/createext4vhdx.go
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
// +build windows
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
winio "github.com/Microsoft/go-winio/vhd"
|
||||
// "github.com/Microsoft/hcsshim"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// dismount is a simple utility function wrapping a conditional HotRemove. It would
|
||||
// have been easier if you could cancel a deferred function, but this works just
|
||||
// as well.
|
||||
func (config *Config) dismount(file string) error {
|
||||
logrus.Debugf("opengcs: CreateExt4Vhdx: hot-remove of %s", file)
|
||||
err := config.HotRemoveVhd(file)
|
||||
if err != nil {
|
||||
logrus.Warnf("failed to hot-remove: %s", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateExt4Vhdx does what it says on the tin. It is the responsibility of the caller to synchronise
|
||||
// simultaneous attempts to create the cache file.
|
||||
func (config *Config) CreateExt4Vhdx(destFile string, sizeGB uint32, cacheFile string) error {
|
||||
// Smallest we can accept is the default sandbox size as we can't size down, only expand.
|
||||
if sizeGB < DefaultVhdxSizeGB {
|
||||
sizeGB = DefaultVhdxSizeGB
|
||||
}
|
||||
|
||||
logrus.Debugf("opengcs: CreateExt4Vhdx: %s size:%dGB cache:%s", destFile, sizeGB, cacheFile)
|
||||
|
||||
// Retrieve from cache if the default size and already on disk
|
||||
if cacheFile != "" && sizeGB == DefaultVhdxSizeGB {
|
||||
if _, err := os.Stat(cacheFile); err == nil {
|
||||
if err := CopyFile(cacheFile, destFile, false); err != nil {
|
||||
return fmt.Errorf("failed to copy cached file '%s' to '%s': %s", cacheFile, destFile, err)
|
||||
}
|
||||
logrus.Debugf("opengcs: CreateExt4Vhdx: %s fulfilled from cache", destFile)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Must have a utility VM to operate on
|
||||
if config.Uvm == nil {
|
||||
return fmt.Errorf("no utility VM")
|
||||
}
|
||||
|
||||
// Create the VHDX
|
||||
if err := winio.CreateVhdx(destFile, sizeGB, defaultVhdxBlockSizeMB); err != nil {
|
||||
return fmt.Errorf("failed to create VHDx %s: %s", destFile, err)
|
||||
}
|
||||
|
||||
// Attach it to the utility VM, but don't mount it (as there's no filesystem on it)
|
||||
if err := config.HotAddVhd(destFile, "", false, false); err != nil {
|
||||
return fmt.Errorf("opengcs: CreateExt4Vhdx: failed to hot-add %s to utility VM: %s", cacheFile, err)
|
||||
}
|
||||
|
||||
// Get the list of mapped virtual disks to find the controller and LUN IDs
|
||||
logrus.Debugf("opengcs: CreateExt4Vhdx: %s querying mapped virtual disks", destFile)
|
||||
mvdControllers, err := config.Uvm.MappedVirtualDisks()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get mapped virtual disks: %s", err)
|
||||
}
|
||||
|
||||
// Find our mapped disk from the list of all currently added.
|
||||
controller := -1
|
||||
lun := -1
|
||||
for controllerNumber, controllerElement := range mvdControllers {
|
||||
for diskNumber, diskElement := range controllerElement.MappedVirtualDisks {
|
||||
if diskElement.HostPath == destFile {
|
||||
controller = controllerNumber
|
||||
lun = diskNumber
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if controller == -1 || lun == -1 {
|
||||
config.dismount(destFile)
|
||||
return fmt.Errorf("failed to find %s in mapped virtual disks after hot-adding", destFile)
|
||||
}
|
||||
logrus.Debugf("opengcs: CreateExt4Vhdx: %s at C=%d L=%d", destFile, controller, lun)
|
||||
|
||||
// Validate /sys/bus/scsi/devices/C:0:0:L exists as a directory
|
||||
testdCommand := fmt.Sprintf(`test -d /sys/bus/scsi/devices/%d:0:0:%d`, controller, lun)
|
||||
testdProc, err := config.RunProcess(testdCommand, nil, nil, nil)
|
||||
if err != nil {
|
||||
config.dismount(destFile)
|
||||
return fmt.Errorf("failed to `%s` following hot-add %s to utility VM: %s", testdCommand, destFile, err)
|
||||
}
|
||||
defer testdProc.Close()
|
||||
testdProc.WaitTimeout(time.Duration(int(time.Second) * config.UvmTimeoutSeconds))
|
||||
testdExitCode, err := testdProc.ExitCode()
|
||||
if err != nil {
|
||||
config.dismount(destFile)
|
||||
return fmt.Errorf("failed to get exit code from `%s` following hot-add %s to utility VM: %s", testdCommand, destFile, err)
|
||||
}
|
||||
if testdExitCode != 0 {
|
||||
config.dismount(destFile)
|
||||
return fmt.Errorf("`%s` return non-zero exit code (%d) following hot-add %s to utility VM", testdCommand, testdExitCode, destFile)
|
||||
}
|
||||
|
||||
// Get the device from under the block subdirectory by doing a simple ls. This will come back as (eg) `sda`
|
||||
lsCommand := fmt.Sprintf(`ls /sys/bus/scsi/devices/%d:0:0:%d/block`, controller, lun)
|
||||
var lsOutput bytes.Buffer
|
||||
lsProc, err := config.RunProcess(lsCommand, nil, &lsOutput, nil)
|
||||
if err != nil {
|
||||
config.dismount(destFile)
|
||||
return fmt.Errorf("failed to `%s` following hot-add %s to utility VM: %s", lsCommand, destFile, err)
|
||||
}
|
||||
defer lsProc.Close()
|
||||
lsProc.WaitTimeout(time.Duration(int(time.Second) * config.UvmTimeoutSeconds))
|
||||
lsExitCode, err := lsProc.ExitCode()
|
||||
if err != nil {
|
||||
config.dismount(destFile)
|
||||
return fmt.Errorf("failed to get exit code from `%s` following hot-add %s to utility VM: %s", lsCommand, destFile, err)
|
||||
}
|
||||
if lsExitCode != 0 {
|
||||
config.dismount(destFile)
|
||||
return fmt.Errorf("`%s` return non-zero exit code (%d) following hot-add %s to utility VM", lsCommand, lsExitCode, destFile)
|
||||
}
|
||||
device := fmt.Sprintf(`/dev/%s`, strings.TrimSpace(lsOutput.String()))
|
||||
logrus.Debugf("opengcs: CreateExt4Vhdx: %s: device at %s", destFile, device)
|
||||
|
||||
// Format it ext4
|
||||
mkfsCommand := fmt.Sprintf(`mkfs.ext4 -q -E lazy_itable_init=1 -O ^has_journal,sparse_super2,uninit_bg,^resize_inode %s`, device)
|
||||
var mkfsStderr bytes.Buffer
|
||||
mkfsProc, err := config.RunProcess(mkfsCommand, nil, nil, &mkfsStderr)
|
||||
if err != nil {
|
||||
config.dismount(destFile)
|
||||
return fmt.Errorf("failed to RunProcess %q following hot-add %s to utility VM: %s", destFile, mkfsCommand, err)
|
||||
}
|
||||
defer mkfsProc.Close()
|
||||
mkfsProc.WaitTimeout(time.Duration(int(time.Second) * config.UvmTimeoutSeconds))
|
||||
mkfsExitCode, err := mkfsProc.ExitCode()
|
||||
if err != nil {
|
||||
config.dismount(destFile)
|
||||
return fmt.Errorf("failed to get exit code from `%s` following hot-add %s to utility VM: %s", mkfsCommand, destFile, err)
|
||||
}
|
||||
if mkfsExitCode != 0 {
|
||||
config.dismount(destFile)
|
||||
return fmt.Errorf("`%s` return non-zero exit code (%d) following hot-add %s to utility VM: %s", mkfsCommand, mkfsExitCode, destFile, strings.TrimSpace(mkfsStderr.String()))
|
||||
}
|
||||
|
||||
// Dismount before we copy it
|
||||
if err := config.dismount(destFile); err != nil {
|
||||
return fmt.Errorf("failed to hot-remove: %s", err)
|
||||
}
|
||||
|
||||
// Populate the cache.
|
||||
if cacheFile != "" && (sizeGB == DefaultVhdxSizeGB) {
|
||||
if err := CopyFile(destFile, cacheFile, true); err != nil {
|
||||
return fmt.Errorf("failed to seed cache '%s' from '%s': %s", destFile, cacheFile, err)
|
||||
}
|
||||
}
|
||||
|
||||
logrus.Debugf("opengcs: CreateExt4Vhdx: %s created (non-cache)", destFile)
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user