Merge pull request #1837 from crosbymichael/bump-cgroups

Update cgroups to 29da22c6171a4316169f9205ab6c49f5
This commit is contained in:
Kenfe-Mickaël Laventure 2017-11-30 08:03:22 -08:00 committed by GitHub
commit 6bff39c643
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 4 additions and 1171 deletions

View File

@ -1,7 +1,7 @@
github.com/coreos/go-systemd 48702e0da86bd25e76cfef347e2adeb434a0d0a6
github.com/containerd/go-runc ed1cbe1fc31f5fb2359d3a54b6330d1a097858b7
github.com/containerd/console 84eeaae905fa414d03e07bcd6c8d3f19e7cf180e
github.com/containerd/cgroups f7dd103d3e4e696aa67152f6b4ddd1779a3455a9
github.com/containerd/cgroups 29da22c6171a4316169f9205ab6c49f59b5b852f
github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788
github.com/docker/go-metrics 8fd5772bf1584597834c6f7961a530f06cbfbb87
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9

View File

@ -1,82 +0,0 @@
// +build windows
package vhd
import "syscall"
//go:generate go run mksyscall_windows.go -output zvhd.go vhd.go
//sys createVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, flags uint32, providerSpecificFlags uint32, parameters *createVirtualDiskParameters, o *syscall.Overlapped, handle *syscall.Handle) (err error) [failretval != 0] = VirtDisk.CreateVirtualDisk
type virtualStorageType struct {
DeviceID uint32
VendorID [16]byte
}
const virtualDiskAccessNONE uint32 = 0
const virtualDiskAccessATTACHRO uint32 = 65536
const virtualDiskAccessATTACHRW uint32 = 131072
const virtualDiskAccessDETACH uint32 = 262144
const virtualDiskAccessGETINFO uint32 = 524288
const virtualDiskAccessCREATE uint32 = 1048576
const virtualDiskAccessMETAOPS uint32 = 2097152
const virtualDiskAccessREAD uint32 = 851968
const virtualDiskAccessALL uint32 = 4128768
const virtualDiskAccessWRITABLE uint32 = 3276800
const createVirtualDiskFlagNone uint32 = 0
const createVirtualDiskFlagFullPhysicalAllocation uint32 = 1
const createVirtualDiskFlagPreventWritesToSourceDisk uint32 = 2
const createVirtualDiskFlagDoNotCopyMetadataFromParent uint32 = 4
type version2 struct {
UniqueID [16]byte // GUID
MaximumSize uint64
BlockSizeInBytes uint32
SectorSizeInBytes uint32
ParentPath *uint16 // string
SourcePath *uint16 // string
OpenFlags uint32
ParentVirtualStorageType virtualStorageType
SourceVirtualStorageType virtualStorageType
ResiliencyGUID [16]byte // GUID
}
type createVirtualDiskParameters struct {
Version uint32 // Must always be set to 2
Version2 version2
}
// CreateVhdx will create a simple vhdx file at the given path using default values.
func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
var defaultType virtualStorageType
parameters := createVirtualDiskParameters{
Version: 2,
Version2: version2{
MaximumSize: uint64(maxSizeInGb) * 1024 * 1024 * 1024,
BlockSizeInBytes: blockSizeInMb * 1024 * 1024,
},
}
var handle syscall.Handle
if err := createVirtualDisk(
&defaultType,
path,
virtualDiskAccessNONE,
nil,
createVirtualDiskFlagNone,
0,
&parameters,
nil,
&handle); err != nil {
return err
}
if err := syscall.CloseHandle(handle); err != nil {
return err
}
return nil
}

View File

@ -1,64 +0,0 @@
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
package vhd
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return nil
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
modVirtDisk = windows.NewLazySystemDLL("VirtDisk.dll")
procCreateVirtualDisk = modVirtDisk.NewProc("CreateVirtualDisk")
)
func createVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, flags uint32, providerSpecificFlags uint32, parameters *createVirtualDiskParameters, o *syscall.Overlapped, handle *syscall.Handle) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(path)
if err != nil {
return
}
return _createVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, securityDescriptor, flags, providerSpecificFlags, parameters, o, handle)
}
func _createVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, virtualDiskAccessMask uint32, securityDescriptor *uintptr, flags uint32, providerSpecificFlags uint32, parameters *createVirtualDiskParameters, o *syscall.Overlapped, handle *syscall.Handle) (err error) {
r1, _, e1 := syscall.Syscall9(procCreateVirtualDisk.Addr(), 9, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(flags), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(handle)))
if r1 != 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) Microsoft Corporation. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE

