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 }