go.mod github.com/Microsoft/hcsshim v0.8.16

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2021-03-12 17:17:51 +01:00
parent bc856372bb
commit 75b64e0f60
623 changed files with 60114 additions and 6182 deletions

View File

@ -1,28 +1,23 @@
package wclayer
import (
"context"
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/internal/oc"
"go.opencensus.io/trace"
)
// ActivateLayer will find the layer with the given id and mount it's filesystem.
// For a read/write layer, the mounted filesystem will appear as a volume on the
// host, while a read-only layer is generally expected to be a no-op.
// An activated layer must later be deactivated via DeactivateLayer.
func ActivateLayer(path string) (err error) {
func ActivateLayer(ctx context.Context, path string) (err error) {
title := "hcsshim::ActivateLayer"
fields := logrus.Fields{
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("path", path))
err = activateLayer(&stdDriverInfo, path)
if err != nil {

View File

@ -1,6 +1,7 @@
package wclayer
import (
"context"
"errors"
"os"
"path/filepath"
@ -8,10 +9,16 @@ import (
"github.com/Microsoft/go-winio"
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/Microsoft/hcsshim/internal/safefile"
"github.com/Microsoft/hcsshim/internal/winapi"
"go.opencensus.io/trace"
)
type baseLayerWriter struct {
ctx context.Context
s *trace.Span
root *os.File
f *os.File
bw *winio.BackupFileWriter
@ -31,7 +38,7 @@ type dirInfo struct {
func reapplyDirectoryTimes(root *os.File, dis []dirInfo) error {
for i := range dis {
di := &dis[len(dis)-i-1] // reverse order: process child directories first
f, err := safefile.OpenRelative(di.path, root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, safefile.FILE_OPEN, safefile.FILE_DIRECTORY_FILE)
f, err := safefile.OpenRelative(di.path, root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, winapi.FILE_OPEN, winapi.FILE_DIRECTORY_FILE|syscall.FILE_FLAG_OPEN_REPARSE_POINT)
if err != nil {
return err
}
@ -41,6 +48,7 @@ func reapplyDirectoryTimes(root *os.File, dis []dirInfo) error {
if err != nil {
return err
}
}
return nil
}
@ -86,14 +94,12 @@ func (w *baseLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) (err e
extraFlags := uint32(0)
if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
extraFlags |= safefile.FILE_DIRECTORY_FILE
if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
w.dirInfo = append(w.dirInfo, dirInfo{name, *fileInfo})
}
extraFlags |= winapi.FILE_DIRECTORY_FILE
w.dirInfo = append(w.dirInfo, dirInfo{name, *fileInfo})
}
mode := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | winio.WRITE_DAC | winio.WRITE_OWNER | winio.ACCESS_SYSTEM_SECURITY)
f, err = safefile.OpenRelative(name, w.root, mode, syscall.FILE_SHARE_READ, safefile.FILE_CREATE, extraFlags)
f, err = safefile.OpenRelative(name, w.root, mode, syscall.FILE_SHARE_READ, winapi.FILE_CREATE, extraFlags)
if err != nil {
return hcserror.New(err, "Failed to safefile.OpenRelative", name)
}
@ -136,12 +142,15 @@ func (w *baseLayerWriter) Write(b []byte) (int, error) {
return n, err
}
func (w *baseLayerWriter) Close() error {
func (w *baseLayerWriter) Close() (err error) {
defer w.s.End()
defer func() { oc.SetSpanStatus(w.s, err) }()
defer func() {
w.root.Close()
w.root = nil
}()
err := w.closeCurrentFile()
err = w.closeCurrentFile()
if err != nil {
return err
}
@ -153,7 +162,7 @@ func (w *baseLayerWriter) Close() error {
return err
}
err = ProcessBaseLayer(w.root.Name())
err = ProcessBaseLayer(w.ctx, w.root.Name())
if err != nil {
return err
}
@ -163,7 +172,7 @@ func (w *baseLayerWriter) Close() error {
if err != nil {
return err
}
err = ProcessUtilityVMImage(filepath.Join(w.root.Name(), "UtilityVM"))
err = ProcessUtilityVMImage(w.ctx, filepath.Join(w.root.Name(), "UtilityVM"))
if err != nil {
return err
}

View File

@ -1,27 +1,23 @@
package wclayer
import (
"context"
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/internal/oc"
"go.opencensus.io/trace"
)
// CreateLayer creates a new, empty, read-only layer on the filesystem based on
// the parent layer provided.
func CreateLayer(path, parent string) (err error) {
func CreateLayer(ctx context.Context, path, parent string) (err error) {
title := "hcsshim::CreateLayer"
fields := logrus.Fields{
"parent": parent,
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("path", path),
trace.StringAttribute("parent", parent))
err = createLayer(&stdDriverInfo, path, parent)
if err != nil {

View File

@ -1,31 +1,27 @@
package wclayer
import (
"context"
"strings"
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/internal/oc"
"go.opencensus.io/trace"
)
// CreateScratchLayer creates and populates new read-write layer for use by a container.
// This requires both the id of the direct parent layer, as well as the full list
// of paths to all parent layers up to the base (and including the direct parent
// whose id was provided).
func CreateScratchLayer(path string, parentLayerPaths []string) (err error) {
// This requires the full list of paths to all parent layers up to the base
func CreateScratchLayer(ctx context.Context, path string, parentLayerPaths []string) (err error) {
title := "hcsshim::CreateScratchLayer"
fields := logrus.Fields{
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
ctx, span := trace.StartSpan(ctx, title)
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("path", path),
trace.StringAttribute("parentLayerPaths", strings.Join(parentLayerPaths, ", ")))
// Generate layer descriptors
layers, err := layerPathsToDescriptors(parentLayerPaths)
layers, err := layerPathsToDescriptors(ctx, parentLayerPaths)
if err != nil {
return err
}

View File

@ -1,25 +1,20 @@
package wclayer
import (
"context"
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/internal/oc"
"go.opencensus.io/trace"
)
// DeactivateLayer will dismount a layer that was mounted via ActivateLayer.
func DeactivateLayer(path string) (err error) {
func DeactivateLayer(ctx context.Context, path string) (err error) {
title := "hcsshim::DeactivateLayer"
fields := logrus.Fields{
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("path", path))
err = deactivateLayer(&stdDriverInfo, path)
if err != nil {

View File

@ -1,26 +1,21 @@
package wclayer
import (
"context"
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/internal/oc"
"go.opencensus.io/trace"
)
// DestroyLayer will remove the on-disk files representing the layer with the given
// path, including that layer's containing folder, if any.
func DestroyLayer(path string) (err error) {
func DestroyLayer(ctx context.Context, path string) (err error) {
title := "hcsshim::DestroyLayer"
fields := logrus.Fields{
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("path", path))
err = destroyLayer(&stdDriverInfo, path)
if err != nil {

View File

@ -1,30 +1,140 @@
package wclayer
import (
"context"
"os"
"path/filepath"
"syscall"
"unsafe"
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/Microsoft/hcsshim/osversion"
"go.opencensus.io/trace"
)
// ExpandScratchSize expands the size of a layer to at least size bytes.
func ExpandScratchSize(path string, size uint64) (err error) {
func ExpandScratchSize(ctx context.Context, path string, size uint64) (err error) {
title := "hcsshim::ExpandScratchSize"
fields := logrus.Fields{
"path": path,
"size": size,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
ctx, span := trace.StartSpan(ctx, title)
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("path", path),
trace.Int64Attribute("size", int64(size)))
err = expandSandboxSize(&stdDriverInfo, path, size)
if err != nil {
return hcserror.New(err, title+" - failed", "")
}
// Manually expand the volume now in order to work around bugs in 19H1 and
// prerelease versions of Vb. Remove once this is fixed in Windows.
if build := osversion.Get().Build; build >= osversion.V19H1 && build < 19020 {
err = expandSandboxVolume(ctx, path)
if err != nil {
return err
}
}
return nil
}
type virtualStorageType struct {
DeviceID uint32
VendorID [16]byte
}
type openVersion2 struct {
GetInfoOnly int32 // bool but 4-byte aligned
ReadOnly int32 // bool but 4-byte aligned
ResiliencyGUID [16]byte // GUID
}
type openVirtualDiskParameters struct {
Version uint32 // Must always be set to 2
Version2 openVersion2
}
func attachVhd(path string) (syscall.Handle, error) {
var (
defaultType virtualStorageType
handle syscall.Handle
)
parameters := openVirtualDiskParameters{Version: 2}
err := openVirtualDisk(
&defaultType,
path,
0,
0,
&parameters,
&handle)
if err != nil {
return 0, &os.PathError{Op: "OpenVirtualDisk", Path: path, Err: err}
}
err = attachVirtualDisk(handle, 0, 0, 0, 0, 0)
if err != nil {
syscall.Close(handle)
return 0, &os.PathError{Op: "AttachVirtualDisk", Path: path, Err: err}
}
return handle, nil
}
func expandSandboxVolume(ctx context.Context, path string) error {
// Mount the sandbox VHD temporarily.
vhdPath := filepath.Join(path, "sandbox.vhdx")
vhd, err := attachVhd(vhdPath)
if err != nil {
return &os.PathError{Op: "OpenVirtualDisk", Path: vhdPath, Err: err}
}
defer syscall.Close(vhd)
// Open the volume.
volumePath, err := GetLayerMountPath(ctx, path)
if err != nil {
return err
}
if volumePath[len(volumePath)-1] == '\\' {
volumePath = volumePath[:len(volumePath)-1]
}
volume, err := os.OpenFile(volumePath, os.O_RDWR, 0)
if err != nil {
return err
}
defer volume.Close()
// Get the volume's underlying partition size in NTFS clusters.
var (
partitionSize int64
bytes uint32
)
const _IOCTL_DISK_GET_LENGTH_INFO = 0x0007405C
err = syscall.DeviceIoControl(syscall.Handle(volume.Fd()), _IOCTL_DISK_GET_LENGTH_INFO, nil, 0, (*byte)(unsafe.Pointer(&partitionSize)), 8, &bytes, nil)
if err != nil {
return &os.PathError{Op: "IOCTL_DISK_GET_LENGTH_INFO", Path: volume.Name(), Err: err}
}
const (
clusterSize = 4096
sectorSize = 512
)
targetClusters := partitionSize / clusterSize
// Get the volume's current size in NTFS clusters.
var volumeSize int64
err = getDiskFreeSpaceEx(volume.Name()+"\\", nil, &volumeSize, nil)
if err != nil {
return &os.PathError{Op: "GetDiskFreeSpaceEx", Path: volume.Name(), Err: err}
}
volumeClusters := volumeSize / clusterSize
// Only resize the volume if there is space to grow, otherwise this will
// fail with invalid parameter. NTFS reserves one cluster.
if volumeClusters+1 < targetClusters {
targetSectors := targetClusters * (clusterSize / sectorSize)
const _FSCTL_EXTEND_VOLUME = 0x000900F0
err = syscall.DeviceIoControl(syscall.Handle(volume.Fd()), _FSCTL_EXTEND_VOLUME, (*byte)(unsafe.Pointer(&targetSectors)), 8, nil, 0, &bytes, nil)
if err != nil {
return &os.PathError{Op: "FSCTL_EXTEND_VOLUME", Path: volume.Name(), Err: err}
}
}
return nil
}

View File

@ -1,12 +1,15 @@
package wclayer
import (
"context"
"io/ioutil"
"os"
"strings"
"github.com/Microsoft/go-winio"
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/internal/oc"
"go.opencensus.io/trace"
)
// ExportLayer will create a folder at exportFolderPath and fill that folder with
@ -14,24 +17,18 @@ import (
// format includes any metadata required for later importing the layer (using
// ImportLayer), and requires the full list of parent layer paths in order to
// perform the export.
func ExportLayer(path string, exportFolderPath string, parentLayerPaths []string) (err error) {
func ExportLayer(ctx context.Context, path string, exportFolderPath string, parentLayerPaths []string) (err error) {
title := "hcsshim::ExportLayer"
fields := logrus.Fields{
"path": path,
"exportFolderPath": exportFolderPath,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
ctx, span := trace.StartSpan(ctx, title)
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("path", path),
trace.StringAttribute("exportFolderPath", exportFolderPath),
trace.StringAttribute("parentLayerPaths", strings.Join(parentLayerPaths, ", ")))
// Generate layer descriptors
layers, err := layerPathsToDescriptors(parentLayerPaths)
layers, err := layerPathsToDescriptors(ctx, parentLayerPaths)
if err != nil {
return err
}
@ -52,25 +49,46 @@ type LayerReader interface {
// NewLayerReader returns a new layer reader for reading the contents of an on-disk layer.
// The caller must have taken the SeBackupPrivilege privilege
// to call this and any methods on the resulting LayerReader.
func NewLayerReader(path string, parentLayerPaths []string) (LayerReader, error) {
func NewLayerReader(ctx context.Context, path string, parentLayerPaths []string) (_ LayerReader, err error) {
ctx, span := trace.StartSpan(ctx, "hcsshim::NewLayerReader")
defer func() {
if err != nil {
oc.SetSpanStatus(span, err)
span.End()
}
}()
span.AddAttributes(
trace.StringAttribute("path", path),
trace.StringAttribute("parentLayerPaths", strings.Join(parentLayerPaths, ", ")))
exportPath, err := ioutil.TempDir("", "hcs")
if err != nil {
return nil, err
}
err = ExportLayer(path, exportPath, parentLayerPaths)
err = ExportLayer(ctx, path, exportPath, parentLayerPaths)
if err != nil {
os.RemoveAll(exportPath)
return nil, err
}
return &legacyLayerReaderWrapper{newLegacyLayerReader(exportPath)}, nil
return &legacyLayerReaderWrapper{
ctx: ctx,
s: span,
legacyLayerReader: newLegacyLayerReader(exportPath),
}, nil
}
type legacyLayerReaderWrapper struct {
ctx context.Context
s *trace.Span
*legacyLayerReader
}
func (r *legacyLayerReaderWrapper) Close() error {
err := r.legacyLayerReader.Close()
func (r *legacyLayerReaderWrapper) Close() (err error) {
defer r.s.End()
defer func() { oc.SetSpanStatus(r.s, err) }()
err = r.legacyLayerReader.Close()
os.RemoveAll(r.root)
return err
}

View File

@ -1,36 +1,30 @@
package wclayer
import (
"context"
"syscall"
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/internal/log"
"github.com/Microsoft/hcsshim/internal/oc"
"go.opencensus.io/trace"
)
// GetLayerMountPath will look for a mounted layer with the given path and return
// the path at which that layer can be accessed. This path may be a volume path
// if the layer is a mounted read-write layer, otherwise it is expected to be the
// folder path at which the layer is stored.
func GetLayerMountPath(path string) (_ string, err error) {
func GetLayerMountPath(ctx context.Context, path string) (_ string, err error) {
title := "hcsshim::GetLayerMountPath"
fields := logrus.Fields{
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
ctx, span := trace.StartSpan(ctx, title)
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("path", path))
var mountPathLength uintptr
mountPathLength = 0
var mountPathLength uintptr = 0
// Call the procedure itself.
logrus.WithFields(fields).Debug("Calling proc (1)")
log.G(ctx).Debug("Calling proc (1)")
err = getLayerMountPath(&stdDriverInfo, path, &mountPathLength, nil)
if err != nil {
return "", hcserror.New(err, title+" - failed", "(first call)")
@ -44,13 +38,13 @@ func GetLayerMountPath(path string) (_ string, err error) {
mountPathp[0] = 0
// Call the procedure again
logrus.WithFields(fields).Debug("Calling proc (2)")
log.G(ctx).Debug("Calling proc (2)")
err = getLayerMountPath(&stdDriverInfo, path, &mountPathLength, &mountPathp[0])
if err != nil {
return "", hcserror.New(err, title+" - failed", "(second call)")
}
mountPath := syscall.UTF16ToString(mountPathp[0:])
fields["mountPath"] = mountPath
span.AddAttributes(trace.StringAttribute("mountPath", mountPath))
return mountPath, nil
}

View File

@ -1,29 +1,29 @@
package wclayer
import (
"context"
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/Microsoft/hcsshim/internal/interop"
"github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/internal/oc"
"go.opencensus.io/trace"
)
// GetSharedBaseImages will enumerate the images stored in the common central
// image store and return descriptive info about those images for the purpose
// of registering them with the graphdriver, graph, and tagstore.
func GetSharedBaseImages() (imageData string, err error) {
func GetSharedBaseImages(ctx context.Context) (_ string, err error) {
title := "hcsshim::GetSharedBaseImages"
logrus.Debug(title)
defer func() {
if err != nil {
logrus.WithError(err).Error(err)
} else {
logrus.WithField("imageData", imageData).Debug(title + " - succeeded")
}
}()
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
var buffer *uint16
err = getBaseImages(&buffer)
if err != nil {
return "", hcserror.New(err, title+" - failed", "")
}
return interop.ConvertAndFreeCoTaskMemString(buffer), nil
imageData := interop.ConvertAndFreeCoTaskMemString(buffer)
span.AddAttributes(trace.StringAttribute("imageData", imageData))
return imageData, nil
}

View File

@ -1,26 +1,22 @@
package wclayer
import (
"context"
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/internal/oc"
"go.opencensus.io/trace"
)
// GrantVmAccess adds access to a file for a given VM
func GrantVmAccess(vmid string, filepath string) (err error) {
func GrantVmAccess(ctx context.Context, vmid string, filepath string) (err error) {
title := "hcsshim::GrantVmAccess"
fields := logrus.Fields{
"vm-id": vmid,
"path": filepath,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("vm-id", vmid),
trace.StringAttribute("path", filepath))
err = grantVmAccess(vmid, filepath)
if err != nil {

View File

@ -1,38 +1,35 @@
package wclayer
import (
"context"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/Microsoft/go-winio"
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/Microsoft/hcsshim/internal/safefile"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
// ImportLayer will take the contents of the folder at importFolderPath and import
// that into a layer with the id layerId. Note that in order to correctly populate
// the layer and interperet the transport format, all parent layers must already
// be present on the system at the paths provided in parentLayerPaths.
func ImportLayer(path string, importFolderPath string, parentLayerPaths []string) (err error) {
func ImportLayer(ctx context.Context, path string, importFolderPath string, parentLayerPaths []string) (err error) {
title := "hcsshim::ImportLayer"
fields := logrus.Fields{
"path": path,
"importFolderPath": importFolderPath,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
ctx, span := trace.StartSpan(ctx, title)
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("path", path),
trace.StringAttribute("importFolderPath", importFolderPath),
trace.StringAttribute("parentLayerPaths", strings.Join(parentLayerPaths, ", ")))
// Generate layer descriptors
layers, err := layerPathsToDescriptors(parentLayerPaths)
layers, err := layerPathsToDescriptors(ctx, parentLayerPaths)
if err != nil {
return err
}
@ -60,20 +57,26 @@ type LayerWriter interface {
}
type legacyLayerWriterWrapper struct {
ctx context.Context
s *trace.Span
*legacyLayerWriter
path string
parentLayerPaths []string
}
func (r *legacyLayerWriterWrapper) Close() error {
func (r *legacyLayerWriterWrapper) Close() (err error) {
defer r.s.End()
defer func() { oc.SetSpanStatus(r.s, err) }()
defer os.RemoveAll(r.root.Name())
defer r.legacyLayerWriter.CloseRoots()
err := r.legacyLayerWriter.Close()
err = r.legacyLayerWriter.Close()
if err != nil {
return err
}
if err = ImportLayer(r.destRoot.Name(), r.path, r.parentLayerPaths); err != nil {
if err = ImportLayer(r.ctx, r.destRoot.Name(), r.path, r.parentLayerPaths); err != nil {
return err
}
for _, name := range r.Tombstones {
@ -90,13 +93,26 @@ func (r *legacyLayerWriterWrapper) Close() error {
return err
}
}
// The reapplyDirectoryTimes must be called AFTER we are done with Tombstone
// deletion and hard link creation. This is because Tombstone deletion and hard link
// creation updates the directory last write timestamps so that will change the
// timestamps added by the `Add` call. Some container applications depend on the
// correctness of these timestamps and so we should change the timestamps back to
// the original value (i.e the value provided in the Add call) after this
// processing is done.
err = reapplyDirectoryTimes(r.destRoot, r.changedDi)
if err != nil {
return err
}
// Prepare the utility VM for use if one is present in the layer.
if r.HasUtilityVM {
err := safefile.EnsureNotReparsePointRelative("UtilityVM", r.destRoot)
if err != nil {
return err
}
err = ProcessUtilityVMImage(filepath.Join(r.destRoot.Name(), "UtilityVM"))
err = ProcessUtilityVMImage(r.ctx, filepath.Join(r.destRoot.Name(), "UtilityVM"))
if err != nil {
return err
}
@ -107,7 +123,18 @@ func (r *legacyLayerWriterWrapper) Close() error {
// NewLayerWriter returns a new layer writer for creating a layer on disk.
// The caller must have taken the SeBackupPrivilege and SeRestorePrivilege privileges
// to call this and any methods on the resulting LayerWriter.
func NewLayerWriter(path string, parentLayerPaths []string) (LayerWriter, error) {
func NewLayerWriter(ctx context.Context, path string, parentLayerPaths []string) (_ LayerWriter, err error) {
ctx, span := trace.StartSpan(ctx, "hcsshim::NewLayerWriter")
defer func() {
if err != nil {
oc.SetSpanStatus(span, err)
span.End()
}
}()
span.AddAttributes(
trace.StringAttribute("path", path),
trace.StringAttribute("parentLayerPaths", strings.Join(parentLayerPaths, ", ")))
if len(parentLayerPaths) == 0 {
// This is a base layer. It gets imported differently.
f, err := safefile.OpenRoot(path)
@ -115,6 +142,8 @@ func NewLayerWriter(path string, parentLayerPaths []string) (LayerWriter, error)
return nil, err
}
return &baseLayerWriter{
ctx: ctx,
s: span,
root: f,
}, nil
}
@ -128,6 +157,8 @@ func NewLayerWriter(path string, parentLayerPaths []string) (LayerWriter, error)
return nil, err
}
return &legacyLayerWriterWrapper{
ctx: ctx,
s: span,
legacyLayerWriter: w,
path: importPath,
parentLayerPaths: parentLayerPaths,

View File

@ -1,26 +1,21 @@
package wclayer
import (
"context"
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/internal/oc"
"go.opencensus.io/trace"
)
// LayerExists will return true if a layer with the given id exists and is known
// to the system.
func LayerExists(path string) (_ bool, err error) {
func LayerExists(ctx context.Context, path string) (_ bool, err error) {
title := "hcsshim::LayerExists"
fields := logrus.Fields{
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("path", path))
// Call the procedure itself.
var exists uint32
@ -28,6 +23,6 @@ func LayerExists(path string) (_ bool, err error) {
if err != nil {
return false, hcserror.New(err, title+" - failed", "")
}
fields["layer-exists"] = exists != 0
span.AddAttributes(trace.BoolAttribute("layer-exists", exists != 0))
return exists != 0, nil
}

View File

@ -1,13 +1,22 @@
package wclayer
import (
"context"
"path/filepath"
"github.com/Microsoft/hcsshim/internal/guid"
"github.com/Microsoft/go-winio/pkg/guid"
"github.com/Microsoft/hcsshim/internal/oc"
"go.opencensus.io/trace"
)
// LayerID returns the layer ID of a layer on disk.
func LayerID(path string) (guid.GUID, error) {
func LayerID(ctx context.Context, path string) (_ guid.GUID, err error) {
title := "hcsshim::LayerID"
ctx, span := trace.StartSpan(ctx, title)
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("path", path))
_, file := filepath.Split(path)
return NameToGuid(file)
return NameToGuid(ctx, file)
}

View File

@ -4,9 +4,10 @@ package wclayer
// functionality.
import (
"context"
"syscall"
"github.com/Microsoft/hcsshim/internal/guid"
"github.com/Microsoft/go-winio/pkg/guid"
"github.com/sirupsen/logrus"
)
@ -68,12 +69,12 @@ type WC_LAYER_DESCRIPTOR struct {
Pathp *uint16
}
func layerPathsToDescriptors(parentLayerPaths []string) ([]WC_LAYER_DESCRIPTOR, error) {
func layerPathsToDescriptors(ctx context.Context, parentLayerPaths []string) ([]WC_LAYER_DESCRIPTOR, error) {
// Array of descriptors that gets constructed.
var layers []WC_LAYER_DESCRIPTOR
for i := 0; i < len(parentLayerPaths); i++ {
g, err := LayerID(parentLayerPaths[i])
g, err := LayerID(ctx, parentLayerPaths[i])
if err != nil {
logrus.WithError(err).Debug("Failed to convert name to guid")
return nil, err

View File

@ -15,6 +15,7 @@ import (
"github.com/Microsoft/go-winio"
"github.com/Microsoft/hcsshim/internal/longpath"
"github.com/Microsoft/hcsshim/internal/safefile"
"github.com/Microsoft/hcsshim/internal/winapi"
)
var errorIterationCanceled = errors.New("")
@ -341,7 +342,7 @@ type legacyLayerWriter struct {
backupWriter *winio.BackupFileWriter
Tombstones []string
HasUtilityVM bool
uvmDi []dirInfo
changedDi []dirInfo
addedFiles map[string]bool
PendingLinks []pendingLink
pendingDirs []pendingDir
@ -389,7 +390,7 @@ func (w *legacyLayerWriter) CloseRoots() {
w.destRoot = nil
}
for i := range w.parentRoots {
w.parentRoots[i].Close()
_ = w.parentRoots[i].Close()
}
w.parentRoots = nil
}
@ -472,8 +473,8 @@ func copyFileWithMetadata(srcRoot, destRoot *os.File, subPath string, isDir bool
srcRoot,
syscall.GENERIC_READ|winio.ACCESS_SYSTEM_SECURITY,
syscall.FILE_SHARE_READ,
safefile.FILE_OPEN,
safefile.FILE_OPEN_REPARSE_POINT)
winapi.FILE_OPEN,
winapi.FILE_OPEN_REPARSE_POINT)
if err != nil {
return nil, err
}
@ -488,14 +489,14 @@ func copyFileWithMetadata(srcRoot, destRoot *os.File, subPath string, isDir bool
extraFlags := uint32(0)
if isDir {
extraFlags |= safefile.FILE_DIRECTORY_FILE
extraFlags |= winapi.FILE_DIRECTORY_FILE
}
dest, err := safefile.OpenRelative(
subPath,
destRoot,
syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY,
syscall.FILE_SHARE_READ,
safefile.FILE_CREATE,
winapi.FILE_CREATE,
extraFlags)
if err != nil {
return nil, err
@ -555,7 +556,7 @@ func cloneTree(srcRoot *os.File, destRoot *os.File, subPath string, mutatedFiles
if err != nil {
return err
}
if isDir && !isReparsePoint {
if isDir {
di = append(di, dirInfo{path: relPath, fileInfo: *fi})
}
} else {
@ -583,6 +584,10 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
return w.initUtilityVM()
}
if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
w.changedDi = append(w.changedDi, dirInfo{path: name, fileInfo: *fileInfo})
}
name = filepath.Clean(name)
if hasPathPrefix(name, utilityVMPath) {
if !w.HasUtilityVM {
@ -591,7 +596,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
if !hasPathPrefix(name, utilityVMFilesPath) && name != utilityVMFilesPath {
return errors.New("invalid UtilityVM layer")
}
createDisposition := uint32(safefile.FILE_OPEN)
createDisposition := uint32(winapi.FILE_OPEN)
if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
st, err := safefile.LstatRelative(name, w.destRoot)
if err != nil && !os.IsNotExist(err) {
@ -612,16 +617,13 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
return err
}
}
if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
w.uvmDi = append(w.uvmDi, dirInfo{path: name, fileInfo: *fileInfo})
}
} else {
// Overwrite any existing hard link.
err := safefile.RemoveRelative(name, w.destRoot)
if err != nil && !os.IsNotExist(err) {
return err
}
createDisposition = safefile.FILE_CREATE
createDisposition = winapi.FILE_CREATE
}
f, err := safefile.OpenRelative(
@ -630,7 +632,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
syscall.GENERIC_READ|syscall.GENERIC_WRITE|winio.WRITE_DAC|winio.WRITE_OWNER|winio.ACCESS_SYSTEM_SECURITY,
syscall.FILE_SHARE_READ,
createDisposition,
safefile.FILE_OPEN_REPARSE_POINT,
winapi.FILE_OPEN_REPARSE_POINT,
)
if err != nil {
return err
@ -638,7 +640,7 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
defer func() {
if f != nil {
f.Close()
safefile.RemoveRelative(name, w.destRoot)
_ = safefile.RemoveRelative(name, w.destRoot)
}
}()
@ -667,14 +669,14 @@ func (w *legacyLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) erro
w.currentIsDir = true
}
f, err := safefile.OpenRelative(fname, w.root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, safefile.FILE_CREATE, 0)
f, err := safefile.OpenRelative(fname, w.root, syscall.GENERIC_READ|syscall.GENERIC_WRITE, syscall.FILE_SHARE_READ, winapi.FILE_CREATE, 0)
if err != nil {
return err
}
defer func() {
if f != nil {
f.Close()
safefile.RemoveRelative(fname, w.root)
_ = safefile.RemoveRelative(fname, w.root)
}
}()
@ -805,11 +807,5 @@ func (w *legacyLayerWriter) Close() error {
return err
}
}
if w.HasUtilityVM {
err := reapplyDirectoryTimes(w.destRoot, w.uvmDi)
if err != nil {
return err
}
}
return nil
}

View File

@ -1,34 +1,29 @@
package wclayer
import (
"github.com/Microsoft/hcsshim/internal/guid"
"context"
"github.com/Microsoft/go-winio/pkg/guid"
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/internal/oc"
"go.opencensus.io/trace"
)
// NameToGuid converts the given string into a GUID using the algorithm in the
// Host Compute Service, ensuring GUIDs generated with the same string are common
// across all clients.
func NameToGuid(name string) (id guid.GUID, err error) {
func NameToGuid(ctx context.Context, name string) (_ guid.GUID, err error) {
title := "hcsshim::NameToGuid"
fields := logrus.Fields{
"name": name,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("name", name))
var id guid.GUID
err = nameToGuid(name, &id)
if err != nil {
err = hcserror.New(err, title+" - failed", "")
return
return guid.GUID{}, hcserror.New(err, title+" - failed", "")
}
fields["guid"] = id.String()
return
span.AddAttributes(trace.StringAttribute("guid", id.String()))
return id, nil
}

View File

@ -1,10 +1,13 @@
package wclayer
import (
"context"
"strings"
"sync"
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/internal/oc"
"go.opencensus.io/trace"
)
var prepareLayerLock sync.Mutex
@ -14,23 +17,17 @@ var prepareLayerLock sync.Mutex
// parent layers, and is necessary in order to view or interact with the layer
// as an actual filesystem (reading and writing files, creating directories, etc).
// Disabling the filter must be done via UnprepareLayer.
func PrepareLayer(path string, parentLayerPaths []string) (err error) {
func PrepareLayer(ctx context.Context, path string, parentLayerPaths []string) (err error) {
title := "hcsshim::PrepareLayer"
fields := logrus.Fields{
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
ctx, span := trace.StartSpan(ctx, title)
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("path", path),
trace.StringAttribute("parentLayerPaths", strings.Join(parentLayerPaths, ", ")))
// Generate layer descriptors
layers, err := layerPathsToDescriptors(parentLayerPaths)
layers, err := layerPathsToDescriptors(ctx, parentLayerPaths)
if err != nil {
return err
}

View File

@ -1,23 +1,41 @@
package wclayer
import "os"
import (
"context"
"os"
"github.com/Microsoft/hcsshim/internal/oc"
"go.opencensus.io/trace"
)
// ProcessBaseLayer post-processes a base layer that has had its files extracted.
// The files should have been extracted to <path>\Files.
func ProcessBaseLayer(path string) error {
err := processBaseImage(path)
func ProcessBaseLayer(ctx context.Context, path string) (err error) {
title := "hcsshim::ProcessBaseLayer"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("path", path))
err = processBaseImage(path)
if err != nil {
return &os.PathError{Op: "ProcessBaseLayer", Path: path, Err: err}
return &os.PathError{Op: title, Path: path, Err: err}
}
return nil
}
// ProcessUtilityVMImage post-processes a utility VM image that has had its files extracted.
// The files should have been extracted to <path>\Files.
func ProcessUtilityVMImage(path string) error {
err := processUtilityImage(path)
func ProcessUtilityVMImage(ctx context.Context, path string) (err error) {
title := "hcsshim::ProcessUtilityVMImage"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("path", path))
err = processUtilityImage(path)
if err != nil {
return &os.PathError{Op: "ProcessUtilityVMImage", Path: path, Err: err}
return &os.PathError{Op: title, Path: path, Err: err}
}
return nil
}

View File

@ -1,26 +1,21 @@
package wclayer
import (
"context"
"github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/internal/oc"
"go.opencensus.io/trace"
)
// UnprepareLayer disables the filesystem filter for the read-write layer with
// the given id.
func UnprepareLayer(path string) (err error) {
func UnprepareLayer(ctx context.Context, path string) (err error) {
title := "hcsshim::UnprepareLayer"
fields := logrus.Fields{
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("path", path))
err = unprepareLayer(&stdDriverInfo, path)
if err != nil {

View File

@ -1,6 +1,9 @@
// Package wclayer provides bindings to HCS's legacy layer management API and
// provides a higher level interface around these calls for container layer
// management.
package wclayer
import "github.com/Microsoft/hcsshim/internal/guid"
import "github.com/Microsoft/go-winio/pkg/guid"
//go:generate go run ../../mksyscall_windows.go -output zsyscall_windows.go wclayer.go
@ -24,4 +27,9 @@ import "github.com/Microsoft/hcsshim/internal/guid"
//sys grantVmAccess(vmid string, filepath string) (hr error) = vmcompute.GrantVmAccess?
//sys openVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, flags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (err error) [failretval != 0] = virtdisk.OpenVirtualDisk
//sys attachVirtualDisk(handle syscall.Handle, sd uintptr, flags uint32, providerFlags uint32, params uintptr, overlapped uintptr) (err error) [failretval != 0] = virtdisk.AttachVirtualDisk
//sys getDiskFreeSpaceEx(directoryName string, freeBytesAvailableToCaller *int64, totalNumberOfBytes *int64, totalNumberOfFreeBytes *int64) (err error) = GetDiskFreeSpaceExW
type _guid = guid.GUID

View File

@ -38,6 +38,8 @@ func errnoErr(e syscall.Errno) error {
var (
modvmcompute = windows.NewLazySystemDLL("vmcompute.dll")
modvirtdisk = windows.NewLazySystemDLL("virtdisk.dll")
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procActivateLayer = modvmcompute.NewProc("ActivateLayer")
procCopyLayer = modvmcompute.NewProc("CopyLayer")
@ -57,6 +59,9 @@ var (
procProcessBaseImage = modvmcompute.NewProc("ProcessBaseImage")
procProcessUtilityImage = modvmcompute.NewProc("ProcessUtilityImage")
procGrantVmAccess = modvmcompute.NewProc("GrantVmAccess")
procOpenVirtualDisk = modvirtdisk.NewProc("OpenVirtualDisk")
procAttachVirtualDisk = modvirtdisk.NewProc("AttachVirtualDisk")
procGetDiskFreeSpaceExW = modkernel32.NewProc("GetDiskFreeSpaceExW")
)
func activateLayer(info *driverInfo, id string) (hr error) {
@ -508,3 +513,57 @@ func _grantVmAccess(vmid *uint16, filepath *uint16) (hr error) {
}
return
}
func openVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, flags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(path)
if err != nil {
return
}
return _openVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, flags, parameters, handle)
}
func _openVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, virtualDiskAccessMask uint32, flags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (err error) {
r1, _, e1 := syscall.Syscall6(procOpenVirtualDisk.Addr(), 6, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(flags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle)))
if r1 != 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func attachVirtualDisk(handle syscall.Handle, sd uintptr, flags uint32, providerFlags uint32, params uintptr, overlapped uintptr) (err error) {
r1, _, e1 := syscall.Syscall6(procAttachVirtualDisk.Addr(), 6, uintptr(handle), uintptr(sd), uintptr(flags), uintptr(providerFlags), uintptr(params), uintptr(overlapped))
if r1 != 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func getDiskFreeSpaceEx(directoryName string, freeBytesAvailableToCaller *int64, totalNumberOfBytes *int64, totalNumberOfFreeBytes *int64) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(directoryName)
if err != nil {
return
}
return _getDiskFreeSpaceEx(_p0, freeBytesAvailableToCaller, totalNumberOfBytes, totalNumberOfFreeBytes)
}
func _getDiskFreeSpaceEx(directoryName *uint16, freeBytesAvailableToCaller *int64, totalNumberOfBytes *int64, totalNumberOfFreeBytes *int64) (err error) {
r1, _, e1 := syscall.Syscall6(procGetDiskFreeSpaceExW.Addr(), 4, uintptr(unsafe.Pointer(directoryName)), uintptr(unsafe.Pointer(freeBytesAvailableToCaller)), uintptr(unsafe.Pointer(totalNumberOfBytes)), uintptr(unsafe.Pointer(totalNumberOfFreeBytes)), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}