View File

@ -1,14 +0,0 @@
# Open Guest Compute Service (opengcs) [![Build Status](https://travis-ci.org/Microsoft/opengcs.svg?branch=master)](https://travis-ci.org/Microsoft/opengcs)
Open Guest Compute Service is a Linux open source project to further the development of a production quality implementation of Linux Hyper-V container on Windows (LCOW). It's designed to run inside a custom Linux OS for supporting Linux container payload.
# Getting Started
[How to build GCS binaries](./docs/gcsbuildinstructions.md/)
[How to build custom Linux OS images](./docs/customosbuildinstructions.md/)
# Contributing
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

View File

@ -1,274 +0,0 @@
// +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
// DefaultVhdxSizeGB is the size of the default sandbox & scratch in GB
DefaultVhdxSizeGB = 20
// defaultVhdxBlockSizeMB is the block-size for the sandbox/scratch VHDx's this package can create.
defaultVhdxBlockSizeMB = 1
)
// Config is the structure used to configuring a utility 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 {
Options // Configuration options
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
}
// Options is the structure used by a client to define configurable options for a utility VM.
type Options struct {
KirdPath string // Path to where kernel/initrd are found (defaults to %PROGRAMFILES%\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
TimeoutSeconds int // Requested time for the utility VM to respond in seconds (may be over-ridden by environment)
BootParameters string // Additional boot parameters for initrd booting (not VHDx)
}
// ParseOptions parses a set of K-V pairs into options used by opengcs. Note
// for consistency with the LCOW graphdriver in docker, we keep the same
// convention of an `lcow.` prefix.
func ParseOptions(options []string) (Options, error) {
rOpts := Options{TimeoutSeconds: 0}
for _, v := range options {
opt := strings.SplitN(v, "=", 2)
if len(opt) == 2 {
switch strings.ToLower(opt[0]) {
case "lcow.kirdpath":
rOpts.KirdPath = opt[1]
case "lcow.kernel":
rOpts.KernelFile = opt[1]
case "lcow.initrd":
rOpts.InitrdFile = opt[1]
case "lcow.vhdx":
rOpts.Vhdx = opt[1]
case "lcow.bootparameters":
rOpts.BootParameters = opt[1]
case "lcow.timeout":
var err error
if rOpts.TimeoutSeconds, err = strconv.Atoi(opt[1]); err != nil {
return rOpts, fmt.Errorf("opengcstimeoutsecs option could not be interpreted as an integer")
}
if rOpts.TimeoutSeconds < 0 {
return rOpts, fmt.Errorf("opengcstimeoutsecs option cannot be negative")
}
}
}
}
// Set default values if not supplied
if rOpts.KirdPath == "" {
rOpts.KirdPath = filepath.Join(os.Getenv("ProgramFiles"), "Linux Containers")
}
if rOpts.Vhdx == "" {
rOpts.Vhdx = filepath.Join(rOpts.KirdPath, `uvm.vhdx`)
}
if rOpts.KernelFile == "" {
rOpts.KernelFile = `bootx64.efi`
}
if rOpts.InitrdFile == "" {
rOpts.InitrdFile = `initrd.img`
}
return rOpts, nil
}
// 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 {
// Parse the options that the user supplied.
var err error
config.Options, err = ParseOptions(options)
if err != nil {
return err
}
// Get the timeout from the environment
envTimeoutSeconds := 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_UVM_TIMEOUT_SECONDS could not be interpreted as an integer")
}
if envTimeoutSeconds < 0 {
return fmt.Errorf("OPENGCS_UVM_TIMEOUT_SECONDS cannot be negative")
}
}
// Priority to the requested timeout from the options.
if config.TimeoutSeconds != 0 {
config.UvmTimeoutSeconds = config.TimeoutSeconds
return nil
}
// Next priority, the environment
if envTimeoutSeconds != 0 {
config.UvmTimeoutSeconds = envTimeoutSeconds
return nil
}
// Last priority is the default timeout
config.UvmTimeoutSeconds = defaultUvmTimeoutSeconds
// Set the default requested mode
config.RequestedMode = ModeRequestAuto
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("VHDx mode must supply a VHDx")
}
if config.RequestedMode == ModeRequestKernelInitrd && (config.KernelFile == "" || config.InitrdFile == "") {
return fmt.Errorf("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("VHDx '%s' not found", config.Vhdx)
}
} else {
config.ActualMode = ModeActualVhdx
// Can't specify boot parameters with VHDx
if config.BootParameters != "" {
return fmt.Errorf("Boot parameters cannot be specified in VHDx mode")
}
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("initrd and kernel options 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("kernel '%s' not found", filepath.Join(config.KirdPath, config.KernelFile))
}
if _, err := os.Stat(filepath.Join(config.KirdPath, config.InitrdFile)); os.IsNotExist(err) {
return fmt.Errorf("initrd '%s' 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("mapped virtual disk '%s' not found", mvd.HostPath)
}
if mvd.ContainerPath == "" {
return fmt.Errorf("mapped virtual disk '%s' requested without a container path", mvd.HostPath)
}
}
return nil
}
// StartUtilityVM creates and starts a utility VM from a configuration.
func (config *Config) StartUtilityVM() error {
logrus.Debugf("opengcs: StartUtilityVM: %+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,
BootSource: "Vhd",
WritableBootSource: true,
}
} else {
configuration.HvRuntime = &hcsshim.HvRuntime{
ImagePath: config.KirdPath,
LinuxInitrdFile: config.InitrdFile,
LinuxKernelFile: config.KernelFile,
LinuxBootParameters: config.BootParameters,
}
}
configurationS, _ := json.Marshal(configuration)
logrus.Debugf("opengcs: StartUtilityVM: calling HCS with '%s'", string(configurationS))
uvm, err := hcsshim.CreateContainer(config.Name, configuration)
if err != nil {
return err
}
logrus.Debugf("opengcs: StartUtilityVM: uvm created, starting...")
err = uvm.Start()
if err != nil {
logrus.Debugf("opengcs: StartUtilityVM: 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 StartUtilityVM: uvm %s is running", config.Name)
return nil
}

