1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/vendor/github.com/jhowardmsft/opengcs/gogcs/client/config.go
Derek McGowan 4f3616fb1c
Update imports for logrus version
Add forks for changes which only make logrus change without functional
change.

Signed-off-by: Derek McGowan <derek@mcgstyle.net>
2017-07-31 13:19:38 -07:00

245 lines
8.4 KiB
Go

// +build windows
package client
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/Microsoft/hcsshim"
"github.com/sirupsen/logrus"
)
// Mode is the operational mode, both requested, and actual after verification
type Mode uint
const (
// Constants for the actual mode after validation
// ModeActualError means an error has occurred during validation
ModeActualError = iota
// ModeActualVhdx means that we are going to use VHDX boot after validation
ModeActualVhdx
// ModeActualKernelInitrd means that we are going to use kernel+initrd for boot after validation
ModeActualKernelInitrd
// Constants for the requested mode
// ModeRequestAuto means auto-select the boot mode for a utility VM
ModeRequestAuto = iota // VHDX will be priority over kernel+initrd
// ModeRequestVhdx means request VHDX boot if possible
ModeRequestVhdx
// ModeRequestKernelInitrd means request Kernel+initrd boot if possible
ModeRequestKernelInitrd
// defaultUvmTimeoutSeconds is the default time to wait for utility VM operations
defaultUvmTimeoutSeconds = 5 * 60
// DefaultSandboxSizeMB is the size of the default sandbox size in MB
DefaultSandboxSizeMB = 20 * 1024 * 1024
)
// Config is the structure used to configuring a utility VM to be used
// as a service VM. There are two ways of starting. Either supply a VHD,
// or a Kernel+Initrd. For the latter, both must be supplied, and both
// must be in the same directory.
//
// VHD is the priority.
type Config struct {
KirdPath string // Path to where kernel/initrd are found (defaults to c:\program files\Linux Containers)
KernelFile string // Kernel for Utility VM (embedded in a UEFI bootloader) - does NOT include full path, just filename
InitrdFile string // Initrd image for Utility VM - does NOT include full path, just filename
Vhdx string // VHD for booting the utility VM - is a full path
Name string // Name of the utility VM
RequestedMode Mode // What mode is preferred when validating
ActualMode Mode // What mode was obtained during validation
UvmTimeoutSeconds int // How long to wait for the utility VM to respond in seconds
Uvm hcsshim.Container // The actual container
MappedVirtualDisks []hcsshim.MappedVirtualDisk // Data-disks to be attached
}
// GenerateDefault generates a default config from a set of options
// If baseDir is not supplied, defaults to $env:ProgramFiles\Linux Containers
func (config *Config) GenerateDefault(options []string) error {
if config.UvmTimeoutSeconds < 0 {
return fmt.Errorf("opengcs: cannot generate a config when supplied a negative utility VM timeout")
}
envTimeoutSeconds := 0
optTimeoutSeconds := 0
if config.UvmTimeoutSeconds != 0 {
envTimeout := os.Getenv("OPENGCS_UVM_TIMEOUT_SECONDS")
if len(envTimeout) > 0 {
var err error
if envTimeoutSeconds, err = strconv.Atoi(envTimeout); err != nil {
return fmt.Errorf("opengcs: OPENGCS_UVM_TIMEOUT_SECONDS could not be interpreted as an integer")
}
if envTimeoutSeconds < 0 {
return fmt.Errorf("opengcs: OPENGCS_UVM_TIMEOUT_SECONDS cannot be negative")
}
}
}
for _, v := range options {
opt := strings.SplitN(v, "=", 2)
if len(opt) == 2 {
switch strings.ToLower(opt[0]) {
case "opengcskirdpath":
config.KirdPath = opt[1]
case "opengcskernel":
config.KernelFile = opt[1]
case "opengcsinitrd":
config.InitrdFile = opt[1]
case "opengcsvhdx":
config.Vhdx = opt[1]
case "opengcstimeoutsecs":
var err error
if optTimeoutSeconds, err = strconv.Atoi(opt[1]); err != nil {
return fmt.Errorf("opengcs: opengcstimeoutsecs option could not be interpreted as an integer")
}
if optTimeoutSeconds < 0 {
return fmt.Errorf("opengcs: opengcstimeoutsecs option cannot be negative")
}
}
}
}
if config.KirdPath == "" {
config.KirdPath = filepath.Join(os.Getenv("ProgramFiles"), "Linux Containers")
}
if config.Vhdx == "" {
config.Vhdx = filepath.Join(config.KirdPath, `uvm.vhdx`)
}
if config.KernelFile == "" {
config.KernelFile = `bootx64.efi`
}
if config.InitrdFile == "" {
config.InitrdFile = `initrd.img`
}
// Which timeout are we going to take? If not through option or environment,
// then use the default constant, otherwise the maximum of the option or
// environment supplied setting. A requested on in the config supplied
// overrides all of this.
if config.UvmTimeoutSeconds == 0 {
config.UvmTimeoutSeconds = defaultUvmTimeoutSeconds
if optTimeoutSeconds != 0 || envTimeoutSeconds != 0 {
config.UvmTimeoutSeconds = optTimeoutSeconds
if envTimeoutSeconds > optTimeoutSeconds {
config.UvmTimeoutSeconds = envTimeoutSeconds
}
}
}
config.MappedVirtualDisks = nil
return nil
}
// validate validates a Config structure for starting a utility VM.
func (config *Config) validate() error {
config.ActualMode = ModeActualError
if config.RequestedMode == ModeRequestVhdx && config.Vhdx == "" {
return fmt.Errorf("opengcs: config is invalid - request for VHDX mode did not supply a VHDX")
}
if config.RequestedMode == ModeRequestKernelInitrd && (config.KernelFile == "" || config.InitrdFile == "") {
return fmt.Errorf("opengcs: config is invalid - request for Kernel+Initrd mode must supply both kernel and initrd")
}
// Validate that if VHDX requested or auto, it exists.
if config.RequestedMode == ModeRequestAuto || config.RequestedMode == ModeRequestVhdx {
if _, err := os.Stat(config.Vhdx); os.IsNotExist(err) {
if config.RequestedMode == ModeRequestVhdx {
return fmt.Errorf("opengcs: mode requested was VHDX but '%s' could not be found", config.Vhdx)
}
} else {
config.ActualMode = ModeActualVhdx
return nil
}
}
// So must be kernel+initrd, or auto where we fallback as the VHDX doesn't exist
if config.InitrdFile == "" || config.KernelFile == "" {
if config.RequestedMode == ModeRequestKernelInitrd {
return fmt.Errorf("opengcs: both initrd and kernel options for utility VM boot must be supplied")
}
return fmt.Errorf("opengcs: configuration is invalid")
}
if _, err := os.Stat(filepath.Join(config.KirdPath, config.KernelFile)); os.IsNotExist(err) {
return fmt.Errorf("opengcs: kernel '%s' was not found", filepath.Join(config.KirdPath, config.KernelFile))
}
if _, err := os.Stat(filepath.Join(config.KirdPath, config.InitrdFile)); os.IsNotExist(err) {
return fmt.Errorf("opengcs: initrd '%s' was not found", filepath.Join(config.KirdPath, config.InitrdFile))
}
config.ActualMode = ModeActualKernelInitrd
// Ensure all the MappedVirtualDisks exist on the host
for _, mvd := range config.MappedVirtualDisks {
if _, err := os.Stat(mvd.HostPath); err != nil {
return fmt.Errorf("opengcs: MappedVirtualDisk '%s' was not found", mvd.HostPath)
}
if mvd.ContainerPath == "" {
return fmt.Errorf("opengcs: MappedVirtualDisk '%s' has no container path", mvd.HostPath)
}
}
return nil
}
// Create creates a utility VM from a configuration.
func (config *Config) Create() error {
logrus.Debugf("opengcs Create: %+v", config)
if err := config.validate(); err != nil {
return err
}
configuration := &hcsshim.ContainerConfig{
HvPartition: true,
Name: config.Name,
SystemType: "container",
ContainerType: "linux",
TerminateOnLastHandleClosed: true,
MappedVirtualDisks: config.MappedVirtualDisks,
}
if config.ActualMode == ModeActualVhdx {
configuration.HvRuntime = &hcsshim.HvRuntime{
ImagePath: config.Vhdx,
}
} else {
configuration.HvRuntime = &hcsshim.HvRuntime{
ImagePath: config.KirdPath,
LinuxInitrdFile: config.InitrdFile,
LinuxKernelFile: config.KernelFile,
}
}
configurationS, _ := json.Marshal(configuration)
logrus.Debugf("opengcs Create: calling HCS with '%s'", string(configurationS))
uvm, err := hcsshim.CreateContainer(config.Name, configuration)
if err != nil {
return err
}
logrus.Debugf("opengcs Create: uvm created, starting...")
err = uvm.Start()
if err != nil {
logrus.Debugf("opengcs Create: uvm failed to start: %s", err)
// Make sure we don't leave it laying around as it's been created in HCS
uvm.Terminate()
return err
}
config.Uvm = uvm
logrus.Debugf("opengcs Create: uvm %s is running", config.Name)
return nil
}