gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/pkg/katautils/create.go (about)

     1  // Copyright (c) 2018 Intel Corporation
     2  // Copyright (c) 2018 HyperHQ Inc.
     3  //
     4  // SPDX-License-Identifier: Apache-2.0
     5  //
     6  
     7  package katautils
     8  
     9  import (
    10  	"context"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"strconv"
    14  	"strings"
    15  
    16  	vc "github.com/kata-containers/runtime/virtcontainers"
    17  	vf "github.com/kata-containers/runtime/virtcontainers/factory"
    18  	"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
    19  	specs "github.com/opencontainers/runtime-spec/specs-go"
    20  )
    21  
    22  // GetKernelParamsFunc use a variable to allow tests to modify its value
    23  var GetKernelParamsFunc = getKernelParams
    24  
    25  var systemdKernelParam = []vc.Param{
    26  	{
    27  		Key:   "systemd.unit",
    28  		Value: systemdUnitName,
    29  	},
    30  	{
    31  		Key:   "systemd.mask",
    32  		Value: "systemd-networkd.service",
    33  	},
    34  	{
    35  		Key:   "systemd.mask",
    36  		Value: "systemd-networkd.socket",
    37  	},
    38  }
    39  
    40  func getKernelParams(needSystemd, trace bool) []vc.Param {
    41  	p := []vc.Param{}
    42  
    43  	if needSystemd {
    44  		p = append(p, systemdKernelParam...)
    45  	}
    46  
    47  	return p
    48  }
    49  
    50  func needSystemd(config vc.HypervisorConfig) bool {
    51  	return config.ImagePath != ""
    52  }
    53  
    54  // HandleFactory  set the factory
    55  func HandleFactory(ctx context.Context, vci vc.VC, runtimeConfig *oci.RuntimeConfig) {
    56  	if !runtimeConfig.FactoryConfig.Template && runtimeConfig.FactoryConfig.VMCacheNumber == 0 {
    57  		return
    58  	}
    59  	factoryConfig := vf.Config{
    60  		Template:        runtimeConfig.FactoryConfig.Template,
    61  		TemplatePath:    runtimeConfig.FactoryConfig.TemplatePath,
    62  		VMCache:         runtimeConfig.FactoryConfig.VMCacheNumber > 0,
    63  		VMCacheEndpoint: runtimeConfig.FactoryConfig.VMCacheEndpoint,
    64  		VMConfig: vc.VMConfig{
    65  			HypervisorType:   runtimeConfig.HypervisorType,
    66  			HypervisorConfig: runtimeConfig.HypervisorConfig,
    67  			AgentType:        runtimeConfig.AgentType,
    68  			AgentConfig:      runtimeConfig.AgentConfig,
    69  			ProxyType:        runtimeConfig.ProxyType,
    70  			ProxyConfig:      runtimeConfig.ProxyConfig,
    71  		},
    72  	}
    73  
    74  	kataUtilsLogger.WithField("factory", factoryConfig).Info("load vm factory")
    75  
    76  	f, err := vf.NewFactory(ctx, factoryConfig, true)
    77  	if err != nil && !factoryConfig.VMCache {
    78  		kataUtilsLogger.WithError(err).Warn("load vm factory failed, about to create new one")
    79  		f, err = vf.NewFactory(ctx, factoryConfig, false)
    80  	}
    81  	if err != nil {
    82  		kataUtilsLogger.WithError(err).Warn("create vm factory failed")
    83  		return
    84  	}
    85  
    86  	vci.SetFactory(ctx, f)
    87  }
    88  
    89  // SetEphemeralStorageType sets the mount type to 'ephemeral'
    90  // if the mount source path is provisioned by k8s for ephemeral storage.
    91  // For the given pod ephemeral volume is created only once
    92  // backed by tmpfs inside the VM. For successive containers
    93  // of the same pod the already existing volume is reused.
    94  func SetEphemeralStorageType(ociSpec specs.Spec) specs.Spec {
    95  	for idx, mnt := range ociSpec.Mounts {
    96  		if vc.IsEphemeralStorage(mnt.Source) {
    97  			ociSpec.Mounts[idx].Type = vc.KataEphemeralDevType
    98  		}
    99  		if vc.Isk8sHostEmptyDir(mnt.Source) {
   100  			ociSpec.Mounts[idx].Type = vc.KataLocalDevType
   101  		}
   102  	}
   103  	return ociSpec
   104  }
   105  
   106  // CreateSandbox create a sandbox container
   107  func CreateSandbox(ctx context.Context, vci vc.VC, ociSpec specs.Spec, runtimeConfig oci.RuntimeConfig, rootFs vc.RootFs,
   108  	containerID, bundlePath, console string, disableOutput, systemdCgroup, builtIn bool) (_ vc.VCSandbox, _ vc.Process, err error) {
   109  	span, ctx := Trace(ctx, "createSandbox")
   110  	defer span.Finish()
   111  
   112  	sandboxConfig, err := oci.SandboxConfig(ociSpec, runtimeConfig, bundlePath, containerID, console, disableOutput, systemdCgroup)
   113  	if err != nil {
   114  		return nil, vc.Process{}, err
   115  	}
   116  
   117  	if builtIn {
   118  		sandboxConfig.Stateful = true
   119  	}
   120  
   121  	if err := checkForFIPS(&sandboxConfig); err != nil {
   122  		return nil, vc.Process{}, err
   123  	}
   124  
   125  	if !rootFs.Mounted && len(sandboxConfig.Containers) == 1 {
   126  		if rootFs.Source != "" {
   127  			realPath, err := ResolvePath(rootFs.Source)
   128  			if err != nil {
   129  				return nil, vc.Process{}, err
   130  			}
   131  			rootFs.Source = realPath
   132  		}
   133  		sandboxConfig.Containers[0].RootFs = rootFs
   134  	}
   135  
   136  	// Important to create the network namespace before the sandbox is
   137  	// created, because it is not responsible for the creation of the
   138  	// netns if it does not exist.
   139  	if err := SetupNetworkNamespace(&sandboxConfig.NetworkConfig); err != nil {
   140  		return nil, vc.Process{}, err
   141  	}
   142  
   143  	defer func() {
   144  		// cleanup netns if kata creates it
   145  		ns := sandboxConfig.NetworkConfig
   146  		if err != nil && ns.NetNsCreated {
   147  			if ex := cleanupNetNS(ns.NetNSPath); ex != nil {
   148  				kataUtilsLogger.WithField("path", ns.NetNSPath).WithError(ex).Warn("failed to cleanup netns")
   149  			}
   150  		}
   151  	}()
   152  
   153  	// Run pre-start OCI hooks.
   154  	err = EnterNetNS(sandboxConfig.NetworkConfig.NetNSPath, func() error {
   155  		return PreStartHooks(ctx, ociSpec, containerID, bundlePath)
   156  	})
   157  	if err != nil {
   158  		return nil, vc.Process{}, err
   159  	}
   160  
   161  	sandbox, err := vci.CreateSandbox(ctx, sandboxConfig)
   162  	if err != nil {
   163  		return nil, vc.Process{}, err
   164  	}
   165  
   166  	sid := sandbox.ID()
   167  	kataUtilsLogger = kataUtilsLogger.WithField("sandbox", sid)
   168  	span.SetTag("sandbox", sid)
   169  
   170  	containers := sandbox.GetAllContainers()
   171  	if len(containers) != 1 {
   172  		return nil, vc.Process{}, fmt.Errorf("BUG: Container list from sandbox is wrong, expecting only one container, found %d containers", len(containers))
   173  	}
   174  
   175  	if !builtIn {
   176  		err = AddContainerIDMapping(ctx, containerID, sandbox.ID())
   177  		if err != nil {
   178  			return nil, vc.Process{}, err
   179  		}
   180  	}
   181  
   182  	return sandbox, containers[0].Process(), nil
   183  }
   184  
   185  var procFIPS = "/proc/sys/crypto/fips_enabled"
   186  
   187  func checkForFIPS(sandboxConfig *vc.SandboxConfig) error {
   188  	content, err := ioutil.ReadFile(procFIPS)
   189  	if err != nil {
   190  		// In case file cannot be found or read, simply return
   191  		return nil
   192  	}
   193  
   194  	enabled, err := strconv.Atoi(strings.Trim(string(content), "\n\t "))
   195  	if err != nil {
   196  		// Unexpected format, ignore and simply return early
   197  		return nil
   198  	}
   199  
   200  	if enabled == 1 {
   201  		param := vc.Param{
   202  			Key:   "fips",
   203  			Value: "1",
   204  		}
   205  
   206  		if err := sandboxConfig.HypervisorConfig.AddKernelParam(param); err != nil {
   207  			return fmt.Errorf("Error enabling fips mode : %v", err)
   208  		}
   209  	}
   210  
   211  	return nil
   212  }
   213  
   214  // CreateContainer create a container
   215  func CreateContainer(ctx context.Context, vci vc.VC, sandbox vc.VCSandbox, ociSpec specs.Spec, rootFs vc.RootFs, containerID, bundlePath, console string, disableOutput, builtIn bool) (vc.Process, error) {
   216  	var c vc.VCContainer
   217  
   218  	span, ctx := Trace(ctx, "createContainer")
   219  	defer span.Finish()
   220  
   221  	ociSpec = SetEphemeralStorageType(ociSpec)
   222  
   223  	contConfig, err := oci.ContainerConfig(ociSpec, bundlePath, containerID, console, disableOutput)
   224  	if err != nil {
   225  		return vc.Process{}, err
   226  	}
   227  
   228  	if !rootFs.Mounted {
   229  		if rootFs.Source != "" {
   230  			realPath, err := ResolvePath(rootFs.Source)
   231  			if err != nil {
   232  				return vc.Process{}, err
   233  			}
   234  			rootFs.Source = realPath
   235  		}
   236  		contConfig.RootFs = rootFs
   237  	}
   238  
   239  	sandboxID, err := oci.SandboxID(ociSpec)
   240  	if err != nil {
   241  		return vc.Process{}, err
   242  	}
   243  
   244  	span.SetTag("sandbox", sandboxID)
   245  
   246  	if builtIn {
   247  		c, err = sandbox.CreateContainer(contConfig)
   248  		if err != nil {
   249  			return vc.Process{}, err
   250  		}
   251  	} else {
   252  		kataUtilsLogger = kataUtilsLogger.WithField("sandbox", sandboxID)
   253  
   254  		sandbox, c, err = vci.CreateContainer(ctx, sandboxID, contConfig)
   255  		if err != nil {
   256  			return vc.Process{}, err
   257  		}
   258  
   259  		if err := AddContainerIDMapping(ctx, containerID, sandboxID); err != nil {
   260  			return vc.Process{}, err
   261  		}
   262  	}
   263  
   264  	// Run pre-start OCI hooks.
   265  	err = EnterNetNS(sandbox.GetNetNs(), func() error {
   266  		return PreStartHooks(ctx, ociSpec, containerID, bundlePath)
   267  	})
   268  	if err != nil {
   269  		return vc.Process{}, err
   270  	}
   271  
   272  	return c.Process(), nil
   273  }