View File

@ -1,165 +0,0 @@
// +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
}

View File

@ -1,40 +0,0 @@
// +build windows
package client
import (
"fmt"
"github.com/Microsoft/hcsshim"
"github.com/sirupsen/logrus"
)
// HotAddVhd hot-adds a VHD to a utility VM. This is used in the global one-utility-VM-
// service-VM per host scenario. In order to do a graphdriver `Diff`, we hot-add the
// sandbox to /mnt/<id> so that we can run `exportSandbox` inside the utility VM to
// get a tar-stream of the sandboxes contents back to the daemon.
func (config *Config) HotAddVhd(hostPath string, containerPath string, readOnly bool, mount bool) error {
logrus.Debugf("opengcs: HotAddVhd: %s: %s", hostPath, containerPath)
if config.Uvm == nil {
return fmt.Errorf("cannot hot-add VHD as no utility VM is in configuration")
}
modification := &hcsshim.ResourceModificationRequestResponse{
Resource: "MappedVirtualDisk",
Data: hcsshim.MappedVirtualDisk{
HostPath: hostPath,
ContainerPath: containerPath,
CreateInUtilityVM: true,
ReadOnly: readOnly,
AttachOnly: !mount,
},
Request: "Add",
}
if err := config.Uvm.Modify(modification); err != nil {
return fmt.Errorf("failed to modify utility VM configuration for hot-add: %s", err)
}
logrus.Debugf("opengcs: HotAddVhd: %s added successfully", hostPath)
return nil
}

View File

