github.com/containerd/nerdctl/v2@v2.0.0-beta.5.0.20240520001846-b5758f54fa28/pkg/cmd/container/run_windows.go (about)

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package container
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"strings"
    24  
    25  	"github.com/containerd/containerd"
    26  	"github.com/containerd/containerd/containers"
    27  	"github.com/containerd/containerd/oci"
    28  	"github.com/containerd/nerdctl/v2/pkg/api/types"
    29  	"github.com/docker/go-units"
    30  	"github.com/opencontainers/runtime-spec/specs-go"
    31  )
    32  
    33  const (
    34  	// HostProcessInheritUser inherits permissions of containerd process
    35  	hostProcessInheritUser = "microsoft.com/hostprocess-inherit-user"
    36  
    37  	// HostProcessContainer will launch a host process container
    38  	hostProcessContainer = "microsoft.com/hostprocess-container"
    39  	uvmMemorySizeInMB    = "io.microsoft.virtualmachine.computetopology.memory.sizeinmb"
    40  	uvmCPUCount          = "io.microsoft.virtualmachine.computetopology.processor.count"
    41  )
    42  
    43  func setPlatformOptions(
    44  	ctx context.Context,
    45  	client *containerd.Client,
    46  	id, uts string,
    47  	internalLabels *internalLabels,
    48  	options types.ContainerCreateOptions,
    49  ) ([]oci.SpecOpts, error) {
    50  	var opts []oci.SpecOpts
    51  	if options.CPUs > 0.0 {
    52  		opts = append(opts, oci.WithWindowsCPUCount(uint64(options.CPUs)))
    53  	}
    54  
    55  	if options.Memory != "" {
    56  		mem64, err := units.RAMInBytes(options.Memory)
    57  		if err != nil {
    58  			return nil, fmt.Errorf("failed to parse memory bytes %q: %w", options.Memory, err)
    59  		}
    60  		opts = append(opts, oci.WithMemoryLimit(uint64(mem64)))
    61  	}
    62  
    63  	switch options.Isolation {
    64  	case "hyperv":
    65  		if options.Memory != "" {
    66  			mem64, err := units.RAMInBytes(options.Memory)
    67  			if err != nil {
    68  				return nil, fmt.Errorf("failed to parse memory bytes %q: %w", options.Memory, err)
    69  			}
    70  			UVMMemmory := map[string]string{
    71  				uvmMemorySizeInMB: fmt.Sprintf("%v", mem64),
    72  			}
    73  			opts = append(opts, oci.WithAnnotations(UVMMemmory))
    74  		}
    75  
    76  		if options.CPUs > 0.0 {
    77  			UVMCPU := map[string]string{
    78  				uvmCPUCount: fmt.Sprintf("%v", options.CPUs),
    79  			}
    80  			opts = append(opts, oci.WithAnnotations(UVMCPU))
    81  		}
    82  		opts = append(opts, oci.WithWindowsHyperV)
    83  	case "host":
    84  		hpAnnotations := map[string]string{
    85  			hostProcessContainer: "true",
    86  		}
    87  
    88  		// If user is set we will attempt to start container with that user (must be present on the host)
    89  		// Otherwise we will inherit permissions from the user that the containerd process is running as
    90  		if options.User == "" {
    91  			hpAnnotations[hostProcessInheritUser] = "true"
    92  		}
    93  
    94  		opts = append(opts, oci.WithAnnotations(hpAnnotations))
    95  	case "process":
    96  		// override the default isolation mode in the case where
    97  		// the containerd default_runtime is set to hyper-v
    98  		opts = append(opts, WithWindowsProcessIsolated())
    99  	case "default":
   100  		// no op
   101  		// use containerd's default runtime option `default_runtime` set in the config.toml
   102  	default:
   103  		return nil, fmt.Errorf("unknown isolation value %q. valid values are 'host', 'process' or 'default'", options.Isolation)
   104  	}
   105  
   106  	opts = append(opts,
   107  		oci.WithWindowNetworksAllowUnqualifiedDNSQuery(),
   108  		oci.WithWindowsIgnoreFlushesDuringBoot())
   109  
   110  	for _, dev := range options.Device {
   111  		idType, devID, ok := strings.Cut(dev, "://")
   112  		if !ok {
   113  			return nil, errors.New("devices must be in the format IDType://ID")
   114  		}
   115  		if idType == "" {
   116  			return nil, errors.New("devices must have a non-empty IDType")
   117  		}
   118  		opts = append(opts, oci.WithWindowsDevice(idType, devID))
   119  	}
   120  
   121  	return opts, nil
   122  }
   123  
   124  func WithWindowsProcessIsolated() oci.SpecOpts {
   125  	return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error {
   126  		if s.Windows == nil {
   127  			s.Windows = &specs.Windows{}
   128  		}
   129  		if s.Windows.HyperV != nil {
   130  			s.Windows.HyperV = nil
   131  		}
   132  		return nil
   133  	}
   134  }