func (a *agentGRPC) CreateContainer(ctx context.Context, req *pb.CreateContainerRequest) (resp *gpb.Empty, err error) { if err := a.createContainerChecks(req); err != nil { return emptyResp, err } // re-scan PCI bus // looking for hidden devices if err = rescanPciBus(); err != nil { agentLog.WithError(err).Warn("Could not rescan PCI bus") } // Some devices need some extra processing (the ones invoked with // --device for instance), and that's what this call is doing. It // updates the devices listed in the OCI spec, so that they actually // match real devices inside the VM. This step is necessary since we // cannot predict everything from the caller. if err = addDevices(ctx, req.Devices, req.OCI, a.sandbox); err != nil { return emptyResp, err } // Both rootfs and volumes (invoked with --volume for instance) will // be processed the same way. The idea is to always mount any provided // storage to the specified MountPoint, so that it will match what's // inside oci.Mounts. // After all those storages have been processed, no matter the order // here, the agent will rely on libcontainer (using the oci.Mounts // list) to bind mount all of them inside the container. mountList, err := addStorages(ctx, req.Storages, a.sandbox) if err != nil { return emptyResp, err } ctr := &container{ id: req.ContainerId, processes: make(map[string]*process), mounts: mountList, useSandboxPidNs: req.SandboxPidns, agentPidNs: req.AgentPidns, ctx: ctx, } // In case the container creation failed, make sure we cleanup // properly by rolling back the actions previously performed. defer func() { if err != nil { a.rollbackFailingContainerCreation(ctr) } }() // Add the nvdimm root partition to the device cgroup to prevent access updateDeviceCgroupForGuestRootfs(req.OCI) // Convert the spec to an actual OCI specification structure. ociSpec, err := pb.GRPCtoOCI(req.OCI) if err != nil { return emptyResp, err } if err := a.handleCPUSet(ociSpec); err != nil { return emptyResp, err } if err := a.applyNetworkSysctls(ociSpec); err != nil { return emptyResp, err } if a.sandbox.guestHooksPresent { // Add any custom OCI hooks to the spec a.sandbox.addGuestHooks(ociSpec) // write the OCI spec to a file so that hooks can read it err = writeSpecToFile(ociSpec, req.ContainerId) if err != nil { return emptyResp, err } // Change cwd because libcontainer assumes the bundle path is the cwd: // https://github.com/opencontainers/runc/blob/v1.0.0-rc5/libcontainer/specconv/spec_linux.go#L157 oldcwd, err := changeToBundlePath(ociSpec, req.ContainerId) if err != nil { return emptyResp, err } defer os.Chdir(oldcwd) } // Convert the OCI specification into a libcontainer configuration. config, err := specconv.CreateLibcontainerConfig(&specconv.CreateOpts{ CgroupName: req.ContainerId, NoNewKeyring: true, Spec: ociSpec, NoPivotRoot: a.sandbox.noPivotRoot, }) if err != nil { return emptyResp, err } // apply rlimits config.Rlimits = posixRlimitsToRlimits(ociSpec.Process.Rlimits) // Update libcontainer configuration for specific cases not handled // by the specconv converter. if err = a.updateContainerConfig(ociSpec, config, ctr); err != nil { return emptyResp, err } return a.finishCreateContainer(ctr, req, config) }
func (a *agentGRPC) CreateSandbox(ctx context.Context, req *pb.CreateSandboxRequest) (*gpb.Empty, error) { if a.sandbox.running { return emptyResp, grpcStatus.Error(codes.AlreadyExists, "Sandbox already started, impossible to start again") } a.sandbox.hostname = req.Hostname a.sandbox.containers = make(map[string]*container) a.sandbox.network.ifaces = make(map[string]*types.Interface) a.sandbox.network.dns = req.Dns a.sandbox.running = true a.sandbox.sandboxPidNs = req.SandboxPidns a.sandbox.storages = make(map[string]*sandboxStorage) a.sandbox.guestHooks = &specs.Hooks{} a.sandbox.guestHooksPresent = false for _, m := range req.KernelModules { if err := loadKernelModule(m); err != nil { return emptyResp, err } } if req.GuestHookPath != "" { a.sandbox.scanGuestHooks(req.GuestHookPath) } if req.SandboxId != "" { a.sandbox.id = req.SandboxId agentLog = agentLog.WithField("sandbox", a.sandbox.id) } // Set up shared UTS and IPC namespaces if err := a.sandbox.setupSharedNamespaces(ctx); err != nil { return emptyResp, err } if req.SandboxPidns { if err := a.sandbox.setupSharedPidNs(); err != nil { return emptyResp, err } } mountList, err := addStorages(ctx, req.Storages, a.sandbox) if err != nil { return emptyResp, err } a.sandbox.mounts = mountList if err := setupDNS(a.sandbox.network.dns); err != nil { return emptyResp, err } return emptyResp, nil }