@ -1,34 +0,0 @@
// +build windows
package client
import (
"fmt"
"github.com/Microsoft/hcsshim"
"github.com/sirupsen/logrus"
)
// HotRemoveVhd hot-removes a VHD from a utility VM. This is used in the global one-utility-VM-
// service-VM per host scenario.
func (config *Config) HotRemoveVhd(hostPath string) error {
logrus.Debugf("opengcs: HotRemoveVhd: %s", hostPath)
if config.Uvm == nil {
return fmt.Errorf("cannot hot-add VHD as no utility VM is in configuration")
}
modification := &hcsshim.ResourceModificationRequestResponse{
Resource: "MappedVirtualDisk",
Data: hcsshim.MappedVirtualDisk{
HostPath: hostPath,
CreateInUtilityVM: true,
},
Request: "Remove",
}
if err := config.Uvm.Modify(modification); err != nil {
return fmt.Errorf("failed modifying utility VM for hot-remove %s: %s", hostPath, err)
}
logrus.Debugf("opengcs: HotRemoveVhd: %s removed successfully", hostPath)
return nil
}

View File

@ -1,31 +0,0 @@
// +build windows
package client
import (
"fmt"
"os"
"path/filepath"
)
// LayerVhdDetails is a utility for getting a file name, size and indication of
// sandbox for a VHD(x) in a folder. A read-only layer will be layer.vhd. A
// read-write layer will be sandbox.vhdx.
func LayerVhdDetails(folder string) (string, int64, bool, error) {
var fileInfo os.FileInfo
isSandbox := false
filename := filepath.Join(folder, "layer.vhd")
var err error
if fileInfo, err = os.Stat(filename); err != nil {
filename = filepath.Join(folder, "sandbox.vhdx")
if fileInfo, err = os.Stat(filename); err != nil {
if os.IsNotExist(err) {
return "", 0, isSandbox, fmt.Errorf("could not find layer or sandbox in %s", folder)
}
return "", 0, isSandbox, fmt.Errorf("error locating layer or sandbox in %s: %s", folder, err)
}
isSandbox = true
}
return filename, fileInfo.Size(), isSandbox, nil
}

View File

@ -1,112 +0,0 @@
// +build windows
package client
import (
"fmt"
"io"
"github.com/Microsoft/hcsshim"
"github.com/sirupsen/logrus"
)
// Process is the structure pertaining to a process running in a utility VM.
type process struct {
Process hcsshim.Process
Stdin io.WriteCloser
Stdout io.ReadCloser
Stderr io.ReadCloser
}
// createUtilsProcess is a convenient wrapper for hcsshim.createUtilsProcess to use when
// communicating with a utility VM.
func (config *Config) createUtilsProcess(commandLine string) (process, error) {
logrus.Debugf("opengcs: createUtilsProcess")
if config.Uvm == nil {
return process{}, fmt.Errorf("cannot create utils process as no utility VM is in configuration")
}
var (
err error
proc process
)
env := make(map[string]string)
env["PATH"] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:"
processConfig := &hcsshim.ProcessConfig{
EmulateConsole: false,
CreateStdInPipe: true,
CreateStdOutPipe: true,
CreateStdErrPipe: true,
CreateInUtilityVm: true,
WorkingDirectory: "/bin",
Environment: env,
CommandLine: commandLine,
}
proc.Process, err = config.Uvm.CreateProcess(processConfig)
if err != nil {
return process{}, fmt.Errorf("failed to create process (%+v) in utility VM: %s", config, err)
}
if proc.Stdin, proc.Stdout, proc.Stderr, err = proc.Process.Stdio(); err != nil {
proc.Process.Kill() // Should this have a timeout?
proc.Process.Close()
return process{}, fmt.Errorf("failed to get stdio pipes for process %+v: %s", config, err)
}
logrus.Debugf("opengcs: createUtilsProcess success: pid %d", proc.Process.Pid())
return proc, nil
}
// RunProcess runs the given command line program in the utilityVM. It takes in
// an input to the reader to feed into stdin and returns stdout to output.
// IMPORTANT: It is the responsibility of the caller to call Close() on the returned process.
func (config *Config) RunProcess(commandLine string, stdin io.Reader, stdout io.Writer, stderr io.Writer) (hcsshim.Process, error) {
logrus.Debugf("opengcs: RunProcess: %s", commandLine)
process, err := config.createUtilsProcess(commandLine)
if err != nil {
return nil, err
}
// Send the data into the process's stdin
if stdin != nil {
if _, err = copyWithTimeout(process.Stdin,
stdin,
0,
config.UvmTimeoutSeconds,
fmt.Sprintf("send to stdin of %s", commandLine)); err != nil {
return nil, err
}
// Don't need stdin now we've sent everything. This signals GCS that we are finished sending data.
if err := process.Process.CloseStdin(); err != nil {
return nil, err
}
}
if stdout != nil {
// Copy the data over to the writer.
if _, err := copyWithTimeout(stdout,
process.Stdout,
0,
config.UvmTimeoutSeconds,
fmt.Sprintf("RunProcess: copy back from %s", commandLine)); err != nil {
return nil, err
}
}
if stderr != nil {
// Copy the data over to the writer.
if _, err := copyWithTimeout(stderr,
process.Stderr,
0,
config.UvmTimeoutSeconds,
fmt.Sprintf("RunProcess: copy back from %s", commandLine)); err != nil {
return nil, err
}
}
logrus.Debugf("opengcs: runProcess success: %s", commandLine)
return process.Process, nil
}

