167 lines
4.8 KiB
Go
167 lines
4.8 KiB
Go
//+build windows
|
|
|
|
/*
|
|
Copyright The containerd Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package windows
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/Microsoft/hcsshim"
|
|
"github.com/containerd/containerd/errdefs"
|
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// newContainerConfig generates a hcsshim container configuration from the
|
|
// provided OCI Spec
|
|
func newContainerConfig(ctx context.Context, owner, id string, spec *specs.Spec) (*hcsshim.ContainerConfig, error) {
|
|
var (
|
|
conf = &hcsshim.ContainerConfig{
|
|
SystemType: "Container",
|
|
Name: id,
|
|
Owner: owner,
|
|
HostName: spec.Hostname,
|
|
}
|
|
)
|
|
|
|
if spec.Windows.Network != nil {
|
|
conf.AllowUnqualifiedDNSQuery = spec.Windows.Network.AllowUnqualifiedDNSQuery
|
|
conf.EndpointList = spec.Windows.Network.EndpointList
|
|
conf.NetworkSharedContainerName = spec.Windows.Network.NetworkSharedContainerName
|
|
if spec.Windows.Network.DNSSearchList != nil {
|
|
conf.DNSSearchList = strings.Join(spec.Windows.Network.DNSSearchList, ",")
|
|
}
|
|
}
|
|
|
|
return conf, nil
|
|
}
|
|
|
|
// newWindowsContainerConfig generates a hcsshim Windows container
|
|
// configuration from the provided OCI Spec
|
|
func newWindowsContainerConfig(ctx context.Context, owner, id string, spec *specs.Spec) (*hcsshim.ContainerConfig, error) {
|
|
conf, err := newContainerConfig(ctx, owner, id, spec)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
conf.IgnoreFlushesDuringBoot = spec.Windows.IgnoreFlushesDuringBoot
|
|
|
|
if len(spec.Windows.LayerFolders) < 2 {
|
|
return nil, errors.Wrap(errdefs.ErrInvalidArgument,
|
|
"spec.Windows.LayerFolders must have at least 2 layers")
|
|
}
|
|
var (
|
|
layerFolderPath = spec.Windows.LayerFolders[0]
|
|
layerFolders = spec.Windows.LayerFolders[1:]
|
|
layerID = filepath.Base(layerFolderPath)
|
|
)
|
|
|
|
// TODO: use the create request Mount for those
|
|
for _, layerPath := range layerFolders {
|
|
_, filename := filepath.Split(layerPath)
|
|
guid, err := hcsshim.NameToGuid(filename)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "unable to get GUID for %s", filename)
|
|
}
|
|
conf.Layers = append(conf.Layers, hcsshim.Layer{
|
|
ID: guid.ToString(),
|
|
Path: layerPath,
|
|
})
|
|
}
|
|
conf.LayerFolderPath = layerFolderPath
|
|
|
|
var di = hcsshim.DriverInfo{
|
|
HomeDir: filepath.Dir(layerFolderPath),
|
|
}
|
|
conf.VolumePath, err = hcsshim.GetLayerMountPath(di, layerID)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to getmount path for layer %s: driverInfo: %#v", id, di)
|
|
}
|
|
|
|
if spec.Windows.HyperV != nil {
|
|
conf.HvPartition = true
|
|
for _, layerPath := range layerFolders {
|
|
utilityVMPath := spec.Windows.HyperV.UtilityVMPath
|
|
_, err := os.Stat(utilityVMPath)
|
|
if err == nil {
|
|
conf.HvRuntime = &hcsshim.HvRuntime{ImagePath: utilityVMPath}
|
|
break
|
|
} else if !os.IsNotExist(err) {
|
|
return nil, errors.Wrapf(err, "failed to access layer %s", layerPath)
|
|
}
|
|
}
|
|
}
|
|
|
|
if spec.Windows.CredentialSpec != nil {
|
|
conf.Credentials = spec.Windows.CredentialSpec.(string)
|
|
}
|
|
|
|
if len(spec.Mounts) > 0 {
|
|
mds := make([]hcsshim.MappedDir, len(spec.Mounts))
|
|
for i, mount := range spec.Mounts {
|
|
mds[i] = hcsshim.MappedDir{
|
|
HostPath: mount.Source,
|
|
ContainerPath: mount.Destination,
|
|
ReadOnly: false,
|
|
}
|
|
for _, o := range mount.Options {
|
|
if strings.ToLower(o) == "ro" {
|
|
mds[i].ReadOnly = true
|
|
}
|
|
}
|
|
}
|
|
conf.MappedDirectories = mds
|
|
}
|
|
|
|
return conf, nil
|
|
}
|
|
|
|
func newProcessConfig(processSpec *specs.Process, pset *pipeSet) *hcsshim.ProcessConfig {
|
|
conf := &hcsshim.ProcessConfig{
|
|
EmulateConsole: pset.src.Terminal,
|
|
CreateStdInPipe: pset.stdin != nil,
|
|
CreateStdOutPipe: pset.stdout != nil,
|
|
CreateStdErrPipe: pset.stderr != nil,
|
|
User: processSpec.User.Username,
|
|
Environment: make(map[string]string),
|
|
WorkingDirectory: processSpec.Cwd,
|
|
}
|
|
|
|
if processSpec.ConsoleSize != nil {
|
|
conf.ConsoleSize = [2]uint{processSpec.ConsoleSize.Height, processSpec.ConsoleSize.Width}
|
|
}
|
|
|
|
// Convert OCI Env format to HCS's
|
|
for _, s := range processSpec.Env {
|
|
arr := strings.SplitN(s, "=", 2)
|
|
if len(arr) == 2 {
|
|
conf.Environment[arr[0]] = arr[1]
|
|
}
|
|
}
|
|
|
|
return conf
|
|
}
|
|
|
|
func newWindowsProcessConfig(processSpec *specs.Process, pset *pipeSet) *hcsshim.ProcessConfig {
|
|
conf := newProcessConfig(processSpec, pset)
|
|
conf.CommandLine = strings.Join(processSpec.Args, " ")
|
|
return conf
|
|
}
|