View File

@ -1,44 +0,0 @@
// +build windows
package client
import (
"fmt"
"io"
"github.com/sirupsen/logrus"
)
// TarToVhd streams a tarstream contained in an io.Reader to a fixed vhd file
func (config *Config) TarToVhd(targetVHDFile string, reader io.Reader) (int64, error) {
logrus.Debugf("opengcs: TarToVhd: %s", targetVHDFile)
if config.Uvm == nil {
return 0, fmt.Errorf("cannot Tar2Vhd as no utility VM is in configuration")
}
process, err := config.createUtilsProcess("tar2vhd")
if err != nil {
return 0, fmt.Errorf("failed to start tar2vhd for %s: %s", targetVHDFile, err)
}
defer process.Process.Close()
// Send the tarstream into the `tar2vhd`s stdin
if _, err = copyWithTimeout(process.Stdin, reader, 0, config.UvmTimeoutSeconds, fmt.Sprintf("stdin of tar2vhd for generating %s", targetVHDFile)); err != nil {
return 0, fmt.Errorf("failed sending to tar2vhd for %s: %s", targetVHDFile, err)
}
// Don't need stdin now we've sent everything. This signals GCS that we are finished sending data.
if err := process.Process.CloseStdin(); err != nil {
return 0, fmt.Errorf("failed closing stdin handle for %s: %s", targetVHDFile, err)
}
// Write stdout contents of `tar2vhd` to the VHD file
payloadSize, err := writeFileFromReader(targetVHDFile, process.Stdout, config.UvmTimeoutSeconds, fmt.Sprintf("stdout of tar2vhd to %s", targetVHDFile))
if err != nil {
return 0, fmt.Errorf("failed to write %s during tar2vhd: %s", targetVHDFile, err)
}
logrus.Debugf("opengcs: TarToVhd: %s created, %d bytes", targetVHDFile, payloadSize)
return payloadSize, err
}

View File

@ -1,3 +0,0 @@
// +build !windows
package client

View File

@ -1,99 +0,0 @@
// +build windows
package client
import (
"fmt"
"io"
"os"
"syscall"
"time"
"unsafe"
"github.com/sirupsen/logrus"
)
var (
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
procCopyFileW = modkernel32.NewProc("CopyFileW")
)
// writeFileFromReader writes an output file from an io.Reader
func writeFileFromReader(path string, reader io.Reader, timeoutSeconds int, context string) (int64, error) {
outFile, err := os.Create(path)
if err != nil {
return 0, fmt.Errorf("opengcs: writeFileFromReader: failed to create %s: %s", path, err)
}
defer outFile.Close()
return copyWithTimeout(outFile, reader, 0, timeoutSeconds, context)
}
// copyWithTimeout is a wrapper for io.Copy using a timeout duration
func copyWithTimeout(dst io.Writer, src io.Reader, size int64, timeoutSeconds int, context string) (int64, error) {
logrus.Debugf("opengcs: copywithtimeout: size %d: timeout %d: (%s)", size, timeoutSeconds, context)
type resultType struct {
err error
bytes int64
}
done := make(chan resultType, 1)
go func() {
result := resultType{}
result.bytes, result.err = io.Copy(dst, src)
done <- result
}()
var result resultType
timedout := time.After(time.Duration(timeoutSeconds) * time.Second)
select {
case <-timedout:
return 0, fmt.Errorf("opengcs: copyWithTimeout: timed out (%s)", context)
case result = <-done:
if result.err != nil && result.err != io.EOF {
// See https://github.com/golang/go/blob/f3f29d1dea525f48995c1693c609f5e67c046893/src/os/exec/exec_windows.go for a clue as to why we are doing this :)
if se, ok := result.err.(syscall.Errno); ok {
const (
errNoData = syscall.Errno(232)
errBrokenPipe = syscall.Errno(109)
)
if se == errNoData || se == errBrokenPipe {
logrus.Debugf("opengcs: copyWithTimeout: hit NoData or BrokenPipe: %d: %s", se, context)
return result.bytes, nil
}
}
return 0, fmt.Errorf("opengcs: copyWithTimeout: error reading: '%s' after %d bytes (%s)", result.err, result.bytes, context)
}
}
logrus.Debugf("opengcs: copyWithTimeout: success - copied %d bytes (%s)", result.bytes, context)
return result.bytes, nil
}
// CopyFile is a utility for copying a file - used for the sandbox cache.
// Uses CopyFileW win32 API for performance
func CopyFile(srcFile, destFile string, overwrite bool) error {
var bFailIfExists uint32 = 1
if overwrite {
bFailIfExists = 0
}
lpExistingFileName, err := syscall.UTF16PtrFromString(srcFile)
if err != nil {
return err
}
lpNewFileName, err := syscall.UTF16PtrFromString(destFile)
if err != nil {
return err
}
r1, _, err := syscall.Syscall(
procCopyFileW.Addr(),
3,
uintptr(unsafe.Pointer(lpExistingFileName)),
uintptr(unsafe.Pointer(lpNewFileName)),
uintptr(bFailIfExists))
if r1 == 0 {
return fmt.Errorf("failed CopyFileW Win32 call from '%s' to '%s': %s", srcFile, destFile, err)
}
return nil
}

View File

@ -1,67 +0,0 @@
// +build windows
package client
import (
"fmt"
"io"
"os"
"github.com/sirupsen/logrus"
)
// VhdToTar does what is says - it exports a VHD in a specified
// folder (either a read-only layer.vhd, or a read-write sandbox.vhd) to a
// ReadCloser containing a tar-stream of the layers contents.
func (config *Config) VhdToTar(vhdFile string, uvmMountPath string, isSandbox bool, vhdSize int64) (io.ReadCloser, error) {
logrus.Debugf("opengcs: VhdToTar: %s isSandbox: %t", vhdFile, isSandbox)
if config.Uvm == nil {
return nil, fmt.Errorf("cannot VhdToTar as no utility VM is in configuration")
}
vhdHandle, err := os.Open(vhdFile)
if err != nil {
return nil, fmt.Errorf("opengcs: VhdToTar: failed to open %s: %s", vhdFile, err)
}
defer vhdHandle.Close()
logrus.Debugf("opengcs: VhdToTar: exporting %s, size %d, isSandbox %t", vhdHandle.Name(), vhdSize, isSandbox)
// Different binary depending on whether a RO layer or a RW sandbox
command := "vhd2tar"
if isSandbox {
command = fmt.Sprintf("exportSandbox -path %s", uvmMountPath)
}
// Start the binary in the utility VM
process, err := config.createUtilsProcess(command)
if err != nil {
return nil, fmt.Errorf("opengcs: VhdToTar: %s: failed to create utils process %s: %s", vhdHandle.Name(), command, err)
}
if !isSandbox {
// Send the VHD contents to the utility VM processes stdin handle if not a sandbox
logrus.Debugf("opengcs: VhdToTar: copying the layer VHD into the utility VM")
if _, err = copyWithTimeout(process.Stdin, vhdHandle, vhdSize, config.UvmTimeoutSeconds, fmt.Sprintf("vhdtotarstream: sending %s to %s", vhdHandle.Name(), command)); err != nil {
process.Process.Close()
return nil, fmt.Errorf("opengcs: VhdToTar: %s: failed to copyWithTimeout on the stdin pipe (to utility VM): %s", vhdHandle.Name(), err)
}
}
// Start a goroutine which copies the stdout (ie the tar stream)
reader, writer := io.Pipe()
go func() {
defer writer.Close()
defer process.Process.Close()
logrus.Debugf("opengcs: VhdToTar: copying tar stream back from the utility VM")
bytes, err := copyWithTimeout(writer, process.Stdout, vhdSize, config.UvmTimeoutSeconds, fmt.Sprintf("vhdtotarstream: copy tarstream from %s", command))
if err != nil {
logrus.Errorf("opengcs: VhdToTar: %s: copyWithTimeout on the stdout pipe (from utility VM) failed: %s", vhdHandle.Name(), err)
}
logrus.Debugf("opengcs: VhdToTar: copied %d bytes of the tarstream of %s from the utility VM", bytes, vhdHandle.Name())
}()
// Return the read-side of the pipe connected to the goroutine which is reading from the stdout of the process in the utility VM
return reader, nil
}

View File

@ -310,7 +310,8 @@ func (c *cgroup) Thaw() error {
}
// OOMEventFD returns the memory cgroup's out of memory event fd that triggers
// when processes inside the cgroup receive an oom event
// when processes inside the cgroup receive an oom event. Returns
// ErrMemoryNotSupported if memory cgroups is not supported.
func (c *cgroup) OOMEventFD() (uintptr, error) {
c.mu.Lock()
defer c.mu.Unlock()

View File

@ -2,7 +2,7 @@ syntax = "proto3";
package io.containerd.cgroups.v1;
import weak "gogoproto/gogo.proto";
import "gogoproto/gogo.proto";
message Metrics {
repeated HugetlbStat hugetlb = 1;

View File

@ -1,66 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: google/protobuf/empty.proto
/*
Package empty is a generated protocol buffer package.
It is generated from these files:
google/protobuf/empty.proto
It has these top-level messages:
Empty
*/
package empty
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// A generic empty message that you can re-use to avoid defining duplicated
// empty messages in your APIs. A typical example is to use it as the request
// or the response type of an API method. For instance:
//
// service Foo {
// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
// }
//
// The JSON representation for `Empty` is empty JSON object `{}`.
type Empty struct {
}
func (m *Empty) Reset() { *m = Empty{} }
func (m *Empty) String() string { return proto.CompactTextString(m) }
func (*Empty) ProtoMessage() {}
func (*Empty) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (*Empty) XXX_WellKnownType() string { return "Empty" }
func init() {
proto.RegisterType((*Empty)(nil), "google.protobuf.Empty")
}
func init() { proto.RegisterFile("google/protobuf/empty.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 148 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4e, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcd, 0x2d, 0x28,
0xa9, 0xd4, 0x03, 0x73, 0x85, 0xf8, 0x21, 0x92, 0x7a, 0x30, 0x49, 0x25, 0x76, 0x2e, 0x56, 0x57,
0x90, 0xbc, 0x53, 0x19, 0x97, 0x70, 0x72, 0x7e, 0xae, 0x1e, 0x9a, 0xbc, 0x13, 0x17, 0x58, 0x36,
0x00, 0xc4, 0x0d, 0x60, 0x8c, 0x52, 0x4f, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf,
0xd5, 0x4f, 0xcf, 0xcf, 0x49, 0xcc, 0x4b, 0x47, 0x58, 0x53, 0x50, 0x52, 0x59, 0x90, 0x5a, 0x0c,
0xb1, 0xed, 0x07, 0x23, 0xe3, 0x22, 0x26, 0x66, 0xf7, 0x00, 0xa7, 0x55, 0x4c, 0x72, 0xee, 0x10,
0x13, 0x03, 0xa0, 0xea, 0xf4, 0xc2, 0x53, 0x73, 0x72, 0xbc, 0xf3, 0xf2, 0xcb, 0xf3, 0x42, 0x40,
0xea, 0x93, 0xd8, 0xc0, 0x06, 0x18, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x64, 0xd4, 0xb3, 0xa6,
0xb7, 0x00, 0x00, 0x00,
}

View File

@ -1,52 +0,0 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option go_package = "github.com/golang/protobuf/ptypes/empty";
option java_package = "com.google.protobuf";
option java_outer_classname = "EmptyProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
option cc_enable_arenas = true;
// A generic empty message that you can re-use to avoid defining duplicated
// empty messages in your APIs. A typical example is to use it as the request
// or the response type of an API method. For instance:
//
// service Foo {
// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
// }
//
// The JSON representation for `Empty` is empty JSON object `{}`.
message Empty {}